[
  {
    "path": ".bazeliskrc",
    "content": "USE_BAZEL_VERSION=7.7.1\n"
  },
  {
    "path": ".bazelrc",
    "content": "common --experimental_repo_remote_exec\ncommon --experimental_cc_shared_library\ncommon --experimental_ui_max_stdouterr_bytes=-1\ncommon --experimental_remote_cache_compression\ncommon --experimental_remote_cache_compression_threshold=100\ncommon --nolegacy_important_outputs\n\ncommon --remote_download_regex='.*\\/scqlengine$'\ncommon --registry=https://raw.githubusercontent.com/secretflow/bazel-registry/main\ncommon --registry=https://bcr.bazel.build\n\ncommon --remote_download_outputs=all\n\ncommon --experimental_proto_descriptor_sets_include_source_info\n\nbuild --incompatible_new_actions_api=false\nbuild --copt=-fdiagnostics-color=always\nbuild --enable_platform_specific_config\n\nbuild --cxxopt=-std=c++17\nbuild --host_cxxopt=-std=c++17\nbuild --linkopt -fvisibility=hidden\n# default off CUDA build\nbuild --@rules_cuda//cuda:enable=false\ntest --@rules_cuda//cuda:enable=false\n\n# Binary safety flags\nbuild --copt=-fPIC\nbuild --host_copt=-fstack-protector-strong\nbuild:linux --host_copt=-Wl,-z,noexecstack\nbuild:macos --host_copt=-Wa,--noexecstack\n\n\n\ntest --keep_going\ntest --test_output=errors\ntest --test_timeout=1800\n\n# platform specific config\n# Bazel will automatic pick platform config since we have enable_platform_specific_config set\nbuild:macos --copt=-Xclang=-fopenmp\nbuild:macos --copt=-Wno-unused-command-line-argument\nbuild:macos --features=-supports_dynamic_linker\n# build:macos --cxxopt -Wno-error=missing-template-arg-list-after-template-kw\n# build:macos --cxxopt -Wno-error=vla-cxx-extension\nbuild:macos --macos_minimum_os=13.0\nbuild:macos --host_macos_minimum_os=13.0\nbuild:macos --action_env MACOSX_DEPLOYMENT_TARGET=13.0\n\n# static link libstdc++ & libgcc on Linux\nbuild:linux --copt=-fopenmp\nbuild:linux --linkopt=-fopenmp\nbuild:linux --action_env=BAZEL_LINKOPTS=-static-libstdc++:-static-libgcc\nbuild:linux --action_env=BAZEL_LINKLIBS=-l%:libstdc++.a:-l%:libgcc.a\n\nbuild:asan --strip=never\nbuild:asan --copt -fno-sanitize-recover=all\nbuild:asan --copt -fsanitize=address\nbuild:asan --copt -Og\nbuild:asan --copt -g\nbuild:asan --copt -fno-omit-frame-pointer\nbuild:asan --linkopt -fsanitize=address\nbuild:asan --define disable_tcmalloc=true\nbuild:asan --copt=\"-Wno-error=uninitialized\"\nbuild:asan --copt=\"-Wno-error=maybe-uninitialized\"\nbuild:asan --action_env=ASAN_OPTIONS=detect_odr_violation=0\n"
  },
  {
    "path": ".circleci/config.yml",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nversion: 2.1\n\nsetup: true\n\norbs:\n  path-filtering: circleci/path-filtering@2.0.1\n  continuation: circleci/continuation@2.0.1\n\nparameters:\n  enable_regtest:\n    type: boolean\n    default: false\n\nworkflows:\n  run_ut:\n    when:\n      not: << pipeline.parameters.enable_regtest >>\n    jobs:\n      - path-filtering/filter:\n          base-revision: main\n          config-path: .circleci/lite-unittest-config.yml\n          mapping: .circleci/path-filtering/unittest.conf\n\n  run_regtest:\n    when: << pipeline.parameters.enable_regtest >>\n    jobs:\n      - continuation/continue:\n          configuration_path: .circleci/regtest-config.yml\n"
  },
  {
    "path": ".circleci/coverage-config.yml",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Use the latest 2.1 version of CircleCI pipeline process engine.\n# See: https://circleci.com/docs/2.0/configuration-reference\n\nversion: 2.1\n\norbs:\n  coveralls: coveralls/coveralls@2.2.5\n\ncommands:\n  setup_go_test:\n    steps:\n      - run:\n          name: Install gcov2lcov\n          command: |\n            which gcov2lcov || go install github.com/jandelgado/gcov2lcov@latest\n\n  setup_cpp_test:\n    steps:\n      - run:\n          name: \"Checkout devtools\"\n          command: git clone --depth=1 https://github.com/secretflow/devtools.git ../devtools\n      - run:\n          name: Setup BuildBuddy Cache\n          command: ../devtools/bazel_cache_setup.py\n\n  run_go_test:\n    description: \"Run go cov tests\"\n    steps:\n      - run:\n          name: \"Go Cov Test\"\n          command: |\n            set +e\n            go mod tidy\n            echo \"Running tests with coverage...\"\n            go test -mod=readonly -timeout=30m -v -cover -race -coverprofile=coverage.tmp ./pkg/...\n            cat coverage.tmp | grep -v '\\.pb\\.go:\\|_mock\\.go:' > coverage.out\n            gcov2lcov -infile=coverage.out -outfile=coverage.lcov\n\n  run_cpp_test:\n    description: \"Run cpp cov tests and collect artifacts\"\n    parameters:\n      extra_bazel_args:\n        type: string\n        default: \"\"\n      find_executable_flag:\n        type: string\n        default: \"-executable\"\n    steps:\n      - run:\n          name: \"Cpp Test\"\n          command: |\n            set +e\n            declare -i test_status\n\n            echo \"Running tests with coverage...\"\n            bazelisk --host_jvm_args=-Xmx8g coverage //engine/... \\\n                << parameters.extra_bazel_args >> \\\n                --combined_report=lcov \\\n                --jobs=auto \\\n                --ui_event_filters=-info,-debug,-warning \\\n                --test_output=errors | tee test_result.log\n\n            # Capture the exit status of the Bazel command\n            test_status=${PIPESTATUS[0]}\n            if [ ${test_status} -eq 0 ]; then\n              echo \"Processing coverage...\"\n              lcov --remove bazel-out/_coverage/_coverage_report.dat '*.pb.h' '*.pb.cc' -o bazel-out/_coverage/_coverage_report_filtered.dat\n            else\n              echo \"Bazel coverage failed, skipping lcov processing. Archiving binaries and logs...\"\n              find bazel-bin/ << parameters.find_executable_flag >> -type f -name \"*_test\" -print0 | xargs -0 tar -cvzf test_binary.tar.gz\n              find bazel-testlogs/ -type f -name \"test.log\" -print0 | xargs -0 tar -cvzf test_logs.tar.gz\n            fi\n\n            sh ../devtools/rename-junit-xml.sh\n            exit ${test_status}\n\n  # ref: https://support.circleci.com/hc/en-us/articles/14114124583195-How-to-set-a-custom-maximum-job-duration\n  cancel_after_timeout:\n    description: \"Cancel job if it takes too long\"\n    parameters:\n      timeout:\n        type: string\n        default: \"60m\"\n    steps:\n      - run:\n          name: Set maximum job duration to << parameters.timeout >>\n          background: true\n          command: |\n            sleep << parameters.timeout >>\n            curl --request POST \\\n            --url https://circleci.com/api/v2/project/gh/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/job/$CIRCLE_BUILD_NUM/cancel \\\n            --header \"Circle-Token: $CIRCLECI_API_TOKEN\"\n\njobs:\n  linux_go_cov:\n    docker:\n      - image: secretflow/scql-ci:latest\n    resource_class: \"large\"\n    steps:\n      - cancel_after_timeout:\n          timeout: \"30m\"\n      - checkout\n      - setup_go_test\n      - run_go_test\n      - coveralls/upload:\n          coverage_file: coverage.lcov\n          coverage_format: lcov\n          flag_name: \"go-tests\"\n\n  linux_cpp_cov:\n    docker:\n      - image: secretflow/scql-ci:latest\n    resource_class: \"2xlarge\"\n    steps:\n      - cancel_after_timeout:\n          timeout: \"90m\"\n      - checkout\n      - run:\n          name: \"Install lcov\"\n          command: apt-get update && apt-get install -y lcov\n      - setup_cpp_test\n      - run_cpp_test:\n          extra_bazel_args: \"-c opt\"\n          find_executable_flag: \"-executable\"\n      - coveralls/upload:\n          coverage_file: bazel-out/_coverage/_coverage_report_filtered.dat\n          coverage_format: lcov\n          flag_name: \"cpp-tests\"\n      - store_test_results:\n          path: test-results\n      - store_artifacts:\n          when: on_fail\n          path: test_binary.tar.gz\n      - store_artifacts:\n          when: on_fail\n          path: test_logs.tar.gz\n\nworkflows:\n  run_cov:\n    jobs:\n      - linux_go_cov\n      - linux_cpp_cov\n"
  },
  {
    "path": ".circleci/diff-cover-config.yml",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Use the latest 2.1 version of CircleCI pipeline process engine.\n# See: https://circleci.com/docs/2.0/configuration-reference\n\nversion: 2.1\n\nparameters:\n  base_commit:\n    type: string\n    description: \"The base commit SHA for the diff.\"\n    default: \"origin/main\"\n\ncommands:\n  setup_go_test:\n    steps:\n      - run:\n          name: Install gcov2lcov\n          command: |\n            which gcov2lcov || go install github.com/jandelgado/gcov2lcov@latest\n\n  setup_cpp_test:\n    steps:\n      - run:\n          name: \"Checkout devtools\"\n          command: git clone --depth=1 https://github.com/secretflow/devtools.git ../devtools\n      - run:\n          name: Setup BuildBuddy Cache\n          command: ../devtools/bazel_cache_setup.py\n\n  run_go_test:\n    description: \"Run go cov tests\"\n    steps:\n      - run:\n          name: \"Go Cov Test\"\n          command: |\n            set +e\n            go mod tidy\n            echo \"Running tests with coverage...\"\n            go test -mod=readonly -timeout=30m -v -cover -race -coverprofile=coverage.tmp ./pkg/...\n            cat coverage.tmp | grep -v '\\.pb\\.go:\\|_mock\\.go:' > coverage.out\n            python ./test-tools/find_uncover_err.py coverage.out filtered_cover_no_err_branch.out\n            gcov2lcov -infile=filtered_cover_no_err_branch.out -outfile=coverage.lcov\n\n  run_cpp_test:\n    description: \"Run cpp cov tests and collect artifacts\"\n    parameters:\n      extra_bazel_args:\n        type: string\n        default: \"\"\n      find_executable_flag:\n        type: string\n        default: \"-executable\"\n    steps:\n      - run:\n          name: \"Cpp Test\"\n          command: |\n            set +e\n            declare -i test_status\n\n            echo \"Running tests with coverage...\"\n            bazelisk --host_jvm_args=-Xmx8g coverage //engine/... \\\n                << parameters.extra_bazel_args >> \\\n                --combined_report=lcov \\\n                --jobs=auto \\\n                --ui_event_filters=-info,-debug,-warning \\\n                --test_output=errors | tee test_result.log\n\n            # Capture the exit status of the Bazel command\n            test_status=${PIPESTATUS[0]}\n            if [ ${test_status} -eq 0 ]; then\n              echo \"Processing coverage...\"\n              lcov --remove bazel-out/_coverage/_coverage_report.dat '*.pb.h' '*.pb.cc' -o bazel-out/_coverage/_coverage_report_filtered.dat\n            else\n              echo \"Bazel coverage failed, skipping lcov processing. Archiving binaries and logs...\"\n              find bazel-bin/ << parameters.find_executable_flag >> -type f -name \"*_test\" -print0 | xargs -0 tar -cvzf test_binary.tar.gz\n              find bazel-testlogs/ -type f -name \"test.log\" -print0 | xargs -0 tar -cvzf test_logs.tar.gz\n            fi\n\n            sh ../devtools/rename-junit-xml.sh\n            exit ${test_status}\n\n  # ref: https://support.circleci.com/hc/en-us/articles/14114124583195-How-to-set-a-custom-maximum-job-duration\n  cancel_after_timeout:\n    description: \"Cancel job if it takes too long\"\n    parameters:\n      timeout:\n        type: string\n        default: \"60m\"\n    steps:\n      - run:\n          name: Set maximum job duration to << parameters.timeout >>\n          background: true\n          command: |\n            sleep << parameters.timeout >>\n            curl --request POST \\\n            --url https://circleci.com/api/v2/project/gh/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/job/$CIRCLE_BUILD_NUM/cancel \\\n            --header \"Circle-Token: $CIRCLECI_API_TOKEN\"\n\njobs:\n  linux_diff_cov:\n    docker:\n      - image: secretflow/scql-ci:latest\n    resource_class: \"2xlarge\"\n    steps:\n      - cancel_after_timeout:\n          timeout: \"90m\"\n      - checkout\n      - run:\n          name: \"Install Dependencies (lcov, diff-cover)\"\n          command: |\n            apt-get update && apt-get install -y lcov\n            pip install diff-cover\n      - setup_go_test\n      - setup_cpp_test\n      - run_go_test\n      - run_cpp_test:\n          extra_bazel_args: \"-c opt\"\n      - run:\n          name: \"Debug Coverage Files\"\n          command: |\n            echo \"=== Debug Information ===\"\n            echo \"Current working directory: $(pwd)\"\n            echo \"Available coverage files:\"\n            find . -name \"*.lcov\" -o -name \"*coverage*\" -type f | head -10\n\n            if [ -f \"coverage.lcov\" ]; then\n              echo \"Go coverage file size: $(wc -l < coverage.lcov) lines\"\n              echo \"Go coverage sample:\"\n              head -10 coverage.lcov\n            fi\n\n            if [ -f \"bazel-out/_coverage/_coverage_report_filtered.dat\" ]; then\n              echo \"C++ coverage file size: $(wc -l < bazel-out/_coverage/_coverage_report_filtered.dat) lines\"\n              echo \"C++ coverage sample:\"\n              head -10 bazel-out/_coverage/_coverage_report_filtered.dat\n            fi\n\n            echo \"Git status:\"\n            git status --porcelain\n            echo \"Recent commits:\"\n            git log --oneline -5\n      - run:\n          name: \"Calculate and Report Incremental Coverage\"\n          command: |\n            echo \"Calculating incremental coverage between << pipeline.parameters.base_commit >> and ${CIRCLE_SHA1}\"\n            git config remote.origin.url \"https://github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}.git\"\n            git config advice.objectNameWarning false\n\n            if ! git rev-parse --verify << pipeline.parameters.base_commit >> >/dev/null 2>&1; then\n              echo \"Base commit not found locally, fetching...\"\n              git fetch origin << pipeline.parameters.base_commit >> || \\\n              git fetch origin --depth=100 || \\\n              git fetch origin\n            fi\n\n            if ! git rev-parse --verify << pipeline.parameters.base_commit >> >/dev/null 2>&1; then\n              echo \"Error: Base commit << pipeline.parameters.base_commit >> not found\"\n              exit 1\n            fi\n            if ! git rev-parse --verify ${CIRCLE_SHA1} >/dev/null 2>&1; then\n              echo \"Error: Current commit ${CIRCLE_SHA1} not found\"\n              exit 1\n            fi\n            echo \"Base commit: $(git rev-parse << pipeline.parameters.base_commit >>)\"\n            echo \"Head commit: $(git rev-parse ${CIRCLE_SHA1})\"\n\n            # Create a directory to store the reports\n            mkdir -p coverage-reports\n            FINAL_EXIT_CODE=0\n\n            # --- 1. Go Incremental Coverage ---\n            echo \"\"\n            echo \"--- Go Incremental Coverage ---\"\n            if [ -f \"coverage.lcov\" ]; then\n              git diff << pipeline.parameters.base_commit >>..${CIRCLE_SHA1} -- '*.go' > go_diff.txt\n              diff-cover coverage.lcov \\\n                --diff-file=go_diff.txt \\\n                --fail-under=80 \\\n                --exclude='*_test.go' \\\n                --exclude='*.pb.go' \\\n                --exclude='*_mock.go' \\\n                --format html:coverage-reports/go_diff_coverage.html \\\n                || { echo \"Go incremental coverage check FAILED.\"; FINAL_EXIT_CODE=1; }\n            else\n              echo \"Go coverage file (coverage.lcov) not found. Skipping.\"\n            fi\n\n            # --- 2. C++ Incremental Coverage ---\n            echo \"\"\n            echo \"--- C++ Incremental Coverage ---\"\n            CPP_COV_FILE=\"bazel-out/_coverage/_coverage_report_filtered.dat\"\n            if [ -f \"${CPP_COV_FILE}\" ]; then\n              git diff << pipeline.parameters.base_commit >>..${CIRCLE_SHA1} -- '*.cpp' '*.h' '*.cc' > cpp_diff.txt\n              diff-cover ${CPP_COV_FILE} \\\n                --diff-file=cpp_diff.txt \\\n                --fail-under=80 \\\n                --exclude='*.pb.h' \\\n                --exclude='*.pb.cc' \\\n                --format html:coverage-reports/cpp_diff_coverage.html \\\n                || { echo \"C++ incremental coverage check FAILED.\"; FINAL_EXIT_CODE=1; }\n            else\n              echo \"C++ coverage file (${CPP_COV_FILE}) not found. Skipping.\"\n            fi\n\n            exit ${FINAL_EXIT_CODE}\n      - store_artifacts:\n          path: coverage-reports\n      - store_artifacts:\n          path: coverage.lcov\n          destination: go-coverage.lcov\n      - store_artifacts:\n          path: bazel-out/_coverage/_coverage_report_filtered.dat\n          destination: cpp-coverage.lcov\n\nworkflows:\n  run_diff_cov_workflow:\n    jobs:\n      - linux_diff_cov\n"
  },
  {
    "path": ".circleci/full-unittest-config.yml",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Use the latest 2.1 version of CircleCI pipeline process engine.\n# See: https://circleci.com/docs/2.0/configuration-reference\n\nversion: 2.1\n\ncommands:\n  setup_cpp_test:\n    steps:\n      - run:\n          name: \"Checkout devtools\"\n          command: git clone --depth=1 https://github.com/secretflow/devtools.git ../devtools\n      - run:\n          name: Setup BuildBuddy Cache\n          command: ../devtools/bazel_cache_setup.py\n\n  run_go_test:\n    description: \"Run go tests\"\n    steps:\n      - run:\n          name: \"Go Test\"\n          command: |\n            set +e\n            go mod tidy\n            echo \"Running unit tests...\"\n            go test -mod=readonly -timeout=30m -v -short ./pkg/...\n\n  run_cpp_test:\n    description: \"Run cpp tests and collect artifacts on fail\"\n    parameters:\n      extra_bazel_args:\n        type: string\n        default: \"\"\n      find_executable_flag:\n        type: string\n        default: \"-executable\"\n    steps:\n      - run:\n          name: \"Cpp Test\"\n          command: |\n            set +e\n            declare -i test_status\n\n            echo \"Running unit tests...\"\n            bazelisk --host_jvm_args=-Xmx8g test //engine/... \\\n                << parameters.extra_bazel_args >> \\\n                --jobs=auto \\\n                --ui_event_filters=-info,-debug,-warning \\\n                --test_output=errors | tee test_result.log\n\n            # Capture the exit status of the Bazel command\n            test_status=${PIPESTATUS[0]}\n\n            sh ../devtools/rename-junit-xml.sh\n            if [ ${test_status} -ne 0 ]; then\n              echo \"Tests failed. Archiving binaries and logs...\"\n              find bazel-bin/ << parameters.find_executable_flag >> -type f -name \"*_test\" -print0 | xargs -0 tar -cvzf test_binary.tar.gz\n              find bazel-testlogs/ -type f -name \"test.log\" -print0 | xargs -0 tar -cvzf test_logs.tar.gz\n            fi\n\n            exit ${test_status}\n\n  # ref: https://support.circleci.com/hc/en-us/articles/14114124583195-How-to-set-a-custom-maximum-job-duration\n  cancel_after_timeout:\n    description: \"Cancel job if it takes too long\"\n    parameters:\n      timeout:\n        type: string\n        default: \"60m\"\n    steps:\n      - run:\n          name: Set maximum job duration to << parameters.timeout >>\n          background: true\n          command: |\n            sleep << parameters.timeout >>\n            curl --request POST \\\n            --url https://circleci.com/api/v2/project/gh/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/job/$CIRCLE_BUILD_NUM/cancel \\\n            --header \"Circle-Token: $CIRCLECI_API_TOKEN\"\n\njobs:\n  linux_go_ut:\n    docker:\n      - image: secretflow/scql-ci:latest\n    parameters:\n      resource_class:\n        type: string\n    resource_class: << parameters.resource_class >>\n    steps:\n      - cancel_after_timeout:\n          timeout: \"20m\"\n      - checkout\n      - run_go_test\n\n  linux_cpp_ut:\n    docker:\n      - image: secretflow/scql-ci:latest\n    parameters:\n      resource_class:\n        type: string\n    resource_class: << parameters.resource_class >>\n    steps:\n      - cancel_after_timeout:\n          timeout: \"60m\"\n      - checkout\n      - setup_cpp_test\n      - run_cpp_test:\n          extra_bazel_args: \"-c opt\"\n          find_executable_flag: \"-executable\"\n      - store_test_results:\n          path: test-results\n      - store_artifacts:\n          when: on_fail\n          path: test_binary.tar.gz\n      - store_artifacts:\n          when: on_fail\n          path: test_logs.tar.gz\n\n  macOS_go_ut:\n    macos:\n      xcode: 16.3.0\n    resource_class: m4pro.medium\n    steps:\n      - cancel_after_timeout:\n          timeout: \"20m\"\n      - checkout\n      - run:\n          name: \"Install homebrew dependencies\"\n          command: |\n            brew install wget go\n      - run_go_test\n\n  macOS_cpp_ut:\n    macos:\n      xcode: 16.3.0\n    resource_class: m4pro.medium\n    steps:\n      - cancel_after_timeout:\n          timeout: \"60m\"\n      - checkout\n      - run:\n          name: \"Install homebrew dependencies\"\n          command: |\n            brew install bazelisk cmake ninja libomp wget go@1.24 md5sha1sum\n            brew link go@1.24\n      - setup_cpp_test\n      - run_cpp_test:\n          extra_bazel_args: \"\"\n          find_executable_flag: \"-perm +111\"\n      - store_test_results:\n          path: test-results\n      - store_artifacts:\n          when: on_fail\n          path: test_binary.tar.gz\n      - store_artifacts:\n          when: on_fail\n          path: test_logs.tar.gz\n\nworkflows:\n  run_go_ut:\n    jobs:\n      - linux_go_ut:\n          matrix:\n            parameters:\n              resource_class: [\"large\", \"arm.large\"]\n      - macOS_go_ut\n  run_cpp_ut:\n    jobs:\n      - linux_cpp_ut:\n          matrix:\n            parameters:\n              resource_class: [\"2xlarge\", \"arm.2xlarge\"]\n      - macOS_cpp_ut\n"
  },
  {
    "path": ".circleci/lite-unittest-config.yml",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Use the latest 2.1 version of CircleCI pipeline process engine.\n# See: https://circleci.com/docs/2.0/configuration-reference\n\nversion: 2.1\n\nparameters:\n  run_go_ut:\n    type: boolean\n    default: false\n  run_cpp_ut:\n    type: boolean\n    default: false\n\ncommands:\n  setup_cpp_test:\n    steps:\n      - run:\n          name: \"Checkout devtools\"\n          command: git clone --depth=1 https://github.com/secretflow/devtools.git ../devtools\n      - run:\n          name: Setup BuildBuddy Cache\n          command: ../devtools/bazel_cache_setup.py\n\n  run_go_test:\n    description: \"Run go tests\"\n    steps:\n      - run:\n          name: \"Go Test\"\n          command: |\n            set +e\n            go mod tidy\n            echo \"Running unit tests...\"\n            go test -mod=readonly -timeout=30m -v -short ./pkg/...\n\n  run_cpp_test:\n    description: \"Run cpp tests and collect artifacts on fail\"\n    steps:\n      - run:\n          name: \"Cpp Test\"\n          command: |\n            set +e\n            declare -i test_status\n\n            echo \"Running unit tests...\"\n            bazelisk --host_jvm_args=-Xmx8g test //engine/... \\\n                -c opt \\\n                --jobs=16 \\\n                --local_ram_resources=20480 \\\n                --ui_event_filters=-info,-debug,-warning \\\n                --test_output=errors | tee test_result.log\n\n            # Capture the exit status of the Bazel command\n            test_status=${PIPESTATUS[0]}\n\n            sh ../devtools/rename-junit-xml.sh\n            if [ ${test_status} -ne 0 ]; then\n              echo \"Tests failed. Archiving binaries and logs...\"\n              find bazel-bin/ -executable -type f -name \"*_test\" -print0 | xargs -0 tar -cvzf test_binary.tar.gz\n              find bazel-testlogs/ -type f -name \"test.log\" -print0 | xargs -0 tar -cvzf test_logs.tar.gz\n            fi\n\n            exit ${test_status}\n\n  # ref: https://support.circleci.com/hc/en-us/articles/14114124583195-How-to-set-a-custom-maximum-job-duration\n  cancel_after_timeout:\n    description: \"Cancel job if it takes too long\"\n    parameters:\n      timeout:\n        type: string\n        default: \"60m\"\n    steps:\n      - run:\n          name: Set maximum job duration to << parameters.timeout >>\n          background: true\n          command: |\n            sleep << parameters.timeout >>\n            curl --request POST \\\n            --url https://circleci.com/api/v2/project/gh/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/job/$CIRCLE_BUILD_NUM/cancel \\\n            --header \"Circle-Token: $CIRCLECI_API_TOKEN\"\n\njobs:\n  linux_go_ut:\n    docker:\n      - image: secretflow/scql-ci:latest\n    resource_class: \"large\"\n    steps:\n      - cancel_after_timeout:\n          timeout: \"20m\"\n      - checkout\n      - run_go_test\n\n  linux_cpp_ut:\n    docker:\n      - image: secretflow/scql-ci:latest\n    resource_class: \"2xlarge\"\n    steps:\n      - cancel_after_timeout:\n          timeout: \"60m\"\n      - checkout\n      - setup_cpp_test\n      - run_cpp_test\n      - store_test_results:\n          path: test-results\n      - store_artifacts:\n          when: on_fail\n          path: test_binary.tar.gz\n      - store_artifacts:\n          when: on_fail\n          path: test_logs.tar.gz\n\nworkflows:\n  run_go_ut:\n    when: << pipeline.parameters.run_go_ut >>\n    jobs:\n      - linux_go_ut\n\n  run_cpp_ut:\n    when: << pipeline.parameters.run_cpp_ut >>\n    jobs:\n      - linux_cpp_ut\n"
  },
  {
    "path": ".circleci/path-filtering/unittest.conf",
    "content": "api/.* run_go_ut true\ncmd/.* run_go_ut true\npkg/.* run_go_ut true\n.circleci/lite-unittest-config.yml run_go_ut true\nbazel/.* run_cpp_ut true\nengine/.* run_cpp_ut true\n.bazelrc run_cpp_ut true\n.bazeliskrc run_cpp_ut true\nMODULE.bazel run_cpp_ut true\n.circleci/lite-unittest-config.yml run_cpp_ut true\n"
  },
  {
    "path": ".clang-format",
    "content": "# Use the Google style in this project.\nBasedOnStyle: Google\n\nIncludeBlocks: Regroup\nIncludeCategories:\n  - Regex: '^<.*\\.h>'\n    Priority: 1\n  - Regex: \"^<.*\"\n    Priority: 2\n  - Regex: '.*\\.pb\\.h\"$'\n    Priority: 5\n  - Regex: '^\"engine.*'\n    Priority: 4\n  - Regex: '^\".*'\n    Priority: 3\n"
  },
  {
    "path": ".clang-tidy",
    "content": "Checks: \"abseil-cleanup-ctad,\n  abseil-faster-strsplit-delimiter,\n  abseil-duration-*,\n  abseil-no-namespace,\n  abseil-redundant-strcat-calls,\n  abseil-str-cat-append,\n  abseil-string-find-startswith,\n  abseil-upgrade-duration-conversions\n  bugprone-*,\n  -bugprone-easily-swappable-parameters,\n  -bugprone-implicit-widening-of-multiplication-result,\n  -bugprone-narrowing-conversions,\n  google-build-using-namespace,\n  google-explicit-constructor,\n  google-global-names-in-headers,\n  google-readability-casting,\n  google-runtime-int,\n  google-runtime-operator,\n  misc-unused-using-decls,\n  modernize-*,\n  -modernize-use-trailing-return-type,\n  -modernize-avoid-c-arrays,\n  -modernize-return-braced-init-list,\n  -modernize-use-nodiscard,\n  performance-*,\n  readability-*,\n  -readability-else-after-return,\n  -readability-identifier-length,\n  -readability-function-cognitive-complexity,\n  -readability-magic-numbers,\n  -readability-named-parameter,\n  -readability-math-missing-parentheses,\n  -readability-redundant-access-specifiers,\n  -readability-simplify-boolean-expr,\n  concurrency-mt-unsafe\"\n\nCheckOptions:\n  - key: bugprone-argument-comment.StrictMode\n    value: 1\n\n  - key: bugprone-dangling-handle.HandleClasses\n    value: \"std::basic_string_view;std::experimental::basic_string_view;absl::string_view\"\n\n  - key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic\n    value: 1\n\n    # Ignore GoogleTest function macros.\n  - key: readability-identifier-naming.FunctionIgnoredRegexp\n    value: \"(TEST|TEST_F|TEST_P|INSTANTIATE_TEST_SUITE_P|MOCK_METHOD|TYPED_TEST)\"\n\n  - key: readability-identifier-naming.ClassCase\n    value: \"CamelCase\"\n\n  - key: readability-identifier-naming.EnumCase\n    value: \"CamelCase\"\n\n  - key: readability-identifier-naming.EnumConstantCase\n    value: \"CamelCase\"\n\n  - key: readability-identifier-naming.ParameterCase\n    value: \"lower_case\"\n\n  - key: readability-identifier-naming.PrivateMemberCase\n    value: \"lower_case\"\n\n  - key: readability-identifier-naming.PrivateMemberSuffix\n    value: \"_\"\n\n  - key: readability-identifier-naming.StructCase\n    value: \"CamelCase\"\n\n  - key: readability-identifier-naming.TypeAliasCase\n    value: \"CamelCase\"\n\n  - key: readability-identifier-naming.UnionCase\n    value: \"CamelCase\"\n\n  - key: readability-identifier-naming.FunctionCase\n    value: \"CamelBack\"\n"
  },
  {
    "path": ".coveralls.yml",
    "content": "# Configure whether the Coveralls status check fails when coverage decreases\nfail_on_coverage_decrease: false\n\ncoverage:\n  status:\n    project:\n      go-tests:\n        # Set a coverage threshold for the changed lines of code.\n        target: 70%\n\n      cpp-tests:\n        target: 70%\n\n    patch:\n      default:\n        target: 70%\n\ncomment:\n  pull_request:\n    # update a comment\n    behavior: default\n\n    # diff:  Shows overall coverage change and coverage of changed lines\n    # flags: If upload multiple reports (C++ and Go), they will be displayed separately\n    # files: Lists the files where coverage has changed\n    layout: \"diff, flags, files\""
  },
  {
    "path": ".devcontainer/Dockerfile",
    "content": "FROM secretflow/ubuntu-base-ci:latest\n\nARG TARGETPLATFORM\nARG GO_VERSION=1.24.0\n\n# install go\nRUN if [ \"$TARGETPLATFORM\" = \"linux/arm64\" ] ; \\\n    then \\\n        GO_ARCH=arm64 && \\\n        GO_SHA256SUM=c3fa6d16ffa261091a5617145553c71d21435ce547e44cc6dfb7470865527cc7 ; \\\n    else \\\n        GO_ARCH=amd64 && \\\n        GO_SHA256SUM=dea9ca38a0b852a74e81c26134671af7c0fbe65d81b0dc1c5bfe22cf7d4c8858 ; \\\n    fi \\\n    && url=\"https://golang.google.cn/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz\"; \\\n    wget --no-check-certificate -O go.tgz \"$url\"; \\\n    echo \"${GO_SHA256SUM} *go.tgz\" | sha256sum -c -; \\\n    tar -C /usr/local -xzf go.tgz; \\\n    rm go.tgz;\n\nENV GOPATH=\"/usr/local\"\nENV PATH=\"/usr/local/go/bin:${GOPATH}/bin:${PATH}\"\n\nRUN apt update \\\n    && apt upgrade -y \\\n    && apt install -y protobuf-compiler \\\n    && apt clean\n\n\n# Create a non-root user 'vscode' with sudo privileges\n# The user ID 1000 is common for the primary user in Linux distributions.\n# The GID 1000 corresponds to the user's primary group.\nRUN groupadd --gid 1000 vscode && \\\n    useradd --uid 1000 --gid 1000 --shell /bin/bash --create-home vscode && \\\n    echo \"vscode ALL=(ALL) NOPASSWD:ALL\" >> /etc/sudoers\n\n# Set the default user for subsequent commands\nUSER vscode\n\n# Set the working directory inside the container\nWORKDIR /workspaces/scql\n\n# Set default shell to bash for the vscode user\nENV SHELL /bin/bash\n\n# You can add more SCQL-specific dependencies here if needed,\n# although 'make install-dev-deps' in postCreateCommand should handle most project dependencies.\n\n# Keep the container running (optional, useful for debugging setup)\n# CMD [\"sleep\", \"infinity\"]\n"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "content": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the\n// README at: https://github.com/devcontainers/templates/tree/main/src/cpp\n{\n    // A name for the dev container which can be displayed in UI.\n    \"name\": \"SCQL Dev Container\",\n\n    // Sets the run context to one level up instead of the .devcontainer folder.\n    \"context\": \"..\",\n\n    // Update the VARIANT arg in docker-compose.yml to pick a Debian OS version: bullseye, buster\n    // Use Python 3.10 to align with SCQL's CI/CD environment if possible, adjust if needed.\n    \"build\": {\n        \"dockerfile\": \"Dockerfile\"\n    },\n\n    // Features to add to the dev container. More info: https://containers.dev/features.\n    // \"features\": {},\n\n    // Use 'forwardPorts' to make a list of ports inside the container available locally.\n    // \"forwardPorts\": [],\n\n    // Use 'postCreateCommand' to run commands after the container is created.\n    // Installs development dependencies using the Makefile target.\n    \"postCreateCommand\": \"echo 'hello world'\",\n\n    // Configure tool-specific properties.\n    // \"customizations\": {},\n\n    // Specifies the user the container will run as. Default is root.\n    // Using a non-root user 'vscode' is recommended for security.\n    \"remoteUser\": \"vscode\",\n\n    // Mount the workspace folder.\n    \"workspaceFolder\": \"/workspaces/scql\",\n    \"workspaceMount\": \"source=${localWorkspaceFolder},target=/workspaces/scql,type=bind,consistency=cached\"\n}\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# default reviewers for everything in this repo.\n* @secretflow/scql-dev\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Consulting_issue_template.yaml",
    "content": "name: Consulting Template\ndescription: Ask SCQL related questions\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Please ensure that you are reporting the consultation issue on GitHub.（CCL、Perfomance、Feature、Documentation、Others）\n  - type: dropdown\n    id: issue-type\n    attributes:\n      label: Issue Type\n      description: What type of issue would you like to report?\n      multiple: false\n      options:\n        - CCL\n        - Perfomance\n        - Feature\n        - Documentation\n        - Others\n    validations:\n      required: true\n  - type: dropdown\n    id: searched-for-existing-issues\n    attributes:\n      label: Have you searched for existing issues? \n      description: It is recommended to search existing [documentation](https://www.secretflow.org.cn/zh-CN/docs/scql/main/topics) and [issues](https://github.com/secretflow/scql/issues) first\n      options:\n        - 'Yes'\n        - 'No'\n    validations:\n      required: true\n  - type: input\n    id: link\n    attributes:\n      label: Link to Relevant Documentation\n      description: For faster problem-solving, if there are relevant documents, please attach links.\n      placeholder: e.g., https://www.secretflow.org.cn/zh-CN/docs/scql/main/topics/ccl/intro\n    validations:\n      required: false\n  - type: textarea\n    id: Question-Details\n    attributes:\n      label: Question Details\n      description: Please detail your issue with observed versus expected behavior and attempted solutions to expedite resolution.\n      placeholder: Describe the questions you want to consult and what you want to do\n      value:\n      render: shell\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Error_Issue_Template.yaml",
    "content": "name: Error Template\ndescription: Thank you for reporting the issue!\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Please ensure that you are reporting the consultation issue on GitHub.（Install/Build、Running、CCL、Others）\n  - type: dropdown\n    id: issue-type\n    attributes:\n      label: Issue Type\n      description: What type of issue would you like to report?\n      multiple: false\n      options:\n        - Install/Build\n        - Running\n        - CCL\n        - Others\n    validations:\n      required: true\n  - type: dropdown\n    id: searched-for-existing-issues\n    attributes:\n      label: Have you searched for existing issues? \n      description: It is recommended to search existing [documentation](https://www.secretflow.org.cn/zh-CN/docs/scql/main/topics) and [issues](https://github.com/secretflow/scql/issues) first\n      options:\n        - 'Yes'\n        - 'No'\n    validations:\n      required: true\n  - type: input\n    id: OS\n    attributes:\n      label: OS Platform and Distribution\n      description:\n      placeholder: e.g., Linux Ubuntu 18.04\n    validations:\n      required: true\n  - type: input\n    id: scql-version\n    attributes:\n      label: SCQL Version\n      description:\n      placeholder: e.g., SCQL 0.7.0b0\n    validations:\n      required: true\n  - type: textarea\n    id: what-happened\n    attributes:\n      label: What happend and What you expected to happen.\n      description: A clear and concise description of what the bug is.\n      placeholder: Describe the bug, expected behavior.\n      value:\n      render: shell\n    validations:\n      required: true\n  - type: textarea\n    id: scql-config\n    attributes:\n      label: Configuration used to run SCQL.\n      description: Supply SCQL runtime config (.yaml, .conf) and, for CCL issues, supply authorization info and SQL statements.\n      placeholder: |\n        # - For install/deploy, provide files ending with `.yaml` and `.conf`.\n        # - For CCL, provide the authorization details and CCL SQL.\n      value:\n      render: shell\n    validations:\n      required: true\n  - type: textarea\n    id: log-output\n    attributes:\n      label: SCQL log output.\n      description: Supply relevant log output (docker logs -f xxx-broker-xxx/xxx-engine-xxx); For multi-party (e.g. Alice, Bob) scenarios, include all corresponding logs.\n      placeholder: |\n        # alice.log\n        .......\n        # bob.log\n        .......\n      value:\n      render: shell\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/workflows/black.yml",
    "content": "---\nname: Python Linter\non:\n  push:\n    branches:\n    - main\n    paths:\n      - '**.py'\n  pull_request:\n    branches:\n    - main\n    paths:\n      - '**.py'\npermissions:\n  contents: read\njobs:\n  python-linter:\n    uses: secretflow/.github/.github/workflows/python-linter.yml@main"
  },
  {
    "path": ".github/workflows/buildifier.yml",
    "content": "---\nname: Bazel files linter\non:\n  push:\n    branches:\n    - main\n  pull_request:\n    branches:\n    - main\npermissions:\n  contents: read\njobs:\n  bazel-formatting-check:\n    uses: secretflow/.github/.github/workflows/bazel-linter.yml@main"
  },
  {
    "path": ".github/workflows/cla.yml",
    "content": "---\nname: CLA Assistant\non:\n  issue_comment:\n    types: [created]\n  pull_request_target:\n    types: [opened, closed, synchronize]\njobs:\n  CLAssistant:\n    uses: secretflow/.github/.github/workflows/cla.yml@main\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/clang-format-linter.yml",
    "content": "---\nname: Run clang-format Linter\non:\n  push:\n    branches:\n    - main\n    paths:\n      - '**.cc'\n      - '**.cpp'\n      - '**.hpp'\n      - '**.h'\n      - '**.proto'\n  pull_request:\n    branches:\n    - main\n    paths:\n      - '**.cc'\n      - '**.cpp'\n      - '**.hpp'\n      - '**.h'\n      - '**.proto'\npermissions:\n  contents: read\njobs:\n  run-clang-format:\n    uses: secretflow/.github/.github/workflows/clang-format.yml@main"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [\"main\"]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [\"main\"]\n  schedule:\n    - cron: \"0 0 * * 1\"\n\npermissions:\n  contents: read\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [\"cpp\", \"go\", \"python\"]\n        # CodeQL supports [ $supported-codeql-languages ]\n        # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support\n\n    steps:\n      - name: Harden the runner (Audit all outbound calls)\n        uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0\n        with:\n          egress-policy: audit\n\n      - name: Checkout repository\n        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n\n      # Initializes the CodeQL tools for scanning.\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16\n        with:\n          languages: ${{ matrix.language }}\n          # If you wish to specify custom queries, you can do so here or in a config file.\n          # By default, queries listed here will override any specified in a config file.\n          # Prefix the list here with \"+\" to use these queries and those in the config file.\n\n      # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n      # If this step fails, then you should remove it and run the build manually (see below)\n      - name: Autobuild\n        uses: github/codeql-action/autobuild@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16\n\n      # ℹ️ Command-line programs to run using the OS shell.\n      # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun\n\n      #   If the Autobuild fails above, remove it and uncomment the following three lines.\n      #   modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.\n\n      # - run: |\n      #   echo \"Run, Build Application using script\"\n      #   ./location_of_script_within_repo/buildscript.sh\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16\n        with:\n          category: \"/language:${{matrix.language}}\"\n"
  },
  {
    "path": ".github/workflows/dependency-review.yml",
    "content": "# Dependency Review Action\n#\n# This Action will scan dependency manifest files that change as part of a Pull Request,\n# surfacing known-vulnerable versions of the packages declared or updated in the PR.\n# Once installed, if the workflow run is marked as required,\n# PRs introducing known-vulnerable packages will be blocked from merging.\n#\n# Source repository: https://github.com/actions/dependency-review-action\nname: 'Dependency Review'\non: [pull_request]\n\npermissions:\n  contents: read\n\njobs:\n  dependency-review:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Harden the runner (Audit all outbound calls)\n        uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0\n        with:\n          egress-policy: audit\n\n      - name: 'Checkout Repository'\n        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n      - name: 'Dependency Review'\n        uses: actions/dependency-review-action@67d4f4bd7a9b17a0db54d2a7519187c65e339de8 # v4\n"
  },
  {
    "path": ".github/workflows/docs-check.yml",
    "content": "---\nname: Check Docs\non:\n  push:\n    branches:\n      - main\n    paths:\n      - 'docs/**'\n  pull_request:\n    branches:\n      - main\n    paths:\n      - 'docs/**'\n\npermissions:\n  contents: read\n  pull-requests: read\n\njobs:\n  check-docs:\n    name: check docs\n    runs-on: [ubuntu-latest]\n    container:\n      image: secretflow/scql-ci:20250228\n    steps:\n      - name: Harden the runner (Audit all outbound calls)\n        uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0\n        with:\n          egress-policy: audit\n\n      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n        with:\n          fetch-depth: '0'\n      - name: make docs\n        run: |\n          # avoid {{ and {# in docs\n          if [ $(grep -E '({{|{#)' --include=\\*.{rst,md,ipynb,po} --exclude=run-scql-on-kuscia.* -rnw 'docs' | wc -l) != 0 ];\n          then\n            echo \"({{|{#) is not allowed in rst,md,ipynb,po files. Thank you for cooperation.\"\n            grep -E '({{|{#)' --include=\\*.{rst,md,ipynb,po} --exclude=run-scql-on-kuscia.* -rnw 'docs'\n            exit 1\n          fi"
  },
  {
    "path": ".github/workflows/docs-publish.yml",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nname: Publish Docs\non:\n  push:\n    branches:\n      - main\n    tags:\n      - \"*\"\n\njobs:\n  check-docs:\n    name: check docs\n    runs-on: [ubuntu-latest]\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version: \"22\"\n      - uses: actions/setup-python@v5\n        with:\n          python-version: \"3.10\"\n      - name: pubilsh docs\n        run: |\n          python3 -m venv ~/.venv/docs\n          source ~/.venv/docs/bin/activate\n          python -m pip install -r docs/requirements.txt\n          secretflow-doctools build --lang zh_CN --lang en\n          secretflow-doctools publish \\\n            --name @secretflow/x-scql \\\n            --index-js docs/_build/esm/index.js\n        env:\n          DRY_RUN: \"0\" # omit in test runs\n          DOCTOOLS_PUBLISH_NPM_TOKEN: ${{secrets.DOCTOOLS_PUBLISH_NPM_TOKEN}}\n"
  },
  {
    "path": ".github/workflows/golangci-lint.yml",
    "content": "---\nname: Golangci-Lint\n\non:\n  push:\n    branches:\n      - main\n    paths:\n      - '**.go'\n      - '.golangci-lint.yml'\n  pull_request:\n    branches:\n      - main\n    paths:\n      - '**.go'\n      - '.golangci-lint.yml'\n\nenv:\n  GO_VERSION: 1.24\n  GOLANGCI_LINT_VERSION: v2.0\n\npermissions:\n  # Required: allow read access to the content for analysis.\n  contents: read\n  # Optional: allow read access to pull request. Use with `only-new-issues` option.\n  pull-requests: read\n\njobs:\n  detect-modules:\n    runs-on: ubuntu-latest\n    outputs:\n      modules: ${{ steps.set-modules.outputs.modules }}\n    steps:\n      - name: Harden the runner (Audit all outbound calls)\n        uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0\n        with:\n          egress-policy: audit\n\n      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n      - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0\n        with:\n          go-version: ${{ env.GO_VERSION }}\n      - id: set-modules\n        run: echo \"modules=$(go list -m -json | jq -s '.' | jq -c '[.[].Dir]')\" >> $GITHUB_OUTPUT\n\n  golangci-lint:\n    needs: detect-modules\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        modules: ${{ fromJSON(needs.detect-modules.outputs.modules) }}\n    steps:\n      - name: Harden the runner (Audit all outbound calls)\n        uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0\n        with:\n          egress-policy: audit\n\n      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n      - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0\n        with:\n          go-version: ${{ env.GO_VERSION }}\n      - name: golangci-lint ${{ matrix.modules }}\n        uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0\n        with:\n          version: ${{ env.GOLANGCI_LINT_VERSION }}\n          working-directory: ${{ matrix.modules }}"
  },
  {
    "path": ".github/workflows/govulncheck.yml",
    "content": "---\nname: Go Vulnerability Check\n\non:\n  push:\n    branches:\n      - main\n    paths:\n      - '**.go'\n      - 'go.mod'\n      - 'go.sum'\n      - '.github/workflows/govulncheck.yml'\n  pull_request:\n    branches:\n      - main\n    paths:\n      - '**.go'\n      - 'go.mod'\n      - 'go.sum'\n      - '.github/workflows/govulncheck.yml'\n\njobs:\n  govulncheck_job:\n    runs-on: ubuntu-latest\n    name: Run govulncheck\n    steps:\n      - id: govulncheck\n        uses: golang/govulncheck-action@v1\n        with:\n           go-package: ./...\n           go-version-file: 'go.mod'\n           output-format: 'text'"
  },
  {
    "path": ".github/workflows/license-check.yml",
    "content": "---\nname: License Check\non:\n  push:\n    branches:\n    - main\n  pull_request:\n    branches:\n    - main\npermissions:\n  contents: read\njobs:\n  license-checker:\n    uses: secretflow/.github/.github/workflows/license-check.yml@main"
  },
  {
    "path": ".github/workflows/oscp.yml",
    "content": "name: Unassign Stale OSCP Issues\n\non:\n  schedule:\n    - cron: \"0 */6 * * *\" # Every 6 hours\n\njobs:\n  unassign-stale-issues:\n    uses: secretflow/.github/.github/workflows/oscp-unassign.yml@main\n"
  },
  {
    "path": ".github/workflows/scorecards.yml",
    "content": "# This workflow uses actions that are not certified by GitHub. They are provided\n# by a third-party and are governed by separate terms of service, privacy\n# policy, and support documentation.\n\nname: Scorecard supply-chain security\non:\n  # For Branch-Protection check. Only the default branch is supported. See\n  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection\n  branch_protection_rule:\n  # To guarantee Maintained check is occasionally updated. See\n  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained\n  schedule:\n    - cron: '20 7 * * 2'\n  push:\n    branches: [\"main\"]\n\n# Declare default permissions as read only.\npermissions: read-all\n\njobs:\n  analysis:\n    name: Scorecard analysis\n    runs-on: ubuntu-latest\n    permissions:\n      # Needed to upload the results to code-scanning dashboard.\n      security-events: write\n      # Needed to publish results and get a badge (see publish_results below).\n      id-token: write\n      contents: read\n      actions: read\n      # To allow GraphQL ListCommits to work\n      issues: read\n      pull-requests: read\n      # To detect SAST tools\n      checks: read\n\n    steps:\n      - name: Harden the runner (Audit all outbound calls)\n        uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0\n        with:\n          egress-policy: audit\n\n      - name: \"Checkout code\"\n        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n        with:\n          persist-credentials: false\n\n      - name: \"Run analysis\"\n        uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0\n        with:\n          results_file: results.sarif\n          results_format: sarif\n          # (Optional) \"write\" PAT token. Uncomment the `repo_token` line below if:\n          # - you want to enable the Branch-Protection check on a *public* repository, or\n          # - you are installing Scorecards on a *private* repository\n          # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.\n          # repo_token: ${{ secrets.SCORECARD_TOKEN }}\n\n          # Public repositories:\n          #   - Publish results to OpenSSF REST API for easy access by consumers\n          #   - Allows the repository to include the Scorecard badge.\n          #   - See https://github.com/ossf/scorecard-action#publishing-results.\n          # For private repositories:\n          #   - `publish_results` will always be set to `false`, regardless\n          #     of the value entered here.\n          publish_results: true\n\n      # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF\n      # format to the repository Actions tab.\n      - name: \"Upload artifact\"\n        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2\n        with:\n          name: SARIF file\n          path: results.sarif\n          retention-days: 5\n\n      # Upload the results to GitHub's code scanning dashboard.\n      - name: \"Upload to code-scanning\"\n        uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16\n        with:\n          sarif_file: results.sarif\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "---\nname: Mark stale issues and pull requests\non:\n  workflow_dispatch:\n  schedule:\n    - cron: 40 9 * * *\njobs:\n  stale:\n    uses: secretflow/.github/.github/workflows/stale.yml@main\n"
  },
  {
    "path": ".github/workflows/trigger-ci-cov.yml",
    "content": "name: Trigger CircleCI Coverage Test\n\non:\n  pull_request_target:\n    types: [labeled] # Only run when a label is added\n\njobs:\n  trigger-circleci:\n    runs-on: ubuntu-latest\n    # This job only runs if the label that was just added is exactly \"run-ci-cov\".\n    if: github.event.label.name == 'run-ci-cov'\n    permissions:\n      pull-requests: write\n    steps:\n      - name: Trigger CircleCI Pipeline\n        run: |\n          echo \"Label 'run-ci-cov' was added to PR #${{ github.event.pull_request.number }}. Triggering CircleCI pipeline...\"\n\n          # We use curl to directly call the CircleCI API v2.\n          # This is more flexible than the official trigger action.\n          curl -X POST \\\n            --url \"https://circleci.com/api/v2/project/github/secretflow/scql/pipeline/run\" \\\n            --header \"Content-Type: application/json\" \\\n            --header \"Circle-Token: ${{ secrets.CCI_TOKEN }}\" \\\n            --data '{\"definition_id\":\"425b19a9-9f21-4d53-a4a6-c2e57939ddd0\",\"config\":{\"branch\":\"pull/${{ github.event.pull_request.number }}/head\"},\"checkout\":{\"branch\":\"pull/${{ github.event.pull_request.number }}/head\"}}'\n      - name: Remove Label from PR\n        run: |\n          echo \"Removing 'run-ci-cov' label from PR #${{ github.event.pull_request.number }}...\"\n\n          curl -s -X DELETE \\\n            -H \"Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}\" \\\n            -H \"Accept: application/vnd.github.v3+json\" \\\n            \"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels/run-ci-cov\"\n"
  },
  {
    "path": ".github/workflows/trigger-ci-full-ut.yml",
    "content": "name: Trigger CircleCI Full Unit Test for Forked & Labeled PR\n\non:\n  pull_request_target:\n    types: [labeled]\n\njobs:\n  trigger-circleci:\n    runs-on: ubuntu-latest\n    # This job only runs if the label that was just added is exactly \"run-ci-full\".\n    if: github.event.label.name == 'run-ci-full'\n    permissions:\n      pull-requests: write\n    steps:\n      - name: Trigger CircleCI Pipeline\n        run: |\n          echo \"Label 'run-ci-full' was added to PR #${{ github.event.pull_request.number }}. Triggering CircleCI pipeline...\"\n\n          curl -X POST \\\n            --url \"https://circleci.com/api/v2/project/github/secretflow/scql/pipeline/run\" \\\n            --header \"Content-Type: application/json\" \\\n            --header \"Circle-Token: ${{ secrets.CCI_TOKEN }}\" \\\n            --data '{\"definition_id\":\"ee28d7c2-ef66-4a57-bc90-6895e2b55f14\",\"config\":{\"branch\":\"pull/${{ github.event.pull_request.number }}/head\"},\"checkout\":{\"branch\":\"pull/${{ github.event.pull_request.number }}/head\"}}'\n      - name: Remove Label from PR\n        run: |\n          echo \"Removing 'run-ci-full' label from PR #${{ github.event.pull_request.number }}...\"\n\n          curl -s -X DELETE \\\n            -H \"Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}\" \\\n            -H \"Accept: application/vnd.github.v3+json\" \\\n            \"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels/run-ci-full\"\n"
  },
  {
    "path": ".github/workflows/trigger-ci-lite-ut.yml",
    "content": "name: Trigger CircleCI Lite Unit Test for Forked & Labeled PR\n\non:\n  pull_request_target:\n    types: [labeled]\n\njobs:\n  trigger-circleci:\n    runs-on: ubuntu-latest\n    # This job only runs under two conditions:\n    # 1. The PR is from a fork.\n    # 2. The label that was just added is exactly \"run-ci\".\n    if: |\n      github.event.pull_request.head.repo.full_name != github.repository &&\n      (github.event.action == 'labeled' && github.event.label.name == 'run-ci')\n    permissions:\n      pull-requests: write\n    steps:\n      - name: Trigger CircleCI Pipeline\n        run: |\n          echo \"Forked PR #${{ github.event.pull_request.number }} has 'run-ci' label. Triggering CircleCI pipeline...\"\n\n          curl -X POST \\\n            --url \"https://circleci.com/api/v2/project/github/secretflow/scql/pipeline/run\" \\\n            --header \"Content-Type: application/json\" \\\n            --header \"Circle-Token: ${{ secrets.CCI_TOKEN }}\" \\\n            --data '{\"definition_id\":\"c6f435ca-697f-488c-83da-156862bb7392\",\"config\":{\"branch\":\"pull/${{ github.event.pull_request.number }}/head\"},\"checkout\":{\"branch\":\"pull/${{ github.event.pull_request.number }}/head\"}}'\n      - name: Remove Label from PR\n        run: |\n          echo \"Removing 'run-ci' label from PR #${{ github.event.pull_request.number }}...\"\n\n          curl -s -X DELETE \\\n            -H \"Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}\" \\\n            -H \"Accept: application/vnd.github.v3+json\" \\\n            \"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels/run-ci\"\n"
  },
  {
    "path": ".github/workflows/trigger-diff-coverage.yml",
    "content": "name: Manually Trigger Incremental Coverage Test\n\n# Use workflow_dispatch to allow manual triggering\non:\n  workflow_dispatch:\n    inputs:\n      base_commit:\n        description: 'The base Commit SHA for comparison (the older one)'\n        required: true\n      head_commit:\n        description: 'The head Commit SHA to generate coverage for (the newer one)'\n        required: true\n\njobs:\n  trigger-circleci-diff-coverage:\n    runs-on: ubuntu-latest\n    steps:\n      - name: \"Trigger CircleCI Incremental Coverage Pipeline via API\"\n        run: |\n          echo \"Triggering CircleCI pipeline for base=${{ github.event.inputs.base_commit }} and head=${{ github.event.inputs.head_commit }}...\"\n\n          curl --request POST \\\n            --url \"https://circleci.com/api/v2/project/github/secretflow/scql/pipeline/run\" \\\n            --header \"Content-Type: application/json\" \\\n            --header \"Circle-Token: ${{ secrets.CCI_TOKEN }}\" \\\n            --data '{\"definition_id\":\"f0835e5e-5836-4869-bcb6-f51ff967281d\",\"checkout\":{\"branch\":\"${{ github.event.inputs.head_commit }}\"},\"parameters\":{\"base_commit\":\"${{ github.event.inputs.base_commit }}\"},\"config\":{\"branch\":\"${{ github.event.inputs.head_commit }}\"}}'\n"
  },
  {
    "path": ".github/workflows/whitespace-check.yml",
    "content": "name: Whitespace Check\n\non:\n  pull_request:\n    types: [opened, synchronize]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  check-whitespace:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Check for whitespace issues\n        run: |\n          ./scripts/check-whitespace.sh \\\n            \"${{ github.event.pull_request.base.sha }}\" \\\n            \"$GITHUB_STEP_SUMMARY\" \\\n            \"https://github.com/${{ github.repository }}\"\n"
  },
  {
    "path": ".github/workflows/yaml-linter.yml",
    "content": "---\nname: Yaml Lint\non:\n  push:\n    branches:\n    - main\n  pull_request:\n    branches:\n    - main\npermissions:\n  contents: read\njobs:\n  yaml-linter:\n    uses: secretflow/.github/.github/workflows/yaml-linter.yml@main"
  },
  {
    "path": ".gitignore",
    "content": "# docs\ndocs/_build\n\n# bazel\n/bazel-*\n\n# go\nbin/*\ntool-bin/*\n/vendor\n\n# cloudide\n.cloudide/\n\n/compile_commands.json\n\n# clangd cache\n/external\n/.cache/\n.vscode/launch.json\n\n# Translations\n*.mo\n*.pot\n\n*.pyc\n\n.venv\n\n# 排除 ide 文件\n.idea/\n# 排除mac本地文件\n*.DS_Store\n\n# ignore bazelrc for remote cache\n.remote.bazelrc\n\n# python binding build\npython/build/\npython/package/\n"
  },
  {
    "path": ".golangci.yml",
    "content": "# This file contains all available configuration options\n# with their default values.\nversion: \"2\"\n\n# options for analysis running\nrun:\n  # default concurrency is a available CPU number\n  concurrency: 4\n\n  # timeout for analysis, e.g. 30s, 5m, default is 1m\n  timeout: 10m\n\n  # exit code when at least one issue was found, default is 1\n  issues-exit-code: 1\n\n  # include test files or not, default is true\n  tests: true\n\n  # list of build tags, all linters use it. Default is empty list.\n  build-tags: []\n\n# output configuration options\noutput:\n  # sort order\n  sort-order:\n    - linter\n    - severity\n    - file\n\n  # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is \"colored-line-number\"\n  formats:\n    text:\n      path: stdout\n      print-linter-name: true\n      print-issued-lines: true\n      colors: true\n\nissues:\n  max-same-issues: 0\n  max-issues-per-linter: 0\n\nformatters:\n  enable:\n    - gofmt\n    - goimports\n  settings:\n    gofmt:\n      # simplify code: gofmt with `-s` option, true by default\n      simplify: true\n    goimports:\n      # put imports beginning with prefix after 3rd-party packages;\n      # it's a comma-separated list of prefixes\n      local-prefixes:\n        - github.com/secretflow/scql\n\nlinters:\n  exclusions:\n    paths:\n      - _test\\.go\n      - pkg/planner\n      - pkg/parser\n      - pkg/proto-gen\n      - pkg/expression\n      - pkg/types\n      - pkg/util\n    rules:\n      - text: 'shadow: declaration of \"(err|ctx)\" shadows declaration at'\n        linters: [govet]\n  settings:\n    staticcheck:\n      # All supported checks can be enabled with \"all\".\n      # To disable checks, prefix them with a minus sign.\n      # Example: [ \"all\", \"-SA1000\", \"-SA1001\"]\n      checks: [\"all\", \"-ST1000\", \"-ST1003\", \"-ST1016\", \"-ST1020\", \"-ST1021\", \"-ST1022\", \"-QF1003\", \"-QF1006\", \"-QF1008\"]\n    gosec:\n      excludes:\n        - G115 # Potential integer overflow when converting between integer types\n        - G401 # Detect the usage of MD5 or SHA1\n        - G402 # Look for bad TLS connection settings\n        - G501 # Import blocklist: crypto/md5\n    revive:\n      rules:\n        - name: unused-parameter # disable unused-parameter rule\n          disabled: true\n    errcheck:\n      # report about not checking of errors in type assetions: `a := b.(MyStruct)`;\n      # default is false: such cases aren't reported by default.\n      check-type-assertions: false\n\n      # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;\n      # default is false: such cases aren't reported by default.\n      check-blank: false\n\n      exclude-functions:\n        - fmt.Fprintf(os.Stdout)\n        - fmt.Fprintln(os.Stdout)\n        - (*database/sql.Rows).Close # prefix is required\n        - (*os.File).Close\n        - (io.ReadCloser).Close\n        - (io.Close).Close\n        - (*google.golang.org/grpc.ClientConn).Close\n    govet:\n      # report about shadowed variables\n      enable:\n        - shadow\n    gocyclo:\n      # minimal code complexity to report, 30 by default (but we recommend 10-20)\n      min-complexity: 10\n    dupl:\n      # tokens count to trigger issue, 150 by default\n      threshold: 150\n    goconst:\n      # minimal length of string constant, 3 by default\n      min-len: 3\n      # minimal occurrences count to trigger, 3 by default\n      min-occurrences: 3\n    depguard:\n      rules:\n        main:\n          deny:\n            - pkg: \"github.com/davecgh/go-spew/spew\"\n    misspell:\n      # Correct spellings using locale preferences for US or UK.\n      # Default is to use a neutral variety of English.\n      # Setting locale to US will correct the British spelling of 'colour' to 'color'.\n      locale: US\n      ignore-rules:\n        - someword\n    lll:\n      # max line length, lines longer will be reported. Default is 120.\n      # '\\t' is counted as 1 character by default, and can be changed with the tab-width option\n      line-length: 120\n      # tab width in spaces. Default to 1.\n      tab-width: 1\n    unused:\n      parameters-are-used: true\n      exported-fields-are-used: true\n    unparam:\n      # Inspect exported functions, default is false. Set to true if no external program/library imports your code.\n      # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:\n      # if it's called for subdir of a project it can't find external interfaces. All text editor integrations\n      # with golangci-lint call it on a directory with the changed file.\n      check-exported: false\n    nakedret:\n      # make an issue if func has more lines of code than this setting and it has naked returns; default is 30\n      max-func-lines: 30\n    prealloc:\n      # XXX: we don't recommend using this linter before doing performance profiling.\n      # For most programs usage of prealloc will be a premature optimization.\n\n      # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.\n      # True by default.\n      simple: true\n      range-loops: true # Report preallocation suggestions on range loops, true by default\n      for-loops: false # Report preallocation suggestions on for loops, false by default\n    gocritic:\n      # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty\n      disabled-checks:\n        - regexpMust\n\n      # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint` run to see all tags and checks.\n      # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section \"Tags\".\n      enabled-tags:\n        - performance\n\n      settings: # settings passed to gocritic\n        captLocal: # must be valid enabled check name\n          paramsOnly: true\n  enable:\n    - unused\n    - govet\n    - revive\n    - errcheck\n    - goconst\n    - dupl\n    # - gosec\n    - staticcheck\n    - bodyclose\n  default: none\n"
  },
  {
    "path": ".licenserc.yaml",
    "content": "header:\n  license:\n    spdx-id: Apache-2.0\n    copyright-owner: Ant Group Co., Ltd.\n    copyright-year: auto\n    software-name: secretflow\n\n    pattern: |\n      Licensed under the Apache License, Version 2.0 \\(the \"License\"\\);\n      you may not use this file except in compliance with the License.\n      You may obtain a copy of the License at\n\n          http[s]?://www\\.apache\\.org/licenses/LICENSE-2\\.0\n\n      Unless required by applicable law or agreed to in writing, software\n      distributed under the License is distributed on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n      See the License for the specific language governing permissions and\n      limitations under the License.\n\n  paths:\n    - \"**\"\n\n  paths-ignore:\n    - \".aci\"\n    - \".ci\"\n    - \".circleci\"\n    - \".github\"\n    - \".vscode\"\n    - \"benchmark/docker-compose/broker\"\n    - \"benchmark/docker-compose/engine\"\n    - \"benchmark/docker-compose/mysql\"\n    - \"benchmark/testdata\"\n    - \"contrib/agent/kusciastub/mock_kusciaapi/mock_kusciaapi.go\"\n    - \"docs/_static\"\n    - \"docs/imgs\"\n    - \"examples\"\n    - \"pkg/executor/engine_stub_mock.go\"\n    - \"pkg/expression\"\n    - \"pkg/infoschema\"\n    - \"pkg/parser\"\n    - \"pkg/planner/core\"\n    - \"pkg/planner/property\"\n    - \"pkg/planner/util/path.go\"\n    - \"pkg/privilege\"\n    - \"pkg/sessionctx\"\n    - \"pkg/table\"\n    - \"pkg/types\"\n    - \"pkg/util/chunk\"\n    - \"pkg/util/codec\"\n    - \"pkg/util/execdetails\"\n    - \"pkg/util/hack\"\n    - \"pkg/util/math\"\n    - \"pkg/util/mathutil\"\n    - \"pkg/util/misc.go\"\n    - \"pkg/util/mvmap\"\n    - \"pkg/util/plancodec\"\n    - \"pkg/util/ranger\"\n    - \"pkg/util/stringutil\"\n    - \"pkg/util/testleak\"\n    - \"pkg/util/testutil\"\n    - \"pkg/util/texttree\"\n    - \"scripts\"\n    - \"**/*.template\"\n    - \"**/*.patch\"\n    - \"**/*.pb.go\"\n    - \"**/*.md\"\n    - \"**/*.json\"\n    - \"**/*.yaml\"\n    - \"**/*.yml\"\n    - \"**/*.txt\"\n    - \"**/*.Dockerfile\"\n    - \"**/Dockerfile\"\n    - \"**/*.po\"\n    - \"**/*.svg\"\n    - \"**/*.bat\"\n    - \"**/*.rst\"\n    - \"**/*.patch\"\n    - \"**/*.csv\"\n    - \"**/*.tmpl\"\n    - \"LICENSE\"\n    - \"NOTICE\"\n    - \"MODULE.bazel.lock\"\n    - \".bazeliskrc\"\n    - \".bazelrc\"\n    - \".clang-format\"\n    - \".clang-tidy\"\n    - \"**/.gitignore\"\n    - \"**/.env\"\n    - \"go.mod\"\n    - \"go.sum\"\n    - \"**/Makefile\"\n\n  comment: never\n\n  license-location-threshold: 80\n\n  language:\n    Starlark:\n      extensions:\n        - \".bazel\"\n        - \".bazelrc\"\n        - \"BUILD\"\n        - \".bzl\"\n        - \"WORKSPACE\"\n      comment_style_id: PythonStyle\n    Cpp:\n      extensions:\n        - \".cc\"\n        - \".h\"\n        - \".cu\"\n      comment_style_id: DoubleSlash\n    Python:\n      extensions:\n        - \".py\"\n      comment_style_id: PythonStyle\n"
  },
  {
    "path": ".markdownlint.yaml",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Enable all markdownlint rules by default\ndefault: true\nMD013: false # line-length Line length\nMD024: false # no-duplicate-heading Multiple headings with the same content\n\n# List formatting:\n#\n# 1. Lists must have a blank line before AND after the list.\n# 2. Lists start aligned to the left (do not indent the top level list items).\n#    NOTE: markdownlint currently checks indentation for unordered lists only.\n#          Please manually verify that your ordered lists are not indented.\n#          See https://github.com/DavidAnson/markdownlint/issues/138.\n# 3. You may use one or zero blank lines between list items.\n# 4. Nested list items should be indented to align with the first character of\n#    the first line. For bullet lists, that means 2 spaces. For numbered\n#    lists, that's 3 spaces (but 4 spaces is okay if that's easier).\n# 5. In multiline list items, subsequent lines are indented by 2 spaces.\n#    This is not checked automatically, so we're documenting this convention\n#    to make sure the codebase stays consistent.\n#\n# Examples:\n#\n# * This is a list item that has multiple\n#   lines and each line aligns with the text from the first line.\n#   * This is a nested list, also aligned with the first line.\n#\n# For ordered lists, that means three spaces for wrapped lines:\n#\n# 1. This is an ordered list item.\n#    1. The nested list aligns with the first line.\nul-indent:\n  indent: 2\n\n# Allow inline HTML\nno-inline-html: false\n\n# Allow dupe heading names only if they're not siblings\nno-duplicate-heading:\n  siblings_only: true\n\n# Allow images w/o alt-text\nno-alt-text: false"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n  - repo: https://github.com/gitleaks/gitleaks\n    rev: v8.24.0\n    hooks:\n      - id: gitleaks\n  - repo: https://github.com/golangci/golangci-lint\n    rev: v2.0.0\n    hooks:\n      - id: golangci-lint\n  - repo: https://github.com/jumanjihouse/pre-commit-hooks\n    rev: 3.0.0\n    hooks:\n      - id: shellcheck\n  - repo: https://github.com/pocc/pre-commit-hooks\n    rev: v1.3.5\n    hooks:\n      - id: cpplint\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v4.4.0\n    hooks:\n      - id: end-of-file-fixer\n      - id: trailing-whitespace\n  - repo: https://github.com/pylint-dev/pylint\n    rev: v2.17.2\n    hooks:\n      - id: pylint\n"
  },
  {
    "path": ".vscode/cspell.json",
    "content": "// cSpell Settings\n{\n  // Version of the setting file.  Always 0.2\n  \"version\": \"0.2\",\n  // language - current active spelling language\n  \"language\": \"en\",\n  // words - list of words to be always considered correct\n  \"words\": [\n    \"brokerctl\",\n    \"gorm\",\n    \"Kuscia\",\n    \"kusciaapi\",\n    \"protojson\",\n    \"quickstart\",\n    \"scql\",\n    \"scqlengine\",\n    \"secretflow\",\n    \"spu\",\n    \"varchar\"\n  ]\n}\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n    \"recommendations\": [\n        \"BazelBuild.vscode-bazel\",\n        \"eamodio.gitlens\",\n        \"golang.go\",\n        \"ms-python.python\",\n        \"ms-vscode.cpptools\",\n        \"jgclark.vscode-todo-highlight\",\n        \"ms-vscode-remote.remote-ssh\",\n        \"drblury.protobuf-vsc\",\n        \"llvm-vs-code-extensions.vscode-clangd\",\n        \"lextudio.restructuredtext\",\n        \"bufbuild.vscode-buf\"\n    ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"editor.formatOnSave\": true,\n    \"gopls\": {\n        \"formatting.local\": \"github.com/secretflow/scql\"\n    },\n    \"[python]\": {\n        \"editor.defaultFormatter\": \"ms-python.black-formatter\"\n    },\n    \"files.watcherExclude\": {\n        \"**/.git/**\": true,\n        \"**/.cache/**\": true,\n        \"**/bazel-*/**\": true,\n        \"**/external/**\": true\n    },\n    \"files.insertFinalNewline\": true,\n    \"files.trimTrailingWhitespace\": true,\n    \"[proto]\": {\n        \"editor.defaultFormatter\": \"bufbuild.vscode-buf\",\n        \"editor.formatOnSave\": true\n    }\n}\n"
  },
  {
    "path": "BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## Types of changes\n\n`Added` for new features.\n`Changed` for changes in existing functionality.\n`Deprecated` for soon-to-be removed features.\n`Removed` for now removed features.\n`Fixed` for any bug fixes.\n`Security` in case of vulnerabilities.\n\n## Staging\n\n## [2.0.0] - 2026-03-16\n\n### Added\n\n- Introduced SCQL 2.0 OpenCore architecture: new `CompilerService` gRPC API (`api/v1alpha1/compiler.proto`) with `CompileSQL` endpoint, and a new Go compiler package (`pkg/interpreter/compiler/`) replacing the old interpreter pipeline.\n- Added Perfetto-based tracing support in engine, controlled by `--enable_trace` and `--trace_log_path` flags.\n- Added `GroupSecretSum` and `GroupSecretAvg` operators using SPU secret-sharing, replacing the old HE-based group aggregation. Benchmarks show the new algorithm is 5-10x faster.\n- Added planner optimization rules: correlated subquery decorrelation, group-by threshold enforcement, `JOIN` reorder by party code, and consecutive selection merging.\n- Added `Rr22Mode` (low/fast) for PSI algorithm negotiation.\n- Added `opencore-demo` example and quickstart documentation for getting started with the new architecture.\n\n### Changed\n\n- **breaking**: Redesigned system architecture from Broker-based (P2P/Centralized) to native Compiler + Engine integration.\n- **breaking**: `Executor.RunExecutionPlan()` now returns `*scql.QueryResponse` instead of `*scql.SCDBQueryResultResponse`.\n- Refactored engine operators to use typed `ExecContext` accessor methods (`GetInputTensor()`, `SetOutputTensor()`, etc.) instead of manual tensor table lookups.\n- Refactored session negotiation: new `Session::Negotiate()` method handles streaming options, PSI options, and curve types via protobuf-serialized `NegotiationOptions`.\n- Consolidated `StreamingOptions` into `SessionOptions`.\n- Extracted `RunPlanCore` from `EngineServiceImpl` into a standalone function for reuse in both RPC and task modes.\n- Updated documentation to reflect the OpenCore architecture.\n\n### Removed\n\n- Removed SCDB centralized query server (`pkg/scdb/`, `cmd/scdbserver/`, `cmd/scdbclient/`, `api/scdb_api.proto`).\n- Removed Broker P2P coordination layer (`pkg/broker/`, `cmd/broker/`, `cmd/brokerctl/`, `api/broker.proto`).\n- Removed CCL (Column Control Language) authorization mechanism (`api/ccl.proto`, `pkg/interpreter/ccl/`).\n- Removed old interpreter/translator pipeline (`pkg/interpreter/translator/`, `pkg/interpreter/interpreter.go`, `pkg/interpreter/svc/`).\n- Removed `cmd/regtest/`, `cmd/agent/`, `cmd/scqltool/`, `pkg/privilege/`, `pkg/executor/job_watcher.go`.\n- Removed `GroupHESum` operator (replaced by `GroupSecretSum`/`GroupSecretAvg`).\n- Removed all legacy deployment guides, API references, CCL docs, and CI infrastructure for removed components.\n\n### Fixed\n\n- Fixed communication stats not accounting for initialization-phase network traffic.\n- Fixed potential async task lifecycle issues in `RunPlanSync` by switching from `std::async` to direct invocation.\n- Fixed null handling in window function, placing null values at the end.\n- Fixed missing `DESC` keyword when rebuilding ORDER BY statement.\n- Fixed interpreter creation time losing timezone information.\n\n## [0.9.4] - 2025-07-29\n\n### Added\n\n- Added Archive API to support project archiving.\n- Enhanced time-type data processing capability: support `STR_TO_DATE` function and implicit conversion from string to time types.\n- Supported richer expression of statements: `PERCENTILE_DISC`, `BETWEEN AND`, `REPLACE`, etc.\n\n### Changed\n\n- Optimized data source reading, improving streaming processing capabilities.\n- Optimized `JOIN` process to eliminate the need for additional `PLAINTEXT_AFTER_JOIN` CCL for non-result-receiving parties on join keys.\n\n### Fixed\n\n- Resolved the issue with compare subquery exceptions in aggregation scenarios.\n- Fixed column disorder issues in the project tables.\n- Resolved problems in LogicalOptimizer to prevent the removal of LogicalProjection nodes that could lead to performance and Tensor property inference issues.\n\n## [0.9.3] - 2025-03-07\n\n### Added\n\n- Support for datasource `Doris 2.1.7`.\n- Support `PERCENT_RANK` window function.\n- Support various string-related single-party operators, including `UPPER`, `LOWER`, `SUBSTRING`, `TRIM`, `CONCAT` and others.\n- Support `Scalar Subquery`, the subquery in the right is scalar value, e.g. SELECT * FROM ta JOIN tb ON ta.ID = tb.ID WHERE ta.salary > (SELECT AVG(ta.salary) FROM ta).\n- Support `Compare Subquery`, allows comparison with ANY or ALL of the subquery results, e.g. SELECT * FROM ta JOIN tb ON ta.ID = tb.ID WHERE ta.salary > ANY(SELECT ta.salary FROM ta), However, comparisons using = or != are not supported in the HAVING clause. For instance, HAVING SUM(ta.salary) = ANY(SELECT salary FROM ta) is not supported.\n\n### Changed\n\n- Improved `JOIN` and `IN` performance in streaming mode.\n- Implemented a more reliable `secret join algorithm`(only works in SEMI2K protocol) inspired by [Scape](https://ieeexplore.ieee.org/document/9835540/).\n- Optimized the column pruning rule for Join, Selection, and Window nodes in the Logical Optimizer to more effectively remove redundant columns.\n\n### Fixed\n\n- Restricted access to SCQLEngine metrics using additional paths like \"engine_ip:engine_port/metrics/additional/path\".\n- Prevented creation of tables with the same ref_table name but different db_type\n- Fixed job creation error when selecting 'OPRF-PSI' but 'server hint' was missing.\n\n## [0.9.2] - 2024-12-23\n\n### Added\n\n- Enhancement: Support `JOIN` after `UNION` operation.\n- Add SCQL Agent to facilitate running SCQL query tasks in Kuscia, making it easier to integrate into SecretPad.\n- Support writing results into multi-parties via `SELECT INTO OUTFILE` syntax.\n- Support datasource `ODPS` via integrating with [dataproxy](https://github.com/secretflow/dataproxy).\n- Support `order by`.\n- Support a lot of single-party operators, such as `ABS`, `ASIN`, `EXP`, `FLOOR`, `SQRT` etc.\n\n### Changed\n\n- Improve the `JOIN` and `IN` performance via integrating [RR22 PSI](https://github.com/secretflow/psi/blob/v0.5.0b0/psi/proto/psi_v2.proto#L62).\n- Improve the aggregation with group by performance if `reveal_group_count` enabled.\n\n### Fixed\n\n- Fixed an occasional crash issue when canceling query job.\n- Fixed `select now()` is not supported issue.\n\n## [0.9.1] - 2024-10-16\n\n### Added\n\n- Support window function `ROW_NUMBER()` with PARTITION BY clause and ORDER BY clause.\n- Add new CCL constraint `REVAL_RANK`.\n- Add ExplainQuery API with path `/intra/query/explain`.\n- Support `INSERT INTO SELECT` syntax to allow writing query result back to db (mysql/sqlite/postgres).\n- Support `trim` function.\n\n### Changed\n\n- Improved the job watcher to work better in broker clustered mode.\n\n## [0.9.0] - 2024-08-01\n\n### Added\n\n- Support write outfile to OSS/MINIO via `select into` query.\n- Support `sin`, `cos`, `acos` function.\n- Support `geodist` function.\n- Broker support using postgres as metadata storage.\n\n### Changed\n\n- Reduce the memory peak of large-scale intersection tasks through streaming execution.\n- Link tcmalloc to solve the problem of memory increase.\n\n### Fixed\n\n- Fix crashes when dumpfile exceeds 2GB string column.\n- Reduce the probability of graph checksum inconsistency issues.\n\n## [0.8.1] - 2024-07-02\n\n### Added\n\n- Support session-based log isolation functioality in the SCQL Engine.\n- Support consul-based broker registration/discovery services, providing ACL/TLS authentication.\n\n### Changed\n\n### Fixed\n\n## [0.8.0] - 2024-06-12\n\n### Added\n\n- Enhanced `FetchResult` RPC and `brokerctl get result` command to report job progress when result is not ready.\n- Support project/query level configs\n- Support NULL for private data: including Arithmetic, Logic, Aggregation, etc., {IS [NOT] NULL, IFNULL, COALESCE} are also supported.\n- Support port isolation for engine link service and control panel service (RunExecutionPlan).\n- Add new CCL constraint `PLAINTEXT_AS_JOIN_PAYLOAD`.\n\n### Changed\n\n- **breaking**: The response value type of Broker API `DoQuery` and `FetchResult` have incompatible changes.\n\n### Fixed\n\n## [0.7.0] - 2024-05-14\n\n### Added\n\n- Added CheckAndUpdate API for self-recovery when status is inconsistent in P2P mode.\n\n### Fixed\n\n- Fixed the problem that Broker was unable to detect SCQLEngine crashes or being killed by OOM.\n\n## [0.6.0] - 2024-04-15\n\n### Added\n\n- Support for RSA key pairs in SCQLBroker.\n- Support running on [kuscia](https://github.com/secretflow/kuscia) and scheduling SCQLEngine dynamic via kuscia job.\n- Added `dry_run` parameter in DoQuery request, it could be used to check query syntax and CCL without actually executing the query.\n- Improve Broker high availability, support deploying in multi-node cluster deployment.\n- Support reading csv from OSS/MINIO.\n\n### Changed\n\n- **breaking**: Reshape column data type, data type `LONG` is deprecated.\n- **breaking**: Modify table schema in broker storage for P2P mode.\n\n## [0.5.0] - 2024-01-10\n\n### Added\n\n- Added support for HTTP data source router.\n\n### Changed\n\n- **breaking**: Add table **members** in broker storage for P2P mode.\n- Speed up GROUP BY with Radix Sort.\n- Adjusted configuration items for SCQLEngine and SCQLBroker.\n\n### Fixed\n\n- Fixed check for grant ccl in P2P mode.\n\n## [0.4.0] - 2023-11-15\n\n### Added\n\n- Added support for P2P mode, no longer need to rely on a trusted third party.\n- Added support for {datetime, timestamp} data types, as well as related operations.\n- Support using ArrowSQL as a data source for Engine\n- Added support for {Limit Cast Mod} operators.\n\n### Changed\n\n- Polished document outline.\n\n## [0.3.0] - 2023-09-10\n\n### Added\n\n- Optimize SCQLEngine memory usage, release unused tensors immediately.\n- Added warning information to the query result.\n- Added support for {LEFT JOIN, RIGHT JOIN, CASE WHEN, IF} operators\n\n### Changed\n\n- Speed up GROUP BY with HEU in some scenarios.\n- Optimized to support billion-level PSI scenarios.\n- Drop GRM from SCQL awareness. We extend the syntax of create user statement and modify the syntax of create table statement.\n- Used json string format to configure spu runtime in scdb yaml conf.\n- Speed up JOIN, IN with Unbalanced PSI in scenarios with unbalanced data.\n\n## [0.2.0] - 2023-06-30\n\n### Added\n\n- Added support for union operator.\n- Added support for reading CSV files as a data source for Engine.\n- Added support for using PostgreSQL as a database for Engine.\n- Added support for change password with ALTER USER statement.\n- Added support for removing table-level and database-level permissions with the REVOKE statement.\n- Added support for structured audit log.\n- Added support for the float64 data type in the Engine.\n- Added the Chinese documentation.\n\n### Changed\n\n- Change some description in document.\n- Enrich test cases.\n- Enhanced support for security protocols of Cheetah and ABY3.\n- Optimized GROUP BY logic.\n- Optimized execution plan nodes.\n- Optimized the execution logic of the runSQL.\n- Optimized the three party ccl in join node.\n\n### Fixed\n\n- Fixed create database failed [#19](https://github.com/secretflow/scql/issues/19).\n- Fixed not support group by string[#48](https://github.com/secretflow/scql/pull/48).\n\n## [0.1.0] - 2023-03-28\n\n### Added\n\n- SCQL init release\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\n## Contributor License Agreement\n\nContributions to this project must be accompanied by a Contributor License\nAgreement. You (or your employer) retain the copyright to your contribution;\nthis simply gives us permission to use and redistribute your contributions as\npart of the project.\n\n## Repo layout\n\n- Please see [repo layout](REPO_LAYOUT.md).\n\n## Style\n\n### Go coding style\n\nGo code follows [Uber Go Style Guide](https://github.com/uber-go/guide/blob/master/style.md)\n\n### C++ coding style\n\nIn general, please use clang-format to format code, and follow clang-tidy tips.\n\nMost of the code style is derived from the [Google C++ style guidelines](https://google.github.io/styleguide/cppguide.html), except:\n\n- Exceptions are allowed and encouraged where appropriate.\n- Header guards should use `#pragma once`.\n\n### Other tips\n\n- Git commit message should be meaningful, we suggest imperative [keywords](https://github.com/joelparkerhenderson/git_commit_message#summary-keywords).\n- Developer must write unit-test (line coverage must be greater than 80%), tests should be deterministic.\n\n## Build\n\n### Prerequisite\n\n#### Docker\n\n\n```sh\n## start dev container\ndocker run -d -it --name scql-dev-$(whoami) \\\n         --mount type=bind,source=\"$(pwd)\",target=/home/admin/dev/ \\\n         -w /home/admin/dev \\\n         --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \\\n         --cap-add=NET_ADMIN \\\n         --privileged=true \\\n         secretflow/scql-ci:latest /bin/bash\n\n# attach to dev container\ndocker exec -it scql-dev-$(whoami) bash\n```\n\n### Build & UnitTest\n\n\n\n\n```sh\n\n# build SCQL engine as release\nbazelisk build //engine/exe:scqlengine -c opt\n\n# run unittests for SCQL engine\nbazelisk test //engine/...\n\n# build with address sanitizer\nbazelisk build --config=asan //engine/exe:scqlengine\n\n# build go code\nmake\n\n# run go unit tests\ngo test ./pkg/...\n```\n\n### Build docs\n\n```sh\n# prerequisite\npip3 install -U -r docs/requirements.txt\n\n# Build HTML docs, and the result is placed in directory 'docs/_build/html'\n# Build documentation in English and Chinese\nmake doc\n```\n"
  },
  {
    "path": "LEGAL.md",
    "content": "# Legal Disclaimer\n\nWithin this source code, the comments in Chinese shall be the original, governing version. Any comment in other languages are for reference only. In the event of any conflict between the Chinese language version comments and other language version comments, the Chinese language version shall prevail.\n\n法律免责声明\n\n关于代码注释部分，中文注释为官方版本，其它语言注释仅做参考。中文注释可能与其它语言注释存在不一致，当中文注释与其它语言注释存在不一致时，请以中文注释为准。\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "MODULE.bazel",
    "content": "# Copyright 2024 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nmodule(\n    name = \"scql\",\n    version = \"0.9.5dev\",\n    compatibility_level = 1,\n)\n\nbazel_dep(name = \"yacl\", version = \"0.4.5b12-nightly-20251024\")\nbazel_dep(name = \"psi\", version = \"0.6.0.dev250922\")\nbazel_dep(name = \"spulib\", version = \"0.9.5rc1\")\ngit_override(\n    module_name = \"spulib\",\n    commit = \"2387c999a4bd2b7e85072f4e25a173a60b5958d4\",\n    remote = \"https://github.com/secretflow/spu.git\",\n    strip_prefix = \"src\",\n)\n\nbazel_dep(name = \"dataproxy_sdk_cc\", version = \"0.5.0.dev20250603\")\nbazel_dep(name = \"kuscia\", version = \"0.13.0b1\")\nbazel_dep(name = \"apple_support\", version = \"1.24.5\")\nbazel_dep(name = \"rules_cuda\", version = \"0.2.3\")\nbazel_dep(name = \"rules_cc\", version = \"0.0.12\")\nbazel_dep(name = \"rules_proto\", version = \"6.0.2\")\n\n# non module dependencies\nnon_module_dependencies = use_extension(\"//bazel:defs.bzl\", \"non_module_dependencies\")\nuse_repo(\n    non_module_dependencies,\n    \"com_github_duckdb\",\n    \"com_github_gperftools_gperftools\",\n    \"org_pocoproject_poco\",\n)\n\nbazel_dep(name = \"arrow\", version = \"17.0.0.bcr.1\", repo_name = \"org_apache_arrow\")\nbazel_dep(name = \"ncurses\", version = \"6.4.20221231.bcr.3\")\nbazel_dep(name = \"rules_pkg\", version = \"1.0.1\")\nbazel_dep(name = \"rules_java\", version = \"8.6.1\")\nbazel_dep(name = \"rules_go\", version = \"0.53.0\")\nbazel_dep(name = \"rules_proto_grpc_cpp\", version = \"5.0.1\")\nbazel_dep(name = \"rules_foreign_cc\", version = \"0.15.0\")\nsingle_version_override(\n    module_name = \"rules_foreign_cc\",\n    patch_strip = 1,\n    patches = [\n        \"//bazel/patches:rules_foreign_cc.patch\",\n    ],\n    version = \"0.15.0\",\n)\n\nbazel_dep(name = \"bazel_features\", version = \"1.20.0\")\nbazel_dep(name = \"platforms\", version = \"0.0.8\")\nbazel_dep(name = \"openssl\", version = \"3.3.2.bcr.1\")\nbazel_dep(name = \"spdlog\", version = \"1.14.1\")\nbazel_dep(name = \"fmt\", version = \"11.0.2\")\nbazel_dep(name = \"brpc\", version = \"1.13.0\")\nbazel_dep(name = \"abseil-cpp\", version = \"20240722.0\")\nbazel_dep(name = \"boost.uuid\", version = \"1.83.0.bcr.1\")\nbazel_dep(name = \"boost.multiprecision\", version = \"1.83.0\")\nbazel_dep(name = \"boost.endian\", version = \"1.83.0\")\nbazel_dep(name = \"boost.geometry\", version = \"1.83.0\")\nbazel_dep(name = \"boost.graph\", version = \"1.83.0\")\nbazel_dep(name = \"boost.spirit\", version = \"1.83.0\")\nbazel_dep(name = \"bazel_skylib\", version = \"1.7.1\")\nbazel_dep(name = \"boost.serialization\", version = \"1.83.0.bcr.1\")\nbazel_dep(name = \"prometheus-cpp\", version = \"1.2.4\")\nbazel_dep(name = \"protobuf\", version = \"27.3\", repo_name = \"com_google_protobuf\")\nsingle_version_override(\n    module_name = \"protobuf\",\n    version = \"27.3\",\n)\n\nbazel_dep(name = \"perfetto\", version = \"41.0\")\nbazel_dep(name = \"googleapis\", version = \"0.0.0-20240819-fe8ba054a\")\nbazel_dep(name = \"zlib\", version = \"1.3.1.bcr.3\")\nbazel_dep(name = \"rules_python\", version = \"0.34.0\")\nbazel_dep(name = \"gflags\", version = \"2.2.2\")\nbazel_dep(name = \"msgpack-c\", version = \"6.1.0\")\nbazel_dep(name = \"grpc\", version = \"1.66.0.bcr.4\")\nbazel_dep(name = \"pybind11_bazel\", version = \"3.0.0\")\n\nsingle_version_override(\n    module_name = \"grpc\",\n    version = \"1.66.0.bcr.4\",\n)\n\nsingle_version_override(\n    module_name = \"openssl\",\n    version = \"3.3.2.bcr.1\",\n)\n\n# use sf.bcr\nbazel_dep(name = \"curl\", version = \"8.4.0.bcr.2\")\nsingle_version_override(\n    module_name = \"curl\",\n    version = \"8.4.0.bcr.2\",\n)\n\nnew_local_repository = use_repo_rule(\"@bazel_tools//tools/build_defs/repo:local.bzl\", \"new_local_repository\")\n\nnew_local_repository(\n    name = \"macos_omp_x64\",\n    build_file = \"@yacl//bazel:local_openmp_macos.BUILD\",\n    path = \"/usr/local/opt/libomp\",\n)\n\nnew_local_repository(\n    name = \"macos_omp_arm64\",\n    build_file = \"@yacl//bazel:local_openmp_macos.BUILD\",\n    path = \"/opt/homebrew/opt/libomp/\",\n)\n\npython = use_extension(\"@rules_python//python/extensions:python.bzl\", \"python\")\npython.toolchain(\n    ignore_root_user_error = True,\n    python_version = \"3.11\",\n)\n\n# test\nbazel_dep(name = \"googletest\", version = \"1.15.2\", dev_dependency = True)\nbazel_dep(name = \"google_benchmark\", version = \"1.8.5\", dev_dependency = True)\nbazel_dep(name = \"rules_buf\", version = \"0.4.0\")\n"
  },
  {
    "path": "Makefile",
    "content": "export GO111MODULE=on\nGOPATH := ${GOPATH}:${PWD}\nTOOLBIN := ${PWD}/tool-bin\nexport PATH := ${TOOLBIN}:$(PATH)\nexport GOFLAGS=-buildmode=pie -buildvcs=false\nexport CGO_CPPFLAGS=-fstack-protector-strong -D_FORTIFY_SOURCE=2\nUNAME_S := $(shell uname -s)\nifeq ($(UNAME_S),Linux)\n\texport CGO_LDFLAGS=-Wl,-z,relro,-z,now,-z,noexecstack\nendif\n\n.PHONY: clean vet lint test detect-shadowing fast pb prepare fmt gogenerate\n\ndefault: install\n\ninstall: clean prepare fmt vet gogenerate\n\tGOBIN=${PWD}/bin go install -ldflags \"-X main.version=${SCQL_VERSION}\" ./cmd/...\n\ngogenerate:\n\tgo generate ./pkg/...\n\tgo generate ./cmd/...\n\nfast: fmt vet\n\tGOBIN=${PWD}/bin go install ./cmd/...\n\nparser:\n\tcd pkg/parser && make\n\nbinary: clean prepare fmt vet gogenerate\n\t$(eval SCQL_VERSION := $(shell bash ${PWD}/version_build.sh))\n\techo \"Binary version: ${SCQL_VERSION}\"\n\tGOBIN=${PWD}/bin go install -ldflags \"-X main.version=${SCQL_VERSION}\" ./cmd/...\n\tbazelisk --host_jvm_args=-Xmx8g build //engine/exe:scqlengine -c opt --jobs=32\n\tbash ${PWD}/version_build.sh -r\n\nbinary-cov: clean prepare fmt vet gogenerate\n\t$(eval SCQL_VERSION := $(shell bash ${PWD}/version_build.sh))\n\techo \"Binary version: ${SCQL_VERSION}\"\n\tGOBIN=${PWD}/bin go install -ldflags \"-X main.version=${SCQL_VERSION}\" -cover ./...\n\tbazelisk --host_jvm_args=-Xmx8g build //engine/exe:scqlengine --jobs=32 --collect_code_coverage --instrumentation_filter=//engine/... --noremote_upload_local_results --copt=-DNDEBUG\n\tbash ${PWD}/version_build.sh -r\n\npb: clean\n\t$(RM) -rf pkg/proto-gen/*\n\t./api/generate_proto.sh\n\nfmt:\n\tgo fmt ./pkg/...\n\nvet:\n\tgo vet -unsafeptr=false ./pkg/...\n\ndoc:\n\tgo run ./cmd/docgen/main.go\n\tcd docs && rm -rf _build && make build\n\nlint: GOLINT-exists\n\t-${TOOLBIN}/golangci-lint run --out-format=colored-line-number\n\ndetect-shadowing:\n\tgo vet -vettool=$(shell which shadow) -strict ./...\n\nclean:\n\t$(RM) bin/*\n\t$(RM) *.coverprofile\n\ntest:\n\tgo test -v -cover ./pkg/...\n\ntestsum:\n\tgo run gotest.tools/gotestsum@latest ./pkg/...\n\ncoverage: install\n\tgo list -f '{{if gt (len .TestGoFiles) 0}}\"go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}\"{{end}}' ./... | xargs -I {} bash -c {}\n\tfind . -name \"*.coverprofile\"\n\t$(info Use `go tool cover -html MODULE_NAME.coverprofile`)\n\nprepare: GO-exists GO-package\n\nGO-exists:\n\t$(if $(shell command -v go 2> /dev/null),$(info Found `go`),$(error Please install go (prefer v1.22): refer to `https://golang.org/dl/`))\n\tgo version\n\tgo env GOPROXY\n\nGOLINT-exists:\n\t$(if $(shell command -v golangci-lint 2> /dev/null),$(info Found `golangci-lint`),$(shell curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b ${TOOLBIN} v1.61.0))\n\nGO-package:\n\t@GOBIN=${TOOLBIN} go install go.uber.org/mock/mockgen@latest && \\\n\tGOBIN=${TOOLBIN} go install golang.org/x/tools/cmd/goyacc@latest && \\\n\tGOBIN=${TOOLBIN} go install github.com/mattn/goveralls@latest && \\\n\tGOBIN=${TOOLBIN} go install github.com/rakyll/gotest@latest && \\\n\tGOBIN=${TOOLBIN} go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest\n"
  },
  {
    "path": "README.md",
    "content": "# SCQL\n\n[![CircleCI](https://dl.circleci.com/status-badge/img/gh/secretflow/scql/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/secretflow/scql/tree/main)\n\nSecure Collaborative Query Language (SCQL) is a system that translates SQL statements into Secure Multiparty Computation (SMC) primitives and executes them on a federation of database systems.\n\n> **Note**: If you are looking for SCQL 1.0, please check the [1.x branch](https://github.com/secretflow/scql/tree/release/1.x).\n\n![SCQL Workflow](./docs/imgs/scql_workflow.png)\n\n## Documentation\n\n- [Documentation in English](https://www.secretflow.org.cn/en/docs/scql)\n- [中文文档](https://www.secretflow.org.cn/zh-CN/docs/scql/)\n\n## Docker Image Release\n\n- Official release docker image: [secretflow/scql](https://hub.docker.com/r/secretflow/scql/tags)\n- We also have images at Alibaba Cloud: secretflow-registry.cn-hangzhou.cr.aliyuncs.com/secretflow/scql:[tag]\n\n## Contribution Guidelines\n\nIf you would like to contribute to SCQL, please see the [Contribution guidelines](CONTRIBUTING.md).\n\nThis documentation also contains instructions for [build and testing](CONTRIBUTING.md#build)\n\n## Hardware Requirements\n\nThe following requirements only apply to SCQLEngine.\n\n- CPU\n  - x86_64: minimum required AVX instruction set. For FourQ based PSI, the AVX2 instruction set is required.\n\n## Disclaimer\n\nNon-release versions of SCQL are prohibited to use in any production environment due to possible bugs, glitches, lack of functionality, security issues or other problems.\n\n## Citing SCQL\n\nIf you think SCQL is helpful for your research or development, please consider citing our [paper](https://www.vldb.org/pvldb/vol17/p3987-fang.pdf):\n\n```text\n@article{scql,\n  author       = {Wenjing Fang and\n                  Shunde Cao and\n                  Guojin Hua and\n                  Junming Ma and\n                  Yongqiang Yu and\n                  Qunshan Huang and\n                  Jun Feng and\n                  Jin Tan and\n                  Xiaopeng Zan and\n                  Pu Duan and\n                  Yang Yang and\n                  Li Wang and\n                  Ke Zhang and\n                  Lei Wang},\n  title        = {SecretFlow-SCQL: {A} Secure Collaborative Query pLatform},\n  journal      = {Proc. VLDB Endow.},\n  volume       = {17},\n  number       = {12},\n  pages        = {3987--4000},\n  year         = {2024},\n  url          = {https://www.vldb.org/pvldb/vol17/p3987-fang.pdf},\n}\n```\n\n## Acknowledgments\n\n- Thanks [TiDB](https://github.com/pingcap/tidb) for providing a powerful SQL parser and planner.\n"
  },
  {
    "path": "REPO_LAYOUT.md",
    "content": "# Repository Layout\n\n- [api/](api/): SCQL protocol files.\n- [examples/](examples/): SCQL examples.\n  - [tutorial](examples/tutorial/): SCQL open core tutorial.\n- [docs/](docs/): Documents of SCQL.\n- [cmd/](cmd/): Main applications for SCQL.\n  - [docgen/](cmd/docgen/): SCQL operators document generator.\n- [pkg/](pkg/): SCQL library code.\n  - [constant/](pkg/constant/): Common constant values.\n  - [parser/](pkg/parser/): SCQL parser.\n  - [types/](pkg/types/): SCQL data types.\n  - [table/](pkg/table/): SCQL table info.\n  - [sessionctx/](pkg/sessionctx/): SCQL logical plan context.\n  - [util/](pkg/util/): SCQL utils.\n  - [planner/](pkg/planner/): SCQL planner.\n  - [interpreter/](pkg/interpreter/): SCQL interpreter.\n    - [compiler/](pkg/interpreter/compiler/): SCQL compiler that translates SQL to execution graph.\n    - [graph/](pkg/interpreter/graph/): Execution graph data structures and processing.\n    - [operator/](pkg/interpreter/operator/): SCQL operators.\n    - [sc/](pkg/interpreter/sc/): SCQL compiler Python bindings using gopy.\n  - [executor/](pkg/executor/): DQL executor. It dispatches execution dag to SCQL engine.\n- [engine/](engine/): SCQL execution engine, implemented in C++.\n  - [exe/](engine/exe/): SCQL execution engine applications.\n  - [services/](engine/services/): Engine RPC services.\n  - [link/](engine/link/): MPI framework based on [YACL link](https://github.com/secretflow/yacl/tree/main/yacl/link).\n  - [core/](engine/core/): Basic data structures used in engine.\n  - [framework/](engine/framework/): Engine framework.\n  - [operator/](engine/operator/): Oblivious operators.\n  - [datasource/](engine/datasource/): SCQL data source adaptors/connectors.\n  - [util/](engine/util/): Engine utilities.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security\n\nIf you believe you have found a security vulnerability in any SecretFlow repository that meets\n[SecretFlow's definition of a security vulnerability](https://security.alipay.com/announcement.htm?id=1), please report it to us as described below.\n\n## Reporting Security Issues\n\n**Please do not report security vulnerabilities through public GitHub issues.**\n\nInstead, please report them to the ANT GROUP SECURITY Response Center at [https://security.alipay.com/](https://security.alipay.com/).\n\nIf you prefer to submit without logging in, send email to [antsrc@alipay.com](mailto:antsrc@alipay.com).\n\nYou should receive a response within 48 hours. If for some reason you do not, please follow up via email to ensure we received your original message.\nAdditional information can be found at [https://security.alipay.com/](https://security.alipay.com/).\n\nPlease include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:\n\n* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)\n* Full paths of source file(s) related to the manifestation of the issue\n* The location of the affected source code (tag/branch/commit or direct URL)\n* Any special configuration required to reproduce the issue\n* Step-by-step instructions to reproduce the issue\n* Proof-of-concept or exploit code (if possible)\n* Impact of the issue, including how an attacker might exploit the issue\n\nThis information will help us triage your report more quickly.\n\n## Preferred Languages\n\nWe prefer all communications to be in Chinese or English.\n"
  },
  {
    "path": "api/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@rules_buf//buf:defs.bzl\", \"buf_lint_test\")\nload(\"@rules_cc//cc:defs.bzl\", \"cc_proto_library\")\nload(\"@rules_go//proto:def.bzl\", \"go_proto_library\")\nload(\"@rules_java//java:defs.bzl\", \"java_proto_library\")\nload(\"@rules_proto//proto:defs.bzl\", \"proto_library\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nproto_library(\n    name = \"core_proto\",\n    srcs = [\"core.proto\"],\n    deps = [\n        \":common_proto\",\n        \":status_proto\",\n    ],\n)\n\nproto_library(\n    name = \"status_code_proto\",\n    srcs = [\"status_code.proto\"],\n)\n\nproto_library(\n    name = \"engine_proto\",\n    srcs = [\"engine.proto\"],\n    deps = [\n        \":common_proto\",\n        \":core_proto\",\n        \":status_proto\",\n        \":subgraph_proto\",\n        \"@com_google_protobuf//:empty_proto\",\n        \"@spulib//libspu:spu_proto\",\n    ],\n)\n\nproto_library(\n    name = \"status_proto\",\n    srcs = [\"status.proto\"],\n    deps = [\n        \"@com_google_protobuf//:any_proto\",\n    ],\n)\n\nproto_library(\n    name = \"common_proto\",\n    srcs = [\"common.proto\"],\n    deps = [\n        \"@com_google_protobuf//:any_proto\",\n        \"@com_google_protobuf//:timestamp_proto\",\n    ],\n)\n\ncc_proto_library(\n    name = \"common_cc_proto\",\n    deps = [\":common_proto\"],\n)\n\ncc_proto_library(\n    name = \"engine_cc_proto\",\n    deps = [\":engine_proto\"],\n)\n\ncc_proto_library(\n    name = \"core_cc_proto\",\n    deps = [\":core_proto\"],\n)\n\ncc_proto_library(\n    name = \"status_cc_proto\",\n    deps = [\":status_code_proto\"],\n)\n\ncc_proto_library(\n    name = \"interpreter_cc_proto\",\n    deps = [\":interpreter_proto\"],\n)\n\nproto_library(\n    name = \"subgraph_proto\",\n    srcs = [\n        \"subgraph.proto\",\n    ],\n    deps = [\":core_proto\"],\n)\n\nproto_library(\n    name = \"interpreter_proto\",\n    srcs = [\"interpreter.proto\"],\n    deps = [\n        \":common_proto\",\n        \":core_proto\",\n        \":status_proto\",\n        \":subgraph_proto\",\n        \"@com_google_protobuf//:timestamp_proto\",\n        \"@spulib//libspu:spu_proto\",\n    ],\n)\n\nproto_library(\n    name = \"scql_task_proto\",\n    srcs = [\"scql_task.proto\"],\n    deps = [\n        \":common_proto\",\n        \":engine_proto\",\n        \":subgraph_proto\",\n        \"@spulib//libspu:spu_proto\",\n    ],\n)\n\ncc_proto_library(\n    name = \"scql_task_cc_proto\",\n    deps = [\":scql_task_proto\"],\n)\n\ngo_proto_library(\n    name = \"spu_go_proto\",\n    importpath = \"github.com/secretflow/scql/pkg/proto-gen/spu\",\n    protos = [\"@spulib//libspu:spu_proto\"],\n)\n\ngo_proto_library(\n    name = \"googleapis_go_proto\",\n    importpath = \"google.golang.org/genproto/googleapis/api\",\n    protos = [\n        \"@googleapis//google/api:annotations_proto\",\n        \"@googleapis//google/api:field_behavior_proto\",\n        \"@googleapis//google/api:http_proto\",\n    ],\n)\n\ngo_proto_library(\n    name = \"scql_go_proto\",\n    compilers = [\"@rules_go//proto:go_grpc\"],\n    importpath = \"github.com/secretflow/scql/pkg/proto-gen/scql\",\n    protos = [\n        \":common_proto\",\n        \":core_proto\",\n        \":engine_proto\",\n        \":interpreter_proto\",\n        \":scql_task_proto\",\n        \":status_code_proto\",\n        \":status_proto\",\n        \":subgraph_proto\",\n    ],\n    deps = [\n        \":googleapis_go_proto\",\n        \":spu_go_proto\",\n    ],\n)\n\n# lint\n\nbuf_lint_test(\n    name = \"core_proto_lint\",\n    config = \"buf.yaml\",\n    targets = [\":core_proto\"],\n)\n\nbuf_lint_test(\n    name = \"status_code_proto_lint\",\n    config = \"buf.yaml\",\n    targets = [\":status_code_proto\"],\n)\n\nbuf_lint_test(\n    name = \"engine_proto_lint\",\n    config = \"buf.yaml\",\n    targets = [\":engine_proto\"],\n)\n\nbuf_lint_test(\n    name = \"status_proto_lint\",\n    config = \"buf.yaml\",\n    targets = [\":status_proto\"],\n)\n\nbuf_lint_test(\n    name = \"common_proto_lint\",\n    config = \"buf.yaml\",\n    targets = [\":common_proto\"],\n)\n\nbuf_lint_test(\n    name = \"subgraph_proto_lint\",\n    config = \"buf.yaml\",\n    targets = [\":subgraph_proto\"],\n)\n\nbuf_lint_test(\n    name = \"interpreter_proto_lint\",\n    config = \"buf.yaml\",\n    targets = [\":interpreter_proto\"],\n)\n"
  },
  {
    "path": "api/buf.yaml",
    "content": "version: v2\nmodules:\n  - path: .\n    name: buf.build/secretflow/scql-protos\ndeps:\n  - buf.build/googleapis/googleapis\n  - buf.build/protocolbuffers/wellknowntypes\nlint:\n  use:\n    - DEFAULT\n    - PACKAGE_DIRECTORY_MATCH\n    - COMMENTS\n    - UNARY_RPC\n  except:\n    # Allow direct resource returns for Create/Get operations following Google AIP patterns\n    - RPC_RESPONSE_STANDARD_NAME\n    - RPC_REQUEST_RESPONSE_UNIQUE\n  ignore_only:\n    # You can ignore specific files or rules if needed\n    # - path/to/file.proto\nbreaking:\n  use:\n    - FILE\n"
  },
  {
    "path": "api/common.proto",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.pb;\n\nimport \"google/protobuf/any.proto\";\nimport \"google/protobuf/timestamp.proto\";\n\noption go_package = \"proto-gen/scql\";\noption java_package = \"org.secretflow.scql\";\n\n// RequestHeader carries the user custom headers.\nmessage RequestHeader {\n  // Custom headers used to record custom information.\n  map<string, string> custom_headers = 1;\n}\n\nmessage DebugOptions {\n  bool enable_psi_detail_log = 1;\n}\n\n// (-- TODO: move SQLWarning to a proper place --)\nmessage SQLWarning {\n  // Description of the warning\n  string reason = 1;\n}\n\n// IOStats contains input/output statistics for a job, including bytes sent and\n// received, as well as the number of send and receive actions performed.\nmessage IOStats {\n  uint64 send_bytes = 1;\n  uint64 recv_bytes = 2;\n  uint64 send_actions = 3;\n  uint64 recv_actions = 4;\n}\n\n// StageInfo provides information about an individual stage within a running\n// job.\nmessage StageInfo {\n  // The name of the stage.\n  string name = 1;\n  // A brief summary describing the stage\n  string summary = 2;\n  // Stage start time\n  google.protobuf.Timestamp start_time = 3;\n  // Personalized details that may have different structures depending on the\n  // stage type.\n  google.protobuf.Any details = 4;\n}\n\n// JobProgress provides detailed information about the progress of a running\n// job.\nmessage JobProgress {\n  // Job start time\n  google.protobuf.Timestamp start_time = 1;\n  // The total number of stages planned for the job.\n  int32 stages_count = 2;\n  // The number of stages that have been executed so far.\n  int32 executed_stages = 3;\n  IOStats io_stats = 4;\n  // A list of currently running stages, providing insight into which parts of\n  // the job are active.\n  repeated StageInfo running_stages = 5;\n}\n\nenum JobState {\n  JOB_STATE_UNSPECIFIED = 0;\n  JOB_INITIALIZED = 1;\n  JOB_RUNNING = 2;\n  JOB_SUCCEEDED = 3;\n  JOB_FAILED = 4;\n  JOB_CANCELED = 5;\n}\n\nmessage LinkConfig {\n  int64 link_recv_timeout_sec = 1;\n  int64 link_throttle_window_size = 2;\n  int64 link_chunked_send_parallel_size = 3;\n  int64 http_max_payload_size = 4;\n}\n\nenum PsiAlgorithmType {\n  // auto means choosing psi type by engine\n  AUTO = 0;\n  ECDH = 1;\n  OPRF = 2;\n  RR22 = 3;\n}\n\nenum Rr22Mode {\n  UNDEFINED = 0;\n  LOW_MODE = 1;\n  FAST_MODE = 2;\n}\n\nmessage PsiConfig {\n  int32 psi_curve_type = 1;\n  PsiAlgorithmType psi_type = 2;\n  // activated when psi_type is rr22\n  Rr22Mode rr22_mode = 3;\n}\n\nmessage LogConfig {\n  bool enable_session_logger_separation = 1;\n}\n\nmessage Placeholder {\n  // placeholder name\n  string name = 1;\n  // placeholder name, e.g. string, int64, float\n  string data_type = 2;\n}\n\nmessage Placeholders {\n  repeated Placeholder placeholders = 1;\n}\n\nmessage Variable {\n  string name = 1;\n  string string_data = 2;\n  int64 int64_data = 3;\n  float float_data = 4;\n  bool bool_data = 5;\n}\n"
  },
  {
    "path": "api/core.proto",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.pb;\n\nimport \"api/common.proto\";\nimport \"api/status.proto\";\n\noption go_package = \"proto-gen/scql\";\noption java_package = \"org.secretflow.scql\";\n\n// Defines a tensor shape. A dimension can be either an integer value\n// or a symbolic variable. A symbolic variable represents an unknown\n// dimension.\nmessage TensorShape {\n  message Dimension {\n    oneof value {\n      int64 dim_value = 1;\n      string dim_param = 2;  // shape is unknown.\n    }\n  }\n  repeated Dimension dim = 1;\n}\n\nenum PrimitiveDataType {\n  PrimitiveDataType_UNDEFINED = 0;\n\n  // Numeric types\n  INT8 = 1;     // the 8-bit signed integer type\n  INT16 = 2;    // the 16-bit signed integer type\n  INT32 = 3;    // the 32-bit signed integer type\n  INT64 = 4;    // the 64-bit signed integer type\n  FLOAT32 = 5;  // the 32-bit binary floating point type\n  FLOAT64 = 6;  // the 64-bit binary floating point type\n\n  // Other types\n  BOOL = 7;\n  STRING = 8;\n  // DATETIME and TIMESTAMP\n  DATETIME = 9;    // https://dev.mysql.com/doc/refman/8.0/en/datetime.html\n  TIMESTAMP = 10;  // seconds since '1970-01-01 00:00:00' UTC\n  DECIMAL = 11;\n}\n\n// Tensor options.\nenum TensorOptions {\n  // A tensor with data.\n  VALUE = 0;\n  // A tensor with reference (URI).\n  REFERENCE = 1;\n  // A tensor variable (declaration).\n  VARIABLE = 2;\n}\n\nenum TensorStatus {\n  // Unknown.\n  TENSORSTATUS_UNKNOWN = 0;\n\n  // Private.\n  TENSORSTATUS_PRIVATE = 1;\n\n  // Secret, usually in the form of secret sharing.\n  TENSORSTATUS_SECRET = 2;\n\n  // Ciphertext, usually in the form of homomorphic encryption ciphertext.\n  TENSORSTATUS_CIPHER = 3;\n\n  // Public.\n  TENSORSTATUS_PUBLIC = 4;\n}\n\nmessage TensorAnnotation {\n  TensorStatus status = 1;\n}\n\n// A tensor data representation.\nmessage Tensor {\n  // Tensor name.\n  string name = 1;\n\n  // Tensor shape.\n  // In SCQL cases, it's normally [M] (a vector with M elements).\n  TensorShape shape = 2;\n\n  // Tensor element type.\n  PrimitiveDataType elem_type = 3;\n  // used by decimal type\n  int32 scale = 14;\n  int32 width = 15;\n  // Tensor options.\n  TensorOptions option = 4;\n\n  // Tensor annotation carries physical status information.\n  // It MUST be there if the <option> is \"Reference\"\n  TensorAnnotation annotation = 5;\n\n  // tensor content\n\n  // For int8, int16, int32 data types\n  repeated int32 int32_data = 6 [packed = true];\n  // For int64 and timestamp data types\n  repeated int64 int64_data = 7 [packed = true];\n  // For float32 data type\n  repeated float float_data = 8 [packed = true];\n  // For float64 data type\n  repeated double double_data = 9 [packed = true];\n  // For bool data type\n  repeated bool bool_data = 10 [packed = true];\n  // For string and datetime and decimal data types\n  repeated string string_data = 11;\n  // validity mask for data(int32_data/int64_data/...), size can be zero(all\n  // data valid) or the same as data, where item false means NULL, true means\n  // valid value\n  repeated bool data_validity = 13 [packed = true];\n  // Tensor reference nums, internally used to delete tensor immediately\n  int32 ref_num = 12;\n}\n\n// Attribute value, it may be a tensor.\nmessage AttributeValue {\n  oneof value {\n    Tensor t = 1;\n\n    // More may be added later, say, Map, Tuple, etc.\n  }\n}\n\nmessage TensorList {\n  repeated Tensor tensors = 1;\n}\n\n// An execution node\nmessage ExecNode {\n  // Node name, should be unique in an execution plan,\n  // its format may be like \"${name}.${id}\"\n  string node_name = 1;\n\n  // Operator type that this node refers to.\n  string op_type = 2;\n\n  // Input arguments.\n  map<string, TensorList> inputs = 3;\n\n  // Output arguments.\n  map<string, TensorList> outputs = 4;\n\n  // Static attributes may be used in this node.\n  // It's used to replace the default value defined\n  // in the operator definition if needed.\n  map<string, AttributeValue> attributes = 5;\n}\n\nmessage FormalAttribute {\n  string name = 1;\n\n  // A complete attribute definition string.\n  string definition = 2;\n}\n\n// Formal parameter options.\nenum FormalParameterOptions {\n  // Undefined.\n  FORMALPARAMETEROPTIONS_UNDEFINED = 0;\n\n  // This is a single formal parameter.\n  FORMALPARAMETEROPTIONS_SINGLE = 1;\n\n  // This is an optional formal parameter.\n  FORMALPARAMETEROPTIONS_OPTIONAL = 2;\n\n  // This is a variadic formal parameter.\n  FORMALPARAMETEROPTIONS_VARIADIC = 3;\n}\n\n// Formal parameter representation of a SCQL operator.\n// It normally includes formal parameter name, type, and some annotations.\nmessage FormalParameter {\n  string param_name = 1;\n\n  // Formal parameter option.\n  FormalParameterOptions option = 2;\n\n  // Formal parameter shape information in the case of \"tensor\".\n  // In the case of scql, the tensor is actually a vector.\n  TensorShape param_shape = 3;\n\n  // A complete parameter definition string.\n  string definition = 4;\n\n  // Name of parameter status constraint(template name), e.g. \"T\" for template\n  // name. It's like the `T` in `template<class T> ...` for C++. The parameter\n  // with the same T should of the same tensor status.\n  string parameter_status_constraint_name = 5;\n}\n\n// TensorStatus list\nmessage TensorStatusList {\n  // TensorStatus list.\n  repeated TensorStatus status = 1;\n}\n\n// An SCQL operator definition representation.\nmessage OperatorDef {\n  // Operator name.\n  string name = 1;\n\n  // Operator input formal parameters.\n  repeated FormalParameter input_params = 2;\n\n  // Operator output formal parameters.\n  // For SCQL case, there may be only one output.\n  repeated FormalParameter output_params = 3;\n\n  // Operator attribute parameters.\n  repeated FormalAttribute attribute_params = 4;\n\n  // Default attribute values needed when running the operator.\n  // The default values may be replaced when creating an execution plan\n  // from a SCQL query.\n  map<string, AttributeValue> default_attribute_values = 5;\n\n  // A complete operator definition string.\n  string definition = 6;\n\n  // Map of key for parameter_status_constraint_name, value for TensorStatusList\n  // e.g.: {\"T\": TensorStatusList{status: [TENSORSTATUS_PRIVATE]}}\n  map<string, TensorStatusList> param_status_constraints = 7;\n}\n\n// TODO: move PartyId to a proper place.\nmessage PartyId {\n  string code = 1;  // party code\n}\n\n// QueryResult represents the result of an executed SQL query.\nmessage QueryResult {\n  int64 affected_rows = 1;\n  repeated SQLWarning warnings = 2;\n  double cost_time_s = 3;\n  // Output columns are used to store the result datas\n  repeated Tensor out_columns = 1000;\n}\n\n// QueryResponse represents the response for a query execution.\nmessage QueryResponse {\n  Status status = 1;\n  QueryResult result = 2;\n}\n"
  },
  {
    "path": "api/engine.proto",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.pb;\n\nimport \"api/common.proto\";\nimport \"api/core.proto\";\nimport \"api/status.proto\";\nimport \"api/subgraph.proto\";\nimport \"google/protobuf/empty.proto\";\nimport \"libspu/spu.proto\";\n\noption cc_generic_services = true;\noption go_package = \"proto-gen/scql\";\n\nservice SCQLEngineService {\n  // Run the whole execution plan\n  rpc RunExecutionPlan(RunExecutionPlanRequest)\n      returns (RunExecutionPlanResponse);\n\n  // Query Job Status\n  rpc QueryJobStatus(QueryJobStatusRequest) returns (QueryJobStatusResponse);\n\n  // Stop Job\n  rpc StopJob(StopJobRequest) returns (Status);\n}\n\nmessage StopJobRequest {\n  string job_id = 1;\n  // job stop reason, it maybe\n  // - \"Finish\". Job ended normally.\n  // - \"Timeout\". Job timeout.\n  // - \"Canceled\". Job canceled by client, maybe triggered by CTRL+C\n  // - \"Error\". Exception caught when running.\n  // - \"Killed\". Killed by client.\n  // - or something else.\n  string reason = 2;\n}\n\n// A message carries all job session-level (execution plan level) information.\nmessage JobStartParams {\n  message Party {\n    // party code\n    string code = 1;\n    // party name\n    string name = 2;\n    // party host\n    string host = 3;\n    // party rank\n    int32 rank = 4;\n\n    // base64 encoded version of the DER encoded public key\n    //\n    // Example:\n    // # 1. generate private key\n    // $ openssl genpkey -algorithm ed25519 -out ed25519key.pem\n    // # 2. generate public key based on above private key\n    // $ openssl pkey -in ed25519key.pem -pubout\n    //\n    // # its output like below:\n    //\n    // -----BEGIN PUBLIC KEY-----\n    // BASE64 ENCODED DATA\n    // -----END PUBLIC KEY-----\n    //\n    // the field `public_key` should be the string between header \"-----BEGIN\n    // PUBLIC KEY-----\" and footer \"-----END PUBLIC KEY-----\"\n    string public_key = 5;\n  }\n\n  // This party code.\n  // It may be used to get this party information from <parties> below.\n  string party_code = 1;\n\n  // All parties that would jointly complete an execution plan.\n  repeated Party parties = 2;\n\n  // The job id\n  string job_id = 3;\n\n  // The spu runtime configuration.\n  spu.pb.RuntimeConfig spu_runtime_cfg = 4;\n\n  // The query job time zone, only support time offset, like: '+08:00'\n  string time_zone = 5;\n\n  LinkConfig link_cfg = 6;\n  PsiConfig psi_cfg = 7;\n  LogConfig log_cfg = 8;\n}\n\nmessage GraphChecksum {\n  bool check_graph_checksum = 1;\n  // map from rank to checksum\n  // It could be used to verify and ensure that engines execute the same\n  // graph.\n  map<string, string> sub_graph_checksums = 2;\n  string whole_graph_checksum = 3;\n}\n\nmessage RunExecutionPlanRequest {\n  JobStartParams job_params = 1;\n\n  SubGraph graph = 2;\n  GraphChecksum graph_checksum = 3;\n\n  // Whether the whole execution plan on the engine should be executed\n  // synchronously or asynchronously. By default, the execution plan is executed\n  // synchronously.\n  bool async = 4;\n\n  // Callback url, e.g.: \"http://alice.com:8080/path/to/callback\".\n  string callback_url = 5;\n  DebugOptions debug_opts = 6;\n}\n\nmessage RunExecutionPlanResponse {\n  Status status = 1;\n  // Output columns used to store result datas.\n  repeated Tensor out_columns = 2;\n  string job_id = 3;\n  // Code of party which finished the execution plan.\n  string party_code = 4;\n  // The number of rows affected by a select into, update, insert, or delete.\n  int64 num_rows_affected = 5;\n}\n\nmessage QueryJobStatusRequest {\n  string job_id = 1;\n}\n\nmessage QueryJobStatusResponse {\n  Status status = 1;\n  JobState job_state = 2;\n\n  JobProgress progress = 3;\n}\n\n// EngineResultCallback\nservice EngineResultCallback {\n  // Engine report the plan result to driver(for example, broker)\n  rpc Report(ReportRequest) returns (google.protobuf.Empty);\n}\n\n// After finishing running an execution plan, the Engine sends a ReportRequest\n// to result callback server (for example, broker) to return the results.\nmessage ReportRequest {\n  // Status including whether the plan run was handled successfully,\n  // if not, error message and some more information included.\n  Status status = 1;\n  // Output columns.\n  repeated Tensor out_columns = 2;\n  // The job_id that this execution plan belongs to.\n  string job_id = 3;\n  // Code of party which finished the plan run.\n  string party_code = 4;\n  // The number of rows affected by a select into, update, insert, or delete.\n  int64 num_rows_affected = 5;\n}\n\nmessage StreamingOptions {\n  int64 streaming_row_num_threshold = 1;\n  int64 batch_row_num = 2;\n}\n\nmessage PsiOptions {\n  repeated int64 psi_curve_types = 1;\n  Rr22Mode rr22_mode = 2;\n}\n\nmessage NegotiationOptions {\n  StreamingOptions streaming_options = 1;\n  PsiOptions psi_options = 2;\n}\n"
  },
  {
    "path": "api/generate_proto.sh",
    "content": "#!/bin/bash\n#\n# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\nbazelisk build --remote_cache=\"\" //api:scql_go_proto //api:spu_go_proto //api/v1alpha1:compiler_go_proto\nmkdir -p pkg/proto-gen/scql\nmkdir -p pkg/proto-gen/scql/v1alpha1\nproto_gen_package=github.com/secretflow/scql/pkg/proto-gen\n# copy files execpt spu.pb.go\nls bazel-bin/api/scql_go_proto_/${proto_gen_package}/scql/ | grep -v spu.* | xargs -I {} cp -r bazel-bin/api/scql_go_proto_/${proto_gen_package}/scql/{} pkg/proto-gen/scql\ncp -r bazel-bin/api/spu_go_proto_/${proto_gen_package}/spu/. pkg/proto-gen/spu\ncp -r bazel-bin/api/v1alpha1/compiler_go_proto_/${proto_gen_package}/scql/v1alpha1/. pkg/proto-gen/scql/v1alpha1\nchmod -R -x+X pkg/proto-gen\n\n# generate openapi file for broker.proto\ntrap \"rm -rf libspu google\" EXIT\n# note: temporary copy spu.proto to avoid external dependency\n# symlink for \"bazel-<workspace-name>\"\nBAZEL_EXEC_ROOT=bazel-$(basename $(pwd))\nmkdir -p libspu\ncp -f ${BAZEL_EXEC_ROOT}/external/spulib~/libspu/spu.proto libspu/spu.proto\n# note: protoc need google api\nmkdir -p google/api\ncp -f ${BAZEL_EXEC_ROOT}/external/googleapis~/google/api/*.proto google/api\n"
  },
  {
    "path": "api/interpreter.proto",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.pb;\n\nimport \"api/common.proto\";\nimport \"api/core.proto\";\nimport \"api/status.proto\";\nimport \"api/subgraph.proto\";\nimport \"google/protobuf/timestamp.proto\";\nimport \"libspu/spu.proto\";\n\noption go_package = \"proto-gen/scql\";\n\nmessage CompiledPlan {\n  // schema of query result\n  TableSchema schema = 1;\n  Warning warning = 2;\n  spu.pb.RuntimeConfig spu_runtime_conf = 3;\n  // participants in execution graph.\n  // The position order matters, the parties[0]'s rank is 0.\n  repeated PartyId parties = 4;\n  map<string, SubGraph> sub_graphs = 5;\n  string whole_graph_checksum = 6;\n  // TODO: Add field to specify the party who report final query result.\n  ExplainInfo explain = 1000;\n}\n\nmessage Warning {\n  // If the value is true, it means that the results may be affected by the\n  // group threshold.\n  bool may_affected_by_group_threshold = 1;\n}\n\nmessage ExplainInfo {\n  // execution graph in dot format.\n  // It has value only when `dump_exe_graph` is true in request compile options.\n  string exe_graph_dot = 1;\n}\n\n// Metadata used to describe the schema (column names, types, comments)\n// of result sets.\nmessage TableSchema {\n  repeated ColumnDesc columns = 1;\n}\n\nmessage ColumnDesc {\n  string name = 1;\n  string type = 2;\n}\n\nmessage OptimizerHints {\n  // auto means choosing psi type by engine\n  PsiAlgorithmType psi_algorithm_type = 1;\n}\n\nmessage CompileOptions {\n  spu.pb.RuntimeConfig spu_conf = 1;\n  SecurityCompromiseConfig security_compromise = 2;\n  // dump execution graph in graphviz dot format\n  bool dump_exe_graph = 3;\n  OptimizerHints optimizer_hints = 4;\n  // whether to run in streaming mode\n  bool batched = 5;\n}\n\nmessage SecurityCompromiseConfig {\n  bool reveal_group_mark = 1;\n  uint64 group_by_threshold = 2;\n  bool reveal_group_count = 3;\n}\n\nmessage Catalog {\n  repeated TableEntry tables = 1;\n}\n\nmessage TableEntry {\n  // table_name could be qualified name, like \"db_name.table_name\"\n  string table_name = 1;\n\n  message Column {\n    string name = 1;\n    string type = 2;\n    int32 ordinal_position = 3;\n  }\n  repeated Column columns = 2;\n\n  // NOTE: So far, the value of `is_view` is always False.\n  // TODO: Add support to view.\n  bool is_view = 3;\n  // The value of `select_string` is the definition body of create view.\n  // It valids only when is_view is True.\n  string select_string = 4;\n\n  // The following fields means when `is_view` is false.\n  // `ref_table` refers the physical/real table name inside individual parties,\n  // it could be empty if it's the same as table_name.\n  // `ref_table` name could be qualified name.\n  string ref_table = 5;\n  // the db type of ref_table, maybe 'MySQL/PostgreSQL/csvdb/...'\n  string db_type = 6;\n  PartyId owner = 7;\n  // The ref_table_uri is utilized to route the ref_table, like domain_data_id\n  // in kuscia\n  string ref_table_uri = 8;\n}\n"
  },
  {
    "path": "api/scql_task.proto",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.pb;\n\nimport \"api/common.proto\";\nimport \"api/engine.proto\";\nimport \"api/subgraph.proto\";\nimport \"libspu/spu.proto\";\n\n// Temporarily removed, may be reused in the future\n// message ClusterDef {\n//   string self_party = 1;\n//   repeated string parties = 2;\n//   map<string, ServiceMap> services = 3;\n// }\n\n// message ServiceMap {\n//   map<string, Service> services = 1;\n// }\n\n// message Service {\n//   string name = 1;\n//   string host = 2;\n//   string port = 3;\n//   string scope = 4;\n//   string protocol = 5;\n// }\n\n// SCQL job configuration containing execution plans and runtime settings\nmessage ScqlConfig {\n  // Table name to input file path mapping\n  map<string, string> input_file_paths = 1;\n\n  // Party code to execution graph mapping\n  map<string, SubGraph> all_sub_graphs = 2;\n\n  // Participating parties sorted by rank (starting from 0)\n  repeated string parties = 3;\n\n  // Runtime configurations\n  spu.pb.RuntimeConfig spu_runtime_cfg = 10;  // SPU protocol settings\n  string time_zone = 11;     // Time zone for temporal operations\n  LinkConfig link_cfg = 12;  // Network communication settings\n  PsiConfig psi_cfg = 13;    // Private set intersection config\n  LogConfig log_cfg = 14;    // Logging configuration\n\n  // Configuration used by the Kpad only\n  string graph_checksum = 20;  // Checksum of the overall execution graph, used\n                               // by other parties to verify graph consistency\n}\n"
  },
  {
    "path": "api/status.proto",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// Reference:\n// https://github.com/grpc/grpc/blob/master/src/proto/grpc/status/status.proto\n\nsyntax = \"proto3\";\n\npackage scql.pb;\n\nimport \"google/protobuf/any.proto\";\n\noption go_package = \"proto-gen/scql\";\noption java_package = \"org.secretflow.scql\";\n\n// The `Status` type defines a logical error model that is suitable for\n// different programming environments, including REST APIs and RPC APIs. It is\n// used by [gRPC](https://github.com/grpc). Each `Status` message contains\n// three pieces of data: error code, error message, and error details.\n//\n// You can find out more about this error model and how to work with it in the\n// [API Design Guide](https://cloud.google.com/apis/design/errors).\nmessage Status {\n  // The status code, see\n  // [definition](https://github.com/secretflow/scql/blob/main/api/status_code.proto#L22)\n  int32 code = 1;\n  // Message for recording the error information.\n  string message = 2;\n  // A list of messages that carry the additional supplementary error details.\n  repeated google.protobuf.Any details = 3;\n}\n"
  },
  {
    "path": "api/status_code.proto",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.pb;\n\noption go_package = \"proto-gen/scql\";\n\nenum Code {\n  // Not an error; returned on success\n  OK = 0;\n\n  // =====================\n  // 100-199 Request Error\n  // =====================\n\n  // General bad request\n  BAD_REQUEST = 100;\n  // Failed to authenticate user credential\n  UNAUTHENTICATED = 101;\n  // Parsing SQL error, returned on invalid SQL\n  SQL_PARSE_ERROR = 102;\n  INVALID_ARGUMENT = 103;\n  // Query result is not ready, please try again later\n  NOT_READY = 104;\n\n  // The user does not have permission to execute the DDL.\n  // For example, the user try to drop other's table.\n  DDL_PERMISSION_DENIED = 131;\n\n  // General not found error\n  NOT_FOUND = 140;\n  // Driver session not found\n  SESSION_NOT_FOUND = 141;\n\n  // Query CCL check failed\n  // NOTE: CCL (Column Control Language) has been removed from SCQL,\n  // this error code is kept for backward compatibility only\n  CCL_CHECK_FAILED = 160;\n\n  // The P2P internal exchange error\n  // Local storage info is not equal to storage info in other parties\n  DATA_INCONSISTENCY = 170;\n  // In P2P mode, the project status in different members conflicts and cannot\n  // reach an agreement\n  PROJECT_CONFLICT = 171;\n\n  // =========================\n  // 200-299 Dependence Error\n  // =========================\n\n  // Driver DB error\n  STORAGE_ERROR = 201;\n\n  // ==============================\n  // 300-399 Server Internal Error\n  // ==============================\n\n  // UNKNOWN Server Internal Error\n  INTERNAL = 300;\n\n  // 320-339 executing execution graph error\n  UNKNOWN_ENGINE_ERROR = 320;\n\n  ENGINE_RUNSQL_ERROR = 332;\n\n  // Feature not supported\n  NOT_SUPPORTED = 340;\n}\n"
  },
  {
    "path": "api/subgraph.proto",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.pb;\n\nimport \"api/core.proto\";\n\noption go_package = \"proto-gen/scql\";\n\n// SubGraph is the part of the whole execution graph seen\n// from the perspective of the party.\n// Each party could only see the ExecNode which it participates in.\nmessage SubGraph {\n  map<string, ExecNode> nodes = 1;\n  SchedulingPolicy policy = 2;\n  // checksum of the current sub graph\n  // It could be used to verify and ensure that engines execute the same graph.\n  string sub_graph_checksum = 3;\n}\n\nmessage SubDAG {\n  message Job {\n    int32 worker_id = 1;\n    repeated string node_ids = 2;\n  }\n\n  repeated Job jobs = 1;\n  // a barrier to sync among parties\n  bool need_call_barrier_after_jobs = 2;\n}\n\nmessage SchedulingPolicy {\n  int32 worker_num = 1;\n  repeated Pipeline pipelines = 2;\n}\n\nmessage Pipeline {\n  // maybe need batch size later\n  bool batched = 1;\n  repeated SubDAG subdags = 2;\n  repeated Tensor inputs = 3;\n  repeated Tensor outputs = 4;\n}\n"
  },
  {
    "path": "api/v1/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@rules_go//proto:def.bzl\", \"go_proto_library\")\nload(\"@rules_proto//proto:defs.bzl\", \"proto_library\")\nload(\"@rules_proto_grpc_cpp//:defs.bzl\", \"cpp_proto_library\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nproto_library(\n    name = \"column_proto\",\n    srcs = [\"column.proto\"],\n)\n\ncpp_proto_library(\n    name = \"column_cpp_proto\",\n    protos = [\":column_proto\"],\n)\n\ngo_proto_library(\n    name = \"column_go_proto\",\n    importpath = \"github.com/secretflow/scql/proto-gen/api/v1\",\n    protos = [\":column_proto\"],\n)\n"
  },
  {
    "path": "api/v1/column.proto",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.api.v1;\n\noption go_package = \"github.com/secretflow/scql/proto-gen/api/v1;scql\";\n\n// Column Data Type\n// Column DataType values are subset of [data types in secretflow\n// spec](https://github.com/secretflow/spec/blob/main/secretflow_spec/protos/secretflow_spec/v1/data.proto#L144)\nenum DataType {\n  DataType_UNSPECIFIED = 0;\n  BOOL = 1;   // reserved datatype, not supported yet, use INT32 instead\n  INT8 = 2;   // reserved datatype, not supported yet, use INT32 instead\n  INT16 = 3;  // reserved datatype, not supported yet, use INT32 instead\n  INT32 = 4;\n  INT64 = 5;\n  FLOAT32 = 6;\n  FLOAT64 = 7;\n  INT = 8;      // alias for INT64\n  INTEGER = 9;  // alias for INT64\n  FLOAT = 10;   // alias for FLOAT64\n  DOUBLE = 11;  // alias for FLOAT64\n  STRING = 12;\n  STR = 13;  // alias for STRING\n  DATETIME = 14;\n  TIMESTAMP = 15;\n}\n"
  },
  {
    "path": "api/v1/genproto.sh",
    "content": "#!/bin/bash\n#\n# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nSCRIPT_DIR=$(\n    cd \"$(dirname \"$0\")\"\n    pwd\n)\n\nROOT_DIR=$(\n    cd ${SCRIPT_DIR}/../..\n    pwd\n)\n\ncd ${ROOT_DIR}\n\nprotoc --go_out=${ROOT_DIR} --go_opt=module=github.com/secretflow/scql api/v1/column.proto\n"
  },
  {
    "path": "api/v1alpha1/BUILD.bazel",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@rules_go//proto:def.bzl\", \"go_proto_library\")\nload(\"@rules_proto//proto:defs.bzl\", \"proto_library\")\nload(\"@rules_proto_grpc_cpp//:defs.bzl\", \"cpp_proto_library\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nproto_library(\n    name = \"compiler_proto\",\n    srcs = [\"compiler.proto\"],\n    deps = [\n        \"//api:common_proto\",\n        \"//api:core_proto\",\n        \"//api:interpreter_proto\",\n        \"//api:status_proto\",\n        \"@com_google_protobuf//:any_proto\",\n        \"@com_google_protobuf//:timestamp_proto\",\n        \"@googleapis//google/api:annotations_proto\",\n        \"@googleapis//google/api:field_behavior_proto\",\n        \"@spulib//libspu:spu_proto\",\n    ],\n)\n\ncpp_proto_library(\n    name = \"compiler_cpp_proto\",\n    protos = [\":compiler_proto\"],\n)\n\ngo_proto_library(\n    name = \"compiler_go_proto\",\n    compilers = [\"@rules_go//proto:go_grpc\"],\n    importpath = \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\",\n    protos = [\":compiler_proto\"],\n    deps = [\n        \"//api:googleapis_go_proto\",\n        \"//api:scql_go_proto\",\n        \"//api:spu_go_proto\",\n    ],\n)\n"
  },
  {
    "path": "api/v1alpha1/compiler.proto",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.pb.v1alpha1;\n\nimport \"api/common.proto\";\nimport \"api/core.proto\";\nimport \"api/interpreter.proto\";\nimport \"api/status.proto\";\nimport \"google/api/annotations.proto\";\nimport \"google/api/field_behavior.proto\";\nimport \"google/protobuf/any.proto\";\nimport \"google/protobuf/timestamp.proto\";\nimport \"libspu/spu.proto\";\n\noption go_package = \"proto-gen/scql/v1alpha1\";\n\nservice CompilerService {\n  rpc CompileSQL(CompileSQLRequest) returns (CompileSQLResponse) {\n    option (google.api.http) = {\n      post: \"/v1alpha1/compiler:compileSql\"\n      body: \"*\"\n    };\n  }\n}\n\nmessage CompileOptions {\n  spu.pb.RuntimeConfig spu_conf = 1 [(google.api.field_behavior) = REQUIRED];\n  // Whether to run in streaming mode\n  bool batched = 2 [(google.api.field_behavior) = REQUIRED];\n  // The PSI algorithm type to use\n  // Default is auto, which means choosing PSI type by engine\n  PsiAlgorithmType psi_algorithm_type = 3\n      [(google.api.field_behavior) = OPTIONAL];\n}\n\nmessage GlobalSecurityRelaxation {\n  // The number of elements in each group can be revealed\n  bool reveal_group_count = 1 [(google.api.field_behavior) = OPTIONAL];\n  // The group mark can be revealed\n  bool reveal_group_mark = 2 [(google.api.field_behavior) = OPTIONAL];\n\n  reserved 3 to 9;\n\n  // Tensors can be revealed when used as join key\n  // e.g.: \"select ta.c1, ta.c2, tb.c2 from ta join tb on ta.c1 = tb.c1\", here\n  // ta.c1 and tb.c2 are join keys \"after join\", we get the \"intersection of\n  // ta.c1 and tb.c1\", which can be revealed Note that only the intersection of\n  // join keys(this is what \"after join\" means) can be revealed So in left outer\n  // join, only the right join key can be revealed, because left join key will\n  // contains values not exits in the intersection after join\n  bool reveal_key_after_join = 10 [(google.api.field_behavior) = OPTIONAL];\n  // Tensors can be revealed when used as filter mask\n  // This security relaxation also requires the filter mask is result of a\n  // comparison, e.g.: \"select ta.c1 from ta join tb on ta.c2 = tb.c2 where\n  // tb.c1 > ta.c3\", here tb.c1 > ta.c3 is the comparison So result of tb.c1 >\n  // ta.c3 can be revealed and used as a filter mask\n  bool reveal_filter_mask = 11 [(google.api.field_behavior) = OPTIONAL];\n}\n\nmessage ColumnSecurityRelaxation {\n  string database = 1 [(google.api.field_behavior) = REQUIRED];\n  string table = 2 [(google.api.field_behavior) = REQUIRED];\n  string column = 3 [(google.api.field_behavior) = REQUIRED];\n\n  // Reserved for future use, and we can keep grouping the bool flags together\n  reserved 4 to 9;\n\n  // Corresponding tensor can be revealed when used as join key\n  bool reveal_key_after_join = 10 [(google.api.field_behavior) = OPTIONAL];\n  // Corresponding tensor can be revealed when used as filter mask\n  bool reveal_filter_mask = 11 [(google.api.field_behavior) = OPTIONAL];\n}\n\nmessage ReverseInferenceConfig {\n  // Whether to enable reverse inference\n  bool enable_reverse_inference = 1 [(google.api.field_behavior) = REQUIRED];\n}\n\n// Security config that may affect the query result\nmessage ResultSecurityConfig {\n  // The threshold for group by operation\n  // If the number of elements in a group is less than this threshold, the group\n  // will be filtered\n  int64 groupby_threshold = 1 [(google.api.field_behavior) = OPTIONAL];\n}\n\nmessage CompilerSecurityConfig {\n  // Global security config\n  GlobalSecurityRelaxation global_relaxation = 1\n      [(google.api.field_behavior) = REQUIRED];\n  // Security relaxation that attaches to columns\n  // Not every tensor in the OperatorGraph has a ColumnSecurityRelaxation:\n  // 1. Users do not need to specify ColumnSecurityRelaxation for every column\n  // used in the query,\n  //    the missing ones will just be default value false.\n  // 2. Some tensors are in the OperatorGraph are the result of relation\n  // operations or expressions,\n  //    the security relaxation properties of these tensors can be inferred from\n  //    their inputs' security relaxation properties.\n  repeated ColumnSecurityRelaxation column_relaxation_list = 2\n      [(google.api.field_behavior) = OPTIONAL];\n  // Config related to reverse inference\n  ReverseInferenceConfig reverse_inference_conf = 3\n      [(google.api.field_behavior) = REQUIRED];\n  // User-specified visibility of columns\n  // Used to get the initial visibility of input tensors\n  // If a column's visibility is not specified, the visible party of\n  // corresponding tensor will be {column's owner} If specified, the visible\n  // party of corresponding tensor will be the union of {column's owner} and the\n  // specified visible parties\n  repeated ColumnVisibility column_visibility_list = 4\n      [(google.api.field_behavior) = OPTIONAL];\n  // Config that may affect the query result\n  ResultSecurityConfig result_security_conf = 5\n      [(google.api.field_behavior) = OPTIONAL];\n}\n\nmessage ColumnVisibility {\n  string database = 1 [(google.api.field_behavior) = REQUIRED];\n  string table = 2 [(google.api.field_behavior) = REQUIRED];\n  string column = 3 [(google.api.field_behavior) = REQUIRED];\n\n  // The parties that the tensor need to be visible to\n  repeated PartyId visible_parties = 4 [(google.api.field_behavior) = REQUIRED];\n}\n\nmessage AdditionalInfoSpec {\n  // If true, OperatorGraph will be provided in the response\n  bool need_operator_graph = 1 [(google.api.field_behavior) = OPTIONAL];\n}\n\nmessage CompileSQLRequest {\n  // The SQL query to compile\n  string query = 1 [(google.api.field_behavior) = REQUIRED];\n  // The database name\n  string db = 2 [(google.api.field_behavior) = OPTIONAL];\n  // The issuer of the query\n  PartyId issuer = 3 [(google.api.field_behavior) = REQUIRED];\n  // The catalog of the database\n  Catalog catalog = 4 [(google.api.field_behavior) = REQUIRED];\n  // The compile options\n  CompileOptions compile_opts = 5 [(google.api.field_behavior) = REQUIRED];\n  // The issue time of the query, used for functions like now()\n  google.protobuf.Timestamp issue_time = 6\n      [(google.api.field_behavior) = REQUIRED];\n  // Contains the config related to data security\n  CompilerSecurityConfig security_config = 7\n      [(google.api.field_behavior) = REQUIRED];\n  // Placeholders used by rule\n  Placeholders placeholders = 8 [(google.api.field_behavior) = OPTIONAL];\n  // Variables used by rule\n  repeated Variable variables = 9 [(google.api.field_behavior) = OPTIONAL];\n  // Specifies what and how additional information are provided in the response\n  AdditionalInfoSpec additional_info = 10\n      [(google.api.field_behavior) = REQUIRED];\n}\n\nmessage CompileSQLResponse {\n  Status status = 1 [(google.api.field_behavior) = REQUIRED];\n  // The query execution plan required by the engine\n  CompiledPlan execution_plan = 2 [(google.api.field_behavior) = REQUIRED];\n  // OperatorGraph is provides when additional_info.need_operator_graph is true\n  OperatorGraph operator_graph = 3 [(google.api.field_behavior) = OPTIONAL];\n}\n\nmessage OperatorGraph {\n  // The version of the OperatorGraph, needed for compatibility check\n  string version = 1 [(google.api.field_behavior) = REQUIRED];\n  // The operator nodes in the OperatorGraph\n  repeated Operator operators = 2 [(google.api.field_behavior) = REQUIRED];\n  // The tensor metadata catalog for the entire plan\n  repeated TensorMeta tensors = 3 [(google.api.field_behavior) = REQUIRED];\n}\n\n// Tensor metadata for the OperatorGraph\nmessage TensorMeta {\n  // Tensor id\n  int32 id = 1 [(google.api.field_behavior) = REQUIRED];\n  // Tensor name\n  string name = 2 [(google.api.field_behavior) = REQUIRED];\n  // The element type of the tensor\n  PrimitiveDataType elem_type = 3 [(google.api.field_behavior) = REQUIRED];\n}\n\n// A list of tensor IDs for referencing tensors by ID\nmessage TensorIdList {\n  repeated int32 ids = 1 [(google.api.field_behavior) = REQUIRED];\n}\n\n// (-- api-linter: core::0123::resource-annotation=disabled\nmessage Operator {\n  // Operator id in the corresponding OperatorGraph\n  string id = 1 [(google.api.field_behavior) = REQUIRED];\n  // Operator name\n  string name = 2 [(google.api.field_behavior) = REQUIRED];\n  // Operator type, such as \"Limit\", \"Filter\", \"GroupAgg\"\n  string type = 3 [(google.api.field_behavior) = REQUIRED];\n  // Inputs of the operator, the key stands for the role of corresponding\n  // tensors, such as \"payload\", \"mask\", \"leftKeys\" Each entry maps to a list of\n  // tensor IDs that can be resolved from OperatorGraph.tensors\n  map<string, TensorIdList> inputs = 4 [(google.api.field_behavior) = REQUIRED];\n  // Outputs of the operator, the key stands for the role of corresponding\n  // tensors, such as \"rank\", \"leftOutputs\" Each entry maps to a list of tensor\n  // IDs that can be resolved from OperatorGraph.tensors\n  map<string, TensorIdList> outputs = 5\n      [(google.api.field_behavior) = REQUIRED];\n  // Attributes of the operator\n  map<string, google.protobuf.Any> attributes = 6\n      [(google.api.field_behavior) = REQUIRED];\n  // The kernel represents the concrete mechanism used to implement the\n  // functionality of this Operator Each query has a deterministic OperatorGraph\n  // structure. As long as the query remains unchanged, the types and\n  // arrangement of Operators in the plan will remain constant. However, the\n  // type of Kernel corresponding to each Operator may vary with changes in the\n  // SecurityConfig.\n  Kernel kernel = 7 [(google.api.field_behavior) = REQUIRED];\n}\n\n// (-- api-linter: core::0123::resource-annotation=disabled\nmessage Kernel {\n  // The name of the kernel\n  // e.g. for GroupAgg, kernel name maybe \"oblivious_group_agg\",\n  // \"private_group_agg\"\n  string name = 1 [(google.api.field_behavior) = REQUIRED];\n  // The cost of the kernel for optimization purposes\n  // Note that comparing Cost values is only meaningful when the original\n  // Operator is identical range: [0, 1]\n  double cost = 2 [(google.api.field_behavior) = OPTIONAL];\n}\n"
  },
  {
    "path": "bazel/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n"
  },
  {
    "path": "bazel/defs.bzl",
    "content": "# Copyright 2024 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nload(\"//bazel:repositories.bzl\", \"scql_deps\")\n\ndef _non_module_deps_impl(_module_ctx):\n    scql_deps()\n\nnon_module_dependencies = module_extension(\n    implementation = _non_module_deps_impl,\n)\n"
  },
  {
    "path": "bazel/patches/BUILD.bazel",
    "content": "# Copyright 2024 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n"
  },
  {
    "path": "bazel/patches/grpc-plugin.patch",
    "content": "diff --git a/bazel/cc_grpc_library.bzl b/bazel/cc_grpc_library.bzl\nindex 55ea11cd53..8177bf864c 100644\n--- a/bazel/cc_grpc_library.bzl\n+++ b/bazel/cc_grpc_library.bzl\n@@ -102,7 +102,7 @@ def cc_grpc_library(\n         generate_cc(\n             name = codegen_grpc_target,\n             srcs = proto_targets,\n-            plugin = \"@com_github_grpc_grpc//src/compiler:grpc_cpp_plugin\",\n+            plugin = Label(\"//src/compiler:grpc_cpp_plugin\"),\n             well_known_protos = well_known_protos,\n             generate_mocks = generate_mocks,\n             **kwargs\n@@ -114,6 +114,6 @@ def cc_grpc_library(\n             hdrs = [\":\" + codegen_grpc_target],\n             deps = deps +\n                    extra_deps +\n-                   [\"@com_github_grpc_grpc//:grpc++_codegen_proto\"],\n+                   [Label(\"//:grpc++_codegen_proto\")],\n             **kwargs\n         )"
  },
  {
    "path": "bazel/patches/protobuf-xla.patch",
    "content": "diff --git a/BUILD.bazel b/BUILD.bazel\nindex 301a04656..b4d953fd2 100644\n--- a/BUILD.bazel\n+++ b/BUILD.bazel\n@@ -8,7 +8,7 @@ load(\"//bazel:java_proto_library.bzl\", \"java_proto_library\")\n load(\"//bazel:proto_library.bzl\", \"proto_library\")\n load(\"//bazel/toolchains:proto_lang_toolchain.bzl\", \"proto_lang_toolchain\")\n load(\"//build_defs:cpp_opts.bzl\", \"COPTS\", \"LINK_OPTS\")\n-load(\":protobuf.bzl\", \"internal_objc_proto_library\", \"internal_php_proto_library\", \"internal_py_proto_library\")\n+load(\":protobuf.bzl\", \"adapt_proto_library\", \"internal_objc_proto_library\", \"internal_php_proto_library\", \"internal_py_proto_library\")\n \n licenses([\"notice\"])\n \n@@ -192,6 +192,25 @@ cc_library(\n     visibility = [\"//visibility:public\"],\n )\n \n+adapt_proto_library(\n+    name = \"cc_wkt_protos_genproto\",\n+    visibility = [\"//visibility:public\"],\n+    deps = [\n+        \"//:any_proto\",\n+        \"//:api_proto\",\n+        \"//:compiler_plugin_proto\",\n+        \"//:descriptor_proto\",\n+        \"//:duration_proto\",\n+        \"//:empty_proto\",\n+        \"//:field_mask_proto\",\n+        \"//:source_context_proto\",\n+        \"//:struct_proto\",\n+        \"//:timestamp_proto\",\n+        \"//:type_proto\",\n+        \"//:wrappers_proto\",\n+    ],\n+)\n+\n # Source protos that are typically part of the protobuf runtime.\n #\n # DEPRECATED: Prefer :well_known_type_protos for the Well-Known Types\ndiff --git a/protobuf.bzl b/protobuf.bzl\nindex 7db5146a0..a0e05d4d2 100644\n--- a/protobuf.bzl\n+++ b/protobuf.bzl\n@@ -88,17 +88,17 @@ def _proto_gen_impl(ctx):\n     if source_dir:\n         has_sources = any([src.is_source for src in srcs])\n         if has_sources:\n-            import_flags += [\"-I\" + source_dir]\n+            import_flags.append(\"-I\" + source_dir)\n     else:\n-        import_flags += [\"-I.\"]\n+        import_flags.append(\"-I.\")\n \n     has_generated = any([not src.is_source for src in srcs])\n     if has_generated:\n-        import_flags += [\"-I\" + gen_dir]\n+        import_flags.append(\"-I\" + gen_dir)\n \n     if ctx.attr.includes:\n         for include in ctx.attr.includes:\n-            import_flags += [\"-I\" + _GetPath(ctx, include)]\n+            import_flags.append(\"-I\" + _GetPath(ctx, include))\n \n     import_flags = depset(direct = import_flags)\n \n@@ -153,7 +153,7 @@ def _proto_gen_impl(ctx):\n                 outs.extend(_RubyOuts([src.basename]))\n \n             # Otherwise, rely on user-supplied outs.\n-            args += [(\"--%s_out=\" + path_tpl) % (lang, gen_dir)]\n+            args.append((\"--%s_out=\" + path_tpl) % (lang, gen_dir))\n \n         if ctx.attr.outs:\n             outs.extend(ctx.attr.outs)\n@@ -174,8 +174,8 @@ def _proto_gen_impl(ctx):\n \n             if ctx.attr.plugin_options:\n                 outdir = \",\".join(ctx.attr.plugin_options) + \":\" + outdir\n-            args += [(\"--plugin=protoc-gen-%s=\" + path_tpl) % (lang, plugin.path)]\n-            args += [\"--%s_out=%s\" % (lang, outdir)]\n+            args.append((\"--plugin=protoc-gen-%s=\" + path_tpl) % (lang, plugin.path))\n+            args.append(\"--%s_out=%s\" % (lang, outdir))\n             tools.append(plugin)\n \n         if not in_gen_dir:\n@@ -765,3 +765,261 @@ def check_protobuf_required_bazel_version():\n     copied filegroup. (Fixed in bazel 0.5.4)\n     \"\"\"\n     versions.check(minimum_bazel_version = \"0.5.4\")\n+\n+def _CcHdrs(srcs, use_grpc_plugin = False):\n+    ret = [s[:-len(\".proto\")] + \".pb.h\" for s in srcs]\n+    if use_grpc_plugin:\n+        ret += [s[:-len(\".proto\")] + \".grpc.pb.h\" for s in srcs]\n+    return ret\n+\n+def _CcSrcs(srcs, use_grpc_plugin = False):\n+    ret = [s[:-len(\".proto\")] + \".pb.cc\" for s in srcs]\n+    if use_grpc_plugin:\n+        ret += [s[:-len(\".proto\")] + \".grpc.pb.cc\" for s in srcs]\n+    return ret\n+\n+def __proto_gen_impl(ctx):\n+    \"\"\"General implementation for generating protos\"\"\"\n+    srcs = ctx.files.srcs\n+    deps = []\n+    deps += ctx.files.srcs\n+    source_dir = _SourceDir(ctx)\n+    gen_dir = _GenDir(ctx)\n+    if source_dir:\n+        import_flags = [\"-I\" + source_dir, \"-I\" + gen_dir]\n+    else:\n+        import_flags = [\"-I.\"]\n+\n+    for dep in ctx.attr.deps:\n+        import_flags += dep.proto.import_flags\n+        deps += dep.proto.deps\n+    import_flags = depset(import_flags).to_list()\n+    deps = depset(deps).to_list()\n+\n+    args = []\n+    if ctx.attr.gen_cc:\n+        args.append(\"--cpp_out=\" + gen_dir)\n+    if ctx.attr.gen_py:\n+        args.append(\"--python_out=\" + gen_dir)\n+\n+    inputs = srcs + deps\n+    tools = [ctx.executable.protoc]\n+    if ctx.executable.plugin:\n+        plugin = ctx.executable.plugin\n+        lang = ctx.attr.plugin_language\n+        if not lang and plugin.basename.startswith(\"protoc-gen-\"):\n+            lang = plugin.basename[len(\"protoc-gen-\"):]\n+        if not lang:\n+            fail(\"cannot infer the target language of plugin\", \"plugin_language\")\n+\n+        outdir = gen_dir\n+        if ctx.attr.plugin_options:\n+            outdir = \",\".join(ctx.attr.plugin_options) + \":\" + outdir\n+        args.append(\"--plugin=protoc-gen-%s=%s\" % (lang, plugin.path))\n+        args.append(\"--%s_out=%s\" % (lang, outdir))\n+        tools.append(plugin)\n+\n+    if args:\n+        ctx.actions.run(\n+            inputs = inputs,\n+            outputs = ctx.outputs.outs,\n+            arguments = args + import_flags + [s.path for s in srcs],\n+            executable = ctx.executable.protoc,\n+            mnemonic = \"ProtoCompile\",\n+            tools = tools,\n+            use_default_shell_env = True,\n+        )\n+\n+    return struct(\n+        proto = struct(\n+            srcs = srcs,\n+            import_flags = import_flags,\n+            deps = deps,\n+        ),\n+    )\n+\n+proto_gen = rule(\n+    attrs = {\n+        \"srcs\": attr.label_list(allow_files = True),\n+        \"deps\": attr.label_list(providers = [\"proto\"]),\n+        \"includes\": attr.string_list(),\n+        \"protoc\": attr.label(\n+            cfg = \"exec\",\n+            executable = True,\n+            allow_single_file = True,\n+            mandatory = True,\n+        ),\n+        \"plugin\": attr.label(\n+            cfg = \"exec\",\n+            allow_files = True,\n+            executable = True,\n+        ),\n+        \"plugin_language\": attr.string(),\n+        \"plugin_options\": attr.string_list(),\n+        \"gen_cc\": attr.bool(),\n+        \"gen_py\": attr.bool(),\n+        \"outs\": attr.output_list(),\n+    },\n+    implementation = __proto_gen_impl,\n+)\n+\n+\"\"\"Generates codes from Protocol Buffers definitions.\n+\n+This rule helps you to implement Skylark macros specific to the target\n+language. You should prefer more specific `cc_proto_library `,\n+`py_proto_library` and others unless you are adding such wrapper macros.\n+\n+Args:\n+  srcs: Protocol Buffers definition files (.proto) to run the protocol compiler\n+    against.\n+  deps: a list of dependency labels; must be other proto libraries.\n+  includes: a list of include paths to .proto files.\n+  protoc: the label of the protocol compiler to generate the sources.\n+  plugin: the label of the protocol compiler plugin to be passed to the protocol\n+    compiler.\n+  plugin_language: the language of the generated sources\n+  plugin_options: a list of options to be passed to the plugin\n+  gen_cc: generates C++ sources in addition to the ones from the plugin.\n+  gen_py: generates Python sources in addition to the ones from the plugin.\n+  outs: a list of labels of the expected outputs from the protocol compiler.\n+\"\"\"\n+\n+def cc_proto_library(\n+        name,\n+        srcs = [],\n+        deps = [],\n+        cc_libs = [],\n+        include = None,\n+        protoc = \"@com_google_protobuf//:protoc\",\n+        internal_bootstrap_hack = False,\n+        use_grpc_plugin = False,\n+        default_runtime = \"@com_google_protobuf//:protobuf\",\n+        **kwargs):\n+    \"\"\"Bazel rule to create a C++ protobuf library from proto source files\n+\n+    NOTE: the rule is only an internal workaround to generate protos. The\n+    interface may change and the rule may be removed when bazel has introduced\n+    the native rule.\n+\n+    Args:\n+      name: the name of the cc_proto_library.\n+      srcs: the .proto files of the cc_proto_library.\n+      deps: a list of dependency labels; must be cc_proto_library.\n+      cc_libs: a list of other cc_library targets depended by the generated\n+          cc_library.\n+      include: a string indicating the include path of the .proto files.\n+      protoc: the label of the protocol compiler to generate the sources.\n+      internal_bootstrap_hack: a flag indicating if the cc_proto_library is used only\n+          for bootstrapping. When it is set to True, no files will be generated.\n+          The rule will simply be a provider for .proto files, so that other\n+          cc_proto_library can depend on it.\n+      use_grpc_plugin: a flag to indicate whether to call the grpc C++ plugin\n+          when processing the proto files.\n+      default_runtime: the implicitly default runtime which will be depended on by\n+          the generated cc_library target.\n+      **kwargs: other keyword arguments that are passed to cc_library.\n+\n+    \"\"\"\n+\n+    includes = []\n+    if include != None:\n+        includes = [include]\n+\n+    if internal_bootstrap_hack:\n+        # For pre-checked-in generated files, we add the internal_bootstrap_hack\n+        # which will skip the codegen action.\n+        proto_gen(\n+            name = name + \"_genproto\",\n+            srcs = srcs,\n+            deps = [s + \"_genproto\" for s in deps],\n+            includes = includes,\n+            protoc = protoc,\n+            visibility = [\"//visibility:public\"],\n+        )\n+\n+        # An empty cc_library to make rule dependency consistent.\n+        native.cc_library(\n+            name = name,\n+            **kwargs\n+        )\n+        return\n+\n+    grpc_cpp_plugin = None\n+    if use_grpc_plugin:\n+        grpc_cpp_plugin = \"//external:grpc_cpp_plugin\"\n+\n+    gen_srcs = _CcSrcs(srcs, use_grpc_plugin)\n+    gen_hdrs = _CcHdrs(srcs, use_grpc_plugin)\n+    outs = gen_srcs + gen_hdrs\n+\n+    proto_gen(\n+        name = name + \"_genproto\",\n+        srcs = srcs,\n+        deps = [s + \"_genproto\" for s in deps],\n+        includes = includes,\n+        protoc = protoc,\n+        plugin = grpc_cpp_plugin,\n+        plugin_language = \"grpc\",\n+        gen_cc = 1,\n+        outs = outs,\n+        visibility = [\"//visibility:public\"],\n+    )\n+\n+    if default_runtime and not default_runtime in cc_libs:\n+        cc_libs = cc_libs + [default_runtime]\n+    if use_grpc_plugin:\n+        cc_libs = cc_libs + [\"//external:grpc_lib\"]\n+\n+    native.cc_library(\n+        name = name,\n+        srcs = gen_srcs,\n+        hdrs = gen_hdrs,\n+        deps = cc_libs + deps,\n+        includes = includes,\n+        alwayslink = 1,\n+        **kwargs\n+    )\n+\n+\"\"\"Generates codes from Protocol Buffers definitions.\n+\n+This rule helps you to implement Skylark macros specific to the target\n+language. You should prefer more specific `cc_proto_library `,\n+`py_proto_library` and others unless you are adding such wrapper macros.\n+\n+Args:\n+  srcs: Protocol Buffers definition files (.proto) to run the protocol compiler\n+    against.\n+  deps: a list of dependency labels; must be other proto libraries.\n+  includes: a list of include paths to .proto files.\n+  protoc: the label of the protocol compiler to generate the sources.\n+  plugin: the label of the protocol compiler plugin to be passed to the protocol\n+    compiler.\n+  plugin_language: the language of the generated sources\n+  plugin_options: a list of options to be passed to the plugin\n+  gen_cc: generates C++ sources in addition to the ones from the plugin.\n+  gen_py: generates Python sources in addition to the ones from the plugin.\n+  outs: a list of labels of the expected outputs from the protocol compiler.\n+\"\"\"\n+\n+def _adapt_proto_library_impl(ctx):\n+    deps = [dep[ProtoInfo] for dep in ctx.attr.deps]\n+\n+    srcs = [src for dep in deps for src in dep.direct_sources]\n+    return struct(\n+        proto = struct(\n+            srcs = srcs,\n+            import_flags = [\"-I{}\".format(path) for dep in deps for path in dep.transitive_proto_path.to_list()],\n+            deps = srcs,\n+        ),\n+    )\n+\n+adapt_proto_library = rule(\n+    implementation = _adapt_proto_library_impl,\n+    attrs = {\n+        \"deps\": attr.label_list(\n+            mandatory = True,\n+            providers = [ProtoInfo],\n+        ),\n+    },\n+    doc = \"Adapts `proto_library` from `@rules_proto` to be used with `{cc,py}_proto_library` from this file.\",\n+)\n"
  },
  {
    "path": "bazel/patches/rules_foreign_cc.patch",
    "content": "diff --git a/MODULE.bazel b/MODULE.bazel\nindex be3a727..6528ebe 100644\n--- a/MODULE.bazel\n+++ b/MODULE.bazel\n@@ -26,7 +26,7 @@ use_repo(python, \"python_3_12\")\n tools = use_extension(\"@rules_foreign_cc//foreign_cc:extensions.bzl\", \"tools\")\n use_repo(\n     tools,\n-    \"cmake_3.31.7_toolchains\",\n+    \"cmake_3.23.2_toolchains\",\n     \"cmake_src\",\n     \"gettext_runtime\",\n     \"glib_dev\",\n@@ -41,7 +41,7 @@ use_repo(\n \n register_toolchains(\n     \"@rules_foreign_cc_framework_toolchains//:all\",\n-    \"@cmake_3.31.7_toolchains//:all\",\n+    \"@cmake_3.23.2_toolchains//:all\",\n     \"@ninja_1.12.1_toolchains//:all\",\n     \"@python_3_12//:all\",\n     \"@rules_foreign_cc//toolchains:all\",\ndiff --git a/foreign_cc/extensions.bzl b/foreign_cc/extensions.bzl\nindex a027279..5b84a87 100644\n--- a/foreign_cc/extensions.bzl\n+++ b/foreign_cc/extensions.bzl\n@@ -3,7 +3,7 @@\n load(\"//foreign_cc:repositories.bzl\", \"rules_foreign_cc_dependencies\")\n load(\"//toolchains:prebuilt_toolchains.bzl\", \"prebuilt_toolchains\")\n \n-_DEFAULT_CMAKE_VERSION = \"3.31.7\"\n+_DEFAULT_CMAKE_VERSION = \"3.23.2\"\n _DEFAULT_NINJA_VERSION = \"1.12.1\"\n \n cmake_toolchain_version = tag_class(attrs = {\ndiff --git a/foreign_cc/repositories.bzl b/foreign_cc/repositories.bzl\nindex cc6266b..cc87f2a 100644\n--- a/foreign_cc/repositories.bzl\n+++ b/foreign_cc/repositories.bzl\n@@ -9,7 +9,7 @@ load(\"//toolchains:toolchains.bzl\", \"built_toolchains\", \"prebuilt_toolchains\", \"\n def rules_foreign_cc_dependencies(\n         native_tools_toolchains = [],\n         register_default_tools = True,\n-        cmake_version = \"3.31.7\",\n+        cmake_version = \"3.23.2\",\n         make_version = \"4.4.1\",\n         ninja_version = \"1.12.1\",\n         meson_version = \"1.5.1\",\n"
  },
  {
    "path": "bazel/repositories.bzl",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"//engine/bazel:engine_deps.bzl\", \"engine_deps\")\n\ndef scql_deps():\n    engine_deps()\n"
  },
  {
    "path": "cmd/docgen/main.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path\"\n\t\"sort\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\ntype OpDocFiller struct {\n\tVersion  int\n\tAllOpDef []*proto.OperatorDef\n}\n\nfunc check(e error) {\n\tif e != nil {\n\t\tpanic(e)\n\t}\n}\n\nfunc AttributeToString(attribute *proto.AttributeValue) string {\n\tt := attribute.GetT()\n\tswitch t.ElemType {\n\tcase proto.PrimitiveDataType_BOOL:\n\t\tif len(t.BoolData) == 1 {\n\t\t\treturn fmt.Sprintf(\"%v\", t.GetBoolData()[0])\n\t\t}\n\t\treturn fmt.Sprintf(\"%v\", t.GetBoolData())\n\tcase proto.PrimitiveDataType_STRING:\n\t\tif len(t.StringData) == 1 {\n\t\t\treturn t.GetStringData()[0]\n\t\t}\n\t\treturn fmt.Sprintf(\"%v\", t.GetStringData())\n\tcase proto.PrimitiveDataType_FLOAT32:\n\t\tif len(t.FloatData) == 1 {\n\t\t\treturn fmt.Sprintf(\"%v\", t.GetFloatData()[0])\n\t\t}\n\t\treturn fmt.Sprintf(\"%v\", t.GetFloatData())\n\tcase proto.PrimitiveDataType_FLOAT64:\n\t\tif len(t.DoubleData) == 1 {\n\t\t\treturn fmt.Sprintf(\"%v\", t.GetDoubleData()[0])\n\t\t}\n\t\treturn fmt.Sprintf(\"%v\", t.GetDoubleData())\n\tcase proto.PrimitiveDataType_INT8, proto.PrimitiveDataType_INT16, proto.PrimitiveDataType_INT32:\n\t\tif len(t.Int32Data) == 1 {\n\t\t\treturn fmt.Sprintf(\"%v\", t.GetInt32Data()[0])\n\t\t}\n\t\treturn fmt.Sprintf(\"%v\", t.GetInt32Data())\n\tcase proto.PrimitiveDataType_INT64:\n\t\tif len(t.Int64Data) == 1 {\n\t\t\treturn fmt.Sprintf(\"%v\", t.GetInt64Data()[0])\n\t\t}\n\t\treturn fmt.Sprintf(\"%v\", t.GetInt64Data())\n\tdefault:\n\t\treturn \"error: unsupported attribute type\"\n\t}\n}\n\nfunc OptionToString(opt proto.FormalParameterOptions) string {\n\tswitch opt {\n\tcase proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE:\n\t\treturn \"single\"\n\tcase proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC:\n\t\treturn \"variadic\"\n\tcase proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_OPTIONAL:\n\t\treturn \"optional\"\n\tdefault:\n\t\treturn \"undefined\"\n\t}\n}\n\nfunc StatusToString(opt proto.TensorStatus) string {\n\tswitch opt {\n\tcase proto.TensorStatus_TENSORSTATUS_UNKNOWN:\n\t\treturn \"unknown\"\n\tcase proto.TensorStatus_TENSORSTATUS_PRIVATE:\n\t\treturn \"private\"\n\tcase proto.TensorStatus_TENSORSTATUS_SECRET:\n\t\treturn \"secret\"\n\tcase proto.TensorStatus_TENSORSTATUS_CIPHER:\n\t\treturn \"cipher\"\n\tcase proto.TensorStatus_TENSORSTATUS_PUBLIC:\n\t\treturn \"public\"\n\tdefault:\n\t\treturn \"undefined\"\n\t}\n}\n\nfunc StatusListToString(in *proto.TensorStatusList) string {\n\tvar result []string\n\tfor _, e := range in.Status {\n\t\tresult = append(result, StatusToString(e))\n\t}\n\treturn strings.Join(result, \",\")\n}\n\nfunc main() {\n\tops, version := operator.GetAllOpDef()\n\tsort.Slice(ops, func(i, j int) bool {\n\t\treturn ops[i].GetName() < ops[j].GetName()\n\t})\n\tfiller := OpDocFiller{\n\t\tAllOpDef: ops,\n\t\tVersion:  version,\n\t}\n\tfileName := \"cmd/docgen/scql_operators.md.tmpl\"\n\ttmpl, err := template.New(path.Base(fileName)).Funcs(\n\t\ttemplate.FuncMap{\n\t\t\t\"attributeToString\":  AttributeToString,\n\t\t\t\"optionToString\":     OptionToString,\n\t\t\t\"statusToString\":     StatusToString,\n\t\t\t\"statusListToString\": StatusListToString,\n\t\t}).ParseFiles(fileName)\n\tcheck(err)\n\n\tf, err := os.Create(\"docs/reference/operators.md\")\n\tcheck(err)\n\terr = tmpl.Execute(f, filler)\n\tcheck(err)\n}\n"
  },
  {
    "path": "cmd/docgen/scql_operators.md.tmpl",
    "content": "# SCQL Operators Specification\n\nThis is a specification (not a kernel library) of SCQL operators, including operator signatures and semantics.\n\n## Op List\n\n<!-- Autogenerated by docgen; don't manually edit -->\n{{- /*gotype: github.com/secretflow/scql/cmd/docgen.OpDocFiller*/ -}}\n\n{{- range $index, $op := .AllOpDef}}\n{{- if gt $index 0}}\n{{end}}\n### `{{$op.Name}}`\n\n{{$op.Definition}}\n\n**Inputs:**\n{{- if $op.InputParams}}\n{{- range $param := $op.InputParams}}\n1. `{{$param.ParamName}}`({{optionToString $param.Option}}, {{$param.ParameterStatusConstraintName}}): {{$param.Definition}}\n{{- end}}\n{{- else}}\nNo input parameter.\n{{- end}}\n\n**Outputs:**\n{{- if $op.OutputParams}}\n{{- range $param := $op.OutputParams}}\n1. `{{$param.ParamName}}`({{optionToString $param.Option}}, {{$param.ParameterStatusConstraintName}}): {{$param.Definition}}\n{{- end}}\n{{- else}}\nNo output parameter.\n{{- end}}\n\n{{- if $op.AttributeParams}}\n\n**Attributes:**\n{{- range $attr := $op.AttributeParams}}\n1. `{{$attr.Name}}`: {{$attr.Definition}}\n{{- end}}\n\n{{- end}}\n{{- if $op.DefaultAttributeValues}}\n\n**Default Attribute Values:**\n{{- range $name, $attr := $op.DefaultAttributeValues}}\n1. `{{$name}}`: {{attributeToString $attr}}\n{{- end}}\n\n{{- end}}\n\n**TensorStatus(ShareType) Constraints:**\n{{- range $name, $statusList := $op.ParamStatusConstraints}}\n1. `{{$name}}`: {{statusListToString $statusList}}\n{{- end }}\n\n\n{{- end}}\n"
  },
  {
    "path": "docs/CONTRIBUTING.md",
    "content": "# Contributing docs | 文档贡献指南 <!-- omit from toc -->\n\n- [tl;dr](#tldr)\n- [Prerequisites](#prerequisites)\n- [Setting up](#setting-up)\n- [Building docs](#building-docs)\n- [Previewing docs](#previewing-docs)\n- [Translations](#translations)\n  - [Updating translation files](#updating-translation-files)\n  - [Translating](#translating)\n  - [Previewing translated docs](#previewing-translated-docs)\n- [Cleaning up](#cleaning-up)\n- [Reporting issues](#reporting-issues)\n- [前置条件](#前置条件)\n- [环境准备](#环境准备)\n- [构建文档](#构建文档)\n- [预览文档](#预览文档)\n- [更新翻译](#更新翻译)\n  - [同步翻译文件](#同步翻译文件)\n  - [进行翻译](#进行翻译)\n  - [预览翻译](#预览翻译)\n- [文件清理](#文件清理)\n- [报告问题](#报告问题)\n\n> [!TIP]\n>\n> Command line examples in this guide assume your working directory to be [docs/](./).\n\n## tl;dr\n\n```sh\npython -m pip install -r requirements.txt\nsecretflow-doctools update-translations --lang zh_CN\nsecretflow-doctools build --lang en --lang zh_CN\nsecretflow-doctools preview\n```\n\n## Prerequisites\n\nThis project uses [Sphinx] to build documentation. You will need:\n\n- [Python] >= 3.10\n\n## Setting up\n\nRun:\n\n```sh\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install -r requirements.txt\n```\n\nThis will:\n\n- Create a new [virtual environment][venv] in a `.venv` directory\n- Activate the virtual environment (so that dependencies are installed to the correct\n  environment).\n- Install the [required dependencies](./requirements.txt)\n\n> [!TIP]\n>\n> This example uses Python's built-in [`venv`][venv] module. You are free to use other\n> package managers such as [uv] or [mamba].\n\n## Building docs\n\n[`secretflow-doctools`] is a command-line utility for building docs for SecretFlow\nprojects.\n\nTo build docs, run:\n\n```sh\nsecretflow-doctools build --lang en --lang zh_CN\n```\n\nThis will build both the English (`en`) and the Simplified Chinese (`zh_CN`) versions of\nthe documentation.\n\nYou should be able to see the following output:\n\n```log\nSUCCESS  to preview, run: secretflow-doctools preview -c .\n```\n\n> [!TIP]\n>\n> If you are getting a \"command not found\" error, you might not have activated the\n> correct environment by running `source .venv/bin/activate`. Please review\n> [Setting up](#setting-up).\n\n## Previewing docs\n\nThe utility features a documentation previewer. You will be able to visualize how your\nchanges will eventually appear on our [website].\n\nTo preview the docs that was built, run:\n\n```sh\nsecretflow-doctools preview\n```\n\nThis will start the server. You should be able to see the following output:\n\n```\n * Running on http://127.0.0.1:5000\n```\n\nNavigate to <http://127.0.0.1:5000> on your browser (the port number may be different),\nyou should be able to see a page similar to the following:\n\n<figure>\n  <img src=\"imgs/CONTRIBUTING/preview-sitemap.png\" alt=\"the sitemap page\">\n</figure>\n\nClick on a version to see the preview. You should be able to see a page similar to the\nfollowing:\n\n<figure>\n  <img src=\"imgs/CONTRIBUTING/preview-content.png\" alt=\"the content page\">\n</figure>\n\n> [!TIP]\n>\n> You may leave the preview server running. When you run the build command again,\n> refresh the page to see updated content.\n\n## Translations\n\n### Updating translation files\n\nAfter updating source docs, you should also update the corresponding translation files.\n\n> [!IMPORTANT]\n>\n> If your updates involve rewriting existing texts, you MUST update translation files,\n> otherwise some translated paragraphs may fall back to showing the original text.\n\nRun:\n\n```sh\nsecretflow-doctools update-translations --lang zh_CN\n# `--lang zh_CN` sets the target language to Chinese (i.e. you are translating into Chinese)\n```\n\nThis will:\n\n- Scan source text for changes\n- Update the translation files under [locales/](locales/) such that they become in-sync\n  again\n\nIf there are updates, you should be able to see output similar to the following, and see\nchanges in source control:\n\n```\nUpdate: locales/zh_CN/LC_MESSAGES/index.po +1, -0\n...\nSUCCESS  finished updating translation files\n```\n\n### Translating\n\nThis project uses [GNU gettext][gettext] to translate docs during build. Translation\nfiles are under [locales/](locales/).\n\nPaths to the [translation files (PO files)][gettext-po] mirror their source document\ncounterparts. For example:\n\n|              |                                                                                                    |\n| :----------- | :------------------------------------------------------------------------------------------------- |\n| Source texts | [**topics/ccl/usage**.rst](topics/ccl/usage.rst)                                                   |\n| Translations | [locales/zh_CN/LC_MESSAGES/**topics/ccl/usage**.po](locales/zh_CN/LC_MESSAGES/topics/ccl/usage.po) |\n\nPO files have the following syntax:\n\n```gettext\nmsgid \"Hello, world!\"\nmsgstr \"你好，世界！\"\n```\n\n`msgid` comes from source docs, which will be used to lookup translations during build,\nand you should not modify them.\n\n`msgstr` is the translation. Please update these.\n\n> [!TIP]\n>\n> [Poedit] is a free and open-source graphical editor for gettext PO files and is highly\n> recommended.\n>\n> <figure>\n>   <img src=\"https://github.com/secretflow/doctools/raw/21e7d4d04f88c29fb68d9d668c6a74d43726eddf/tests/demo/media/poedit.png\" alt=\"screenshot of Poedit\">\n> </figure>\n\n> [!IMPORTANT]\n\n- `msgstr` may contain inline markups, such as bolded text or links. Translations should\n  retain such markups. You should ensure the markup syntax is consistent with the source\n  document:\n\n  ```diff\n    msgid \"This is a `link <https://example.org/>`_.\"\n  - msgstr \"这是一个 [链接](https://example.org/) 。\"\n  + msgstr \"这是一个 `链接 <https://example.org/>`_ 。\"\n  ```\n\n- You may notice a `fuzzy` label after\n  [updating translation files](#updating-translation-files):\n\n  ```diff\n    #: ../../topics/ccl/usage.rst:9\n  + #, fuzzy\n  - msgid \"What is SCQL CCL? Please read :doc:`/topics/ccl/intro`.\"\n  + msgid \"What is SCQL CCL? Please read :doc:`/topics/ccl/intro` first.\"\n    msgstr \"什么是 SCQL CCL？请参阅 :doc:`/topics/ccl/intro`。\"\n  ```\n\n  `fuzzy` indicates that a source paragraph is updated but only slightly. You should\n  revise `fuzzy` translations, and then remove the `fuzzy` label.\n\n  `fuzzy` entries will still appear in the output even if they not updated in time,\n  albeit the displayed content is then slightly different from source text.\n\n- You may notice `.mo` files under [locales/](locales/). These are binary files\n  autogenerated during builds and are not editable. The files to edit are `.po` files.\n\n### Previewing translated docs\n\nAfter updating translations, [build docs](#building-docs) again to preview them.\n\n## Cleaning up\n\nThe above tasks generate temporary files under [\\_build](./_build/). To clean up these\nfiles, run:\n\n```sh\nsecretflow-doctools clean\n```\n\n## Reporting issues\n\nIf commands or previews aren't working as expecting, please file an issue at\n<https://github.com/secretflow/doctools/issues>.\n\nFor project-specific questions, please file an issue in this repository instead.\n\n> [!NOTE]\n>\n> To help with troubleshooting, set the `LOGURU_LEVEL=DEBUG` environment variable to see\n> debug logs.\n>\n> `secretflow-doctools` invokes other programs. When `LOGURU_LEVEL=DEBUG` is set,\n> logging will contain the full commands being run:\n>\n> | Command                                   | Delegates to                   |\n> | :---------------------------------------- | :----------------------------- |\n> | `secretflow-doctools build`               | [`sphinx-build`][sphinx-build] |\n> | `secretflow-doctools update-translations` | [`sphinx-intl`]                |\n\n---\n\n> [!TIP]\n>\n> 下文的示例命令建议在[本目录 (docs)](./) 下执行。\n\n## 前置条件\n\n本项目使用 [Sphinx] 作为文档框架。你需要：\n\n- [Python] >= 3.10\n\n## 环境准备\n\n执行：\n\n```sh\npython -m venv .venv\nsource .venv/bin/activate\npython -m pip install -r requirements.txt\n```\n\n这将会：\n\n- 在当前目录下的 `.venv` 目录创建一个 [Python 虚拟环境][venv]\n- 激活该虚拟环境（以确保依赖被安装到正确位置）\n- 安装文档构建[所需要的依赖](./requirements.txt)\n\n> [!TIP]\n>\n> 这里以 Python 自带的 [`venv`][venv] 为示例。你也可以使用 [uv], [mamba] 等其他的依赖管\n> 理工具。\n\n## 构建文档\n\n[`secretflow-doctools`] 是针对隐语项目文档构建的辅助工具，它协助开发者在本地构建并\n且[预览](#预览文档)文档。\n\n执行：\n\n```sh\nsecretflow-doctools build --lang en --lang zh_CN\n```\n\n这将会构建英文版 `en` 以及中文版 `zh_CN` 文档。\n\n如果一切正常，你应当能看到以下输出：\n\n```log\nSUCCESS  to preview, run: secretflow-doctools preview -c .\n```\n\n> [!TIP]\n>\n> 如果提示 `secretflow-doctools` 命令未找到，你可能没有执行 `source .venv/bin/activate`\n> 以激活正确的 Python 环境；请参考[环境准备](#环境准备)中的指引。\n\n如果想要只构建某个语言的文档，可以调整 `--lang` 选项。\n\n## 预览文档\n\n工具提供了本地预览的能力，帮助开发者验证文档在**发布到[隐语官网][website]后的显示效\n果**。\n\n执行：\n\n```sh\nsecretflow-doctools preview\n```\n\n这将会在本地启动一个预览服务器。你应当能看到以下输出：\n\n```\n * Running on http://127.0.0.1:5000\n```\n\n用浏览器访问 <http://127.0.0.1:5000> （或其它端口号），你应当能看到类似下图的页面，其中\n将会列出在本地构建好的文档版本：\n\n<figure>\n  <img src=\"imgs/CONTRIBUTING/preview-sitemap.png\" alt=\"the sitemap page\">\n</figure>\n\n点击一个版本即可打开对应预览，你应当能看到类似下图的页面：\n\n<figure>\n  <img src=\"imgs/CONTRIBUTING/preview-content.png\" alt=\"the content page\">\n</figure>\n\n> [!TIP]\n>\n> 你可以保持预览服务器一直开启：在重新构建文档后，刷新页面即可看到更新的内容。\n\n## 更新翻译\n\n### 同步翻译文件\n\n当你更新了文档原文（无论是新增、修改还是删除），你需要同时更新对应的翻译文件。\n\n> [!IMPORTANT]\n>\n> 如果你的变更是对现有文本进行修改，请务必同步翻译文件，否则现有翻译可能会失效，发布后可\n> 能会出现中英文夹杂的情况。\n\n执行：\n\n```sh\nsecretflow-doctools update-translations --lang zh_CN\n# 其中 --lang zh_CN 代表目标语言是中文（翻译成中文）\n```\n\n这将会：\n\n- 扫描文档原文的文本内容\n- 更新 [locales/](locales/) 目录下的翻译文件，使得它们和原文维持同步\n\n如果有更新，你应当能看到类似下文的输出，并且在版本控制中看到文件修改：\n\n```\nUpdate: locales/zh_CN/LC_MESSAGES/index.po +1, -0\n...\nSUCCESS  finished updating translation files\n```\n\n### 进行翻译\n\n本项目使用 [GNU gettext][gettext] 来配置文档内容的多语言版本。翻译用文件全部位于\n[locales/](locales/) 目录下。\n\n[翻译文件（PO 文件）][gettext-po]的路径与文档原文是**一对一**的关系，示例：\n\n|      |                                                                                                    |\n| :--- | :------------------------------------------------------------------------------------------------- |\n| 原文 | [**topics/ccl/usage**.rst](topics/ccl/usage.rst)                                                   |\n| 翻译 | [locales/zh_CN/LC_MESSAGES/**topics/ccl/usage**.po](locales/zh_CN/LC_MESSAGES/topics/ccl/usage.po) |\n\n翻译文件的格式如下：\n\n```gettext\nmsgid \"Hello, world!\"\nmsgstr \"你好，世界！\"\n```\n\n`msgid` 来自文档原文，**将会用于在构建时通过原文索引到翻译，因此请勿修改。**\n\n`msgstr` 是翻译后的文本，请修改这一字段。\n\n> [!TIP]\n>\n> [Poedit] 是一个用于编辑 PO 文件的自由开源软件。可以尝试使用它来进行翻译。\n>\n> <figure>\n>   <img src=\"https://github.com/secretflow/doctools/raw/21e7d4d04f88c29fb68d9d668c6a74d43726eddf/tests/demo/media/poedit.png\" alt=\"screenshot of Poedit\">\n> </figure>\n\n> [!IMPORTANT]\n>\n> 以下是翻译的一些注意事项：\n\n- `msgstr` 中可能会包含样式标记（比如字体加粗、链接等），在翻译文本中，标记应当与原文一\n  致：\n\n  ```diff\n    msgid \"This is a `link <https://example.org/>`_.\"\n  - msgstr \"这是一个 [链接](https://example.org/) 。\"\n  + msgstr \"这是一个 `链接 <https://example.org/>`_ 。\"\n  ```\n\n- 在[同步翻译文件](#同步翻译文件)后，你可能会留意到一些翻译条目被加上了 `fuzzy` 的标记，\n  比如：\n\n  ```diff\n    #: ../../topics/ccl/usage.rst:9\n  + #, fuzzy\n  - msgid \"What is SCQL CCL? Please read :doc:`/topics/ccl/intro`.\"\n  + msgid \"What is SCQL CCL? Please read :doc:`/topics/ccl/intro` first.\"\n    msgstr \"什么是 SCQL CCL？请参阅 :doc:`/topics/ccl/intro`。\"\n  ```\n\n  `fuzzy` 意味着 `gettext` 判断原文有轻微变化，需要人工校对。你应当更新翻译，然后将\n  `fuzzy` 标记去掉。\n\n  `fuzzy` 条目的意义在于构建后不会失效，也就是说，即使没有及时更新翻译，旧翻译也能继续显\n  示（不过会稍微与原文不一致）。\n\n- 你可能会在 [locales/](locales/) 目录下找到后缀为 `.mo` 的文件，这些文件时构建时产生的\n  二进制文件，它们无法被修改也无需关注，你应当修改后缀为 `.po` 的文件。\n\n### 预览翻译\n\n在更新了翻译文件之后，重新[执行文档构建](#构建文档)然后[预览文档](#预览文档)，即可看到翻\n译后的显示效果。\n\n## 文件清理\n\n以上流程会产生额外的临时文件，这些文件全部位于 [\\_build](./_build/) 目录下。如果需要清理\n，可以执行：\n\n```sh\nsecretflow-doctools clean\n```\n\n## 报告问题\n\n如果在以上过程中遇到报错、预览无法显示等问题，可以提交问题到\n<https://github.com/secretflow/doctools/issues>。\n\n文档内容及本项目代码的相关问题请提交到本项目的 Issues 中。\n\n> [!NOTE]\n>\n> 为协助排查问题，你可以设置 `LOGURU_LEVEL=DEBUG` 环境变量来让文档工具输出更多日志。\n>\n> `secretflow-doctools` 会调用其他工具，在 `LOGURU_LEVEL=DEBUG` 时，日志会在每个步骤打印\n> 完整的命令行指令：\n>\n> |                                           |                                |\n> | :---------------------------------------- | :----------------------------- |\n> | `secretflow-doctools build`               | [`sphinx-build`][sphinx-build] |\n> | `secretflow-doctools update-translations` | [`sphinx-intl`]                |\n\n[`secretflow-doctools`]: https://github.com/secretflow/doctools\n[mamba]: https://mamba.readthedocs.io/en/latest/\n[Poedit]: https://poedit.net/\n[Python]: https://www.python.org/\n[Sphinx]: https://www.sphinx-doc.org/en/master/tutorial/index.html\n[uv]: https://docs.astral.sh/uv/\n[venv]: https://docs.python.org/3/library/venv.html\n[gettext]: https://www.gnu.org/software/gettext/\n[gettext-po]: https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html\n[sphinx-build]: https://www.sphinx-doc.org/en/master/man/sphinx-build.html\n[`sphinx-intl`]: https://www.sphinx-doc.org/en/master/usage/advanced/intl.html\n[website]: https://www.secretflow.org.cn/\n"
  },
  {
    "path": "docs/Makefile",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n.PHONY: build\nbuild:\n\tsecretflow-doctools build --lang en --lang zh_CN\n\n.PHONY: translations\ntranslations:\n\tsecretflow-doctools update-translations --lang zh_CN\n\n.PHONY: preview\npreview:\n\tsecretflow-doctools preview\n\n.PHONY: clean\nclean:\n\tsecretflow-doctools clean\n"
  },
  {
    "path": "docs/_static/css/custom.css",
    "content": "@import \"../basic.css\";\n\nhtml[data-theme=\"light\"] {\n    --pst-color-primary: rgb(22 119 255);\n    --pst-color-secondary: rgb(22 255 201);\n}\n\nhtml[data-theme=\"dark\"] {\n    --pst-color-primary: rgb(22 119 255);\n    --pst-color-secondary: rgb(22 255 201);\n    --pst-color-background: rgb(56, 56, 56);\n}"
  },
  {
    "path": "docs/_static/js/custom.js",
    "content": "$(document).ready(function () {\n    $('a.external').attr('target', '_blank');\n});\n"
  },
  {
    "path": "docs/conf.py",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nproject = \"SCQL\"\n\nextensions = [\n    # enable support for .md files\n    # https://myst-parser.readthedocs.io/en/latest/\n    \"myst_parser\",\n    \"secretflow_doctools\",\n    # link to titles using :ref:`Title text`\n    # https://www.sphinx-doc.org/en/master/usage/extensions/autosectionlabel.html\n    \"sphinx.ext.autosectionlabel\",\n    \"sphinx.ext.extlinks\",\n    \"sphinx.ext.graphviz\",\n    \"sphinx.ext.todo\",\n    \"sphinxcontrib.mermaid\",\n]\n\n# also link to titles using :ref:`path/to/document:Title text`\n# (note that path should not have a leading slash)\n# https://www.sphinx-doc.org/en/master/usage/extensions/autosectionlabel.html#confval-autosectionlabel_prefix_document\nautosectionlabel_prefix_document = True\n\n# source files are in this language\nlanguage = \"en\"\n# translation files are in this directory\nlocale_dirs = [\"./locales/\"]\n# this should be false so 1 doc file corresponds to 1 translation file\ngettext_compact = False\ngettext_uuid = False\n# allow source texts to keep using outdated translations if they are only marginally changed\n# otherwise any change to source text will cause their translations to not appear\ngettext_allow_fuzzy_translations = True\n\n# list of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\nexclude_patterns = [\n    \"CONTRIBUTING.md\",  # prevent CONTRIBUTING.md from being included in output, optional\n    \".venv\",\n    \"_build\",\n    \"Thumbs.db\",\n    \".DS_Store\",\n]\n\ntodo_include_todos = True\n\n# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html\nmyst_enable_extensions = [\n    # LaTeX math\n    # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#direct-latex-math\n    \"amsmath\",\n    # attributes\n    # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#attributes\n    \"attrs_block\",\n    \"attrs_inline\",\n    # code fence using :::\n    # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#code-fences-using-colons\n    \"colon_fence\",\n    # $math$ and $$math$$\n    # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#dollar-delimited-math\n    \"dollarmath\",\n    # :name: value\n    # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#field-lists\n    \"fieldlist\",\n    # <img src=\"...\">\n    # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#html-images\n    \"html_image\",\n    # detect \"bare\" links\n    # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#linkify\n    \"linkify\",\n    # \"double quotes\" => “double quotes”\n    # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#typography\n    \"smartquotes\",\n    # ~~strikethrough~~\n    # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#strikethrough\n    \"strikethrough\",\n]\n# enable all MyST syntax features\n# https://myst-parser.readthedocs.io/en/latest/configuration.html#global-configuration\nmyst_gfm_only = False\n# generate #anchors for heading # through ######\n# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#auto-generated-header-anchors\nmyst_heading_anchors = 6\n\nsuppress_warnings = [\"autosectionlabel\", \"myst.header\"]\n"
  },
  {
    "path": "docs/index.rst",
    "content": ".. SCQL documentation master file, created by\n   sphinx-quickstart on Wed Jul 13 19:32:45 2022.\n   You can adapt this file completely to your liking, but it should at least\n   contain the root `toctree` directive.\n\nSCQL Documentation\n==================\n\nSecure Collaborative Query Language (SCQL) is a system that translates SQL statements into a hybrid MPC-plaintext execution graph and executes them on a federation of database systems. The MPC framework is powered by `SPU <https://github.com/secretflow/spu>`_.\n\n.. important::\n\n   **You are viewing SCQL 2.0 OpenCore documentation.**\n\n   SCQL 2.0 uses a native **Compiler + Engine** architecture. Previous components (SCDB, SCQLBroker, CCL) are no longer supported.\n\n   Looking for SCQL 1.x documentation? Visit `SCQL 1.0.0b1 docs <https://www.secretflow.org.cn/en/docs/scql/1.0.0b1/>`_.\n\n\nGetting started\n---------------\n\nFollow the :doc:`OpenCore Quickstart </intro/opencore-quickstart>` to get started with SCQL's native compiler + engine architecture.\n\n\nSCQL Systems\n------------\n\n- **Overview**:\n  :doc:`SCQL system overview </topics/system/intro>`\n\n- **Security**:\n  :doc:`Security overview </topics/security/overview>`\n\n- **Reference**:\n  :doc:`SCQL implementation status </reference/implementation-status>`\n\n\nThe SCQL Language\n-----------------\n\n- **Reference**:\n  :doc:`SCQL language manual </reference/lang/manual>` |\n  :doc:`Compatibility with MySQL </reference/lang/mysql-compatibility>`\n\n\nDeployment\n----------\n\n.. note::\n   The previous deployment modes (P2P, Centralized, and Kuscia) are **deprecated and no longer supported**.\n\n   **Recommended approach**: Use native compiler + engine integration.\n\n   - See ``examples/opencore-demo/`` for integration examples\n\n\nFor contributors\n----------------\n\n- **Reference**:\n  :doc:`SCQL operators </reference/operators>`\n\n\n.. toctree::\n    :hidden:\n\n    intro/index\n    topics/index\n    reference/index\n"
  },
  {
    "path": "docs/intro/index.rst",
    "content": "Introduction\n============\n\n.. toctree::\n\n   opencore-quickstart\n"
  },
  {
    "path": "docs/intro/opencore-quickstart.rst",
    "content": "SCQL OpenCore Quickstart\n========================\n\nThis guide shows how to use SCQL's native compiler + engine architecture.\n\nArchitecture Overview\n---------------------\n\nSCQL consists of two components:\n\n- **Compiler**: Translates SQL queries into secure execution plans\n- **Engine**: Executes plans using MPC protocols\n\nWorkflow:\n\n1. Compile SQL to execution plan\n2. Send plan to engine nodes\n3. Get query results\n\nQuick Start\n-----------\n\nSetup\n^^^^^\n\n.. code-block:: bash\n\n    git clone https://github.com/secretflow/scql.git\n    cd scql\n\n    # Start engines\n    cd examples/tutorial\n    bash setup.sh\n    bash project_bootstrap.sh\n\nRun Example\n^^^^^^^^^^^\n\n.. code-block:: bash\n\n    # From examples/tutorial\n    ./opencore-demo --config example_config.json\n\nThis compiles a SQL query and executes it across Alice and Bob's engines.\n\n**Output:**\n\n.. code-block:: text\n\n    INFO[0000] Step 1: Compiling SQL to execution plan...\n    INFO[0000] Compilation successful. SubGraphs: 2\n    INFO[0000] Step 2: Executing plan on engine...\n    INFO[0000] Calling engine for party bob at localhost:8005...\n    INFO[0000] Calling engine for party alice at localhost:8003...\n    INFO[0000] Party alice execution succeeded\n    INFO[0000] Party bob execution succeeded\n    INFO[0000] Step 3: Query results:\n    [fetch]\n    17 rows in set: (0s)\n    +--------+-------------+-----+-----------------+-----------+\n    |   ID   | credit_rank | age |  order_amount   | is_active |\n    +--------+-------------+-----+-----------------+-----------+\n    | id0011 |           5 |  28 | 9816.2001953125 |         1 |\n    | id0019 |           6 |  25 | 9816.2001953125 |         1 |\n    | id0014 |           5 |  28 | 9816.2001953125 |         1 |\n    | id0001 |           6 |  20 |            3598 |         1 |\n    | id0006 |           5 |  25 |            3598 |         1 |\n    | id0010 |           5 |  25 |             322 |         0 |\n    | id0009 |           6 |  30 |            3598 |         1 |\n    | id0002 |           5 |  19 |             100 |         0 |\n    | id0005 |           6 |  30 |          4985.5 |         1 |\n    | id0016 |           5 |  26 | 9816.2001953125 |         1 |\n    | id0017 |           5 |  27 |            3598 |         1 |\n    | id0013 |           5 |  25 |             322 |         0 |\n    | id0008 |           6 |  50 | 9816.2001953125 |         1 |\n    | id0003 |           6 |  32 |            2549 |         1 |\n    | id0007 |           6 |  28 |             322 |         0 |\n    | id0012 |           6 |  50 |            3598 |         1 |\n    | id0020 |           5 |  28 | 9816.2001953125 |         1 |\n    +--------+-------------+-----+-----------------+-----------+\n\nConfiguration\n-------------\n\nThis is the configuration for ``examples/opencore-demo``, containing the minimal configuration required when integrating compiler + engine. For more tutorial information, please refer to the ``examples/tutorial`` directory.\n\n**Minimal Example:**\n\n.. code-block:: examples/tutorial/example_config.json\n\n    {\n        \"sql\": \"SELECT a.ID, a.credit_rank, a.age, b.order_amount, b.is_active FROM user_credit a JOIN user_stats b ON a.ID = b.ID WHERE a.age > 18\",\n        \"catalog\": {\n            \"tables\": [\n                {\n                    \"table_name\": \"user_credit\",\n                    \"columns\": [\n                        {\n                            \"name\": \"ID\",\n                            \"type\": \"string\",\n                            \"ordinal_position\": 1\n                        },\n                        {\n                            \"name\": \"credit_rank\",\n                            \"type\": \"int\",\n                            \"ordinal_position\": 2\n                        },\n                        {\n                            \"name\": \"income\",\n                            \"type\": \"int\",\n                            \"ordinal_position\": 3\n                        },\n                        {\n                            \"name\": \"age\",\n                            \"type\": \"int\",\n                            \"ordinal_position\": 4\n                        }\n                    ],\n                    \"ref_table\": \"alice.user_credit\",\n                    \"db_type\": \"mysql\",\n                    \"owner\": {\n                        \"code\": \"alice\"\n                    }\n                },\n                {\n                    \"table_name\": \"user_stats\",\n                    \"columns\": [\n                        {\n                            \"name\": \"ID\",\n                            \"type\": \"string\",\n                            \"ordinal_position\": 1\n                        },\n                        {\n                            \"name\": \"order_amount\",\n                            \"type\": \"float\",\n                            \"ordinal_position\": 2\n                        },\n                        {\n                            \"name\": \"is_active\",\n                            \"type\": \"int\",\n                            \"ordinal_position\": 3\n                        }\n                    ],\n                    \"ref_table\": \"bob.user_stats\",\n                    \"db_type\": \"mysql\",\n                    \"owner\": {\n                        \"code\": \"bob\"\n                    }\n                }\n            ]\n        },\n        \"security_conf\": {\n            \"reverse_inference_conf\": {\n                \"enable_reverse_inference\": false\n            }\n        },\n        \"engine_endpoints\": {\n            \"alice\": \"localhost:8003\",\n            \"bob\": \"localhost:8005\"\n        },\n        \"engine_link_endpoints\": {\n            \"alice\": \"tutorial-engine_alice-1:8004\",\n            \"bob\": \"tutorial-engine_bob-1:8004\"\n        },\n        \"engine_client_type\": \"GRPC\",\n        \"engine_timeout\": 300,\n        \"tls_ca_cert\": \"./tls/root-ca.crt\",\n        \"issuer\": \"alice\",\n        \"compile_opts\": {\n            \"spu_conf\": {\n                \"protocol\": \"SEMI2K\",\n                \"field\": \"FM64\"\n            },\n            \"batched\": false\n        }\n    }\n\n\nIntegration\n-----------\n\nBasic Usage\n^^^^^^^^^^^\n\n.. code-block:: go\n\n    import (\n        \"github.com/secretflow/scql/pkg/interpreter/compiler\"\n        \"github.com/secretflow/scql/pkg/executor\"\n    )\n\n    ...\n\n    // 1. Compile SQL\n    req := &v1.CompileSQLRequest{\n        Query:          sql,\n        Issuer:         &pb.PartyId{Code: \"alice\"},\n        Catalog:        catalog,\n        CompileOpts:    compileOpts,\n        SecurityConfig: securityConfig,\n    }\n    plan, err := compiler.Compile(ctx, req)\n\n    // 2. Execute on engines\n    client, _ := executor.NewEngineClient(\n\t\tclientType,\n\t\ttimeout,\n\t\ttlsConfig,\n\t\t\"application/json\",\n\t\t\"\",\n\t)\n    ...\n    result, err := client.RunExecutionPlan(\n        engineEndpoint,\n        \"\", // no credential\n        execReq,\n    )\n\nFor complete code, see ``examples/opencore-demo/main.go``.\n\nNext Steps\n----------\n\n- Compiler configuration: :doc:`/reference/compiler-config`\n- Engine configuration: :doc:`/reference/engine-config`\n- Implementation status: :doc:`/reference/implementation-status`\n- Examples: ``examples/opencore-demo/`` and ``examples/tutorial/``\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/index.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version:  SCQL\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-24 19:19+0800\\n\"\n\"PO-Revision-Date: 2023-10-11 20:47+0800\\n\"\n\"Last-Translator: \\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../index.rst:7\nmsgid \"SCQL Documentation\"\nmsgstr \"SCQL 文档\"\n\n#: ../../index.rst:9\nmsgid \"\"\n\"Secure Collaborative Query Language (SCQL) is a system that translates \"\n\"SQL statements into a hybrid MPC-plaintext execution graph and executes \"\n\"them on a federation of database systems. The MPC framework is powered by\"\n\" `SPU <https://github.com/secretflow/spu>`_.\"\nmsgstr \"\"\n\"Secure Collaborative Query Language (SCQL) 是一种能够将 SQL 语句转换为明密文混合执行图, \"\n\"并在联合数据库系统上执行的系统. 该系统的 MPC 框架由 `SPU <https://github.com/secretflow/spu>`_ \"\n\"提供支持.\"\n\n#: ../../index.rst:13\nmsgid \"**You are viewing SCQL 2.0 OpenCore documentation.**\"\nmsgstr \"**您正在查看 SCQL 2.0 OpenCore 文档.**\"\n\n#: ../../index.rst:15\nmsgid \"\"\n\"SCQL 2.0 uses a native **Compiler + Engine** architecture. Previous \"\n\"components (SCDB, SCQLBroker, CCL) are no longer supported.\"\nmsgstr \"\"\n\"SCQL 2.0 采用原生的 **Compiler + Engine** 架构. 之前的组件 (SCDB, SCQLBroker, CCL) \"\n\"不再支持.\"\n\n#: ../../index.rst:17\nmsgid \"\"\n\"Looking for SCQL 1.x documentation? Visit `SCQL 1.0.0b1 docs \"\n\"<https://www.secretflow.org.cn/en/docs/scql/1.0.0b1/>`_.\"\nmsgstr \"\"\n\"如果您正在寻找 SCQL 1.x 的文档, 请访问 `SCQL 1.0.0b1 文档 \"\n\"<https://www.secretflow.org.cn/en/docs/scql/1.0.0b1/>`_.\"\n\n#: ../../index.rst:21\nmsgid \"Getting started\"\nmsgstr \"开始\"\n\n#: ../../index.rst:23\nmsgid \"\"\n\"Follow the :doc:`OpenCore Quickstart </intro/opencore-quickstart>` to get\"\n\" started with SCQL's native compiler + engine architecture.\"\nmsgstr \"\"\n\"参考 :doc:`OpenCore 快速开始 </intro/opencore-quickstart>` 来开始使用 SCQL 的原生 \"\n\"compiler + engine 架构.\"\n\n#: ../../index.rst:27\nmsgid \"SCQL Systems\"\nmsgstr \"SCQL 系统\"\n\n#: ../../index.rst:29\n#, fuzzy\nmsgid \"**Overview**: :doc:`SCQL system overview </topics/system/intro>`\"\nmsgstr \"**概述**: :doc:`系统简介及架构设计 </topics/system/intro>`\"\n\n#: ../../index.rst:32\nmsgid \"**Security**: :doc:`Security overview </topics/security/overview>`\"\nmsgstr \"**安全性**: :doc:`安全性说明 </topics/security/overview>`\"\n\n#: ../../index.rst:35\nmsgid \"\"\n\"**Reference**: :doc:`SCQL implementation status </reference\"\n\"/implementation-status>`\"\nmsgstr \"**参考**: :doc:`SCQL 实现进度 </reference/implementation-status>`\"\n\n#: ../../index.rst:40\nmsgid \"The SCQL Language\"\nmsgstr \"SCQL 方言\"\n\n#: ../../index.rst:42\nmsgid \"\"\n\"**Reference**: :doc:`SCQL language manual </reference/lang/manual>` | \"\n\":doc:`Compatibility with MySQL </reference/lang/mysql-compatibility>`\"\nmsgstr \"\"\n\"**参考**: :doc:`SCQL 方言手册 </reference/lang/manual>` | :doc:`与 MySQL 兼容性 \"\n\"</reference/lang/mysql-compatibility>`\"\n\n#: ../../index.rst:48\nmsgid \"Deployment\"\nmsgstr \"部署\"\n\n#: ../../index.rst:51\nmsgid \"\"\n\"The previous deployment modes (P2P, Centralized, and Kuscia) are \"\n\"**deprecated and no longer supported**.\"\nmsgstr \"之前的部署模式 (P2P, 中心化和 Kuscia) 已经 **废弃且不再支持**.\"\n\n#: ../../index.rst:53\nmsgid \"**Recommended approach**: Use native compiler + engine integration.\"\nmsgstr \"**推荐方式**: 使用原生的 compiler + engine 集成方式.\"\n\n#: ../../index.rst:55\n#, fuzzy\nmsgid \"See ``examples/opencore-demo/`` for integration examples\"\nmsgstr \"查看 ``examples/opencore-demo/`` 了解集成示例\"\n\n#: ../../index.rst:59\nmsgid \"For contributors\"\nmsgstr \"贡献者文档\"\n\n#: ../../index.rst:61\nmsgid \"**Reference**: :doc:`SCQL operators </reference/operators>`\"\nmsgstr \"**参考**: :doc:`SCQL 算子规范 </reference/operators>`\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/intro/index.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2023-10-11 20:36+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.13.0\\n\"\n\n#: ../../intro/index.rst:2\nmsgid \"Introduction\"\nmsgstr \"介绍\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/intro/opencore-quickstart.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C)\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2026.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-24 17:24+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../intro/opencore-quickstart.rst:2\nmsgid \"SCQL OpenCore Quickstart\"\nmsgstr \"SCQL OpenCore 快速入门\"\n\n#: ../../intro/opencore-quickstart.rst:4\nmsgid \"This guide shows how to use SCQL's native compiler + engine architecture.\"\nmsgstr \"本指南展示如何使用 SCQL 的原生编译器 + 引擎架构。\"\n\n#: ../../intro/opencore-quickstart.rst:7\nmsgid \"Architecture Overview\"\nmsgstr \"架构概览\"\n\n#: ../../intro/opencore-quickstart.rst:9\nmsgid \"SCQL consists of two components:\"\nmsgstr \"SCQL 由两个组件组成：\"\n\n#: ../../intro/opencore-quickstart.rst:11\nmsgid \"**Compiler**: Translates SQL queries into secure execution plans\"\nmsgstr \"**编译器**: 将 SQL 查询转换为安全执行计划\"\n\n#: ../../intro/opencore-quickstart.rst:12\nmsgid \"**Engine**: Executes plans using MPC protocols\"\nmsgstr \"**引擎**: 使用 MPC 协议执行计划\"\n\n#: ../../intro/opencore-quickstart.rst:14\nmsgid \"Workflow:\"\nmsgstr \"工作流程：\"\n\n#: ../../intro/opencore-quickstart.rst:16\nmsgid \"Compile SQL to execution plan\"\nmsgstr \"编译 SQL 为执行计划\"\n\n#: ../../intro/opencore-quickstart.rst:17\nmsgid \"Send plan to engine nodes\"\nmsgstr \"将计划发送到引擎节点\"\n\n#: ../../intro/opencore-quickstart.rst:18\nmsgid \"Get query results\"\nmsgstr \"获取查询结果\"\n\n#: ../../intro/opencore-quickstart.rst:21\nmsgid \"Quick Start\"\nmsgstr \"快速开始\"\n\n#: ../../intro/opencore-quickstart.rst:24\nmsgid \"Setup\"\nmsgstr \"环境设置\"\n\n#: ../../intro/opencore-quickstart.rst:37\nmsgid \"Run Example\"\nmsgstr \"运行示例\"\n\n#: ../../intro/opencore-quickstart.rst:44\nmsgid \"This compiles a SQL query and executes it across Alice and Bob's engines.\"\nmsgstr \"这会编译一个 SQL 查询并在 Alice 和 Bob 的引擎上执行。\"\n\n#: ../../intro/opencore-quickstart.rst:46\nmsgid \"**Output:**\"\nmsgstr \"**输出:**\"\n\n#: ../../intro/opencore-quickstart.rst:83\nmsgid \"Configuration\"\nmsgstr \"配置\"\n\n#: ../../intro/opencore-quickstart.rst:85\nmsgid \"\"\n\"This is the configuration for ``examples/opencore-demo``, containing the \"\n\"minimal configuration required when integrating compiler + engine. For \"\n\"more tutorial information, please refer to the ``examples/tutorial`` \"\n\"directory.\"\nmsgstr \"这是 ``examples/opencore-demo`` 的配置示例，包含了集成编译器 + 引擎时所需的最小配置。更多教程信息请参考 ``examples/tutorial`` 目录。\"\n\n#: ../../intro/opencore-quickstart.rst:87\nmsgid \"**Minimal Example:**\"\nmsgstr \"**最小示例:**\"\n\n#: ../../intro/opencore-quickstart.rst:180\nmsgid \"Integration\"\nmsgstr \"集成\"\n\n#: ../../intro/opencore-quickstart.rst:183\nmsgid \"Basic Usage\"\nmsgstr \"基本用法\"\n\n#: ../../intro/opencore-quickstart.rst:219\nmsgid \"For complete code, see ``examples/opencore-demo/main.go``.\"\nmsgstr \"完整代码请参见 ``examples/opencore-demo/main.go``。\"\n\n#: ../../intro/opencore-quickstart.rst:222\nmsgid \"Next Steps\"\nmsgstr \"下一步\"\n\n#: ../../intro/opencore-quickstart.rst:224\nmsgid \"Compiler configuration: :doc:`/reference/compiler-config`\"\nmsgstr \"编译器配置: :doc:`/reference/compiler-config`\"\n\n#: ../../intro/opencore-quickstart.rst:225\nmsgid \"Engine configuration: :doc:`/reference/engine-config`\"\nmsgstr \"引擎配置: :doc:`/reference/engine-config`\"\n\n#: ../../intro/opencore-quickstart.rst:226\nmsgid \"Implementation status: :doc:`/reference/implementation-status`\"\nmsgstr \"实现状态: :doc:`/reference/implementation-status`\"\n\n#: ../../intro/opencore-quickstart.rst:227\nmsgid \"Examples: ``examples/opencore-demo/`` and ``examples/tutorial/``\"\nmsgstr \"示例: ``examples/opencore-demo/`` 和 ``examples/tutorial/``\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/reference/compiler-config.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C)\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2026.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-24 17:00+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../reference/compiler-config.rst:4\nmsgid \"SCQL Compiler Configuration\"\nmsgstr \"SCQL 编译器配置\"\n\n#: ../../reference/compiler-config.rst:6\nmsgid \"\"\n\"The SCQL compiler translates SQL queries into secure execution plans. \"\n\"This document describes the configuration options for the compiler API.\"\nmsgstr \"SCQL 编译器将 SQL 查询转换为安全执行计划。本文档描述编译器 API 的配置选项。\"\n\n#: ../../reference/compiler-config.rst:10\nmsgid \"CompileSQLRequest\"\nmsgstr \"CompileSQLRequest 编译请求\"\n\n#: ../../reference/compiler-config.rst:12\nmsgid \"The main request message for compiling SQL queries.\"\nmsgstr \"编译 SQL 查询的主要请求消息。\"\n\n#: ../../reference/compiler-config.rst:14\nmsgid \"**query** (*required*): The SQL query string to compile\"\nmsgstr \"**query** （*必需*）：要编译的 SQL 查询字符串\"\n\n#: ../../reference/compiler-config.rst:15\nmsgid \"**db** (*optional*): Database name\"\nmsgstr \"**db** （*可选*）：数据库名称\"\n\n#: ../../reference/compiler-config.rst:16\n#, python-brace-format\nmsgid \"\"\n\"**issuer** (*required*): The party code of the query issuer (e.g., \"\n\"``{\\\"code\\\": \\\"alice\\\"}``)\"\nmsgstr \"**issuer** （*必需*）：查询发起方的参与方代码（例如， ``{\\\"code\\\": \\\"alice\\\"}`` ）\"\n\n#: ../../reference/compiler-config.rst:17\nmsgid \"\"\n\"**catalog** (*required*): Database catalog metadata describing tables and\"\n\" columns, see :ref:`catalog_config`\"\nmsgstr \"**catalog** （*必需*）：描述表和列的数据库目录元数据，参见 :ref:`catalog_config`\"\n\n#: ../../reference/compiler-config.rst:18\nmsgid \"\"\n\"**compile_opts** (*required*): Compilation options, see \"\n\":ref:`compile_options`\"\nmsgstr \"**compile_opts** （*必需*）：编译选项，参见 :ref:`compile_options`\"\n\n#: ../../reference/compiler-config.rst:19\nmsgid \"\"\n\"**issue_time** (*required*): Query issue timestamp, used for functions \"\n\"like ``NOW()``\"\nmsgstr \"**issue_time** （*必需*）：查询发起时间戳，用于 ``NOW()`` 等函数\"\n\n#: ../../reference/compiler-config.rst:20\nmsgid \"\"\n\"**security_config** (*required*): Security configuration, see \"\n\":ref:`security_config`\"\nmsgstr \"**security_config** （*必需*）：安全配置，参见 :ref:`security_config`\"\n\n#: ../../reference/compiler-config.rst:21\nmsgid \"\"\n\"**additional_info** (*required*): Specifies additional information in \"\n\"response, see :ref:`additional_info_spec`\"\nmsgstr \"**additional_info** （*必需*）：指定响应中的附加信息，参见 :ref:`additional_info_spec`\"\n\n#: ../../reference/compiler-config.rst:27\nmsgid \"CompileOptions\"\nmsgstr \"CompileOptions 编译选项\"\n\n#: ../../reference/compiler-config.rst:29\nmsgid \"Compilation options that control the execution strategy.\"\nmsgstr \"控制执行策略的编译选项。\"\n\n#: ../../reference/compiler-config.rst:31\nmsgid \"\"\n\"**spu_conf** (*required*): SPU runtime configuration (protocol, field, \"\n\"etc.), see `SPU documentation`_\"\nmsgstr \"**spu_conf** （*必需*）：SPU 运行时配置（协议、域等），参见 `SPU documentation`_\"\n\n#: ../../reference/compiler-config.rst:32\nmsgid \"**batched** (*required*): Whether to run in streaming mode\"\nmsgstr \"**batched** （*必需*）：是否以流式模式运行\"\n\n#: ../../reference/compiler-config.rst:33\nmsgid \"\"\n\"**psi_algorithm_type** (*optional*): PSI algorithm type: ``UNSPECIFIED`` \"\n\"(auto), ``ECDH_PSI``, ``KKRT_PSI``, ``RR22``\"\nmsgstr \"\"\n\"**psi_algorithm_type** （*可选*）：PSI 算法类型： ``UNSPECIFIED`` （自动）、 \"\n\"``ECDH_PSI`` 、 ``KKRT_PSI`` 、 ``RR22``\"\n\n#: ../../reference/compiler-config.rst:35\nmsgid \"**SPU Configuration Example:**\"\nmsgstr \"**SPU 配置示例：**\"\n\n#: ../../reference/compiler-config.rst:47\nmsgid \"**Supported SPU Protocols:**\"\nmsgstr \"**支持的 SPU 协议：**\"\n\n#: ../../reference/compiler-config.rst:49\nmsgid \"``SEMI2K``: Semi-honest 2PC/MPC (supports N parties)\"\nmsgstr \"``SEMI2K`` ：半诚实 2PC/MPC（支持 N 方）\"\n\n#: ../../reference/compiler-config.rst:50\nmsgid \"``CHEETAH``: Semi-honest 2PC (2 parties only)\"\nmsgstr \"``CHEETAH`` ：半诚实 2PC（仅支持 2 方）\"\n\n#: ../../reference/compiler-config.rst:51\nmsgid \"``ABY3``: Semi-honest 3PC (3 parties only)\"\nmsgstr \"``ABY3`` ：半诚实 3PC（仅支持 3 方）\"\n\n#: ../../reference/compiler-config.rst:53\nmsgid \"**Supported Fields:**\"\nmsgstr \"**支持的域：**\"\n\n#: ../../reference/compiler-config.rst:55\nmsgid \"``FM32``: 32-bit finite field\"\nmsgstr \"``FM32`` ：32 位有限域\"\n\n#: ../../reference/compiler-config.rst:56\nmsgid \"``FM64``: 64-bit finite field\"\nmsgstr \"``FM64`` ：64 位有限域\"\n\n#: ../../reference/compiler-config.rst:57\nmsgid \"``FM128``: 128-bit finite field\"\nmsgstr \"``FM128`` ：128 位有限域\"\n\n#: ../../reference/compiler-config.rst:63\nmsgid \"CompilerSecurityConfig\"\nmsgstr \"CompilerSecurityConfig 安全配置\"\n\n#: ../../reference/compiler-config.rst:65\nmsgid \"\"\n\"Security configuration that controls data visibility and security \"\n\"relaxations.\"\nmsgstr \"控制数据可见性和安全放宽的安全配置。\"\n\n#: ../../reference/compiler-config.rst:67\nmsgid \"\"\n\"**global_relaxation** (*required*): Global security relaxation settings, \"\n\"see :ref:`global_security_relaxation`\"\nmsgstr \"\"\n\"**global_relaxation** （*必需*）：全局安全放宽设置，参见 \"\n\":ref:`global_security_relaxation`\"\n\n#: ../../reference/compiler-config.rst:68\nmsgid \"\"\n\"**column_relaxation_list** (*optional*): Per-column security relaxations,\"\n\" see :ref:`column_security_relaxation`\"\nmsgstr \"\"\n\"**column_relaxation_list** （*可选*）：按列的安全放宽设置，参见 \"\n\":ref:`column_security_relaxation`\"\n\n#: ../../reference/compiler-config.rst:69\nmsgid \"\"\n\"**reverse_inference_conf** (*required*): Reverse inference detection \"\n\"config, see :ref:`reverse_inference_config`\"\nmsgstr \"\"\n\"**reverse_inference_conf** （*必需*）：反向推理检测配置，参见 \"\n\":ref:`reverse_inference_config`\"\n\n#: ../../reference/compiler-config.rst:70\nmsgid \"\"\n\"**column_visibility_list** (*optional*): User-specified column \"\n\"visibility, see :ref:`column_visibility`\"\nmsgstr \"**column_visibility_list** （*可选*）：用户指定的列可见性，参见 :ref:`column_visibility`\"\n\n#: ../../reference/compiler-config.rst:71\nmsgid \"\"\n\"**result_security_conf** (*optional*): Result-level security config, see \"\n\":ref:`result_security_config`\"\nmsgstr \"**result_security_conf** （*可选*）：结果级安全配置，参见 :ref:`result_security_config`\"\n\n#: ../../reference/compiler-config.rst:77\nmsgid \"GlobalSecurityRelaxation\"\nmsgstr \"全局安全放松\"\n\n#: ../../reference/compiler-config.rst:79\nmsgid \"Global security relaxation that applies to all data.\"\nmsgstr \"适用于所有数据的全局安全放松配置。\"\n\n#: ../../reference/compiler-config.rst:81\nmsgid \"\"\n\"**reveal_group_count** (*optional*): Allow group counts to be visible in \"\n\"plaintext\"\nmsgstr \"**reveal_group_count** （*可选*）：允许分组计数以明文可见\"\n\n#: ../../reference/compiler-config.rst:82\nmsgid \"\"\n\"**reveal_group_mark** (*optional*): Allow group marks to be visible in \"\n\"plaintext\"\nmsgstr \"**reveal_group_mark** （*可选*）：允许分组标记以明文可见\"\n\n#: ../../reference/compiler-config.rst:83\n#: ../../reference/compiler-config.rst:110\n#, fuzzy\nmsgid \"\"\n\"**reveal_key_after_join** (*optional*): Allow join keys to be visible in \"\n\"plaintext after join (intersection only). When enabled, the compiler will\"\n\" prefer PSI join over secret join for better performance\"\nmsgstr \"\"\n\"**reveal_key_after_join** （*可选*）：允许连接键明文可见。启用后，编译器将优先选择 \"\n\"PSI join 而非 secret join，以获得更好的性能\"\n\n#: ../../reference/compiler-config.rst:84\n#: ../../reference/compiler-config.rst:111\nmsgid \"\"\n\"**reveal_filter_mask** (*optional*): Allow filter mask to be used in \"\n\"plaintext for subsequent computations\"\nmsgstr \"**reveal_filter_mask** （*可选*）：允许过滤掩码可以在后续计算中当作明文使用\"\n\n#: ../../reference/compiler-config.rst:86\n#: ../../reference/compiler-config.rst:116\n#: ../../reference/compiler-config.rst:143\n#: ../../reference/compiler-config.rst:168\n#: ../../reference/compiler-config.rst:197\nmsgid \"**Example:**\"\nmsgstr \"**示例：**\"\n\n#: ../../reference/compiler-config.rst:103\nmsgid \"ColumnSecurityRelaxation\"\nmsgstr \"列级安全放松\"\n\n#: ../../reference/compiler-config.rst:105\nmsgid \"Per-column security relaxation for fine-grained control.\"\nmsgstr \"用于细粒度控制的列级安全放松配置。\"\n\n#: ../../reference/compiler-config.rst:107\n#: ../../reference/compiler-config.rst:161\nmsgid \"**database** (*required*): Database name\"\nmsgstr \"**database** （*必需*）：数据库名称\"\n\n#: ../../reference/compiler-config.rst:108\n#: ../../reference/compiler-config.rst:162\nmsgid \"**table** (*required*): Table name\"\nmsgstr \"**table** （*必需*）：表名称\"\n\n#: ../../reference/compiler-config.rst:109\n#: ../../reference/compiler-config.rst:163\nmsgid \"**column** (*required*): Column name\"\nmsgstr \"**column** （*必需*）：列名称\"\n\n#: ../../reference/compiler-config.rst:114\nmsgid \"\"\n\"Column-level settings use logical OR with global settings. If global \"\n\"``reveal_key_after_join`` is ``true`` and column-level is ``false``, the \"\n\"result is ``true``. If global is ``false`` and column-level is ``true``, \"\n\"the result is ``true``. Only when both are ``false`` is the final result \"\n\"``false``. The same logic applies to ``reveal_filter_mask``.\"\nmsgstr \"\"\n\"列级设置与全局设置使用逻辑或运算。如果全局 ``reveal_key_after_join`` 为 ``true`` 而列级为 \"\n\"``false`` ，结果为 ``true`` 。如果全局为 ``false`` 而列级为 ``true`` ，结果为 ``true`` 。\"\n\"只有当两者都为 ``false`` 时，最终结果才为 ``false`` 。 ``reveal_filter_mask`` 也适用相同的逻辑。\"\n\n#: ../../reference/compiler-config.rst:135\nmsgid \"ReverseInferenceConfig\"\nmsgstr \"结果反推配置\"\n\n#: ../../reference/compiler-config.rst:137\n#, fuzzy\nmsgid \"Configuration for reverse inference.\"\nmsgstr \"用于结果反推的配置。\"\n\n#: ../../reference/compiler-config.rst:139\nmsgid \"\"\n\"**enable_reverse_inference** (*required*): Infer intermediate visibility \"\n\"from result visibility to enable plaintext compute\"\nmsgstr \"**enable_reverse_inference** （*必需*）：从结果可见性推断中间可见性以启用明文计算\"\n\n#: ../../reference/compiler-config.rst:141\nmsgid \"\"\n\"When enabled, the compiler will infer the visibility of intermediate \"\n\"computation steps based on the final result visibility, increasing the \"\n\"possibility of plaintext computation and improving performance.\"\nmsgstr \"启用后，编译器将根据最终结果的可见性推断中间计算步骤的可见性，从而增加明文计算的可能性并提高性能。\"\n\n#: ../../reference/compiler-config.rst:157\nmsgid \"ColumnVisibility\"\nmsgstr \"列可见性\"\n\n#: ../../reference/compiler-config.rst:159\nmsgid \"Specifies which parties can see specific columns.\"\nmsgstr \"指定哪些参与方可以查看特定列。\"\n\n#: ../../reference/compiler-config.rst:164\nmsgid \"\"\n\"**visible_parties** (*required*): List of party codes that can see this \"\n\"column during computation (in addition to the owner)\"\nmsgstr \"**visible_parties** （*必需*）：可在计算期间查看该列的参与方代码列表（除所有者之外）\"\n\n#: ../../reference/compiler-config.rst:166\nmsgid \"\"\n\"By default, only the column owner can see the data. Use this to grant \"\n\"visibility to other parties. Adding column visibility will make the \"\n\"execution graph prefer plaintext operators, improving execution \"\n\"efficiency.\"\nmsgstr \"默认情况下，只有列所有者可以查看数据。使用此配置可以向其他参与方授予可见性。增加列可见性会使执行图更优先使用明文算子，提高执行效率。\"\n\n#: ../../reference/compiler-config.rst:189\nmsgid \"ResultSecurityConfig\"\nmsgstr \"结果安全配置\"\n\n#: ../../reference/compiler-config.rst:191\nmsgid \"Security configuration that affects query results.\"\nmsgstr \"影响查询结果的安全配置。\"\n\n#: ../../reference/compiler-config.rst:193\nmsgid \"\"\n\"**groupby_threshold** (*optional*): Minimum number of rows in a group for\"\n\" GROUP BY results (default: 4)\"\nmsgstr \"**groupby_threshold** （*可选*）：GROUP BY 结果中一个分组的最小行数（默认值：4）\"\n\n#: ../../reference/compiler-config.rst:195\nmsgid \"\"\n\"Groups with fewer rows than this threshold will be filtered out to \"\n\"prevent inference attacks.\"\nmsgstr \"行数少于此阈值的分组将被过滤掉，以防止推理攻击。\"\n\n#: ../../reference/compiler-config.rst:211\nmsgid \"AdditionalInfoSpec\"\nmsgstr \"附加信息规范\"\n\n#: ../../reference/compiler-config.rst:213\nmsgid \"Specifies what additional information should be included in the response.\"\nmsgstr \"指定应在响应中包含哪些附加信息。\"\n\n#: ../../reference/compiler-config.rst:215\nmsgid \"\"\n\"**need_operator_graph** (*optional*): Whether to return the operator \"\n\"graph for debugging (default: ``false``)\"\nmsgstr \"**need_operator_graph** （*可选*）：是否返回用于调试的算子图（默认值： ``false`` ）\"\n\n#: ../../reference/compiler-config.rst:221\nmsgid \"Catalog Configuration\"\nmsgstr \"数据目录配置\"\n\n#: ../../reference/compiler-config.rst:223\nmsgid \"\"\n\"The catalog defines the database schema. See ``api/interpreter.proto`` \"\n\"for the complete definition.\"\nmsgstr \"数据目录定义了数据库模式。完整定义请参见 ``api/interpreter.proto`` 。\"\n\n#: ../../reference/compiler-config.rst:225\nmsgid \"**Basic Structure:**\"\nmsgstr \"**基本结构：**\"\n\n#: ../../reference/compiler-config.rst:254\nmsgid \"**Supported Column Types:**\"\nmsgstr \"**支持的列类型：**\"\n\n#: ../../reference/compiler-config.rst:256\nmsgid \"``int``, ``long``, ``string``, ``float``, ``double``\"\nmsgstr \"``int`` 、 ``long`` 、 ``string`` 、 ``float`` 、 ``double``\"\n\n#: ../../reference/compiler-config.rst:257\nmsgid \"``datetime``, ``timestamp``\"\nmsgstr \"``datetime`` 、 ``timestamp``\"\n\n#: ../../reference/compiler-config.rst:259\nmsgid \"**Supported Database Types:**\"\nmsgstr \"**支持的数据库类型：**\"\n\n#: ../../reference/compiler-config.rst:261\nmsgid \"``mysql``, ``postgres``, ``sqlite``\"\nmsgstr \"``mysql`` 、 ``postgres`` 、 ``sqlite``\"\n\n#: ../../reference/compiler-config.rst:262\nmsgid \"``csvdb`` (for CSV files)\"\nmsgstr \"``csvdb`` （用于 CSV 文件）\"\n\n#: ../../reference/compiler-config.rst:263\nmsgid \"``arrowsql`` (for Arrow Flight servers)\"\nmsgstr \"``arrowsql`` （用于 Arrow Flight 服务器）\"\n\n#: ../../reference/compiler-config.rst:266\nmsgid \"See Also\"\nmsgstr \"另请参阅\"\n\n#: ../../reference/compiler-config.rst:268\nmsgid \":doc:`/reference/engine-config` - Engine configuration reference\"\nmsgstr \":doc:`/reference/engine-config` - 引擎配置参考\"\n\n#: ../../reference/compiler-config.rst:269\nmsgid \":doc:`/intro/opencore-quickstart` - Quick start guide\"\nmsgstr \":doc:`/intro/opencore-quickstart` - 快速入门指南\"\n\n#: ../../reference/compiler-config.rst:270\nmsgid \"\"\n\"`SPU Documentation <https://github.com/secretflow/spu>`_ - SPU protocol \"\n\"details\"\nmsgstr \"`SPU 文档 <https://github.com/secretflow/spu>`_ - SPU 协议详细信息\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/reference/engine-config.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-11 19:32+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../reference/engine-config.rst:5\nmsgid \"SCQLEngine Configuration\"\nmsgstr \"SCQLEngine 配置说明\"\n\n#: ../../reference/engine-config.rst:7\nmsgid \"SCQLEngine uses Gflags to manage configurations when SCQLEngine set up.\"\nmsgstr \"SCQLEngine 使用 Gflags 来管理配置项。\"\n\n#: ../../reference/engine-config.rst:10\nmsgid \"Example configuration for SCQLEngine\"\nmsgstr \"SCQLEngine 配置示例\"\n\n#: ../../reference/engine-config.rst:22\nmsgid \"Configuration Options of SCQLEngine\"\nmsgstr \"SCQLEngine 配置项\"\n\n#: ../../reference/engine-config.rst:24\nmsgid \"\"\n\"SCQLEngine works with the native compiler to execute query plans. In the \"\n\"configuration, ``Driver`` refers to the module that sends execution plans\"\n\" to the engine.\"\nmsgstr \"SCQLEngine 与原生编译器配合执行查询计划。在配置中，``Driver`` 指的是向引擎发送执行计划的模块。\"\n\n#: ../../reference/engine-config.rst:27\nmsgid \"Name\"\nmsgstr \"名称\"\n\n#: ../../reference/engine-config.rst:27\nmsgid \"Default\"\nmsgstr \"默认值\"\n\n#: ../../reference/engine-config.rst:27\nmsgid \"Description\"\nmsgstr \"描述\"\n\n#: ../../reference/engine-config.rst:29\nmsgid \"log_enable_console_logger\"\nmsgstr \"log_enable_console_logger\"\n\n#: ../../reference/engine-config.rst:29 ../../reference/engine-config.rst:47\n#: ../../reference/engine-config.rst:71 ../../reference/engine-config.rst:89\n#: ../../reference/engine-config.rst:123 ../../reference/engine-config.rst:127\n#: ../../reference/engine-config.rst:135 ../../reference/engine-config.rst:141\n#: ../../reference/engine-config.rst:153 ../../reference/engine-config.rst:157\n#: ../../reference/engine-config.rst:171\nmsgid \"true\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:29\nmsgid \"Whether logging to stdout while logging to file\"\nmsgstr \"是否记录日志文件到控制台\"\n\n#: ../../reference/engine-config.rst:31\nmsgid \"log_enable_session_logger_separation\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:31 ../../reference/engine-config.rst:49\n#: ../../reference/engine-config.rst:73 ../../reference/engine-config.rst:79\n#: ../../reference/engine-config.rst:83 ../../reference/engine-config.rst:95\n#: ../../reference/engine-config.rst:99 ../../reference/engine-config.rst:131\n#: ../../reference/engine-config.rst:173\nmsgid \"false\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:31\nmsgid \"Whether output session-related logs to a dedicated file\"\nmsgstr \"是否将 session 相关日志输出到专用文件\"\n\n#: ../../reference/engine-config.rst:33\nmsgid \"log_dir\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:33\nmsgid \"logs\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:33\nmsgid \"The directory to save log file\"\nmsgstr \"保存log文件的目录\"\n\n#: ../../reference/engine-config.rst:35\nmsgid \"log_level\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:35\nmsgid \"info\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:35\nmsgid \"Log level, can be trace/debug/info/warning/error/critical/off\"\nmsgstr \"日志级别，可取 trace/debug/info/warning/error/critical/off\"\n\n#: ../../reference/engine-config.rst:37\nmsgid \"peer_engine_protocol\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:37\nmsgid \"baidu_std\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:37\nmsgid \"The rpc protocol between engine and engine\"\nmsgstr \"SCQLEngine 与 SCQLEngine 之间的rpc协议\"\n\n#: ../../reference/engine-config.rst:39\nmsgid \"peer_engine_connection_type\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:39\nmsgid \"single\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:39\nmsgid \"The rpc connection type between engine and engine\"\nmsgstr \"SCQLEngine 与SCQLEngine 之间的 rpc 连接类型\"\n\n#: ../../reference/engine-config.rst:41\nmsgid \"peer_engine_load_balancer\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:41 ../../reference/engine-config.rst:51\n#: ../../reference/engine-config.rst:65 ../../reference/engine-config.rst:75\n#: ../../reference/engine-config.rst:91 ../../reference/engine-config.rst:93\n#: ../../reference/engine-config.rst:97 ../../reference/engine-config.rst:101\n#: ../../reference/engine-config.rst:109 ../../reference/engine-config.rst:111\n#: ../../reference/engine-config.rst:115 ../../reference/engine-config.rst:117\n#: ../../reference/engine-config.rst:119 ../../reference/engine-config.rst:121\n#: ../../reference/engine-config.rst:125 ../../reference/engine-config.rst:129\n#: ../../reference/engine-config.rst:147 ../../reference/engine-config.rst:149\n#: ../../reference/engine-config.rst:151 ../../reference/engine-config.rst:159\n#: ../../reference/engine-config.rst:161 ../../reference/engine-config.rst:175\n#: ../../reference/engine-config.rst:177 ../../reference/engine-config.rst:179\nmsgid \"none\"\nmsgstr \"无\"\n\n#: ../../reference/engine-config.rst:41\nmsgid \"The rpc load balancer between engine and engine, can be rr or empty string\"\nmsgstr \"SCQLEngine 与 SCQLEngine 之间 load balancer, 值可以是 rr 或者空字符串\"\n\n#: ../../reference/engine-config.rst:43\nmsgid \"peer_engine_timeout_ms\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:43\nmsgid \"300000\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:43\nmsgid \"The rpc timeout between engine and engine, unit: ms\"\nmsgstr \"SCQLEngine 与 SCQLEngine之间的 rpc 超时时间，单位：ms\"\n\n#: ../../reference/engine-config.rst:45\nmsgid \"peer_engine_max_retry\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:45 ../../reference/engine-config.rst:69\nmsgid \"3\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:45\nmsgid \"Rpc max retries(not including the first rpc) between engine and engine\"\nmsgstr \"SCQLEngine 与 SCQLEngine 之间的rpc最大重试次数（不包括第一个rpc）\"\n\n#: ../../reference/engine-config.rst:47\nmsgid \"peer_engine_enable_ssl_as_client\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:47\nmsgid \"Whether enable ssl encryption when send message to another engine\"\nmsgstr \"SCQLEngine 与 SCQLEngine 之间发送消息是否启用ssl加密\"\n\n#: ../../reference/engine-config.rst:49\nmsgid \"peer_engine_enable_ssl_client_verification\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:49\nmsgid \"\"\n\"Whether enable certificate verification when send message to another \"\n\"engine\"\nmsgstr \"作为客户端时，是否验证来自其他 SCQLEngine 的证书\"\n\n#: ../../reference/engine-config.rst:51\nmsgid \"peer_engine_ssl_client_ca_certificate\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:51\nmsgid \"\"\n\"The trusted CA file to verify certificate when send message to another \"\n\"engine\"\nmsgstr \"可信 CA 文件，作为客户端时，用于验证来自其他 SCQLEngine 的证书\"\n\n#: ../../reference/engine-config.rst:53\nmsgid \"link_recv_timeout_ms\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:53\nmsgid \"30000\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:53\nmsgid \"The max time that engine will wait for message come from another engine\"\nmsgstr \"等待其他 SCQLEngine 消息的最大响应时间\"\n\n#: ../../reference/engine-config.rst:55\nmsgid \"link_throttle_window_size\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:55\nmsgid \"16\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:55\nmsgid \"\"\n\"Throttle window size for channel, set to limit the number of messages \"\n\"sent asynchronously to avoid network congestion, set 0 to disable\"\nmsgstr \"channel 的限制窗口大小，用于限制异步发送的消息并发数量以避免网络拥塞，设置为 0 表示不限制\"\n\n#: ../../reference/engine-config.rst:57\nmsgid \"link_chunked_send_parallel_size\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:57\nmsgid \"1\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:57\nmsgid \"Parallel size when send chunked value\"\nmsgstr \"分块发送数据时的并行大小\"\n\n#: ../../reference/engine-config.rst:59\nmsgid \"http_max_payload_size\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:59\nmsgid \"1048576\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:59\nmsgid \"Max payload to decide whether to send value chunked, default 1MB\"\nmsgstr \"决定是否启用分块发送数据的最大有效负载，默认 1MB\"\n\n#: ../../reference/engine-config.rst:61\nmsgid \"driver_protocol\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:61\nmsgid \"`http:proto`\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:61\nmsgid \"The rpc protocol between engine and Driver\"\nmsgstr \"SCQLEngine 与 Driver 之间的 rpc 协议\"\n\n#: ../../reference/engine-config.rst:63\nmsgid \"driver_connection_type\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:63\nmsgid \"pooled\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:63\nmsgid \"The rpc connection type between engine and Driver\"\nmsgstr \"SCQLEngine 与 Driver 之间的 rpc 连接类型\"\n\n#: ../../reference/engine-config.rst:65\nmsgid \"driver_load_balancer\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:65\nmsgid \"The rpc load balancer between engine and Driver, can be rr or empty string\"\nmsgstr \"SCQLEngine 和 Driver 之间 RPC 通信的 load balancer 类型，可以是 rr 或者是空字符串\"\n\n#: ../../reference/engine-config.rst:67\nmsgid \"driver_timeout_ms\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:67\nmsgid \"5000\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:67\nmsgid \"The rpc timeout between engine and Driver, unit: ms\"\nmsgstr \"SCQLEngine 与 Driver 之间的 rpc 超时时间，单位：ms\"\n\n#: ../../reference/engine-config.rst:69\nmsgid \"driver_max_retry\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:69\nmsgid \"Rpc max retries(not including the first rpc) between engine and Driver\"\nmsgstr \"SCQLEngine 和 Driver 之间的 rpc 最大重试次数（不包括第一个 rpc）\"\n\n#: ../../reference/engine-config.rst:71\nmsgid \"driver_enable_ssl_as_client\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:71\nmsgid \"Whether enable ssl encryption when send message to Driver\"\nmsgstr \"作为客户端，向 Driver 发送消息时是否启用 ssl 加密\"\n\n#: ../../reference/engine-config.rst:73\nmsgid \"driver_enable_ssl_client_verification\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:73\nmsgid \"Whether enable certificate verification when send message to Driver\"\nmsgstr \"作为客户端，是否验证 Driver 的证书\"\n\n#: ../../reference/engine-config.rst:75\nmsgid \"driver_ssl_client_ca_certificate\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:75\nmsgid \"The trusted CA file to verify certificate when send message to Driver\"\nmsgstr \"可信 CA 文件，作为客户端时，用于验证 Driver 的证书\"\n\n#: ../../reference/engine-config.rst:77\nmsgid \"listen_port\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:77\nmsgid \"8003\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:77\nmsgid \"The listening port of engine service\"\nmsgstr \"SCQLEngine 作为服务器的监听端口\"\n\n#: ../../reference/engine-config.rst:79\nmsgid \"enable_builtin_service\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:79\nmsgid \"Whether enable brpc builtin service\"\nmsgstr \"是否启用 brpc 内置服务\"\n\n#: ../../reference/engine-config.rst:81\nmsgid \"internal_port\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:81\nmsgid \"9527\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:81\nmsgid \"The listening port of brpc builtin services\"\nmsgstr \"brpc 内置服务的监听端口\"\n\n#: ../../reference/engine-config.rst:83\nmsgid \"enable_separate_link_port\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:83\nmsgid \"Whether use a separate port for link service\"\nmsgstr \"是否为 link service 启用隔离的端口\"\n\n#: ../../reference/engine-config.rst:85\nmsgid \"link_port\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:85\nmsgid \"8004\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:85\nmsgid \"Port for link service\"\nmsgstr \"link 服务的监听端口\"\n\n#: ../../reference/engine-config.rst:87\nmsgid \"idle_timeout_s\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:87\nmsgid \"30\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:87\nmsgid \"\"\n\"Idle connection close delay in seconds between the engine and Driver, \"\n\"unit: s\"\nmsgstr \"SCQLEngine 与 Driver 之间的空闲连接关闭延迟（单位：秒）\"\n\n#: ../../reference/engine-config.rst:89\nmsgid \"server_enable_ssl\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:89\nmsgid \"Whether enable SSL when engine work as a server\"\nmsgstr \"SCQLEngine 作为服务器时是否启用SSL\"\n\n#: ../../reference/engine-config.rst:91\nmsgid \"server_ssl_certificate\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:91\nmsgid \"Certificate file path to enable SSL when engine work as a server\"\nmsgstr \"SCQLEngine 作为服务器时启用 SSL 的证书文件路径\"\n\n#: ../../reference/engine-config.rst:93\nmsgid \"server_ssl_private_key\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:93\nmsgid \"Private key file path to enable SSL when engine work as a server\"\nmsgstr \"SCQLEngine 作为服务器时启用 SSL 的私钥文件路径\"\n\n#: ../../reference/engine-config.rst:95\nmsgid \"enable_client_authorization\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:95\nmsgid \"Whether check requests' http header when engine work as a server\"\nmsgstr \"SCQLEngine 作为服务器时是否检查请求的 http 头\"\n\n#: ../../reference/engine-config.rst:97\nmsgid \"auth_credential\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:97\nmsgid \"Authorization credential used to check requests' http header\"\nmsgstr \"SCQLEngine 作为服务器时用于检查请求的 http 头的 凭证\"\n\n#: ../../reference/engine-config.rst:99\nmsgid \"enable_driver_authorization\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:99\nmsgid \"Whether to authenticate the identity of Driver\"\nmsgstr \"是否启动 Driver 身份认证\"\n\n#: ../../reference/engine-config.rst:101\nmsgid \"engine_credential\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:101\nmsgid \"Credential used to authenticate Driver\"\nmsgstr \"用于验证 Driver 的凭证\"\n\n#: ../../reference/engine-config.rst:103\nmsgid \"session_timeout_s\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:103\nmsgid \"1800\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:103\nmsgid \"Expiration duration of a session between engine and Driver, unit: s\"\nmsgstr \"SCQLEngine 与 Driver 之间的会话过期时间，单位：秒\"\n\n#: ../../reference/engine-config.rst:105\nmsgid \"spu_allowed_protocols\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:105\nmsgid \"SEMI2K,ABY3,CHEETAH\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:105\nmsgid \"SPU allowed protocols\"\nmsgstr \"允许启用的 SPU 协议\"\n\n#: ../../reference/engine-config.rst:107\nmsgid \"datasource_router\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:107\nmsgid \"embed\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:107\nmsgid \"The datasource router type, \\\"embed\\\" or \\\"http\\\"\"\nmsgstr \"数据源路由类型， \\\"embed\\\" or \\\"http\\\"\"\n\n#: ../../reference/engine-config.rst:109\n#, fuzzy\nmsgid \"embed_router_conf\"\nmsgstr \"embed_router_conf\"\n\n#: ../../reference/engine-config.rst:109\nmsgid \"Configuration for embed router in json format\"\nmsgstr \"数据源的路由配置，其类型为 json 字符串格式\"\n\n#: ../../reference/engine-config.rst:111\nmsgid \"http_router_endpoint\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:111\nmsgid \"\"\n\"http datasource router endpoint, it is valid only datasource_router is \"\n\"set to \\\"http\\\"\"\nmsgstr \"http 数据源的路由端点，只在 datasource_router 设置为 http 时生效\"\n\n#: ../../reference/engine-config.rst:113\nmsgid \"kuscia_datamesh_endpoint\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:113\nmsgid \"datamesh:8071\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:113\nmsgid \"Kuscia datamesh grpc endpoint\"\nmsgstr \"Kuscia datamesh 的 grpc 端点\"\n\n#: ../../reference/engine-config.rst:115\nmsgid \"kuscia_datamesh_client_key_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:115\nmsgid \"Kuscia datamesh client key file\"\nmsgstr \"Kuscia datamesh 的客户端秘钥文件\"\n\n#: ../../reference/engine-config.rst:117\nmsgid \"kuscia_datamesh_client_cert_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:117\nmsgid \"Kuscia datamesh client cert file\"\nmsgstr \"Kuscia datamesh 的客户端证书文件\"\n\n#: ../../reference/engine-config.rst:119\nmsgid \"kuscia_datamesh_cacert_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:119\nmsgid \"Kuscia datamesh server cacert file\"\nmsgstr \"Kuscia datamesh 的客户端 CA 证书文件\"\n\n#: ../../reference/engine-config.rst:121\nmsgid \"db_connection_info\"\nmsgstr \"db_connection_info\"\n\n#: ../../reference/engine-config.rst:121\nmsgid \"Connection string used to connect to mysql\"\nmsgstr \"用于连接 MySQL 数据库的连接串\"\n\n#: ../../reference/engine-config.rst:123\nmsgid \"enable_self_auth\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:123\nmsgid \"Whether enable self identity authentication\"\nmsgstr \"是否启用自我身份认证\"\n\n#: ../../reference/engine-config.rst:125\nmsgid \"private_key_pem_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:125\nmsgid \"Path to private key pem file\"\nmsgstr \"私钥 pem 文件的路径\"\n\n#: ../../reference/engine-config.rst:127\nmsgid \"enable_peer_auth\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:127\nmsgid \"Whether enable peer parties identity authentication\"\nmsgstr \"是否启用对端身份认证\"\n\n#: ../../reference/engine-config.rst:129\nmsgid \"authorized_profile_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:129\nmsgid \"Path to authorized profile, in json format\"\nmsgstr \"数据源的路由配置，其类型为 json 字符串格式\"\n\n#: ../../reference/engine-config.rst:131\nmsgid \"enable_psi_detail_logger\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:131\nmsgid \"Whether enable detail log\"\nmsgstr \"是否记录算法详细日志\"\n\n#: ../../reference/engine-config.rst:133\nmsgid \"psi_detail_logger_dir\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:133\nmsgid \"logs/detail\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:133\nmsgid \"Detail log directory\"\nmsgstr \"详细日志目录\"\n\n#: ../../reference/engine-config.rst:135\nmsgid \"enable_restricted_read_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:135\nmsgid \"Whether restrict path for file to read\"\nmsgstr \"是否限制读取文件的路径\"\n\n#: ../../reference/engine-config.rst:137\nmsgid \"restricted_read_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:137 ../../reference/engine-config.rst:143\nmsgid \"./data\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:137\nmsgid \"In where the file is allowed to read if enable restricted read path\"\nmsgstr \"开启读取路径限制后，允许读取文件的路径\"\n\n#: ../../reference/engine-config.rst:139\nmsgid \"csv_null_str\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:139 ../../reference/engine-config.rst:145\nmsgid \"NULL\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:139\nmsgid \"Specifies the string that represents a NULL value when reading csv\"\nmsgstr \"指定读取 csv 时表示 NULL 值的字符串\"\n\n#: ../../reference/engine-config.rst:141\nmsgid \"enable_restricted_write_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:141\nmsgid \"Whether restrict path for file to write\"\nmsgstr \"是否限制文件写入路径\"\n\n#: ../../reference/engine-config.rst:143\nmsgid \"restricted_write_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:143\nmsgid \"In where the file is allowed to write if enable restricted write path\"\nmsgstr \"开启文件写入路径限制后，允许写入的路径\"\n\n#: ../../reference/engine-config.rst:145\nmsgid \"null_string_to_write\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:145\nmsgid \"The string to write for NULL values\"\nmsgstr \"写入 NULL 值时使用的字符串\"\n\n#: ../../reference/engine-config.rst:147\nmsgid \"output_s3_endpoint\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:147\nmsgid \"The endpoint of output s3/minio/oss\"\nmsgstr \"输出到 s3/minio/oss 时 server 的 endpoint\"\n\n#: ../../reference/engine-config.rst:149\nmsgid \"output_s3_access_key\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:149\nmsgid \"The access key id of output s3/minio/oss\"\nmsgstr \"输出到 s3/minio/oss 时的 access key id\"\n\n#: ../../reference/engine-config.rst:151\nmsgid \"output_s3_secret_key\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:151\nmsgid \"The secret access key of output s3/minio/oss\"\nmsgstr \"输出到 s3/minio/oss 时的 secret access key\"\n\n#: ../../reference/engine-config.rst:153\nmsgid \"output_s3_enalbe_ssl\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:153\nmsgid \"Default enable ssl, if s3 server not enable ssl, set to false\"\nmsgstr \"默认启用 ssl，如果 s3 server 端未启用 ssl，请设置为 false\"\n\n#: ../../reference/engine-config.rst:155\nmsgid \"output_s3_ca_dir_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:155\nmsgid \"/etc/ssl/certs/\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:155\nmsgid \"Directory where the certificates stored to verify s3 server\"\nmsgstr \"存储 ca 证书的目录，用于验证 s3 server 的证书\"\n\n#: ../../reference/engine-config.rst:157\nmsgid \"output_s3_force_virtual_addressing\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:157\nmsgid \"Default set to true to work with oss, for minio please set to false\"\nmsgstr \"默认为 true，以便写入 oss，对于 minio 请设置为 false\"\n\n#: ../../reference/engine-config.rst:159\nmsgid \"output_db_kind\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:159\nmsgid \"The kind of output db, support mysql/sqlite/postgresql\"\nmsgstr \"输出的数据库类型，支持 mysql/sqlite/postgresql\"\n\n#: ../../reference/engine-config.rst:161\nmsgid \"output_db_connection_str\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:161\nmsgid \"The :ref:`connection string <connection_str>` to connect to output db\"\nmsgstr \"用于连接输出数据库的 :ref:`连接串 <connection_str>`\"\n\n#: ../../reference/engine-config.rst:163\nmsgid \"psi_curve_type\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:163\nmsgid \"2\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:163\nmsgid \"\"\n\"Curve type used in PSI, default 2: CURVE_FOURQ, for more see `psi curve \"\n\"type`_\"\nmsgstr \"PSI 里使用的曲线类型， 默认值为 2: CURVE_FOURQ ，更多参考 `psi curve type`_\"\n\n#: ../../reference/engine-config.rst:165\nmsgid \"provider_batch_size\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:165\nmsgid \"8192\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:165\nmsgid \"Batch size used in PSI Provider\"\nmsgstr \"PSI Provider 使用的 batch size\"\n\n#: ../../reference/engine-config.rst:167\nmsgid \"detail_logger_sample_num\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:167\nmsgid \"0\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:167\nmsgid \"Sample number for detail logger, 0 means print all, default 0\"\nmsgstr \"详细日志的采样行数，0 表示打印全部，默认值为 0\"\n\n#: ../../reference/engine-config.rst:169\nmsgid \"max_chunk_size\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:169\nmsgid \"134217728\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:169\nmsgid \"Max chunk size for spu value proto, default 128MB\"\nmsgstr \"spu value proto 的单个 chunk 的体积限制，默认值为 128MB\"\n\n#: ../../reference/engine-config.rst:171\nmsgid \"enable_tensor_life_cycle_manage\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:171\nmsgid \"Whether tensor life cycle manage is enable/disable\"\nmsgstr \"是否启用 tensor 的生命周期管理\"\n\n#: ../../reference/engine-config.rst:173\nmsgid \"arrow_client_disable_server_verification\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:173\nmsgid \"Whether disable server verification for ArrowSQL adaptor\"\nmsgstr \"是否禁用 ArrowSQL adaptor 服务端的认证\"\n\n#: ../../reference/engine-config.rst:175\nmsgid \"arrow_cert_pem_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:175\nmsgid \"\"\n\"Certificate file path for server verification when \"\n\"arrow_client_disable_server_verification is false\"\nmsgstr \"当 arrow_client_disable_server_verification 设置为 false 的时候，server 认证的证书文件路径\"\n\n#: ../../reference/engine-config.rst:177\nmsgid \"arrow_client_key_pem_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:177\nmsgid \"Private key file path for ArrowSQL client to work in mtls\"\nmsgstr \"ArrowSQL client 启用 mtls 时使用的 private key 文件路径\"\n\n#: ../../reference/engine-config.rst:179\nmsgid \"arrow_client_cert_pem_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:179\nmsgid \"Certificate file path for ArrowSQL client to work in mtls\"\nmsgstr \"ArrowSQL client 启用 mtls 时使用的证书文件路径\"\n\n#: ../../reference/engine-config.rst:181\nmsgid \"tmp_file_path\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:181\nmsgid \"/tmp\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:181\nmsgid \"The path for temporarily storing local data in streaming mode.\"\nmsgstr \"streaming 模式下存储临时文件的路径\"\n\n#: ../../reference/engine-config.rst:183\nmsgid \"streaming_row_num_threshold\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:183\nmsgid \"30000000\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:183\nmsgid \"Minimum row num to use streaming mode\"\nmsgstr \"触发 streaming 模式的最小数据量\"\n\n#: ../../reference/engine-config.rst:185\nmsgid \"batch_row_num\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:185\nmsgid \"10000000\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:185\nmsgid \"Max row num in one batch\"\nmsgstr \"每个 batch 的最大数据量\"\n\n#: ../../reference/engine-config.rst:191\nmsgid \"Config for datasource\"\nmsgstr \"数据源配置\"\n\n#: ../../reference/engine-config.rst:192\nmsgid \"\"\n\"datasources(MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL) are where the \"\n\"SCQLEngine gets its data from.\"\nmsgstr \"SCQLEngine 支持多种数据源，包括 MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL 。\"\n\n#: ../../reference/engine-config.rst:194\n#, fuzzy\nmsgid \"\"\n\"``datasource_router`` is design to support multi datasources, currently \"\n\"supported: ``embed`` and ``http``.\"\nmsgstr \"``datasource_router`` 是为了支持多数据源而设计的，目前支持 `embed` 和 `http`。\"\n\n#: ../../reference/engine-config.rst:196\n#, fuzzy\nmsgid \"\"\n\"For ``embed`` type, which is initialized with ``embed_router_conf`` \"\n\"first, a json string like::\"\nmsgstr \"\"\n\"对于 ``embed`` 模式，首先通过 ``embed_router_conf`` 来初始化，``embed_router_conf`` 是 \"\n\"json 类型的字符串，一个典型的配置项如下所示：\"\n\n#: ../../reference/engine-config.rst:214\nmsgid \"\"\n\"if ``embed_router_conf`` is empty, embed_router will try to initialized \"\n\"with ``db_connection_info``.\"\nmsgstr \"\"\n\"如果 ``embed_router_conf`` 为空， `embed_router` 则会尝试通过 ``db_connection_info``\"\n\" 来初始化。\"\n\n#: ../../reference/engine-config.rst:216\nmsgid \"\"\n\"For ``http`` type, ``http_router_endpoint`` must be set and will be \"\n\"accessed to get database information.\"\nmsgstr \"对于 ``http`` 模式，``http_router_endpoint`` 必须被设置，会通过访问 endpoint 来获取数据库信息。\"\n\n#: ../../reference/engine-config.rst:218\nmsgid \"Example of a mock http router server: `mock http router`_.\"\nmsgstr \"模拟 http router server 例子：`mock http router`_。\"\n\n#: ../../reference/engine-config.rst:221\nmsgid \"Embed router\"\nmsgstr \"Embed router\"\n\n#: ../../reference/engine-config.rst:222\nmsgid \"\"\n\"datasources in embed_router_conf contain information for connecting \"\n\"MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL:\"\nmsgstr \"\"\n\"embed_router_conf 中的 datasources 包含用于连接 \"\n\"MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL 数据源的信息:\"\n\n#: ../../reference/engine-config.rst:224\nmsgid \"id: unique id of datasource.\"\nmsgstr \"id：数据源的唯一ID。\"\n\n#: ../../reference/engine-config.rst:226\nmsgid \"name: custom description help to distinguish datasources.\"\nmsgstr \"name：自定义描述，有助于区分数据源。\"\n\n#: ../../reference/engine-config.rst:228\nmsgid \"\"\n\"kind: datasource type, currently support \"\n\"MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL.\"\nmsgstr \"kind：数据源类型，目前支持 MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL 。\"\n\n#: ../../reference/engine-config.rst:230\nmsgid \"\"\n\"connection_str: string used to connect \"\n\"MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL.\"\nmsgstr \"connection_str：用于连接 MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL 数据库的连接串。\"\n\n#: ../../reference/engine-config.rst:234\nmsgid \"MySQL Connection string format:\"\nmsgstr \"MySQL 连接串格式：\"\n\n#: ../../reference/engine-config.rst:235\nmsgid \"<str> == <assignment> | <assignment> ';' <str>\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:237 ../../reference/engine-config.rst:255\nmsgid \"<assignment> == <name> '=' <value>\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:239\nmsgid \"\"\n\"<name> == 'host' | 'port' | 'user' | 'password' | 'db' | 'compress' | \"\n\"'auto-reconnect' | 'reset' | 'fail-readonly'\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:241 ../../reference/engine-config.rst:259\nmsgid \"<value> == [~;]*\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:243\nmsgid \"MySQL Connection string e.g:\"\nmsgstr \"MySQL 连接串示例：\"\n\n#: ../../reference/engine-config.rst:244\n#, python-brace-format\nmsgid \"``db=${db};user=${user};password=${password};host=${host}``\"\nmsgstr \"``db=${db};user=${user};password=${password};host=${host}``\"\n\n#: ../../reference/engine-config.rst:246\nmsgid \"SQLite3 Connection string format:\"\nmsgstr \"SQLite3 连接串格式：\"\n\n#: ../../reference/engine-config.rst:247\nmsgid \"more infos: https://www.sqlite.org/c3ref/open.html\"\nmsgstr \"参考：https://www.sqlite.org/c3ref/open.html\"\n\n#: ../../reference/engine-config.rst:249\nmsgid \"SQLite3 Connection string e.g:\"\nmsgstr \"SQLite3 连接串示例\"\n\n#: ../../reference/engine-config.rst:250\nmsgid \"``file:/path/to/data.db``\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:252\nmsgid \"PostgreSQL Connection string format:\"\nmsgstr \"PostgreSQL 连接串格式：\"\n\n#: ../../reference/engine-config.rst:253\nmsgid \"<str> == <assignment> | <assignment> ' ' <str>\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:257\nmsgid \"\"\n\"<name> == 'host' | 'port' | 'user' | 'password' | 'dbname' | \"\n\"'connect_timeout'\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:261\nmsgid \"PostgreSQL Connection string e.g:\"\nmsgstr \"PostgreSQL 连接串示例：\"\n\n#: ../../reference/engine-config.rst:262\n#, python-brace-format\nmsgid \"\"\n\"``dbname=${db} user=${user} password=${password} host=${host} \"\n\"port=${port}``\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:264\nmsgid \"CSVDB Connection string format:\"\nmsgstr \"CSVDB 连接串格式：\"\n\n#: ../../reference/engine-config.rst:265\nmsgid \"\"\n\"CSVDB support read csv from local and OSS/MinIO, since connection_str is \"\n\"an object in another json object, the format is a converted json string \"\n\"corresponding to `CsvdbConf \"\n\"<https://github.com/secretflow/scql/tree/main/engine/datasource/csvdb_conf.proto>`_\"\nmsgstr \"\"\n\"CSVDB 支持从 local 和 OSS/MinIO 读取 csv 文件，由于 connection_str 是另一个 json \"\n\"对象中的对象，因此其格式是根据 `CsvdbConf \"\n\"<https://github.com/secretflow/scql/tree/main/engine/datasource/csvdb_conf.proto>`_\"\n\" 结构体转换后的的json字符串 \"\n\n#: ../../reference/engine-config.rst:267\nmsgid \"CSVDB Connection string e.g:\"\nmsgstr \"CSVDB连接语句示例:\"\n\n#: ../../reference/engine-config.rst:268\n#, python-brace-format\nmsgid \"\"\n\"local csv: \"\n\"\\\"{\\\\\\\\\\\\\\\"db_name\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"csvdb\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"tables\\\\\\\\\\\\\\\":[{\\\\\\\\\\\\\\\"table_name\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"staff\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"data_path\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"test.csv\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"columns\\\\\\\\\\\\\\\":[{\\\\\\\\\\\\\\\"column_name\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"id\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"column_type\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"string\\\\\\\\\\\\\\\"}]}]}\\\"\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:270\n#, python-brace-format\nmsgid \"\"\n\"OSS csv: \"\n\"\\\"{\\\\\\\\\\\\\\\"db_name\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"csvdb\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"s3_conf\\\\\\\\\\\\\\\":{\\\\\\\\\\\\\\\"endpoint\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"test_endpoint\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"access_key_id\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"test_id\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"secret_access_key\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"test_key\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"virtualhost\\\\\\\\\\\\\\\":\"\n\" true \"\n\"},\\\\\\\\\\\\\\\"tables\\\\\\\\\\\\\\\":[{\\\\\\\\\\\\\\\"table_name\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"staff\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"data_path\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"oss://test_bucket/test.csv\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"columns\\\\\\\\\\\\\\\":[{\\\\\\\\\\\\\\\"column_name\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"id\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"column_type\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"string\\\\\\\\\\\\\\\"}]}]}\\\"\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:272\nmsgid \"ArrowSQL Connection string format:\"\nmsgstr \"ArrowSQL 连接串格式：\"\n\n#: ../../reference/engine-config.rst:273\nmsgid \"grpc+<scheme>://host:port\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:275\nmsgid \"<scheme> == 'tcp' | 'tls'\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:277\nmsgid \"ArrowSQL Connection string e.g:\"\nmsgstr \"ArrowSQL 连接串示例：\"\n\n#: ../../reference/engine-config.rst:278\nmsgid \"``grpc+tcp://127.0.0.1:6666``\"\nmsgstr \"\"\n\n#: ../../reference/engine-config.rst:281\nmsgid \"\"\n\"As a datasource embedded in SCQLEngine, ArrowSQL requires an additional \"\n\"gRPC server which provides the corresponding interface for executing an \"\n\"ad-hoc query in `Arrow Flight SQL \"\n\"<https://arrow.apache.org/docs/format/FlightSql.html>`_\"\nmsgstr \"\"\n\"作为 SCQLEngine 内嵌的数据源，ArrowSQL 依赖额外的 gRPC 服务，该服务需要提供相应的接口，用于执行 `Arrow \"\n\"Flight SQL <https://arrow.apache.org/docs/format/FlightSql.html>`_ 即时查询\"\n\n#: ../../reference/engine-config.rst:284\nmsgid \"Routing rules\"\nmsgstr \"路由规则\"\n\n#: ../../reference/engine-config.rst:285\nmsgid \"\"\n\"embed_router's rules support wildcard ``*`` , when given a table in \"\n\"format: *database_name:table_name*, embed_router will route to the \"\n\"corresponding datasource by\"\nmsgstr \"\"\n\"embed_router 的规则支持通配符 ``*`` ，当给定一个 *database_name:table_name* \"\n\"的数据表时，embed_router 将通过以下方式路由到对应的数据源：\"\n\n#: ../../reference/engine-config.rst:288\n#, python-brace-format\nmsgid \"\"\n\"find the exact rules first, whose ``${db}:${table}`` equals to \"\n\"*database_name:table_name*;\"\nmsgstr \"\"\n\"在 `embed_router_conf` 的 `rules` 中查找 `${db}:${table}` 与 \"\n\"`database_name:table_name` 完全相等的 rule\"\n\n#: ../../reference/engine-config.rst:289\nmsgid \"try the database_name:\\\\* rules;\"\nmsgstr \"在 `embed_router_conf` 的 `rules` 中查找 `${db}` 与 `database_name` 完全相等的 rule\"\n\n#: ../../reference/engine-config.rst:290\nmsgid \"try \\\\*:table_name in the end.\"\nmsgstr \"在 `embed_router_conf` 的 `rules` 中查找 `${table}` 与 `table_name` 完全相等的 rule\"\n\n#: ../../reference/engine-config.rst:292\nmsgid \"\"\n\"Once found, SCQLEngine will try to connect database with datasource's \"\n\"information correspond to the *datasource_id*.\"\nmsgstr \"\"\n\"一旦找到对应的 rule ，SCQLEngine 将根据 rule 中 datasource_id 在 datasources 中找到 \"\n\"对应的数据源信息，并根据这些信息连接对应的数据库。\"\n\n#: ../../reference/engine-config.rst:295\nmsgid \"Config for Brpc server\"\nmsgstr \"Brpc 服务器配置\"\n\n#: ../../reference/engine-config.rst:296\nmsgid \"\"\n\"SCQLEngine uses **Brpc** to communicate with Driver and other peer \"\n\"SCQLEngines, each SCQLEngine will start a Brpc service on *local-\"\n\"host:listen_port* to receive data from outside. If you want to enable \"\n\"Brpc builtin services, add FLAGS:\"\nmsgstr \"\"\n\"SCQLEngine 使用 Brpc 与 Driver 以及其他的 SCQLEngine 进行通信，每个 SCQLEngine 都会在 \"\n\"local-host:listen_port 上启动 Brpc 服务以接收来自外部的数据。如果要启用 Brpc 内置服务，请添加 FLAGS：\"\n\n#: ../../reference/engine-config.rst:307\nmsgid \"Config for SSL\"\nmsgstr \"SSL配置\"\n\n#: ../../reference/engine-config.rst:308\nmsgid \"If you want to enable SSL in SCQLEngine, add FLAGS as follows.\"\nmsgstr \"如果你想在SCQLEngine中启用SSL，请添加以下FLAGS。\"\n\n#: ../../reference/engine-config.rst:321\nmsgid \"Config for party authentication\"\nmsgstr \"参与方身份验证配置\"\n\n#: ../../reference/engine-config.rst:322\nmsgid \"\"\n\"For security, SCQLEngine enables party authentication by default. \"\n\"SCQLEngine will check it's public key in the Driver request matches the \"\n\"local public key in ``private_key_pem_path``, and that the other \"\n\"participant's public key also matches the one in \"\n\"``authorized_profile_path``.\"\nmsgstr \"\"\n\"安全起见，SCQLEngine 默认启用参与方身份验证。 SCQLEngine 将检查 Driver 请求中自身的公钥是否与 \"\n\"``private_key_pem_path`` 中的本地公钥匹配，并且其他参与者的公钥也与 \"\n\"``authorized_profile_path`` 中的公钥匹配。\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/reference/implementation-status.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-11 19:17+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../reference/implementation-status.rst:2\nmsgid \"SCQL Implementation Status\"\nmsgstr \"SCQL 实现进度\"\n\n#: ../../reference/implementation-status.rst:5\nmsgid \"SELECT Statement\"\nmsgstr \"SELECT 语句\"\n\n#: ../../reference/implementation-status.rst:8\nmsgid \"syntax\"\nmsgstr \"语法\"\n\n#: ../../reference/implementation-status.rst:8\n#: ../../reference/implementation-status.rst:37\n#: ../../reference/implementation-status.rst:82\nmsgid \"supported(fully/partial/no)\"\nmsgstr \"支持程度(完全/部分/未支持)\"\n\n#: ../../reference/implementation-status.rst:8\n#: ../../reference/implementation-status.rst:37\n#: ../../reference/implementation-status.rst:82\nmsgid \"notes\"\nmsgstr \"说明\"\n\n#: ../../reference/implementation-status.rst:10\nmsgid \"join\"\nmsgstr \"join\"\n\n#: ../../reference/implementation-status.rst:10\n#: ../../reference/implementation-status.rst:26\n#: ../../reference/implementation-status.rst:51\n#: ../../reference/implementation-status.rst:55\n#: ../../reference/implementation-status.rst:59\n#: ../../reference/implementation-status.rst:61\n#: ../../reference/implementation-status.rst:63\n#: ../../reference/implementation-status.rst:65\n#: ../../reference/implementation-status.rst:67\n#: ../../reference/implementation-status.rst:69\n#: ../../reference/implementation-status.rst:71\n#: ../../reference/implementation-status.rst:73\n#: ../../reference/implementation-status.rst:75\n#: ../../reference/implementation-status.rst:86\n#: ../../reference/implementation-status.rst:88\nmsgid \"partial\"\nmsgstr \"部分\"\n\n#: ../../reference/implementation-status.rst:10\nmsgid \"keyword ``using`` is not supported yet\"\nmsgstr \"暂不支持关键字 ``using``\"\n\n#: ../../reference/implementation-status.rst:12\nmsgid \"where clause\"\nmsgstr \"where 子句\"\n\n#: ../../reference/implementation-status.rst:12\n#: ../../reference/implementation-status.rst:14\n#: ../../reference/implementation-status.rst:16\n#: ../../reference/implementation-status.rst:18\n#: ../../reference/implementation-status.rst:20\n#: ../../reference/implementation-status.rst:22\n#: ../../reference/implementation-status.rst:24\n#: ../../reference/implementation-status.rst:28\n#: ../../reference/implementation-status.rst:39\n#: ../../reference/implementation-status.rst:41\n#: ../../reference/implementation-status.rst:43\n#: ../../reference/implementation-status.rst:45\n#: ../../reference/implementation-status.rst:47\n#: ../../reference/implementation-status.rst:49\n#: ../../reference/implementation-status.rst:53\n#: ../../reference/implementation-status.rst:57\n#: ../../reference/implementation-status.rst:84\nmsgid \"fully\"\nmsgstr \"完全\"\n\n#: ../../reference/implementation-status.rst:14\nmsgid \"group by clause\"\nmsgstr \"group by 子句\"\n\n#: ../../reference/implementation-status.rst:16\nmsgid \"having clause\"\nmsgstr \"having 子句\"\n\n#: ../../reference/implementation-status.rst:18\nmsgid \"union/union all clause\"\nmsgstr \"union/union all 子句\"\n\n#: ../../reference/implementation-status.rst:20\nmsgid \"distinct clause\"\nmsgstr \"distinct 子句\"\n\n#: ../../reference/implementation-status.rst:22\nmsgid \"limit clause\"\nmsgstr \"limit 子句\"\n\n#: ../../reference/implementation-status.rst:24\nmsgid \"order by clause\"\nmsgstr \"order by 子句\"\n\n#: ../../reference/implementation-status.rst:26\n#, fuzzy\nmsgid \"subquery clause\"\nmsgstr \"subquery 子句\"\n\n#: ../../reference/implementation-status.rst:26\nmsgid \"support partial scalar subquery and compare subquery\"\nmsgstr \"支持部分scalar subquery和compare subquery\"\n\n#: ../../reference/implementation-status.rst:28\n#, fuzzy\nmsgid \"in clause\"\nmsgstr \"in 子句\"\n\n#: ../../reference/implementation-status.rst:34\n#: ../../reference/implementation-status.rst:37\nmsgid \"Functions and Operators\"\nmsgstr \"函数和运算符\"\n\n#: ../../reference/implementation-status.rst:37\nmsgid \"Category\"\nmsgstr \"类别\"\n\n#: ../../reference/implementation-status.rst:39\n#: ../../reference/implementation-status.rst:41\n#: ../../reference/implementation-status.rst:43\n#: ../../reference/implementation-status.rst:45\n#: ../../reference/implementation-status.rst:47\nmsgid \"aggregation\"\nmsgstr \"聚合运算\"\n\n#: ../../reference/implementation-status.rst:39\nmsgid \"sum\"\nmsgstr \"sum\"\n\n#: ../../reference/implementation-status.rst:41\nmsgid \"count\"\nmsgstr \"count\"\n\n#: ../../reference/implementation-status.rst:43\nmsgid \"avg\"\nmsgstr \"avg\"\n\n#: ../../reference/implementation-status.rst:45\nmsgid \"min\"\nmsgstr \"min\"\n\n#: ../../reference/implementation-status.rst:47\nmsgid \"max\"\nmsgstr \"max\"\n\n#: ../../reference/implementation-status.rst:49\n#, fuzzy\nmsgid \"binary arithmetic\"\nmsgstr \"二元算术运算\"\n\n#: ../../reference/implementation-status.rst:49\nmsgid \"+,-,*,/,div\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:49\nmsgid \"div means ``integer division``\"\nmsgstr \"div: 整数除法\"\n\n#: ../../reference/implementation-status.rst:51\n#, fuzzy\nmsgid \"unary arithmetic\"\nmsgstr \"一元算术运算\"\n\n#: ../../reference/implementation-status.rst:51\n#, fuzzy\nmsgid \"\"\n\"trigonometric, abs, round, ceil, floor, round, radians, degrees, ln, \"\n\"log10, log2, sqrt, exp, etc\"\nmsgstr \"\"\n\"三角函数, abs, ceil, floor, round, radians, degrees, ln, log10, log2, sqrt, \"\n\"exp, etc\"\n\n#: ../../reference/implementation-status.rst:51\nmsgid \"log2, log10, round does not support secret input\"\nmsgstr \"log2, log10, round运算不支持密态运算\"\n\n#: ../../reference/implementation-status.rst:53\nmsgid \"logical\"\nmsgstr \"逻辑运算\"\n\n#: ../../reference/implementation-status.rst:53\nmsgid \"logical_and,logical_or,not\"\nmsgstr \"logical_and,logical_or,not\"\n\n#: ../../reference/implementation-status.rst:55\n#: ../../reference/implementation-status.rst:57\nmsgid \"compare\"\nmsgstr \"比较运算\"\n\n#: ../../reference/implementation-status.rst:55\nmsgid \"<,<=,>,>=\"\nmsgstr \"<,<=,>,>=\"\n\n#: ../../reference/implementation-status.rst:55\nmsgid \"string data comparison is not supported\"\nmsgstr \"不支持字符串类型数据比较\"\n\n#: ../../reference/implementation-status.rst:57\nmsgid \"=, !=\"\nmsgstr \"=, !=\"\n\n#: ../../reference/implementation-status.rst:59\nmsgid \"in\"\nmsgstr \"in\"\n\n#: ../../reference/implementation-status.rst:59\nmsgid \"in, not in\"\nmsgstr \"in, not in\"\n\n#: ../../reference/implementation-status.rst:59\nmsgid \"all arguments should be of the same type\"\nmsgstr \"所有参数应为同一类型\"\n\n#: ../../reference/implementation-status.rst:61\n#: ../../reference/implementation-status.rst:63\n#: ../../reference/implementation-status.rst:65\n#: ../../reference/implementation-status.rst:67\n#: ../../reference/implementation-status.rst:69\n#: ../../reference/implementation-status.rst:71\nmsgid \"datetime\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:61\nmsgid \"now\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:61\nmsgid \"no arguments, affected by timezone\"\nmsgstr \"无参数，受时区影响\"\n\n#: ../../reference/implementation-status.rst:63\nmsgid \"curdate\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:63\nmsgid \"\"\n\"no arguments, different datasource may have different result because of \"\n\"timezone\"\nmsgstr \"无参数，受时区影响，不同的数据源可能有不同的结果\"\n\n#: ../../reference/implementation-status.rst:65\nmsgid \"last_day\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:65\n#: ../../reference/implementation-status.rst:67\nmsgid \"arguments must be datetime or timestamp, not supported by PostgreSQL\"\nmsgstr \"参数必须是 datetime 或者 timestamp ，不支持 PostgreSQL \"\n\n#: ../../reference/implementation-status.rst:67\nmsgid \"str_to_date, date_format\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:69\nmsgid \"adddate, subdate\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:69\nmsgid \"\"\n\"the first argument must be datetime or timestamp, second argument is \"\n\"interval\"\nmsgstr \"第一个参数必须是 datetime 或者 timestamp，第二个参数是间隔\"\n\n#: ../../reference/implementation-status.rst:71\nmsgid \"datediff\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:71\nmsgid \"\"\n\"arguments must be datetime or timestamp, not supported by PostgreSQL and \"\n\"csv\"\nmsgstr \"参数必须是 datetime 或者 timestamp ，不支持 PostgreSQL 和 csv \"\n\n#: ../../reference/implementation-status.rst:73\nmsgid \"string\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:73\nmsgid \"substr, lower, upper, trim, concat\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:73\nmsgid \"do not support secret input\"\nmsgstr \"不支持密态运算\"\n\n#: ../../reference/implementation-status.rst:75\nmsgid \"window\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:75\nmsgid \"row_number, percent_rank\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:79\nmsgid \"Data Source\"\nmsgstr \"数据源\"\n\n#: ../../reference/implementation-status.rst:82\nmsgid \"Database Type\"\nmsgstr \"数据库类型\"\n\n#: ../../reference/implementation-status.rst:84\nmsgid \"MySQL\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:86\nmsgid \"PostgreSQL\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:88\nmsgid \"CSV\"\nmsgstr \"\"\n\n#: ../../reference/implementation-status.rst:88\nmsgid \"Data stored in csv files\"\nmsgstr \"数据源为 CSV 文件\"\n\n#: ../../reference/implementation-status.rst:92\nmsgid \"\"\n\"SCQL supports different databases as data source, but there may be minor \"\n\"differences in the results due to data type differences built in \"\n\"databases. Please choose backend database with caution.\"\nmsgstr \"SCQL 支持不同的数据库作为数据源，但由于数据库内置的数据类型差异，结果可能会存在细微差异。请谨慎选择后端数据库。\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/reference/index.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-11 17:17+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../reference/index.rst:4\nmsgid \"Language\"\nmsgstr \"语言\"\n\n#: ../../reference/index.rst:11\nmsgid \"Configuration\"\nmsgstr \"配置\"\n\n#: ../../reference/index.rst:18\nmsgid \"Internal Reference\"\nmsgstr \"内部开发者参考\"\n\n#: ../../reference/index.rst:2\nmsgid \"Reference\"\nmsgstr \"参考文档\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/reference/lang/manual.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-24 16:33+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../reference/lang/manual.rst:2\nmsgid \"SCQL Language Manual\"\nmsgstr \"SCQL 方言指南\"\n\n#: ../../reference/lang/manual.rst:8\nmsgid \"SCQL Data Types\"\nmsgstr \"SCQL 数据类型\"\n\n#: ../../reference/lang/manual.rst:10\nmsgid \"\"\n\"SCQL supports frequently-used data types, as illustrated in the following\"\n\" table.\"\nmsgstr \"SCQL 支持常用的数据类型，如下表所示。\"\n\n#: ../../reference/lang/manual.rst:13\nmsgid \"Data Type\"\nmsgstr \"数据类型\"\n\n#: ../../reference/lang/manual.rst:13\nmsgid \"Alias\"\nmsgstr \"别名\"\n\n#: ../../reference/lang/manual.rst:13\nmsgid \"Description\"\nmsgstr \"描述\"\n\n#: ../../reference/lang/manual.rst:15\nmsgid \"``integer``\"\nmsgstr \"``integer``\"\n\n#: ../../reference/lang/manual.rst:15\nmsgid \"``int``, ``int32``, ``int64``\"\nmsgstr \"``int``, ``int32``, ``int64``\"\n\n#: ../../reference/lang/manual.rst:17\nmsgid \"``float``\"\nmsgstr \"``float``\"\n\n#: ../../reference/lang/manual.rst:17\n#, fuzzy\nmsgid \"``float32``\"\nmsgstr \"``float``\"\n\n#: ../../reference/lang/manual.rst:19\n#, fuzzy\nmsgid \"``double``\"\nmsgstr \"``float64``, ``double``\"\n\n#: ../../reference/lang/manual.rst:19\n#, fuzzy\nmsgid \"``float``, ``double``, ``float64``\"\nmsgstr \"``float``, ``double``, ``float64``\"\n\n#: ../../reference/lang/manual.rst:21\nmsgid \"``string``\"\nmsgstr \"``string``\"\n\n#: ../../reference/lang/manual.rst:21\nmsgid \"``str``\"\nmsgstr \"``str``\"\n\n#: ../../reference/lang/manual.rst:23\nmsgid \"``datetime``\"\nmsgstr \"``datetime``\"\n\n#: ../../reference/lang/manual.rst:23\nmsgid \"\"\n\"Used for values that contain both date and time parts. SCQL retrieves and\"\n\" displays in 'YYYY-MM-DD hh:mm:ss' format\"\nmsgstr \"包含日期和时间两部分， SCQL 使用 'YYYY-MM-DD hh:mm:ss' 格式识别及表示\"\n\n#: ../../reference/lang/manual.rst:25\nmsgid \"``timestamp``\"\nmsgstr \"``timestamp``\"\n\n#: ../../reference/lang/manual.rst:25\nmsgid \"\"\n\"Used for values that contain both date and time parts. SCQL retrieves in \"\n\"'YYYY-MM-DD hh:mm:ss' format and displays in int64 value affected by time\"\n\" zone\"\nmsgstr \"包含日期和时间两部分， SCQL 使用 'YYYY-MM-DD hh:mm:ss' 格式识别，但表示为受时区影响的 int64 值\"\n\n#: ../../reference/lang/manual.rst:32\nmsgid \"SCQL Query Syntax\"\nmsgstr \"SCQL 查询语法\"\n\n#: ../../reference/lang/manual.rst:34\nmsgid \"\"\n\"It is compatible with most MySQL DQL syntax. For syntax differences \"\n\"between SCQL and MySQL, please read :doc:`/reference/lang/mysql-\"\n\"compatibility`.\"\nmsgstr \"\"\n\"SCQL 兼容大多数 MySQL 语法。关于 SCQL 和 MySQL 之间的语法差异，请阅读 :doc:`/reference/lang\"\n\"/mysql-compatibility` 。\"\n\n#: ../../reference/lang/manual.rst:107\nmsgid \"\"\n\"SCQL support ``export_options`` with limitations: only support '\\\"' or ''\"\n\" for **enclosing_character**; **ESCAPED BY** is not supported.\"\nmsgstr \"\"\n\"SCQL 在一定限制下支持 ``export_options``: 目前只支持 '\\\"' 或者 '' 作为 \"\n\"**enclosing_character**；暂时不支持 **ESCAPED BY** 语法。\"\n\n#: ../../reference/lang/manual.rst:108\nmsgid \"\"\n\"**OPTIONALLY** in ``export_options`` controls quoting of fields, if \"\n\"omitted all fields are enclosed by the **enclosing_character**, otherwise\"\n\" only string fields are enclosed. see `mysql load data`_\"\nmsgstr \"\"\n\"``export_options`` 中的 **OPTIONALLY** 用于控制字段的引用行为，如果省略则所有类型的字段都会使用 \"\n\"**enclosing_character** 括起来，否则只有 string 类型的字段被括起来, 参考 `mysql load data`_\"\n\n#: ../../reference/lang/manual.rst:109\nmsgid \"\"\n\"**file_path** in ``into_option`` can be local path like '/data/file.csv' \"\n\"or oss path like 'oss://bucket_name/path/to/file', flags for writing \"\n\"should be set correctly, see :ref:`Engine configuration options \"\n\"<engine_config_options>` for more.\"\nmsgstr \"\"\n\"``into_option`` 中的 **file_path** 可以是一个本地路径： '/data/file.csv' ，或者一个 oss \"\n\"路径： 'oss://bucket_name/path/to/file' ， write 相关的 flag 应该正确设置，参考 \"\n\":ref:`Engine 配置项 <engine_config_options>`\"\n\n#: ../../reference/lang/manual.rst:114\nmsgid \"Functions and Operators\"\nmsgstr \"函数与操作符\"\n\n#: ../../reference/lang/manual.rst:116\nmsgid \"待处理\"\nmsgstr \"\"\n\n#: ../../reference/lang/manual.rst:116\nmsgid \"this part is not ready, please check later\"\nmsgstr \"该部分尚未准备好，请之后查看\"\n\n#~ msgid \"Todo\"\n#~ msgstr \"待办\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/reference/lang/mysql-compatibility.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-11 17:17+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../reference/lang/mysql-compatibility.rst:2\nmsgid \"MySQL Compatibility\"\nmsgstr \"与 MySQL 的兼容性\"\n\n#: ../../reference/lang/mysql-compatibility.rst:4\nmsgid \"\"\n\"SCQL is highly compatible with MySQL, but there are still some syntax \"\n\"differences.\"\nmsgstr \"SCQL 与 MySQL 高度兼容，但仍有一些语法差异。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:7\nmsgid \"Unsupported Features\"\nmsgstr \"不支持的功能\"\n\n#: ../../reference/lang/mysql-compatibility.rst:9\nmsgid \"Partition table\"\nmsgstr \"分区表\"\n\n#: ../../reference/lang/mysql-compatibility.rst:10\nmsgid \"Character sets\"\nmsgstr \"字符集\"\n\n#: ../../reference/lang/mysql-compatibility.rst:11\nmsgid \"User-defined functions\"\nmsgstr \"用户自定义的函数\"\n\n#: ../../reference/lang/mysql-compatibility.rst:12\nmsgid \"TCL(Transaction Control Language)\"\nmsgstr \"TCL（事务控制语言）\"\n\n#: ../../reference/lang/mysql-compatibility.rst:13\nmsgid \"DML(Data Manipulation Language)\"\nmsgstr \"DML（数据操作语言）\"\n\n#: ../../reference/lang/mysql-compatibility.rst:16\nmsgid \"Features that are different from MySQL\"\nmsgstr \"与 MySQL 存在语法差异的功能\"\n\n#: ../../reference/lang/mysql-compatibility.rst:19\nmsgid \"DDL(Data Definition Language)\"\nmsgstr \"DDL（数据定义语言）\"\n\n#: ../../reference/lang/mysql-compatibility.rst:22\nmsgid \"CREATE Table\"\nmsgstr \"创建表\"\n\n#: ../../reference/lang/mysql-compatibility.rst:23\nmsgid \"\"\n\"The Table created in SCQL is a virtual Table and needs to be mapped to \"\n\"the actual Table, so we extend the statement to transfer the mapping \"\n\"information. For more information, please read \"\n\":doc:`/reference/lang/manual`.\"\nmsgstr \"\"\n\"SCQL 中创建的 Table 是一个虚拟 Table，需要映射到实际 Table，所以我们扩展该语句来传递映射信息。更多信息，请阅读 \"\n\":doc:`/reference/lang/manual`。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:27\nmsgid \"DQL(Data Query Language)\"\nmsgstr \"DQL（数据查询语言）\"\n\n#: ../../reference/lang/mysql-compatibility.rst:29\nmsgid \"\"\n\"About implementation status, please read :doc:`/reference/implementation-\"\n\"status`.\"\nmsgstr \"关于实现的具体情况，请阅读 :doc:`/reference/implementation-status`。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:32\nmsgid \"Type Null is unsupported in SCQL.\"\nmsgstr \"SCQL 不支持 Null 类型。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:35\nmsgid \"Functions different from MySQL\"\nmsgstr \"与 MySQL 的功能差异\"\n\n#: ../../reference/lang/mysql-compatibility.rst:38\nmsgid \"Function Name\"\nmsgstr \"功能名称\"\n\n#: ../../reference/lang/mysql-compatibility.rst:38\nmsgid \"In SCQL\"\nmsgstr \"SCQL 的方式\"\n\n#: ../../reference/lang/mysql-compatibility.rst:38\nmsgid \"In MySQL\"\nmsgstr \"MySQL 的方式\"\n\n#: ../../reference/lang/mysql-compatibility.rst:38\nmsgid \"Note\"\nmsgstr \"备注\"\n\n#: ../../reference/lang/mysql-compatibility.rst:40\nmsgid \"SUM(INT)\"\nmsgstr \"SUM(INT) 整数求和\"\n\n#: ../../reference/lang/mysql-compatibility.rst:40\nmsgid \"returns int\"\nmsgstr \"返回整型 int\"\n\n#: ../../reference/lang/mysql-compatibility.rst:40\nmsgid \"returns Decimal/Double\"\nmsgstr \"返回小数 Decimal /双精度 Double\"\n\n#: ../../reference/lang/mysql-compatibility.rst:42\nmsgid \"Aggregation Functions With Group BY\"\nmsgstr \"使用 Group BY 的聚合函数\"\n\n#: ../../reference/lang/mysql-compatibility.rst:42\nmsgid \"return groups which have greater or equal ``group_by_threshold`` elements\"\nmsgstr \"返回组内数据数量大于等于 ``group_by_threshold`` 的组\"\n\n#: ../../reference/lang/mysql-compatibility.rst:42\nmsgid \"return all groups\"\nmsgstr \"返回所有组\"\n\n#: ../../reference/lang/mysql-compatibility.rst:42\nmsgid \"for safety\"\nmsgstr \"出于安全性考虑\"\n\n#: ../../reference/lang/mysql-compatibility.rst:46\nmsgid \"DCL(Data Control Language)\"\nmsgstr \"DCL（数据控制语言）\"\n\n#: ../../reference/lang/mysql-compatibility.rst:49\nmsgid \"GRANT/REVOKE\"\nmsgstr \"GRANT/REVOKE\"\n\n#: ../../reference/lang/mysql-compatibility.rst:53\nmsgid \"\"\n\"**CCL (Column Control List) is deprecated** and no longer used in the new\"\n\" architecture.\"\nmsgstr \"\"\n\n#: ../../reference/lang/mysql-compatibility.rst:55\nmsgid \"\"\n\"In previous versions, CCL settings were required before executing \"\n\"queries, and could be changed via GRANT/REVOKE. This is no longer \"\n\"applicable in the current version. Please refer to ``examples/opencore-\"\n\"demo/`` for the new access control mechanisms.\"\nmsgstr \"\"\n\n#: ../../reference/lang/mysql-compatibility.rst:58\nmsgid \"Type Conversion Rule\"\nmsgstr \"类型转换规则\"\n\n#: ../../reference/lang/mysql-compatibility.rst:60\nmsgid \"\"\n\"Type conversion takes place when using an operator with operands of \"\n\"different types, to make them compatible. Some conversions occur \"\n\"implicitly. For example, SCQL automatically converts int to float as \"\n\"necessary\"\nmsgstr \"考虑兼容性，当使用运算符操作不同类型的数据时，会发生类型转换。有些转换是隐式发生的。例如，SCQL 会根据需要自动将 int 转换为 float。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:74\nmsgid \"The following rules describe how conversion occurs in SCQL.\"\nmsgstr \"以下规则描述了如何在 SCQL 中进行类型转换。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:79\nmsgid \"single-party query\"\nmsgstr \"单方查询\"\n\n#: ../../reference/lang/mysql-compatibility.rst:80\nmsgid \"\"\n\"If a query only involves one participant, SCQL will convert the query \"\n\"into a syntax that conforms to the participant's database (such as \"\n\"MySQL), and then dispatch it directly to the corresponding database for \"\n\"execution. Thus, for a single-party query, its type conversion rules are \"\n\"generally consistent with the database used by the participant.\"\nmsgstr \"\"\n\"如果只有一方查询，SCQL 会将查询语句转换成符合参与者数据库（如 MySQL）的语法，然后直接分派到相应的数据库中执行。 \"\n\"因此对于单方查询，其类型转换规则一般与参与方使用的数据库类型一致。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:85\nmsgid \"multi-party query\"\nmsgstr \"多方查询\"\n\n#: ../../reference/lang/mysql-compatibility.rst:86\nmsgid \"\"\n\"If a query involves multiple participants, SCQL will execute type \"\n\"conversion by applying the following rules.\"\nmsgstr \"如果涉及多方查询，SCQL 将通过以下规则进行类型转换。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:89\nmsgid \"Compare(>, <, <=, >=, <>, =, !=)\"\nmsgstr \"比较运算 (>, <, <=, >=, <>, =, !=)\"\n\n#: ../../reference/lang/mysql-compatibility.rst:90\nmsgid \"Both arguments in a comparison operation shouldn't be string.\"\nmsgstr \"比较操作中的两个参数都不能是 string 类型。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:91\nmsgid \"If both arguments are long, they are compared as long.\"\nmsgstr \"如果两个参数都是 long 类型，则它们将按照 long 类型进行比较。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:92\nmsgid \"\"\n\"If one of the arguments is float or double, the other argument will be \"\n\"compared as double.\"\nmsgstr \"如果其中一个参数是 float 或者 double 类型，则会将另一个参数转换为 double 类型进行比较。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:95\nmsgid \"Arithmetic(+, -, \\\\*, /, %)\"\nmsgstr \"算术运算 (+, -, \\\\*, /, %)\"\n\n#: ../../reference/lang/mysql-compatibility.rst:96\nmsgid \"\"\n\"Arguments of '%' operation only support type long, while other arithmetic\"\n\" operations support types other than type string.\"\nmsgstr \"'%' 运算的参数仅支持 long 类型，而其他算术运算支持除 string 以外的数据类型。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:97\nmsgid \"If both arguments are long, they are calculated as long.\"\nmsgstr \"如果两个参数都是 long 类型，则它们将按照 long 类型进行计算。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:98\n#: ../../reference/lang/mysql-compatibility.rst:104\nmsgid \"\"\n\"If one of the arguments is float or double, the other argument will be \"\n\"calculated as double.\"\nmsgstr \"如果其中一个参数是 float 或者 double 类型，则会将另一个参数转换为 double 进行计算。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:101\nmsgid \"Aggregation(sum, count, avg, min, max)\"\nmsgstr \"聚合操作 (sum, count, avg, min, max)\"\n\n#: ../../reference/lang/mysql-compatibility.rst:102\nmsgid \"\"\n\"In all aggregation functions except count, parameters should not be type \"\n\"string.\"\nmsgstr \"除了 count ，聚合操作中的所有参数都不能是 string 类型。\"\n\n#: ../../reference/lang/mysql-compatibility.rst:103\nmsgid \"If all arguments are long, they are calculated as long.\"\nmsgstr \"如果所有参数都是 long 类型，则它们将按照 long 类型进行计算。\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/reference/operators.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-11 19:17+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../reference/operators.md:1\nmsgid \"SCQL Operators Specification\"\nmsgstr \"SCQL 算子规范\"\n\n#: ../../reference/operators.md:3\nmsgid \"\"\n\"This is a specification (not a kernel library) of SCQL operators, \"\n\"including operator signatures and semantics.\"\nmsgstr \"本文将介绍 SCQL 支持的算子（不是内核库）， 包括算子的签名和语义。\"\n\n#: ../../reference/operators.md:5\nmsgid \"Op List\"\nmsgstr \"算子列表\"\n\n#: ../../reference/operators.md:8\nmsgid \"`ACos`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:10\nmsgid \"Definition: return the value of arc cosine function\"\nmsgstr \"定义：返回数据的 arc cosine 结果\"\n\n#: ../../reference/operators.md:12 ../../reference/operators.md:25\n#: ../../reference/operators.md:38 ../../reference/operators.md:51\n#: ../../reference/operators.md:67 ../../reference/operators.md:80\n#: ../../reference/operators.md:104 ../../reference/operators.md:128\n#: ../../reference/operators.md:144 ../../reference/operators.md:171\n#: ../../reference/operators.md:189 ../../reference/operators.md:202\n#: ../../reference/operators.md:223 ../../reference/operators.md:243\n#: ../../reference/operators.md:285 ../../reference/operators.md:302\n#: ../../reference/operators.md:315 ../../reference/operators.md:328\n#: ../../reference/operators.md:341 ../../reference/operators.md:357\n#: ../../reference/operators.md:381 ../../reference/operators.md:397\n#: ../../reference/operators.md:419 ../../reference/operators.md:442\n#: ../../reference/operators.md:456 ../../reference/operators.md:469\n#: ../../reference/operators.md:485 ../../reference/operators.md:501\n#: ../../reference/operators.md:522 ../../reference/operators.md:545\n#: ../../reference/operators.md:569 ../../reference/operators.md:593\n#: ../../reference/operators.md:617 ../../reference/operators.md:641\n#: ../../reference/operators.md:665 ../../reference/operators.md:690\n#: ../../reference/operators.md:717 ../../reference/operators.md:742\n#: ../../reference/operators.md:767 ../../reference/operators.md:791\n#: ../../reference/operators.md:817 ../../reference/operators.md:840\n#: ../../reference/operators.md:865 ../../reference/operators.md:882\n#: ../../reference/operators.md:905 ../../reference/operators.md:944\n#: ../../reference/operators.md:969 ../../reference/operators.md:982\n#: ../../reference/operators.md:998 ../../reference/operators.md:1023\n#: ../../reference/operators.md:1040 ../../reference/operators.md:1053\n#: ../../reference/operators.md:1066 ../../reference/operators.md:1079\n#: ../../reference/operators.md:1095 ../../reference/operators.md:1111\n#: ../../reference/operators.md:1128 ../../reference/operators.md:1142\n#: ../../reference/operators.md:1156 ../../reference/operators.md:1172\n#: ../../reference/operators.md:1188 ../../reference/operators.md:1204\n#: ../../reference/operators.md:1217 ../../reference/operators.md:1241\n#: ../../reference/operators.md:1263 ../../reference/operators.md:1287\n#: ../../reference/operators.md:1308 ../../reference/operators.md:1330\n#: ../../reference/operators.md:1352 ../../reference/operators.md:1374\n#: ../../reference/operators.md:1398 ../../reference/operators.md:1423\n#: ../../reference/operators.md:1437 ../../reference/operators.md:1456\n#: ../../reference/operators.md:1472 ../../reference/operators.md:1485\n#: ../../reference/operators.md:1498 ../../reference/operators.md:1527\n#: ../../reference/operators.md:1547 ../../reference/operators.md:1567\n#: ../../reference/operators.md:1587 ../../reference/operators.md:1608\n#: ../../reference/operators.md:1631 ../../reference/operators.md:1656\n#: ../../reference/operators.md:1674 ../../reference/operators.md:1687\n#: ../../reference/operators.md:1734 ../../reference/operators.md:1758\n#: ../../reference/operators.md:1785 ../../reference/operators.md:1798\n#: ../../reference/operators.md:1819 ../../reference/operators.md:1839\n#: ../../reference/operators.md:1852 ../../reference/operators.md:1872\nmsgid \"**Inputs:**\"\nmsgstr \"**输入：**\"\n\n#: ../../reference/operators.md:13\nmsgid \"`In`(single, T): the expression pass to arc cosine function\"\nmsgstr \"``In`` （单列数组，类型为 T ）：arcosine 的入参 。\"\n\n#: ../../reference/operators.md:15 ../../reference/operators.md:28\n#: ../../reference/operators.md:41 ../../reference/operators.md:55\n#: ../../reference/operators.md:70 ../../reference/operators.md:84\n#: ../../reference/operators.md:107 ../../reference/operators.md:132\n#: ../../reference/operators.md:148 ../../reference/operators.md:176\n#: ../../reference/operators.md:192 ../../reference/operators.md:205\n#: ../../reference/operators.md:226 ../../reference/operators.md:246\n#: ../../reference/operators.md:272 ../../reference/operators.md:288\n#: ../../reference/operators.md:305 ../../reference/operators.md:318\n#: ../../reference/operators.md:331 ../../reference/operators.md:345\n#: ../../reference/operators.md:360 ../../reference/operators.md:385\n#: ../../reference/operators.md:400 ../../reference/operators.md:423\n#: ../../reference/operators.md:446 ../../reference/operators.md:459\n#: ../../reference/operators.md:473 ../../reference/operators.md:489\n#: ../../reference/operators.md:504 ../../reference/operators.md:525\n#: ../../reference/operators.md:550 ../../reference/operators.md:574\n#: ../../reference/operators.md:598 ../../reference/operators.md:622\n#: ../../reference/operators.md:646 ../../reference/operators.md:670\n#: ../../reference/operators.md:695 ../../reference/operators.md:722\n#: ../../reference/operators.md:747 ../../reference/operators.md:772\n#: ../../reference/operators.md:796 ../../reference/operators.md:821\n#: ../../reference/operators.md:844 ../../reference/operators.md:868\n#: ../../reference/operators.md:886 ../../reference/operators.md:908\n#: ../../reference/operators.md:948 ../../reference/operators.md:972\n#: ../../reference/operators.md:986 ../../reference/operators.md:1002\n#: ../../reference/operators.md:1026 ../../reference/operators.md:1043\n#: ../../reference/operators.md:1056 ../../reference/operators.md:1069\n#: ../../reference/operators.md:1083 ../../reference/operators.md:1099\n#: ../../reference/operators.md:1114 ../../reference/operators.md:1131\n#: ../../reference/operators.md:1145 ../../reference/operators.md:1160\n#: ../../reference/operators.md:1176 ../../reference/operators.md:1192\n#: ../../reference/operators.md:1207 ../../reference/operators.md:1221\n#: ../../reference/operators.md:1245 ../../reference/operators.md:1267\n#: ../../reference/operators.md:1290 ../../reference/operators.md:1312\n#: ../../reference/operators.md:1334 ../../reference/operators.md:1356\n#: ../../reference/operators.md:1378 ../../reference/operators.md:1402\n#: ../../reference/operators.md:1427 ../../reference/operators.md:1442\n#: ../../reference/operators.md:1460 ../../reference/operators.md:1475\n#: ../../reference/operators.md:1488 ../../reference/operators.md:1503\n#: ../../reference/operators.md:1530 ../../reference/operators.md:1550\n#: ../../reference/operators.md:1570 ../../reference/operators.md:1590\n#: ../../reference/operators.md:1611 ../../reference/operators.md:1634\n#: ../../reference/operators.md:1660 ../../reference/operators.md:1677\n#: ../../reference/operators.md:1692 ../../reference/operators.md:1709\n#: ../../reference/operators.md:1740 ../../reference/operators.md:1761\n#: ../../reference/operators.md:1788 ../../reference/operators.md:1801\n#: ../../reference/operators.md:1823 ../../reference/operators.md:1842\n#: ../../reference/operators.md:1855 ../../reference/operators.md:1875\nmsgid \"**Outputs:**\"\nmsgstr \"**输出：**\"\n\n#: ../../reference/operators.md:16 ../../reference/operators.md:29\n#: ../../reference/operators.md:42 ../../reference/operators.md:71\n#: ../../reference/operators.md:206 ../../reference/operators.md:227\n#: ../../reference/operators.md:306 ../../reference/operators.md:319\n#: ../../reference/operators.md:332 ../../reference/operators.md:401\n#: ../../reference/operators.md:460 ../../reference/operators.md:822\n#: ../../reference/operators.md:1044 ../../reference/operators.md:1057\n#: ../../reference/operators.md:1070 ../../reference/operators.md:1489\n#: ../../reference/operators.md:1678 ../../reference/operators.md:1802\n#: ../../reference/operators.md:1843 ../../reference/operators.md:1856\nmsgid \"`Out`(single, T): Result\"\nmsgstr \"``Out`` （单列数组，类型为 T ）：结果 。\"\n\n#: ../../reference/operators.md:18 ../../reference/operators.md:31\n#: ../../reference/operators.md:44 ../../reference/operators.md:58\n#: ../../reference/operators.md:73 ../../reference/operators.md:87\n#: ../../reference/operators.md:113 ../../reference/operators.md:135\n#: ../../reference/operators.md:154 ../../reference/operators.md:179\n#: ../../reference/operators.md:195 ../../reference/operators.md:208\n#: ../../reference/operators.md:229 ../../reference/operators.md:255\n#: ../../reference/operators.md:278 ../../reference/operators.md:295\n#: ../../reference/operators.md:308 ../../reference/operators.md:321\n#: ../../reference/operators.md:334 ../../reference/operators.md:348\n#: ../../reference/operators.md:374 ../../reference/operators.md:388\n#: ../../reference/operators.md:403 ../../reference/operators.md:426\n#: ../../reference/operators.md:449 ../../reference/operators.md:462\n#: ../../reference/operators.md:476 ../../reference/operators.md:492\n#: ../../reference/operators.md:507 ../../reference/operators.md:529\n#: ../../reference/operators.md:553 ../../reference/operators.md:577\n#: ../../reference/operators.md:601 ../../reference/operators.md:625\n#: ../../reference/operators.md:649 ../../reference/operators.md:673\n#: ../../reference/operators.md:701 ../../reference/operators.md:725\n#: ../../reference/operators.md:750 ../../reference/operators.md:775\n#: ../../reference/operators.md:799 ../../reference/operators.md:824\n#: ../../reference/operators.md:857 ../../reference/operators.md:875\n#: ../../reference/operators.md:889 ../../reference/operators.md:911\n#: ../../reference/operators.md:961 ../../reference/operators.md:975\n#: ../../reference/operators.md:989 ../../reference/operators.md:1005\n#: ../../reference/operators.md:1033 ../../reference/operators.md:1046\n#: ../../reference/operators.md:1059 ../../reference/operators.md:1072\n#: ../../reference/operators.md:1086 ../../reference/operators.md:1102\n#: ../../reference/operators.md:1120 ../../reference/operators.md:1134\n#: ../../reference/operators.md:1148 ../../reference/operators.md:1163\n#: ../../reference/operators.md:1179 ../../reference/operators.md:1195\n#: ../../reference/operators.md:1210 ../../reference/operators.md:1224\n#: ../../reference/operators.md:1248 ../../reference/operators.md:1270\n#: ../../reference/operators.md:1293 ../../reference/operators.md:1315\n#: ../../reference/operators.md:1337 ../../reference/operators.md:1359\n#: ../../reference/operators.md:1381 ../../reference/operators.md:1408\n#: ../../reference/operators.md:1430 ../../reference/operators.md:1449\n#: ../../reference/operators.md:1463 ../../reference/operators.md:1478\n#: ../../reference/operators.md:1491 ../../reference/operators.md:1510\n#: ../../reference/operators.md:1533 ../../reference/operators.md:1553\n#: ../../reference/operators.md:1573 ../../reference/operators.md:1593\n#: ../../reference/operators.md:1617 ../../reference/operators.md:1637\n#: ../../reference/operators.md:1667 ../../reference/operators.md:1680\n#: ../../reference/operators.md:1699 ../../reference/operators.md:1716\n#: ../../reference/operators.md:1744 ../../reference/operators.md:1770\n#: ../../reference/operators.md:1791 ../../reference/operators.md:1804\n#: ../../reference/operators.md:1832 ../../reference/operators.md:1845\n#: ../../reference/operators.md:1858 ../../reference/operators.md:1878\nmsgid \"**TensorStatus(ShareType) Constraints:**\"\nmsgstr \"**Tensor 类型约束：**\"\n\n#: ../../reference/operators.md:19 ../../reference/operators.md:32\n#: ../../reference/operators.md:45 ../../reference/operators.md:59\n#: ../../reference/operators.md:74 ../../reference/operators.md:88\n#: ../../reference/operators.md:180 ../../reference/operators.md:196\n#: ../../reference/operators.md:209 ../../reference/operators.md:309\n#: ../../reference/operators.md:322 ../../reference/operators.md:335\n#: ../../reference/operators.md:349 ../../reference/operators.md:389\n#: ../../reference/operators.md:404 ../../reference/operators.md:463\n#: ../../reference/operators.md:477 ../../reference/operators.md:493\n#: ../../reference/operators.md:508 ../../reference/operators.md:800\n#: ../../reference/operators.md:890 ../../reference/operators.md:976\n#: ../../reference/operators.md:990 ../../reference/operators.md:1006\n#: ../../reference/operators.md:1034 ../../reference/operators.md:1047\n#: ../../reference/operators.md:1060 ../../reference/operators.md:1073\n#: ../../reference/operators.md:1087 ../../reference/operators.md:1103\n#: ../../reference/operators.md:1164 ../../reference/operators.md:1180\n#: ../../reference/operators.md:1196 ../../reference/operators.md:1211\n#: ../../reference/operators.md:1225 ../../reference/operators.md:1464\n#: ../../reference/operators.md:1492 ../../reference/operators.md:1681\n#: ../../reference/operators.md:1771 ../../reference/operators.md:1805\n#: ../../reference/operators.md:1846 ../../reference/operators.md:1859\nmsgid \"`T`: public,private,secret\"\nmsgstr \"``T`` ：公开，私有，密态\"\n\n#: ../../reference/operators.md:21\nmsgid \"`ASin`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:23\nmsgid \"Definition: return the value of arc sine function\"\nmsgstr \"定义：返回数据对应的 arc sine 值。\"\n\n#: ../../reference/operators.md:26\nmsgid \"`In`(single, T): the expression pass to arc sine function\"\nmsgstr \"``In`` （单列数组，类型为 T ）：arc sine 的入参 。\"\n\n#: ../../reference/operators.md:34\nmsgid \"`ATan`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:36\nmsgid \"Definition: return the value of arc tangent function\"\nmsgstr \"定义：返回数据对应的 arc tangent 值。\"\n\n#: ../../reference/operators.md:39\nmsgid \"`In`(single, T): the expression pass to arc tangent function\"\nmsgstr \"``In`` （单列数组，类型为 T ）：arc tangent 的入参 。\"\n\n#: ../../reference/operators.md:47\nmsgid \"`ATan2`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:49\nmsgid \"Definition: Out = Left `ATan2` Right\"\nmsgstr \"定义：对两个 tensor 进行 ATan2 运算， Out = (Left ATan2 Right) 。\"\n\n#: ../../reference/operators.md:52 ../../reference/operators.md:81\n#: ../../reference/operators.md:342 ../../reference/operators.md:382\n#: ../../reference/operators.md:470 ../../reference/operators.md:486\n#: ../../reference/operators.md:883 ../../reference/operators.md:983\n#: ../../reference/operators.md:999 ../../reference/operators.md:1080\n#: ../../reference/operators.md:1096 ../../reference/operators.md:1157\n#: ../../reference/operators.md:1173 ../../reference/operators.md:1189\n#: ../../reference/operators.md:1218 ../../reference/operators.md:1457\nmsgid \"`Left`(variadic, T): First operand.\"\nmsgstr \"``Left`` （多列数组，类型为 T ）： 第一个操作数。\"\n\n#: ../../reference/operators.md:53 ../../reference/operators.md:82\n#: ../../reference/operators.md:343 ../../reference/operators.md:383\n#: ../../reference/operators.md:471 ../../reference/operators.md:487\n#: ../../reference/operators.md:884 ../../reference/operators.md:984\n#: ../../reference/operators.md:1000 ../../reference/operators.md:1081\n#: ../../reference/operators.md:1097 ../../reference/operators.md:1158\n#: ../../reference/operators.md:1174 ../../reference/operators.md:1190\n#: ../../reference/operators.md:1219 ../../reference/operators.md:1458\nmsgid \"`Right`(variadic, T1): Second operand.\"\nmsgstr \"``Right`` （多列数组，类型为 T1 ）： 第二个操作数。\"\n\n#: ../../reference/operators.md:56 ../../reference/operators.md:85\n#: ../../reference/operators.md:346 ../../reference/operators.md:386\n#: ../../reference/operators.md:474 ../../reference/operators.md:490\n#: ../../reference/operators.md:887 ../../reference/operators.md:987\n#: ../../reference/operators.md:1003 ../../reference/operators.md:1084\n#: ../../reference/operators.md:1100 ../../reference/operators.md:1161\n#: ../../reference/operators.md:1177 ../../reference/operators.md:1193\n#: ../../reference/operators.md:1222 ../../reference/operators.md:1461\nmsgid \"`Out`(variadic, T2): Output Tensor.\"\nmsgstr \"``Out`` （多列数组，类型为 T2 ）：输出。 \"\n\n#: ../../reference/operators.md:60 ../../reference/operators.md:89\n#: ../../reference/operators.md:137 ../../reference/operators.md:181\n#: ../../reference/operators.md:350 ../../reference/operators.md:390\n#: ../../reference/operators.md:478 ../../reference/operators.md:494\n#: ../../reference/operators.md:801 ../../reference/operators.md:891\n#: ../../reference/operators.md:991 ../../reference/operators.md:1007\n#: ../../reference/operators.md:1088 ../../reference/operators.md:1104\n#: ../../reference/operators.md:1165 ../../reference/operators.md:1181\n#: ../../reference/operators.md:1197 ../../reference/operators.md:1226\n#: ../../reference/operators.md:1465\nmsgid \"`T1`: public,private,secret\"\nmsgstr \"``T1`` ：公开，私有，密态\"\n\n#: ../../reference/operators.md:61 ../../reference/operators.md:90\n#: ../../reference/operators.md:351 ../../reference/operators.md:391\n#: ../../reference/operators.md:479 ../../reference/operators.md:495\n#: ../../reference/operators.md:892 ../../reference/operators.md:992\n#: ../../reference/operators.md:1008 ../../reference/operators.md:1089\n#: ../../reference/operators.md:1105 ../../reference/operators.md:1166\n#: ../../reference/operators.md:1182 ../../reference/operators.md:1198\n#: ../../reference/operators.md:1227 ../../reference/operators.md:1466\nmsgid \"`T2`: private,secret\"\nmsgstr \"``T2`` ：公开，私有\"\n\n#: ../../reference/operators.md:63\nmsgid \"`Abs`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:65\nmsgid \"Definition: return the value of Abs function\"\nmsgstr \"定义：返回数据对应的绝对值\"\n\n#: ../../reference/operators.md:68\nmsgid \"`In`(single, T): the expression pass to Abs function\"\nmsgstr \"``In`` （单列数组，类型为 T） Abs 的入参。\"\n\n#: ../../reference/operators.md:76\nmsgid \"`Add`\"\nmsgstr \"``Add``\"\n\n#: ../../reference/operators.md:78\nmsgid \"Definition: Out = Left `Add` Right\"\nmsgstr \"定义：对两个 tensor 进行求和运算， Out = (Left + Right) 。\"\n\n#: ../../reference/operators.md:92\nmsgid \"`ArrowFunc`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:94\nmsgid \"Definition: Call arrow functions to finish calculation. Example:\"\nmsgstr \"定义：调用 arrow 内置函数完成计算。例如：\"\n\n#: ../../reference/operators.md:105\nmsgid \"`In`(variadic, T): Input tensors.\"\nmsgstr \"``In`` （多列数组，类型为 T1 ）：输入 tensor 。\"\n\n#: ../../reference/operators.md:108\nmsgid \"`Out`(variadic, T): Output tensors.\"\nmsgstr \"``Out`` （多列数组，类型为 T2 ）：输出 tensor 。\"\n\n#: ../../reference/operators.md:110 ../../reference/operators.md:151\n#: ../../reference/operators.md:249 ../../reference/operators.md:275\n#: ../../reference/operators.md:291 ../../reference/operators.md:363\n#: ../../reference/operators.md:698 ../../reference/operators.md:847\n#: ../../reference/operators.md:871 ../../reference/operators.md:952\n#: ../../reference/operators.md:1029 ../../reference/operators.md:1117\n#: ../../reference/operators.md:1405 ../../reference/operators.md:1445\n#: ../../reference/operators.md:1506 ../../reference/operators.md:1614\n#: ../../reference/operators.md:1664 ../../reference/operators.md:1695\n#: ../../reference/operators.md:1712 ../../reference/operators.md:1764\n#: ../../reference/operators.md:1826\nmsgid \"**Attributes:**\"\nmsgstr \"**属性：**\"\n\n#: ../../reference/operators.md:111\nmsgid \"`func_name`: the name of arrow function, e.g: add/ifnull/...\"\nmsgstr \"`func_name`:  arrow 内置函数名，例如：add/ifnull/...\"\n\n#: ../../reference/operators.md:114 ../../reference/operators.md:155\n#: ../../reference/operators.md:230 ../../reference/operators.md:375\n#: ../../reference/operators.md:450 ../../reference/operators.md:530\n#: ../../reference/operators.md:554 ../../reference/operators.md:578\n#: ../../reference/operators.md:602 ../../reference/operators.md:626\n#: ../../reference/operators.md:650 ../../reference/operators.md:674\n#: ../../reference/operators.md:702 ../../reference/operators.md:776\n#: ../../reference/operators.md:825 ../../reference/operators.md:858\n#: ../../reference/operators.md:876 ../../reference/operators.md:912\n#: ../../reference/operators.md:1450 ../../reference/operators.md:1479\n#: ../../reference/operators.md:1511 ../../reference/operators.md:1668\n#: ../../reference/operators.md:1700 ../../reference/operators.md:1717\n#: ../../reference/operators.md:1879\nmsgid \"`T`: private\"\nmsgstr \"``T`` ：私有\"\n\n#: ../../reference/operators.md:116\nmsgid \"`BroadcastTo`\"\nmsgstr \"`BroadcastTo`\"\n\n#: ../../reference/operators.md:118\n#, fuzzy\nmsgid \"\"\n\"Definition: Broadcast Input tensor `In` to the same shape as \"\n\"`ShapeRefTensor`. Example:\"\nmsgstr \"定义：根据参考 tensor ``ShapeRefTensor`` 的大小, 对输入的 tensor ``In`` 进行扩展。例如：\"\n\n#: ../../reference/operators.md:129\nmsgid \"`In`(variadic, T): Input tensor\"\nmsgstr \"``In`` （多列数组，类型为 T ）：输入 tensor 。\"\n\n#: ../../reference/operators.md:130\nmsgid \"`ShapeRefTensor`(single, T1): Shape reference tensor\"\nmsgstr \"``ShapeRefTensor`` （单列数组，类型为 T2 ）：参考的 tensor 。\"\n\n#: ../../reference/operators.md:133\nmsgid \"`Out`(variadic, T2): Result tensor\"\nmsgstr \"``Out`` （多列数组，类型为 T2 ）： 输出结果。\"\n\n#: ../../reference/operators.md:136\nmsgid \"`T`: public\"\nmsgstr \"``T`` ：公开\"\n\n#: ../../reference/operators.md:138\nmsgid \"`T2`: public,private\"\nmsgstr \"``T2`` ：公开，私有\"\n\n#: ../../reference/operators.md:140\nmsgid \"`Bucket`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:142\nmsgid \"\"\n\"Definition: Put the data into buckets based on the hash value of the join\"\n\" key.\"\nmsgstr \"根据 hash 值对数据进行分桶\"\n\n#: ../../reference/operators.md:145\nmsgid \"`Key`(variadic, T): Join Key Tensors\"\nmsgstr \"``In`` （多列数组，类型为 T ）：输入 Tensor 。\"\n\n#: ../../reference/operators.md:146 ../../reference/operators.md:1759\nmsgid \"`In`(variadic, T): Input Tensors\"\nmsgstr \"``In`` （多列数组，类型为 T ）：输入 Tensor 。\"\n\n#: ../../reference/operators.md:149\nmsgid \"`Out`(variadic, T): Result\"\nmsgstr \"``Out`` （多列数组，类型为 T2 ）： 输出结果。\"\n\n#: ../../reference/operators.md:152 ../../reference/operators.md:953\nmsgid \"\"\n\"`input_party_codes`: List of parties the inputs belong to([PartyCodeLeft,\"\n\" PartyCodeRight]).\"\nmsgstr \"``input_party_codes`` ：输入数据对应的参与方列表。\"\n\n#: ../../reference/operators.md:157\nmsgid \"`CaseWhen`\"\nmsgstr \"``CaseWhen``\"\n\n#: ../../reference/operators.md:159\nmsgid \"\"\n\"The CaseWhen operator goes through conditions and returns a value when \"\n\"the first condition is met (like an if-then-else statement)\"\nmsgstr \"CaseWhen 算子遍历 ``Condition`` 中的条件，并在遇到满足的第一个条件时返回对应值（类似于 if-then-else 语句）\"\n\n#: ../../reference/operators.md:161\nmsgid \"Example:\"\nmsgstr \"例子：\"\n\n#: ../../reference/operators.md:172\nmsgid \"`Condition`(variadic, T): Condition tensor.\"\nmsgstr \"``Condition`` （多列数组，类型为 T ）：条件 tensor 。\"\n\n#: ../../reference/operators.md:173\nmsgid \"\"\n\"`Value`(variadic, T1): Value if condition tensor is true and all previous\"\n\" conditions are false.\"\nmsgstr \"\"\n\"``Value`` （多列数组，类型为 T1）：如果 condition tensor 为真并且之前的所有 condition 都为假，则取该 \"\n\"Value 。\"\n\n#: ../../reference/operators.md:174\nmsgid \"`ValueElse`(single, T2): Value if all condition tensors are false.\"\nmsgstr \"``ValueElse`` （单列数组，类型为 T2）：当所有 condition tensors 都为假，则取 ValueElse 。\"\n\n#: ../../reference/operators.md:177 ../../reference/operators.md:797\nmsgid \"`Out`(single, T3): Result tensor.\"\nmsgstr \"``Out`` （单列数组，类型为 T3 ）：结果 tensor 。\"\n\n#: ../../reference/operators.md:182 ../../reference/operators.md:802\nmsgid \"`T2`: public,private,secret\"\nmsgstr \"``T2`` ：公开，私有，密态\"\n\n#: ../../reference/operators.md:183 ../../reference/operators.md:803\nmsgid \"`T3`: public,private,secret\"\nmsgstr \"``T3`` ：公开，私有，密态\"\n\n#: ../../reference/operators.md:185\nmsgid \"`Cast`\"\nmsgstr \"``Cast``\"\n\n#: ../../reference/operators.md:187\nmsgid \"Definition: Cast Input tensor's data type to Output tensor's.\"\nmsgstr \"定义：将输入 tensor 的数据类型转换为输出 tensor 的数据类型。\"\n\n#: ../../reference/operators.md:190 ../../reference/operators.md:906\n#: ../../reference/operators.md:1205\nmsgid \"`In`(single, T): Input tensor.\"\nmsgstr \"``In`` （单列数组，类型为 T ）：输入 tensor 。\"\n\n#: ../../reference/operators.md:193 ../../reference/operators.md:909\n#: ../../reference/operators.md:1208\nmsgid \"`Out`(single, T): Output tensor.\"\nmsgstr \"``Out`` （单列数组，类型为 T ）：输出 tensor 。\"\n\n#: ../../reference/operators.md:198\nmsgid \"`Ceil`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:200\nmsgid \"Definition: return the value of Ceil function\"\nmsgstr \"定义：返回数据对应的 Ceil 值\"\n\n#: ../../reference/operators.md:203\nmsgid \"`In`(single, T): the expression pass to Ceil function\"\nmsgstr \"``In`` （单列数组，类型为 T） Ceil 的入参 。\"\n\n#: ../../reference/operators.md:211\nmsgid \"`Coalesce`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:213\nmsgid \"\"\n\"Definition: Coalesce returns the first value of Exprs that is not NULL. \"\n\"NULL is returned only if Exprs are all NULL. Example:\"\nmsgstr \"定义： Coalesce 返回 Exprs 中第一个不为 NULL 的值， 只有 Exprs 全为 NULL 才会 返回 NULL\"\n\n#: ../../reference/operators.md:224\nmsgid \"`Exprs`(variadic, T): The expressions to coalesce\"\nmsgstr \"``Exprs`` （多列数组，类型为 T ）：coalesce 的参数 。\"\n\n#: ../../reference/operators.md:232\nmsgid \"`Concat`\"\nmsgstr \"``Concat``\"\n\n#: ../../reference/operators.md:234\nmsgid \"\"\n\"Definition: Given a number of tensors In (variadic, each tensor's shape \"\n\"must be the same in every dimension except for the axis), concat the In \"\n\"tensors along the axis. Example:\"\nmsgstr \"\"\n\"定义：给定一组 tensor ``In`` （多列数组，所有的 tensor 的大小在除了 axis 之外的所有维度上必须相同)，将它们在 \"\n\"axis 所指定的维度上进行拼接。例如：\"\n\n#: ../../reference/operators.md:244\nmsgid \"`In`(variadic, T): Tensors to be concat.\"\nmsgstr \"``In`` （多列数组，类型为 T ）：待拼接的 tensor 。\"\n\n#: ../../reference/operators.md:247\nmsgid \"`Out`(single, T): Concated Tensor.\"\nmsgstr \"``Out`` （单列数组，类型为 T ）：拼接后的 tensor 。\"\n\n#: ../../reference/operators.md:250\nmsgid \"`axis`: Int64. Dimension along which to concatenate.\"\nmsgstr \"``axis`` ： Int64 类型，待拼接的维度。\"\n\n#: ../../reference/operators.md:252 ../../reference/operators.md:369\n#: ../../reference/operators.md:853 ../../reference/operators.md:957\n#: ../../reference/operators.md:1767 ../../reference/operators.md:1829\nmsgid \"**Default Attribute Values:**\"\nmsgstr \"**默认值:**\"\n\n#: ../../reference/operators.md:253\nmsgid \"`axis`: 0\"\nmsgstr \"``axis`` : 0\"\n\n#: ../../reference/operators.md:256 ../../reference/operators.md:726\n#: ../../reference/operators.md:751 ../../reference/operators.md:1249\n#: ../../reference/operators.md:1271 ../../reference/operators.md:1316\n#: ../../reference/operators.md:1338 ../../reference/operators.md:1360\n#: ../../reference/operators.md:1382 ../../reference/operators.md:1409\n#: ../../reference/operators.md:1431 ../../reference/operators.md:1745\n#: ../../reference/operators.md:1792\nmsgid \"`T`: secret\"\nmsgstr \"``T`` ：私有\"\n\n#: ../../reference/operators.md:258\nmsgid \"`Constant`\"\nmsgstr \"``Constant``\"\n\n#: ../../reference/operators.md:260\nmsgid \"Definition: Make constant from attribute. Example:\"\nmsgstr \"定义：根据属性中的 ``scalar`` 和 ``to_status`` 参数生成对应的常量。例如：\"\n\n#: ../../reference/operators.md:269 ../../reference/operators.md:1706\n#, fuzzy\nmsgid \"**Inputs:** No input parameter.\"\nmsgstr \"无输入参数。\"\n\n#: ../../reference/operators.md:273\nmsgid \"`Out`(single, T): output tensor(shape [M]) from constant.\"\nmsgstr \"``Out`` （单列数组，类型为 T ）：生成的常量，大小为 [M] 。\"\n\n#: ../../reference/operators.md:276\nmsgid \"`scalar`: scalar attribute(with shape [M])\"\nmsgstr \"``scalar`` ：大小为 [M] 的标量。\"\n\n#: ../../reference/operators.md:279\nmsgid \"`T`: public,private\"\nmsgstr \"``T`` ：公共，私有\"\n\n#: ../../reference/operators.md:281\nmsgid \"`Copy`\"\nmsgstr \"``Copy``\"\n\n#: ../../reference/operators.md:283\nmsgid \"\"\n\"Definition: Copy source tensor \\\"In\\\" to new tensor \\\"Out\\\" on target \"\n\"party\"\nmsgstr \"定义：复制源 tensor 至目标 tensor 。\"\n\n#: ../../reference/operators.md:286\nmsgid \"`In`(single, T1): source tensor\"\nmsgstr \"``In`` （单列数组，类型为 T1 ）：源 tensor 。\"\n\n#: ../../reference/operators.md:289\nmsgid \"`Out`(single, T1): target tensor\"\nmsgstr \"``Out`` （单列数组，类型为 T1 ）：目标 tensor 。\"\n\n#: ../../reference/operators.md:292\nmsgid \"`input_party_codes`: Input tensor `In` belongs to\"\nmsgstr \"``input_party_codes``：输入 tensor ``In`` 的所属方。\"\n\n#: ../../reference/operators.md:293\nmsgid \"`output_party_codes`: Output tensor `Out` belongs to\"\nmsgstr \"``output_party_codes``：输出 tensor ``Out`` 的所属方。\"\n\n#: ../../reference/operators.md:296 ../../reference/operators.md:859\n#: ../../reference/operators.md:962 ../../reference/operators.md:1149\n#: ../../reference/operators.md:1772\nmsgid \"`T1`: private\"\nmsgstr \"``T1`` ：私有\"\n\n#: ../../reference/operators.md:298\nmsgid \"`Cos`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:300\nmsgid \"Definition: return the value of cosine function\"\nmsgstr \"定义：返回数据的 cosine 结果。\"\n\n#: ../../reference/operators.md:303\nmsgid \"`In`(single, T): the expression pass to cosine function\"\nmsgstr \"``In`` （单列数组，类型为 T cosine 的入参 。\"\n\n#: ../../reference/operators.md:311\nmsgid \"`Cot`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:313\nmsgid \"Definition: return the value of cotangent function\"\nmsgstr \"定义：返回数据的 cotangent 结果。\"\n\n#: ../../reference/operators.md:316\nmsgid \"`In`(single, T): the expression pass to cotangent function\"\nmsgstr \"``In`` （单列数组，类型为 T） cotangent 的入参 。\"\n\n#: ../../reference/operators.md:324\nmsgid \"`Degrees`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:326\nmsgid \"Definition: return the value of Degrees function\"\nmsgstr \"定义：返回数据的 Degrees 结果。\"\n\n#: ../../reference/operators.md:329\nmsgid \"`In`(single, T): the expression pass to Degrees function\"\nmsgstr \"``In`` （单列数组，类型为 T） Degrees 的入参。\"\n\n#: ../../reference/operators.md:337\nmsgid \"`Div`\"\nmsgstr \"``Div``\"\n\n#: ../../reference/operators.md:339\nmsgid \"Definition: Out = Left `Div` Right\"\nmsgstr \"定义：对两个 tensor 进行除法运算， Out = (Left / Right) 。\"\n\n#: ../../reference/operators.md:353\nmsgid \"`DumpFile`\"\nmsgstr \"`DumpFile`\"\n\n#: ../../reference/operators.md:355\nmsgid \"\"\n\"Definition: Dump the input tensor. Note: This op will change the affected\"\n\" rows in the session\"\nmsgstr \"定义：将输入的 tensor 存储到文件中。此操作将更改会话中受影响的行。\"\n\n#: ../../reference/operators.md:358\nmsgid \"`In`(variadic, T): Tensors to be dumped.\"\nmsgstr \"``In`` （多列数组，类型为 T ）：待存储的 tensor。\"\n\n#: ../../reference/operators.md:361\nmsgid \"`Out`(variadic, T): Tensors have been dumped.\"\nmsgstr \"``Out`` （多列数组，类型为 T ）： 已存储的 tensor。\"\n\n#: ../../reference/operators.md:364\nmsgid \"`file_path`: String. Absolute file path to dump the tensors.\"\nmsgstr \"``file_path`` ：字符串类型。用于存储 tensor 的绝对文件路径。\"\n\n#: ../../reference/operators.md:365\nmsgid \"`field_deliminator`: String. Column deliminator, e.g. `\\\\t`\"\nmsgstr \"``field_deliminator`` ：字符串类型。列分隔符，例如：`\\\\t`\"\n\n#: ../../reference/operators.md:366\nmsgid \"\"\n\"`quoting_style`: Int64. Strategies for using quotes, 0: do not use \"\n\"quotes; 1: use quotes for strings; 2: use quotes for all valid data\"\nmsgstr \"`quoting_style`：Int64 。使用引用的策略，0：不使用引用；1：对字符串类型使用引用；2：对所有有效数据使用引用\"\n\n#: ../../reference/operators.md:367\nmsgid \"`line_terminator`: String. Line terminator, e.g. `\\\\n`\"\nmsgstr \"``line_terminator`` ：字符串类型。列分隔符，例如：`\\\\n`\"\n\n#: ../../reference/operators.md:370\nmsgid \"`field_deliminator`: \\\\t\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:371\nmsgid \"`line_terminator`: \\\\n\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:372\nmsgid \"`quoting_style`: 0\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:377\nmsgid \"`Equal`\"\nmsgstr \"``Equal``\"\n\n#: ../../reference/operators.md:379\nmsgid \"Definition: Out = Left `Equal` Right\"\nmsgstr \"定义：对两个 tensor 进行比较运算， Out = (Left == Right) 。\"\n\n#: ../../reference/operators.md:393\nmsgid \"`Exp`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:395\nmsgid \"Definition: return the value of Exp function\"\nmsgstr \"定义：返回数据的 Exp 结果。\"\n\n#: ../../reference/operators.md:398\nmsgid \"`In`(single, T): the expression pass to Exp function\"\nmsgstr \"``In`` （单列数组，类型为 T） Exp 的入参。\"\n\n#: ../../reference/operators.md:406\nmsgid \"`Filter`\"\nmsgstr \"``Filter``\"\n\n#: ../../reference/operators.md:408\nmsgid \"\"\n\"Definition: Given a boolean tensor Filter (its shape is [M]), and a \"\n\"number of tensors In (variadic, each tensor's shape must be [M]), for i \"\n\"in [0, M-1], keep the In tensors' element if and only if Filter[i] is \"\n\"True, output the filter result tensors Out (variadic). Example:\"\nmsgstr \"\"\n\"定义：给定一个布尔类型的 tensors ``Filter`` (其大小为 [M] )，以及一个输入 tensor ``In`` （多列数组，每个\"\n\" tensor 的大小均为 [M] ）。仅当 Filter 中第 i 个元素为真时，保留 In 中第 i 个元素。例:\"\n\n#: ../../reference/operators.md:420\nmsgid \"`Filter`(single, T1): Filter tensor.\"\nmsgstr \"``Filter`` （单列数组，类型为 T1 ）：用来做筛选的 tensor 。\"\n\n#: ../../reference/operators.md:421\nmsgid \"`In`(variadic, T): Tensors to be filtered.\"\nmsgstr \"``In`` （多列数组，类型为 T ）：待筛选的 tensor 。\"\n\n#: ../../reference/operators.md:424 ../../reference/operators.md:1027\nmsgid \"`Out`(variadic, T): Output tensor.\"\nmsgstr \"``Out`` （多列数组，类型为 T ）：输出 tensor 。\"\n\n#: ../../reference/operators.md:427 ../../reference/operators.md:1294\n#: ../../reference/operators.md:1534 ../../reference/operators.md:1554\n#: ../../reference/operators.md:1574 ../../reference/operators.md:1594\n#: ../../reference/operators.md:1618 ../../reference/operators.md:1638\n#: ../../reference/operators.md:1833\nmsgid \"`T`: private,secret\"\nmsgstr \"``T`` ：私有，密态\"\n\n#: ../../reference/operators.md:428\nmsgid \"`T1`: public,private\"\nmsgstr \"``T1`` ：公开，私有\"\n\n#: ../../reference/operators.md:430\nmsgid \"`FilterByIndex`\"\nmsgstr \"``FilterByIndex``\"\n\n#: ../../reference/operators.md:432\nmsgid \"Definition: Filter by rows index. Example:\"\nmsgstr \"定义：按行索引筛选。例如：\"\n\n#: ../../reference/operators.md:443\nmsgid \"`RowsIndexFilter`(single, T): Rows index filter vector(shape [K][1]).\"\nmsgstr \"``RowsIndexFilter`` （单列数组，类型为 T ）：用于筛选的索引 tensor （大小为 [K][1] ）。\"\n\n#: ../../reference/operators.md:444\nmsgid \"`Data`(variadic, T): Input data tensor(shape [M][N]).\"\nmsgstr \"``Data`` （多列数组，类型为 T ）：待筛选的 tensor （大小为 [M][N] ）。\"\n\n#: ../../reference/operators.md:447\nmsgid \"`Out`(variadic, T): Output data tensor(shape [X][N]).\"\nmsgstr \"``Out`` （多列数组，类型为 T ）：输出结果 tensor （大小为 [X][N] ）。\"\n\n#: ../../reference/operators.md:452\nmsgid \"`Floor`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:454\nmsgid \"Definition: return the value of Floor function\"\nmsgstr \"定义：返回数据的 Floor 结果\"\n\n#: ../../reference/operators.md:457\nmsgid \"`In`(single, T): the expression pass to Floor function\"\nmsgstr \"``In`` （单列数组，类型为 T） Floor 的入参 。\"\n\n#: ../../reference/operators.md:465\nmsgid \"`Greater`\"\nmsgstr \"`Greater`\"\n\n#: ../../reference/operators.md:467\nmsgid \"Definition: Out = Left `Greater` Right\"\nmsgstr \"定义：对两个 tensor 进行比较运算， Out = (Left > Right) 。\"\n\n#: ../../reference/operators.md:481\nmsgid \"`GreaterEqual`\"\nmsgstr \"`GreaterEqual`\"\n\n#: ../../reference/operators.md:483\nmsgid \"Definition: Out = Left `GreaterEqual` Right\"\nmsgstr \"定义：对两个 tensor 进行比较运算， Out = (Left >= Right) 。\"\n\n#: ../../reference/operators.md:497\nmsgid \"`Greatest`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:499\nmsgid \"return the greatest value in the given expressions.\"\nmsgstr \"返回给定表达式中最大的值。\"\n\n#: ../../reference/operators.md:502\nmsgid \"`In`(variadic, T): expressions passed for getting greatest value\"\nmsgstr \"``In`` （多列数组，类型为 T ）：需要计算最大值的入参 。\"\n\n#: ../../reference/operators.md:505\nmsgid \"`Out`(variadic, T): greatest value\"\nmsgstr \"``Out`` （多列数组，类型为 T ）： 最大值结果。\"\n\n#: ../../reference/operators.md:510\nmsgid \"`Group`\"\nmsgstr \"`Group`\"\n\n#: ../../reference/operators.md:512\nmsgid \"\"\n\"Definition: Assign a group id(start from 0) for each input element. \"\n\"Example:\"\nmsgstr \"定义：为每个输入元素分配一个group id (从0开始)。例如：\"\n\n#: ../../reference/operators.md:523\nmsgid \"`Key`(variadic, T): input key tensors(shape [M][1]).\"\nmsgstr \"``Key`` （多列数组，类型为 T ）： group key （大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:526\nmsgid \"`GroupId`(single, T): group id vector(shape [M][1]).\"\nmsgstr \"``GroupId`` （单列数组，类型为 T ）： group id （大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:527\nmsgid \"`GroupNum`(single, T): number of groups vector(shape [1][1])\"\nmsgstr \"``GroupNum`` （单列数组，类型为 T ）： group 的数量（大小为 [1][1] ）。\"\n\n#: ../../reference/operators.md:532\nmsgid \"`GroupAvg`\"\nmsgstr \"``GroupAvg``\"\n\n#: ../../reference/operators.md:534 ../../reference/operators.md:558\n#: ../../reference/operators.md:582 ../../reference/operators.md:606\n#: ../../reference/operators.md:630 ../../reference/operators.md:654\n#: ../../reference/operators.md:756\nmsgid \"Definition: Aggregate `In` for each group. Example:\"\nmsgstr \"定义：聚合每个 group 的 ``In`` 。例如:\"\n\n#: ../../reference/operators.md:546 ../../reference/operators.md:570\n#: ../../reference/operators.md:594 ../../reference/operators.md:618\n#: ../../reference/operators.md:642 ../../reference/operators.md:666\n#: ../../reference/operators.md:691 ../../reference/operators.md:718\n#: ../../reference/operators.md:743 ../../reference/operators.md:768\nmsgid \"`GroupId`(single, T): Input group id vector(shape [M][1]).\"\nmsgstr \"``GroupId`` （单列数组，类型为 T ）： group id （大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:547 ../../reference/operators.md:571\n#: ../../reference/operators.md:595 ../../reference/operators.md:619\n#: ../../reference/operators.md:643 ../../reference/operators.md:667\n#: ../../reference/operators.md:692 ../../reference/operators.md:769\nmsgid \"`GroupNum`(single, T): Input number of groups vector(shape [1][1]).\"\nmsgstr \"``GroupNum`` （单列数组，类型为 T ）： group 的数量（大小为 [1][1] ）。\"\n\n#: ../../reference/operators.md:548 ../../reference/operators.md:572\n#: ../../reference/operators.md:596 ../../reference/operators.md:620\n#: ../../reference/operators.md:644 ../../reference/operators.md:668\n#: ../../reference/operators.md:693 ../../reference/operators.md:770\nmsgid \"`In`(variadic, T): Input data tensor(shape [M][1]).\"\nmsgstr \"``In`` （单列数组，类型为 T ）：输入数据 （大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:551 ../../reference/operators.md:575\n#: ../../reference/operators.md:599 ../../reference/operators.md:623\n#: ../../reference/operators.md:647 ../../reference/operators.md:671\n#: ../../reference/operators.md:696 ../../reference/operators.md:773\nmsgid \"\"\n\"`Out`(variadic, T): Output data tensors(shape [K][1], K equals to number \"\n\"of groups), Out[i] is the agg result for i-th group.\"\nmsgstr \"\"\n\"``Out`` （多列数组，类型为 T ）：计算结果（大小为 [K][1] ， K 等于 group 的个数）， Out[i] 是第 i 个 \"\n\"group 的聚合结果。\"\n\n#: ../../reference/operators.md:556\nmsgid \"`GroupCount`\"\nmsgstr \"``GroupCount``\"\n\n#: ../../reference/operators.md:580\nmsgid \"`GroupCountDistinct`\"\nmsgstr \"``GroupCountDistinct``\"\n\n#: ../../reference/operators.md:604\nmsgid \"`GroupFirstOf`\"\nmsgstr \"``GroupFirstOf``\"\n\n#: ../../reference/operators.md:628\nmsgid \"`GroupMax`\"\nmsgstr \"`GroupMax`\"\n\n#: ../../reference/operators.md:652\nmsgid \"`GroupMin`\"\nmsgstr \"`GroupMin`\"\n\n#: ../../reference/operators.md:676\n#, fuzzy\nmsgid \"`GroupPercentileDisc`\"\nmsgstr \"``GroupPercentileDisc``\"\n\n#: ../../reference/operators.md:678 ../../reference/operators.md:1386\n#, fuzzy\nmsgid \"\"\n\"Definition: find the value of given percentile of `In` for each group. \"\n\"Example:\"\nmsgstr \"定义：根据给定百分比，算出每个group的 `In`该位置的值 。例如:\"\n\n#: ../../reference/operators.md:699 ../../reference/operators.md:1406\n#: ../../reference/operators.md:1615\nmsgid \"\"\n\"`percent`: Float. The percentile to calculate the range of which is [0, \"\n\"1], 0 means the min one, 1 means the max one.\"\nmsgstr \"`percent`: float。取值在[0, 1]间，0表示取最小值，1表示取最大值。\"\n\n#: ../../reference/operators.md:704\n#, fuzzy\nmsgid \"`GroupSecretAvg`\"\nmsgstr \"``GroupAvg``\"\n\n#: ../../reference/operators.md:706\n#, fuzzy\nmsgid \"Definition: Calculate secret AVG for each group. Example:\"\nmsgstr \"定义：聚合每个 group 的 ``In`` 。例如:\"\n\n#: ../../reference/operators.md:719 ../../reference/operators.md:744\n#, fuzzy\nmsgid \"`GroupNum`(single, T1): Input number of groups vector(shape [1][1]).\"\nmsgstr \"``GroupNum`` （单列数组，类型为 T ）： group 的数量（大小为 [1][1] ）。\"\n\n#: ../../reference/operators.md:720 ../../reference/operators.md:745\nmsgid \"`In`(single, T): Input data tensor(shape [M][1]).\"\nmsgstr \"``In`` （单列数组，类型为 T ）：输入数据 （大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:723 ../../reference/operators.md:748\nmsgid \"\"\n\"`Out`(single, T): Output data tensors(shape [K][1], K equals to number of\"\n\" groups), Out[i] is the agg result for i-th group.\"\nmsgstr \"\"\n\"``Out`` （多列数组，类型为 T ）：计算结果（大小为 [K][1] ， K 等于 group 的个数）， Out[i] 是第 i 个 \"\n\"group 的聚合结果。\"\n\n#: ../../reference/operators.md:727 ../../reference/operators.md:752\n#, fuzzy\nmsgid \"`T1`: public\"\nmsgstr \"``T`` ：公开\"\n\n#: ../../reference/operators.md:729\n#, fuzzy\nmsgid \"`GroupSecretSum`\"\nmsgstr \"``GroupHeSum``\"\n\n#: ../../reference/operators.md:731\n#, fuzzy\nmsgid \"Definition: Calculate secret SUM for each group. Example:\"\nmsgstr \"定义：使用同态加密对每个 group 进行求合。例如:\"\n\n#: ../../reference/operators.md:754\nmsgid \"`GroupSum`\"\nmsgstr \"`GroupSum`\"\n\n#: ../../reference/operators.md:778\nmsgid \"`If`\"\nmsgstr \"`If`\"\n\n#: ../../reference/operators.md:780\nmsgid \"\"\n\"The IF operator returns a value if a condition is TRUE, or another value \"\n\"if a condition is FALSE. Example:\"\nmsgstr \"如果条件为 TRUE ，则 IF 算子返回一个值；如果条件为 FALSE ，则返回另一个值。\"\n\n#: ../../reference/operators.md:792\nmsgid \"`Condition`(single, T): Condition tensor.\"\nmsgstr \"``Condition`` （多列数组，类型为 T ）：条件 tensor 。\"\n\n#: ../../reference/operators.md:793\nmsgid \"`ValueIfTrue`(single, T1): Value if true tensor.\"\nmsgstr \"``Filter`` （单列数组，类型为 T1 ）：用来做筛选的 tensor 。\"\n\n#: ../../reference/operators.md:794\nmsgid \"`ValueIfFalse`(single, T2): Value if false tensor.\"\nmsgstr \"``ValueIfFalse`` （单列数组，类型为 T2）：当条件为假，则取 ValueIfFalse 。\"\n\n#: ../../reference/operators.md:805\nmsgid \"`IfNull`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:807\nmsgid \"\"\n\"Definition: If Expr is NULL, return AltValue. Otherwise, return Expr. \"\n\"Example:\"\nmsgstr \"定义：如果 Expr 为 NULL ，则返回 AltValue ，否则返回 Expr 。示例：\"\n\n#: ../../reference/operators.md:818\nmsgid \"`Expr`(single, T): The expression to test whether is NULL\"\nmsgstr \"`Expr` （单列数组，类型为 T ）：需要校验是否为 NULL 的表达式\"\n\n#: ../../reference/operators.md:819\nmsgid \"`AltValue`(single, T): The value to return if Expr is NULL\"\nmsgstr \"`AltValue` （单列数组，类型为 T ）：当 Expr 为 NULL 时返回的值\"\n\n#: ../../reference/operators.md:827\nmsgid \"`In`\"\nmsgstr \"`In`\"\n\n#: ../../reference/operators.md:829\nmsgid \"\"\n\"Definition: Given an input tensor Left (its shape is [M]), and another \"\n\"input tensor Right (its shape is [N]), check whether Left's element \"\n\"exists in Right's elements and output a boolean tensor Out (its shape is \"\n\"[M]). Left and Right must be the same type. Example:\"\nmsgstr \"\"\n\"定义：给定输入数组 Left ( 维度为 [M]) 和另一数组 Right ( 维度为 [N]) ，校验 Left 中的元素是否在 Right \"\n\"中存在，并输出布尔数组 Out (维度为 [M] )。 Left 和 Right 的类型必须相同。示例：\"\n\n#: ../../reference/operators.md:841\nmsgid \"`Left`(single, T): First operand.\"\nmsgstr \"``Left`` （单列数组 , 类型为 T ）： 第一个操作数。\"\n\n#: ../../reference/operators.md:842\nmsgid \"`Right`(single, T1): Second operand.\"\nmsgstr \"``Right`` （单列数组 , 类型为 T1 ）： 第二个操作数。\"\n\n#: ../../reference/operators.md:845\nmsgid \"`Out`(single, T): Output Tensor.\"\nmsgstr \"``Out`` （单列数组 , 类型为 T ）：输出结果，类型为布尔值。\"\n\n#: ../../reference/operators.md:848\nmsgid \"`in_type`: Int64. 0: PSI In, 1: Share In, 2: Local In\"\nmsgstr \"``in_type`` ： Int64 类型。 0: PSI In; 1: Share In; 2: Local In\"\n\n#: ../../reference/operators.md:849\nmsgid \"`psi_algorithm`: Int64. PSI Algorithm for In. 0: Auto, 1: Ecdh, 2: Oprf;\"\nmsgstr \"``psi_algorithm`` ： Int64 类型， In 算子使用的 PSI 算法，0: Auto; 1: Ecdh; 2: Oprf\"\n\n#: ../../reference/operators.md:850\nmsgid \"\"\n\"`input_party_codes`: List of parties the inputs belong to. This attribute\"\n\" is required if algorithm = PSI.\"\nmsgstr \"``input_party_codes`` ： 参与该操作的参与方的列表。如果采用 PSI 算法，则需要此属性。\"\n\n#: ../../reference/operators.md:851\nmsgid \"\"\n\"`reveal_to`: A party can see the result. This attribute is required if \"\n\"algorithm = PSI.\"\nmsgstr \"``reveal_to`` ：可以看到结果的参与方。如果采用 PSI 算法，则需要此属性。\"\n\n#: ../../reference/operators.md:854\nmsgid \"`in_type`: 0\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:855 ../../reference/operators.md:959\nmsgid \"`psi_algorithm`: 0\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:861\nmsgid \"`InsertTable`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:863\nmsgid \"\"\n\"Definition: Insert the input tensor to existing table in Database. Note: \"\n\"This op will change the affected rows in the session\"\nmsgstr \"定义：将输入 tensor 存储到数据库已存在的表中。此操作将更改 session 中受影响的行。\"\n\n#: ../../reference/operators.md:866\nmsgid \"`In`(variadic, T): Tensors to be inserted to DB table.\"\nmsgstr \"``In`` （多列数组，类型为 T ）：待存储到数据库的 tensor。\"\n\n#: ../../reference/operators.md:869\nmsgid \"`Out`(variadic, T): Tensors have been inserted to DB table.\"\nmsgstr \"``Out`` （多列数组，类型为 T ）： 已存储到数据库的 tensor。\"\n\n#: ../../reference/operators.md:872\nmsgid \"`table_name`: String. table to insert the tensors.\"\nmsgstr \"``table_name`` ：字符串类型。用于存储 tensor 的表名称。\"\n\n#: ../../reference/operators.md:873\nmsgid \"`column_names`: String array. column names of table.\"\nmsgstr \"``column_names`` ：字符串类型。表的列名。\"\n\n#: ../../reference/operators.md:878\nmsgid \"`IntDiv`\"\nmsgstr \"`IntDiv`\"\n\n#: ../../reference/operators.md:880\nmsgid \"Definition: Out = Left `IntDiv` Right\"\nmsgstr \"定义：对两个整数类型的 tensor 进行整形除法运算， Out = (Left / Right) 。\"\n\n#: ../../reference/operators.md:894\nmsgid \"`IsNull`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:896\nmsgid \"Definition: Test if Input tensor's data contains NULL. Example:\"\nmsgstr \"定义：测试输入 Tensor 是否含有 NULL。例子：\"\n\n#: ../../reference/operators.md:914\nmsgid \"`Join`\"\nmsgstr \"`Join`\"\n\n#: ../../reference/operators.md:916\nmsgid \"\"\n\"Definition: Create Join Index based on EQ-Join, return result's \"\n\"corresponding rows index in the original input. Example:\"\nmsgstr \"定义：基于 EQ-Join 对输入进行求交，返回回原始输入中与交集对应的索引值。例如：\"\n\n#: ../../reference/operators.md:945\nmsgid \"`Left`(single, T1): Left vector(shape [M][1])\"\nmsgstr \"``Left`` （单列数组 , 类型为 T1 ）：参与 join 操作的左侧输入（大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:946\nmsgid \"`Right`(single, T1): Right vector(shape [N][1])\"\nmsgstr \"``Right`` （单列数组 , 类型为 T1 ）：参与 join 操作的右侧输入（大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:949\n#, fuzzy\nmsgid \"\"\n\"`LeftJoinIndex`(optional, T2): Joined rows index for left vector(shape \"\n\"[K][1])\"\nmsgstr \"``LeftJoinIndex`` （单列数组 , 类型为 T2 ）：参与 join 操作的左侧输入的行索引。\"\n\n#: ../../reference/operators.md:950\n#, fuzzy\nmsgid \"\"\n\"`RightJoinIndex`(optional, T2): Joined rows index for right vector(shape \"\n\"[K][1])\"\nmsgstr \"``RightJoinIndex`` （单列数组 , 类型为 T2 ）：参与 join 操作的右侧输入的行索引。\"\n\n#: ../../reference/operators.md:954\nmsgid \"`join_type`: Int64. 0: inner join; 1: left join; 2: right join;\"\nmsgstr \"\"\n\"``join_type`` ： Int64 类型，join 算子的类型。 0: inner join; 1: left join; 2: \"\n\"right join;\"\n\n#: ../../reference/operators.md:955\nmsgid \"\"\n\"`psi_algorithm`: Choose PSI join algorithm, Int64. 0: Auto; 1: Ecdh; 2: \"\n\"Oprf;\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:958\nmsgid \"`join_type`: 0\"\nmsgstr \"``join_type`` : 0\"\n\n#: ../../reference/operators.md:963 ../../reference/operators.md:1122\nmsgid \"`T2`: private\"\nmsgstr \"``T2`` ：私有\"\n\n#: ../../reference/operators.md:965\nmsgid \"`Least`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:967\nmsgid \"return the least value in the given expressions.\"\nmsgstr \"返回给定表达式中的最小值。\"\n\n#: ../../reference/operators.md:970\nmsgid \"`In`(variadic, T): expressions passed for getting least value\"\nmsgstr \"``In`` （多列数组，类型为 T ）：需要计算最小值的入参 。\"\n\n#: ../../reference/operators.md:973\nmsgid \"`Out`(variadic, T): least value\"\nmsgstr \"``Out`` （多列数组，类型为 T2 ）： 最小值结果。\"\n\n#: ../../reference/operators.md:978\nmsgid \"`Less`\"\nmsgstr \"`Less`\"\n\n#: ../../reference/operators.md:980\nmsgid \"Definition: Out = Left `Less` Right\"\nmsgstr \"定义：对两个 tensor 进行比较运算， Out = (Left < Right) 。\"\n\n#: ../../reference/operators.md:994\nmsgid \"`LessEqual`\"\nmsgstr \"`LessEqual`\"\n\n#: ../../reference/operators.md:996\nmsgid \"Definition: Out = Left `LessEqual` Right\"\nmsgstr \"定义：对两个 tensor 进行比较运算， Out = (Left <= Right) 。\"\n\n#: ../../reference/operators.md:1010\nmsgid \"`Limit`\"\nmsgstr \"``Limit``\"\n\n#: ../../reference/operators.md:1012\nmsgid \"\"\n\"Limit return part of data, the amount of data depends on limit attr, the \"\n\"offset of data depends on offset attr. Example:\"\nmsgstr \"Limit 算子返回部分数据，数据量取决于 limit attr ，数据的起始位置取决于 offset attr 。 例子：\"\n\n#: ../../reference/operators.md:1024\nmsgid \"`In`(variadic, T): Tensors to be limited.\"\nmsgstr \"``In`` （多列数组，类型为 T ）：待 limit 的 tensor 。\"\n\n#: ../../reference/operators.md:1030\nmsgid \"`offset`: offset in limit\"\nmsgstr \"`offset`: limit 结果的起始位置\"\n\n#: ../../reference/operators.md:1031\nmsgid \"`count`: count in limit\"\nmsgstr \"`count`: limit 结果的数据量\"\n\n#: ../../reference/operators.md:1036\nmsgid \"`Ln`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1038\nmsgid \"Definition: return the value of Ln function\"\nmsgstr \"定义：返回数据对应的 Ln 结果值。\"\n\n#: ../../reference/operators.md:1041\nmsgid \"`In`(single, T): the expression pass to Ln function\"\nmsgstr \"``In`` （单列数组，类型为 T） Ln 的入参。\"\n\n#: ../../reference/operators.md:1049\nmsgid \"`Log10`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1051\nmsgid \"Definition: return the value of Log10 function\"\nmsgstr \"定义：返回数据对应的 Log10 结果值。\"\n\n#: ../../reference/operators.md:1054\nmsgid \"`In`(single, T): the expression pass to Log10 function\"\nmsgstr \"``In`` （单列数组，类型为 T） Log10 的入参 。\"\n\n#: ../../reference/operators.md:1062\nmsgid \"`Log2`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1064\nmsgid \"Definition: return the value of Log2 function\"\nmsgstr \"定义：返回数据对应的 Log2 结果值。\"\n\n#: ../../reference/operators.md:1067\nmsgid \"`In`(single, T): the expression pass to Log2 function\"\nmsgstr \"``In`` （单列数组，类型为 T） Log2 的入参 。\"\n\n#: ../../reference/operators.md:1075\nmsgid \"`LogicalAnd`\"\nmsgstr \"`LogicalAnd`\"\n\n#: ../../reference/operators.md:1077\nmsgid \"Definition: Out = Left `LogicalAnd` Right\"\nmsgstr \"定义：对两个 tensor 进行逻辑与运算， Out = (Left & Right) 。\"\n\n#: ../../reference/operators.md:1091\nmsgid \"`LogicalOr`\"\nmsgstr \"`LogicalOr`\"\n\n#: ../../reference/operators.md:1093\nmsgid \"Definition: Out = Left `LogicalOr` Right\"\nmsgstr \"定义：对两个 tensor 进行逻辑或运算， Out = (Left ｜ Right) 。\"\n\n#: ../../reference/operators.md:1107\nmsgid \"`MakePrivate`\"\nmsgstr \"`MakePrivate`\"\n\n#: ../../reference/operators.md:1109\nmsgid \"Definition: Convert In tensor from share status to private status.\"\nmsgstr \"定义：将 tensor 从秘态转换为私有状态。\"\n\n#: ../../reference/operators.md:1112 ../../reference/operators.md:1129\n#: ../../reference/operators.md:1143\nmsgid \"`In`(variadic, T1): Input tensors.\"\nmsgstr \"``In`` （多列数组，类型为 T1 ）：输入 tensor 。\"\n\n#: ../../reference/operators.md:1115 ../../reference/operators.md:1132\n#: ../../reference/operators.md:1146\nmsgid \"`Out`(variadic, T2): Output tensors.\"\nmsgstr \"``Out`` （多列数组，类型为 T2 ）：输出 tensor 。\"\n\n#: ../../reference/operators.md:1118\nmsgid \"\"\n\"`reveal_to`: List of parties to see the private data. If it is revealed \"\n\"to one party only, the other party also needs to run the op, but does not\"\n\" have an output. Only the reveal_to party gets the output.\"\nmsgstr \"\"\n\"``reveal_to`` ：可以获取结果的参与方列表。如果只有一方能获取结果，那么另一方也需要运行 ``MakePrivate`` \"\n\"操作，但它无法获取结果。只有被指定为 reveal_to 的参与方才能获取结果。\"\n\n#: ../../reference/operators.md:1121\nmsgid \"`T1`: secret,public\"\nmsgstr \"``T1`` ：秘态，公开\"\n\n#: ../../reference/operators.md:1124\nmsgid \"`MakePublic`\"\nmsgstr \"`MakePublic`\"\n\n#: ../../reference/operators.md:1126\nmsgid \"Definition: Convert In tensor from share/private status to public status.\"\nmsgstr \"定义：将 tensor 从私有或者秘态转变为公开状态。\"\n\n#: ../../reference/operators.md:1135\nmsgid \"`T1`: private,secret\"\nmsgstr \"``T1`` ：私有，密态\"\n\n#: ../../reference/operators.md:1136\nmsgid \"`T2`: public\"\nmsgstr \"`T2` ：公开\"\n\n#: ../../reference/operators.md:1138\nmsgid \"`MakeShare`\"\nmsgstr \"`MakeShare`\"\n\n#: ../../reference/operators.md:1140\nmsgid \"Definition: Convert In tensor from private status to share status.\"\nmsgstr \"定义：将 tensor 从私有态转变为秘态。\"\n\n#: ../../reference/operators.md:1150\nmsgid \"`T2`: secret\"\nmsgstr \"``T2`` : 密态\"\n\n#: ../../reference/operators.md:1152\nmsgid \"`Minus`\"\nmsgstr \"`Minus`\"\n\n#: ../../reference/operators.md:1154\nmsgid \"Definition: Out = Left `Minus` Right\"\nmsgstr \"定义：对两个 tensor 进行求最小值运算， Out = (Left ``Minus`` Right) 。\"\n\n#: ../../reference/operators.md:1168\nmsgid \"`Mod`\"\nmsgstr \"`Mod`\"\n\n#: ../../reference/operators.md:1170\nmsgid \"Definition: Out = Left `Mod` Right\"\nmsgstr \"定义：对两个 tensor 进行求余运算， Out = (Left % Right) 。\"\n\n#: ../../reference/operators.md:1184\nmsgid \"`Mul`\"\nmsgstr \"`Mul`\"\n\n#: ../../reference/operators.md:1186\nmsgid \"Definition: Out = Left `Mul` Right\"\nmsgstr \"定义：对两个 tensor 进行减法运算， Out = (Left - Right) 。\"\n\n#: ../../reference/operators.md:1200\nmsgid \"`Not`\"\nmsgstr \"`Not`\"\n\n#: ../../reference/operators.md:1202\nmsgid \"Definition:  Out = Not In\"\nmsgstr \"定义：对 tensor 进行逻辑非运算， Out = !In 。\"\n\n#: ../../reference/operators.md:1213\nmsgid \"`NotEqual`\"\nmsgstr \"`NotEqual`\"\n\n#: ../../reference/operators.md:1215\nmsgid \"Definition: Out = Left `NotEqual` Right\"\nmsgstr \"定义：对两个 tensor 进行比较运算， Out = (Left != Right) 。\"\n\n#: ../../reference/operators.md:1229\nmsgid \"`ObliviousGroupAvg`\"\nmsgstr \"`ObliviousGroupAvg`\"\n\n#: ../../reference/operators.md:1231 ../../reference/operators.md:1253\n#: ../../reference/operators.md:1298 ../../reference/operators.md:1320\n#: ../../reference/operators.md:1342 ../../reference/operators.md:1364\n#: ../../reference/operators.md:1413\nmsgid \"\"\n\"Definition: partially aggregate `In` according to end of group indicator.\"\n\" Example:\"\nmsgstr \"定义：根据 group mask 来对输入进行分组聚合。\"\n\n#: ../../reference/operators.md:1242 ../../reference/operators.md:1264\n#: ../../reference/operators.md:1291 ../../reference/operators.md:1309\n#: ../../reference/operators.md:1331 ../../reference/operators.md:1353\n#: ../../reference/operators.md:1375 ../../reference/operators.md:1399\n#: ../../reference/operators.md:1424\nmsgid \"\"\n\"`Group`(single, T): End of group indicator(shape [M][1]). Element 1 means\"\n\" the row is the last element of the group, 0 is not.\"\nmsgstr \"\"\n\"``Group`` （单列数组，类型为 T ）： groupMark （大小为 [M][1] ），其中 1 \"\n\"表示该位置的输入对应的元素是该分组中的最后一元素，0 则表示不是最后一个元素。\"\n\n#: ../../reference/operators.md:1243 ../../reference/operators.md:1265\n#: ../../reference/operators.md:1310 ../../reference/operators.md:1332\n#: ../../reference/operators.md:1354 ../../reference/operators.md:1376\n#: ../../reference/operators.md:1400 ../../reference/operators.md:1425\nmsgid \"`In`(variadic, T): Values to be aggregated (shape [M][1]).\"\nmsgstr \"``In`` （多列数组，类型为 T ）：待进行分组聚合的输入（大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:1246 ../../reference/operators.md:1268\n#: ../../reference/operators.md:1313 ../../reference/operators.md:1335\n#: ../../reference/operators.md:1357 ../../reference/operators.md:1379\n#: ../../reference/operators.md:1403 ../../reference/operators.md:1428\nmsgid \"`Out`(variadic, T): Partially aggregated values (shape [M][1]).\"\nmsgstr \"``Out`` （多列数组，类型为 T ）：分组聚合的结果（大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:1251\nmsgid \"`ObliviousGroupCount`\"\nmsgstr \"`ObliviousGroupCount`\"\n\n#: ../../reference/operators.md:1273\nmsgid \"`ObliviousGroupMark`\"\nmsgstr \"`ObliviousGroupMark`\"\n\n#: ../../reference/operators.md:1275\nmsgid \"\"\n\"Definition: generate end of group indicator `Group` based on `Key`. The \"\n\"operator calculates Group[i] = not_eq(Key[i+1], Key[i]). Example:\"\nmsgstr \"定义：根据输入的 key 生成一个 group ，group 的计算规则为 Group[i] = (Key[i+1] != Key[i] )。例如：\"\n\n#: ../../reference/operators.md:1288\nmsgid \"`Key`(variadic, T): Pre-sorted group keys (shape [M][1]).\"\nmsgstr \"``Key`` （多列数组，类型为 T ）：排序过的 group key 。\"\n\n#: ../../reference/operators.md:1296\nmsgid \"`ObliviousGroupMax`\"\nmsgstr \"`ObliviousGroupMax`\"\n\n#: ../../reference/operators.md:1318\nmsgid \"`ObliviousGroupMin`\"\nmsgstr \"`ObliviousGroupMin`\"\n\n#: ../../reference/operators.md:1340\nmsgid \"`ObliviousGroupSum`\"\nmsgstr \"`ObliviousGroupSum`\"\n\n#: ../../reference/operators.md:1362\nmsgid \"`ObliviousPercentRank`\"\nmsgstr \"`ObliviousPercentRank`\"\n\n#: ../../reference/operators.md:1384\n#, fuzzy\nmsgid \"`ObliviousPercentileDisc`\"\nmsgstr \"`ObliviousPercentileDisc`\"\n\n#: ../../reference/operators.md:1411\n#, fuzzy\nmsgid \"`ObliviousRank`\"\nmsgstr \"`ObliviousRank`\"\n\n#: ../../reference/operators.md:1433\nmsgid \"`PercentRank`\"\nmsgstr \"`PercentRank`\"\n\n#: ../../reference/operators.md:1435\nmsgid \"Definition: return the percent rank in each partition\"\nmsgstr \"定义：当前行占该分区的百分比\"\n\n#: ../../reference/operators.md:1438 ../../reference/operators.md:1499\n#: ../../reference/operators.md:1688\nmsgid \"\"\n\"`Key`(variadic, T): the tensors which used for sorting in partition, e.g.\"\n\" [2,0,4,2,3,7]\"\nmsgstr \"``Key`` （多列数组，类型为 T ）：用于分区的 tensors 。例如： [2,0,4,2,3,7]\"\n\n#: ../../reference/operators.md:1439 ../../reference/operators.md:1500\n#: ../../reference/operators.md:1689\nmsgid \"\"\n\"`PartitionId`(single, T): the partitioned id, e.g. [0,0,0,1,1,1], the \"\n\"first 3 in a group and the others are in another group\"\nmsgstr \"``PartitionId`` （单列数组，类型为 T ）：分区编号 。 例如： [0,0,0,1,1,1] ，前三个属于一组，其余的属于另一组。\"\n\n#: ../../reference/operators.md:1440 ../../reference/operators.md:1501\n#: ../../reference/operators.md:1690\nmsgid \"`PartitionNum`(single, T): the partitioned num, e.g. [2]\"\nmsgstr \"``PartitionNum`` （单列数组，类型为 T ）：总的分区数量， 例如： [2]\"\n\n#: ../../reference/operators.md:1443\nmsgid \"`Out`(single, T): percent rank output\"\nmsgstr \"``Out`` （单列数组，类型为 T ）：所占位置的百分比 。\"\n\n#: ../../reference/operators.md:1446 ../../reference/operators.md:1507\n#: ../../reference/operators.md:1696\n#, fuzzy\nmsgid \"\"\n\"`reverse`: string array consists of \\\"0\\\" and \\\"1\\\", \\\"0\\\" means this \"\n\"input tensor sort by ascending, \\\"1\\\" means this tensor sort by \"\n\"descending.  \\te.g. [\\\"0\\\",\\\"1\\\"] means the first input key sort by \"\n\"ascending, the second sort by descending\"\nmsgstr \"\"\n\"`reverse`: 由 \\\"0\\\" 和 \\\"1\\\" 组成的字符串数组， \\\"0\\\" 表示该输入 tensor 以升序排序， \\\"1\\\"  \"\n\"表示该输入 tensor 以降序排序。例如： [\\\"0\\\",\\\"1\\\"] 表示第一个输入 key 以升序排序，第二个输入 key 以降序排序。\"\n\n#: ../../reference/operators.md:1452\nmsgid \"`Pow`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1454\nmsgid \"Definition: Out = Left `Pow` Right\"\nmsgstr \"定义：Out = (Left `Pow` Right) 。\"\n\n#: ../../reference/operators.md:1468\nmsgid \"`Publish`\"\nmsgstr \"`Publish`\"\n\n#: ../../reference/operators.md:1470\nmsgid \"Definition: This operator publishes the DAG results.\"\nmsgstr \"定义：将输入的 tensor 进行披露。\"\n\n#: ../../reference/operators.md:1473\nmsgid \"`In`(variadic, T): Tensors to be published.\"\nmsgstr \"``In`` （多列数组，类型为 T ）：要披露的 Tensors 。\"\n\n#: ../../reference/operators.md:1476\nmsgid \"\"\n\"`Out`(variadic, T): Published name of input tensors. Tensors are in \"\n\"TensorOption VALUE.\"\nmsgstr \"``Out`` （多列数组，类型为 T ）：输入 tensors 的披露结果。 Tensors 位于 TensorOption VALUE 。\"\n\n#: ../../reference/operators.md:1481\nmsgid \"`Radians`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1483\nmsgid \"Definition: return the value of Radians function\"\nmsgstr \"定义：返回输入数据对应的 Radians 结果。\"\n\n#: ../../reference/operators.md:1486\nmsgid \"`In`(single, T): the expression pass to Radians function\"\nmsgstr \"``In`` （单列数组，类型为 T） Radians 的入参。\"\n\n#: ../../reference/operators.md:1494\n#, fuzzy\nmsgid \"`Rank`\"\nmsgstr \"`Rank`\"\n\n#: ../../reference/operators.md:1496\n#, fuzzy\nmsgid \"Definition: return the rank in each partition\"\nmsgstr \"定义：返回当前行在所在组的排序\"\n\n#: ../../reference/operators.md:1504\n#, fuzzy\nmsgid \"`Out`(single, T): rank output\"\nmsgstr \"``Out`` （单列数组，类型为 T ）：排序 。\"\n\n#: ../../reference/operators.md:1513\nmsgid \"`ReduceAvg`\"\nmsgstr \"`ReduceAvg`\"\n\n#: ../../reference/operators.md:1515\nmsgid \"\"\n\"Definition: Given a input tensor In, return the average of input tensor's\"\n\" elements. Example:\"\nmsgstr \"定义：给定一个输入 tensor ，返回输入 tensor 元素的平均值。例如：\"\n\n#: ../../reference/operators.md:1528 ../../reference/operators.md:1609\nmsgid \"`In`(single, T): Tensor to be reduced (shape [M]).\"\nmsgstr \"``In`` （单列数组 , 类型为 T ）：需要求平均的输入（大小为 [M] ）。\"\n\n#: ../../reference/operators.md:1531\nmsgid \"`Out`(single, T): The average Tensor (shape [1]).\"\nmsgstr \"``Out``  （单列数组 , 类型为 T ）：计算结果（大小为 [1] ）。\"\n\n#: ../../reference/operators.md:1536\nmsgid \"`ReduceCount`\"\nmsgstr \"`ReduceCount`\"\n\n#: ../../reference/operators.md:1538\nmsgid \"\"\n\"Definition: Given an input tensor In, return the count of input tensor's \"\n\"elements. Example:\"\nmsgstr \"定义：给定一个输入 tensor ，返回输入 tensor 元素的数量。例如：\"\n\n#: ../../reference/operators.md:1548\nmsgid \"`In`(single, T): Tensor to be counted (shape [M]).\"\nmsgstr \"``In`` （单列数组 , 类型为 T ）：需要计算元素数量的输入（大小为 [M] ）。\"\n\n#: ../../reference/operators.md:1551\nmsgid \"`Out`(single, T): The counted Tensor (shape [1]).\"\nmsgstr \"``Out`` （单列数组 , 类型为 T ）：计算结果（大小为 [1] ）。\"\n\n#: ../../reference/operators.md:1556\nmsgid \"`ReduceMax`\"\nmsgstr \"`ReduceMax`\"\n\n#: ../../reference/operators.md:1558\nmsgid \"\"\n\"Definition: Given a input tensor In, return the max of input tensor's \"\n\"elements. Example:\"\nmsgstr \"定义：给定一个输入 tensor ，返回输入 tensor 元素的最大值。例如：\"\n\n#: ../../reference/operators.md:1568\nmsgid \"`In`(single, T): Tensor to be maxed (shape [M]).\"\nmsgstr \"``In`` （单列数组 , 类型为 T ）：需要计算最大值的输入（大小为 [M] ）。\"\n\n#: ../../reference/operators.md:1571\nmsgid \"`Out`(single, T): The maxed Tensor (shape [1]).\"\nmsgstr \"``Out`` （单列数组 , 类型为 T ）：计算结果（大小为 [1] ）。\"\n\n#: ../../reference/operators.md:1576\nmsgid \"`ReduceMin`\"\nmsgstr \"`ReduceMin`\"\n\n#: ../../reference/operators.md:1578\nmsgid \"\"\n\"Definition: Given a input tensor In, return the min of input tensor's \"\n\"elements. Example:\"\nmsgstr \"定义：给定一个输入 tensor ，返回输入 tensor 元素的最小值。例如：\"\n\n#: ../../reference/operators.md:1588\nmsgid \"`In`(single, T): Tensor to be mined (shape [M]).\"\nmsgstr \"``In`` （单列数组 , 类型为 T ）：需要计算最小值的输入（大小为 [M] ）。\"\n\n#: ../../reference/operators.md:1591\nmsgid \"`Out`(single, T): The mined Tensor (shape [1]).\"\nmsgstr \"``Out`` （单列数组 , 类型为 T ）：计算结果（大小为 [1] ）。\"\n\n#: ../../reference/operators.md:1596\n#, fuzzy\nmsgid \"`ReducePercentileDisc`\"\nmsgstr \"`ReducePercentileDisc`\"\n\n#: ../../reference/operators.md:1598\n#, fuzzy\nmsgid \"\"\n\"Definition: Given a input tensor In, return the value of given percentile\"\n\" position. Example:\"\nmsgstr \"定义：给定一个输入 tensor ，返回输入 tensor 元素在给定百分比位置的值。例如：\"\n\n#: ../../reference/operators.md:1612\n#, fuzzy\nmsgid \"`Out`(single, T): The value of given percentile position(shape [1]).\"\nmsgstr \"``Out``  （单列数组 , 类型为 T ）：计算结果（大小为 [1] ）。\"\n\n#: ../../reference/operators.md:1620\nmsgid \"`ReduceSum`\"\nmsgstr \"`ReduceSum`\"\n\n#: ../../reference/operators.md:1622\nmsgid \"\"\n\"Definition: Given an input tensor In, return the sum of input tensor's \"\n\"elements. Example:\"\nmsgstr \"定义：给定一个输入 tensor ，返回输入 tensor 元素的总和。例如：\"\n\n#: ../../reference/operators.md:1632\nmsgid \"`In`(single, T): Tensor to be summed (shape [M]).\"\nmsgstr \"``In`` （单列数组 , 类型为 T ）：要求和的输入（大小为 [M] ）。\"\n\n#: ../../reference/operators.md:1635\nmsgid \"`Out`(single, T): The summed Tensor (shape [1]).\"\nmsgstr \"``Out`` （单列数组 , 类型为 T ）：计算结果（大小为 [1] ）。\"\n\n#: ../../reference/operators.md:1640\nmsgid \"`Replicate`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1642\nmsgid \"\"\n\"Replicate the Left with a given scale (rows of Right[0]) in interleaving \"\n\"way, when sending to the left party. And replicate the Right with a given\"\n\" scale (rows of Left[0]) in non-interleaving way, when sending to the \"\n\"right party. Output the replication result Out. Example:\"\nmsgstr \"获取 Left 和 Right 的笛卡尔积：以交错的方式复制 Left， 以非交错的方式复制 Right。输出结果为 Out。例如：\"\n\n#: ../../reference/operators.md:1657\nmsgid \"`Left`(variadic, T): Left tensors to be replicated.\"\nmsgstr \"``Left`` （多列数组，类型为 T ）：待复制的 Left tensors 。\"\n\n#: ../../reference/operators.md:1658\nmsgid \"`Right`(variadic, T): Right tensors to be replicated.\"\nmsgstr \"``Right`` （多列数组，类型为 T ）：待复制的 Right tensors 。\"\n\n#: ../../reference/operators.md:1661\nmsgid \"`LeftOut`(variadic, T): Left Output tensors.\"\nmsgstr \"``LeftOut`` （多列数组，类型为 T ）：Left tensors 复制后的结果 。\"\n\n#: ../../reference/operators.md:1662\nmsgid \"`RightOut`(variadic, T): Right Output tensors.\"\nmsgstr \"``RightOut`` （多列数组，类型为 T2 ）：Right tensors 复制后的结果。\"\n\n#: ../../reference/operators.md:1665\nmsgid \"\"\n\"`input_party_codes`: List of parties the inputs belong to([PartyCodeLeft,\"\n\" PartyCodeRight])\"\nmsgstr \"``input_party_codes`` ：输入数据对应的参与方列表。\"\n\n#: ../../reference/operators.md:1670\nmsgid \"`Round`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1672\nmsgid \"Definition: return the value of Round function\"\nmsgstr \"定义：返回输入数据对应的 Round 结果\"\n\n#: ../../reference/operators.md:1675\nmsgid \"`In`(single, T): the expression pass to Round function\"\nmsgstr \"``In`` （单列数组，类型为 T） Round 的入参 。\"\n\n#: ../../reference/operators.md:1683\nmsgid \"`RowNumber`\"\nmsgstr \"`RowNumber`\"\n\n#: ../../reference/operators.md:1685\nmsgid \"Definition: return the row number in each partition\"\nmsgstr \"定义：返回每个分区的行号\"\n\n#: ../../reference/operators.md:1693\nmsgid \"`Out`(single, T): row number output\"\nmsgstr \"``Out`` （单列数组，类型为 T ）：输出的行号，例如： [2,1,3,1,2,3]\"\n\n#: ../../reference/operators.md:1702\nmsgid \"`RunSQL`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1704\nmsgid \"\"\n\"Definition: Run a SQL statement and return a list of tensors in private \"\n\"status\"\nmsgstr \"定义：运行 SQL 语句并返回私有态的结果\"\n\n#: ../../reference/operators.md:1710\nmsgid \"`Out`(variadic, T): Result tensors of the SQL statement.\"\nmsgstr \"``Out`` （多列数组，类型为 T ）： SQL 语句的执行结果。\"\n\n#: ../../reference/operators.md:1713\nmsgid \"`sql`: SQL statement\"\nmsgstr \"``sql`` ：SQL 语句\"\n\n#: ../../reference/operators.md:1714\nmsgid \"`table_refs`: tables referenced by query\"\nmsgstr \"``table_refs`` ：SQL 语句中所引用的表格。\"\n\n#: ../../reference/operators.md:1719\nmsgid \"`SecretJoin`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1721\nmsgid \"\"\n\"Definition: inner join the left and right payloads based on the left and \"\n\"right keys. Example:\"\nmsgstr \"定义：根据 left 和 right keys \"\n\n#: ../../reference/operators.md:1735\nmsgid \"`LeftKey`(variadic, T): Left keys for join\"\nmsgstr \"``LeftKey`` （多列数组，类型为 T）：拼接的 Left keys 。\"\n\n#: ../../reference/operators.md:1736\nmsgid \"`RightKey`(variadic, T): Right keys for join\"\nmsgstr \"``RightKey`` （多列数组，类型为 T）：拼接的 Right keys 。\"\n\n#: ../../reference/operators.md:1737\n#, fuzzy\nmsgid \"`Left`(optional, T): Left payloads for join\"\nmsgstr \"``Left`` （多列数组，类型为 T ）： 拼接的 Left payloads。\"\n\n#: ../../reference/operators.md:1738\n#, fuzzy\nmsgid \"`Right`(optional, T): Right payloads for join\"\nmsgstr \"``Right`` （多列数组，类型为 T ）： 拼接的 Right payloads。\"\n\n#: ../../reference/operators.md:1741\n#, fuzzy\nmsgid \"`LeftOutput`(optional, T): Left payloads after join\"\nmsgstr \"``LeftOutput`` （多列数组，类型为 T ）： Left payloads 拼接后的输出。\"\n\n#: ../../reference/operators.md:1742\n#, fuzzy\nmsgid \"`RightOutput`(optional, T): Right payloads after join\"\nmsgstr \"``RightOutput`` （多列数组，类型为 T ）： Right payloads 拼接后的输出。\"\n\n#: ../../reference/operators.md:1747\nmsgid \"`Shape`\"\nmsgstr \"`Shape`\"\n\n#: ../../reference/operators.md:1749\nmsgid \"\"\n\"Definition: Given tensors In, return shapes of each tensor. Axis starts \"\n\"from 0. If axis is set, dimensions of each shape are returned. If axis is\"\n\" not set(default -1), shapes are returned. Example:\"\nmsgstr \"\"\n\"定义：从维度 0 开始计算 tensor 在各个维度的大小，如果设置了 Axis，则返回 Axis 所指定的维度上的大小，否则 ( Axis \"\n\"默认为 -1)，则返回 tensor 在所有维度上的大小。例如：\"\n\n#: ../../reference/operators.md:1762\nmsgid \"`Out`(variadic, T1): Shape Tensors\"\nmsgstr \"``Out`` （多列数组，类型为 T1 ）： Tensor 在各个维度上的大小。\"\n\n#: ../../reference/operators.md:1765\nmsgid \"`axis`: Int64. Specific dimension of the shape.\"\nmsgstr \"``axis`` ： Int64 类型，特定的维度。\"\n\n#: ../../reference/operators.md:1768\nmsgid \"`axis`: -1\"\nmsgstr \"``axis`` : -1\"\n\n#: ../../reference/operators.md:1774\nmsgid \"`Shuffle`\"\nmsgstr \"`Shuffle`\"\n\n#: ../../reference/operators.md:1776\nmsgid \"Definition: Shuffle `In`. Example:\"\nmsgstr \"定义：将输入 tensor 的顺序进行随机打乱。例如：\"\n\n#: ../../reference/operators.md:1786\nmsgid \"`In`(variadic, T): Input Value(shape [M][1]).\"\nmsgstr \"``In`` （多列数组，类型为 T ）：输入 Tensor （大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:1789\nmsgid \"`Out`(variadic, T): Output Value(shape [M][1])\"\nmsgstr \"``Out`` （多列数组，类型为 T ）：输出 Tensor （大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:1794\nmsgid \"`Sin`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1796\nmsgid \"Definition: return the value of sine function\"\nmsgstr \"定义：返回数据的 sine 结果\"\n\n#: ../../reference/operators.md:1799\nmsgid \"`In`(single, T): the expression pass to sine function\"\nmsgstr \"``In`` （单列数组，类型为 T sine 的入参。\"\n\n#: ../../reference/operators.md:1807\nmsgid \"`Sort`\"\nmsgstr \"`Sort`\"\n\n#: ../../reference/operators.md:1809\nmsgid \"Definition: sort `In` using `Key`. Example:\"\nmsgstr \"定义：根据排序键 ``Key`` 对输入 ``In`` 中的元素进行排序。例如：\"\n\n#: ../../reference/operators.md:1820\nmsgid \"`Key`(variadic, T): Sort Key(shape [M][1]).\"\nmsgstr \"``Key`` （多列数组，类型为 T ）：排序键（大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:1821\nmsgid \"`In`(variadic, T): Sort Value(shape [M][1]).\"\nmsgstr \"``In`` （多列数组，类型为 T ）：所需排序的输入（大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:1824\nmsgid \"`Out`(variadic, T): Sorted Value(shape [M][1])\"\nmsgstr \"``Out`` （多列数组，类型为 T ）：排序后的结果（大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:1827\nmsgid \"`reverse`: Bool. If True, the sorted tensor in descending order.\"\nmsgstr \"``reverse`` : 布尔类型, 如果为 True ，则表示按照从大到小的顺序进行排序。\"\n\n#: ../../reference/operators.md:1830\nmsgid \"`reverse`: false\"\nmsgstr \"``reverse`` : false\"\n\n#: ../../reference/operators.md:1835\nmsgid \"`Sqrt`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1837\nmsgid \"Definition: return the value of Sqrt function\"\nmsgstr \"定义：返回数据的 Sqrt 结果\"\n\n#: ../../reference/operators.md:1840\nmsgid \"`In`(single, T): the expression pass to Sqrt function\"\nmsgstr \"``In`` （单列数组，类型为 T） Sqrt 的入参。\"\n\n#: ../../reference/operators.md:1848\nmsgid \"`Tan`\"\nmsgstr \"\"\n\n#: ../../reference/operators.md:1850\nmsgid \"Definition: return the value of tangent function\"\nmsgstr \"定义：返回数据的 tangent 结果\"\n\n#: ../../reference/operators.md:1853\nmsgid \"`In`(single, T): the expression pass to tangent function\"\nmsgstr \"``In`` （单列数组，类型为 T） tangent 的入参。\"\n\n#: ../../reference/operators.md:1861\nmsgid \"`Unique`\"\nmsgstr \"``Unique``\"\n\n#: ../../reference/operators.md:1863\nmsgid \"Definition: Unique of Key tensor. Example:\"\nmsgstr \"定义：获取输入 tensor 中唯一元素。例如：\"\n\n#: ../../reference/operators.md:1873\nmsgid \"`Key`(single, T): Input key tensors(shape [M][1]).\"\nmsgstr \"``Key`` （单列数组，类型为 T ）：输入 tensor （大小为 [M][1] ）。\"\n\n#: ../../reference/operators.md:1876\nmsgid \"`UniqueKey`(single, T): Output unique key tensor(shape [K][1]).\"\nmsgstr \"``UniqueKey`` （单列数组，类型为 T ）：输出结果（大小为 [K][1] ）。\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/topics/faq.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-25 15:35+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../topics/faq.rst:2\nmsgid \"Frequently Asked Questions (FAQ)\"\nmsgstr \"常见问题汇总（FAQ）\"\n\n#: ../../topics/faq.rst:4\nmsgid \"\"\n\"We will collect some popular questions from users and update this part \"\n\"promptly.\"\nmsgstr \"这里收集了使用 SCQL 常见的问题，并持续更新。\"\n\n#: ../../topics/faq.rst:7\nmsgid \"Deploy Issues\"\nmsgstr \"部署相关问题\"\n\n#: ../../topics/faq.rst:9\nmsgid \"**Q**: System/CPU architectures supported by SCQL\"\nmsgstr \"**Q**: SCQL 支持的系统/CPU架构\"\n\n#: ../../topics/faq.rst:11\nmsgid \"\"\n\"System: Supports Linux and macOS with M-series chips (but macOS requires \"\n\"self-verification). CPU architectures: ARM and x86-64\"\nmsgstr \"系统：支持 linux 和 macOS（macOS 需要自行验证）。CPU架构：支持 ARM 和 x86-64\"\n\n#: ../../topics/faq.rst:13\nmsgid \"**Q**: Network timeout when pulling Go packages/GitHub packages\"\nmsgstr \"**Q**: 拉取 go 包/ GitHub 包超时\"\n\n#: ../../topics/faq.rst:15\nmsgid \"Add an appropriate GOPROXY\"\nmsgstr \"添加合适的 GOPROXY\"\n\n#: ../../topics/faq.rst:17\nmsgid \"**Q**: Does SCQL support outsourcing computation\"\nmsgstr \"**Q**: SCQL 是否支持外包计算\"\n\n#: ../../topics/faq.rst:19\nmsgid \"Not supported for now\"\nmsgstr \"目前还不支持\"\n\n#: ../../topics/faq.rst:22\nmsgid \"Project Preparation Issues\"\nmsgstr \"项目准备相关问题\"\n\n#: ../../topics/faq.rst:24\nmsgid \"**Q**: What is the data scale supported by SCQL?\"\nmsgstr \"**Q**: SCQL 支持多大的数据规模？\"\n\n#: ../../topics/faq.rst:26\nmsgid \"\"\n\"The data scale supported by SCQL is mainly limited by resource \"\n\"configurations (such as network, memory, etc.) and the complexity of the \"\n\"query. With sufficient memory, SCQL can support intersection tasks at the\"\n\" scale of billions. For more detailed scenarios, a benchmark test based \"\n\"on the available resources is needed to determine the exact capacity.\"\nmsgstr \"\"\n\"SCQL 支持的数据规模主要受到资源配置（如网络、内存等）和 query 的复杂度的影响。内存充足的情况下，SCQL \"\n\"可以支持十亿级别的数据规模。更加详细的场景，需要基于实际的资源配置进行性能测试来确定。\"\n\n#: ../../topics/faq.rst:28\nmsgid \"**Q**: How many participating parties does SCQL support?\"\nmsgstr \"**Q**: SCQL 支持多少参与方？\"\n\n#: ../../topics/faq.rst:30\nmsgid \"\"\n\"SCQL does not have a limit on the number of participating parties in a \"\n\"project, but the number of parties that can simultaneously participate in\"\n\" computations is restricted based on the secure computation protocols \"\n\"used. Specifically, CHEETAH supports only two parties, ABY3 supports only\"\n\" three parties, and SEMI2K supports any number of participating parties.\"\nmsgstr \"\"\n\"SCQL 不限制一个项目中参与方数量，但是同时参与计算的参与方数量受到使用的安全计算协议的影响。例如，CHEETAH 只支持两个参与方，ABY3 \"\n\"只支持三个参与方，SEMI2K 支持任意数量的参与方。\"\n\n#: ../../topics/faq.rst:32\nmsgid \"**Q**: Which syntax does SCQL support?\"\nmsgstr \"**Q**: SCQL 支持哪些 SQL 语法\"\n\n#: ../../topics/faq.rst:34\nmsgid \"\"\n\"SCQL is compatible with MySQL syntax. For specific details, please refer \"\n\"to the documentation. For differences from MySQL syntax, please also \"\n\"refer to :doc:`/reference/lang/manual`.\"\nmsgstr \"\"\n\"SCQL 兼容 MySQL 语法，具体细节请参考文档。对于与 MySQL 语法的差异，请参考 \"\n\":doc:`/reference/lang/manual`。\"\n\n#: ../../topics/faq.rst:36\nmsgid \"**Q**: What data sources does the engine support?\"\nmsgstr \"**Q**: 引擎支持哪些数据源？\"\n\n#: ../../topics/faq.rst:38\nmsgid \"SCQL directly supports the following data sources:\"\nmsgstr \"SCQL 支持下面这些数据源：\"\n\n#: ../../topics/faq.rst:40\nmsgid \"CSV (including local files, OSS, Minio)\"\nmsgstr \"CSV（包括本地文件、OSS、Minio）\"\n\n#: ../../topics/faq.rst:41\nmsgid \"MySQL and databases compatible with the MySQL protocol\"\nmsgstr \"MySQL 和兼容 MySQL 协议的数据库\"\n\n#: ../../topics/faq.rst:42\nmsgid \"Postgres\"\nmsgstr \"Postgres\"\n\n#: ../../topics/faq.rst:44\nmsgid \"SCQL can be extended to support the following data sources:\"\nmsgstr \"SCQL 可以扩展支持下列数据源：\"\n\n#: ../../topics/faq.rst:46\nmsgid \"\"\n\"On Kuscia, additional support for ODPS. **NOTE:** When using Kuscia, \"\n\"users can register data source information (such as CSV file locations, \"\n\"database connection string of MySQL and Postgres) in Kuscia DomainData. \"\n\"SCQL can then access this information through Kuscia Datamesh and process\"\n\" it accordingly.\"\nmsgstr \"\"\n\"在 Kuscia 中运行的时候，可以扩展支持 ODPS 数据源。**NOTE:** 在 Kuscia 中运行的时候，用户可以在 Kuscia \"\n\"DomainData 中注册数据源信息（比如 CSV 文件位置，MySQL 和 Postgres 数据库链接串）。SCQL 可以通过 \"\n\"DataMesh 获取注册到 Kuscia 的信息\"\n\n#: ../../topics/faq.rst:47\nmsgid \"\"\n\"SCQL supports the Arrow SQL client, and users can implement their own \"\n\"data sources by providing an Arrow SQL server\"\nmsgstr \"SCQL 支持 Arrow SQL client，用户可以自行实现 Arrow SQL server，作为提供给 SCQL 的数据源\"\n\n#: ../../topics/faq.rst:50\nmsgid \"Errors Occurred During Execution\"\nmsgstr \"运行时报错\"\n\n#: ../../topics/faq.rst:52\nmsgid \"**Q**: The engine reported a \\\"Get data timeout\\\" error during execution.\"\nmsgstr \"**Q**: engine 执行时上报 \\\"Get data timeout\\\" 错误\"\n\n#: ../../topics/faq.rst:54\n#, fuzzy\nmsgid \"\"\n\"It is necessary to troubleshoot based on the specific situation, whether \"\n\"the request was intercepted by the gateway, or if there was an error in \"\n\"the execution of the engine on the other side. It could also be due to \"\n\"poor network conditions. If the issue is caused by poor network \"\n\"conditions, you can alleviate this error by modifying the relevant \"\n\"network configuration. Please refer to ``examples/opencore-demo/`` for \"\n\"configuration examples and :doc:`/reference/engine-config` for detailed \"\n\"settings.\"\nmsgstr \"\"\n\"需要根据具体的场景来分析，可能是被网关拦截了，或者对方引擎执行出错了，也有可能是因为网络条件不好导致数据传输超时。如果是网络条件不好导致的错误，可以通过修改配置来缓解这个问题，具体配置可以参考\"\n\" :doc:`/reference/engine-config`。\"\n\n#: ../../topics/faq.rst:56\nmsgid \"\"\n\"**Q**: SCQL results from executing group by related syntax are incomplete\"\n\" or do not match the MySQL results?\"\nmsgstr \"**Q**: SCQL 执行 group by 相关语法的结果不完整或者和 MySQL 结果不一致？\"\n\n#: ../../topics/faq.rst:58\n#, fuzzy\nmsgid \"\"\n\"SCQL, to protect data privacy and prevent the malicious theft of data \"\n\"within groups, hides groups where the number of data items within a group\"\n\" is less than the GroupByThreshold. For specific details, please refer to\"\n\" ``examples/opencore-demo/`` for configuration examples and \"\n\":doc:`/reference/compiler-config` for the ``groupby_threshold`` \"\n\"configuration option (by default, groups with fewer than 4 data items are\"\n\" not displayed). Setting this value to 1 will disable the group filtering\"\n\" operation.\"\nmsgstr \"\"\n\"SCQL 为了保护隐私数据避免被恶意偷取，会过滤掉组内数据项数量小于 GroupByThreshold 的组。具体可以参考 \"\n\":doc:`/reference/compiler-config` 的 groupby_threshold 配置，默认会将 group \"\n\"内部元素数量小于 4 的 group 过滤掉。将该值设置为 1 可以关闭过滤操作。\"\n\n#: ../../topics/faq.rst:60\nmsgid \"**Q**: There are precision errors in the numerical calculations.\"\nmsgstr \"**Q**: 计算过程中出现数值误差？\"\n\n#: ../../topics/faq.rst:62\nmsgid \"\"\n\"When SCQL enters secure MPC protocol, it needs to encode the data into \"\n\"Ring64 or Ring128 and then perform the secure computation. Numerical \"\n\"inaccuracies can occur during both the encoding and the secure \"\n\"computation processes, and this is unavoidable.\"\nmsgstr \"\"\n\"SCQL 中的数据进入 MPC 协议前需要先对数据进行 Ring64 或 Ring128 \"\n\"的编码，然后进行密态计算，编码和密态计算过程中都会产生数值误差，这是无法避免的。\"\n\n#: ../../topics/faq.rst:65\nmsgid \"Configuration Issues\"\nmsgstr \"配置相关问题\"\n\n#: ../../topics/faq.rst:67\nmsgid \"**Q**: Data source configuration for different data sources.\"\nmsgstr \"**Q**: 不同的数据源需要使用不同的配置。\"\n\n#: ../../topics/faq.rst:69\nmsgid \"\"\n\"Please refer to the deployment documentation :doc:`/reference/engine-\"\n\"config`.\"\nmsgstr \"请参考部署文档 :doc:`/reference/engine-config`。\"\n\n#: ../../topics/faq.rst:71\nmsgid \"\"\n\"**Q**: How to configure relevant timeout settings when the network \"\n\"quality is poor.\"\nmsgstr \"**Q**: 网络环境不好的时候，如何配置超时相关配置？\"\n\n#: ../../topics/faq.rst:73\nmsgid \"\"\n\"In a poor network environment, you can appropriately increase \"\n\"**link_recv_timeout_ms** (the waiting time for the receiving party) and \"\n\"decrease **link_throttle_window_size** (the size of the channel sliding \"\n\"window). You can also appropriately configure **http_max_payload_size** \"\n\"(the size of individual packets when splitting data for transmission) and\"\n\" **link_chunked_send_parallel_size** (the number of chunks sent in \"\n\"parallel).\"\nmsgstr \"\"\n\"网络环境不好的场景，可以适当增加接收方等待时间(link_recv_timeout_ms)，减少 channel 的滑动窗口大小 \"\n\"(link_throttle_window_size)。带宽小的情况下，可以适当减小单个 http payload 的大小 \"\n\"(http_max_payload_size) 以及并发的 chunk 数量 (link_chunked_send_parallel_size)。\"\n\n#: ../../topics/faq.rst:75\nmsgid \"\"\n\"For specific configurations, please refer to the configuration \"\n\"documentation :doc:`/reference/engine-config`.\"\nmsgstr \"更加具体的配置请参考 :doc:`/reference/engine-config`。\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/topics/index.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-24 15:10+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../topics/index.rst:2\nmsgid \"Topics\"\nmsgstr \"主题\"\n\n#~ msgid \"Security\"\n#~ msgstr \"安全性\"\n\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/topics/security/overview.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-11 19:17+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../topics/security/overview.rst:2\nmsgid \"Security overview\"\nmsgstr \"安全性说明\"\n\n#: ../../topics/security/overview.rst:5\nmsgid \"Security Guarantees and Threat Model\"\nmsgstr \"安全保障和威胁模型\"\n\n#: ../../topics/security/overview.rst:7\nmsgid \"\"\n\"For a single query, SCQL protects the confidentiality of data during the \"\n\"computation process according to the security configuration.\"\nmsgstr \"对于单次查询，SCQL 在计算过程中根据安全配置提供数据机密性保护。\"\n\n#: ../../topics/security/overview.rst:9\nmsgid \"\"\n\"SCQL does not protect queries as queries are designed to be public to all\"\n\" participants in SCQL. SCQL also does not protect the size (dimension) \"\n\"information of intermediate computation results.\"\nmsgstr \"SCQL 不保护查询语句，因为查询语句对 SCQL 所有的参与方公开。SCQL 也不保护中间计算结果的大小（维度）信息。\"\n\n#: ../../topics/security/overview.rst:11\nmsgid \"\"\n\"SCQL is built on top of the MPC framework `secretflow/spu`_, using a \"\n\"semi-honest security model. The SCQL semi-honest model assumes that all \"\n\"participants, including the query issuer and the data owners (SCQLEngine \"\n\"is deployed on each data owner), strictly abide by the protocol, but may \"\n\"try to learn others' private data from legitimately received messages.\"\nmsgstr \"\"\n\"SCQL 构建在 MPC 框架 `secretflow/spu`_ 之上，使用的是 semi-honest 安全模型。SCQL semi-\"\n\"honest 模型假设所有的参与方，包括查询者和数据拥有方（SCQLEngine \"\n\"部署在数据拥有方），都严格遵守协议，但有可能会尝试分析自己得到的中间信息以获得额外的其他参与方的隐私信息。\"\n\n#: ../../topics/security/overview.rst:14\nmsgid \"\"\n\"If you select the SEMI2K as SCQL's underlying mpc protocol, it is \"\n\"recommended to use the `TrustedThirdParty beaver provider`_ [#f1]_. The \"\n\"other beaver provider mode `TrustedFirstParty beaver provider`_ should \"\n\"only be used for testing and debugging purposes.\"\nmsgstr \"\"\n\"如果选择使用 SPU SEMI2K 作为 SCQL 的底层 MPC 协议，建议使用 `TrustedThirdParty beaver \"\n\"provider`_ [#f1]_。另一种 `TrustedFirstParty beaver provider`_ 仅用于测试和调试目的。\"\n\n#: ../../topics/security/overview.rst:16\nmsgid \"\"\n\"Like all cryptography-based privacy-preserving computing systems, SCQL at\"\n\" this stage cannot solve the problem of deducing original privacy data \"\n\"based on the results of legal queries. The current academic solution to \"\n\"this problem is generally to add noise into data through differential \"\n\"privacy mechanism. Although security configurations allow data owners to \"\n\"control data access, which can alleviate risks to a certain extent, it \"\n\"cannot completely eliminate the risks. SCQL also does not solve the \"\n\"problem of participants tampering with their original input to obtain \"\n\"other participants' private information.\"\nmsgstr \"\"\n\"和所有基于密码学的隐私计算系统一样，现阶段 SCQL 无法解决建立在合法查询结果上的反推原始数据隐私的问题。目前学术界解决该问题的方案一般都是通过\"\n\" DP 加噪音。虽然安全配置机制可以让数据 owner 对自己的数据进行使用限制授权，能一定程度地缓解风险，但是不能完全杜绝风险。SCQL \"\n\"也不解决参与方篡改自己原始输入从而得到其他参与方隐私信息的问题。\"\n\n#: ../../topics/security/overview.rst:18\nmsgid \"\"\n\"The following chapters will describe possible attack methods for \"\n\"inferring data from results, and give corresponding suggestions.\"\nmsgstr \"下面的章节会介绍可能存在的结果反推攻击方法，并给出相应的建议。\"\n\n#: ../../topics/security/overview.rst:22\nmsgid \"Suggestions on Deployment\"\nmsgstr \"部署建议\"\n\n#: ../../topics/security/overview.rst:24\nmsgid \"\"\n\"In the current OpenCore architecture, the native compiler and engines \"\n\"work directly together. Please refer to ``examples/opencore-demo/`` for \"\n\"the recommended deployment approach and security configuration.\"\nmsgstr \"\"\n\"在当前的 OpenCore 架构中，原生编译器和引擎直接协同工作。推荐的部署方式和安全配置请参考 ``examples/opencore-\"\n\"demo/``。\"\n\n#: ../../topics/security/overview.rst:28\nmsgid \"Risk Statement and Suggestion for SCQL Result Inversion Attack\"\nmsgstr \"针对 SCQL 的结果反推攻击风险说明及建议\"\n\n#: ../../topics/security/overview.rst:30\nmsgid \"\"\n\"The query of SCQL could be flexible, adversaries may construct adaptive \"\n\"attacks using multiple legit queries or one complex query to achieve the \"\n\"purpose of deriving the original data.\"\nmsgstr \"SCQL 的查询灵活多变，攻击者可以使用多次合法查询或一个复杂查询来构建自适应攻击，以达到反推原始数据的目的。\"\n\n#: ../../topics/security/overview.rst:34\nmsgid \"Attack Method 1: Multi-query Attack\"\nmsgstr \"攻击方法一：多次查询攻击\"\n\n#: ../../topics/security/overview.rst:36\nmsgid \"\"\n\"The multi-query attack method includes two attack ways: (1) One way to \"\n\"obtain the other party's information is to tamper with the input content \"\n\"for each query, while keeping the query itself unchanged. For example, \"\n\"the attacker can obtain all the information of the other party's join key\"\n\" through multiple join queries and tampering with the content of his join\"\n\" key each time. (2) Another way is to infer the other party's private \"\n\"data by rewriting the query each time and comparing the results of \"\n\"multiple queries. For example, the attacker can use the where condition \"\n\"to limit the input of the aggregation function. The first time the query \"\n\"obtains the aggregation result of N pieces of data, the second time by \"\n\"changing the where condition, the aggregation result of N-1 pieces of \"\n\"data can be obtained, and then the attacker can obtain the original \"\n\"information of 1 piece of data by comparing results.\"\nmsgstr \"\"\n\"多次查询攻击方法包含两种攻击方式： (1) 一种方式是查询语句不变，每次查询时篡改输入内容的方式来获取对方信息。比如攻击者可以通过改变自己 \"\n\"join key 的内容，多次枚举查询来获得对方 join key 的全部信息。 (2) \"\n\"另一种方式是通过改写每次查询语句，对比多次查询结果来推测对方的隐私数据。比如攻击者可以利用 where 条件限制聚合函数的输入，第一次查询获得 N\"\n\" 条数据的聚合结果，第二次通过改变 where 条件，获得其中 N-1 条数据的聚合结果，对比结果可以获得其中 1 条记录的明文数据信息。\"\n\n#: ../../topics/security/overview.rst:42\nmsgid \"Attack Method 2: Constructing Complex Query Attack\"\nmsgstr \"攻击方法二：构造复杂查询攻击\"\n\n#: ../../topics/security/overview.rst:44\nmsgid \"\"\n\"This attack method is similar to the multi-query attack method, and its \"\n\"core idea is to write multiple queries into one complex query. For \"\n\"example, the attacker can perform multiple comparisons on a certain \"\n\"column in one query, and narrow down the range of data to infer the \"\n\"original data.\"\nmsgstr \"\"\n\"该攻击方法和多次查询攻击方法类似，其核心思想是将多个查询语句写成一个复杂查询语句。 \"\n\"举个例子，攻击者可以在一个查询语句里对某一列进行多次比较，缩小数据范围来反推原始数据。\"\n\n#: ../../topics/security/overview.rst:49\nmsgid \"Suggestions\"\nmsgstr \"建议\"\n\n#: ../../topics/security/overview.rst:51\n#, fuzzy\nmsgid \"\"\n\"Each data owner is advised to give careful consideration when setting CCL\"\n\" for their own data.\"\nmsgstr \"数据拥有方在为自己的数据设置安全配置时要慎重考虑；\"\n\n#: ../../topics/security/overview.rst:52\nmsgid \"\"\n\"When the upstream platform integrates the SCQL system, it's recommended \"\n\"to add an approval process before running the query. The query is \"\n\"submitted to SCQL for execution only after it has been reviewed and \"\n\"confirmed by all data owners.\"\nmsgstr \"上游平台在集成 SCQL 时，建议在执行查询前加一个人工审批流程。查询语句只有经过所有数据拥有方的审核确认后，才能提交到 SCQL 执行；\"\n\n#: ../../topics/security/overview.rst:53 ../../topics/security/overview.rst:66\nmsgid \"\"\n\"It is recommended to add an audit mechanism, analyze historical queries, \"\n\"and track down information leakage issues.\"\nmsgstr \"建议集成事后审计机制，对历史查询的执行情况进行分析，使得可以追踪和发现敏感信息泄露问题。\"\n\n#: ../../topics/security/overview.rst:57\nmsgid \"System Security Configuration Instructions\"\nmsgstr \"系统安全配置说明\"\n\n#: ../../topics/security/overview.rst:59\nmsgid \"\"\n\"SCQL supports HTTPS protocol, it is recommended to enable HTTPS by \"\n\"default. Please see :ref:`SCQLEngine TLS Configuration <scqlengine-tls>` \"\n\"for details on how to enable HTTPS for SCQLEngine.\"\nmsgstr \"\"\n\"SCQL 支持 HTTPS 协议，建议默认开启。有关如何为 SCQLEngine 启用 HTTPS 的方法详见 :ref:`SCQLEngine \"\n\"TLS 配置 <scqlengine-tls>`。\"\n\n#: ../../topics/security/overview.rst:63\nmsgid \"Suggestions for upstream integrators\"\nmsgstr \"对上游集成方的建议\"\n\n#: ../../topics/security/overview.rst:65\nmsgid \"\"\n\"It is recommended to add an approval process before submitting any \"\n\"queries to SCQL for execution.\"\nmsgstr \"在向 SCQL 提交查询前，增加数据参与方审批查询语句的流程。\"\n\n#: ../../topics/security/overview.rst:67\nmsgid \"\"\n\"It is recommended to divide the use of SCQL into two stages: development \"\n\"stage and production stage, and to adopt different security control \"\n\"measures.\"\nmsgstr \"建议将 SCQL 的使用过程分为研发态和生产态，并采用不同的安全管控措施。\"\n\n#: ../../topics/security/overview.rst:69\nmsgid \"\"\n\"The development stage refers to the stage where the query is under \"\n\"development iteration. The data samples used in the development stage \"\n\"must be small-scale data sets that have been desensitized, de-identified,\"\n\" anonymized, and added with noise, aiming to quickly build the data \"\n\"analysis processing flow.\"\nmsgstr \"\"\n\"研发态指 query \"\n\"处于迭代中的研发模式。研发态中使用的数据样本必须是经过脱敏、去标识化、匿名化、加噪等手段处理后的小规模数据集，旨在快速地构建数据分析处理流程。\"\n\n#: ../../topics/security/overview.rst:70\nmsgid \"\"\n\"The production stage refers to the joint analysis of the query by \"\n\"multiple participating parties to ensure that the task is risk-free or \"\n\"within the acceptance range of multiple participating parties, and is \"\n\"released for production operation. If the related query needs to be \"\n\"changed, it needs to go through multi-party audit and evaluation again. \"\n\"The production stage uses real data, and parties participating in the \"\n\"joint analysis need to: (1) conduct task evaluation and approval before \"\n\"the event; (2) ensure task consistency during the event, and suspend the \"\n\"task in a timely manner if there is any risk; (3) conduct audit after the\"\n\" event, and ensure that potential data leakage risks can be discovered \"\n\"and avoided in case of malicious behavior.\"\nmsgstr \"\"\n\"生产态指 query 经过联合分析的多个参与方一起安全审计，确保任务无风险或者风险在多个参与方的接受范围内，并发布在生产上运行。若相关 query\"\n\" 要变更，需要重新走多方审计评审。生产态使用的数据为真实数据，联合分析的多方需要进行：(1) 事前对任务评审与审批；(2) \"\n\"事中确保任务一致性，若有风险及时中止任务；(3) 事后进行审计，若发生恶意行为，确保可以发现和规避潜在的数据泄漏风险。\"\n\n#: ../../topics/security/overview.rst:75\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../topics/security/overview.rst:76\nmsgid \"\"\n\"SPU SEMI2K protocol adopts a trusted third party for generating Beaver \"\n\"triples for efficiency. In the future, we will consider adding a Beaver \"\n\"provider implementation that does not rely on third parties.\"\nmsgstr \"\"\n\"SPU SEMI2K 协议实现时为了效率采用了可信第三方来生成 Beaver triples，将来会考虑增加不依赖第三方的 Beaver \"\n\"provider 实现。\"\n"
  },
  {
    "path": "docs/locales/zh_CN/LC_MESSAGES/topics/system/intro.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2023 Ant Group Co., Ltd.\n# This file is distributed under the same license as the SCQL package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: SCQL \\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-02-25 10:33+0800\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: zh_CN\\n\"\n\"Language-Team: zh_CN <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../topics/system/intro.rst:2\nmsgid \"SCQL System Overview\"\nmsgstr \"SCQL 系统概述\"\n\n#: ../../topics/system/intro.rst:4\nmsgid \"\"\n\"Secure Collaborative Query Language (SCQL) is a system that allows \"\n\"multiple distrusting parties to run joint analysis without revealing \"\n\"their private data.\"\nmsgstr \"\"\n\"安全协作查询语言（Secure Collaborative Query Language， \"\n\"SCQL）是一个允许多个互不信任参与方在不泄露各自隐私数据的条件下进行联合数据分析的系统。\"\n\n#: ../../topics/system/intro.rst:7\nmsgid \"Key Features\"\nmsgstr \"关键特点\"\n\n#: ../../topics/system/intro.rst:9\nmsgid \"Semi-honest security. SCQL assumes that all parties are semi-honest.\"\nmsgstr \"半诚实安全。SCQL 假设所有参与方都是半诚实的。\"\n\n#: ../../topics/system/intro.rst:10\nmsgid \"Support multiple parties (N >= 1).\"\nmsgstr \"支持多方（N>=1）。\"\n\n#: ../../topics/system/intro.rst:11\nmsgid \"\"\n\"Support common SQL select syntax and functions to meet the needs of most \"\n\"scenarios. Please check :doc:`/reference/implementation-status` for \"\n\"details.\"\nmsgstr \"\"\n\"支持常见的 SQL select 语法和函数，满足大多数场景的需求。详情请查看 :doc:`/reference/implementation-\"\n\"status`。\"\n\n#: ../../topics/system/intro.rst:12\nmsgid \"\"\n\"Practical performance. SCQL has multiple levels of performance \"\n\"optimization.\"\nmsgstr \"实用的性能。SCQL 具有多层次的性能优化。\"\n\n#: ../../topics/system/intro.rst:13\nmsgid \"Simple structure, easy to integrate.\"\nmsgstr \"结构简单，易于集成。\"\n\n#: ../../topics/system/intro.rst:16\nmsgid \"Architecture\"\nmsgstr \"架构\"\n\n#: ../../topics/system/intro.rst:18\nmsgid \"SCQL uses a compiler + engine architecture:\"\nmsgstr \"SCQL 使用编译器 + 引擎架构：\"\n\n#: ../../topics/system/intro.rst:20\nmsgid \"\"\n\"**Compiler** translates SQL queries into secure execution plans. The \"\n\"compiler performs query parsing, logical planning, and generates \"\n\"execution graphs that specify how data should be processed securely.\"\nmsgstr \"**编译器** 将 SQL 查询转换为安全执行计划。编译器执行查询解析、逻辑规划，并生成指定如何安全处理数据的执行图。\"\n\n#: ../../topics/system/intro.rst:21\nmsgid \"\"\n\"**SCQLEngine** is a hybrid MPC-plaintext execution engine that executes \"\n\"the plans generated by the compiler. SCQLEngine collaborates with peer \"\n\"engines to run the execution graph and returns query results. SCQLEngine \"\n\"is implemented on top of state-of-the-art MPC framework \"\n\"`secretflow/spu`_.\"\nmsgstr \"\"\n\"**SCQLEngine** 是一个明密文混合执行引擎，执行编译器生成的计划。SCQLEngine \"\n\"与对等引擎协作运行执行图并返回查询结果。SCQLEngine 基于先进的 MPC 框架 `secretflow/spu`_ 实现。\"\n\n#: ../../topics/system/intro.rst:24\nmsgid \"How SCQL Works\"\nmsgstr \"SCQL 如何工作\"\n\n#: ../../topics/system/intro.rst:26\nmsgid \"\"\n\"We will show how SCQL works through the life of the following sample SCQL\"\n\" query Q.\"\nmsgstr \"我们将通过以下的 SCQL 查询样本 Q 的整个生命周期来展示 SCQL 是如何工作的。\"\n\n#: ../../topics/system/intro.rst:28\nmsgid \"SCQL query Q\"\nmsgstr \"SCQL 查询 Q\"\n\n#: ../../topics/system/intro.rst:38 ../../topics/system/intro.rst:42\nmsgid \"Table schema\"\nmsgstr \"表的结构\"\n\n#: ../../topics/system/intro.rst:40\nmsgid \"Let's have a look at the schema of tables involved in the above query Q.\"\nmsgstr \"让我们来看看上面查询 Q 中涉及的表的结构。\"\n\n#: ../../topics/system/intro.rst:45\nmsgid \"``bank_1``\"\nmsgstr \"``bank_1``\"\n\n#: ../../topics/system/intro.rst:46\nmsgid \"\"\n\"Party Bank1 owns the table ``bank_1`` in its local database ``DB1``, \"\n\"which has two columns ``customer_id`` and ``deposit``.\"\nmsgstr \"\"\n\"参与方 Bank1 在其本地数据库 ``DB1`` 中有张表 ``bank_1``，该数据表有两列分别是 ``customer_id`` 和 \"\n\"``deposit``。\"\n\n#: ../../topics/system/intro.rst:47\nmsgid \"``bank_2``\"\nmsgstr \"``bank_2``\"\n\n#: ../../topics/system/intro.rst:48\nmsgid \"\"\n\"Party Bank2 owns the table ``bank_2`` in its local database ``DB2``, \"\n\"which has two columns ``customer_id`` and ``loan``.\"\nmsgstr \"\"\n\"参与方 Bank2 在其本地数据库 ``DB2`` 中有张表 ``bank_2``，该数据表有两列分别是 ``customer_id`` 和 \"\n\"``loan``。\"\n\n#: ../../topics/system/intro.rst:52\nmsgid \"Lifetime of SCQL query\"\nmsgstr \"SCQL 查询的生命周期\"\n\n#: ../../topics/system/intro.rst:54\nmsgid \"SCQL Workflow\"\nmsgstr \"SCQL 工作流\"\n\n#: ../../topics/system/intro.rst:58\nmsgid \"Step1. Compile SQL Query\"\nmsgstr \"步骤1. 编译 SQL 查询\"\n\n#: ../../topics/system/intro.rst:60\nmsgid \"The compiler receives the SQL query and performs the following operations:\"\nmsgstr \"编译器接收 SQL 查询并执行以下操作：\"\n\n#: ../../topics/system/intro.rst:62\nmsgid \"**Step1.1 Parse**\"\nmsgstr \"**步骤1.1 解析**\"\n\n#: ../../topics/system/intro.rst:64\nmsgid \"Parser parses the SQL query Q into an AST (Abstract Syntax Tree).\"\nmsgstr \"解析器将 SQL 查询 Q 解析为 AST（抽象语法树）。\"\n\n#: ../../topics/system/intro.rst:66\nmsgid \"**Step1.2 Plan**\"\nmsgstr \"**步骤1.2 规划**\"\n\n#: ../../topics/system/intro.rst:68\n#, fuzzy\nmsgid \"\"\n\"Planner converts the AST into Logical Plan, and applies optimizations to \"\n\"the plan.\"\nmsgstr \"规划器将 AST 转换为逻辑计划，并且对逻辑计划进行优化。\"\n\n#: ../../topics/system/intro.rst:70\nmsgid \"Logical Plan for Q\"\nmsgstr \"Q 的逻辑计划\"\n\n#: ../../topics/system/intro.rst:74\n#, fuzzy\nmsgid \"**Step1.3 Translate to Operator Graph**\"\nmsgstr \"**步骤1.3 转化成操作图**\"\n\n#: ../../topics/system/intro.rst:76\n#, fuzzy\nmsgid \"The compiler translates the logical plan into an operator graph\"\nmsgstr \"编译器将逻辑计划转换为查询 Q 的操作图。\"\n\n#: ../../topics/system/intro.rst:78\n#, fuzzy\nmsgid \"**Step1.4 Visibility Analysis**\"\nmsgstr \"**步骤1.4 可见性分析**\"\n\n#: ../../topics/system/intro.rst:80\nmsgid \"\"\n\"The compiler performs visibility analysis on the operator graph to \"\n\"determine which nodes are visible to each party, and optimize the graph \"\n\"accordingly.\"\nmsgstr \"编译器在操作图上执行可见性分析以确定哪些节点对每个参与方可见，并根据需要优化图。\"\n\n#: ../../topics/system/intro.rst:82\n#, fuzzy\nmsgid \"**Step1.5 Generate Execution Graph**\"\nmsgstr \"**步骤1.5 生成执行图**\"\n\n#: ../../topics/system/intro.rst:84\n#, fuzzy\nmsgid \"The compiler generates an execution graph for the query Q.\"\nmsgstr \"编译器为查询 Q 生成执行图。\"\n\n#: ../../topics/system/intro.rst:86\nmsgid \"Execution Graph for Q\"\nmsgstr \"Q 的执行图\"\n\n#: ../../topics/system/intro.rst:89\n#, fuzzy\nmsgid \"**Step1.6 Split Execution Graph**\"\nmsgstr \"**步骤1.6 拆分执行图**\"\n\n#: ../../topics/system/intro.rst:91\nmsgid \"\"\n\"The compiler splits the execution graph into subgraphs based on the \"\n\"parties of the nodes.\"\nmsgstr \"编译器根据执行图上节点的拥有方将执行图拆分为子图。\"\n\n#: ../../topics/system/intro.rst:93\nmsgid \"subgraphs\"\nmsgstr \"子图\"\n\n#: ../../topics/system/intro.rst:97\n#, fuzzy\nmsgid \"Step2. Execute on Engines\"\nmsgstr \"步骤2. 在引擎上执行\"\n\n#: ../../topics/system/intro.rst:99\nmsgid \"\"\n\"The subgraphs are sent to corresponding SCQLEngine nodes. SCQLEngine \"\n\"cooperates with peer engines to execute the graph and produces the final \"\n\"result of query Q.\"\nmsgstr \"子图被发送到相应的 SCQLEngine 节点。SCQLEngine 与对等引擎协作执行图并生成查询 Q 的最终结果。\"\n\n"
  },
  {
    "path": "docs/reference/compiler-config.rst",
    "content": ".. _compiler_config_options:\n\nSCQL Compiler Configuration\n============================\n\nThe SCQL compiler translates SQL queries into secure execution plans. This document describes the configuration options for the compiler API.\n\n\nCompileSQLRequest\n-----------------\n\nThe main request message for compiling SQL queries.\n\n- **query** (*required*): The SQL query string to compile\n- **db** (*optional*): Database name\n- **issuer** (*required*): The party code of the query issuer (e.g., ``{\"code\": \"alice\"}``)\n- **catalog** (*required*): Database catalog metadata describing tables and columns, see :ref:`catalog_config`\n- **compile_opts** (*required*): Compilation options, see :ref:`compile_options`\n- **issue_time** (*required*): Query issue timestamp, used for functions like ``NOW()``\n- **security_config** (*required*): Security configuration, see :ref:`security_config`\n- **additional_info** (*required*): Specifies additional information in response, see :ref:`additional_info_spec`\n\n\n.. _compile_options:\n\nCompileOptions\n--------------\n\nCompilation options that control the execution strategy.\n\n- **spu_conf** (*required*): SPU runtime configuration (protocol, field, etc.), see `SPU documentation`_\n- **batched** (*required*): Whether to run in streaming mode\n- **psi_algorithm_type** (*optional*): PSI algorithm type: ``UNSPECIFIED`` (auto), ``ECDH_PSI``, ``KKRT_PSI``, ``RR22``\n\n**SPU Configuration Example:**\n\n.. code-block:: json\n\n    {\n      \"spu_conf\": {\n        \"protocol\": \"SEMI2K\",\n        \"field\": \"FM64\"\n      },\n      \"batched\": false\n    }\n\n**Supported SPU Protocols:**\n\n- ``SEMI2K``: Semi-honest 2PC/MPC (supports N parties)\n- ``CHEETAH``: Semi-honest 2PC (2 parties only)\n- ``ABY3``: Semi-honest 3PC (3 parties only)\n\n**Supported Fields:**\n\n- ``FM32``: 32-bit finite field\n- ``FM64``: 64-bit finite field\n- ``FM128``: 128-bit finite field\n\n\n.. _security_config:\n\nCompilerSecurityConfig\n----------------------\n\nSecurity configuration that controls data visibility and security relaxations.\n\n- **global_relaxation** (*required*): Global security relaxation settings, see :ref:`global_security_relaxation`\n- **column_relaxation_list** (*optional*): Per-column security relaxations, see :ref:`column_security_relaxation`\n- **reverse_inference_conf** (*required*): Reverse inference detection config, see :ref:`reverse_inference_config`\n- **column_visibility_list** (*optional*): User-specified column visibility, see :ref:`column_visibility`\n- **result_security_conf** (*optional*): Result-level security config, see :ref:`result_security_config`\n\n\n.. _global_security_relaxation:\n\nGlobalSecurityRelaxation\n~~~~~~~~~~~~~~~~~~~~~~~~\n\nGlobal security relaxation that applies to all data.\n\n- **reveal_group_count** (*optional*): Allow group counts to be visible in plaintext\n- **reveal_group_mark** (*optional*): Allow group marks to be visible in plaintext\n- **reveal_key_after_join** (*optional*): Allow join keys to be visible in plaintext after join (intersection only). When enabled, the compiler will prefer PSI join over secret join for better performance\n- **reveal_filter_mask** (*optional*): Allow filter mask to be used in plaintext for subsequent computations\n\n**Example:**\n\n.. code-block:: json\n\n    {\n      \"global_relaxation\": {\n        \"reveal_group_count\": false,\n        \"reveal_group_mark\": false,\n        \"reveal_key_after_join\": true,\n        \"reveal_filter_mask\": false\n      }\n    }\n\n\n.. _column_security_relaxation:\n\nColumnSecurityRelaxation\n~~~~~~~~~~~~~~~~~~~~~~~~\n\nPer-column security relaxation for fine-grained control.\n\n- **database** (*required*): Database name\n- **table** (*required*): Table name\n- **column** (*required*): Column name\n- **reveal_key_after_join** (*optional*): Allow join keys to be visible in plaintext after join (intersection only). When enabled, the compiler will prefer PSI join over secret join for better performance\n- **reveal_filter_mask** (*optional*): Allow filter mask to be used in plaintext for subsequent computations\n\n.. note::\n    Column-level settings use logical OR with global settings. If global ``reveal_key_after_join`` is ``true`` and column-level is ``false``, the result is ``true``. If global is ``false`` and column-level is ``true``, the result is ``true``. Only when both are ``false`` is the final result ``false``. The same logic applies to ``reveal_filter_mask``.\n\n**Example:**\n\n.. code-block:: json\n\n    {\n      \"column_relaxation_list\": [\n        {\n          \"database\": \"alice\",\n          \"table\": \"user_credit\",\n          \"column\": \"ID\",\n          \"reveal_key_after_join\": true\n        }\n      ]\n    }\n\n\n.. _reverse_inference_config:\n\nReverseInferenceConfig\n~~~~~~~~~~~~~~~~~~~~~~\n\nConfiguration for reverse inference.\n\n- **enable_reverse_inference** (*required*): Infer intermediate visibility from result visibility to enable plaintext compute\n\nWhen enabled, the compiler will infer the visibility of intermediate computation steps based on the final result visibility, increasing the possibility of plaintext computation and improving performance.\n\n**Example:**\n\n.. code-block:: json\n\n    {\n      \"reverse_inference_conf\": {\n        \"enable_reverse_inference\": true\n      }\n    }\n\n\n.. _column_visibility:\n\nColumnVisibility\n~~~~~~~~~~~~~~~~\n\nSpecifies which parties can see specific columns.\n\n- **database** (*required*): Database name\n- **table** (*required*): Table name\n- **column** (*required*): Column name\n- **visible_parties** (*required*): List of party codes that can see this column during computation (in addition to the owner)\n\nBy default, only the column owner can see the data. Use this to grant visibility to other parties. Adding column visibility will make the execution graph prefer plaintext operators, improving execution efficiency.\n\n**Example:**\n\n.. code-block:: json\n\n    {\n      \"column_visibility_list\": [\n        {\n          \"database\": \"alice\",\n          \"table\": \"user_credit\",\n          \"column\": \"age\",\n          \"visible_parties\": [\n            {\"code\": \"bob\"}\n          ]\n        }\n      ]\n    }\n\n\n.. _result_security_config:\n\nResultSecurityConfig\n~~~~~~~~~~~~~~~~~~~~\n\nSecurity configuration that affects query results.\n\n- **groupby_threshold** (*optional*): Minimum number of rows in a group for GROUP BY results (default: 4)\n\nGroups with fewer rows than this threshold will be filtered out to prevent inference attacks.\n\n**Example:**\n\n.. code-block:: json\n\n    {\n      \"result_security_conf\": {\n        \"groupby_threshold\": 4\n      }\n    }\n\n\n.. _additional_info_spec:\n\nAdditionalInfoSpec\n------------------\n\nSpecifies what additional information should be included in the response.\n\n- **need_operator_graph** (*optional*): Whether to return the operator graph for debugging (default: ``false``)\n\n\n.. _catalog_config:\n\nCatalog Configuration\n---------------------\n\nThe catalog defines the database schema. See ``api/interpreter.proto`` for the complete definition.\n\n**Basic Structure:**\n\n.. code-block:: json\n\n    {\n      \"catalog\": {\n        \"tables\": [\n          {\n            \"table_name\": \"user_credit\",\n            \"columns\": [\n              {\n                \"name\": \"ID\",\n                \"type\": \"string\",\n                \"ordinal_position\": 1\n              },\n              {\n                \"name\": \"age\",\n                \"type\": \"int\",\n                \"ordinal_position\": 2\n              }\n            ],\n            \"ref_table\": \"alice.user_credit\",\n            \"db_type\": \"mysql\",\n            \"owner\": {\"code\": \"alice\"}\n          }\n        ]\n      }\n    }\n\n**Supported Column Types:**\n\n- ``int``, ``long``, ``string``, ``float``, ``double``\n- ``datetime``, ``timestamp``\n\n**Supported Database Types:**\n\n- ``mysql``, ``postgres``, ``sqlite``\n- ``csvdb`` (for CSV files)\n- ``arrowsql`` (for Arrow Flight servers)\n\nSee Also\n--------\n\n- :doc:`/reference/engine-config` - Engine configuration reference\n- :doc:`/intro/opencore-quickstart` - Quick start guide\n- `SPU Documentation <https://github.com/secretflow/spu>`_ - SPU protocol details\n\n.. _SPU documentation: https://github.com/secretflow/spu\n"
  },
  {
    "path": "docs/reference/engine-config.rst",
    "content": "\n.. _engine_config_options:\n\nSCQLEngine Configuration\n------------------------\n\nSCQLEngine uses Gflags to manage configurations when SCQLEngine set up.\n\nExample configuration for SCQLEngine\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code-block::\n\n  # Config for Brpc server\n  --listen_port=8003\n  # Config for datasource\n  --datasource_router=embed\n  --embed_router_conf={\"datasources\":[{\"id\":\"ds001\",\"name\":\"mysql db\",\"kind\":\"MYSQL\",\"connection_str\":\"${connection_str}\"}],\"rules\":[{\"db\":\"*\",\"table\":\"*\",\"datasource_id\":\"ds001\"}]}\n\n\nConfiguration Options of SCQLEngine\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSCQLEngine works with the native compiler to execute query plans. In the configuration, ``Driver`` refers to the module that sends execution plans to the engine.\n\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n|                      Name                       |       Default       |                                                               Description                                                               |\n+=================================================+=====================+=========================================================================================================================================+\n| log_enable_console_logger                       | true                | Whether logging to stdout while logging to file                                                                                         |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| log_enable_session_logger_separation            | false               | Whether output session-related logs to a dedicated file                                                                                 |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| log_dir                                         | logs                | The directory to save log file                                                                                                          |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| log_level                                       | info                | Log level, can be trace/debug/info/warning/error/critical/off                                                                           |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| peer_engine_protocol                            | baidu_std           | The rpc protocol between engine and engine                                                                                              |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| peer_engine_connection_type                     | single              | The rpc connection type between engine and engine                                                                                       |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| peer_engine_load_balancer                       | none                | The rpc load balancer between engine and engine, can be rr or empty string                                                              |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| peer_engine_timeout_ms                          | 300000              | The rpc timeout between engine and engine, unit: ms                                                                                     |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| peer_engine_max_retry                           | 3                   | Rpc max retries(not including the first rpc) between engine and engine                                                                  |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| peer_engine_enable_ssl_as_client                | true                | Whether enable ssl encryption when send message to another engine                                                                       |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| peer_engine_enable_ssl_client_verification      | false               | Whether enable certificate verification when send message to another engine                                                             |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| peer_engine_ssl_client_ca_certificate           | none                | The trusted CA file to verify certificate when send message to another engine                                                           |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| link_recv_timeout_ms                            | 30000               | The max time that engine will wait for message come from another engine                                                                 |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| link_throttle_window_size                       | 16                  | Throttle window size for channel, set to limit the number of messages sent asynchronously to avoid network congestion, set 0 to disable |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| link_chunked_send_parallel_size                 | 1                   | Parallel size when send chunked value                                                                                                   |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| http_max_payload_size                           | 1048576             | Max payload to decide whether to send value chunked, default 1MB                                                                        |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| driver_protocol                                 | `http:proto`        | The rpc protocol between engine and Driver                                                                                              |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| driver_connection_type                          | pooled              | The rpc connection type between engine and Driver                                                                                       |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| driver_load_balancer                            | none                | The rpc load balancer between engine and Driver, can be rr or empty string                                                              |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| driver_timeout_ms                               | 5000                | The rpc timeout between engine and Driver, unit: ms                                                                                     |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| driver_max_retry                                | 3                   | Rpc max retries(not including the first rpc) between engine and Driver                                                                  |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| driver_enable_ssl_as_client                     | true                | Whether enable ssl encryption when send message to Driver                                                                               |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| driver_enable_ssl_client_verification           | false               | Whether enable certificate verification when send message to Driver                                                                     |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| driver_ssl_client_ca_certificate                | none                | The trusted CA file to verify certificate when send message to Driver                                                                   |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| listen_port                                     | 8003                | The listening port of engine service                                                                                                    |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| enable_builtin_service                          | false               | Whether enable brpc builtin service                                                                                                     |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| internal_port                                   | 9527                | The listening port of brpc builtin services                                                                                             |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| enable_separate_link_port                       | false               | Whether use a separate port for link service                                                                                            |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| link_port                                       | 8004                | Port for link service                                                                                                                   |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| idle_timeout_s                                  | 30                  | Idle connection close delay in seconds between the engine and Driver, unit: s                                                           |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| server_enable_ssl                               | true                | Whether enable SSL when engine work as a server                                                                                         |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| server_ssl_certificate                          | none                | Certificate file path to enable SSL when engine work as a server                                                                        |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| server_ssl_private_key                          | none                | Private key file path to enable SSL when engine work as a server                                                                        |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| enable_client_authorization                     | false               | Whether check requests' http header when engine work as a server                                                                        |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| auth_credential                                 | none                | Authorization credential used to check requests' http header                                                                            |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| enable_driver_authorization                     | false               | Whether to authenticate the identity of Driver                                                                                          |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| engine_credential                               | none                | Credential used to authenticate Driver                                                                                                  |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| session_timeout_s                               | 1800                | Expiration duration of a session between engine and Driver, unit: s                                                                     |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| spu_allowed_protocols                           | SEMI2K,ABY3,CHEETAH | SPU allowed protocols                                                                                                                   |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| datasource_router                               | embed               | The datasource router type, \"embed\" or \"http\"                                                                                           |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| embed_router_conf                               | none                | Configuration for embed router in json format                                                                                           |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| http_router_endpoint                            | none                | http datasource router endpoint, it is valid only datasource_router is set to \"http\"                                                    |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| kuscia_datamesh_endpoint                        | datamesh:8071       | Kuscia datamesh grpc endpoint                                                                                                           |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| kuscia_datamesh_client_key_path                 | none                | Kuscia datamesh client key file                                                                                                         |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| kuscia_datamesh_client_cert_path                | none                | Kuscia datamesh client cert file                                                                                                        |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| kuscia_datamesh_cacert_path                     | none                | Kuscia datamesh server cacert file                                                                                                      |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| db_connection_info                              | none                | Connection string used to connect to mysql                                                                                              |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| enable_self_auth                                | true                | Whether enable self identity authentication                                                                                             |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| private_key_pem_path                            | none                | Path to private key pem file                                                                                                            |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| enable_peer_auth                                | true                | Whether enable peer parties identity authentication                                                                                     |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| authorized_profile_path                         | none                | Path to authorized profile, in json format                                                                                              |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| enable_psi_detail_logger                        | false               | Whether enable detail log                                                                                                               |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| psi_detail_logger_dir                           | logs/detail         | Detail log directory                                                                                                                    |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| enable_restricted_read_path                     | true                | Whether restrict path for file to read                                                                                                  |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| restricted_read_path                            | ./data              | In where the file is allowed to read if enable restricted read path                                                                     |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| csv_null_str                                    | NULL                | Specifies the string that represents a NULL value when reading csv                                                                      |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| enable_restricted_write_path                    | true                | Whether restrict path for file to write                                                                                                 |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| restricted_write_path                           | ./data              | In where the file is allowed to write if enable restricted write path                                                                   |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| null_string_to_write                            | NULL                | The string to write for NULL values                                                                                                     |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| output_s3_endpoint                              | none                | The endpoint of output s3/minio/oss                                                                                                     |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| output_s3_access_key                            | none                | The access key id of output s3/minio/oss                                                                                                |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| output_s3_secret_key                            | none                | The secret access key of output s3/minio/oss                                                                                            |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| output_s3_enalbe_ssl                            | true                | Default enable ssl, if s3 server not enable ssl, set to false                                                                           |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| output_s3_ca_dir_path                           | /etc/ssl/certs/     | Directory where the certificates stored to verify s3 server                                                                             |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| output_s3_force_virtual_addressing              | true                | Default set to true to work with oss, for minio please set to false                                                                     |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| output_db_kind                                  | none                | The kind of output db, support mysql/sqlite/postgresql                                                                                  |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| output_db_connection_str                        | none                | The :ref:`connection string <connection_str>` to connect to output db                                                                   |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| psi_curve_type                                  | 2                   | Curve type used in PSI, default 2: CURVE_FOURQ, for more see `psi curve type`_                                                          |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| provider_batch_size                             | 8192                | Batch size used in PSI Provider                                                                                                         |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| detail_logger_sample_num                        | 0                   | Sample number for detail logger, 0 means print all, default 0                                                                           |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| max_chunk_size                                  | 134217728           | Max chunk size for spu value proto, default 128MB                                                                                       |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| enable_tensor_life_cycle_manage                 | true                | Whether tensor life cycle manage is enable/disable                                                                                      |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| arrow_client_disable_server_verification        | false               | Whether disable server verification for ArrowSQL adaptor                                                                                |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| arrow_cert_pem_path                             | none                | Certificate file path for server verification when arrow_client_disable_server_verification is false                                    |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| arrow_client_key_pem_path                       | none                | Private key file path for ArrowSQL client to work in mtls                                                                               |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| arrow_client_cert_pem_path                      | none                | Certificate file path for ArrowSQL client to work in mtls                                                                               |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| tmp_file_path                                   | /tmp                | The path for temporarily storing local data in streaming mode.                                                                          |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| streaming_row_num_threshold                     | 30000000            | Minimum row num to use streaming mode                                                                                                   |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n| batch_row_num                                   | 10000000            | Max row num in one batch                                                                                                                |\n+-------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------+\n\n.. _datasource_router:\n\nConfig for datasource\n^^^^^^^^^^^^^^^^^^^^^\ndatasources(MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL) are where the SCQLEngine gets its data from.\n\n``datasource_router`` is design to support multi datasources, currently supported: ``embed`` and ``http``.\n\nFor ``embed`` type, which is initialized with ``embed_router_conf`` first, a json string like::\n\n  \"datasources\": [\n    {\n      \"id\": \"ds001\",\n      \"name\": \"mysql db for scql\",\n      \"kind\": \"MYSQL\",\n      \"connection_str\": \"${connection_str}\"\n    }\n  ],\n  \"rules\":[\n    {\n      \"db\": \"*\",\n      \"table\": \"*\",\n      \"datasource_id\": \"ds001\"\n    }\n  ]\n\nif ``embed_router_conf`` is empty, embed_router will try to initialized with ``db_connection_info``.\n\nFor ``http`` type, ``http_router_endpoint`` must be set and will be accessed to get database information.\n\nExample of a mock http router server: `mock http router`_.\n\nEmbed router\n\"\"\"\"\"\"\"\"\"\"\"\"\ndatasources in embed_router_conf contain information for connecting MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL:\n\n  id: unique id of datasource.\n\n  name: custom description help to distinguish datasources.\n\n  kind: datasource type, currently support MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL.\n\n  connection_str: string used to connect MySQL/SQLite3/PostgreSQL/CSVDB/ArrowSQL.\n\n.. _connection_str:\n\n    MySQL Connection string format:\n      <str> == <assignment> | <assignment> ';' <str>\n\n      <assignment> == <name> '=' <value>\n\n      <name> == 'host' | 'port' | 'user' | 'password' | 'db' | 'compress' | 'auto-reconnect' | 'reset' | 'fail-readonly'\n\n      <value> == [~;]*\n\n    MySQL Connection string e.g:\n      ``db=${db};user=${user};password=${password};host=${host}``\n\n    SQLite3 Connection string format:\n      more infos: https://www.sqlite.org/c3ref/open.html\n\n    SQLite3 Connection string e.g:\n      ``file:/path/to/data.db``\n\n    PostgreSQL Connection string format:\n      <str> == <assignment> | <assignment> ' ' <str>\n\n      <assignment> == <name> '=' <value>\n\n      <name> == 'host' | 'port' | 'user' | 'password' | 'dbname' | 'connect_timeout'\n\n      <value> == [~;]*\n\n    PostgreSQL Connection string e.g:\n      ``dbname=${db} user=${user} password=${password} host=${host} port=${port}``\n\n    CSVDB Connection string format:\n      CSVDB support read csv from local and OSS/MinIO, since connection_str is an object in another json object, the format is a converted json string corresponding to `CsvdbConf <https://github.com/secretflow/scql/tree/main/engine/datasource/csvdb_conf.proto>`_\n\n    CSVDB Connection string e.g:\n      local csv: \"{\\\\\\\"db_name\\\\\\\":\\\\\\\"csvdb\\\\\\\",\\\\\\\"tables\\\\\\\":[{\\\\\\\"table_name\\\\\\\":\\\\\\\"staff\\\\\\\",\\\\\\\"data_path\\\\\\\":\\\\\\\"test.csv\\\\\\\",\\\\\\\"columns\\\\\\\":[{\\\\\\\"column_name\\\\\\\":\\\\\\\"id\\\\\\\",\\\\\\\"column_type\\\\\\\":\\\\\\\"string\\\\\\\"}]}]}\"\n\n      OSS csv: \"{\\\\\\\"db_name\\\\\\\":\\\\\\\"csvdb\\\\\\\",\\\\\\\"s3_conf\\\\\\\":{\\\\\\\"endpoint\\\\\\\":\\\\\\\"test_endpoint\\\\\\\",\\\\\\\"access_key_id\\\\\\\":\\\\\\\"test_id\\\\\\\",\\\\\\\"secret_access_key\\\\\\\":\\\\\\\"test_key\\\\\\\",\\\\\\\"virtualhost\\\\\\\": true },\\\\\\\"tables\\\\\\\":[{\\\\\\\"table_name\\\\\\\":\\\\\\\"staff\\\\\\\",\\\\\\\"data_path\\\\\\\":\\\\\\\"oss://test_bucket/test.csv\\\\\\\",\\\\\\\"columns\\\\\\\":[{\\\\\\\"column_name\\\\\\\":\\\\\\\"id\\\\\\\",\\\\\\\"column_type\\\\\\\":\\\\\\\"string\\\\\\\"}]}]}\"\n\n    ArrowSQL Connection string format:\n      grpc+<scheme>://host:port\n\n      <scheme> == 'tcp' | 'tls'\n\n    ArrowSQL Connection string e.g:\n      ``grpc+tcp://127.0.0.1:6666``\n\n      .. note::\n        As a datasource embedded in SCQLEngine, ArrowSQL requires an additional gRPC server which provides the corresponding interface for executing an ad-hoc query in `Arrow Flight SQL <https://arrow.apache.org/docs/format/FlightSql.html>`_\n\nRouting rules\n\"\"\"\"\"\"\"\"\"\"\"\"\"\nembed_router's rules support wildcard ``*`` , when given a table in format: *database_name:table_name*,\nembed_router will route to the corresponding datasource by\n\n1. find the exact rules first, whose ``${db}:${table}`` equals to *database_name:table_name*;\n2. try the database_name:\\* rules;\n3. try \\*:table_name in the end.\n\nOnce found, SCQLEngine will try to connect database with datasource's information correspond to the *datasource_id*.\n\nConfig for Brpc server\n^^^^^^^^^^^^^^^^^^^^^^\nSCQLEngine uses **Brpc** to communicate with Driver and other peer SCQLEngines, each SCQLEngine will start a Brpc service on *local-host:listen_port* to receive data from outside. If you want to enable Brpc builtin services, add FLAGS:\n\n.. code-block::\n\n  --enable_builtin_service=true\n  --internal_port=9527\n\n\n.. _scqlengine-tls:\n\nConfig for SSL\n^^^^^^^^^^^^^^\nIf you want to enable SSL in SCQLEngine, add FLAGS as follows.\n\n.. code-block::\n\n  --server_enable_ssl=true\n  --server_ssl_certificate=${file path of cert}\n  --server_ssl_private_key=${file path of key}\n  # set peer_engine_enable_ssl_as_client to true when peer SCQLEngine has https enabled\n  --peer_engine_enable_ssl_as_client=true\n  # set driver_enable_ssl_as_client to true when the Driver has https enabled\n  --driver_enable_ssl_as_client=true\n\nConfig for party authentication\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nFor security, SCQLEngine enables party authentication by default. SCQLEngine will check it's public key in the Driver request matches the local public key in ``private_key_pem_path``, and that the other participant's public key also matches the one in ``authorized_profile_path``.\n\n.. _heu/ou: https://www.secretflow.org.cn/docs/heu/getting_started/algo_choice#ou-paillier\n\n.. _psi curve type: https://www.secretflow.org.cn/en/docs/psi/main/reference/psi_config#curvetype\n\n.. _replay attacks: https://en.wikipedia.org/wiki/Replay_attack\n\n.. _mock http router: https://github.com/secretflow/scql/blob/main/engine/datasource/mock_router_readme.md\n"
  },
  {
    "path": "docs/reference/implementation-status.rst",
    "content": "SCQL Implementation Status\n==========================\n\nSELECT Statement\n----------------\n\n+------------------------+-----------------------------+------------------------------------------------------+\n| syntax                 | supported(fully/partial/no) | notes                                                |\n+========================+=============================+======================================================+\n| join                   | partial                     | keyword ``using`` is not supported yet               |\n+------------------------+-----------------------------+------------------------------------------------------+\n| where clause           | fully                       |                                                      |\n+------------------------+-----------------------------+------------------------------------------------------+\n| group by clause        | fully                       |                                                      |\n+------------------------+-----------------------------+------------------------------------------------------+\n| having clause          | fully                       |                                                      |\n+------------------------+-----------------------------+------------------------------------------------------+\n| union/union all clause | fully                       |                                                      |\n+------------------------+-----------------------------+------------------------------------------------------+\n| distinct clause        | fully                       |                                                      |\n+------------------------+-----------------------------+------------------------------------------------------+\n| limit clause           | fully                       |                                                      |\n+------------------------+-----------------------------+------------------------------------------------------+\n| order by clause        | fully                       |                                                      |\n+------------------------+-----------------------------+------------------------------------------------------+\n| subquery clause        | partial                     | support partial scalar subquery and compare subquery |\n+------------------------+-----------------------------+------------------------------------------------------+\n| in clause              | fully                       |                                                      |\n+------------------------+-----------------------------+------------------------------------------------------+\n\n\n\nFunctions and Operators\n-----------------------\n\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| Category          | Functions and Operators                                                                          | supported(fully/partial/no) | notes                                                                            |\n+===================+==================================================================================================+=============================+==================================================================================+\n| aggregation       | sum                                                                                              | fully                       |                                                                                  |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| aggregation       | count                                                                                            | fully                       |                                                                                  |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| aggregation       | avg                                                                                              | fully                       |                                                                                  |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| aggregation       | min                                                                                              | fully                       |                                                                                  |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| aggregation       | max                                                                                              | fully                       |                                                                                  |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| binary arithmetic | +,-,*,/,div                                                                                      | fully                       | div means ``integer division``                                                   |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| unary arithmetic  | trigonometric, abs, round, ceil, floor, round, radians, degrees, ln, log10, log2, sqrt, exp, etc | partial                     | log2, log10, round does not support secret input                                 |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| logical           | logical_and,logical_or,not                                                                       | fully                       |                                                                                  |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| compare           | <,<=,>,>=                                                                                        | partial                     | string data comparison is not supported                                          |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| compare           | =, !=                                                                                            | fully                       |                                                                                  |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| in                | in, not in                                                                                       | partial                     | all arguments should be of the same type                                         |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| datetime          | now                                                                                              | partial                     | no arguments, affected by timezone                                               |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| datetime          | curdate                                                                                          | partial                     | no arguments, different datasource may have different result because of timezone |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| datetime          | last_day                                                                                         | partial                     | arguments must be datetime or timestamp, not supported by PostgreSQL             |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| datetime          | str_to_date, date_format                                                                         | partial                     | arguments must be datetime or timestamp, not supported by PostgreSQL             |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| datetime          | adddate, subdate                                                                                 | partial                     | the first argument must be datetime or timestamp, second argument is interval    |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| datetime          | datediff                                                                                         | partial                     | arguments must be datetime or timestamp, not supported by PostgreSQL and csv     |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| string            | substr, lower, upper, trim, concat                                                               | partial                     | do not support secret input                                                      |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n| window            | row_number, percent_rank                                                                         | partial                     |                                                                                  |\n+-------------------+--------------------------------------------------------------------------------------------------+-----------------------------+----------------------------------------------------------------------------------+\n\nData Source\n-----------\n\n+---------------+-----------------------------+--------------------------+\n| Database Type | supported(fully/partial/no) | notes                    |\n+===============+=============================+==========================+\n| MySQL         | fully                       |                          |\n+---------------+-----------------------------+--------------------------+\n| PostgreSQL    | partial                     |                          |\n+---------------+-----------------------------+--------------------------+\n| CSV           | partial                     | Data stored in csv files |\n+---------------+-----------------------------+--------------------------+\n\n.. warning::\n    SCQL supports different databases as data source, but there may be minor differences in the results due to data type differences built in databases. Please choose backend database with caution.\n"
  },
  {
    "path": "docs/reference/index.rst",
    "content": "Reference\n=========\n\n.. toctree::\n    :caption: Language\n    :maxdepth: 1\n\n    lang/manual\n    lang/mysql-compatibility\n\n.. toctree::\n    :caption: Configuration\n    :maxdepth: 1\n\n    compiler-config\n    engine-config\n\n.. toctree::\n    :caption: Internal Reference\n    :maxdepth: 1\n\n    operators\n\n.. toctree::\n    :maxdepth: 1\n\n    implementation-status\n"
  },
  {
    "path": "docs/reference/lang/manual.rst",
    "content": "SCQL Language Manual\n====================\n\n\n.. _scql_data_types:\n\nSCQL Data Types\n---------------\n\nSCQL supports frequently-used data types, as illustrated in the following table.\n\n+---------------+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+\n| Data Type     | Alias                              | Description                                                                                                                                             |\n+===============+====================================+=========================================================================================================================================================+\n| ``integer``   | ``int``, ``int32``, ``int64``      |                                                                                                                                                         |\n+---------------+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+\n| ``float``     | ``float32``                        |                                                                                                                                                         |\n+---------------+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+\n| ``double``    | ``float``, ``double``, ``float64`` |                                                                                                                                                         |\n+---------------+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+\n| ``string``    | ``str``                            |                                                                                                                                                         |\n+---------------+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+\n| ``datetime``  |                                    | Used for values that contain both date and time parts. SCQL retrieves and displays in 'YYYY-MM-DD hh:mm:ss' format                                      |\n+---------------+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+\n| ``timestamp`` |                                    | Used for values that contain both date and time parts. SCQL retrieves in 'YYYY-MM-DD hh:mm:ss' format and displays in int64 value affected by time zone |\n+---------------+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+\n\n\n.. _scql_statements:\n\nSCQL Query Syntax\n-----------------\n\nIt is compatible with most MySQL DQL syntax. For syntax differences between SCQL and MySQL, please read :doc:`/reference/lang/mysql-compatibility`.\n\n.. code-block:: SQL\n\n    SELECT [DISTINCT] select_expr [, select_expr] ...\n    [FROM table_reference]\n    [WHERE where_condition]\n    [GROUP BY column]\n    [into_option]\n\n    select_expr:\n        col_reference [AS alias]\n\n    col_reference:\n        column\n    | agg_function(column)\n\n    column:\n        *\n    | db_name.tbl_name.col_name field_as_name_opt\n    | alias.col_name field_as_name_opt\n    | expression field_as_name_opt\n\n    field_as_name_opt:\n        \"\"\n    | field_as_name\n\n    field_as_name:\n        identifier\n    | \"AS\" identifier\n\n    table_reference:\n        table_factor\n    | join_table\n    | union_table\n\n    table_factor:\n        db_name.tbl_name [[AS] alias]\n\n    join_table:\n        table_reference [INNER] JOIN table_factor [join_specification]\n\n    union_table:\n        select_expr\n        | UNION [ALL] union_table\n\n    join_specification:\n        ON search_condition\n\n    expression:\n        expression \"SUPPORTED_OP\" expression\n        | \"NOT\" expression\n        | predicate_expr\n\n    predicate_expr:\n        column InOrNotOp '(' expression_list ')'\n        | column InOrNotOp sub_select\n        | column\n\n    sub_select:\n        '(' select_stmt ')'\n\n    into_option:\n        INTO OUTFILE PARTY_CODE 'party_code' 'file_path' [export_options]\n\n    export_options:\n        [FIELDS | COLUMNS\n            [TERMINATED BY 'terminal_character']\n            [[OPTIONALLY] ENCLOSED BY 'enclosing_character']\n        ]\n        [LINES TERMINATED BY 'terminal_string']\n\n.. note::\n   - SCQL support ``export_options`` with limitations: only support '\"' or '' for **enclosing_character**; **ESCAPED BY** is not supported.\n   - **OPTIONALLY** in ``export_options`` controls quoting of fields, if omitted all fields are enclosed by the **enclosing_character**, otherwise only string fields are enclosed. see `mysql load data`_\n   - **file_path** in ``into_option`` can be local path like '/data/file.csv' or oss path like 'oss://bucket_name/path/to/file', flags for writing should be set correctly, see :ref:`Engine configuration options <engine_config_options>` for more.\n\n\n\nFunctions and Operators\n-----------------------\n\n.. todo:: this part is not ready, please check later\n\n.. _mysql load data: https://dev.mysql.com/doc/refman/8.0/en/load-data.html\n"
  },
  {
    "path": "docs/reference/lang/mysql-compatibility.rst",
    "content": "MySQL Compatibility\n===================\n\nSCQL is highly compatible with MySQL, but there are still some syntax differences.\n\nUnsupported Features\n--------------------\n\n1. Partition table\n2. Character sets\n3. User-defined functions\n4. TCL(Transaction Control Language)\n5. DML(Data Manipulation Language)\n\nFeatures that are different from MySQL\n--------------------------------------\n\nDDL(Data Definition Language)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nCREATE Table\n`````````````\nThe Table created in SCQL is a virtual Table and needs to be mapped to the actual Table, so we extend the statement to transfer the mapping information. For more information, please read :doc:`/reference/lang/manual`.\n\n\nDQL(Data Query Language)\n~~~~~~~~~~~~~~~~~~~~~~~~\n\nAbout implementation status, please read :doc:`/reference/implementation-status`.\n\n.. note::\n    Type Null is unsupported in SCQL.\n\nFunctions different from MySQL\n``````````````````````````````\n\n+-------------------------------------+---------------------------------------------------------------------------+------------------------+------------+\n| Function Name                       | In SCQL                                                                   | In MySQL               | Note       |\n+=====================================+===========================================================================+========================+============+\n| SUM(INT)                            | returns int                                                               | returns Decimal/Double |            |\n+-------------------------------------+---------------------------------------------------------------------------+------------------------+------------+\n| Aggregation Functions With Group BY | return groups which have greater or equal ``group_by_threshold`` elements | return all groups      | for safety |\n+-------------------------------------+---------------------------------------------------------------------------+------------------------+------------+\n\nDCL(Data Control Language)\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nGRANT/REVOKE\n````````````\n\n.. note::\n\n   **CCL (Column Control List) is deprecated** and no longer used in the new architecture.\n\n   In previous versions, CCL settings were required before executing queries, and could be changed via GRANT/REVOKE. This is no longer applicable in the current version. Please refer to ``examples/opencore-demo/`` for the new access control mechanisms.\n\nType Conversion Rule\n~~~~~~~~~~~~~~~~~~~~\n\nType conversion takes place when using an operator with operands of different types, to make them compatible. Some conversions occur implicitly.\nFor example, SCQL automatically converts int to float as necessary\n\n.. code-block:: bash\n\n    user> SELECT alice.plain_long AS alice_long, bob.plain_float AS bob_float, alice.plain_long + bob.plain_float AS sum_result FROM alice INNER JOIN bob ON alice.id = bob.id;\n    +------------+-----------+------------+\n    | alice_long | bob_float | sum_result |\n    +------------+-----------+------------+\n    | -1         | -1.5      | -2.5       |\n    | 0          | 0.5       | 0.5        |\n    | 1          | 1.5       | 2.5        |\n    +------------+-----------+------------+\n\nThe following rules describe how conversion occurs in SCQL.\n\n\n\nsingle-party query\n``````````````````\nIf a query only involves one participant, SCQL will convert the query into a syntax that conforms to the participant's database (such as MySQL),\nand then dispatch it directly to the corresponding database for execution. Thus, for a single-party query, its type conversion rules are generally\nconsistent with the database used by the participant.\n\nmulti-party query\n`````````````````\nIf a query involves multiple participants, SCQL will execute type conversion by applying the following rules.\n\nCompare(>, <, <=, >=, <>, =, !=)\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n* Both arguments in a comparison operation shouldn't be string.\n* If both arguments are long, they are compared as long.\n* If one of the arguments is float or double, the other argument will be compared as double.\n\nArithmetic(+, -, \\*, /, %)\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n* Arguments of '%' operation only support type long, while other arithmetic operations support types other than type string.\n* If both arguments are long, they are calculated as long.\n* If one of the arguments is float or double, the other argument will be calculated as double.\n\nAggregation(sum, count, avg, min, max)\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n* In all aggregation functions except count, parameters should not be type string.\n* If all arguments are long, they are calculated as long.\n* If one of the arguments is float or double, the other argument will be calculated as double.\n"
  },
  {
    "path": "docs/reference/operators.md",
    "content": "# SCQL Operators Specification\n\nThis is a specification (not a kernel library) of SCQL operators, including operator signatures and semantics.\n\n## Op List\n\n<!-- Autogenerated by docgen; don't manually edit -->\n### `ACos`\n\nDefinition: return the value of arc cosine function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to arc cosine function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `ASin`\n\nDefinition: return the value of arc sine function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to arc sine function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `ATan`\n\nDefinition: return the value of arc tangent function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to arc tangent function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `ATan2`\n\nDefinition: Out = Left `ATan2` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `Abs`\n\nDefinition: return the value of Abs function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Abs function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Add`\n\nDefinition: Out = Left `Add` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `ArrowFunc`\n\nDefinition: Call arrow functions to finish calculation.\nExample:\n\n```python\nIn = {{0, 1, NULL}}\nfunc_name = \"ifnull\"\nOut = {{false, false, true}}\n```\n\n\n**Inputs:**\n1. `In`(variadic, T): Input tensors.\n\n**Outputs:**\n1. `Out`(variadic, T): Output tensors.\n\n**Attributes:**\n1. `func_name`: the name of arrow function, e.g: add/ifnull/...\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `BroadcastTo`\n\nDefinition: Broadcast Input tensor `In` to the same shape as `ShapeRefTensor`.\nExample:\n```Python\nIn = [1]\nShapeRefTensor = [a, b, c]\n# ShapeRefTensor's shape is (3, 1), broadcast In to shape (3, 1)\nOut = BroadcastTo(In, ShapeRefTensor) = [1, 1, 1]\n```\n\n\n**Inputs:**\n1. `In`(variadic, T): Input tensor\n1. `ShapeRefTensor`(single, T1): Shape reference tensor\n\n**Outputs:**\n1. `Out`(variadic, T2): Result tensor\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public\n1. `T1`: public,private,secret\n1. `T2`: public,private\n\n### `Bucket`\n\nDefinition: Put the data into buckets based on the hash value of the join key.\n\n**Inputs:**\n1. `Key`(variadic, T): Join Key Tensors\n1. `In`(variadic, T): Input Tensors\n\n**Outputs:**\n1. `Out`(variadic, T): Result\n\n**Attributes:**\n1. `input_party_codes`: List of parties the inputs belong to([PartyCodeLeft, PartyCodeRight]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `CaseWhen`\n\nThe CaseWhen operator goes through conditions and returns a value when the first condition is met (like an if-then-else statement)\n\nExample:\n\n```python\nCondition = [[true, false, false, false], [true, true, false, false]]\nValue = [[0, 0, 0, 0], [1, 1, 1, 1]]\nValueElse = [2, 2, 2, 2]\nOut = [0, 1, 2, 2]\n```\n\n\n**Inputs:**\n1. `Condition`(variadic, T): Condition tensor.\n1. `Value`(variadic, T1): Value if condition tensor is true and all previous conditions are false.\n1. `ValueElse`(single, T2): Value if all condition tensors are false.\n\n**Outputs:**\n1. `Out`(single, T3): Result tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: public,private,secret\n1. `T3`: public,private,secret\n\n### `Cast`\n\nDefinition: Cast Input tensor's data type to Output tensor's.\n\n**Inputs:**\n1. `In`(single, T): Input tensor.\n\n**Outputs:**\n1. `Out`(single, T): Output tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Ceil`\n\nDefinition: return the value of Ceil function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Ceil function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Coalesce`\n\nDefinition: Coalesce returns the first value of Exprs that is not NULL. NULL is returned only if Exprs are all NULL.\nExample:\n\n```python\nExprs[0] = {0, NULL, NULL}\nExprs[1] = {0, 1, NULL}\nOut = {0, 1, NULL}\n```\n\n\n**Inputs:**\n1. `Exprs`(variadic, T): The expressions to coalesce\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `Concat`\n\nDefinition: Given a number of tensors In (variadic, each tensor's shape must be the same in every dimension except for the axis), concat the In tensors along the axis.\nExample:\n\n```python\nIn = { {1, 2}, {2, 3, 4}, {3, 4, 5, 6} }\nOut = {1, 2, 2, 3, 4, 3, 4, 5, 6}\n```\n\n\n**Inputs:**\n1. `In`(variadic, T): Tensors to be concat.\n\n**Outputs:**\n1. `Out`(single, T): Concated Tensor.\n\n**Attributes:**\n1. `axis`: Int64. Dimension along which to concatenate.\n\n**Default Attribute Values:**\n1. `axis`: 0\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `Constant`\n\nDefinition: Make constant from attribute.\nExample:\n\n```python\nscalar = [{\"a\", \"b\", \"c\"}]\nOut = [{\"a\", \"b\", \"c\"}]\n```\n\n\n**Inputs:**\nNo input parameter.\n\n**Outputs:**\n1. `Out`(single, T): output tensor(shape [M]) from constant.\n\n**Attributes:**\n1. `scalar`: scalar attribute(with shape [M])\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private\n\n### `Copy`\n\nDefinition: Copy source tensor \"In\" to new tensor \"Out\" on target party\n\n**Inputs:**\n1. `In`(single, T1): source tensor\n\n**Outputs:**\n1. `Out`(single, T1): target tensor\n\n**Attributes:**\n1. `input_party_codes`: Input tensor `In` belongs to\n1. `output_party_codes`: Output tensor `Out` belongs to\n\n**TensorStatus(ShareType) Constraints:**\n1. `T1`: private\n\n### `Cos`\n\nDefinition: return the value of cosine function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to cosine function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Cot`\n\nDefinition: return the value of cotangent function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to cotangent function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Degrees`\n\nDefinition: return the value of Degrees function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Degrees function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Div`\n\nDefinition: Out = Left `Div` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `DumpFile`\n\nDefinition: Dump the input tensor. Note: This op will change the affected rows in the session\n\n**Inputs:**\n1. `In`(variadic, T): Tensors to be dumped.\n\n**Outputs:**\n1. `Out`(variadic, T): Tensors have been dumped.\n\n**Attributes:**\n1. `file_path`: String. Absolute file path to dump the tensors.\n1. `field_deliminator`: String. Column deliminator, e.g. `\\t`\n1. `quoting_style`: Int64. Strategies for using quotes, 0: do not use quotes; 1: use quotes for strings; 2: use quotes for all valid data\n1. `line_terminator`: String. Line terminator, e.g. `\\n`\n\n**Default Attribute Values:**\n1. `field_deliminator`: \\t\n1. `line_terminator`: \\n\n1. `quoting_style`: 0\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `Equal`\n\nDefinition: Out = Left `Equal` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `Exp`\n\nDefinition: return the value of Exp function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Exp function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Filter`\n\nDefinition: Given a boolean tensor Filter (its shape is [M]), and a number of tensors In\n(variadic, each tensor's shape must be [M]), for i in [0, M-1], keep the In tensors' element if and only if Filter[i]\nis True, output the filter result tensors Out (variadic). Example:\n\n```python\nFilter = {True, False, False, True, False}\nIn = {a, b, c, d, e}\nOut = {a, d}\n```\n\n\n**Inputs:**\n1. `Filter`(single, T1): Filter tensor.\n1. `In`(variadic, T): Tensors to be filtered.\n\n**Outputs:**\n1. `Out`(variadic, T): Output tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private,secret\n1. `T1`: public,private\n\n### `FilterByIndex`\n\nDefinition: Filter by rows index.\nExample:\n\n```python\nRowsIndexFilter = {3,1,0}\nData = [{\"a\", \"b\", \"c\", \"d\"}, {0, 1, 2, 3}]\nOut = [{\"d\", \"b\", \"a\"}, {3, 1, 0}]\n```\n\n\n**Inputs:**\n1. `RowsIndexFilter`(single, T): Rows index filter vector(shape [K][1]).\n1. `Data`(variadic, T): Input data tensor(shape [M][N]).\n\n**Outputs:**\n1. `Out`(variadic, T): Output data tensor(shape [X][N]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `Floor`\n\nDefinition: return the value of Floor function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Floor function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Greater`\n\nDefinition: Out = Left `Greater` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `GreaterEqual`\n\nDefinition: Out = Left `GreaterEqual` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `Greatest`\n\nreturn the greatest value in the given expressions.\n\n**Inputs:**\n1. `In`(variadic, T): expressions passed for getting greatest value\n\n**Outputs:**\n1. `Out`(variadic, T): greatest value\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Group`\n\nDefinition: Assign a group id(start from 0) for each input element.\nExample:\n\n```python\nKey = [{\"a\", \"c\", \"a\", \"d\"}, {0, 2, 0, 3}]\nGroupId = {0, 1, 0, 2}\nGroupNum = {3}\n```\n\n\n**Inputs:**\n1. `Key`(variadic, T): input key tensors(shape [M][1]).\n\n**Outputs:**\n1. `GroupId`(single, T): group id vector(shape [M][1]).\n1. `GroupNum`(single, T): number of groups vector(shape [1][1])\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `GroupAvg`\n\nDefinition: Aggregate `In` for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\nOut = [{1, 2, 4}, {8, 7, 5}]\n```\n\n\n**Inputs:**\n1. `GroupId`(single, T): Input group id vector(shape [M][1]).\n1. `GroupNum`(single, T): Input number of groups vector(shape [1][1]).\n1. `In`(variadic, T): Input data tensor(shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `GroupCount`\n\nDefinition: Aggregate `In` for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\nOut = [{2, 2, 1}, {2, 2, 1}]\n```\n\n\n**Inputs:**\n1. `GroupId`(single, T): Input group id vector(shape [M][1]).\n1. `GroupNum`(single, T): Input number of groups vector(shape [1][1]).\n1. `In`(variadic, T): Input data tensor(shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `GroupCountDistinct`\n\nDefinition: Aggregate `In` for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\nOut = [{2, 2, 1}, {2, 2, 1}]\n```\n\n\n**Inputs:**\n1. `GroupId`(single, T): Input group id vector(shape [M][1]).\n1. `GroupNum`(single, T): Input number of groups vector(shape [1][1]).\n1. `In`(variadic, T): Input data tensor(shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `GroupFirstOf`\n\nDefinition: Aggregate `In` for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\nOut = [{0, 1, 4}, {9, 8, 5}]\n```\n\n\n**Inputs:**\n1. `GroupId`(single, T): Input group id vector(shape [M][1]).\n1. `GroupNum`(single, T): Input number of groups vector(shape [1][1]).\n1. `In`(variadic, T): Input data tensor(shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `GroupMax`\n\nDefinition: Aggregate `In` for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\nOut = [{2, 3, 4}, {9, 8, 5}]\n```\n\n\n**Inputs:**\n1. `GroupId`(single, T): Input group id vector(shape [M][1]).\n1. `GroupNum`(single, T): Input number of groups vector(shape [1][1]).\n1. `In`(variadic, T): Input data tensor(shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `GroupMin`\n\nDefinition: Aggregate `In` for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\nOut = [{0, 1, 4}, {7, 6, 5}]\n```\n\n\n**Inputs:**\n1. `GroupId`(single, T): Input group id vector(shape [M][1]).\n1. `GroupNum`(single, T): Input number of groups vector(shape [1][1]).\n1. `In`(variadic, T): Input data tensor(shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `GroupPercentileDisc`\n\nDefinition: find the value of given percentile of `In` for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\npercent = 0.5 //the percent is 0.5, the index of each group is = ceil(0.5 * group_size) - 1\nOut = [{0, 1, 4}, {7, 6, 5}]\n```\n\n\n**Inputs:**\n1. `GroupId`(single, T): Input group id vector(shape [M][1]).\n1. `GroupNum`(single, T): Input number of groups vector(shape [1][1]).\n1. `In`(variadic, T): Input data tensor(shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\n\n**Attributes:**\n1. `percent`: Float. The percentile to calculate the range of which is [0, 1], 0 means the min one, 1 means the max one.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `GroupSecretAvg`\n\nDefinition: Calculate secret AVG for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = {0, 1, 2, 3, 4}\nOut = {1, 2, 4}\n```\n\n\n**Inputs:**\n1. `GroupId`(single, T): Input group id vector(shape [M][1]).\n1. `GroupNum`(single, T1): Input number of groups vector(shape [1][1]).\n1. `In`(single, T): Input data tensor(shape [M][1]).\n\n**Outputs:**\n1. `Out`(single, T): Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n1. `T1`: public\n\n### `GroupSecretSum`\n\nDefinition: Calculate secret SUM for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = {0, 1, 2, 3, 4}\nOut = {2, 4, 4}\n```\n\n\n**Inputs:**\n1. `GroupId`(single, T): Input group id vector(shape [M][1]).\n1. `GroupNum`(single, T1): Input number of groups vector(shape [1][1]).\n1. `In`(single, T): Input data tensor(shape [M][1]).\n\n**Outputs:**\n1. `Out`(single, T): Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n1. `T1`: public\n\n### `GroupSum`\n\nDefinition: Aggregate `In` for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\nOut = [{2, 4, 4}, {16, 14, 5}]\n```\n\n\n**Inputs:**\n1. `GroupId`(single, T): Input group id vector(shape [M][1]).\n1. `GroupNum`(single, T): Input number of groups vector(shape [1][1]).\n1. `In`(variadic, T): Input data tensor(shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `If`\n\nThe IF operator returns a value if a condition is TRUE, or another value if a condition is FALSE.\nExample:\n\n```python\nCondition = [true, false, true, true]\nValueIfTrue = [0, 0, 0, 0]\nValueIfFalse = [1, 1, 1, 1]\nOut = [0, 1, 0, 0]\n```\n\n\n**Inputs:**\n1. `Condition`(single, T): Condition tensor.\n1. `ValueIfTrue`(single, T1): Value if true tensor.\n1. `ValueIfFalse`(single, T2): Value if false tensor.\n\n**Outputs:**\n1. `Out`(single, T3): Result tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: public,private,secret\n1. `T3`: public,private,secret\n\n### `IfNull`\n\nDefinition: If Expr is NULL, return AltValue. Otherwise, return Expr.\nExample:\n\n```python\nExpr = {0, 1, NULL}\nAltValue = {10, 10, 10}\nOut = {0, 1, 10}\n```\n\n\n**Inputs:**\n1. `Expr`(single, T): The expression to test whether is NULL\n1. `AltValue`(single, T): The value to return if Expr is NULL\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `In`\n\nDefinition: Given an input tensor Left (its shape is [M]), and another input tensor Right (its shape is [N]),\ncheck whether Left's element exists in Right's elements and output a boolean tensor Out (its shape is [M]). Left and Right must be the same type.\nExample:\n\n```python\nLeft = {a, b, c, d}\nRight = {b, d, e, f, g, h}\nOut = {False, True, False, True}\n```\n\n\n**Inputs:**\n1. `Left`(single, T): First operand.\n1. `Right`(single, T1): Second operand.\n\n**Outputs:**\n1. `Out`(single, T): Output Tensor.\n\n**Attributes:**\n1. `in_type`: Int64. 0: PSI In, 1: Share In, 2: Local In\n1. `psi_algorithm`: Int64. PSI Algorithm for In. 0: Auto, 1: Ecdh, 2: Oprf;\n1. `input_party_codes`: List of parties the inputs belong to. This attribute is required if algorithm = PSI.\n1. `reveal_to`: A party can see the result. This attribute is required if algorithm = PSI.\n\n**Default Attribute Values:**\n1. `in_type`: 0\n1. `psi_algorithm`: 0\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n1. `T1`: private\n\n### `InsertTable`\n\nDefinition: Insert the input tensor to existing table in Database. Note: This op will change the affected rows in the session\n\n**Inputs:**\n1. `In`(variadic, T): Tensors to be inserted to DB table.\n\n**Outputs:**\n1. `Out`(variadic, T): Tensors have been inserted to DB table.\n\n**Attributes:**\n1. `table_name`: String. table to insert the tensors.\n1. `column_names`: String array. column names of table.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `IntDiv`\n\nDefinition: Out = Left `IntDiv` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `IsNull`\n\nDefinition: Test if Input tensor's data contains NULL.\nExample:\n\n```python\nIn = {0, 1, NULL}\nOut = {false, false, true}\n```\n\n\n**Inputs:**\n1. `In`(single, T): Input tensor.\n\n**Outputs:**\n1. `Out`(single, T): Output tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `Join`\n\nDefinition: Create Join Index based on EQ-Join, return result's corresponding rows index in the original input.\nExample:\n\n```python\n// inner join example\nLeft = {4,4,3,2,1} // shape:[M=5]\nRight = {1,3,4,5} // shape: [N=4]\njoin_type = 0\nLeftJoinIndex = {4,2,0,1}  // shape:[K=4], rows after applied filter eq-join-list={1,3,4,4}\nRightJoinIndex = {0,1,2,2} // shape:[K=4], rows after applied filter eq-join-list={1,3,4,4}\n\n// Left join example\nLeft = {4,4,3,2,1} // shape:[M=5]\nRight = {1,3,4,5} // shape: [N=4]\njoin_type = 1\nLeftJoinIndex = {4,2,0,1,3}  // shape:[K=5], rows after applied filter eq-join-list={1,3,4,4,2}\nRightJoinIndex = {0,1,2,2,null} // shape:[K=5], rows after applied filter eq-join-list={1,3,4,4,null}\n\n// Right join example\nLeft = {4,4,3,2,1} // shape:[M=5]\nRight = {1,3,4,5} // shape: [N=4]\njoin_type = 2\nLeftJoinIndex = {4,2,0,1,null}  // shape:[K=5], rows after applied filter eq-join-list={1,3,4,4,null}\nRightJoinIndex = {0,1,2,2,3} // shape:[K=5], rows after applied filter eq-join-list={1,3,4,4,5}\n\n```\n\n\n**Inputs:**\n1. `Left`(single, T1): Left vector(shape [M][1])\n1. `Right`(single, T1): Right vector(shape [N][1])\n\n**Outputs:**\n1. `LeftJoinIndex`(optional, T2): Joined rows index for left vector(shape [K][1])\n1. `RightJoinIndex`(optional, T2): Joined rows index for right vector(shape [K][1])\n\n**Attributes:**\n1. `input_party_codes`: List of parties the inputs belong to([PartyCodeLeft, PartyCodeRight]).\n1. `join_type`: Int64. 0: inner join; 1: left join; 2: right join;\n1. `psi_algorithm`: Choose PSI join algorithm, Int64. 0: Auto; 1: Ecdh; 2: Oprf;\n\n**Default Attribute Values:**\n1. `join_type`: 0\n1. `psi_algorithm`: 0\n\n**TensorStatus(ShareType) Constraints:**\n1. `T1`: private\n1. `T2`: private\n\n### `Least`\n\nreturn the least value in the given expressions.\n\n**Inputs:**\n1. `In`(variadic, T): expressions passed for getting least value\n\n**Outputs:**\n1. `Out`(variadic, T): least value\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Less`\n\nDefinition: Out = Left `Less` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `LessEqual`\n\nDefinition: Out = Left `LessEqual` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `Limit`\n\nLimit return part of data, the amount of data depends on limit attr, the offset of data depends on offset attr.\nExample:\n\n```python\noffset = 1\ncount = 2\nIn = {a, b, c, d, e}\nOut = {b, c}\n```\n\n\n**Inputs:**\n1. `In`(variadic, T): Tensors to be limited.\n\n**Outputs:**\n1. `Out`(variadic, T): Output tensor.\n\n**Attributes:**\n1. `offset`: offset in limit\n1. `count`: count in limit\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Ln`\n\nDefinition: return the value of Ln function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Ln function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Log10`\n\nDefinition: return the value of Log10 function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Log10 function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Log2`\n\nDefinition: return the value of Log2 function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Log2 function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `LogicalAnd`\n\nDefinition: Out = Left `LogicalAnd` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `LogicalOr`\n\nDefinition: Out = Left `LogicalOr` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `MakePrivate`\n\nDefinition: Convert In tensor from share status to private status.\n\n**Inputs:**\n1. `In`(variadic, T1): Input tensors.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output tensors.\n\n**Attributes:**\n1. `reveal_to`: List of parties to see the private data. If it is revealed to one party only, the other party also needs to run the op, but does not have an output. Only the reveal_to party gets the output.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T1`: secret,public\n1. `T2`: private\n\n### `MakePublic`\n\nDefinition: Convert In tensor from share/private status to public status.\n\n**Inputs:**\n1. `In`(variadic, T1): Input tensors.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output tensors.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T1`: private,secret\n1. `T2`: public\n\n### `MakeShare`\n\nDefinition: Convert In tensor from private status to share status.\n\n**Inputs:**\n1. `In`(variadic, T1): Input tensors.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output tensors.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T1`: private\n1. `T2`: secret\n\n### `Minus`\n\nDefinition: Out = Left `Minus` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `Mod`\n\nDefinition: Out = Left `Mod` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `Mul`\n\nDefinition: Out = Left `Mul` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `Not`\n\nDefinition:  Out = Not In\n\n**Inputs:**\n1. `In`(single, T): Input tensor.\n\n**Outputs:**\n1. `Out`(single, T): Output tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `NotEqual`\n\nDefinition: Out = Left `NotEqual` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `ObliviousGroupAvg`\n\nDefinition: partially aggregate `In` according to end of group indicator.\nExample:\n\n```python\nGroup = {1, 0, 0, 1, 1}\nIn = [{1, 3, 2, 4, 0}, {9, 8, 7, 6, 5}]\nOut = [{1, 3, 2.5, 3, 0}, {9, 8, 7.5, 7, 5}]\n```\n\n\n**Inputs:**\n1. `Group`(single, T): End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\n1. `In`(variadic, T): Values to be aggregated (shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Partially aggregated values (shape [M][1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `ObliviousGroupCount`\n\nDefinition: partially aggregate `In` according to end of group indicator.\nExample:\n\n```python\nGroup = {1, 0, 0, 1, 1}\nIn = [{1, 3, 2, 4, 0}, {9, 8, 7, 6, 5}]\nOut = [{1, 1, 2, 3, 1}, {1, 1, 2, 3, 1}]\n```\n\n\n**Inputs:**\n1. `Group`(single, T): End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\n1. `In`(variadic, T): Values to be aggregated (shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Partially aggregated values (shape [M][1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `ObliviousGroupMark`\n\nDefinition: generate end of group indicator `Group` based on `Key`. The operator calculates Group[i] = not_eq(Key[i+1], Key[i]).\nExample:\n\n```python\nKey = [{0, 0, 0, 1}, {0, 1, 1, 1}]\nGroup = {1, 0, 1, 1}\n\nKey = [{0, 0, 1, 2, 2}]\nGroup = {0, 1, 1, 0, 1}\n```\n\n\n**Inputs:**\n1. `Key`(variadic, T): Pre-sorted group keys (shape [M][1]).\n\n**Outputs:**\n1. `Group`(single, T): End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private,secret\n\n### `ObliviousGroupMax`\n\nDefinition: partially aggregate `In` according to end of group indicator.\nExample:\n\n```python\nGroup = {1, 0, 0, 1, 1}\nIn = [{1, 3, 2, 4, 0}, {9, 8, 7, 6, 5}]\nOut = [{1, 3, 3, 4, 0}, {9, 8, 8, 8, 5}]\n```\n\n\n**Inputs:**\n1. `Group`(single, T): End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\n1. `In`(variadic, T): Values to be aggregated (shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Partially aggregated values (shape [M][1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `ObliviousGroupMin`\n\nDefinition: partially aggregate `In` according to end of group indicator.\nExample:\n\n```python\nGroup = {1, 0, 0, 1, 1}\nIn = [{1, 3, 2, 4, 0}, {9, 8, 7, 6, 5}]\nOut = [{1, 3, 2, 2, 0}, {9, 8, 7, 6, 5}]\n```\n\n\n**Inputs:**\n1. `Group`(single, T): End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\n1. `In`(variadic, T): Values to be aggregated (shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Partially aggregated values (shape [M][1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `ObliviousGroupSum`\n\nDefinition: partially aggregate `In` according to end of group indicator.\nExample:\n\n```python\nGroup = {1, 0, 0, 1, 1}\nIn = [{1, 3, 2, 4, 0}, {9, 8, 7, 6, 5}]\nOut = [{1, 3, 5, 9, 0}, {9, 8, 15, 21, 5}]\n```\n\n\n**Inputs:**\n1. `Group`(single, T): End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\n1. `In`(variadic, T): Values to be aggregated (shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Partially aggregated values (shape [M][1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `ObliviousPercentRank`\n\nDefinition: partially aggregate `In` according to end of group indicator.\nExample:\n\n```python\nGroup = {1, 0, 0, 1, 1}\nIn = [{1, 3, 2, 4, 0}, {9, 8, 7, 6, 5}]\nOut = [{1, 0.3333, 0.6666, 1, 1, 1}, {1, 0.3333, 0.6666, 1, 1, 1}]\n```\n\n\n**Inputs:**\n1. `Group`(single, T): End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\n1. `In`(variadic, T): Values to be aggregated (shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Partially aggregated values (shape [M][1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `ObliviousPercentileDisc`\n\nDefinition: find the value of given percentile of `In` for each group.\nExample:\n\n```python\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\nthe percent is 0.5, the index of each group is = upper_bound(0.5 * group_size) - 1\nOut = [{0, 1, 4}, {7, 6, 5}]\n```\n\n\n**Inputs:**\n1. `Group`(single, T): End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\n1. `In`(variadic, T): Values to be aggregated (shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Partially aggregated values (shape [M][1]).\n\n**Attributes:**\n1. `percent`: Float. The percentile to calculate the range of which is [0, 1], 0 means the min one, 1 means the max one.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `ObliviousRank`\n\nDefinition: partially aggregate `In` according to end of group indicator.\nExample:\n\n```python\nGroup = {1, 0, 0, 1, 1}\nIn = [{1, 3, 2, 4, 0}, {9, 8, 7, 6, 5}]\nOut = [{2, 2, 1, 3, 1}, {3, 2, 1, 2, 1}]\n```\n\n\n**Inputs:**\n1. `Group`(single, T): End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\n1. `In`(variadic, T): Values to be aggregated (shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Partially aggregated values (shape [M][1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `PercentRank`\n\nDefinition: return the percent rank in each partition\n\n**Inputs:**\n1. `Key`(variadic, T): the tensors which used for sorting in partition, e.g. [2,0,4,2,3,7]\n1. `PartitionId`(single, T): the partitioned id, e.g. [0,0,0,1,1,1], the first 3 in a group and the others are in another group\n1. `PartitionNum`(single, T): the partitioned num, e.g. [2]\n\n**Outputs:**\n1. `Out`(single, T): percent rank output\n\n**Attributes:**\n1. `reverse`: string array consists of \"0\" and \"1\", \"0\" means this input tensor sort by ascending, \"1\" means this tensor sort by descending.\n\t\te.g. [\"0\",\"1\"] means the first input key sort by ascending, the second sort by descending\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `Pow`\n\nDefinition: Out = Left `Pow` Right\n\n**Inputs:**\n1. `Left`(variadic, T): First operand.\n1. `Right`(variadic, T1): Second operand.\n\n**Outputs:**\n1. `Out`(variadic, T2): Output Tensor.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: public,private,secret\n1. `T2`: private,secret\n\n### `Publish`\n\nDefinition: This operator publishes the DAG results.\n\n**Inputs:**\n1. `In`(variadic, T): Tensors to be published.\n\n**Outputs:**\n1. `Out`(variadic, T): Published name of input tensors. Tensors are in TensorOption VALUE.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `Radians`\n\nDefinition: return the value of Radians function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Radians function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Rank`\n\nDefinition: return the rank in each partition\n\n**Inputs:**\n1. `Key`(variadic, T): the tensors which used for sorting in partition, e.g. [2,0,4,2,3,7]\n1. `PartitionId`(single, T): the partitioned id, e.g. [0,0,0,1,1,1], the first 3 in a group and the others are in another group\n1. `PartitionNum`(single, T): the partitioned num, e.g. [2]\n\n**Outputs:**\n1. `Out`(single, T): rank output\n\n**Attributes:**\n1. `reverse`: string array consists of \"0\" and \"1\", \"0\" means this input tensor sort by ascending, \"1\" means this tensor sort by descending.\n\t\te.g. [\"0\",\"1\"] means the first input key sort by ascending, the second sort by descending\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `ReduceAvg`\n\nDefinition: Given a input tensor In, return the average of input tensor's elements.\nExample:\n\n```python\nIn = {1, 2, 3, 4, 5}\nOut = {3}\n\nIn = {1, 2, 3, 4}\nOut = {2.5}\n```\n\n\n**Inputs:**\n1. `In`(single, T): Tensor to be reduced (shape [M]).\n\n**Outputs:**\n1. `Out`(single, T): The average Tensor (shape [1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private,secret\n\n### `ReduceCount`\n\nDefinition: Given an input tensor In, return the count of input tensor's elements.\nExample:\n\n```python\nIn = {1, 2, 3, 4, 5, 6}\nOut = {6}\n```\n\n\n**Inputs:**\n1. `In`(single, T): Tensor to be counted (shape [M]).\n\n**Outputs:**\n1. `Out`(single, T): The counted Tensor (shape [1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private,secret\n\n### `ReduceMax`\n\nDefinition: Given a input tensor In, return the max of input tensor's elements.\nExample:\n\n```python\nIn = {1, 2, 3, 4, 5, 6}\nOut = {6}\n```\n\n\n**Inputs:**\n1. `In`(single, T): Tensor to be maxed (shape [M]).\n\n**Outputs:**\n1. `Out`(single, T): The maxed Tensor (shape [1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private,secret\n\n### `ReduceMin`\n\nDefinition: Given a input tensor In, return the min of input tensor's elements.\nExample:\n\n```python\nIn = {1, 2, 3, 4, 5, 6}\nOut = {1}\n```\n\n\n**Inputs:**\n1. `In`(single, T): Tensor to be mined (shape [M]).\n\n**Outputs:**\n1. `Out`(single, T): The mined Tensor (shape [1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private,secret\n\n### `ReducePercentileDisc`\n\nDefinition: Given a input tensor In, return the value of given percentile position.\nExample:\n\n```python\nIn = {1, 2, 3, 4, 5}\npercent = 0.5 // the position is ceil(percent * length) - 1, which is 2 here\nOut = {3}\n```\n\n\n**Inputs:**\n1. `In`(single, T): Tensor to be reduced (shape [M]).\n\n**Outputs:**\n1. `Out`(single, T): The value of given percentile position(shape [1]).\n\n**Attributes:**\n1. `percent`: Float. The percentile to calculate the range of which is [0, 1], 0 means the min one, 1 means the max one.\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private,secret\n\n### `ReduceSum`\n\nDefinition: Given an input tensor In, return the sum of input tensor's elements.\nExample:\n\n```python\nIn = {1, 2, 3, 4, 5, 6}\nOut = {21}\n```\n\n\n**Inputs:**\n1. `In`(single, T): Tensor to be summed (shape [M]).\n\n**Outputs:**\n1. `Out`(single, T): The summed Tensor (shape [1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private,secret\n\n### `Replicate`\n\nReplicate the Left with a given scale (rows of Right[0]) in interleaving way, when sending to the left party.\nAnd replicate the Right with a given scale (rows of Left[0]) in non-interleaving way, when sending to the right party.\nOutput the replication result Out. Example:\n\n```python\nLeft = {a, b, c, d} # i.e. scale = 4\nRight = {0, 1, 2} # i.e. scale = 3\nsending to the interleaving party:\n  LeftOut = {a, b, c, d, a, b, c, d, a, b, c, d}\nthe other party:\n  RightOut = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2}\n```\n\n\n**Inputs:**\n1. `Left`(variadic, T): Left tensors to be replicated.\n1. `Right`(variadic, T): Right tensors to be replicated.\n\n**Outputs:**\n1. `LeftOut`(variadic, T): Left Output tensors.\n1. `RightOut`(variadic, T): Right Output tensors.\n\n**Attributes:**\n1. `input_party_codes`: List of parties the inputs belong to([PartyCodeLeft, PartyCodeRight])\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `Round`\n\nDefinition: return the value of Round function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Round function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `RowNumber`\n\nDefinition: return the row number in each partition\n\n**Inputs:**\n1. `Key`(variadic, T): the tensors which used for sorting in partition, e.g. [2,0,4,2,3,7]\n1. `PartitionId`(single, T): the partitioned id, e.g. [0,0,0,1,1,1], the first 3 in a group and the others are in another group\n1. `PartitionNum`(single, T): the partitioned num, e.g. [2]\n\n**Outputs:**\n1. `Out`(single, T): row number output\n\n**Attributes:**\n1. `reverse`: string array consists of \"0\" and \"1\", \"0\" means this input tensor sort by ascending, \"1\" means this tensor sort by descending.\n\t\te.g. [\"0\",\"1\"] means the first input key sort by ascending, the second sort by descending\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `RunSQL`\n\nDefinition: Run a SQL statement and return a list of tensors in private status\n\n**Inputs:**\nNo input parameter.\n\n**Outputs:**\n1. `Out`(variadic, T): Result tensors of the SQL statement.\n\n**Attributes:**\n1. `sql`: SQL statement\n1. `table_refs`: tables referenced by query\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n\n### `SecretJoin`\n\nDefinition: inner join the left and right payloads based on the left and right keys.\nExample:\n\n```python\nLeftKey = {{1,2,1,3,5}} // shape:[5*1]\nRightKey = {{1,2,1,2}}  // shape:[4*1]\nLeft = {{0,1,2,3,4}}\nRight = {{0,1,2,3}}\nLeftOutput = {0,0,2,2,1,1}\nRightOutput = {0,2,0,2,1,3}\n```\n\n\n**Inputs:**\n1. `LeftKey`(variadic, T): Left keys for join\n1. `RightKey`(variadic, T): Right keys for join\n1. `Left`(optional, T): Left payloads for join\n1. `Right`(optional, T): Right payloads for join\n\n**Outputs:**\n1. `LeftOutput`(optional, T): Left payloads after join\n1. `RightOutput`(optional, T): Right payloads after join\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `Shape`\n\nDefinition: Given tensors In, return shapes of each tensor. Axis starts from 0. If axis is set, dimensions of each shape are returned. If axis is not set(default -1), shapes are returned.\nExample:\n\n```python\nIn = { {1, 2}, {2, 3}, {4, 3, 3} } # {1, 2} here is a column vector\nOut = { {2, 1}, {2, 1}, {3, 1} }\n```\n\n\n**Inputs:**\n1. `In`(variadic, T): Input Tensors\n\n**Outputs:**\n1. `Out`(variadic, T1): Shape Tensors\n\n**Attributes:**\n1. `axis`: Int64. Specific dimension of the shape.\n\n**Default Attribute Values:**\n1. `axis`: -1\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n1. `T1`: private\n\n### `Shuffle`\n\nDefinition: Shuffle `In`.\nExample:\n\n```python\nIn = [{1, 2, 3, 4}, {9, 8, 7, 6}]\nOut = [{4, 3, 2, 1}, {6, 7, 8, 9}]\n```\n\n\n**Inputs:**\n1. `In`(variadic, T): Input Value(shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Output Value(shape [M][1])\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: secret\n\n### `Sin`\n\nDefinition: return the value of sine function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to sine function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Sort`\n\nDefinition: sort `In` using `Key`.\nExample:\n\n```python\nKey = {3, 1, 2, 4}\nIn = [{3, 1, 2, 4}, {1, 2, 3, 4}, {9, 8, 7, 6}]\nOut = [{1, 2, 3, 4}, {2, 3, 1, 4}, {8, 7, 9, 6}]\n```\n\n\n**Inputs:**\n1. `Key`(variadic, T): Sort Key(shape [M][1]).\n1. `In`(variadic, T): Sort Value(shape [M][1]).\n\n**Outputs:**\n1. `Out`(variadic, T): Sorted Value(shape [M][1])\n\n**Attributes:**\n1. `reverse`: Bool. If True, the sorted tensor in descending order.\n\n**Default Attribute Values:**\n1. `reverse`: false\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private,secret\n\n### `Sqrt`\n\nDefinition: return the value of Sqrt function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to Sqrt function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Tan`\n\nDefinition: return the value of tangent function\n\n**Inputs:**\n1. `In`(single, T): the expression pass to tangent function\n\n**Outputs:**\n1. `Out`(single, T): Result\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: public,private,secret\n\n### `Unique`\n\nDefinition: Unique of Key tensor.\nExample:\n\n```python\nKey = {\"a\", \"b\", \"a\", \"d\"}\nUniqueKey = {\"a\", \"b\", \"d\"}\n```\n\n\n**Inputs:**\n1. `Key`(single, T): Input key tensors(shape [M][1]).\n\n**Outputs:**\n1. `UniqueKey`(single, T): Output unique key tensor(shape [K][1]).\n\n**TensorStatus(ShareType) Constraints:**\n1. `T`: private\n"
  },
  {
    "path": "docs/requirements.txt",
    "content": "sphinx~=8.0\nlinkify-it-py~=2.0\nmyst-parser~=4.0\nsphinx-intl~=2.3\nsphinxcontrib-mermaid~=1.0\nsecretflow-doctools~=0.8.4\nsphinx-autobuild\n"
  },
  {
    "path": "docs/topics/faq.rst",
    "content": "Frequently Asked Questions (FAQ)\n================================\n\nWe will collect some popular questions from users and update this part promptly.\n\nDeploy Issues\n-------------\n\n**Q**: System/CPU architectures supported by SCQL\n\n   System: Supports Linux and macOS with M-series chips (but macOS requires self-verification). CPU architectures: ARM and x86-64\n\n**Q**: Network timeout when pulling Go packages/GitHub packages\n\n   Add an appropriate GOPROXY\n\n**Q**: Does SCQL support outsourcing computation\n\n   Not supported for now\n\nProject Preparation Issues\n--------------------------\n\n**Q**: What is the data scale supported by SCQL?\n\n   The data scale supported by SCQL is mainly limited by resource configurations (such as network, memory, etc.) and the complexity of the query. With sufficient memory, SCQL can support intersection tasks at the scale of billions. For more detailed scenarios, a benchmark test based on the available resources is needed to determine the exact capacity.\n\n**Q**: How many participating parties does SCQL support?\n\n   SCQL does not have a limit on the number of participating parties in a project, but the number of parties that can simultaneously participate in computations is restricted based on the secure computation protocols used. Specifically, CHEETAH supports only two parties, ABY3 supports only three parties, and SEMI2K supports any number of participating parties.\n\n**Q**: Which syntax does SCQL support?\n\n   SCQL is compatible with MySQL syntax. For specific details, please refer to the documentation. For differences from MySQL syntax, please also refer to :doc:`/reference/lang/manual`.\n\n**Q**: What data sources does the engine support?\n\n   - SCQL directly supports the following data sources:\n\n   1. CSV (including local files, OSS, Minio)\n   2. MySQL and databases compatible with the MySQL protocol\n   3. Postgres\n\n   - SCQL can be extended to support the following data sources:\n\n   4. On Kuscia, additional support for ODPS. **NOTE:** When using Kuscia, users can register data source information (such as CSV file locations, database connection string of MySQL and Postgres) in Kuscia DomainData. SCQL can then access this information through Kuscia Datamesh and process it accordingly.\n   5. SCQL supports the Arrow SQL client, and users can implement their own data sources by providing an Arrow SQL server\n\nErrors Occurred During Execution\n--------------------------------\n\n**Q**: The engine reported a \"Get data timeout\" error during execution.\n\n   It is necessary to troubleshoot based on the specific situation, whether the request was intercepted by the gateway, or if there was an error in the execution of the engine on the other side. It could also be due to poor network conditions. If the issue is caused by poor network conditions, you can alleviate this error by modifying the relevant network configuration. Please refer to ``examples/opencore-demo/`` for configuration examples and :doc:`/reference/engine-config` for detailed settings.\n\n**Q**: SCQL results from executing group by related syntax are incomplete or do not match the MySQL results?\n\n   SCQL, to protect data privacy and prevent the malicious theft of data within groups, hides groups where the number of data items within a group is less than the GroupByThreshold. For specific details, please refer to :doc:`/reference/compiler-config` for the ``groupby_threshold`` configuration option (by default, groups with fewer than 4 data items are not displayed). Setting this value to 1 will disable the group filtering operation.\n\n**Q**: There are precision errors in the numerical calculations.\n\n   When SCQL enters secure MPC protocol, it needs to encode the data into Ring64 or Ring128 and then perform the secure computation. Numerical inaccuracies can occur during both the encoding and the secure computation processes, and this is unavoidable.\n\nConfiguration Issues\n--------------------\n\n**Q**: Data source configuration for different data sources.\n\n   Please refer to the deployment documentation :doc:`/reference/engine-config`.\n\n**Q**: How to configure relevant timeout settings when the network quality is poor.\n\n   In a poor network environment, you can appropriately increase **link_recv_timeout_ms** (the waiting time for the receiving party) and decrease **link_throttle_window_size** (the size of the channel sliding window). You can also appropriately configure **http_max_payload_size** (the size of individual packets when splitting data for transmission) and **link_chunked_send_parallel_size** (the number of chunks sent in parallel).\n\n   For specific configurations, please refer to the configuration documentation :doc:`/reference/engine-config`.\n"
  },
  {
    "path": "docs/topics/index.rst",
    "content": "Topics\n======\n\n.. toctree::\n    :maxdepth: 2\n\n    system/intro\n    faq\n    security/overview\n"
  },
  {
    "path": "docs/topics/security/overview.rst",
    "content": "Security overview\n=================\n\nSecurity Guarantees and Threat Model\n------------------------------------\n\nFor a single query, SCQL protects the confidentiality of data during the computation process according to the security configuration.\n\nSCQL does not protect queries as queries are designed to be public to all participants in SCQL. SCQL also does not protect the size (dimension) information of intermediate computation results.\n\nSCQL is built on top of the MPC framework `secretflow/spu`_, using a semi-honest security model. The SCQL semi-honest model assumes that all participants, including the query issuer and the data owners (SCQLEngine is deployed on each data owner), strictly abide by the protocol, but may try to learn others' private data from legitimately received messages.\n\n.. warning::\n    If you select the SEMI2K as SCQL's underlying mpc protocol, it is recommended to use the `TrustedThirdParty beaver provider`_ [#f1]_. The other beaver provider mode `TrustedFirstParty beaver provider`_ should only be used for testing and debugging purposes.\n\nLike all cryptography-based privacy-preserving computing systems, SCQL at this stage cannot solve the problem of deducing original privacy data based on the results of legal queries. The current academic solution to this problem is generally to add noise into data through differential privacy mechanism. Although security configurations allow data owners to control data access, which can alleviate risks to a certain extent, it cannot completely eliminate the risks. SCQL also does not solve the problem of participants tampering with their original input to obtain other participants' private information.\n\nThe following chapters will describe possible attack methods for inferring data from results, and give corresponding suggestions.\n\n\nSuggestions on Deployment\n-------------------------\n\nIn the current OpenCore architecture, the native compiler and engines work directly together. Please refer to ``examples/opencore-demo/`` for the recommended deployment approach and security configuration.\n\n\nRisk Statement and Suggestion for SCQL Result Inversion Attack\n--------------------------------------------------------------\n\nThe query of SCQL could be flexible, adversaries may construct adaptive attacks using multiple legit queries or one complex query to achieve the purpose of deriving the original data.\n\n\nAttack Method 1: Multi-query Attack\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe multi-query attack method includes two attack ways:\n(1) One way to obtain the other party's information is to tamper with the input content for each query, while keeping the query itself unchanged. For example, the attacker can obtain all the information of the other party's join key through multiple join queries and tampering with the content of his join key each time.\n(2) Another way is to infer the other party's private data by rewriting the query each time and comparing the results of multiple queries. For example, the attacker can use the where condition to limit the input of the aggregation function. The first time the query obtains the aggregation result of N pieces of data, the second time by changing the where condition, the aggregation result of N-1 pieces of data can be obtained, and then the attacker can obtain the original information of 1 piece of data by comparing results.\n\n\nAttack Method 2: Constructing Complex Query Attack\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis attack method is similar to the multi-query attack method, and its core idea is to write multiple queries into one complex query.\nFor example, the attacker can perform multiple comparisons on a certain column in one query, and narrow down the range of data to infer the original data.\n\n\nSuggestions\n^^^^^^^^^^^\n\n1. Each data owner is advised to give careful consideration when setting CCL for their own data.\n2. When the upstream platform integrates the SCQL system, it's recommended to add an approval process before running the query. The query is submitted to SCQL for execution only after it has been reviewed and confirmed by all data owners.\n3. It is recommended to add an audit mechanism, analyze historical queries, and track down information leakage issues.\n\n\nSystem Security Configuration Instructions\n------------------------------------------\n\n1. SCQL supports HTTPS protocol, it is recommended to enable HTTPS by default. Please see :ref:`SCQLEngine TLS Configuration <scqlengine-tls>` for details on how to enable HTTPS for SCQLEngine.\n\n\nSuggestions for upstream integrators\n------------------------------------\n\n1. It is recommended to add an approval process before submitting any queries to SCQL for execution.\n2. It is recommended to add an audit mechanism, analyze historical queries, and track down information leakage issues.\n3. It is recommended to divide the use of SCQL into two stages: development stage and production stage, and to adopt different security control measures.\n\n   * The development stage refers to the stage where the query is under development iteration. The data samples used in the development stage must be small-scale data sets that have been desensitized, de-identified, anonymized, and added with noise, aiming to quickly build the data analysis processing flow.\n   * The production stage refers to the joint analysis of the query by multiple participating parties to ensure that the task is risk-free or within the acceptance range of multiple participating parties, and is released for production operation. If the related query needs to be changed, it needs to go through multi-party audit and evaluation again. The production stage uses real data, and parties participating in the joint analysis need to: (1) conduct task evaluation and approval before the event; (2) ensure task consistency during the event, and suspend the task in a timely manner if there is any risk; (3) conduct audit after the event, and ensure that potential data leakage risks can be discovered and avoided in case of malicious behavior.\n\n\n\n.. rubric:: Footnotes\n\n.. [#f1] SPU SEMI2K protocol adopts a trusted third party for generating Beaver triples for efficiency. In the future, we will consider adding a Beaver provider implementation that does not rely on third parties.\n\n\n.. _secretflow/spu: https://github.com/secretflow/spu\n.. _TrustedThirdParty beaver provider: https://github.com/secretflow/spu/blob/270f6e90c2464a8dba7c681fddf37dcd37adfe32/libspu/spu.proto#L281\n.. _TrustedFirstParty beaver provider: https://github.com/secretflow/spu/blob/270f6e90c2464a8dba7c681fddf37dcd37adfe32/libspu/spu.proto#L279\n\n"
  },
  {
    "path": "docs/topics/system/intro.rst",
    "content": "SCQL System Overview\n====================\n\nSecure Collaborative Query Language (SCQL) is a system that allows multiple distrusting parties to run joint analysis without revealing their private data.\n\nKey Features\n------------\n\n* Semi-honest security. SCQL assumes that all parties are semi-honest.\n* Support multiple parties (N >= 1).\n* Support common SQL select syntax and functions to meet the needs of most scenarios. Please check :doc:`/reference/implementation-status` for details.\n* Practical performance. SCQL has multiple levels of performance optimization.\n* Simple structure, easy to integrate.\n\nArchitecture\n------------\n\nSCQL uses a compiler + engine architecture:\n\n- **Compiler** translates SQL queries into secure execution plans. The compiler performs query parsing, logical planning, and generates execution graphs that specify how data should be processed securely.\n- **SCQLEngine** is a hybrid MPC-plaintext execution engine that executes the plans generated by the compiler. SCQLEngine collaborates with peer engines to run the execution graph and returns query results. SCQLEngine is implemented on top of state-of-the-art MPC framework `secretflow/spu`_.\n\nHow SCQL Works\n--------------\n\nWe will show how SCQL works through the life of the following sample SCQL query Q.\n\n.. code-block:: SQL\n    :caption: SCQL query Q\n\n    SELECT AVG(bank_1.deposit), AVG(bank_2.loan)\n    FROM bank_1\n    INNER JOIN bank_2\n    ON bank_1.customer_id = bank_2.customer_id;\n\n\nTable schema\n^^^^^^^^^^^^\n\nLet's have a look at the schema of tables involved in the above query Q.\n\n.. image:: /imgs/the_life_of_scql_query_env.png\n    :alt: Table schema\n\n- ``bank_1``\n    Party Bank1 owns the table ``bank_1`` in its local database ``DB1``, which has two columns ``customer_id`` and ``deposit``.\n- ``bank_2``\n    Party Bank2 owns the table ``bank_2`` in its local database ``DB2``, which has two columns ``customer_id`` and ``loan``.\n\n\nLifetime of SCQL query\n^^^^^^^^^^^^^^^^^^^^^^\n\n.. image:: /imgs/scql_workflow.png\n    :alt: SCQL Workflow\n\nStep1. Compile SQL Query\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\nThe compiler receives the SQL query and performs the following operations:\n\n**Step1.1 Parse**\n\nParser parses the SQL query Q into an AST (Abstract Syntax Tree).\n\n**Step1.2 Plan**\n\nPlanner converts the AST into Logical Plan, and applies optimizations to the plan.\n\n.. image:: /imgs/logicalplan_for_Q.png\n    :alt: Logical Plan for Q\n\n\n**Step1.3 Translate to Operator Graph**\n\nThe compiler translates the logical plan into an operator graph\n\n**Step1.4 Visibility Analysis**\n\nThe compiler performs visibility analysis on the operator graph to determine which nodes are visible to each party, and optimize the graph accordingly.\n\n**Step1.5 Generate Execution Graph**\n\nThe compiler generates an execution graph for the query Q.\n\n.. image:: /imgs/exe_graph_for_Q.png\n    :alt: Execution Graph for Q\n\n**Step1.6 Split Execution Graph**\n\nThe compiler splits the execution graph into subgraphs based on the parties of the nodes.\n\n.. image:: /imgs/subgraph_for_Q.png\n    :alt: subgraphs\n\nStep2. Execute on Engines\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\nThe subgraphs are sent to corresponding SCQLEngine nodes. SCQLEngine cooperates with peer engines to execute the graph and produces the final result of query Q.\n\n\n.. _secretflow/spu: https://github.com/secretflow/spu\n"
  },
  {
    "path": "engine/auth/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nproto_library(\n    name = \"authorized_profile_proto\",\n    srcs = [\"authorized_profile.proto\"],\n)\n\ncc_proto_library(\n    name = \"authorized_profile_cc_proto\",\n    deps = [\":authorized_profile_proto\"],\n)\n\ncc_library(\n    name = \"authorized_profile\",\n    srcs = [\"authorized_profile.cc\"],\n    hdrs = [\"authorized_profile.h\"],\n    deps = [\n        \":authorized_profile_cc_proto\",\n        \"@com_google_protobuf//:json_util\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"authenticator\",\n    srcs = [\"authenticator.cc\"],\n    hdrs = [\"authenticator.h\"],\n    deps = [\n        \":authorized_profile\",\n        \"@abseil-cpp//absl/strings\",\n        \"@brpc//:butil\",\n        \"@yacl//yacl/crypto:key_utils\",\n    ],\n)\n\nscql_cc_test(\n    name = \"authenticator_test\",\n    srcs = [\"authenticator_test.cc\"],\n    deps = [\n        \":authenticator\",\n        # NOTE:  include @brpc//:bthread to fix circle dependency between `@brpc//:bthread` and `@brpc//:butil`\n        \"@brpc//:bthread\",\n        \"@brpc//:butil\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n"
  },
  {
    "path": "engine/auth/authenticator.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/auth/authenticator.h\"\n\n#include \"absl/strings/escaping.h\"\n#include \"butil/file_util.h\"\n#include \"yacl/base/exception.h\"\n#include \"yacl/crypto/key_utils.h\"\n\n#include \"engine/auth/authorized_profile.h\"\n\nnamespace scql::engine::auth {\n\nAuthenticator::Authenticator(AuthOption option) : option_(std::move(option)) {\n  if (option_.enable_self_auth) {\n    auto priv_key = yacl::crypto::LoadKeyFromFile(option_.private_key_pem_path);\n\n    yacl::Buffer buf = yacl::crypto::ExportPublicKeyToDerBuf(priv_key);\n    char* pkey_der = reinterpret_cast<char*>(buf.data());\n    int64_t pkey_der_len = buf.size();\n    YACL_ENFORCE(pkey_der_len > 0, \"abnormal length of extracted public key\");\n\n    self_public_key_ =\n        absl::Base64Escape({pkey_der, static_cast<size_t>(pkey_der_len)});\n  }\n\n  if (option_.enable_peer_auth) {\n    // load authorized profile\n    std::string json_str;\n    YACL_ENFORCE(\n        butil::ReadFileToString(\n            butil::FilePath(option_.authorized_profile_path), &json_str),\n        \"failed to read authorized profile file: {}\",\n        option_.authorized_profile_path);\n    auth_profile_ = std::make_unique<AuthorizedProfile>(json_str);\n  }\n}\n\nvoid Authenticator::Verify(const std::string& self_party_code,\n                           const std::vector<PartyIdentity>& parties) const {\n  if (!option_.enable_self_auth && !option_.enable_peer_auth) {\n    return;\n  }\n\n  bool self_auth_done = false;\n  for (const auto& pi : parties) {\n    if (pi.party_code == self_party_code) {\n      if (option_.enable_self_auth) {\n        YACL_ENFORCE(self_public_key_ == pi.pub_key,\n                     \"self public key mismatched\");\n        self_auth_done = true;\n      }\n    } else if (option_.enable_peer_auth) {\n      auth_profile_->VerifyParty(pi.party_code, pi.pub_key);\n    }\n  }\n\n  if (option_.enable_self_auth) {\n    YACL_ENFORCE(self_auth_done,\n                 \"self public key not found in parameter parties\");\n  }\n}\n\n}  // namespace scql::engine::auth"
  },
  {
    "path": "engine/auth/authenticator.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n#include <vector>\n\n#include \"engine/auth/authorized_profile.h\"\n\nnamespace scql::engine::auth {\n\nstruct AuthOption {\n  bool enable_self_auth;\n  bool enable_peer_auth;\n  std::string private_key_pem_path;\n  std::string authorized_profile_path;\n};\n\nstruct PartyIdentity {\n  std::string party_code;\n  std::string pub_key;\n};\n\nclass Authenticator {\n public:\n  explicit Authenticator(AuthOption option);\n\n  void Verify(const std::string& self_party_code,\n              const std::vector<PartyIdentity>& parties) const;\n\n private:\n  const AuthOption option_;\n  std::string self_public_key_;\n  std::unique_ptr<AuthorizedProfile> auth_profile_;\n};\n\n}  // namespace scql::engine::auth"
  },
  {
    "path": "engine/auth/authenticator_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/auth/authenticator.h\"\n\n#include \"butil/files/temp_file.h\"\n#include \"gtest/gtest.h\"\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine::auth {\n\nclass AuthenticatorTest : public ::testing::Test {\n protected:\n  butil::TempFile pem_file;\n  butil::TempFile profile_file;\n  std::string self_party_code;\n  std::string self_public_key;\n\n  void SetUp() override {\n    // create private key pem\n    pem_file.save(R\"pem(-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEINTZWUEn/Jt6TV9OxGxjD+6CtqKB3MtcJdFAzFUg3fk/\n-----END PRIVATE KEY-----\n)pem\");\n\n    // create authorized profile json\n    profile_file.save(\n        R\"({\n          \"driver\": {\n              \"public_key\": \"driver_public_key\"\n          },\n          \"parties\": [\n              {\n                  \"party_code\": \"alice\",\n                  \"public_key\": \"MCowBQYDK2VwAyEAPBDjfKgiUSIjVLrvsR+pxw5i9unTpr8S5BL04T13r6w=\"\n              },\n              {\n                  \"party_code\": \"bob\",\n                  \"public_key\": \"party_public_key_bob\"\n              },\n              {\n                  \"party_code\": \"carol\",\n                  \"public_key\": \"party_public_key_carol\"\n              }\n          ]\n        })\");\n\n    self_party_code = \"alice\";\n    self_public_key =\n        \"MCowBQYDK2VwAyEAPBDjfKgiUSIjVLrvsR+pxw5i9unTpr8S5BL04T13r6w=\";\n  }\n\n  AuthOption CreateAuthOption() const {\n    return AuthOption{true, true, pem_file.fname(), profile_file.fname()};\n  }\n};\n\nTEST_F(AuthenticatorTest, ConstructorInitializesCorrectly) {\n  AuthOption auth_option = CreateAuthOption();\n  EXPECT_NO_THROW(Authenticator authenticator(auth_option));\n}\n\nTEST_F(AuthenticatorTest, VerifyWorksCorrectly) {\n  AuthOption auth_option = CreateAuthOption();\n  Authenticator authenticator(auth_option);\n\n  std::vector<PartyIdentity> parties = {{self_party_code, self_public_key},\n                                        {\"bob\", \"party_public_key_bob\"},\n                                        {\"carol\", \"party_public_key_carol\"}};\n  EXPECT_NO_THROW(authenticator.Verify(self_party_code, parties));\n\n  std::vector<PartyIdentity> invalid_parties = {\n      {self_party_code, self_public_key},\n      {\"bob\", \"invalid_party_public_key_bob\"},\n      {\"carol\", \"invalid_party_public_key_carol\"}};\n  EXPECT_THROW(authenticator.Verify(self_party_code, invalid_parties),\n               ::yacl::EnforceNotMet);\n}\n\n}  // namespace scql::engine::auth\n"
  },
  {
    "path": "engine/auth/authorized_profile.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/auth/authorized_profile.h\"\n\n#include \"google/protobuf/util/json_util.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/auth/authorized_profile.pb.h\"\n\nnamespace scql {\nnamespace engine {\nnamespace auth {\n\nAuthorizedProfile::AuthorizedProfile(const std::string& json_str) {\n  pb::AuthorizedProfile profile_pb;\n  auto status =\n      google::protobuf::util::JsonStringToMessage(json_str, &profile_pb);\n  YACL_ENFORCE(\n      status.ok(),\n      \"failed to parse json to message AuthorizedProfile: json={}, error={}\",\n      json_str, status.ToString());\n\n  driver_pub_key_ = profile_pb.driver().public_key();\n\n  for (const auto& pi : profile_pb.parties()) {\n    YACL_ENFORCE(trusted_parties_.count(pi.party_code()) == 0,\n                 \"duplicate party code '{}' in AuthorizedProfile\",\n                 pi.party_code());\n    trusted_parties_[pi.party_code()] = pi.public_key();\n  }\n}\n\nvoid AuthorizedProfile::VerifyParty(const std::string& party_code,\n                                    const std::string& pub_key) const {\n  auto iter = trusted_parties_.find(party_code);\n  YACL_ENFORCE(iter != trusted_parties_.end(),\n               \"party code `{}` not found in trusted parties\", party_code);\n  YACL_ENFORCE(iter->second == pub_key,\n               \"public key mismatched for party code `{}`\", party_code);\n}\n\nvoid AuthorizedProfile::VerifyDriver(const std::string& pub_key) const {\n  YACL_ENFORCE(driver_pub_key_ == pub_key, \"driver public key mismatched\");\n}\n\n}  // namespace auth\n}  // namespace engine\n}  // namespace scql"
  },
  {
    "path": "engine/auth/authorized_profile.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <string>\n#include <unordered_map>\n\nnamespace scql::engine::auth {\nclass AuthorizedProfile {\n public:\n  explicit AuthorizedProfile(const std::string& json_str);\n\n  void VerifyParty(const std::string& party_code,\n                   const std::string& pub_key) const;\n\n  void VerifyDriver(const std::string& pub_key) const;\n\n private:\n  std::string driver_pub_key_;\n  std::unordered_map<std::string, std::string> trusted_parties_;\n};\n\n}  // namespace scql::engine::auth"
  },
  {
    "path": "engine/auth/authorized_profile.proto",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.engine.auth.pb;\n\nmessage PartyIdentity {\n  string party_code = 1;\n  // base64 encoded version of the DER encoded public key\n  string public_key = 2;\n}\n\nmessage DriverIdentity {\n  // base64 encoded version of the DER encoded public key\n  string public_key = 1;\n}\n\nmessage AuthorizedProfile {\n  DriverIdentity driver = 1;\n  repeated PartyIdentity parties = 2;\n}\n"
  },
  {
    "path": "engine/bazel/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n"
  },
  {
    "path": "engine/bazel/duckdb.BUILD",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@spulib//bazel:spu.bzl\", \"spu_cmake_external\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nfilegroup(\n    name = \"all_srcs\",\n    srcs = glob(\n        [\"**\"],\n        exclude = [\"data/**\"],\n    ),\n)\n\ncommon_cache_entries = {\n    \"BUILD_SHARED_LIBS\": \"OFF\",\n    \"BUILD_SHELL\": \"OFF\",\n    \"BUILD_UNITTESTS\": \"OFF\",\n    \"EXPORT_DLL_SYMBOLS\": \"OFF\",\n    \"ENABLE_SANITIZER\": \"OFF\",\n    \"ENABLE_UBSAN\": \"OFF\",\n    \"OPENSSL_ROOT_DIR\": \"$$EXT_BUILD_DEPS/openssl\",\n}\n\nspu_cmake_external(\n    name = \"duckdb\",\n    build_args = [\"-j 8\"],\n    cache_entries = common_cache_entries,\n    env = {\n        \"CCACHE_DISABLE\": \"1\",\n    },\n    lib_source = \":all_srcs\",\n    linkopts = [\n        \"-lm\",\n    ],\n    out_static_libs = [\n        \"libduckdb_static.a\",\n        \"libduckdb_pg_query.a\",\n        \"libduckdb_re2.a\",\n        \"libduckdb_miniz.a\",\n        \"libduckdb_fmt.a\",\n        \"libduckdb_utf8proc.a\",\n        \"libduckdb_hyperloglog.a\",\n        \"libduckdb_fastpforlib.a\",\n        \"libduckdb_mbedtls.a\",\n        \"libduckdb_fsst.a\",\n        \"libparquet_extension.a\",\n        \"libhttpfs_extension.a\",\n        \"libduckdb_skiplistlib.a\",\n        \"libduckdb_yyjson.a\",\n    ],\n    deps = [\n        \"@openssl\",\n    ],\n)\n"
  },
  {
    "path": "engine/bazel/engine_deps.bzl",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@bazel_tools//tools/build_defs/repo:git.bzl\", \"git_repository\")\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"@bazel_tools//tools/build_defs/repo:utils.bzl\", \"maybe\")\n\ndef engine_deps():\n    _com_github_gperftools_gperftools()\n    _io_opentelemetry_cpp()\n    _com_mysql()\n    _org_pocoproject_poco()\n    _org_sqlite()\n    _com_github_duckdb()\n    _org_postgres()\n    _rules_proto_grpc()\n\ndef _rules_proto_grpc():\n    maybe(\n        http_archive,\n        name = \"rules_proto_grpc\",\n        sha256 = \"2a0860a336ae836b54671cbbe0710eec17c64ef70c4c5a88ccfd47ea6e3739bd\",\n        strip_prefix = \"rules_proto_grpc-4.6.0\",\n        urls = [\n            \"https://github.com/rules-proto-grpc/rules_proto_grpc/releases/download/4.6.0/rules_proto_grpc-4.6.0.tar.gz\",\n        ],\n    )\n\ndef _com_github_gperftools_gperftools():\n    maybe(\n        http_archive,\n        name = \"com_github_gperftools_gperftools\",\n        type = \"tar.gz\",\n        strip_prefix = \"gperftools-2.15\",\n        sha256 = \"c69fef855628c81ef56f12e3c58f2b7ce1f326c0a1fe783e5cae0b88cbbe9a80\",\n        urls = [\n            \"https://github.com/gperftools/gperftools/releases/download/gperftools-2.15/gperftools-2.15.tar.gz\",\n        ],\n        build_file = \"@scql//engine/bazel:gperftools.BUILD\",\n    )\n\ndef _io_opentelemetry_cpp():\n    maybe(\n        http_archive,\n        name = \"io_opentelemetry_cpp\",\n        urls = [\n            \"https://codeload.github.com/open-telemetry/opentelemetry-cpp/tar.gz/refs/tags/v1.3.0\",\n        ],\n        sha256 = \"6a4c43b9c9f753841ebc0fe2717325271f02e2a1d5ddd0b52735c35243629ab3\",\n        strip_prefix = \"opentelemetry-cpp-1.3.0\",\n    )\n\ndef _com_mysql():\n    maybe(\n        http_archive,\n        name = \"com_mysql\",\n        urls = [\n            \"https://github.com/mysql/mysql-server/archive/refs/tags/mysql-8.0.30.tar.gz\",\n        ],\n        patch_args = [\"-p1\"],\n        patches = [\"@scql//engine/bazel:patches/mysql.patch\"],\n        sha256 = \"e76636197f9cb764940ad8d800644841771def046ce6ae75c346181d5cdd879a\",\n        strip_prefix = \"mysql-server-mysql-8.0.30\",\n        build_file = \"@scql//engine/bazel:mysql.BUILD\",\n    )\n\ndef _org_postgres():\n    maybe(\n        http_archive,\n        name = \"org_postgres\",\n        urls = [\n            \"https://ftp.postgresql.org/pub/source/v15.2/postgresql-15.2.tar.gz\",\n        ],\n        sha256 = \"eccd208f3e7412ad7bc4c648ecc87e0aa514e02c24a48f71bf9e46910bf284ca\",\n        strip_prefix = \"postgresql-15.2\",\n        build_file = \"@scql//engine/bazel:postgres.BUILD\",\n    )\n\ndef _org_pocoproject_poco():\n    maybe(\n        http_archive,\n        name = \"org_pocoproject_poco\",\n        urls = [\n            \"https://github.com/pocoproject/poco/archive/refs/tags/poco-1.12.2-release.tar.gz\",\n        ],\n        strip_prefix = \"poco-poco-1.12.2-release\",\n        sha256 = \"30442ccb097a0074133f699213a59d6f8c77db5b2c98a7c1ad9c5eeb3a2b06f3\",\n        build_file = \"@scql//engine/bazel:poco.BUILD\",\n        patch_args = [\"-p1\"],\n        patches = [\"@scql//engine/bazel:patches/poco.patch\"],\n    )\n\ndef _org_sqlite():\n    maybe(\n        http_archive,\n        name = \"org_sqlite\",\n        urls = [\n            \"https://www.sqlite.org/2020/sqlite-amalgamation-3320200.zip\",\n        ],\n        sha256 = \"7e1ebd182a61682f94b67df24c3e6563ace182126139315b659f25511e2d0b5d\",\n        strip_prefix = \"sqlite-amalgamation-3320200\",\n        build_file = \"@scql//engine/bazel:sqlite3.BUILD\",\n    )\n\ndef _com_github_duckdb():\n    maybe(\n        http_archive,\n        name = \"com_github_duckdb\",\n        urls = [\n            \"https://github.com/duckdb/duckdb/archive/refs/tags/v1.0.0.tar.gz\",\n        ],\n        patch_args = [\"-p1\"],\n        patches = [\"@scql//engine/bazel:patches/duckdb.patch\"],\n        sha256 = \"04e472e646f5cadd0a3f877a143610674b0d2bcf9f4102203ac3c3d02f1c5f26\",\n        strip_prefix = \"duckdb-1.0.0\",\n        build_file = \"@scql//engine/bazel:duckdb.BUILD\",\n    )\n"
  },
  {
    "path": "engine/bazel/gperftools.BUILD",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@rules_cc//cc:defs.bzl\", \"cc_library\")\nload(\"@rules_foreign_cc//foreign_cc:defs.bzl\", \"configure_make\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nfilegroup(\n    name = \"all_srcs\",\n    srcs = glob([\"**\"]),\n)\n\nconfigure_make(\n    name = \"gperftools_build\",\n    configure_options = [\n        \"--enable-shared=no\",\n        \"--enable-frame-pointers\",\n        \"--disable-libunwind\",\n        \"--disable-dependency-tracking\",\n    ],\n    env = {\n        \"AR\": \"\",\n    },\n    lib_source = \":all_srcs\",\n    linkopts = [\"-lpthread\"],\n    out_static_libs = [\"libtcmalloc.a\"],\n    targets = [\"-s -j4 install-libLTLIBRARIES install-perftoolsincludeHEADERS\"],\n)\n\ncc_library(\n    name = \"gperftools\",\n    deps = [\n        \"gperftools_build\",\n    ],\n)\n"
  },
  {
    "path": "engine/bazel/mysql.BUILD",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@spulib//bazel:spu.bzl\", \"spu_cmake_external\")\n\nfilegroup(\n    name = \"all_srcs\",\n    srcs = glob([\"**\"]),\n)\n\nspu_cmake_external(\n    name = \"mysqlclient\",\n    build_args = [\"-j 8\"],\n    cache_entries = {\n        \"WITHOUT_SERVER\": \"ON\",\n        \"INSTALL_PRIV_LIBDIR\": \"$$EXT_BUILD_DEPS\",\n        \"WITH_SSL\": \"$$EXT_BUILD_DEPS/openssl\",  # MySQL 8.0.30 and later could use OpenSSL3\n        \"WITH_UNIT_TESTS\": \"OFF\",\n        \"WITH_PROTOBUF\": \"system\",\n        \"WITH_BOOST\": \"$$EXT_BUILD_DEPS/include\",\n        \"CURSES_LIBRARY\": \"$$EXT_BUILD_DEPS/ncurses/lib/libcurses.a\",\n        \"CURSES_INCLUDE_PATH\": \"$$EXT_BUILD_DEPS/ncurses/include/\",\n        \"INSTALL_INCLUDEDIR\": \"include/mysql\",  # poco data needs <mysql/mysql.h>\n        \"CMAKE_C_COMPILER\": \"gcc\",\n        \"CMAKE_CXX_COMPILER\": \"g++\",\n    },\n    install = False,\n    lib_source = \":all_srcs\",\n    linkopts = [\n        \"-lpthread\",\n    ],\n    out_static_libs = [\n        \"libmysqlclient.a\",\n    ],\n    # fix install_args can't specify directory to install\n    postfix_script = \"cmake --install include --config Release --component Development --prefix $$INSTALLDIR && cp -p archive_output_directory/libmysqlclient.a $$INSTALLDIR/lib/\",\n    targets = [\n        \"mysqlclient\",\n    ],\n    visibility = [\"//visibility:public\"],\n    deps = [\n        \"@boost.endian\",\n        \"@boost.geometry\",\n        \"@boost.graph\",\n        \"@boost.multiprecision\",\n        \"@boost.spirit\",\n        \"@com_google_protobuf//:protobuf\",\n        \"@ncurses\",\n        \"@openssl\",\n        \"@zlib\",\n    ],\n)\n"
  },
  {
    "path": "engine/bazel/patches/dataproxy.patch",
    "content": "diff --git a/dataproxy_sdk/bazel/defs.bzl b/dataproxy_sdk/bazel/defs.bzl\nindex 7aac85c..3d2f7fb 100644\n--- a/dataproxy_sdk/bazel/defs.bzl\n+++ b/dataproxy_sdk/bazel/defs.bzl\n@@ -67,7 +67,7 @@ def dataproxy_cc_library(\n         linkopts = linkopts,\n         copts = _dataproxy_copts() + copts,\n         deps = deps + [\n-            \"@com_github_gabime_spdlog//:spdlog\",\n+            \"@spdlog\",\n         ],\n         **kargs\n     )"
  },
  {
    "path": "engine/bazel/patches/duckdb.patch",
    "content": "diff --git a/extension/extension_config.cmake b/extension/extension_config.cmake\nindex 8990ddc4bc..23ff3b2b50 100644\n--- a/extension/extension_config.cmake\n+++ b/extension/extension_config.cmake\n@@ -9,9 +9,10 @@\n\n # Parquet is loaded by default on every build as its a essential part of DuckDB\n duckdb_extension_load(parquet)\n+duckdb_extension_load(httpfs)\n\n # The Linux allocator has issues so we use jemalloc, but only on x86 because page sizes are fixed at 4KB.\n # If page sizes vary for an architecture (e.g., arm64), we cannot create a portable binary due to jemalloc config\n-if(OS_NAME STREQUAL \"linux\" AND (OS_ARCH STREQUAL \"amd64\" OR OS_ARCH STREQUAL \"i386\") AND NOT WASM_LOADABLE_EXTENSIONS AND NOT CLANG_TIDY AND NOT ANDROID AND NOT ZOS)\n-    duckdb_extension_load(jemalloc)\n-endif()\n+# if(OS_NAME STREQUAL \"linux\" AND (OS_ARCH STREQUAL \"amd64\" OR OS_ARCH STREQUAL \"i386\") AND NOT WASM_LOADABLE_EXTENSIONS AND NOT CLANG_TIDY AND NOT ANDROID AND NOT ZOS)\n+#     duckdb_extension_load(jemalloc)\n+# endif()\ndiff --git a/extension/httpfs/CMakeLists.txt b/extension/httpfs/CMakeLists.txt\nindex da6e6e32bf..64219c4a61 100644\n--- a/extension/httpfs/CMakeLists.txt\n+++ b/extension/httpfs/CMakeLists.txt\n@@ -39,3 +39,10 @@ install(\n   EXPORT \"${DUCKDB_EXPORT_SET}\"\n   LIBRARY DESTINATION \"${INSTALL_LIB_DIR}\"\n   ARCHIVE DESTINATION \"${INSTALL_LIB_DIR}\")\n+\n+install(FILES \"${PROJECT_SOURCE_DIR}/include/httpfs.hpp\"\n+              \"${PROJECT_SOURCE_DIR}/include/s3fs.hpp\"\n+              \"${PROJECT_SOURCE_DIR}/include/http_metadata_cache.hpp\"\n+              \"${PROJECT_SOURCE_DIR}/include/httpfs_extension.hpp\"\n+              \"${PROJECT_SOURCE_DIR}/include/crypto.hpp\"\n+              DESTINATION \"${INSTALL_INCLUDE_DIR}/duckdb/extension/httpfs/\")\n\\ No newline at end of file\ndiff --git a/third_party/re2/CMakeLists.txt b/third_party/re2/CMakeLists.txt\nindex 4440566c86..b554c39578 100644\n--- a/third_party/re2/CMakeLists.txt\n+++ b/third_party/re2/CMakeLists.txt\n@@ -99,4 +99,8 @@ install(TARGETS duckdb_re2\n         LIBRARY DESTINATION \"${INSTALL_LIB_DIR}\"\n         ARCHIVE DESTINATION \"${INSTALL_LIB_DIR}\")\n\n+install(FILES \"${PROJECT_SOURCE_DIR}/re2/re2.h\"\n+        \"${PROJECT_SOURCE_DIR}/re2/stringpiece.h\"\n+        DESTINATION \"${INSTALL_INCLUDE_DIR}/re2/\")\n+\n disable_target_warnings(duckdb_re2)\n"
  },
  {
    "path": "engine/bazel/patches/mysql.patch",
    "content": "diff --git a/cmake/boost.cmake b/cmake/boost.cmake\nindex 64e5cd6..894640a 100644\n--- a/cmake/boost.cmake\n+++ b/cmake/boost.cmake\n@@ -38,7 +38,7 @@\n # we assume that the correct version (see below)\n # is installed on the compile host in the standard location.\n\n-SET(BOOST_PACKAGE_NAME \"boost_1_77_0\")\n+SET(BOOST_PACKAGE_NAME \"boost_1_83_0\")\n SET(BOOST_TARBALL \"${BOOST_PACKAGE_NAME}.tar.bz2\")\n SET(BOOST_DOWNLOAD_URL\n   \"https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/${BOOST_TARBALL}\"\n@@ -301,9 +301,9 @@ IF(NOT BOOST_MAJOR_VERSION EQUAL 10)\n   COULD_NOT_FIND_BOOST()\n ENDIF()\n\n-IF(NOT BOOST_MINOR_VERSION EQUAL 77)\n+IF(NOT BOOST_MINOR_VERSION EQUAL 83)\n   MESSAGE(WARNING \"Boost minor version found is ${BOOST_MINOR_VERSION} \"\n-    \"we need 77\"\n+    \"we need 83\"\n     )\n   COULD_NOT_FIND_BOOST()\n ENDIF()\n"
  },
  {
    "path": "engine/bazel/patches/poco.patch",
    "content": "diff --git a/Data/MySQL/src/MySQLStatementImpl.cpp b/Data/MySQL/src/MySQLStatementImpl.cpp\nindex 7bc39e8ad..00c836c52 100644\n--- a/Data/MySQL/src/MySQLStatementImpl.cpp\n+++ b/Data/MySQL/src/MySQLStatementImpl.cpp\n@@ -153,6 +153,17 @@ void MySQLStatementImpl::bindImpl()\n \ttry\n \t{\n \t\t_stmt.execute();\n+        if (!extractions().size() && !isStoredProcedure())\n+\t\t{\n+\t\t    _metadata.reset();\n+\t\t    _metadata.init(_stmt);\n+\t\t    if (_metadata.columnsReturned() > 0)\n+            {\n+\t\t\t    _stmt.bindResult(_metadata.row());\n+                makeExtractors(_metadata.columnsReturned());\n+\t\t        fixupExtraction();\n+            }\n+\t\t}\n \t}\n \tcatch (MySQLException& exc)\n \t{\n"
  },
  {
    "path": "engine/bazel/patches/psi.patch",
    "content": "diff --git a/psi/utils/BUILD.bazel b/psi/utils/BUILD.bazel\nindex c9ca51f..c1b642d 100644\n--- a/psi/utils/BUILD.bazel\n+++ b/psi/utils/BUILD.bazel\n@@ -67,6 +67,7 @@ psi_cc_library(\n     hdrs = [\"pb_helper.h\"],\n     deps = [\n         \":io\",\n+        \"@com_google_protobuf//:protobuf\",\n         \"@yacl//yacl/base:exception\",\n     ],\n )"
  },
  {
    "path": "engine/bazel/perfetto.BUILD",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\ncc_library(\n    name = \"perfetto\",\n    srcs = [\n        \"sdk/perfetto.cc\",\n        \"sdk/perfetto.h\",\n    ],\n    hdrs = [\n        \"sdk/perfetto.h\",\n    ],\n    includes = [\"sdk\"],\n    visibility = [\"//visibility:public\"],\n)"
  },
  {
    "path": "engine/bazel/poco.BUILD",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@spulib//bazel:spu.bzl\", \"spu_cmake_external\")\n\nfilegroup(\n    name = \"all_srcs\",\n    srcs = glob([\"**\"]),\n)\n\nspu_cmake_external(\n    name = \"poco\",\n    cache_entries = {\n        \"ENABLE_DATA_SQLITE\": \"ON\",\n        \"ENABLE_DATA_MYSQL\": \"ON\",\n        # disable not required components to speed up the build process\n        \"ENABLE_DATA_ODBC\": \"OFF\",\n        \"ENABLE_DATA_POSTGRESQL\": \"ON\",\n        \"ENABLE_ACTIVERECORD\": \"OFF\",\n        \"ENABLE_ACTIVERECORD_COMPILER\": \"OFF\",\n        \"ENABLE_ENCODINGS\": \"OFF\",\n        \"ENABLE_XML\": \"OFF\",\n        \"ENABLE_JSON\": \"OFF\",\n        \"ENABLE_MONGODB\": \"OFF\",\n        \"ENABLE_REDIS\": \"OFF\",\n        \"ENABLE_PROMETHEUS\": \"OFF\",\n        \"ENABLE_UTIL\": \"OFF\",\n        \"ENABLE_NET\": \"OFF\",\n        \"ENABLE_ZIP\": \"OFF\",\n        \"ENABLE_TESTS\": \"OFF\",\n        \"ENABLE_APACHECONNECTOR\": \"OFF\",\n        \"CMAKE_FIND_DEBUG_MODE\": \"OFF\",\n        \"BUILD_SHARED_LIBS\": \"OFF\",\n        \"OPENSSL_ROOT_DIR\": \"$$EXT_BUILD_DEPS/openssl\",\n        \"MYSQL_ROOT_INCLUDE_DIRS\": \"$$EXT_BUILD_DEPS/mysqlclient/include\",\n        \"MYSQL_ROOT_LIBRARY_DIRS\": \"$$EXT_BUILD_DEPS/mysqlclient/lib\",\n        \"PostgreSQL_LIBRARY\": \"$$EXT_BUILD_DEPS/postgres/lib\",\n        \"PostgreSQL_INCLUDE_DIR\": \"$$EXT_BUILD_DEPS/postgres/include\",\n        \"CMAKE_BUILD_TYPE\": \"Release\",\n    },\n    generate_crosstool_file = False,\n    lib_source = \":all_srcs\",\n    linkopts = select({\n        \"@platforms//os:osx\": [],\n        \"//conditions:default\": [\n            \"-lrt\",\n        ],\n    }),\n    out_lib_dir = \"lib\",\n    out_static_libs = [\n        \"libPocoFoundation.a\",\n        \"libPocoData.a\",\n        \"libPocoDataMySQL.a\",\n        \"libPocoDataSQLite.a\",\n        \"libPocoDataPostgreSQL.a\",\n    ],\n    visibility = [\"//visibility:public\"],\n    deps = [\n        \"@com_mysql//:mysqlclient\",\n        \"@org_postgres//:postgres\",\n        \"@org_sqlite//:sqlite3\",\n    ],\n)\n"
  },
  {
    "path": "engine/bazel/postgres.BUILD",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@rules_foreign_cc//foreign_cc:defs.bzl\", \"configure_make\")\n\nfilegroup(\n    name = \"all_srcs\",\n    srcs = glob([\"**\"]),\n)\n\nconfigure_make(\n    name = \"postgres\",\n    args = [\"-j 8\"],\n    configure_options = [\n        \"--without-readline\",\n        \"--without-zlib\",\n    ],\n    env = {\n        \"AR\": \"ar\",\n    },\n    lib_source = \":all_srcs\",\n    out_static_libs = [\n        \"libpq.a\",\n        \"libpgcommon.a\",\n        \"libpgport.a\",\n        \"libpgport_shlib.a\",\n    ],\n    visibility = [\"//visibility:public\"],\n)\n"
  },
  {
    "path": "engine/bazel/scql.bzl",
    "content": "# Copyright 2024 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@rules_cc//cc:defs.bzl\", \"cc_test\")\n\n\"\"\"\n    scql_cc_test wraps cc_test with scql specific flags.\n\"\"\"\n\ndef scql_cc_test(\n        deps = [],\n        **kwargs):\n    cc_test(\n        deps = [\n            \"@googletest//:gtest_main\",\n        ] + deps,\n        **kwargs\n    )\n"
  },
  {
    "path": "engine/bazel/sqlite3.BUILD",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@rules_cc//cc:defs.bzl\", \"cc_library\")\n\ncc_library(\n    name = \"sqlite3\",\n    srcs = [\"sqlite3.c\"],\n    hdrs = [\n        \"sqlite3.h\",\n        \"sqlite3ext.h\",\n    ],\n    copts = [\n        \"-DSQLITE_ENABLE_STAT4\",\n    ],\n    includes = [\".\"],\n    linkopts = [\"-ldl\"],\n    linkstatic = True,\n    visibility = [\"//visibility:public\"],\n)\n"
  },
  {
    "path": "engine/core/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncc_library(\n    name = \"tensor\",\n    srcs = [\n        \"tensor.cc\",\n        \"tensor_batch_reader.cc\",\n    ],\n    hdrs = [\n        \"tensor.h\",\n        \"tensor_batch_reader.h\",\n    ],\n    deps = [\n        \":type\",\n        \"//api:core_cc_proto\",\n        \"//engine/util/disk:arrow_reader\",\n        \"//engine/util/disk:arrow_writer\",\n        \"@org_apache_arrow//:arrow\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\nscql_cc_test(\n    name = \"tensor_batch_reader_test\",\n    srcs = [\"tensor_batch_reader_test.cc\"],\n    deps = [\n        \":tensor\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/util:filepath_helper\",\n    ],\n)\n\ncc_library(\n    name = \"tensor_builder\",\n    srcs = [\"tensor_builder.cc\"],\n    hdrs = [\"tensor_builder.h\"],\n    deps = [\n        \":arrow_helper\",\n        \":tensor\",\n        \":tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"primitive_builder\",\n    srcs = [\"primitive_builder.cc\"],\n    hdrs = [\"primitive_builder.h\"],\n    deps = [\n        \":arrow_helper\",\n        \":tensor_builder\",\n        \"@org_apache_arrow//:arrow\",\n    ],\n)\n\nscql_cc_test(\n    name = \"primitive_builder_test\",\n    srcs = [\"primitive_builder_test.cc\"],\n    linkopts = [\n        \"-ldl\",\n    ],\n    deps = [\n        \":primitive_builder\",\n    ],\n)\n\ncc_library(\n    name = \"string_tensor_builder\",\n    srcs = [\"string_tensor_builder.cc\"],\n    hdrs = [\"string_tensor_builder.h\"],\n    deps = [\":tensor_builder\"],\n)\n\nscql_cc_test(\n    name = \"string_tensor_builder_test\",\n    srcs = [\"string_tensor_builder_test.cc\"],\n    linkopts = [\n        \"-ldl\",\n    ],\n    deps = [\n        \":string_tensor_builder\",\n    ],\n)\n\ncc_library(\n    name = \"arrow_helper\",\n    hdrs = [\"arrow_helper.h\"],\n    deps = [\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"tensor_constructor\",\n    srcs = [\"tensor_constructor.cc\"],\n    hdrs = [\"tensor_constructor.h\"],\n    deps = [\n        \":arrow_helper\",\n        \":tensor\",\n        \"//engine/util/disk:arrow_writer\",\n    ],\n)\n\nscql_cc_test(\n    name = \"tensor_constructor_test\",\n    srcs = [\"tensor_constructor_test.cc\"],\n    deps = [\n        \":tensor_constructor\",\n        \"//engine/util:filepath_helper\",\n    ],\n)\n\ncc_library(\n    name = \"type\",\n    srcs = [\"type.cc\"],\n    hdrs = [\"type.h\"],\n    deps = [\n        \"//api:core_cc_proto\",\n        \"@org_apache_arrow//:arrow\",\n        \"@spulib//libspu:spu\",\n    ],\n)\n\ncc_library(\n    name = \"tensor_slice\",\n    srcs = [\"tensor_slice.cc\"],\n    hdrs = [\"tensor_slice.h\"],\n    deps = [\n        \":tensor\",\n        \":tensor_constructor\",\n        \"@org_apache_arrow//:arrow\",\n    ],\n)\n"
  },
  {
    "path": "engine/core/arrow_helper.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"yacl/base/exception.h\"\n\n#ifndef THROW_IF_ARROW_NOT_OK\n#define THROW_IF_ARROW_NOT_OK(status)      \\\n  do {                                     \\\n    if (!status.ok()) {                    \\\n      YACL_THROW(\"{}\", status.ToString()); \\\n    }                                      \\\n  } while (0)\n\n#endif  // not defined(THROW_IF_ARROW_NOT_OK)\n\n#ifndef ASSIGN_OR_THROW_ARROW_STATUS\n#define ASSIGN_OR_THROW_ARROW_STATUS(lhs, rexpr)  \\\n  do {                                            \\\n    auto&& _tmp = (rexpr);                        \\\n    if (!_tmp.ok()) {                             \\\n      YACL_THROW(\"{}\", _tmp.status().ToString()); \\\n    }                                             \\\n    lhs = std::move(_tmp).ValueUnsafe();          \\\n  } while (0)\n#endif  // ASSIGN_OR_THROW_ARROW_STATUS\n"
  },
  {
    "path": "engine/core/primitive_builder.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/primitive_builder.h\"\n\nnamespace scql::engine {\n\nvoid BooleanTensorBuilder::Reserve(int64_t additional_elements) {\n  THROW_IF_ARROW_NOT_OK(builder_.Reserve(additional_elements));\n}\n\nvoid BooleanTensorBuilder::AppendNull() {\n  THROW_IF_ARROW_NOT_OK(builder_.AppendNull());\n}\n\nvoid BooleanTensorBuilder::Append(bool val) {\n  THROW_IF_ARROW_NOT_OK(builder_.Append(val));\n}\n\nvoid BooleanTensorBuilder::UnsafeAppend(bool val) {\n  builder_.UnsafeAppend(val);\n}\n\nvoid BooleanTensorBuilder::UnsafeAppendNull() { builder_.UnsafeAppendNull(); }\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/primitive_builder.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <cstdint>\n\n#include \"arrow_helper.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_builder.h\"\n\nnamespace scql::engine {\n\nclass BooleanTensorBuilder : public TensorBuilder {\n public:\n  BooleanTensorBuilder() : TensorBuilder(arrow::boolean()) {}\n\n  ~BooleanTensorBuilder() override = default;\n\n  // Ensure that there is enough space allocated to append the indicated number\n  // of elements without any further reallocation. Note that additional_capacity\n  // is relative to the current number of elements, so calls to Reserve() which\n  // are not interspersed with addition of new elements may not increase the\n  // capacity.\n  void Reserve(int64_t additional_elements);\n  void AppendNull() override;\n  void Append(bool val);\n  // Note: make sure Reserve is called to attain enough capacity before calling\n  // UnsafeAppend\n  void UnsafeAppend(bool val);\n  // Note: make sure Reserve is called to attain enough capacity before calling\n  // UnsafeAppendNull\n  void UnsafeAppendNull();\n\n private:\n  arrow::ArrayBuilder* GetBaseBuilder() override { return &builder_; }\n\n  arrow::BooleanBuilder builder_;\n};\n\ntemplate <typename T>\nclass NumericTensorBuilder : public TensorBuilder {\n public:\n  using ValueType = typename T::c_type;\n\n  NumericTensorBuilder()\n      : TensorBuilder(arrow::TypeTraits<T>::type_singleton()) {}\n\n  ~NumericTensorBuilder() override = default;\n\n  // Ensure that there is enough space allocated to append the indicated number\n  // of elements without any further reallocation. Note that additional_capacity\n  // is relative to the current number of elements, so calls to Reserve() which\n  // are not interspersed with addition of new elements may not increase the\n  // capacity.\n  void Reserve(int64_t additional_elements);\n\n  void AppendNull() override;\n\n  void Append(const ValueType val) {\n    THROW_IF_ARROW_NOT_OK(builder_.Append(val));\n  }\n\n  // Note: make sure Reserve is called to attain enough capacity before calling\n  // UnsafeAppend\n  void UnsafeAppend(const ValueType val) { builder_.UnsafeAppend(val); }\n\n  // Note: make sure Reserve is called to attain enough capacity before calling\n  // UnsafeAppendNull\n  void UnsafeAppendNull() { builder_.UnsafeAppendNull(); }\n\n private:\n  arrow::ArrayBuilder* GetBaseBuilder() override { return &builder_; }\n\n  arrow::NumericBuilder<T> builder_;\n};\n\ntemplate <typename T>\nvoid NumericTensorBuilder<T>::Reserve(int64_t additional_elements) {\n  THROW_IF_ARROW_NOT_OK(builder_.Reserve(additional_elements));\n}\n\ntemplate <typename T>\nvoid NumericTensorBuilder<T>::AppendNull() {\n  THROW_IF_ARROW_NOT_OK(builder_.AppendNull());\n}\n\ntemplate <typename T>\nTensorPtr FullNumericTensor(size_t count, typename T::c_type value) {\n  NumericTensorBuilder<T> builder;\n  builder.Reserve(count);\n  for (size_t i = 0; i < count; ++i) {\n    builder.UnsafeAppend(value);\n  }\n\n  TensorPtr result_tensor;\n  builder.Finish(&result_tensor);\n  return result_tensor;\n}\n\nusing UInt32TensorBuilder = NumericTensorBuilder<arrow::UInt32Type>;\nusing Int64TensorBuilder = NumericTensorBuilder<arrow::Int64Type>;\nusing UInt64TensorBuilder = NumericTensorBuilder<arrow::UInt64Type>;\nusing FloatTensorBuilder = NumericTensorBuilder<arrow::FloatType>;\nusing DoubleTensorBuilder = NumericTensorBuilder<arrow::DoubleType>;\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/primitive_builder_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/primitive_builder.h\"\n\n#include \"gtest/gtest.h\"\n\nnamespace scql::engine {\n\nTEST(BooleanTensorBuilderTest, appendWorks) {\n  // Given\n  BooleanTensorBuilder builder;\n\n  builder.Append(true);\n  builder.Append(false);\n  builder.Append(false);\n  builder.Append(true);\n\n  // When\n  std::shared_ptr<Tensor> tensor;\n  builder.Finish(&tensor);\n\n  // Then\n  EXPECT_EQ(tensor->Length(), 4);\n  EXPECT_EQ(tensor->GetNullCount(), 0);\n}\n\nTEST(BooleanTensorBuilderTest, AppendNullWorks) {\n  // Given\n  BooleanTensorBuilder builder;\n\n  builder.Append(true);\n  builder.AppendNull();\n  builder.Append(false);\n  builder.AppendNull();\n  builder.AppendNull();\n\n  // When\n  std::shared_ptr<Tensor> tensor;\n  builder.Finish(&tensor);\n\n  // Then\n  EXPECT_EQ(tensor->Length(), 5);\n  EXPECT_EQ(tensor->GetNullCount(), 3);\n}\n\nTEST(Int64TensorBuilderTest, works) {\n  // Given\n  Int64TensorBuilder builder;\n\n  builder.Append(1);\n  builder.Append(2);\n  builder.Append(3);\n  builder.Append(4);\n  builder.Append(5);\n  builder.AppendNull();\n  builder.Append(7);\n  builder.Append(8);\n\n  // When\n  std::shared_ptr<Tensor> tensor;\n  builder.Finish(&tensor);\n\n  // Then\n  EXPECT_EQ(tensor->Length(), 8);\n  EXPECT_EQ(tensor->GetNullCount(), 1);\n}\n\nTEST(FloatTensorBuilderTest, works) {\n  // Given\n  FloatTensorBuilder builder;\n\n  builder.Append(0.1);\n  builder.Append(0.2);\n  builder.Append(0.3);\n  builder.Append(3.1415826);\n  builder.AppendNull();\n\n  // When\n  std::shared_ptr<Tensor> tensor;\n  builder.Finish(&tensor);\n\n  // Then\n  EXPECT_EQ(tensor->Length(), 5);\n  EXPECT_EQ(tensor->GetNullCount(), 1);\n}\n\n};  // namespace scql::engine"
  },
  {
    "path": "engine/core/string_tensor_builder.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/string_tensor_builder.h\"\n\n#include \"arrow_helper.h\"\n\nnamespace scql::engine {\n\nvoid StringTensorBuilder::AppendNull() {\n  THROW_IF_ARROW_NOT_OK(builder_.AppendNull());\n}\n\nvoid StringTensorBuilder::Append(std::string_view value) {\n  THROW_IF_ARROW_NOT_OK(builder_.Append(value));\n}\n\nvoid StringTensorBuilder::Append(const char* str, std::size_t len) {\n  THROW_IF_ARROW_NOT_OK(builder_.Append(str, len));\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/string_tensor_builder.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <string_view>\n\n#include \"engine/core/tensor_builder.h\"\n\nnamespace scql::engine {\n\n/// @brief Builder for UTF8 strings tensor\nclass StringTensorBuilder : public TensorBuilder {\n public:\n  StringTensorBuilder() : TensorBuilder(arrow::large_utf8()) {}\n  ~StringTensorBuilder() = default;\n\n  void AppendNull() override;\n\n  void Append(std::string_view value);\n  void Append(const char* str, std::size_t len);\n\n private:\n  arrow::ArrayBuilder* GetBaseBuilder() override { return &builder_; }\n\n  arrow::LargeStringBuilder builder_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/string_tensor_builder_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/string_tensor_builder.h\"\n\n#include \"gtest/gtest.h\"\n\nnamespace scql::engine {\n\nTEST(StringTensorBuilderTest, works) {\n  // Given\n  StringTensorBuilder builder;\n\n  builder.Append(\"hello\");\n  builder.Append(\"scql\");\n  builder.AppendNull();\n  builder.Append(\"only only will been appened\", 4);\n\n  // When\n  std::shared_ptr<Tensor> tensor;\n  builder.Finish(&tensor);\n\n  // Then\n  EXPECT_EQ(tensor->Length(), 4);\n  EXPECT_EQ(tensor->GetNullCount(), 1);\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/tensor.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/tensor.h\"\n\n#include <cstddef>\n#include <memory>\n\n#include \"arrow/compute/cast.h\"\n#include \"spdlog/spdlog.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/core/tensor_batch_reader.h\"\n#include \"engine/core/type.h\"\n#include \"engine/util/disk/arrow_reader.h\"\n#include \"engine/util/disk/arrow_writer.h\"\n\nnamespace scql::engine {\n\nstd::shared_ptr<arrow::ChunkedArray> ConvertArrayTo(\n    const std::shared_ptr<arrow::ChunkedArray>& in_arr,\n    const std::shared_ptr<arrow::DataType>& to_type) {\n  arrow::compute::CastOptions options;\n  options.allow_decimal_truncate = true;\n  auto result = arrow::compute::Cast(in_arr, to_type, options);\n  YACL_ENFORCE(result.ok(), \"caught error while cast {} to {}: {}\",\n               in_arr->type()->ToString(), to_type->ToString(),\n               result.status().ToString());\n  return result.ValueOrDie().chunked_array();\n}\n\nstd::shared_ptr<arrow::DataType> GetExpectedConvertType(\n    const std::shared_ptr<arrow::DataType>& in_type) {\n  // try to cast decimal128(x, 0) to int64\n  if (in_type->id() == arrow::Type::DECIMAL128) {\n    auto decimal_type =\n        std::dynamic_pointer_cast<arrow::Decimal128Type>(in_type);\n    if (decimal_type->scale() == 0) {\n      return arrow::int64();\n    }\n  }\n  return in_type;\n}\n\nMemTensor::MemTensor(std::shared_ptr<arrow::ChunkedArray> chunked_arr)\n    : Tensor(pb::PrimitiveDataType::PrimitiveDataType_UNDEFINED),\n      chunked_arr_(std::move(chunked_arr)) {\n  auto to_type = GetExpectedConvertType(chunked_arr_->type());\n  if (to_type->id() != chunked_arr_->type()->id()) {\n    chunked_arr_ = ConvertArrayTo(chunked_arr_, to_type);\n  }\n  dtype_ = FromArrowDataType(chunked_arr_->type());\n  YACL_ENFORCE(dtype_ != pb::PrimitiveDataType::PrimitiveDataType_UNDEFINED,\n               \"unsupported arrow data type: {}\",\n               chunked_arr_->type()->ToString());\n}\n\nstd::shared_ptr<TensorBatchReader> MemTensor::CreateBatchReader(\n    size_t batch_size) {\n  return std::make_shared<MemTensorBatchReader>(shared_from_this(), batch_size);\n}\n\nDiskTensor::DiskTensor(std::vector<std::shared_ptr<FileArray>> file_arrays,\n                       scql::pb::PrimitiveDataType dtype,\n                       std::shared_ptr<arrow::DataType> arrow_type)\n    : Tensor(dtype),\n      file_arrays_(std::move(file_arrays)),\n      arrow_type_(std::move(arrow_type)) {\n  auto to_type = GetExpectedConvertType(arrow_type_);\n  for (auto& file_array : file_arrays_) {\n    len_ += file_array->GetLen();\n    null_count_ += file_array->GetNullCount();\n    if (to_type->id() != arrow_type_->id()) {\n      util::disk::FileBatchReader reader(file_array->GetFilePath());\n      std::string new_file_name =\n          file_array->GetFilePath().string() + \"-converted\";\n      util::disk::ArrowWriter writer(\"mock_name\", to_type, new_file_name);\n      constexpr size_t batch_size = 1000 * 1000;\n      while (true) {\n        auto batch = reader.ReadNext(batch_size);\n        if (batch == nullptr) {\n          break;\n        }\n        auto tmp = ConvertArrayTo(batch, to_type);\n        YACL_ENFORCE(tmp->type()->ToString() == to_type->ToString());\n        writer.WriteBatch(*tmp);\n      }\n      std::error_code ec;\n      std::filesystem::remove(file_array->GetFilePath(), ec);\n      if (ec.value() != 0) {\n        SPDLOG_WARN(\"can not remove tmp dir: {}, msg: {}\",\n                    file_array->GetFilePath().string(), ec.message());\n      }\n      file_array = std::make_shared<FileArray>(\n          new_file_name, file_array->GetLen(), file_array->GetNullCount());\n    }\n  }\n  if (to_type->id() != arrow_type_->id()) {\n    arrow_type_ = to_type;\n  }\n}\n\nstd::shared_ptr<TensorBatchReader> DiskTensor::CreateBatchReader(\n    size_t batch_size) {\n  return std::make_shared<DiskTensorBatchReader>(shared_from_this(),\n                                                 batch_size);\n}\n\nstd::shared_ptr<arrow::ChunkedArray> DiskTensor::ToArrowChunkedArray() const {\n  std::vector<std::shared_ptr<arrow::Array>> result_arrays;\n  for (size_t i = 0; i < GetFileNum(); i++) {\n    auto chunked_array =\n        util::disk::ReadFileArray(GetFileArray(i)->GetFilePath());\n    if (chunked_array == nullptr) {\n      continue;\n    }\n    result_arrays.insert(result_arrays.end(), chunked_array->chunks().begin(),\n                         chunked_array->chunks().end());\n  }\n  return std::make_shared<arrow::ChunkedArray>(result_arrays, arrow_type_);\n}\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/tensor.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <filesystem>\n#include <iostream>\n#include <memory>\n#include <utility>\n\n#include \"arrow/chunked_array.h\"\n\n#include \"api/core.pb.h\"\n\nnamespace scql::engine {\n\nclass TensorBatchReader;\nclass DiskTensorBatchReader;\nclass MemTensorBatchReader;\nclass DiskTensorSlice;\nclass MemTensorSlice;\n\n/// @brief A Tensor represents a column of a relation\nclass Tensor {\n public:\n  Tensor(const Tensor&) = delete;\n  Tensor& operator=(const Tensor&) = delete;\n  explicit Tensor(pb::PrimitiveDataType dtype) : dtype_(dtype) {}\n\n  virtual int64_t Length() const = 0;\n\n  // return the total number of nulls\n  virtual int64_t GetNullCount() const = 0;\n\n  /// @returns the data type of tensor element\n  pb::PrimitiveDataType Type() const { return dtype_; }\n\n  virtual std::shared_ptr<arrow::DataType> ArrowType() const = 0;\n\n  /// @returns as arrow chunked array\n  virtual std::shared_ptr<arrow::ChunkedArray> ToArrowChunkedArray() const = 0;\n\n  /// @return as tensor batch reader\n  virtual std::shared_ptr<TensorBatchReader> CreateBatchReader(\n      size_t batch_size) = 0;\n\n  virtual bool IsBucketTensor() = 0;\n\n protected:\n  pb::PrimitiveDataType dtype_;\n};\n\nclass MemTensor : public Tensor,\n                  public std::enable_shared_from_this<MemTensor> {\n public:\n  explicit MemTensor(std::shared_ptr<arrow::ChunkedArray> chunked_arr);\n\n  int64_t Length() const override { return chunked_arr_->length(); }\n\n  // return the total number of nulls\n  int64_t GetNullCount() const override { return chunked_arr_->null_count(); }\n\n  /// @returns as arrow chunked array\n  std::shared_ptr<arrow::ChunkedArray> ToArrowChunkedArray() const override {\n    return chunked_arr_;\n  }\n\n  std::shared_ptr<arrow::DataType> ArrowType() const override {\n    return chunked_arr_->type();\n  }\n\n  std::shared_ptr<TensorBatchReader> CreateBatchReader(\n      size_t batch_size) override;\n\n  // for now, no memory bucket tensor\n  bool IsBucketTensor() override { return false; }\n\n private:\n  std::shared_ptr<arrow::ChunkedArray> chunked_arr_;\n};\n\nclass FileArray {\n public:\n  FileArray(std::filesystem::path file_path, size_t len, size_t null_count)\n      : file_path_(std::move(file_path)), len_(len), null_count_(null_count) {}\n  ~FileArray() {\n    std::error_code ec;\n    std::filesystem::remove(file_path_, ec);\n    if (ec.value() != 0) {\n      // avoid throwing fmt exceptions in the destructor\n      std::cerr << \"can not remove tmp dir: \" << file_path_.string()\n                << \", msg: \" << ec.message() << \"\\n\";\n    }\n  }\n  std::filesystem::path GetFilePath() const { return file_path_; }\n  size_t GetLen() const { return len_; }\n  size_t GetNullCount() const { return null_count_; }\n\n private:\n  std::filesystem::path file_path_;\n  size_t len_;\n  size_t null_count_;\n};\n\nclass DiskTensor : public Tensor,\n                   public std::enable_shared_from_this<DiskTensor> {\n public:\n  explicit DiskTensor(std::vector<std::shared_ptr<FileArray>> file_arrays,\n                      scql::pb::PrimitiveDataType dtype,\n                      std::shared_ptr<arrow::DataType> arrow_type);\n\n  int64_t Length() const override { return len_; }\n\n  // return the total number of nulls\n  int64_t GetNullCount() const override { return null_count_; }\n\n  /// @returns as arrow chunked array\n  std::shared_ptr<arrow::ChunkedArray> ToArrowChunkedArray() const override;\n\n  std::shared_ptr<arrow::DataType> ArrowType() const override {\n    return arrow_type_;\n  }\n\n  std::shared_ptr<TensorBatchReader> CreateBatchReader(\n      size_t batch_size) override;\n\n  bool IsBucketTensor() override { return is_bucket_tensor_; }\n\n protected:\n  void SetAsBucketTensor() { is_bucket_tensor_ = true; }\n\n private:\n  std::shared_ptr<FileArray> GetFileArray(size_t i) const {\n    return file_arrays_[i];\n  }\n  size_t GetFileNum() const { return file_arrays_.size(); }\n\n private:\n  friend class DiskTensorBatchReader;\n  friend class DiskTensorSlice;\n  friend class DiskBucketTensorConstructor;\n  size_t len_ = 0;\n  size_t null_count_ = 0;\n  bool is_bucket_tensor_ = false;\n  std::vector<std::shared_ptr<FileArray>> file_arrays_;\n  std::shared_ptr<arrow::DataType> arrow_type_;\n};\n\n// TODO(xiaoyuan): move to tensor builder\nstruct TensorBuildOptions {\n  bool dump_to_disk;\n  std::filesystem::path dump_dir;\n  size_t max_row_num_one_file = std::numeric_limits<int64_t>::max();\n};\n\nusing TensorPtr = std::shared_ptr<Tensor>;\nusing RepeatedPbTensor = google::protobuf::RepeatedPtrField<pb::Tensor>;\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/core/tensor_batch_reader.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/tensor_batch_reader.h\"\n\nnamespace scql::engine {\n\nstd::shared_ptr<arrow::ChunkedArray> MemTensorBatchReader::Next() {\n  if (offset_ >= arrays_->length()) {\n    return nullptr;\n  }\n  auto array = arrays_->Slice(offset_, batch_size_);\n  offset_ += array->length();\n  return array;\n}\n\nstd::shared_ptr<arrow::ChunkedArray> DiskTensorBatchReader::Next() {\n  if (offset_ >= tensor_->Length() || tensor_->GetFileNum() == 0) {\n    return nullptr;\n  }\n  if (cur_reader_ == nullptr) {\n    if (!FreshReader()) {\n      return nullptr;\n    }\n  }\n  size_t num_to_read = batch_size_;\n  std::vector<std::shared_ptr<arrow::Array>> result_arrays;\n  while (num_to_read > 0) {\n    auto chunked_array = cur_reader_->ReadNext(num_to_read);\n    if (chunked_array == nullptr) {\n      if (!FreshReader()) {\n        break;\n      }\n      chunked_array = cur_reader_->ReadNext(num_to_read);\n    }\n    num_to_read -= chunked_array->length();\n    offset_ += chunked_array->length();\n    result_arrays.insert(result_arrays.end(), chunked_array->chunks().begin(),\n                         chunked_array->chunks().end());\n  }\n  if (result_arrays.empty()) {\n    return nullptr;\n  }\n  return std::make_shared<arrow::ChunkedArray>(result_arrays);\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/tensor_batch_reader.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"arrow/table.h\"\n\n#include \"engine/core/tensor.h\"\n#include \"engine/util/disk/arrow_reader.h\"\n\nnamespace scql::engine {\n\nclass TensorBatchReader {\n public:\n  explicit TensorBatchReader(size_t batch_size)\n      : batch_size_(batch_size), offset_(0) {}\n  /// @returns tensor ptr, return nullptr if no more batches\n  virtual std::shared_ptr<arrow::ChunkedArray> Next() = 0;\n\n protected:\n  size_t batch_size_;\n  int64_t offset_;\n};\n\nclass MemTensorBatchReader : public TensorBatchReader {\n public:\n  explicit MemTensorBatchReader(\n      const std::shared_ptr<MemTensor>& tensor,\n      size_t batch_size = std::numeric_limits<size_t>::max())\n      : TensorBatchReader(batch_size), arrays_(tensor->ToArrowChunkedArray()) {}\n\n  MemTensorBatchReader(const MemTensorBatchReader&) = delete;\n\n  MemTensorBatchReader& operator=(const MemTensorBatchReader&) = delete;\n\n  std::shared_ptr<arrow::ChunkedArray> Next() override;\n\n private:\n  std::shared_ptr<arrow::ChunkedArray> arrays_;\n};\n\nclass DiskTensorBatchReader : public TensorBatchReader {\n public:\n  explicit DiskTensorBatchReader(\n      std::shared_ptr<DiskTensor> tensor,\n      size_t batch_size = std::numeric_limits<size_t>::max())\n      : TensorBatchReader(batch_size), tensor_(std::move(tensor)) {}\n\n  DiskTensorBatchReader(const DiskTensorBatchReader&) = delete;\n\n  DiskTensorBatchReader& operator=(const DiskTensorBatchReader&) = delete;\n\n  std::shared_ptr<arrow::ChunkedArray> Next() override;\n\n private:\n  bool FreshReader() {\n    // skip empty files;\n    while (cur_file_idx_ < tensor_->GetFileNum() &&\n           tensor_->GetFileArray(cur_file_idx_)->GetLen() == 0) {\n      cur_file_idx_++;\n    }\n    if (cur_file_idx_ >= tensor_->GetFileNum()) {\n      return false;\n    }\n    cur_reader_ = std::make_shared<util::disk::FileBatchReader>(\n        tensor_->GetFileArray(cur_file_idx_)->GetFilePath());\n    cur_file_idx_++;\n    return true;\n  }\n\n private:\n  std::shared_ptr<DiskTensor> tensor_;\n  // file index\n  size_t cur_file_idx_ = 0;\n  std::shared_ptr<util::disk::FileBatchReader> cur_reader_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/tensor_batch_reader_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/tensor_batch_reader.h\"\n\n#include <filesystem>\n\n#include \"arrow/testing/random.h\"\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/filepath_helper.h\"\n\nnamespace scql::engine {\n\nclass TensorBatchReaderTest : public ::testing::Test {\n public:\n  TensorBatchReaderTest()\n      : tmp_dir_(util::ScopedDir(util::CreateDirWithRandSuffix(\n            std::filesystem::temp_directory_path(), \"test\"))) {}\n\n protected:\n  util::ScopedDir tmp_dir_;\n};\n\nTEST_F(TensorBatchReaderTest, ReadDisk) {\n  constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n  arrow::ArrayVector arrays;\n  constexpr size_t array_num = 3;\n  constexpr size_t array_num_rows = 1000;\n  auto field = std::make_shared<arrow::Field>(\"a\", arrow::int64());\n  for (size_t i = 0; i < array_num; ++i) {\n    arrays.push_back(\n        arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n  }\n  arrow::FieldVector fields = {field};\n  auto schema = std::make_shared<arrow::Schema>(fields);\n  auto chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n  TensorPtr ptr;\n  {\n    TensorWriter writer(schema, tmp_dir_.path().string());\n    auto write_num = writer.WriteBatch(*chunked_array);\n    ASSERT_EQ(array_num * array_num_rows, write_num);\n    writer.Finish(&ptr);\n  }\n  size_t batch_size = 400;\n  auto reader = ptr->CreateBatchReader(batch_size);\n  size_t offset = 0;\n  while (true) {\n    auto array = reader->Next();\n    if (!array) {\n      break;\n    }\n    offset += array->length();\n    ASSERT_TRUE(batch_size == static_cast<size_t>(array->length()) ||\n                offset == array_num * array_num_rows);\n  }\n  ASSERT_TRUE(offset == array_num * array_num_rows);\n}\n\nTEST_F(TensorBatchReaderTest, ReadDiskOnlyOneBatch) {\n  constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n  arrow::ArrayVector arrays;\n  constexpr size_t array_num = 1;\n  constexpr size_t array_num_rows = 1000;\n  auto field = std::make_shared<arrow::Field>(\"a\", arrow::int64());\n  for (size_t i = 0; i < array_num; ++i) {\n    arrays.push_back(\n        arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n  }\n  arrow::FieldVector fields = {field};\n  auto schema = std::make_shared<arrow::Schema>(fields);\n  auto chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n  TensorPtr ptr;\n  {\n    TensorWriter writer(schema, tmp_dir_.path().string());\n    auto write_num = writer.WriteBatch(*chunked_array);\n    ASSERT_EQ(array_num * array_num_rows, write_num);\n    writer.Finish(&ptr);\n  }\n  size_t batch_size = 1000;\n  auto reader = ptr->CreateBatchReader(batch_size);\n  size_t offset = 0;\n  while (true) {\n    auto array = reader->Next();\n    if (!array) {\n      break;\n    }\n    offset += array->length();\n    ASSERT_TRUE(batch_size == static_cast<size_t>(array->length()) ||\n                offset == array_num * array_num_rows);\n  }\n  ASSERT_TRUE(offset == array_num * array_num_rows);\n}\n\nTEST_F(TensorBatchReaderTest, ReadMemory) {\n  constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n  arrow::ArrayVector arrays;\n  constexpr size_t array_num = 3;\n  constexpr size_t array_num_rows = 1000;\n  auto field = std::make_shared<arrow::Field>(\"a\", arrow::int64());\n  for (size_t i = 0; i < array_num; ++i) {\n    arrays.push_back(\n        arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n  }\n  arrow::FieldVector fields = {field};\n  auto schema = std::make_shared<arrow::Schema>(fields);\n  auto chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n  TensorPtr ptr = std::make_shared<MemTensor>(chunked_array);\n  size_t batch_size = 400;\n  auto reader = ptr->CreateBatchReader(batch_size);\n  size_t offset = 0;\n  while (true) {\n    auto array = reader->Next();\n    if (!array) {\n      break;\n    }\n    offset += array->length();\n    ASSERT_TRUE(batch_size == static_cast<size_t>(array->length()) ||\n                offset == array_num * array_num_rows);\n  }\n  ASSERT_TRUE(offset == array_num * array_num_rows);\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/tensor_builder.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/tensor_builder.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n\nnamespace scql::engine {\n\nvoid TensorBuilder::Finish(std::shared_ptr<Tensor>* out) {\n  FinishInternal();\n\n  auto result = arrow::ChunkedArray::Make(chunks_, type_);\n\n  std::shared_ptr<arrow::ChunkedArray> chunked_arr;\n  THROW_IF_ARROW_NOT_OK(std::move(result).Value(&chunked_arr));\n\n  *out = TensorFrom(std::move(chunked_arr));\n  chunks_.clear();\n}\n\nvoid TensorBuilder::FinishInternal() {\n  std::shared_ptr<arrow::Array> arr;\n\n  arrow::ArrayBuilder* builder = GetBaseBuilder();\n  THROW_IF_ARROW_NOT_OK(builder->Finish(&arr));\n  builder->Reset();\n\n  chunks_.push_back(std::move(arr));\n}\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/core/tensor_builder.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"arrow/builder.h\"\n\n#include \"engine/core/tensor.h\"\n\nnamespace scql::engine {\n\nclass TensorBuilder {\n public:\n  explicit TensorBuilder(std::shared_ptr<arrow::DataType> type)\n      : type_(std::move(type)) {}\n\n  virtual ~TensorBuilder() = default;\n\n  // Return result of builder as a Tensor object.\n  void Finish(std::shared_ptr<Tensor>* out);\n  std::shared_ptr<arrow::DataType> Type() { return GetBaseBuilder()->type(); }\n\n  // Append a null value to builder\n  virtual void AppendNull() = 0;\n\n protected:\n  void FinishInternal();\n  virtual arrow::ArrayBuilder* GetBaseBuilder() = 0;\n\n  arrow::ArrayVector chunks_;\n  std::shared_ptr<arrow::DataType> type_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/core/tensor_constructor.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/tensor_constructor.h\"\n\n#include <memory>\n\n#include \"arrow/array/array_base.h\"\n#include \"arrow/ipc/json_simple.h\"\n#include \"arrow/record_batch.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor.h\"\n#include \"engine/core/type.h\"\n\nnamespace scql::engine {\n\nTensorPtr TensorFrom(const std::shared_ptr<arrow::DataType>& dtype,\n                     const std::string& json) {\n  using arrow::ipc::internal::json::ChunkedArrayFromJSON;\n\n  std::shared_ptr<arrow::ChunkedArray> chunked_arr;\n  THROW_IF_ARROW_NOT_OK(ChunkedArrayFromJSON(\n      dtype, std::vector<std::string>{json}, &chunked_arr));\n\n  return std::make_shared<MemTensor>(std::move(chunked_arr));\n}\n\nTensorPtr TensorFrom(std::shared_ptr<arrow::ChunkedArray> arrays) {\n  return std::make_shared<MemTensor>(arrays);\n}\n\nTensorPtr ConcatTensors(const std::vector<TensorPtr>& tensors) {\n  for (const auto& tensor : tensors) {\n    YACL_ENFORCE(typeid(*tensor) == typeid(MemTensor));\n  }\n  arrow::ArrayVector arrays;\n  for (const auto& tensor : tensors) {\n    auto tmp_v = tensor->ToArrowChunkedArray();\n    arrays.insert(arrays.end(), tmp_v->chunks().begin(), tmp_v->chunks().end());\n  }\n  return std::make_shared<MemTensor>(\n      arrow::ChunkedArray::Make(arrays).ValueOrDie());\n}\n\n// create a new writer to write when current writer is null or current writer is\n// full\nvoid TensorWriter::FreshCurWriter() {\n  if (current_writer_ != nullptr) {\n    auto file_array = std::make_shared<FileArray>(\n        current_writer_->GetFilePath(), current_writer_->GetRowNum(),\n        current_writer_->GetNullCount());\n    file_arrays_.push_back(file_array);\n  }\n  std::filesystem::path path = parent_path_ / std::to_string(file_index_);\n  current_writer_ = std::make_shared<util::disk::ArrowWriter>(schema_, path);\n  file_index_++;\n}\n\nsize_t TensorWriter::WriteBatch(const arrow::RecordBatch& batch) {\n  if (batch.num_rows() == 0) {\n    return 0;\n  }\n  if (current_writer_ == nullptr) {\n    FreshCurWriter();\n  }\n  auto num_to_write = batch.num_rows();\n  if (num_to_write <= max_single_file_row_num_ -\n                          static_cast<int64_t>(current_writer_->GetRowNum())) {\n    current_writer_->WriteBatch(batch);\n    return batch.num_rows();\n  }\n  while (num_to_write > 0) {\n    if (static_cast<int64_t>(current_writer_->GetRowNum()) >=\n        max_single_file_row_num_) {\n      FreshCurWriter();\n    }\n    auto write_row_num = max_single_file_row_num_ -\n                         static_cast<int64_t>(current_writer_->GetRowNum());\n    auto sliced_batch =\n        batch.Slice(batch.num_rows() - num_to_write, write_row_num);\n    num_to_write -= write_row_num;\n    current_writer_->WriteBatch(*sliced_batch);\n  }\n  return batch.num_rows();\n}\n\nsize_t TensorWriter::WriteBatch(const arrow::ChunkedArray& batch) {\n  size_t offset = 0;\n  for (int i = 0; i < batch.num_chunks(); ++i) {\n    std::vector<std::shared_ptr<arrow::Array>> arrays = {batch.chunk(i)};\n    offset += WriteBatch(\n        *arrow::RecordBatch::Make(schema_, batch.chunk(i)->length(), arrays));\n  }\n  return offset;\n}\n\nvoid TensorWriter::Finish(std::shared_ptr<Tensor>* out) {\n  // add last file to tensor\n  if (current_writer_ != nullptr && current_writer_->GetRowNum() > 0) {\n    auto file_array = std::make_shared<FileArray>(\n        current_writer_->GetFilePath(), current_writer_->GetRowNum(),\n        current_writer_->GetNullCount());\n    file_arrays_.push_back(file_array);\n  }\n\n  current_writer_.reset();\n  *out = std::make_shared<DiskTensor>(\n      file_arrays_, FromArrowDataType(schema_->field(0)->type()),\n      schema_->field(0)->type());\n}\n\nvoid DiskBucketTensorConstructor::InsertBucket(const TensorPtr& tensor,\n                                               size_t bucket_index) {\n  InsertBucket(tensor->ToArrowChunkedArray(), bucket_index);\n}\n\nvoid DiskBucketTensorConstructor::InsertBucket(\n    const std::shared_ptr<arrow::ChunkedArray>& arrays, size_t bucket_index) {\n  writers_[bucket_index]->WriteBatch(*arrays);\n}\n\nvoid DiskBucketTensorConstructor::Finish(TensorPtr* tensor) {\n  std::vector<std::shared_ptr<FileArray>> file_arrays(writers_.size());\n  for (size_t j = 0; j < file_arrays.size(); j++) {\n    auto file_array = std::make_shared<FileArray>(writers_[j]->GetFilePath(),\n                                                  writers_[j]->GetRowNum(),\n                                                  writers_[j]->GetNullCount());\n    file_arrays[j] = file_array;\n  }\n  auto type = writers_[0]->GetSchema()->field(0)->type();\n  // remove writers to call ipc writer close()\n  writers_.clear();\n  auto disk_tensor =\n      std::make_shared<DiskTensor>(file_arrays, dtype_, data_type_);\n  disk_tensor->SetAsBucketTensor();\n  *tensor = std::move(disk_tensor);\n}\n\nvoid MemoryBucketTensorConstructor::InsertBucket(const TensorPtr& tensor,\n                                                 size_t bucket_index) {\n  InsertBucket(tensor->ToArrowChunkedArray(), bucket_index);\n}\nvoid MemoryBucketTensorConstructor::InsertBucket(\n    const std::shared_ptr<arrow::ChunkedArray>& arrays, size_t bucket_index) {\n  array_vecs_[bucket_index].push_back(arrays);\n}\nvoid MemoryBucketTensorConstructor::Finish(TensorPtr* tensor) {\n  arrow::ArrayVector arrays;\n  for (const auto& arrs : array_vecs_) {\n    for (const auto& tmp_v : arrs) {\n      arrays.insert(arrays.end(), tmp_v->chunks().begin(),\n                    tmp_v->chunks().end());\n    }\n  }\n  // TODO: no bucket mem tensor for now, add it later if needed\n  *tensor = std::make_shared<MemTensor>(\n      arrow::ChunkedArray::Make(arrays).ValueOrDie());\n}\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/core/tensor_constructor.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <cstddef>\n#include <memory>\n#include <vector>\n\n#include \"yacl/base/exception.h\"\n\n#include \"engine/core/tensor.h\"\n#include \"engine/util/disk/arrow_writer.h\"\n\nnamespace scql::engine {\n\n/// @brief construct tensor from json\n/// It would be helpful in unittests.\n/// TODO(shunde.csd): use wrapped data type instead of arrow::DataType directly\nTensorPtr TensorFrom(const std::shared_ptr<arrow::DataType>& dtype,\n                     const std::string& json);\n\nTensorPtr TensorFrom(std::shared_ptr<arrow::ChunkedArray> arrays);\n\nTensorPtr ConcatTensors(const std::vector<TensorPtr>& tensors);\n\nclass TensorWriter {\n public:\n  TensorWriter(\n      std::shared_ptr<arrow::Schema> schema, std::filesystem::path parent_path,\n      int64_t max_single_file_row_num = std::numeric_limits<int64_t>::max())\n      : schema_(std::move(schema)),\n        parent_path_(std::move(parent_path)),\n        max_single_file_row_num_(max_single_file_row_num) {\n    YACL_ENFORCE(std::filesystem::is_empty(parent_path_),\n                 \"directory for tensor writer must be empty: {}\",\n                 parent_path_.string());\n  }\n\n  TensorWriter(\n      const std::string& field_name,\n      const std::shared_ptr<arrow::DataType>& data_type,\n      std::filesystem::path parent_path,\n      int64_t max_single_file_row_num = std::numeric_limits<int64_t>::max())\n      : parent_path_(std::move(parent_path)),\n        max_single_file_row_num_(max_single_file_row_num) {\n    YACL_ENFORCE(std::filesystem::is_empty(parent_path_),\n                 \"directory for tensor writer must be empty: {}\",\n                 parent_path_.string());\n    auto field = std::make_shared<arrow::Field>(field_name, data_type);\n    arrow::FieldVector fields = {field};\n    schema_ = std::make_shared<arrow::Schema>(fields);\n  }\n\n  virtual ~TensorWriter() = default;\n\n  size_t WriteBatch(const arrow::RecordBatch& batch);\n  size_t WriteBatch(const arrow::ChunkedArray& batch);\n  // Return result of builder as a Tensor object.\n  void Finish(std::shared_ptr<Tensor>* out);\n\n  std::shared_ptr<arrow::Schema> GetSchema() const { return schema_; }\n\n  size_t GetFilesNum() const { return file_arrays_.size(); }\n\n private:\n  void FreshCurWriter();\n\n  std::shared_ptr<arrow::Schema> schema_;\n  const std::filesystem::path parent_path_;\n  std::vector<std::shared_ptr<FileArray>> file_arrays_;\n  std::shared_ptr<util::disk::ArrowWriter> current_writer_;\n  size_t file_index_ = 0;\n\n  // max row num in a single file, if more than this, will create a new file\n  // to write.\n  const int64_t max_single_file_row_num_;\n};\n\nclass BucketTensorConstructor {\n public:\n  virtual void InsertBucket(const TensorPtr& tensor, size_t bucket_index) = 0;\n  virtual void InsertBucket(const std::shared_ptr<arrow::ChunkedArray>& arrays,\n                            size_t bucket_index) = 0;\n  virtual void Finish(TensorPtr* tensor) = 0;\n};\n\nclass DiskBucketTensorConstructor : public BucketTensorConstructor {\n public:\n  DiskBucketTensorConstructor(const std::string& field_name,\n                              const std::shared_ptr<arrow::DataType>& data_type,\n                              scql::pb::PrimitiveDataType dtype,\n                              const std::string& file_path, size_t bucket_num)\n      : writers_(bucket_num), data_type_(data_type), dtype_(dtype) {\n    for (size_t j = 0; j < bucket_num; j++) {\n      writers_[j] = std::make_shared<util::disk::ArrowWriter>(\n          field_name, data_type,\n          std::filesystem::path(file_path) / std::to_string(j));\n    }\n  }\n  void InsertBucket(const TensorPtr& tensor, size_t bucket_index) override;\n  void InsertBucket(const std::shared_ptr<arrow::ChunkedArray>& arrays,\n                    size_t bucket_index) override;\n  void Finish(TensorPtr* tensor) override;\n\n private:\n  std::vector<std::shared_ptr<util::disk::ArrowWriter>> writers_;\n  std::shared_ptr<arrow::DataType> data_type_;\n  scql::pb::PrimitiveDataType dtype_;\n};\n\nclass MemoryBucketTensorConstructor : public BucketTensorConstructor {\n public:\n  explicit MemoryBucketTensorConstructor(size_t bucket_num)\n      : array_vecs_(bucket_num) {}\n  void InsertBucket(const TensorPtr& tensor, size_t bucket_index) override;\n  void InsertBucket(const std::shared_ptr<arrow::ChunkedArray>& arrays,\n                    size_t bucket_index) override;\n  void Finish(TensorPtr* tensor) override;\n\n private:\n  std::vector<arrow::ChunkedArrayVector> array_vecs_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/tensor_constructor_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/tensor_constructor.h\"\n\n#include <filesystem>\n\n#include \"arrow/compute/cast.h\"\n#include \"arrow/testing/random.h\"\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/util/filepath_helper.h\"\n\nnamespace scql::engine {\n\nclass ReaderWriterTest : public ::testing::Test {\n public:\n  ReaderWriterTest()\n      : tmp_dir_(util::ScopedDir(util::CreateDirWithRandSuffix(\n            std::filesystem::temp_directory_path(), \"test\"))) {}\n\n protected:\n  util::ScopedDir tmp_dir_;\n};\n\nTEST_F(ReaderWriterTest, WriteOneFile) {\n  constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n  arrow::ArrayVector arrays;\n  constexpr size_t array_num = 3;\n  constexpr size_t array_num_rows = 1000;\n  auto field = std::make_shared<arrow::Field>(\"a\", arrow::int64());\n  for (size_t i = 0; i < array_num; ++i) {\n    arrays.push_back(\n        arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n  }\n  arrow::FieldVector fields = {field};\n  auto schema = std::make_shared<arrow::Schema>(fields);\n  auto expected_chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n  TensorPtr ptr;\n  {\n    TensorWriter writer(schema, tmp_dir_.path().string());\n    auto write_num = writer.WriteBatch(*expected_chunked_array);\n    ASSERT_EQ(array_num * array_num_rows, write_num);\n    writer.Finish(&ptr);\n    ASSERT_EQ(write_num, ptr->Length());\n  }\n  {\n    auto chunked_array = ptr->ToArrowChunkedArray();\n    ASSERT_EQ(array_num * array_num_rows, chunked_array->length());\n    EXPECT_TRUE(chunked_array->Equals(expected_chunked_array))\n        << \"\\nexpect=\" << expected_chunked_array->ToString()\n        << \"\\n,but got=\" << chunked_array->ToString();\n  }\n}\n\nTEST_F(ReaderWriterTest, WriteMultiFile) {\n  constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n  arrow::ArrayVector arrays;\n  constexpr size_t array_num = 3;\n  constexpr size_t array_num_rows = 1000;\n  auto field = std::make_shared<arrow::Field>(\"a\", arrow::large_utf8());\n  for (size_t i = 0; i < array_num; ++i) {\n    arrays.push_back(\n        arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n  }\n  arrow::FieldVector fields = {field};\n  auto schema = std::make_shared<arrow::Schema>(fields);\n  auto expected_chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n  TensorPtr ptr;\n  {\n    size_t file_row_num = 500;\n    TensorWriter writer(schema, tmp_dir_.path().string(), file_row_num);\n    auto write_num = writer.WriteBatch(*expected_chunked_array);\n    ASSERT_EQ(array_num * array_num_rows, write_num);\n    writer.Finish(&ptr);\n    // 1000 / 500 * 3 = 6\n    ASSERT_EQ(6, writer.GetFilesNum());\n  }\n  {\n    auto chunked_array = ptr->ToArrowChunkedArray();\n    ASSERT_EQ(array_num * array_num_rows, chunked_array->length());\n    EXPECT_TRUE(chunked_array->Equals(expected_chunked_array))\n        << \"\\nexpect=\" << expected_chunked_array->ToString()\n        << \"\\n,but got=\" << chunked_array->ToString();\n  }\n}\n\nTEST_F(ReaderWriterTest, WriteNullArray) {\n  arrow::ArrayVector arrays;\n  auto expected_chunked_array =\n      std::make_shared<arrow::ChunkedArray>(arrays, arrow::large_utf8());\n  TensorPtr ptr;\n  {\n    size_t file_row_num = 500;\n    TensorWriter writer(\"a\", arrow::large_utf8(), tmp_dir_.path().string(),\n                        file_row_num);\n    auto write_num = writer.WriteBatch(*expected_chunked_array);\n    ASSERT_EQ(0, write_num);\n    writer.Finish(&ptr);\n    ASSERT_EQ(0, writer.GetFilesNum());\n  }\n  {\n    auto chunked_array = ptr->ToArrowChunkedArray();\n    ASSERT_EQ(0, chunked_array->length());\n    EXPECT_TRUE(chunked_array->Equals(expected_chunked_array))\n        << \"\\nexpect=\" << expected_chunked_array->ToString()\n        << \"\\n,but got=\" << chunked_array->ToString();\n  }\n}\n\nTEST_F(ReaderWriterTest, TypeConvert) {\n  constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n  arrow::ArrayVector arrays;\n  constexpr size_t array_num = 3;\n  constexpr size_t array_num_rows = 1000;\n  auto field = std::make_shared<arrow::Field>(\"a\", arrow::decimal128(5, 0));\n  for (size_t i = 0; i < array_num; ++i) {\n    arrays.push_back(\n        arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n  }\n  arrow::FieldVector fields = {field};\n  auto schema = std::make_shared<arrow::Schema>(fields);\n  auto expected_chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n  TensorPtr ptr;\n  {\n    TensorWriter writer(schema, tmp_dir_.path().string());\n    auto write_num = writer.WriteBatch(*expected_chunked_array);\n    ASSERT_EQ(array_num * array_num_rows, write_num);\n    writer.Finish(&ptr);\n    ASSERT_EQ(write_num, ptr->Length());\n    ASSERT_EQ(arrow::int64(), ptr->ArrowType());\n  }\n  {\n    auto chunked_array = ptr->ToArrowChunkedArray();\n    arrow::compute::CastOptions options;\n    options.allow_decimal_truncate = true;\n    auto result =\n        arrow::compute::Cast(expected_chunked_array, arrow::int64(), options)\n            .ValueOrDie()\n            .chunked_array();\n    ASSERT_EQ(array_num * array_num_rows, chunked_array->length());\n    EXPECT_TRUE(chunked_array->Equals(result))\n        << \"\\nexpect=\" << result->ToString()\n        << \"\\n,but got=\" << chunked_array->ToString();\n  }\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/tensor_slice.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/tensor_slice.h\"\n\nnamespace scql::engine {\n\nTensorPtr DiskTensorSlice::Next() {\n  // specially for tensor created by bucket op\n  if (tensor_->IsBucketTensor()) {\n    if (cur_slice_idx_ >= tensor_->GetFileNum()) {\n      return TensorFrom(\n          arrow::ChunkedArray::MakeEmpty(tensor_->ArrowType()).ValueOrDie());\n    }\n    auto cur_path = {tensor_->GetFileArray(cur_slice_idx_)};\n    auto result_tensor = std::make_shared<DiskTensor>(cur_path, tensor_->Type(),\n                                                      tensor_->ArrowType());\n    cur_slice_idx_++;\n    offset_ += result_tensor->Length();\n    return result_tensor;\n  }\n\n  if (offset_ >= tensor_->Length() || tensor_->GetFileNum() == 0) {\n    return TensorFrom(\n        arrow::ChunkedArray::MakeEmpty(tensor_->ArrowType()).ValueOrDie());\n  }\n\n  auto arrays = reader_->Next();\n  if (arrays == nullptr) {\n    return TensorFrom(\n        arrow::ChunkedArray::MakeEmpty(tensor_->ArrowType()).ValueOrDie());\n  }\n  offset_ += arrays->length();\n  return TensorFrom(arrays);\n}\n\nstd::shared_ptr<TensorSlice> CreateTensorSlice(std::shared_ptr<Tensor>& tensor,\n                                               size_t slice_size) {\n  if (typeid(*tensor) == typeid(MemTensor)) {\n    std::shared_ptr<MemTensor> mem_tensor =\n        std::dynamic_pointer_cast<MemTensor>(tensor);\n    return std::make_shared<MemTensorSlice>(mem_tensor);\n  } else if (typeid(*tensor) == typeid(DiskTensor)) {\n    std::shared_ptr<DiskTensor> disk_tensor =\n        std::dynamic_pointer_cast<DiskTensor>(tensor);\n    return std::make_shared<DiskTensorSlice>(disk_tensor);\n  }\n  YACL_THROW(\"unsupported tensor type\");\n}\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/tensor_slice.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <algorithm>\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_batch_reader.h\"\n#include \"engine/core/tensor_constructor.h\"\n\nnamespace scql::engine {\n\nclass TensorSlice {\n public:\n  explicit TensorSlice(size_t slice_size) {}\n  /// @returns tensor ptr, return nullptr if no more slices\n  virtual TensorPtr Next() = 0;\n  virtual size_t GetSliceNum() = 0;\n  virtual TensorPtr GetSlice(size_t i) = 0;\n};\n\nclass MemTensorSlice : public TensorSlice {\n public:\n  explicit MemTensorSlice(\n      std::shared_ptr<MemTensor> tensor,\n      size_t slice_size = std::numeric_limits<int64_t>::max())\n      : TensorSlice(slice_size),\n        tensor_(std::move(tensor)),\n        slice_size_(slice_size) {\n    reader_ = std::make_shared<MemTensorBatchReader>(tensor_, slice_size);\n  }\n  MemTensorSlice(MemTensorSlice&) = delete;\n\n  TensorPtr Next() override {\n    auto arrays = reader_->Next();\n    if (arrays == nullptr) {\n      arrays =\n          arrow::ChunkedArray::MakeEmpty(tensor_->ArrowType()).ValueOrDie();\n    }\n    return TensorFrom(arrays);\n  }\n\n  size_t GetSliceNum() override { return 1; }\n  TensorPtr GetSlice(size_t i) override {\n    if (i == 0 && static_cast<size_t>(tensor_->Length()) < slice_size_) {\n      return tensor_;\n    }\n    YACL_THROW(\"unsupport get specific slice\");\n  }\n\n private:\n  std::shared_ptr<MemTensorBatchReader> reader_;\n  std::shared_ptr<MemTensor> tensor_;\n  size_t slice_size_;\n};\n\nclass DiskTensorSlice : public TensorSlice {\n public:\n  explicit DiskTensorSlice(\n      std::shared_ptr<DiskTensor> tensor,\n      size_t slice_size = std::numeric_limits<int64_t>::max())\n      : TensorSlice(slice_size),\n        tensor_(std::move(tensor)),\n        slice_size_(slice_size) {\n    if (!tensor_->IsBucketTensor()) {\n      reader_ = std::make_shared<DiskTensorBatchReader>(tensor_, slice_size);\n    }\n  }\n  DiskTensorSlice(DiskTensorSlice&) = delete;\n\n  TensorPtr Next() override;\n\n  size_t GetSliceNum() override {\n    if (tensor_->IsBucketTensor()) {\n      return tensor_->GetFileNum();\n    }\n    return 1;\n  }\n\n  TensorPtr GetSlice(size_t i) override {\n    // specially for tensor created by bucket op\n    if (tensor_->IsBucketTensor()) {\n      if (i >= tensor_->GetFileNum()) {\n        return TensorFrom(\n            arrow::ChunkedArray::MakeEmpty(tensor_->ArrowType()).ValueOrDie());\n      }\n      auto cur_path = {tensor_->GetFileArray(i)};\n      auto result_tensor = std::make_shared<DiskTensor>(\n          cur_path, tensor_->Type(), tensor_->ArrowType());\n      return result_tensor;\n    }\n    if (i == 0 && static_cast<size_t>(tensor_->Length()) < slice_size_) {\n      return tensor_;\n    }\n    YACL_THROW(\"unsupport get specific slice\");\n  }\n\n private:\n  std::shared_ptr<DiskTensor> tensor_;\n  std::shared_ptr<DiskTensorBatchReader> reader_;\n  // file index\n  size_t cur_slice_idx_ = 0;\n  int64_t offset_ = 0;\n  size_t slice_size_;\n};\n\nstd::shared_ptr<TensorSlice> CreateTensorSlice(\n    std::shared_ptr<Tensor>& tensor,\n    size_t slice_size = std::numeric_limits<int64_t>::max());\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/core/type.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/type.h\"\n\nnamespace scql::engine {\n\n// TODO(shunde.csd): try to simplify the following data type conversion via\n// macro instructions.\n\npb::PrimitiveDataType FromArrowDataType(\n    const std::shared_ptr<arrow::DataType>& dtype) {\n  pb::PrimitiveDataType ty;\n  switch (dtype->id()) {\n    case arrow::Type::BOOL:\n      ty = pb::PrimitiveDataType::BOOL;\n      break;\n    case arrow::Type::UINT8:\n    case arrow::Type::INT8:\n    case arrow::Type::UINT16:\n    case arrow::Type::INT16:\n    case arrow::Type::INT32:\n      ty = pb::PrimitiveDataType::INT32;\n      break;\n    case arrow::Type::UINT32:\n    case arrow::Type::INT64:\n    case arrow::Type::UINT64:\n      ty = pb::PrimitiveDataType::INT64;\n      break;\n    case arrow::Type::FLOAT:\n      ty = pb::PrimitiveDataType::FLOAT32;\n      break;\n    case arrow::Type::DOUBLE:\n      ty = pb::PrimitiveDataType::FLOAT64;\n      break;\n    case arrow::Type::DECIMAL128: {\n      auto decimal_type =\n          std::dynamic_pointer_cast<arrow::Decimal128Type>(dtype);\n      if (decimal_type->scale() == 0) {\n        ty = pb::PrimitiveDataType::INT64;\n      } else {\n        ty = pb::PrimitiveDataType::PrimitiveDataType_UNDEFINED;\n      }\n      break;\n    }\n    case arrow::Type::STRING:\n    case arrow::Type::LARGE_STRING:\n      ty = pb::PrimitiveDataType::STRING;\n      break;\n    default:\n      ty = pb::PrimitiveDataType::PrimitiveDataType_UNDEFINED;\n  }\n  return ty;\n}\n\nstd::shared_ptr<arrow::DataType> ToArrowDataType(pb::PrimitiveDataType dtype) {\n  std::shared_ptr<arrow::DataType> dt;\n  switch (dtype) {\n    case pb::PrimitiveDataType::INT8:\n      dt = arrow::int8();\n      break;\n    case pb::PrimitiveDataType::INT16:\n      dt = arrow::int16();\n      break;\n    case pb::PrimitiveDataType::INT32:\n      dt = arrow::int32();\n      break;\n    case pb::PrimitiveDataType::INT64:\n      dt = arrow::int64();\n      break;\n    case pb::PrimitiveDataType::BOOL:\n      dt = arrow::boolean();\n      break;\n    case pb::PrimitiveDataType::FLOAT32:\n      dt = arrow::float32();\n      break;\n    case pb::PrimitiveDataType::FLOAT64:\n      dt = arrow::float64();\n      break;\n    case pb::PrimitiveDataType::STRING:\n      // scql use large_utf8 to support large scale string\n      dt = arrow::large_utf8();\n      break;\n    case pb::PrimitiveDataType::DATETIME:\n    case pb::PrimitiveDataType::TIMESTAMP:\n      // scql using int64 seconds to represent datetime/timestamp\n      dt = arrow::int64();\n      break;\n    default:\n      dt = nullptr;\n  }\n  return dt;\n}\n\nspu::PtType ArrowDataTypeToSpuPtType(\n    const std::shared_ptr<arrow::DataType>& dtype) {\n  spu::PtType pt;\n  switch (dtype->id()) {\n    case arrow::Type::BOOL:\n      pt = spu::PT_I1;\n      break;\n    case arrow::Type::UINT8:\n      pt = spu::PT_U8;\n      break;\n    case arrow::Type::INT8:\n      pt = spu::PT_I8;\n      break;\n    case arrow::Type::UINT16:\n      pt = spu::PT_U16;\n      break;\n    case arrow::Type::INT16:\n      pt = spu::PT_I16;\n      break;\n    case arrow::Type::UINT32:\n      pt = spu::PT_U32;\n      break;\n    case arrow::Type::INT32:\n      pt = spu::PT_I32;\n      break;\n    case arrow::Type::UINT64:\n      pt = spu::PT_U64;\n      break;\n    case arrow::Type::INT64:\n      pt = spu::PT_I64;\n      break;\n    case arrow::Type::FLOAT:\n      pt = spu::PT_F32;\n      break;\n    case arrow::Type::DOUBLE:\n      pt = spu::PT_F64;\n      break;\n    default:\n      pt = spu::PT_INVALID;\n  }\n  return pt;\n}\n\nstd::shared_ptr<arrow::DataType> SpuPtTypeToArrowDataType(spu::PtType pt_type) {\n  std::shared_ptr<arrow::DataType> dt;\n  switch (pt_type) {\n    case spu::PT_I8:\n      dt = arrow::int8();\n      break;\n    case spu::PT_U8:\n      dt = arrow::uint8();\n      break;\n    case spu::PT_I16:\n      dt = arrow::int16();\n      break;\n    case spu::PT_U16:\n      dt = arrow::uint16();\n      break;\n    case spu::PT_I32:\n      dt = arrow::int32();\n      break;\n    case spu::PT_U32:\n      dt = arrow::uint32();\n      break;\n    case spu::PT_I64:\n      dt = arrow::int64();\n      break;\n    case spu::PT_U64:\n      dt = arrow::uint64();\n      break;\n    case spu::PT_F32:\n      dt = arrow::float32();\n      break;\n    case spu::PT_F64:\n      dt = arrow::float64();\n      break;\n    case spu::PT_I1:\n      dt = arrow::boolean();\n      break;\n    default:\n      dt = nullptr;\n  }\n  return dt;\n}\n\nspu::PtType DataTypeToSpuPtType(pb::PrimitiveDataType dtype) {\n  spu::PtType pt;\n  switch (dtype) {\n    case pb::PrimitiveDataType::INT8:\n      pt = spu::PT_I8;\n      break;\n    case pb::PrimitiveDataType::INT16:\n      pt = spu::PT_I16;\n      break;\n    case pb::PrimitiveDataType::INT32:\n      pt = spu::PT_I32;\n      break;\n    case pb::PrimitiveDataType::INT64:\n    case pb::PrimitiveDataType::DATETIME:\n    case pb::PrimitiveDataType::TIMESTAMP:\n      pt = spu::PT_I64;\n      break;\n    case pb::PrimitiveDataType::BOOL:\n      pt = spu::PT_I1;\n      break;\n    case pb::PrimitiveDataType::FLOAT32:\n      pt = spu::PT_F32;\n      break;\n    case pb::PrimitiveDataType::FLOAT64:\n      pt = spu::PT_F64;\n      break;\n    default:\n      pt = spu::PT_INVALID;\n  }\n  return pt;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/core/type.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"arrow/type.h\"\n#include \"libspu/spu.h\"\n\n#include \"api/core.pb.h\"\n\nnamespace scql::engine {\n\nenum class Visibility {\n  Unknown = 0,\n  Private,\n  Public,\n  Secret,\n};\n\n/// @returns pb::PrimitiveDataType::PrimitiveDataType_UNDEFINED\n/// if @param[in] dtype is not supported\npb::PrimitiveDataType FromArrowDataType(\n    const std::shared_ptr<arrow::DataType>& dtype);\n\n/// @brief convert scql primitive data type to arrow data type\n/// @returns nullptr if @param[in] dtype is not supported\nstd::shared_ptr<arrow::DataType> ToArrowDataType(pb::PrimitiveDataType dtype);\n\n/// @brief convert arrow data type to spu plaintext type enum\n/// @returns spu::PT_INVALID if @param[in] dtype is not supported\nspu::PtType ArrowDataTypeToSpuPtType(\n    const std::shared_ptr<arrow::DataType>& dtype);\n\n/// @brief convert spu plaintext type enum to arrow data type\n/// @returns nullptr if @param[in] pt_type is not supported\nstd::shared_ptr<arrow::DataType> SpuPtTypeToArrowDataType(spu::PtType pt_type);\n\n/// @brief convert scql primitive data type to spu plaintext type enum\n/// @returns spu::PT_INVALID if @param[in] dtype is not supported\nspu::PtType DataTypeToSpuPtType(pb::PrimitiveDataType dtype);\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@rules_cc//cc:defs.bzl\", \"cc_proto_library\")\nload(\"@rules_proto//proto:defs.bzl\", \"proto_library\")\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncc_library(\n    name = \"datasource_adaptor\",\n    srcs = [\"datasource_adaptor.cc\"],\n    hdrs = [\"datasource_adaptor.h\"],\n    deps = [\n        \"//api:core_cc_proto\",\n        \"//engine/core:arrow_helper\",\n        \"//engine/core:tensor\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/exe:flags\",\n        \"//engine/util:concurrent_queue\",\n        \"//engine/util:filepath_helper\",\n        \"//engine/util:tensor_util\",\n        \"@spdlog\",\n    ],\n)\n\ncc_library(\n    name = \"arrow_sql_adaptor\",\n    srcs = [\"arrow_sql_adaptor.cc\"],\n    hdrs = [\"arrow_sql_adaptor.h\"],\n    deps = [\n        \":datasource_adaptor\",\n        \":datasource_cc_proto\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/util:spu_io\",\n        \"@org_apache_arrow//:arrow\",\n        \"@org_apache_arrow//:arrow_flight\",\n    ],\n)\n\ncc_binary(\n    name = \"arrow_sql_adaptor_test\",\n    srcs = [\"arrow_sql_adaptor_test.cc\"],\n    deps = [\n        \":arrow_sql_adaptor\",\n        \"@abseil-cpp//absl/flags:flag\",\n        \"@abseil-cpp//absl/flags:parse\",\n        \"@googletest//:gtest\",\n    ],\n)\n\ncc_library(\n    name = \"odbc_connector\",\n    srcs = [\"odbc_connector.cc\"],\n    hdrs = [\"odbc_connector.h\"],\n    deps = [\n        \"@org_pocoproject_poco//:poco\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"odbc_adaptor\",\n    srcs = [\"odbc_adaptor.cc\"],\n    hdrs = [\"odbc_adaptor.h\"],\n    deps = [\n        \":datasource_adaptor\",\n        \":datasource_cc_proto\",\n        \":odbc_connector\",\n        \"//engine/core:primitive_builder\",\n        \"//engine/core:string_tensor_builder\",\n        \"//engine/util:spu_io\",\n        \"@org_pocoproject_poco//:poco\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\nscql_cc_test(\n    name = \"odbc_adaptor_sqlite_test\",\n    srcs = [\"odbc_adaptor_sqlite_test.cc\"],\n    deps = [\n        \":odbc_adaptor\",\n        \"//engine/operator:test_util\",\n    ],\n)\n\n# binary for integration test\n# run odbc_adaptor_mysql_test with `/engine/datasource/run_odbc_adaptor_mysql_test.sh`\ncc_binary(\n    name = \"odbc_adaptor_mysql_test\",\n    srcs = [\"odbc_adaptor_mysql_test.cc\"],\n    deps = [\n        \":odbc_adaptor\",\n        \"//engine/operator:test_util\",\n        \"@abseil-cpp//absl/flags:flag\",\n        \"@abseil-cpp//absl/flags:parse\",\n        \"@googletest//:gtest\",\n    ],\n)\n\ncc_library(\n    name = \"router\",\n    hdrs = [\"router.h\"],\n    deps = [\":datasource_cc_proto\"],\n)\n\nproto_library(\n    name = \"embed_router_proto\",\n    srcs = [\"embed_router.proto\"],\n    deps = [\":datasource_proto\"],\n)\n\ncc_proto_library(\n    name = \"embed_router_cc_proto\",\n    deps = [\":embed_router_proto\"],\n)\n\nproto_library(\n    name = \"datasource_proto\",\n    srcs = [\"datasource.proto\"],\n)\n\ncc_proto_library(\n    name = \"datasource_cc_proto\",\n    deps = [\":datasource_proto\"],\n)\n\ncc_library(\n    name = \"embed_router\",\n    srcs = [\"embed_router.cc\"],\n    hdrs = [\"embed_router.h\"],\n    deps = [\n        \":csvdb_conf_cc_proto\",\n        \":embed_router_cc_proto\",\n        \":router\",\n        \"@abseil-cpp//absl/container:flat_hash_map\",\n        \"@abseil-cpp//absl/strings\",\n        \"@com_google_protobuf//:json_util\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\nscql_cc_test(\n    name = \"embed_router_test\",\n    srcs = [\"embed_router_test.cc\"],\n    deps = [\n        \":embed_router\",\n    ],\n)\n\ncc_library(\n    name = \"datasource_adaptor_mgr\",\n    srcs = [\"datasource_adaptor_mgr.cc\"],\n    hdrs = [\"datasource_adaptor_mgr.h\"],\n    deps = [\n        \":arrow_sql_adaptor_factory\",\n        \":csvdb_adaptor_factory\",\n        \":datasource_adaptor\",\n        \":datasource_cc_proto\",\n        \":dm_adaptor_factory\",\n        \":dp_adaptor_factory\",\n        \":odbc_adaptor_factory\",\n        \"@abseil-cpp//absl/container:flat_hash_map\",\n        \"@abseil-cpp//absl/synchronization\",\n    ],\n)\n\ncc_library(\n    name = \"datasource_adaptor_factory\",\n    hdrs = [\"datasource_adaptor_factory.h\"],\n    deps = [\n        \":datasource_adaptor\",\n        \":datasource_cc_proto\",\n    ],\n)\n\ncc_library(\n    name = \"arrow_sql_adaptor_factory\",\n    hdrs = [\"arrow_sql_adaptor_factory.h\"],\n    deps = [\n        \":arrow_sql_adaptor\",\n        \":datasource_adaptor_factory\",\n    ],\n)\n\ncc_library(\n    name = \"odbc_adaptor_factory\",\n    srcs = [\"odbc_adaptor_factory.cc\"],\n    hdrs = [\"odbc_adaptor_factory.h\"],\n    deps = [\n        \":datasource_adaptor_factory\",\n        \":odbc_adaptor\",\n    ],\n)\n\nproto_library(\n    name = \"csvdb_conf_proto\",\n    srcs = [\"csvdb_conf.proto\"],\n)\n\ncc_proto_library(\n    name = \"csvdb_conf_cc_proto\",\n    deps = [\":csvdb_conf_proto\"],\n)\n\ncc_library(\n    name = \"duckdb_wrapper\",\n    srcs = [\"duckdb_wrapper.cc\"],\n    hdrs = [\"duckdb_wrapper.h\"],\n    deps = [\n        \":csvdb_conf_cc_proto\",\n        \"//api/v1:column_cpp_proto\",\n        \"//engine/util:filepath_helper\",\n        \"@abseil-cpp//absl/strings\",\n        \"@com_github_duckdb//:duckdb\",\n        \"@gflags\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\nscql_cc_test(\n    name = \"duckdb_wrapper_test\",\n    srcs = [\"duckdb_wrapper_test.cc\"],\n    deps = [\n        \":duckdb_wrapper\",\n        \"@brpc//:butil\",\n        \"@fmt\",\n    ],\n)\n\ncc_library(\n    name = \"csvdb_adaptor\",\n    srcs = [\"csvdb_adaptor.cc\"],\n    hdrs = [\"csvdb_adaptor.h\"],\n    deps = [\n        \":datasource_adaptor\",\n        \":datasource_cc_proto\",\n        \":duckdb_wrapper\",\n        \"//api/v1:column_cpp_proto\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@abseil-cpp//absl/strings\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"dm_adaptor\",\n    srcs = [\"dm_adaptor.cc\"],\n    hdrs = [\"dm_adaptor.h\"],\n    deps = [\n        \":datasource_adaptor\",\n        \":datasource_cc_proto\",\n        \":duckdb_wrapper\",\n        \"//api/v1:column_cpp_proto\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/exe:flags\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@abseil-cpp//absl/strings\",\n        \"@dataproxy_sdk_cc//dataproxy_sdk:data_proxy_stream\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_binary(\n    name = \"dm_adaptor_kuscia_test\",\n    srcs = [\"dm_adaptor_kuscia_test.cc\"],\n    deps = [\n        \":dm_adaptor\",\n        \"@abseil-cpp//absl/debugging:failure_signal_handler\",\n        \"@abseil-cpp//absl/debugging:symbolize\",\n        \"@abseil-cpp//absl/flags:flag\",\n        \"@abseil-cpp//absl/flags:parse\",\n        \"@googletest//:gtest\",\n    ],\n)\n\ncc_library(\n    name = \"dm_adaptor_factory\",\n    srcs = [\"dm_adaptor_factory.cc\"],\n    hdrs = [\"dm_adaptor_factory.h\"],\n    deps = [\n        \":datasource_adaptor_factory\",\n        \":dm_adaptor\",\n    ],\n)\n\nscql_cc_test(\n    name = \"csvdb_adaptor_test\",\n    srcs = [\"csvdb_adaptor_test.cc\"],\n    deps = [\n        \":csvdb_adaptor\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/operator:test_util\",\n        \"@brpc//:butil\",\n    ],\n)\n\ncc_library(\n    name = \"csvdb_adaptor_factory\",\n    srcs = [\"csvdb_adaptor_factory.cc\"],\n    hdrs = [\"csvdb_adaptor_factory.h\"],\n    deps = [\n        \":csvdb_adaptor\",\n        \":datasource_adaptor_factory\",\n    ],\n)\n\nproto_library(\n    name = \"http_router_proto\",\n    srcs = [\"http_router.proto\"],\n    deps = [\n        \":datasource_proto\",\n        \"//api:common_proto\",\n        \"//api:status_proto\",\n    ],\n)\n\ncc_proto_library(\n    name = \"http_router_cc_proto\",\n    deps = [\n        \":http_router_proto\",\n    ],\n)\n\ncc_library(\n    name = \"http_router\",\n    srcs = [\"http_router.cc\"],\n    hdrs = [\"http_router.h\"],\n    deps = [\n        \":http_router_cc_proto\",\n        \":router\",\n        \"@abseil-cpp//absl/strings\",\n        \"@brpc\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"kuscia_datamesh_router\",\n    srcs = [\"kuscia_datamesh_router.cc\"],\n    hdrs = [\"kuscia_datamesh_router.h\"],\n    deps = [\n        \":csvdb_conf_cc_proto\",\n        \":router\",\n        \"//engine/util:datamesh_helper\",\n        \"//engine/util:filepath_helper\",\n        \"@abseil-cpp//absl/strings\",\n        \"@brpc//:bthread\",\n        \"@brpc//:butil\",\n        \"@grpc//:grpc++\",\n        \"@kuscia//proto/api/v1alpha1/datamesh:domaindata_cpp_grpc\",\n        \"@kuscia//proto/api/v1alpha1/datamesh:domaindatasource_cpp_grpc\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_binary(\n    name = \"kuscia_datamesh_router_test\",\n    srcs = [\n        \"kuscia_datamesh_router_test.cc\",\n    ],\n    deps = [\n        \":kuscia_datamesh_router\",\n        \"@abseil-cpp//absl/debugging:failure_signal_handler\",\n        \"@abseil-cpp//absl/debugging:symbolize\",\n    ],\n)\n\nproto_library(\n    name = \"dataproxy_conf_proto\",\n    srcs = [\"dataproxy_conf.proto\"],\n    deps = [\n        \"@kuscia//proto/api/v1alpha1/datamesh:domaindatasource_proto\",\n    ],\n)\n\ncc_proto_library(\n    name = \"dataproxy_conf_cc_proto\",\n    deps = [\n        \":dataproxy_conf_proto\",\n    ],\n)\n\ncc_library(\n    name = \"dp_adaptor\",\n    srcs = [\"dp_adaptor.cc\"],\n    hdrs = [\"dp_adaptor.h\"],\n    deps = [\n        \":dataproxy_conf_cc_proto\",\n        \":datasource_adaptor\",\n        \":datasource_cc_proto\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/util:spu_io\",\n        \"//engine/util/dp:flight_cc_proto\",\n        \"@org_apache_arrow//:arrow\",\n        \"@org_apache_arrow//:arrow_flight\",\n    ],\n)\n\nscql_cc_test(\n    name = \"dp_adaptor_test\",\n    srcs = [\n        \"dp_adaptor_test.cc\",\n    ],\n    deps = [\n        \":dp_adaptor\",\n    ],\n)\n\ncc_library(\n    name = \"dp_adaptor_factory\",\n    srcs = [\"dp_adaptor_factory.cc\"],\n    hdrs = [\"dp_adaptor_factory.h\"],\n    deps = [\n        \":datasource_adaptor_factory\",\n        \":dp_adaptor\",\n    ],\n)\n"
  },
  {
    "path": "engine/datasource/arrow_sql_adaptor.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/arrow_sql_adaptor.h\"\n\n#include <future>\n#include <memory>\n#include <optional>\n#include <sstream>\n#include <string>\n#include <utility>\n\n#include \"absl/strings/str_split.h\"\n#include \"arrow/flight/client.h\"\n#include \"arrow/status.h\"\n#include \"arrow/table.h\"\n#include \"arrow/util/base64.h\"\n#include \"butil/file_util.h\"\n#include \"gflags/gflags.h\"\n#include \"spdlog/spdlog.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/spu_io.h\"\n\nDEFINE_bool(arrow_client_disable_server_verification, false,\n            \"arrow sql client disable server verification\");\nDEFINE_string(arrow_cert_pem_path, \"\",\n              \"work in tls/mtls, used in server verification when \"\n              \"arrow_client_disable_server_verification is false\");\nDEFINE_string(arrow_client_key_pem_path, \"\", \"work in mtls\");\nDEFINE_string(arrow_client_cert_pem_path, \"\", \"work in mtls\");\n\nnamespace scql::engine {\narrow::flight::FlightClientOptions GetFlightClientOptions() {\n  arrow::flight::FlightClientOptions options;\n  options.disable_server_verification =\n      FLAGS_arrow_client_disable_server_verification;\n  if ((!options.disable_server_verification) &&\n      (!FLAGS_arrow_cert_pem_path.empty())) {\n    std::string cert_pem_content;\n    YACL_ENFORCE(\n        butil::ReadFileToString(butil::FilePath(FLAGS_arrow_cert_pem_path),\n                                &cert_pem_content),\n        \"fail to read from {}\", FLAGS_arrow_cert_pem_path);\n    options.tls_root_certs = cert_pem_content;\n  }\n  if (!FLAGS_arrow_client_key_pem_path.empty()) {\n    std::string client_private_key;\n    YACL_ENFORCE(butil::ReadFileToString(\n                     butil::FilePath(FLAGS_arrow_client_key_pem_path),\n                     &client_private_key),\n                 \"fail to read from {}\", FLAGS_arrow_client_key_pem_path);\n    options.private_key = client_private_key;\n  }\n  if (!FLAGS_arrow_client_cert_pem_path.empty()) {\n    std::string client_cert_perm;\n    YACL_ENFORCE(butil::ReadFileToString(\n                     butil::FilePath(FLAGS_arrow_client_cert_pem_path),\n                     &client_cert_perm),\n                 \"fail to read from {}\", FLAGS_arrow_client_cert_pem_path);\n    options.cert_chain = client_cert_perm;\n  }\n  return options;\n}\n\nvoid ArrowClientManager::CreateDefaultClient(const std::string& uri) {\n  auto location = arrow::flight::Location::Parse(uri);\n  YACL_ENFORCE(location.ok(), \"fail to parse arrow uri: {}\", uri);\n  auto flight_client = arrow::flight::FlightClient::Connect(\n      location.ValueOrDie(), GetFlightClientOptions());\n  YACL_ENFORCE(flight_client.ok(), \"fail to connect arrow sql server: {}\",\n               flight_client.status().ToString());\n  sql_client_ = std::make_shared<arrow::flight::sql::FlightSqlClient>(\n      std::move(flight_client.ValueOrDie()));\n  client_map_.emplace(location->ToString(), sql_client_);\n}\n\nArrowSqlAdaptor::ArrowSqlAdaptor(const std::string& conn_str) {\n  // use default call options\n  // TODO(@xiaoyuan) set call options by long time benchmark\n  arrow::flight::FlightCallOptions call_options;\n  constexpr char kAuthHeader[] = \"authorization\";\n  constexpr char kBasicPrefix[] = \"Basic\";\n  std::vector<absl::string_view> fields = absl::StrSplit(conn_str, '@');\n  YACL_ENFORCE(fields.size() <= 2,\n               \"invalid conn_str for arrow sql with more than one '@'\");\n  if (fields.size() == 2) {\n    call_options.headers.emplace_back(\n        kAuthHeader, fmt::format(\"{} {}\", kBasicPrefix,\n                                 arrow::util::base64_encode(fields[1])));\n  }\n  client_creator_ = std::make_shared<ArrowClientManager>(call_options);\n\n  client_creator_->CreateDefaultClient(std::string(fields[0]));\n}\n\nSqlClientPtr ArrowClientManager::GetClientFromEndpoint(\n    const arrow::flight::FlightEndpoint& endpoint) {\n  SqlClientPtr client;\n  if (endpoint.locations.empty()) {\n    // use current service\n    client = sql_client_;\n  } else {\n    bool has_connected_location = false;\n    for (const auto& location : endpoint.locations) {\n      const auto& iter = client_map_.find(location.ToString());\n      if (iter != client_map_.end()) {\n        client = iter->second;\n        has_connected_location = true;\n        break;\n      }\n    }\n    if (!has_connected_location) {\n      for (const auto& location : endpoint.locations) {\n        auto flight_client = arrow::flight::FlightClient::Connect(location);\n        if (flight_client.ok()) {\n          client = std::make_shared<arrow::flight::sql::FlightSqlClient>(\n              std::move(flight_client.ValueOrDie()));\n          client_map_.emplace(endpoint.locations[0].ToString(), client);\n          return client;\n        }\n      }\n      std::stringstream err_str;\n      for (const auto& location : endpoint.locations) {\n        err_str << location.ToString();\n      }\n      YACL_THROW(\"fail to connect any location in endpoint: {}\", err_str.str());\n    }\n  }\n  return client;\n}\n\nstd::shared_ptr<ChunkedResult> ArrowSqlAdaptor::SendQuery(\n    const std::string& query) {\n  std::unique_ptr<arrow::flight::FlightInfo> flight_info;\n  ASSIGN_OR_THROW_ARROW_STATUS(flight_info,\n                               client_creator_->GetDefaultClient()->Execute(\n                                   client_creator_->GetCallOptions(), query));\n  arrow::ipc::DictionaryMemo memo;\n  auto schema = flight_info->GetSchema(&memo).ValueOrDie();\n  return std::make_shared<ArrowSqlChunkedResult>(schema, std::move(flight_info),\n                                                 client_creator_);\n}\n\nstd::optional<arrow::ChunkedArrayVector> ArrowSqlChunkedResult::Fetch() {\n  if (endpoint_index_ >= flight_info_->endpoints().size()) {\n    return std::nullopt;\n  }\n  arrow::ChunkedArrayVector arrs;\n  auto endpoint = flight_info_->endpoints()[endpoint_index_];\n  endpoint_index_++;\n  std::unique_ptr<arrow::flight::FlightStreamReader> stream;\n  SqlClientPtr client = client_creator_->GetClientFromEndpoint(endpoint);\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      stream,\n      client->DoGet(client_creator_->GetCallOptions(), endpoint.ticket));\n  std::shared_ptr<arrow::Table> table;\n  // stream read data until all data has been read or error occurs\n  // TODO(@xiaoyuan): maybe we should use stream.Next() to get data by batch\n  ASSIGN_OR_THROW_ARROW_STATUS(table, stream->ToTable());\n  THROW_IF_ARROW_NOT_OK(table->Validate());\n  for (int i = 0; i < table->num_columns(); ++i) {\n    arrs.push_back(table->column(i));\n  }\n\n  return arrs;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/arrow_sql_adaptor.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n#include <string>\n#include <unordered_map>\n\n#include \"arrow/flight/sql/client.h\"\n\n#include \"engine/core/tensor.h\"\n#include \"engine/datasource/datasource_adaptor.h\"\n\nnamespace scql::engine {\n\nusing SqlClientPtr = std::shared_ptr<arrow::flight::sql::FlightSqlClient>;\n\nclass ArrowClientManager {\n public:\n  explicit ArrowClientManager(arrow::flight::FlightCallOptions& call_options)\n      : call_options_(call_options) {}\n\n  void CreateDefaultClient(const std::string& uri);\n  SqlClientPtr GetClientFromEndpoint(\n      const arrow::flight::FlightEndpoint& endpoint);\n  arrow::flight::FlightCallOptions GetCallOptions() { return call_options_; }\n  SqlClientPtr GetDefaultClient() { return sql_client_; }\n  ~ArrowClientManager() {\n    for (auto& client : client_map_) {\n      static_cast<void>(client.second->Close());\n    }\n  }\n\n private:\n  SqlClientPtr sql_client_;\n  std::unordered_map<std::string, SqlClientPtr> client_map_;\n  arrow::flight::FlightCallOptions call_options_;\n};\n\nclass ArrowSqlChunkedResult : public ChunkedResult {\n public:\n  ArrowSqlChunkedResult(std::shared_ptr<arrow::Schema> schema,\n                        std::unique_ptr<arrow::flight::FlightInfo> flight_info,\n                        std::shared_ptr<ArrowClientManager> client_creator)\n      : schema_(std::move(schema)),\n        flight_info_(std::move(flight_info)),\n        client_creator_(std::move(client_creator)) {}\n\n  std::optional<arrow::ChunkedArrayVector> Fetch() override;\n  std::shared_ptr<arrow::Schema> GetSchema() override { return schema_; };\n\n private:\n  std::shared_ptr<arrow::Schema> schema_;\n  std::unique_ptr<arrow::flight::FlightInfo> flight_info_;\n  size_t endpoint_index_ = 0;\n  std::shared_ptr<ArrowClientManager> client_creator_;\n};\n\nclass ArrowSqlAdaptor : public DatasourceAdaptor {\n public:\n  // example: grpc+tcp://127.0.0.1:12929\n  // with authorization: grpc+tcp://127.0.0.1:12929@username:password\n  explicit ArrowSqlAdaptor(const std::string& conn_str);\n\n  ~ArrowSqlAdaptor() override = default;\n\n private:\n  // Send query and return schema\n  std::shared_ptr<ChunkedResult> SendQuery(const std::string& query) override;\n\n  std::shared_ptr<ArrowClientManager> client_creator_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/arrow_sql_adaptor_factory.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/datasource/arrow_sql_adaptor.h\"\n#include \"engine/datasource/datasource_adaptor_factory.h\"\n\nnamespace scql::engine {\n\nclass ArrowSqlAdaptorFactory final : public DatasourceAdaptorFactory {\n public:\n  std::unique_ptr<DatasourceAdaptor> CreateAdaptor(\n      const DataSource& datasource_spec) override {\n    return std::make_unique<ArrowSqlAdaptor>(datasource_spec.connection_str());\n  }\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/arrow_sql_adaptor_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/arrow_sql_adaptor.h\"\n\n#include \"absl/flags/flag.h\"\n#include \"absl/flags/parse.h\"\n#include \"gtest/gtest.h\"\n\nABSL_FLAG(std::string, url, \"\", \"url of arrow sql server\");\n\nnamespace scql::engine {\n// you must mock these data in your arrow server\n// create table\n// \"DROP TABLE IF EXISTS person\"\n// \"CREATE TABLE person(name VARCHAR(30), age INTEGER(3))\"\n// insert some rows\n//  \"INSERT INTO person VALUES(\\\"alice\\\", 18)\"\n//  \"INSERT INTO person VALUES(\\\"bob\\\", 20)\"\n//  \"INSERT INTO person VALUES(\\\"carol\\\", NULL)\"\n//  \"INSERT INTO person VALUES(NULL, NULL)\"\nclass ArrowSqlAdaptorTest : public ::testing::Test {\n protected:\n  std::string getUrl() { return absl::GetFlag(FLAGS_url); }\n};\n\nTEST_F(ArrowSqlAdaptorTest, works) {\n  // Given\n  ArrowSqlAdaptor adaptor(getUrl());\n\n  // When\n  const std::string query = \"SELECT name, age FROM person\";\n  std::vector<ColumnDesc> outputs{{\"name\", pb::PrimitiveDataType::STRING},\n                                  {\"age\", pb::PrimitiveDataType::INT32}};\n\n  auto results = adaptor.ExecQuery(query, outputs);\n\n  // Then\n  EXPECT_EQ(results.size(), 2);\n\n  // column name\n  EXPECT_EQ(results[0]->Length(), 4);\n  EXPECT_EQ(results[0]->GetNullCount(), 1);\n\n  // column age\n  EXPECT_EQ(results[1]->Length(), 4);\n  EXPECT_EQ(results[1]->GetNullCount(), 2);\n}\n\n}  // namespace scql::engine\n\nint main(int argc, char* argv[]) {\n  ::testing::InitGoogleTest(&argc, argv);\n\n  absl::ParseCommandLine(argc, argv);\n  return RUN_ALL_TESTS();\n}\n"
  },
  {
    "path": "engine/datasource/csvdb_adaptor.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/csvdb_adaptor.h\"\n\n#include <filesystem>\n#include <future>\n#include <memory>\n#include <optional>\n\n#include \"absl/strings/ascii.h\"\n#include \"arrow/c/abi.h\"\n#include \"arrow/c/bridge.h\"\n#include \"arrow/result.h\"\n#include \"arrow/status.h\"\n#include \"duckdb/common/arrow/arrow_converter.hpp\"\n#include \"duckdb/main/client_properties.hpp\"\n#include \"duckdb/main/query_result.hpp\"\n#include \"google/protobuf/util/json_util.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/datasource/duckdb_wrapper.h\"\n#include \"engine/util/spu_io.h\"\n\n#include \"api/v1/column.pb.h\"\n#include \"engine/datasource/csvdb_conf.pb.h\"\n\nnamespace scql::engine {\n\nCsvdbAdaptor::CsvdbAdaptor(const std::string& json_str) {\n  auto status =\n      google::protobuf::util::JsonStringToMessage(json_str, &csvdb_conf_);\n  YACL_ENFORCE(status.ok(),\n               \"failed to parse json to csvdb conf: json={}, error={}\",\n               json_str, status.ToString());\n  // check column data type\n  for (const auto& tbl : csvdb_conf_.tables()) {\n    for (const auto& col : tbl.columns()) {\n      scql::api::v1::DataType dtype;\n      if (!scql::api::v1::DataType_Parse(\n              absl::AsciiStrToUpper(col.column_type()), &dtype)) {\n        YACL_THROW(\"unknown column type={} of column={} in table={}\",\n                   col.column_type(), col.column_name(), tbl.table_name());\n      }\n    }\n  }\n}\n\nstd::shared_ptr<ChunkedResult> CsvdbAdaptor::SendQuery(\n    const std::string& query) {\n  // idea from:\n  // https://github.com/duckdb/duckdb/blob/0d2d7930d2789405a0d07a15e37485fe70faee3e/test/arrow/parquet_test.cpp#L86-L104\n  duckdb::DuckDB db = DuckDBWrapper::CreateDB(&csvdb_conf_);\n\n  duckdb::Connection conn(db);\n  conn.BeginTransaction();\n  DuckDBWrapper::CreateCSVScanFunction(conn);\n  conn.Commit();\n\n  auto duck_result = conn.SendQuery(query);\n  YACL_ENFORCE(!duck_result->HasError(), \"send query to DuckDB failed, msg={}\",\n               duck_result->GetError());\n  ArrowSchema abi_arrow_schema;\n  // avoid converting from string to large_string\n  duck_result->client_properties.arrow_offset_size =\n      duckdb::ArrowOffsetSize::LARGE;\n  duckdb::ArrowConverter::ToArrowSchema(&abi_arrow_schema, duck_result->types,\n                                        duck_result->names,\n                                        duck_result->client_properties);\n  std::shared_ptr<arrow::Schema> schema;\n  ASSIGN_OR_THROW_ARROW_STATUS(schema, arrow::ImportSchema(&abi_arrow_schema));\n  return std::make_shared<CsvdbChunkedResult>(schema, std::move(duck_result));\n};\n\nstd::optional<arrow::ChunkedArrayVector> CsvdbChunkedResult::Fetch() {\n  auto data_chunk = duck_result_->Fetch();\n  YACL_ENFORCE(!duck_result_->HasError(), \"fetch result failed, msg={}\",\n               duck_result_->GetError());\n  if (!data_chunk || data_chunk->size() == 0) {\n    return std::nullopt;\n  }\n  data_chunk->Verify();\n  ArrowArray arrow_array;\n  duckdb::ArrowConverter::ToArrowArray(*data_chunk, &arrow_array,\n                                       duck_result_->client_properties);\n  std::shared_ptr<arrow::RecordBatch> batch;\n  ASSIGN_OR_THROW_ARROW_STATUS(batch,\n                               arrow::ImportRecordBatch(&arrow_array, schema_));\n  arrow::ChunkedArrayVector chunked_arrs;\n  for (int i = 0; i < batch->num_columns(); ++i) {\n    chunked_arrs.push_back(\n        arrow::ChunkedArray::Make({batch->column(i)}).ValueOrDie());\n  }\n  return chunked_arrs;\n}\n\nDataSource MergeCsvdbDatasources(const std::vector<DataSource>& dss) {\n  YACL_ENFORCE(!dss.empty(), \"input datasources is empty\");\n  DataSource result = dss[0];\n  csv::CsvdbConf merged_conf;\n  for (size_t i = 0; i < dss.size(); ++i) {\n    const auto& ds = dss[i];\n    YACL_ENFORCE(ds.kind() == DataSourceKind::CSVDB,\n                 \"only CSVDB datasource can be merged\");\n    YACL_ENFORCE(ds.id() == result.id(),\n                 \"only datasource with same id can be merged\");\n    csv::CsvdbConf conf;\n    auto status =\n        google::protobuf::util::JsonStringToMessage(ds.connection_str(), &conf);\n    YACL_ENFORCE(status.ok(),\n                 \"failed to parse json to csvdb conf: json={}, error={}\",\n                 ds.connection_str(), status.ToString());\n    if (i == 0) {\n      merged_conf = conf;\n    } else {\n      for (const auto& tbl : conf.tables()) {\n        auto new_tbl = merged_conf.add_tables();\n        *new_tbl = tbl;\n      }\n    }\n  }\n  std::string connection_str;\n  auto status =\n      google::protobuf::util::MessageToJsonString(merged_conf, &connection_str);\n  YACL_ENFORCE(status.ok(), \"failed to convert CsvdbConf to json string: {}\",\n               status.ToString());\n  result.set_connection_str(connection_str);\n  return result;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/csvdb_adaptor.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <utility>\n\n#include \"duckdb/main/query_result.hpp\"\n\n#include \"engine/datasource/datasource_adaptor.h\"\n\n#include \"engine/datasource/csvdb_conf.pb.h\"\n#include \"engine/datasource/datasource.pb.h\"\n\nnamespace scql::engine {\n\nclass CsvdbChunkedResult : public ChunkedResult {\n public:\n  CsvdbChunkedResult(std::shared_ptr<arrow::Schema>& schema,\n                     std::unique_ptr<duckdb::QueryResult> duck_result)\n      : schema_(schema), duck_result_(std::move(duck_result)) {}\n\n  std::optional<arrow::ChunkedArrayVector> Fetch() override;\n  std::shared_ptr<arrow::Schema> GetSchema() override { return schema_; };\n\n private:\n  std::shared_ptr<arrow::Schema> schema_;\n  std::unique_ptr<duckdb::QueryResult> duck_result_;\n};\n\nclass CsvdbAdaptor : public DatasourceAdaptor {\n public:\n  explicit CsvdbAdaptor(const std::string& json_str);\n\n  ~CsvdbAdaptor() override = default;\n\n private:\n  // Send query and return schema\n  std::shared_ptr<ChunkedResult> SendQuery(const std::string& query) override;\n\n  csv::CsvdbConf csvdb_conf_;\n};\n\nDataSource MergeCsvdbDatasources(const std::vector<DataSource>& dss);\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/csvdb_adaptor_factory.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/csvdb_adaptor_factory.h\"\n\n#include \"engine/datasource/csvdb_adaptor.h\"\n\nnamespace scql::engine {\n\nstd::unique_ptr<DatasourceAdaptor> CsvdbAdaptorFactory::CreateAdaptor(\n    const DataSource& datasource_spec) {\n  return std::make_unique<CsvdbAdaptor>(datasource_spec.connection_str());\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/csvdb_adaptor_factory.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/datasource/datasource_adaptor_factory.h\"\n\nnamespace scql::engine {\n\nclass CsvdbAdaptorFactory final : public DatasourceAdaptorFactory {\n public:\n  std::unique_ptr<DatasourceAdaptor> CreateAdaptor(\n      const DataSource& datasource_spec) override;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/csvdb_adaptor_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/csvdb_adaptor.h\"\n\n#include <exception>\n\n#include \"arrow/type.h\"\n#include \"butil/files/temp_file.h\"\n#include \"gflags/gflags.h\"\n#include \"google/protobuf/util/json_util.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\n#include \"engine/datasource/csvdb_conf.pb.h\"\n\nnamespace scql::engine {\n\nDECLARE_string(restricted_read_path);\n\nclass CsvdbAdaptorTest : public ::testing::Test {\n protected:\n  void SetUp() override {\n    FLAGS_restricted_read_path = \"./\";\n    temp_file_ = std::make_unique<butil::TempFile>(\"csv\");\n    temp_file_->save(csv_content_.c_str());\n\n    {\n      csvdb_conf_.set_db_name(\"csvdb\");\n      auto table = csvdb_conf_.add_tables();\n      table->set_table_name(\"staff\");\n      table->set_data_path(temp_file_->fname());\n\n      auto column = table->add_columns();\n      column->set_column_name(\"id\");\n      column->set_column_type(\"int64\");\n      column = table->add_columns();\n      column->set_column_name(\"age\");\n      column->set_column_type(\"int64\");\n      column = table->add_columns();\n      column->set_column_name(\"name\");\n      column->set_column_type(\"string\");\n      column = table->add_columns();\n      column->set_column_name(\"salary\");\n      column->set_column_type(\"double\");\n      column = table->add_columns();\n      column->set_column_name(\"dt\");\n      column->set_column_type(\"datetime\");\n      column = table->add_columns();\n      column->set_column_name(\"tt\");\n      column->set_column_type(\"timestamp\");\n    }\n    auto status = google::protobuf::util::MessageToJsonString(csvdb_conf_,\n                                                              &csvdb_conf_str_);\n    EXPECT_TRUE(status.ok());\n  }\n\n public:\n  csv::CsvdbConf csvdb_conf_;\n  std::string csvdb_conf_str_;\n  std::unique_ptr<butil::TempFile> temp_file_;\n  std::string csv_content_ = R\"csv(id, age, name, salary, dt, tt\n1,21,alice,2100.2,2025-06-06 13:00:00,2025-06-06T13:00:00-07:00\n2,42,bob,4500.8,2025-06-16 16:00:00,2025-06-16T16:00:00-07:00\n3,19,carol,1900.5,2025-06-26 16:00:00,2025-06-26T16:00:00-07:00\n4,NULL,NULL,NULL,NULL,NULL)csv\";\n};\n\nTEST_F(CsvdbAdaptorTest, NormalQuery) {\n  // Given\n  CsvdbAdaptor csvdb_adaptor(csvdb_conf_str_);\n\n  const std::string query = \"select * from csvdb.staff\";\n  std::vector<ColumnDesc> outputs{{\"id\", pb::PrimitiveDataType::INT64},\n                                  {\"age\", pb::PrimitiveDataType::INT64},\n                                  {\"name\", pb::PrimitiveDataType::STRING},\n                                  {\"salary\", pb::PrimitiveDataType::FLOAT64},\n                                  {\"dt\", pb::PrimitiveDataType::DATETIME},\n                                  {\"tt\", pb::PrimitiveDataType::TIMESTAMP}};\n\n  // When\n  auto results = csvdb_adaptor.ExecQuery(query, outputs);\n  // Then\n  EXPECT_EQ(results.size(), 6);\n  scql::engine::op::test::CheckTensorEqual(\n      results[0], TensorFrom(arrow::int64(), \"[1,2,3,4]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[1], TensorFrom(arrow::int64(), \"[21,42,19,null]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[2], TensorFrom(arrow::large_utf8(),\n                             R\"json([\"alice\",\"bob\",\"carol\",null])json\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[3], TensorFrom(arrow::float64(), \"[2100.2,4500.8,1900.5,null]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[4],\n      TensorFrom(arrow::int64(), \"[1749214800,1750089600,1750953600,null]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[5],\n      TensorFrom(arrow::int64(), \"[1749240000,1750114800,1750978800,null]\"));\n}\n\nTEST_F(CsvdbAdaptorTest, WriteToFile) {\n  // Given\n  CsvdbAdaptor csvdb_adaptor(csvdb_conf_str_);\n\n  const std::string query = \"select * from csvdb.staff\";\n  std::vector<ColumnDesc> outputs{{\"id\", pb::PrimitiveDataType::INT64},\n                                  {\"age\", pb::PrimitiveDataType::INT64},\n                                  {\"name\", pb::PrimitiveDataType::STRING},\n                                  {\"salary\", pb::PrimitiveDataType::FLOAT64},\n                                  {\"dt\", pb::PrimitiveDataType::DATETIME},\n                                  {\"tt\", pb::PrimitiveDataType::TIMESTAMP}};\n\n  // When\n  auto results = csvdb_adaptor.ExecQuery(\n      query, outputs,\n      TensorBuildOptions{.dump_to_disk = true,\n                         .dump_dir = std::filesystem::temp_directory_path(),\n                         .max_row_num_one_file = 2});\n\n  // Then\n  EXPECT_EQ(results.size(), 6);\n  scql::engine::op::test::CheckTensorEqual(\n      results[0], TensorFrom(arrow::int64(), \"[1,2,3,4]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[1], TensorFrom(arrow::int64(), \"[21,42,19,null]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[2], TensorFrom(arrow::large_utf8(),\n                             R\"json([\"alice\",\"bob\",\"carol\",null])json\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[3], TensorFrom(arrow::float64(), \"[2100.2,4500.8,1900.5,null]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[4],\n      TensorFrom(arrow::int64(), \"[1749214800,1750089600,1750953600,null]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[5],\n      TensorFrom(arrow::int64(), \"[1749240000,1750114800,1750978800,null]\"));\n}\n\nTEST_F(CsvdbAdaptorTest, QueryWithAggregation) {\n  // Given\n  CsvdbAdaptor csvdb_adaptor(csvdb_conf_str_);\n\n  const std::string query = \"select SUM(age), SUM(salary) from csvdb.staff\";\n  std::vector<ColumnDesc> outputs{\n      {\"age_sum\", pb::PrimitiveDataType::INT64},\n      {\"salary_sum\", pb::PrimitiveDataType::FLOAT64}};\n\n  // When\n  auto results = csvdb_adaptor.ExecQuery(query, outputs);\n\n  // Then\n  EXPECT_EQ(results.size(), 2);\n  scql::engine::op::test::CheckTensorEqual(results[0],\n                                           TensorFrom(arrow::int64(), \"[82]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[1], TensorFrom(arrow::float64(), \"[8501.5]\"));\n}\n\nTEST_F(CsvdbAdaptorTest, QueryWithPredicate) {\n  // Given\n  CsvdbAdaptor csvdb_adaptor(csvdb_conf_str_);\n\n  const std::string query =\n      \"select age, name, salary from csvdb.staff where age > 30\";\n  std::vector<ColumnDesc> outputs{{\"age\", pb::PrimitiveDataType::INT64},\n                                  {\"name\", pb::PrimitiveDataType::STRING},\n                                  {\"salary\", pb::PrimitiveDataType::FLOAT64}};\n\n  // When\n  auto results = csvdb_adaptor.ExecQuery(query, outputs);\n\n  // Then\n  EXPECT_EQ(results.size(), 3);\n\n  scql::engine::op::test::CheckTensorEqual(results[0],\n                                           TensorFrom(arrow::int64(), \"[42]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[1], TensorFrom(arrow::large_utf8(), R\"json([\"bob\"])json\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[2], TensorFrom(arrow::float64(), \"[4500.8]\"));\n}\n\nTEST_F(CsvdbAdaptorTest, QueryWithDomainDataID) {\n  // Given\n  csvdb_conf_.clear_db_name();\n  ASSERT_EQ(csvdb_conf_.tables_size(), 1);\n  csvdb_conf_.mutable_tables()->at(0).set_table_name(\n      \"usercredit-0afb3b4c-d160-4050-b71a-c6674a11d2f9\");\n  std::string conf_str;\n  auto status =\n      google::protobuf::util::MessageToJsonString(csvdb_conf_, &conf_str);\n  EXPECT_TRUE(status.ok());\n  CsvdbAdaptor csvdb_adaptor(conf_str);\n\n  const std::string query =\n      R\"str(select \"usercredit-0afb3b4c-d160-4050-b71a-c6674a11d2f9\".\"ID\",\n                   \"usercredit-0afb3b4c-d160-4050-b71a-c6674a11d2f9\".\"Age\",\n                   \"usercredit-0afb3b4c-d160-4050-b71a-c6674a11d2f9\".\"name\",\n                   \"usercredit-0afb3b4c-d160-4050-b71a-c6674a11d2f9\".\"salarY\"\n            from \"usercredit-0afb3b4c-d160-4050-b71a-c6674a11d2f9\")str\";\n  std::vector<ColumnDesc> outputs{{\"id\", pb::PrimitiveDataType::INT64},\n                                  {\"age\", pb::PrimitiveDataType::INT64},\n                                  {\"name\", pb::PrimitiveDataType::STRING},\n                                  {\"salary\", pb::PrimitiveDataType::FLOAT64}};\n\n  // When\n  auto results = csvdb_adaptor.ExecQuery(query, outputs);\n\n  // Then\n  EXPECT_EQ(results.size(), 4);\n  scql::engine::op::test::CheckTensorEqual(\n      results[0], TensorFrom(arrow::int64(), \"[1,2,3,4]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[1], TensorFrom(arrow::int64(), \"[21,42,19,null]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[2], TensorFrom(arrow::large_utf8(),\n                             R\"json([\"alice\",\"bob\",\"carol\",null])json\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[3], TensorFrom(arrow::float64(), \"[2100.2,4500.8,1900.5,null]\"));\n}\n\nTEST_F(CsvdbAdaptorTest, MergeCsvdbDatasources) {\n  // Given\n  DataSource ds1;\n  ds1.set_id(\"test-datasource-1\");\n  ds1.set_name(\"test-datasource-1\");\n  ds1.set_kind(DataSourceKind::CSVDB);\n\n  csv::CsvdbConf conf1;\n  {\n    auto table = conf1.add_tables();\n    table->set_table_name(\"table1\");\n    table->set_data_path(\"/path/to/table1.csv\");\n\n    auto column = table->add_columns();\n    column->set_column_name(\"id\");\n    column->set_column_type(\"int64\");\n    column = table->add_columns();\n    column->set_column_name(\"name\");\n    column->set_column_type(\"string\");\n  }\n  std::string conf1_str;\n  auto status = google::protobuf::util::MessageToJsonString(conf1, &conf1_str);\n  EXPECT_TRUE(status.ok());\n  ds1.set_connection_str(conf1_str);\n\n  DataSource ds2;\n  ds2.set_id(\"test-datasource-1\");\n  ds2.set_name(\"test-datasource-2\");\n  ds2.set_kind(DataSourceKind::CSVDB);\n\n  csv::CsvdbConf conf2;\n  {\n    auto table = conf2.add_tables();\n    table->set_table_name(\"table2\");\n    table->set_data_path(\"/path/to/table2.csv\");\n\n    auto column = table->add_columns();\n    column->set_column_name(\"age\");\n    column->set_column_type(\"int32\");\n    column = table->add_columns();\n    column->set_column_name(\"salary\");\n    column->set_column_type(\"double\");\n  }\n  std::string conf2_str;\n  status = google::protobuf::util::MessageToJsonString(conf2, &conf2_str);\n  EXPECT_TRUE(status.ok());\n  ds2.set_connection_str(conf2_str);\n\n  std::vector<DataSource> datasources = {ds1, ds2};\n\n  // When\n  auto merged = MergeCsvdbDatasources(datasources);\n\n  // Then\n  EXPECT_EQ(merged.id(), \"test-datasource-1\");\n  EXPECT_EQ(merged.kind(), DataSourceKind::CSVDB);\n\n  csv::CsvdbConf merged_conf;\n  status = google::protobuf::util::JsonStringToMessage(merged.connection_str(),\n                                                       &merged_conf);\n  EXPECT_TRUE(status.ok());\n  EXPECT_EQ(merged_conf.tables_size(), 2);\n\n  // Check first table\n  const auto& merged_table1 = merged_conf.tables(0);\n  EXPECT_EQ(merged_table1.table_name(), \"table1\");\n  EXPECT_EQ(merged_table1.data_path(), \"/path/to/table1.csv\");\n  EXPECT_EQ(merged_table1.columns_size(), 2);\n  EXPECT_EQ(merged_table1.columns(0).column_name(), \"id\");\n  EXPECT_EQ(merged_table1.columns(0).column_type(), \"int64\");\n  EXPECT_EQ(merged_table1.columns(1).column_name(), \"name\");\n  EXPECT_EQ(merged_table1.columns(1).column_type(), \"string\");\n\n  // Check second table\n  const auto& merged_table2 = merged_conf.tables(1);\n  EXPECT_EQ(merged_table2.table_name(), \"table2\");\n  EXPECT_EQ(merged_table2.data_path(), \"/path/to/table2.csv\");\n  EXPECT_EQ(merged_table2.columns_size(), 2);\n  EXPECT_EQ(merged_table2.columns(0).column_name(), \"age\");\n  EXPECT_EQ(merged_table2.columns(0).column_type(), \"int32\");\n  EXPECT_EQ(merged_table2.columns(1).column_name(), \"salary\");\n  EXPECT_EQ(merged_table2.columns(1).column_type(), \"double\");\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/csvdb_conf.proto",
    "content": "//\n// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.engine.csv;\n\nmessage CsvTableConf {\n  message ColumnConf {\n    string column_name = 1;\n    // column_type value should be string value defined in DataType in\n    // \"api/column.proto\"\n    string column_type = 2;\n  };\n\n  string table_name = 1;\n  string data_path = 2;\n  repeated ColumnConf columns = 3;\n}\n\nmessage S3Conf {\n  string endpoint = 2;\n  string access_key_id = 3;\n  string secret_access_key = 4;\n  // See\n  // https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html\n  bool virtualhost = 5;\n}\n\nmessage CsvdbConf {\n  string db_name = 1;\n  S3Conf s3_conf = 2;\n  repeated CsvTableConf tables = 3;\n}"
  },
  {
    "path": "engine/datasource/dataproxy_conf.proto",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage scql.engine.datasource;\n\nimport \"kuscia/proto/api/v1alpha1/datamesh/domaindatasource.proto\";\n\nmessage DataProxyConf {\n  string dp_uri = 1;\n  kuscia.proto.api.v1alpha1.datamesh.DomainDataSource datasource = 3;\n}"
  },
  {
    "path": "engine/datasource/datasource.proto",
    "content": "//\n// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.engine;\n\nenum DataSourceKind {\n  UNKNOWN = 0;\n  MYSQL = 1;\n  SQLITE = 2;\n  POSTGRESQL = 3;\n  CSVDB = 4;\n  ARROWSQL = 5;\n  GRPC = 6;\n  DATAMESH = 7;\n  DATAPROXY = 8;\n}\n\nmessage DataSource {\n  // datasource uuid\n  string id = 1;\n  // human-friendly datasource name\n  string name = 2;\n  DataSourceKind kind = 3;\n  // concrete data source connection string\n  // It is comprehend to related data source adaptor.\n  string connection_str = 4;\n};"
  },
  {
    "path": "engine/datasource/datasource_adaptor.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/datasource_adaptor.h\"\n\n#include <cstddef>\n#include <future>\n#include <memory>\n#include <vector>\n\n#include \"arrow/compute/cast.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/core/type.h\"\n#include \"engine/exe/flags.h\"\n#include \"engine/util/filepath_helper.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine {\n\n// ExecQuery execute query,\nstd::vector<TensorPtr> DatasourceAdaptor::CreateDiskTensor(\n    const std::shared_ptr<spdlog::logger>& logger,\n    const std::vector<ColumnDesc>& expected_outputs,\n    const TensorBuildOptions& options,\n    util::SimpleChannel<arrow::ChunkedArrayVector>& data_queue) {\n  std::vector<TensorPtr> tensors(expected_outputs.size());\n  std::vector<std::shared_ptr<TensorWriter>> writers(expected_outputs.size());\n  bool has_data = false;\n  auto data_arrs = data_queue.Pop();\n  while (data_arrs.has_value()) {\n    auto converted_arrs =\n        ConvertDataTypeToExpected(logger, data_arrs.value(), expected_outputs);\n    if (!has_data) {\n      has_data = true;\n      for (size_t i = 0; i < expected_outputs.size(); ++i) {\n        auto column_file_path = util::CreateDirWithRandSuffix(\n            options.dump_dir, expected_outputs[i].name);\n        auto writer = std::make_shared<TensorWriter>(\n            expected_outputs[i].name, converted_arrs[i]->type(),\n            column_file_path, options.max_row_num_one_file);\n        writers[i] = writer;\n      }\n    }\n    for (size_t i = 0; i < converted_arrs.size(); i++) {\n      writers[i]->WriteBatch(*converted_arrs[i]);\n    }\n    data_arrs = data_queue.Pop();\n  }\n  if (!has_data) {\n    // create empty tensor\n    for (size_t i = 0; i < expected_outputs.size(); ++i) {\n      tensors[i] = std::make_shared<MemTensor>(\n          arrow::ChunkedArray::Make({},\n                                    ToArrowDataType(expected_outputs[i].dtype))\n              .ValueOrDie());\n    }\n  } else {\n    for (size_t i = 0; i < expected_outputs.size(); ++i) {\n      writers[i]->Finish(&tensors[i]);\n    }\n  }\n  return tensors;\n}\n\nstd::vector<TensorPtr> DatasourceAdaptor::CreateMemTensor(\n    const std::shared_ptr<spdlog::logger>& logger,\n    const std::vector<ColumnDesc>& expected_outputs,\n    [[maybe_unused]] const TensorBuildOptions& options,\n    util::SimpleChannel<arrow::ChunkedArrayVector>& data_queue) {\n  std::vector<TensorPtr> tensors(expected_outputs.size());\n  std::vector<std::shared_ptr<arrow::DataType>> types(expected_outputs.size());\n  for (size_t i = 0; i < expected_outputs.size(); ++i) {\n    types[i] = ToArrowDataType(expected_outputs[i].dtype);\n  }\n  std::vector<arrow::ChunkedArrayVector> result_arrs(expected_outputs.size());\n  auto data_arrs = data_queue.Pop();\n  while (data_arrs.has_value()) {\n    auto converted_arrs =\n        ConvertDataTypeToExpected(logger, data_arrs.value(), expected_outputs);\n    for (size_t i = 0; i < converted_arrs.size(); i++) {\n      // reset data type due to data type converted by\n      // ConvertDataTypeToExpected\n      types[i] = converted_arrs[i]->type();\n      result_arrs[i].push_back(converted_arrs[i]);\n    }\n    data_arrs = data_queue.Pop();\n  }\n  for (size_t i = 0; i < result_arrs.size(); i++) {\n    arrow::ArrayVector arrays;\n    for (const auto& arrs : result_arrs[i]) {\n      arrays.insert(arrays.end(), arrs->chunks().begin(), arrs->chunks().end());\n    }\n    tensors[i] = std::make_shared<MemTensor>(\n        arrow::ChunkedArray::Make(arrays, types[i]).ValueOrDie());\n  }\n  return tensors;\n}\n\nstd::vector<TensorPtr> DatasourceAdaptor::ExecQuery(\n    const std::shared_ptr<spdlog::logger>& logger, const std::string& query,\n    const std::vector<ColumnDesc>& expected_outputs,\n    const TensorBuildOptions& options) {\n  std::vector<TensorPtr> tensors;\n  constexpr size_t data_queue_capacity = 1;\n  util::SimpleChannel<arrow::ChunkedArrayVector> data_queue(\n      data_queue_capacity, FLAGS_queue_max_block_seconds);\n  auto result = SendQuery(query);\n  auto f = std::async(std::launch::async, [&] {\n    try {\n      while (true) {\n        auto data_arrays = result->Fetch();\n        if (!data_arrays.has_value()) {\n          data_queue.Close();\n          break;\n        }\n        data_queue.Push(data_arrays.value());\n      }\n    } catch (const std::exception& e) {\n      // close queue to avoid other thread be blocked forever\n      data_queue.Close();\n      throw e;\n    }\n  });\n  try {\n    if (options.dump_to_disk) {\n      // write data to disk\n      tensors = CreateDiskTensor(logger, expected_outputs, options, data_queue);\n    } else {\n      // create in-memory tensor\n      tensors = CreateMemTensor(logger, expected_outputs, options, data_queue);\n    }\n  } catch (const std::exception& e) {\n    SPDLOG_ERROR(\n        \"exception caught in DatasourceAdaptor::ExecQuery \"\n        \"while pushing data: {}\",\n        e.what());\n    data_queue.Close();\n    throw e;\n  }\n\n  f.get();\n\n  return tensors;\n}\n\narrow::ChunkedArrayVector DatasourceAdaptor::ConvertDataTypeToExpected(\n    const std::shared_ptr<spdlog::logger>& logger,\n    const arrow::ChunkedArrayVector& chunked_arrs,\n    const std::vector<ColumnDesc>& expected_outputs) {\n  YACL_ENFORCE_EQ(chunked_arrs.size(), expected_outputs.size(),\n                  \"query result column size={} not equal to expected size={}\",\n                  chunked_arrs.size(), expected_outputs.size());\n  arrow::ChunkedArrayVector result_chunked_arrs;\n  for (size_t i = 0; i < chunked_arrs.size(); ++i) {\n    auto chunked_arr = chunked_arrs[i];\n    YACL_ENFORCE(chunked_arr, \"get column(idx={}) from table failed\", i);\n    auto to_type = ToArrowDataType(expected_outputs[i].dtype);\n    YACL_ENFORCE(to_type, \"unsupported column data type {}\",\n                 fmt::underlying(expected_outputs[i].dtype));\n    if (arrow::is_temporal(chunked_arr->type()->id())) {\n      // CSV data source returns temporal types that must be converted to int64\n      // seconds.\n      // Since Arrow's cast function cannot control time units, special\n      // handling is required.\n      auto tensor = util::ConvertDateTimeToInt64(chunked_arr);\n      chunked_arr = tensor->ToArrowChunkedArray();\n    }\n    if (!chunked_arr->type()->Equals(to_type)) {\n      SPDLOG_LOGGER_WARN(logger, \"arrow type mismatch, convert from {} to {}\",\n                         chunked_arr->type()->ToString(), to_type->ToString());\n      arrow::Datum cast_result;\n      ASSIGN_OR_THROW_ARROW_STATUS(cast_result,\n                                   arrow::compute::Cast(chunked_arr, to_type));\n      chunked_arr = cast_result.chunked_array();\n    }\n\n    result_chunked_arrs.push_back(std::move(chunked_arr));\n  }\n  return result_chunked_arrs;\n}\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/datasource_adaptor.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <future>\n#include <memory>\n#include <optional>\n#include <string>\n#include <vector>\n\n#include \"spdlog/spdlog.h\"\n\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/concurrent_queue.h\"\n\n#include \"api/core.pb.h\"\n\nnamespace scql::engine {\n\n/// @brief ColumnDesc contains column metadata information.\nstruct ColumnDesc {\n  std::string name;             // column name\n  pb::PrimitiveDataType dtype;  // column data type\n\n  ColumnDesc(std::string name, pb::PrimitiveDataType dtype)\n      : name(std::move(name)), dtype(dtype) {}\n};\n\nclass ChunkedResult {\n public:\n  virtual ~ChunkedResult() = default;\n  virtual std::optional<arrow::ChunkedArrayVector> Fetch() = 0;\n  virtual std::shared_ptr<arrow::Schema> GetSchema() = 0;\n};\n\nclass DatasourceAdaptor {\n public:\n  virtual ~DatasourceAdaptor() = default;\n\n  // ExecQuery execute query,\n  std::vector<TensorPtr> ExecQuery(\n      const std::shared_ptr<spdlog::logger>& logger, const std::string& query,\n      const std::vector<ColumnDesc>& expected_outputs,\n      const TensorBuildOptions& options = {});\n\n  std::vector<TensorPtr> ExecQuery(\n      const std::string& query, const std::vector<ColumnDesc>& expected_outputs,\n      const TensorBuildOptions& options = {}) {\n    return ExecQuery(spdlog::default_logger(), query, expected_outputs,\n                     options);\n  }\n\n private:\n  // Send query and return schema\n  virtual std::shared_ptr<ChunkedResult> SendQuery(\n      const std::string& query) = 0;\n  // It will complain if the actual outputs not matched with expected_outputs.\n  static arrow::ChunkedArrayVector ConvertDataTypeToExpected(\n      const std::shared_ptr<spdlog::logger>& logger,\n      const arrow::ChunkedArrayVector& chunked_arrs,\n      const std::vector<ColumnDesc>& expected_outputs);\n\n  static std::vector<TensorPtr> CreateDiskTensor(\n      const std::shared_ptr<spdlog::logger>& logger,\n      const std::vector<ColumnDesc>& expected_outputs,\n      const TensorBuildOptions& options,\n      util::SimpleChannel<arrow::ChunkedArrayVector>& data_queue);\n\n  static std::vector<TensorPtr> CreateMemTensor(\n      const std::shared_ptr<spdlog::logger>& logger,\n      const std::vector<ColumnDesc>& expected_outputs,\n      [[maybe_unused]] const TensorBuildOptions& options,\n      util::SimpleChannel<arrow::ChunkedArrayVector>& data_queue);\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/datasource_adaptor_factory.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/datasource/datasource_adaptor.h\"\n\n#include \"engine/datasource/datasource.pb.h\"\n\nnamespace scql::engine {\n\nclass DatasourceAdaptorFactory {\n public:\n  virtual ~DatasourceAdaptorFactory() = default;\n\n  virtual std::unique_ptr<DatasourceAdaptor> CreateAdaptor(\n      const DataSource& datasource_spec) = 0;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/datasource_adaptor_mgr.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/datasource_adaptor_mgr.h\"\n\n#include \"yacl/base/exception.h\"\n\n#include \"engine/datasource/arrow_sql_adaptor_factory.h\"\n#include \"engine/datasource/csvdb_adaptor_factory.h\"\n#include \"engine/datasource/dm_adaptor_factory.h\"\n#include \"engine/datasource/dp_adaptor_factory.h\"\n#include \"engine/datasource/odbc_adaptor_factory.h\"\n\nnamespace scql::engine {\n\nDatasourceAdaptorMgr::DatasourceAdaptorMgr() {\n  RegisterBuiltinAdaptorFactories();\n}\n\nstd::shared_ptr<DatasourceAdaptor> DatasourceAdaptorMgr::GetAdaptor(\n    const DataSource& datasource_spec) {\n  // CSVDB may change frequently, so avoid to store in map.\n  if (datasource_spec.kind() == DataSourceKind::CSVDB) {\n    return CreateAdaptor(datasource_spec);\n  }\n\n  auto spec_pair =\n      std::pair(datasource_spec.connection_str(), datasource_spec.kind());\n  {\n    absl::ReaderMutexLock lock(&mu_);\n\n    auto iter = adaptors_.find(spec_pair);\n    if (iter != adaptors_.end()) {\n      return iter->second;\n    }\n  }\n  // not existed, or datasource specification updated\n  std::shared_ptr<DatasourceAdaptor> adaptor = CreateAdaptor(datasource_spec);\n  YACL_ENFORCE(adaptor, \"unsupported datasource: {}\",\n               datasource_spec.ShortDebugString());\n\n  {\n    absl::MutexLock lock(&mu_);\n    adaptors_[spec_pair] = adaptor;\n  }\n  return adaptor;\n}\n\nstd::shared_ptr<DatasourceAdaptor> DatasourceAdaptorMgr::CreateAdaptor(\n    const DataSource& datasource_spec) {\n  auto iter = factory_maps_.find(datasource_spec.kind());\n  if (iter == factory_maps_.end()) {\n    return nullptr;\n  }\n  auto& factory = iter->second;\n  return factory->CreateAdaptor(datasource_spec);\n}\n\nvoid DatasourceAdaptorMgr::RegisterBuiltinAdaptorFactories() {\n  auto odbc_adaptor_factory = std::make_shared<OdbcAdaptorFactory>();\n  factory_maps_.insert({DataSourceKind::MYSQL, odbc_adaptor_factory});\n  factory_maps_.insert({DataSourceKind::SQLITE, odbc_adaptor_factory});\n  factory_maps_.insert({DataSourceKind::POSTGRESQL, odbc_adaptor_factory});\n  factory_maps_.insert(\n      {DataSourceKind::DATAMESH, std::make_shared<DmAdaptorFactory>()});\n  factory_maps_.insert(\n      {DataSourceKind::CSVDB, std::make_shared<CsvdbAdaptorFactory>()});\n  factory_maps_.insert(\n      {DataSourceKind::ARROWSQL, std::make_shared<ArrowSqlAdaptorFactory>()});\n  factory_maps_.insert(\n      {DataSourceKind::DATAPROXY, std::make_shared<DpAdaptorFactory>()});\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/datasource_adaptor_mgr.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"absl/container/flat_hash_map.h\"\n#include \"absl/synchronization/mutex.h\"\n\n#include \"engine/datasource/datasource_adaptor.h\"\n#include \"engine/datasource/datasource_adaptor_factory.h\"\n\nnamespace scql::engine {\n/// @brief Datasource Adaptor Manager\nclass DatasourceAdaptorMgr {\n public:\n  DatasourceAdaptorMgr();\n\n  /// @brief Returns adaptor if it already existed,\n  /// otherwise, create adaptor according DataSource spec.\n  std::shared_ptr<DatasourceAdaptor> GetAdaptor(\n      const DataSource& datasource_spec);\n\n private:\n  void RegisterBuiltinAdaptorFactories();\n\n  std::shared_ptr<DatasourceAdaptor> CreateAdaptor(\n      const DataSource& datasource_spec);\n\n  absl::flat_hash_map<DataSourceKind, std::shared_ptr<DatasourceAdaptorFactory>>\n      factory_maps_;\n\n  absl::Mutex mu_;\n  // following member variables are protected by `mu_`\n\n  // datasource.connection_str + datasource.kind --> datasource adaptor\n  absl::flat_hash_map<std::pair<std::string, int>,\n                      std::shared_ptr<DatasourceAdaptor>>\n      adaptors_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/dm_adaptor.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/dm_adaptor.h\"\n\n#include <cstddef>\n#include <filesystem>\n#include <future>\n#include <memory>\n#include <optional>\n#include <vector>\n\n#include \"absl/strings/ascii.h\"\n#include \"arrow/c/abi.h\"\n#include \"arrow/c/bridge.h\"\n#include \"arrow/compute/cast.h\"\n#include \"arrow/record_batch.h\"\n#include \"arrow/result.h\"\n#include \"arrow/status.h\"\n#include \"arrow/table.h\"\n#include \"dataproxy_sdk/data_proxy_stream.h\"\n#include \"gflags/gflags.h\"\n\n#include \"engine/exe/flags.h\"\n\nnamespace scql::engine {\n\nstd::shared_ptr<ChunkedResult> DmAdaptor::SendQuery(const std::string& query) {\n  dataproxy_sdk::proto::DataProxyConfig config;\n  config.set_data_proxy_addr(FLAGS_kuscia_datamesh_endpoint);\n  config.mutable_tls_config()->set_certificate_path(\n      FLAGS_kuscia_datamesh_client_cert_path);\n  config.mutable_tls_config()->set_private_key_path(\n      FLAGS_kuscia_datamesh_client_key_path);\n  config.mutable_tls_config()->set_ca_file_path(\n      FLAGS_kuscia_datamesh_cacert_path);\n  auto stream = dataproxy_sdk::DataProxyStream::Make(config);\n  YACL_ENFORCE(stream != nullptr);\n  dataproxy_sdk::proto::SQLInfo sql_info;\n  sql_info.set_sql(query);\n  sql_info.set_datasource_id(datasource_id_);\n  auto stream_reader = stream->GetReader(sql_info);\n  YACL_ENFORCE(stream_reader != nullptr);\n  return std::make_shared<DmChunkedResult>(std::move(stream_reader));\n}\n\nstd::optional<arrow::ChunkedArrayVector> DmChunkedResult::Fetch() {\n  std::shared_ptr<arrow::RecordBatch> batch;\n  stream_reader_->Get(&batch);\n  if (batch == nullptr || batch->num_rows() == 0) {\n    return std::nullopt;\n  }\n  arrow::ChunkedArrayVector chunked_arrs;\n  for (int i = 0; i < batch->num_columns(); ++i) {\n    chunked_arrs.push_back(\n        arrow::ChunkedArray::Make({batch->column(i)}).ValueOrDie());\n  }\n  return chunked_arrs;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/dm_adaptor.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <future>\n#include <utility>\n\n#include \"arrow/type_fwd.h\"\n#include \"dataproxy_sdk/data_proxy_stream.h\"\n\n#include \"engine/datasource/datasource_adaptor.h\"\n\n#include \"engine/datasource/datasource.pb.h\"\n\nnamespace scql::engine {\n\nclass DmChunkedResult : public ChunkedResult {\n public:\n  DmChunkedResult(\n      std::unique_ptr<dataproxy_sdk::DataProxyStreamReader> stream_reader)\n      : stream_reader_(std::move(stream_reader)) {}\n\n  std::optional<arrow::ChunkedArrayVector> Fetch() override;\n  std::shared_ptr<arrow::Schema> GetSchema() override {\n    return stream_reader_->Schema();\n  };\n\n private:\n  std::unique_ptr<dataproxy_sdk::DataProxyStreamReader> stream_reader_;\n};\nclass DmAdaptor : public DatasourceAdaptor {\n public:\n  explicit DmAdaptor(std::string datasource_id)\n      : datasource_id_(std::move(datasource_id)) {}\n\n  ~DmAdaptor() override = default;\n\n private:\n  // Send query and return schema\n  std::shared_ptr<ChunkedResult> SendQuery(const std::string& query) override;\n\n  std::string datasource_id_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/dm_adaptor_factory.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/dm_adaptor_factory.h\"\n\n#include \"engine/datasource/dm_adaptor.h\"\n\nnamespace scql::engine {\n\nstd::unique_ptr<DatasourceAdaptor> DmAdaptorFactory::CreateAdaptor(\n    const DataSource& datasource_spec) {\n  return std::make_unique<DmAdaptor>(datasource_spec.connection_str());\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/dm_adaptor_factory.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/datasource/datasource_adaptor_factory.h\"\n\nnamespace scql::engine {\n\nclass DmAdaptorFactory final : public DatasourceAdaptorFactory {\n public:\n  std::unique_ptr<DatasourceAdaptor> CreateAdaptor(\n      const DataSource& datasource_spec) override;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/dm_adaptor_kuscia_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <gflags/gflags_declare.h>\n\n#include <iostream>\n\n#include \"absl/debugging/failure_signal_handler.h\"\n#include \"absl/debugging/symbolize.h\"\n#include \"absl/flags/flag.h\"\n#include \"absl/flags/parse.h\"\n#include \"absl/strings/str_split.h\"\n#include \"gflags/gflags.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/datasource/dm_adaptor.h\"\n\nDEFINE_string(domaindata_id, \"\", \"domain data id split by ','\");\n\nDECLARE_string(kuscia_datamesh_endpoint);\nDECLARE_string(kuscia_datamesh_client_key_path);\nDECLARE_string(kuscia_datamesh_client_cert_path);\nDECLARE_string(kuscia_datamesh_cacert_path);\n\nusing namespace scql::engine;\n\nint main(int argc, char* argv[]) {\n  {\n    absl::InitializeSymbolizer(argv[0]);\n\n    absl::FailureSignalHandlerOptions options;\n    absl::InstallFailureSignalHandler(options);\n  }\n\n  gflags::ParseCommandLineFlags(&argc, &argv, true);\n  // Given\n  DmAdaptor adaptor(FLAGS_domaindata_id);\n  // When\n  const std::string query = \"SELECT count(*) as tt FROM table;\";\n  std::vector<ColumnDesc> outputs{{\"tt\", scql::pb::PrimitiveDataType::INT64}};\n\n  auto results = adaptor.ExecQuery(query, outputs);\n  std::cout << \"results.size: \" << results.size() << '\\n';\n  std::cout << \"results length: \" << results[0]->Length() << '\\n';\n  std::cout << \"results null count: \" << results[0]->GetNullCount() << '\\n';\n  std::cout << \"results to string: \"\n            << results[0]->ToArrowChunkedArray()->ToString() << '\\n';\n  return 0;\n}"
  },
  {
    "path": "engine/datasource/dp_adaptor.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/dp_adaptor.h\"\n\n#include <memory>\n#include <optional>\n\n#include \"arrow/table.h\"\n#include \"google/protobuf/util/json_util.h\"\n\n#include \"engine/core/arrow_helper.h\"\n\n#include \"engine/datasource/dataproxy_conf.pb.h\"\n#include \"google/protobuf/any.pb.h\"\nnamespace scql::engine {\n\nDpAdaptor::DpAdaptor(std::string json_str) {\n  datasource::DataProxyConf dp_conf;\n  auto status = google::protobuf::util::JsonStringToMessage(json_str, &dp_conf);\n  YACL_ENFORCE(status.ok(),\n               \"failed to parse json to dataproxy conf: json={}, error={}\",\n               json_str, status.ToString());\n\n  // construct command_ and client_\n  command_.mutable_datasource()->CopyFrom(dp_conf.datasource());\n\n  arrow::flight::Location location;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      location, arrow::flight::Location::Parse(dp_conf.dp_uri()));\n  arrow::flight::FlightClientOptions\n      options;  // TODO: support tls and more options\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      client_, arrow::flight::FlightClient::Connect(location, options));\n}\n\nstd::shared_ptr<ChunkedResult> DpAdaptor::SendQuery(const std::string& query) {\n  command_.mutable_query()->set_sql(query);\n  google::protobuf::Any any_msg;\n  any_msg.PackFrom(command_);\n  std::string serialized_data;\n  YACL_ENFORCE(any_msg.SerializeToString(&serialized_data),\n               \"failed to serialize the flight command\");\n\n  std::unique_ptr<arrow::flight::FlightInfo> flight_info;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      flight_info,\n      client_->GetFlightInfo(\n          arrow::flight::FlightDescriptor::Command(serialized_data)));\n\n  arrow::ipc::DictionaryMemo memo;\n  std::shared_ptr<arrow::Schema> schema;\n  ASSIGN_OR_THROW_ARROW_STATUS(schema, flight_info->GetSchema(&memo));\n  return std::make_shared<DpChunkedResult>(schema, std::move(flight_info),\n                                           client_.get());\n}\n\nstd::optional<arrow::ChunkedArrayVector> DpChunkedResult::Fetch() {\n  if (endpoint_index_ >= flight_info_->endpoints().size()) {\n    return std::nullopt;\n  }\n\n  auto endpoint = flight_info_->endpoints()[endpoint_index_];\n  endpoint_index_++;\n\n  std::unique_ptr<arrow::flight::FlightStreamReader> stream;\n  YACL_ENFORCE(client_);\n  ASSIGN_OR_THROW_ARROW_STATUS(stream, client_->DoGet(endpoint.ticket));\n\n  std::shared_ptr<arrow::Table> table;\n  // TODO: maybe we should use stream.Next() to get data by batch\n  ASSIGN_OR_THROW_ARROW_STATUS(table, stream->ToTable());\n  THROW_IF_ARROW_NOT_OK(table->Validate());\n\n  arrow::ChunkedArrayVector arrs;\n  for (int i = 0; i < table->num_columns(); ++i) {\n    arrs.push_back(table->column(i));\n  }\n\n  return arrs;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/dp_adaptor.h",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <utility>\n\n#include \"arrow/flight/client.h\"\n#include \"arrow/type_fwd.h\"\n\n#include \"engine/datasource/datasource_adaptor.h\"\n\n#include \"engine/util/dp/flight.pb.h\"\n\nnamespace scql::engine {\n\nusing kuscia::proto::api::v1alpha1::datamesh::CommandDataMeshSqlQuery;\n\nclass DpChunkedResult : public ChunkedResult {\n public:\n  DpChunkedResult(std::shared_ptr<arrow::Schema> schema,\n                  std::unique_ptr<arrow::flight::FlightInfo> flight_info,\n                  arrow::flight::FlightClient* client_ptr)\n      : schema_(std::move(schema)),\n        flight_info_(std::move(flight_info)),\n        client_(client_ptr) {}\n\n  std::optional<arrow::ChunkedArrayVector> Fetch() override;\n  std::shared_ptr<arrow::Schema> GetSchema() override { return schema_; };\n\n private:\n  std::shared_ptr<arrow::Schema> schema_;\n  std::unique_ptr<arrow::flight::FlightInfo> flight_info_;\n  size_t endpoint_index_ = 0;\n  arrow::flight::FlightClient* client_ = nullptr;\n};\n\nclass DpAdaptor : public DatasourceAdaptor {\n public:\n  explicit DpAdaptor(std::string json_str);\n\n  ~DpAdaptor() override = default;\n\n private:\n  // Send query and return schema\n  std::shared_ptr<ChunkedResult> SendQuery(const std::string& query) override;\n\n  CommandDataMeshSqlQuery command_;\n  std::unique_ptr<arrow::flight::FlightClient> client_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/dp_adaptor_factory.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/dp_adaptor_factory.h\"\n\n#include \"engine/datasource/dp_adaptor.h\"\n\nnamespace scql::engine {\n\nstd::unique_ptr<DatasourceAdaptor> DpAdaptorFactory::CreateAdaptor(\n    const DataSource& datasource_spec) {\n  return std::make_unique<DpAdaptor>(datasource_spec.connection_str());\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/dp_adaptor_factory.h",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/datasource/datasource_adaptor_factory.h\"\n\nnamespace scql::engine {\n\nclass DpAdaptorFactory final : public DatasourceAdaptorFactory {\n public:\n  std::unique_ptr<DatasourceAdaptor> CreateAdaptor(\n      const DataSource& datasource_spec) override;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/dp_adaptor_test.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/dp_adaptor.h\"\n\n#include <gtest/gtest.h>\n\n#include \"arrow/flight/client.h\"\n#include \"arrow/table.h\"\n#include \"google/protobuf/util/json_util.h\"\n\nusing namespace testing;\n\nnamespace scql::engine {\n\nstd::string GenerateValidJson() {\n  return R\"json({\"dp_uri\":\"grpc+tcp://localhost:8989\",\"datasource\":{\"type\":\"odps\",\"info\":{\"odps\":{\"endpoint\":\"xxx\",\"project\":\"xxx\",\"accessKeyId\":\"xxx\",\"accessKeySecret\":\"xxx\"}}}})json\";\n}\n\nTEST(DpAdaptorTest, Constructor) {\n  std::string json = GenerateValidJson();\n  // No exceptions should be thrown during construction\n  EXPECT_NO_THROW({ DpAdaptor dp_adaptor(json); });\n\n  std::string invalid_json = R\"({\"invalid_field\": \"missing_dp_uri\"})\";\n  EXPECT_THROW({ DpAdaptor dp_adaptor(invalid_json); }, yacl::EnforceNotMet);\n}\n\nTEST(DpAdaptorTest, OtherFunc) {\n  std::string json = GenerateValidJson();\n  DpAdaptor dp_adaptor(json);\n  std::vector<ColumnDesc> outputs{{\"age\", scql::pb::PrimitiveDataType::INT64}};\n  EXPECT_THROW(\n      {\n        auto results =\n            dp_adaptor.ExecQuery(\"SELECT age from user_credit;\", outputs);\n      },\n      yacl::RuntimeError);\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/duckdb_wrapper.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/duckdb_wrapper.h\"\n\n#include \"absl/strings/ascii.h\"\n#include \"duckdb/function/replacement_scan.hpp\"\n#include \"duckdb/function/table/read_csv.hpp\"\n#include \"duckdb/parser/expression/constant_expression.hpp\"\n#include \"duckdb/parser/expression/function_expression.hpp\"\n#include \"duckdb/parser/parsed_data/create_table_function_info.hpp\"\n#include \"duckdb/parser/tableref/table_function_ref.hpp\"\n#include \"gflags/gflags.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/util/filepath_helper.h\"\n\n#include \"api/v1/column.pb.h\"\n#include \"engine/datasource/csvdb_conf.pb.h\"\n\nnamespace scql::engine {\n\nDEFINE_bool(enable_restricted_read_path, true,\n            \"whether restrict path for file to read\");\nDEFINE_string(\n    restricted_read_path, \"./data\",\n    \"in where the file is allowed to read if enable restricted read path\");\nDEFINE_string(csv_null_str, \"NULL\",\n              \"specifies the string that represents a NULL value.\");\n\nnamespace {\n\nstatic duckdb::LogicalTypeId ToLogicalTypeId(scql::api::v1::DataType type) {\n  switch (type) {\n    case scql::api::v1::DataType::BOOL:\n      return duckdb::LogicalTypeId::BOOLEAN;\n    case scql::api::v1::DataType::INT8:\n      return duckdb::LogicalTypeId::TINYINT;\n    case scql::api::v1::DataType::INT16:\n      return duckdb::LogicalTypeId::SMALLINT;\n    case scql::api::v1::DataType::INT32:\n      return duckdb::LogicalTypeId::INTEGER;\n    // int -> int64, keep consistent with secretflow/spec\n    case scql::api::v1::DataType::INT:\n    case scql::api::v1::DataType::INTEGER:\n    case scql::api::v1::DataType::INT64:\n      return duckdb::LogicalTypeId::BIGINT;\n    case scql::api::v1::DataType::FLOAT32:\n      return duckdb::LogicalTypeId::FLOAT;\n    // float -> float64, keep consistent with secretflow/spec\n    case scql::api::v1::DataType::FLOAT:\n    case scql::api::v1::DataType::FLOAT64:\n    case scql::api::v1::DataType::DOUBLE:\n      return duckdb::LogicalTypeId::DOUBLE;\n    case scql::api::v1::DataType::STRING:\n    case scql::api::v1::DataType::STR:\n      return duckdb::LogicalTypeId::VARCHAR;\n    case scql::api::v1::DataType::DATETIME:\n      return duckdb::LogicalTypeId::TIMESTAMP_SEC;\n    case scql::api::v1::DataType::TIMESTAMP:\n      return duckdb::LogicalTypeId::TIMESTAMP_TZ;\n    default:\n      return duckdb::LogicalTypeId::INVALID;\n  }\n}\n\nstd::string ToDuckDBDataType(const std::string &type) {\n  duckdb::LogicalTypeId ret = duckdb::LogicalTypeId::INVALID;\n\n  scql::api::v1::DataType dtype;\n  if (scql::api::v1::DataType_Parse(absl::AsciiStrToUpper(type), &dtype)) {\n    ret = ToLogicalTypeId(dtype);\n  }\n\n  return duckdb::EnumUtil::ToString(ret);\n}\n\nstruct CSVTableReplacementScanData : public duckdb::ReplacementScanData {\n  const csv::CsvdbConf *csvdb_conf;\n};\n\nstatic duckdb::unique_ptr<duckdb::TableRef> CSVTableReplacementScan(\n    duckdb::ClientContext &context, duckdb::ReplacementScanInput &input,\n    duckdb::optional_ptr<duckdb::ReplacementScanData> data) {\n  const std::string &table_name = input.table_name;\n\n  auto scan_data = dynamic_cast<CSVTableReplacementScanData *>(data.get());\n  if (!scan_data || !scan_data->csvdb_conf) {\n    return nullptr;\n  }\n\n  const csv::CsvTableConf *csv_tbl = nullptr;\n  for (int i = 0; i < scan_data->csvdb_conf->tables_size(); ++i) {\n    std::string full_table_name;\n    if (scan_data->csvdb_conf->db_name().empty()) {\n      full_table_name = scan_data->csvdb_conf->tables(i).table_name();\n    } else {\n      full_table_name =\n          fmt::format(\"{}.{}\", scan_data->csvdb_conf->db_name(),\n                      scan_data->csvdb_conf->tables(i).table_name());\n    }\n\n    if (full_table_name == table_name) {\n      csv_tbl = &scan_data->csvdb_conf->tables(i);\n      break;\n    }\n  }\n  if (!csv_tbl) {\n    return nullptr;\n  }\n\n  auto table_function = std::make_unique<duckdb::TableFunctionRef>();\n  std::vector<duckdb::unique_ptr<duckdb::ParsedExpression>> children;\n  auto data_path = csv_tbl->data_path();\n  // NOTE: duckdb just support parse s3 prefix path url, ref:\n  // https://github.com/duckdb/duckdb/blob/v0.9.2/extension/httpfs/s3fs.cpp#L559\n  // if inherit from duckdb::S3FileSystem, we should rewrite the\n  // S3UrlParse. so here just replace prefix here, such as from oss://\n  // to s3://, then duckdb can parse the path url. When duckdb release\n  // next version, we can considier inherit from duckdb::S3FileSystem\n  // and make patch\n  auto scheme = util::GetS3LikeScheme(data_path);\n  if (!scheme.empty()) {\n    data_path.replace(0, scheme.length(), \"s3://\");\n  }\n  children.emplace_back(\n      duckdb::make_uniq<duckdb::ConstantExpression>(duckdb::Value(data_path)));\n\n  {\n    std::vector<duckdb::Value> names;\n    std::vector<duckdb::Value> types;\n    for (const auto &col : csv_tbl->columns()) {\n      names.emplace_back(col.column_name());\n      types.emplace_back(ToDuckDBDataType(col.column_type()));\n    }\n    children.emplace_back(duckdb::make_uniq<duckdb::ConstantExpression>(\n        duckdb::Value::LIST(duckdb::LogicalType::VARCHAR, std::move(names))));\n    children.emplace_back(duckdb::make_uniq<duckdb::ConstantExpression>(\n        duckdb::Value::LIST(duckdb::LogicalType::VARCHAR, std::move(types))));\n  }\n\n  table_function->function = duckdb::make_uniq<duckdb::FunctionExpression>(\n      \"csv_scan\", std::move(children));\n  return table_function;\n}\n\nstatic duckdb::unique_ptr<duckdb::FunctionData> CSVScanBind(\n    duckdb::ClientContext &context, duckdb::TableFunctionBindInput &input,\n    duckdb::vector<duckdb::LogicalType> &return_types,\n    duckdb::vector<std::string> &names) {\n  auto name_list = duckdb::ListValue::GetChildren(input.inputs[1]);\n  auto type_list = duckdb::ListValue::GetChildren(input.inputs[2]);\n  if (name_list.size() != type_list.size()) {\n    throw duckdb::BinderException(\n        \"csv_scan: name_list & type_list size mismatched\");\n  }\n  duckdb::child_list_t<duckdb::Value> columns;\n  for (size_t i = 0; i < name_list.size(); i++) {\n    if (name_list[i].type().id() != duckdb::LogicalTypeId::VARCHAR ||\n        type_list[i].type().id() != duckdb::LogicalTypeId::VARCHAR) {\n      throw duckdb::BinderException(\n          \"csv_scan requires a column name & type specification as \"\n          \"string\");\n    }\n    columns.emplace_back(\n        std::make_pair(duckdb::StringValue::Get(name_list[i]),\n                       duckdb::StringValue::Get(type_list[i])));\n  }\n  input.named_parameters[\"nullstr\"] = duckdb::Value(FLAGS_csv_null_str);\n  input.named_parameters[\"header\"] = duckdb::Value::BOOLEAN(true);\n  input.named_parameters[\"auto_detect\"] = duckdb::Value::BOOLEAN(true);\n  input.named_parameters[\"types\"] = duckdb::Value::STRUCT(std::move(columns));\n\n  // delegate to ReadCSVBind\n  return duckdb::ReadCSVTableFunction::GetFunction().bind(context, input,\n                                                          return_types, names);\n}\n\nstatic std::string CheckTablePathsAndGetPrefix(\n    const csv::CsvdbConf &csvdb_conf) {\n  std::string path_prefix;\n  for (const auto &table_conf : csvdb_conf.tables()) {\n    // If path not s3 and not illegal, exception will be thrown.\n    auto data_path = table_conf.data_path();\n    auto scheme = util::GetS3LikeScheme(data_path);\n    if (!scheme.empty()) {\n      if (!path_prefix.empty()) {\n        YACL_ENFORCE(path_prefix == scheme,\n                     \"csvdb_conf have different oss prefix\");\n      } else {\n        path_prefix = scheme;\n      }\n    } else {\n      util::CheckAndGetAbsoluteLocalPath(data_path,\n                                         FLAGS_enable_restricted_read_path,\n                                         FLAGS_restricted_read_path);\n    }\n  }\n\n  return path_prefix;\n}\n\n}  // namespace\n\nduckdb::DuckDB DuckDBWrapper::CreateDB(const csv::CsvdbConf *csvdb_conf) {\n  auto path_prefix = CheckTablePathsAndGetPrefix(*csvdb_conf);\n  auto scan_data = duckdb::make_uniq<CSVTableReplacementScanData>();\n  scan_data->csvdb_conf = csvdb_conf;\n\n  duckdb::DBConfig config;\n  config.replacement_scans.push_back(\n      duckdb::ReplacementScan(CSVTableReplacementScan, std::move(scan_data)));\n\n  duckdb::DuckDB db(nullptr, &config);\n  if (!csvdb_conf->s3_conf().endpoint().empty()) {\n    auto &db_config = duckdb::DBConfig::GetConfig(*db.instance);\n\n    std::string endpoint = csvdb_conf->s3_conf().endpoint();\n    bool use_ssl = util::GetAndRemoveS3EndpointPrefix(endpoint);\n\n    db_config.SetOption(\"s3_endpoint\", duckdb::Value(endpoint));\n    db_config.SetOption(\"s3_access_key_id\",\n                        duckdb::Value(csvdb_conf->s3_conf().access_key_id()));\n    db_config.SetOption(\n        \"s3_secret_access_key\",\n        duckdb::Value(csvdb_conf->s3_conf().secret_access_key()));\n    db_config.SetOption(\"s3_use_ssl\", duckdb::Value(use_ssl));\n\n    if (!csvdb_conf->s3_conf().virtualhost()) {\n      db_config.SetOption(\"s3_url_style\", duckdb::Value(\"path\"));\n    }\n  }\n\n  return db;\n}\n\nvoid DuckDBWrapper::CreateCSVScanFunction(duckdb::Connection &conn) {\n  auto &context = *conn.context;\n  auto &catalog = duckdb::Catalog::GetSystemCatalog(context);\n\n  duckdb::TableFunction read_csv = duckdb::ReadCSVTableFunction::GetFunction();\n\n  duckdb::TableFunction csv_scan(\n      \"csv_scan\",\n      {duckdb::LogicalType::VARCHAR,\n       duckdb::LogicalType::LIST(duckdb::LogicalType::VARCHAR),\n       duckdb::LogicalType::LIST(duckdb::LogicalType::VARCHAR)},\n      read_csv.function, CSVScanBind, read_csv.init_global,\n      read_csv.init_local);\n  csv_scan.table_scan_progress = read_csv.table_scan_progress;\n  csv_scan.pushdown_complex_filter = read_csv.pushdown_complex_filter;\n  csv_scan.serialize = read_csv.serialize;\n  csv_scan.deserialize = read_csv.deserialize;\n  csv_scan.get_batch_index = read_csv.get_batch_index;\n  csv_scan.cardinality = read_csv.cardinality;\n  csv_scan.projection_pushdown = read_csv.projection_pushdown;\n\n  csv_scan.named_parameters = read_csv.named_parameters;\n\n  duckdb::CreateTableFunctionInfo info(std::move(csv_scan));\n  catalog.CreateTableFunction(context, &info);\n  return;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/duckdb_wrapper.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"duckdb.hpp\"\n\n#include \"engine/datasource/csvdb_conf.pb.h\"\n\nnamespace scql::engine {\n\nclass DuckDBWrapper {\n public:\n  static duckdb::DuckDB CreateDB(const csv::CsvdbConf* csvdb_conf);\n\n  // NOTE: This function must be called in an active transaction\n  // For example:\n  // ```cpp\n  // conn.BeginTransaction();\n  // CreateCSVScanFunction(conn);\n  // conn.Commit();\n  // ```\n  static void CreateCSVScanFunction(duckdb::Connection& conn);\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/duckdb_wrapper_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/duckdb_wrapper.h\"\n\n#include \"butil/files/temp_file.h\"\n#include \"fmt/format.h\"\n#include \"gflags/gflags.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/datasource/csvdb_conf.pb.h\"\n\nnamespace scql::engine {\n\nDECLARE_string(restricted_read_path);\nnamespace {\n\n::testing::AssertionResult ColumnEquals(\n    duckdb::ClientContext& context, const duckdb::DataChunk& chunk,\n    size_t col_idx, const std::vector<duckdb::Value>& values) {\n  if (chunk.size() != values.size()) {\n    return ::testing::AssertionFailure()\n           << fmt::format(\"chunk' size({}) doesn't match value's size({})\",\n                          chunk.size(), values.size());\n  }\n  auto& vector = chunk.data[col_idx];\n  for (std::size_t i = 0; i < values.size(); i++) {\n    if (!duckdb::Value::ValuesAreEqual(context, vector.GetValue(i),\n                                       values[i])) {\n      return ::testing::AssertionFailure()\n             << \"the #\" << i\n             << \"th element is not equal, got=\" << vector.GetValue(i).ToString()\n             << \", while expected=\" << values[i].ToString();\n    }\n  }\n  return ::testing::AssertionSuccess();\n}\n\n}  // namespace\n\nclass DuckdbWrapperTest : public ::testing::Test {\n protected:\n  void SetUp() override {\n    temp_file_ = std::make_unique<butil::TempFile>(\"csv\");\n    temp_file_->save(csv_content_.c_str());\n    {\n      csvdb_conf_.set_db_name(\"csvdb\");\n      auto table = csvdb_conf_.add_tables();\n      table->set_table_name(\"staff\");\n      table->set_data_path(temp_file_->fname());\n\n      auto column = table->add_columns();\n      column->set_column_name(\"ID\");\n      column->set_column_type(\"string\");\n      // ignore setting 'age' column and swap the 'income' and 'name' columns to\n      // test auto_detection feature in NormalQuery\n      column = table->add_columns();\n      column->set_column_name(\"income\");\n      column->set_column_type(\"double\");\n      column = table->add_columns();\n      column->set_column_name(\"name\");\n      column->set_column_type(\"string\");\n    }\n  }\n\n public:\n  csv::CsvdbConf csvdb_conf_;\n  std::unique_ptr<butil::TempFile> temp_file_;\n  std::string csv_content_ = R\"csv(id,age,name,income\n1,25,bob,25000.1\n2,30,alice,48000\n3,42,\"\",98000\n4,18,NULL,118000)csv\";\n};\n\nTEST_F(DuckdbWrapperTest, NormalQuery) {\n  FLAGS_restricted_read_path = \"./\";\n  duckdb::DuckDB db = DuckDBWrapper::CreateDB(&csvdb_conf_);\n  duckdb::Connection conn(db);\n\n  conn.BeginTransaction();\n  DuckDBWrapper::CreateCSVScanFunction(conn);\n  conn.Commit();\n\n  auto result = conn.Query(\"select * from csvdb.staff\");\n  EXPECT_FALSE(result->HasError()) << result->GetError();\n  ASSERT_EQ(result->RowCount(), 4);\n  ASSERT_EQ(result->ColumnCount(), 4);\n  auto data_chunk = result->Fetch();\n\n  // column \"id\", the type is manually specified as VARCHAR instead of the\n  // default BIGINT\n  EXPECT_TRUE(\n      ColumnEquals(*conn.context, *data_chunk, 0, {\"1\", \"2\", \"3\", \"4\"}));\n  EXPECT_TRUE(data_chunk->data[0].GetType() == duckdb::LogicalType::VARCHAR);\n  // column \"age\"\n  EXPECT_TRUE(ColumnEquals(*conn.context, *data_chunk, 1, {25, 30, 42, 18}));\n  EXPECT_TRUE(data_chunk->data[1].GetType() == duckdb::LogicalType::BIGINT);\n  // column \"name\"\n  EXPECT_TRUE(ColumnEquals(*conn.context, *data_chunk, 2,\n                           {\"bob\", \"alice\", \"\", duckdb::Value()}));\n  EXPECT_TRUE(data_chunk->data[2].GetType() == duckdb::LogicalType::VARCHAR);\n  // column \"income\"\n  EXPECT_TRUE(ColumnEquals(*conn.context, *data_chunk, 3,\n                           {25000.1, 48000, 98000, 118000}));\n  EXPECT_TRUE(data_chunk->data[3].GetType() == duckdb::LogicalType::DOUBLE);\n}\n\nTEST_F(DuckdbWrapperTest, QueryWithPredicate) {\n  duckdb::DuckDB db = DuckDBWrapper::CreateDB(&csvdb_conf_);\n  duckdb::Connection conn(db);\n\n  conn.BeginTransaction();\n  DuckDBWrapper::CreateCSVScanFunction(conn);\n  conn.Commit();\n\n  auto result = conn.Query(\"select name from csvdb.staff where age > 30\");\n  EXPECT_FALSE(result->HasError()) << result->GetError();\n  ASSERT_EQ(result->RowCount(), 1);\n  ASSERT_EQ(result->ColumnCount(), 1);\n  auto data_chunk = result->Fetch();\n\n  // column \"name\"\n  EXPECT_TRUE(ColumnEquals(*conn.context, *data_chunk, 0, {\"\"}));\n}\n\nTEST_F(DuckdbWrapperTest, IngoringColumnCase) {\n  duckdb::DuckDB db = DuckDBWrapper::CreateDB(&csvdb_conf_);\n  duckdb::Connection conn(db);\n\n  conn.BeginTransaction();\n  DuckDBWrapper::CreateCSVScanFunction(conn);\n  conn.Commit();\n\n  // AgE -> age\n  auto result = conn.Query(\"select AgE from csvdb.staff\");\n  EXPECT_FALSE(result->HasError()) << result->GetError();\n  ASSERT_EQ(result->RowCount(), 4);\n  ASSERT_EQ(result->ColumnCount(), 1);\n  auto data_chunk = result->Fetch();\n\n  EXPECT_TRUE(ColumnEquals(*conn.context, *data_chunk, 0, {25, 30, 42, 18}));\n}\n\nTEST_F(DuckdbWrapperTest, DISABLED_ComplexQueryWithBigDataset) {\n  // test with dataset download from kaggle:\n  // https://www.kaggle.com/datasets/luiscorter/netflix-original-films-imdb-scores\n  // download the dataset and rename header \"IMDB Score\" to \"IMDB_Score\".\n  csv::CsvdbConf csvdb_conf;\n  {\n    csvdb_conf.set_db_name(\"csvdb\");\n    auto table = csvdb_conf.add_tables();\n    table->set_table_name(\"netflix_original_films_imdb_scores\");\n    table->set_data_path(\"./netflix_original_films_imdb_scores.csv\");\n\n    auto column = table->add_columns();\n    column->set_column_name(\"Title\");\n    column->set_column_type(\"string\");\n\n    column = table->add_columns();\n    column->set_column_name(\"Genre\");\n    column->set_column_type(\"string\");\n\n    column = table->add_columns();\n    column->set_column_name(\"Premiere\");\n    column->set_column_type(\"string\");\n\n    column = table->add_columns();\n    column->set_column_name(\"Runtime\");\n    column->set_column_type(\"int64\");\n\n    column = table->add_columns();\n    column->set_column_name(\"IMDB_Score\");\n    column->set_column_type(\"double\");\n\n    column = table->add_columns();\n    column->set_column_name(\"Language\");\n    column->set_column_type(\"string\");\n  }\n\n  duckdb::DuckDB db = DuckDBWrapper::CreateDB(&csvdb_conf);\n  duckdb::Connection conn(db);\n\n  conn.BeginTransaction();\n  DuckDBWrapper::CreateCSVScanFunction(conn);\n  conn.Commit();\n\n  auto result = conn.Query(\n      \"select Genre, count(*) as cnt, avg(IMDB_Score) as avg_score from \"\n      \"csvdb.netflix_original_films_imdb_scores where Runtime > 60 and \"\n      \"IMDB_Score > 3 group by Genre order by cnt desc\");\n  EXPECT_FALSE(result->HasError()) << result->GetError();\n  ASSERT_EQ(result->RowCount(), 104);\n  ASSERT_EQ(result->ColumnCount(), 3);\n\n  // The first row is \"Documentary, 118, 7.079661016949156\"\n  auto data_chunk = result->Fetch();\n  EXPECT_EQ(data_chunk->data[1].GetValue(0), 118);\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/embed_router.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/embed_router.h\"\n\n#include \"absl/strings/str_split.h\"\n#include \"google/protobuf/util/json_util.h\"\n#include \"spdlog/spdlog.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/datasource/csvdb_conf.pb.h\"\n\nnamespace scql::engine {\n\nstd::vector<DataSource> EmbedRouter::Route(\n    const std::vector<std::string>& table_refs) {\n  std::vector<std::string> datasource_ids;\n\n  for (const auto& table_ref : table_refs) {\n    // 1. find it in table level route rules\n    {\n      auto iter = table_route_map_.find(table_ref);\n      if (iter != table_route_map_.end()) {\n        datasource_ids.push_back(iter->second);\n        continue;\n      }\n    }\n\n    // 2. find it in db level route rules\n    {\n      std::vector<absl::string_view> fields = absl::StrSplit(table_ref, '.');\n      if (fields.size() != 2) {\n        YACL_THROW(\"Fail to split '$db.$table' format from: {}\", table_ref);\n      }\n\n      auto iter = db_route_map_.find(fields[0]);\n      if (iter != db_route_map_.end()) {\n        datasource_ids.push_back(iter->second);\n        continue;\n      }\n    }\n\n    // 3. default route rule\n    if (default_route_datasource_.has_value()) {\n      datasource_ids.push_back(default_route_datasource_.value());\n      continue;\n    }\n\n    YACL_THROW(\"Fail to find datasource for table={}\", table_ref);\n  }\n\n  std::vector<DataSource> result(datasource_ids.size());\n  for (size_t i = 0; i < datasource_ids.size(); i++) {\n    auto iter = datasource_map_.find(datasource_ids[i]);\n    if (iter == datasource_map_.end()) {\n      YACL_THROW(\"Fail to find datasource id={}\", datasource_ids[i]);\n    }\n    result[i].CopyFrom(iter->second);\n  }\n  return result;\n}\n\nstd::unique_ptr<EmbedRouter> EmbedRouter::FromJsonStr(\n    std::string_view json_str) {\n  EmbedRouterConf router_conf;\n  auto status =\n      google::protobuf::util::JsonStringToMessage(json_str, &router_conf);\n  if (!status.ok()) {\n    YACL_THROW(\"Fail to parse json_str to `EmbedRouterConf`, reason={}\",\n               status.ToString());\n  }\n\n  return FromProto(router_conf);\n}\n\nstd::unique_ptr<EmbedRouter> EmbedRouter::FromConnectionStr(\n    const std::string& connection_str) {\n  EmbedRouterConf router_conf;\n  const std::string kDefaultDatasourceId = \"ds001\";\n  {\n    auto* ds = router_conf.add_datasources();\n    ds->set_id(kDefaultDatasourceId);\n    ds->set_name(\"default db\");\n    ds->set_kind(DataSourceKind::MYSQL);\n    ds->set_connection_str(connection_str);\n  }\n  {\n    auto* rule = router_conf.add_rules();\n    rule->set_db(\"*\");\n    rule->set_table(\"*\");\n    rule->set_datasource_id(kDefaultDatasourceId);\n  }\n\n  return FromProto(router_conf);\n}\n\nstd::unique_ptr<EmbedRouter> EmbedRouter::FromFilePaths(\n    const google::protobuf::Map<std::string, std::string>& input_file_paths) {\n  EmbedRouterConf router_conf;\n\n  std::string db_name;\n  std::string datasource_id;\n  csv::CsvdbConf csv_conf;\n\n  for (const auto& [table_ref, file_path] : input_file_paths) {\n    // Parse table_ref to extract db and table\n    std::vector<absl::string_view> fields = absl::StrSplit(table_ref, '.');\n    std::string current_db_name;\n    std::string table_name;\n\n    YACL_ENFORCE(fields.size() == 2,\n                 \"Invalid table_ref format: {}, expected 'db.table' format\",\n                 table_ref);\n    current_db_name = std::string(fields[0]);\n    table_name = std::string(fields[1]);\n\n    if (db_name.empty()) {\n      db_name = current_db_name;\n      datasource_id = fmt::format(\"csvdb_{}\", db_name);\n\n      auto* ds = router_conf.add_datasources();\n      ds->set_id(datasource_id);\n      ds->set_name(fmt::format(\"CSV database for {}\", db_name));\n      ds->set_kind(DataSourceKind::CSVDB);\n\n      csv_conf.set_db_name(db_name);\n\n      SPDLOG_INFO(\"Creating datasource '{}' for db '{}'\", datasource_id,\n                  db_name);\n    }\n\n    YACL_ENFORCE(db_name == current_db_name,\n                 \"Multiple databases detected: '{}' and '{}'. Only one \"\n                 \"database is supported in FromFilePaths\",\n                 db_name, current_db_name);\n\n    auto* csv_tbl = csv_conf.add_tables();\n    csv_tbl->set_table_name(table_name);\n    csv_tbl->set_data_path(file_path);\n\n    auto* rule = router_conf.add_rules();\n    rule->set_db(db_name);\n    rule->set_table(table_name);\n    rule->set_datasource_id(datasource_id);\n  }\n\n  YACL_ENFORCE(!db_name.empty(),\n               \"No valid table references found in input_file_paths\");\n\n  // Serialize CsvdbConf to JSON and set as connection string\n  std::string connection_str;\n  auto status =\n      google::protobuf::util::MessageToJsonString(csv_conf, &connection_str);\n  YACL_ENFORCE(status.ok(), \"Failed to serialize CsvdbConf to JSON: {}\",\n               status.ToString());\n\n  bool found_datasource = false;\n  for (auto& ds : *router_conf.mutable_datasources()) {\n    if (ds.id() == datasource_id) {\n      ds.set_connection_str(connection_str);\n      found_datasource = true;\n      break;\n    }\n  }\n\n  YACL_ENFORCE(found_datasource, \"Failed to find datasource with id: {}\",\n               datasource_id);\n\n  return FromProto(router_conf);\n}\n\nstd::unique_ptr<EmbedRouter> EmbedRouter::FromProto(\n    const EmbedRouterConf& router_conf) {\n  auto router = std::make_unique<EmbedRouter>();\n  // initialize router with router_conf\n  {\n    for (const auto& ds : router_conf.datasources()) {\n      auto ret = router->datasource_map_.insert({ds.id(), ds});\n      if (!ret.second) {\n        YACL_THROW(\"Fail to insert datasource: duplicate id={}\", ds.id());\n      }\n    }\n\n    for (const auto& rule : router_conf.rules()) {\n      // check rule target <datasource_id> exists\n      YACL_ENFORCE(router->datasource_map_.contains(rule.datasource_id()),\n                   \"Fail to find associated datasource for rule={}\",\n                   rule.ShortDebugString());\n\n      if (rule.db() == \"*\" && rule.table() == \"*\") {\n        if (router->default_route_datasource_.has_value()) {\n          YACL_THROW(\"Fail to set default route rule: exists already.\");\n        }\n        router->default_route_datasource_ = rule.datasource_id();\n        continue;\n      } else if (rule.table() == \"*\") {  // rule.db() != \"*\"\n        router->db_route_map_[rule.db()] = rule.datasource_id();\n        continue;\n      } else if (rule.db() == \"*\") {  // rule.table() != \"*\"\n        YACL_ENFORCE(\n            \"Fail to parse rule: not support format (db=\\\"*\\\",table!=\\\"*\\\"), \"\n            \"rule={}\",\n            rule.ShortDebugString());\n      } else {  // rule.db() != \"*\" && rule.table() != \"*\"\n        router\n            ->table_route_map_[fmt::format(\"{}.{}\", rule.db(), rule.table())] =\n            rule.datasource_id();\n        continue;\n      }\n    }\n  }\n\n  return router;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/embed_router.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n#include <optional>\n#include <string_view>\n\n#include \"absl/container/flat_hash_map.h\"\n\n#include \"engine/datasource/router.h\"\n\n#include \"engine/datasource/embed_router.pb.h\"\n\nnamespace scql::engine {\n\n// EmbedRouter is built from static configuration file\nclass EmbedRouter final : public Router {\n public:\n  virtual ~EmbedRouter() {}\n\n  std::vector<DataSource> Route(\n      const std::vector<std::string>& table_refs) override;\n\n public:\n  static std::unique_ptr<EmbedRouter> FromJsonStr(std::string_view json_str);\n\n  // Only support MYSQL's connection string temporarily.\n  // TODO(jingshi) : Add DataSourceKind: HTTP/CVSDB... if needed.\n  static std::unique_ptr<EmbedRouter> FromConnectionStr(\n      const std::string& connection_str);\n\n  // Build router from input file paths for kpad task mode\n  static std::unique_ptr<EmbedRouter> FromFilePaths(\n      const google::protobuf::Map<std::string, std::string>& input_file_paths);\n\n private:\n  static std::unique_ptr<EmbedRouter> FromProto(\n      const EmbedRouterConf& router_conf);\n\n private:\n  // $datasource_id --> datasource spec\n  absl::flat_hash_map<std::string, DataSource> datasource_map_;\n\n  // table level route rule\n  // ($db,$table) -> datasource_id\n  absl::flat_hash_map<std::string, std::string> table_route_map_;\n\n  // database level route rule\n  // ($db) -> datasource_id\n  absl::flat_hash_map<std::string, std::string> db_route_map_;\n\n  // default route rule\n  std::optional<std::string> default_route_datasource_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/embed_router.proto",
    "content": "//\n// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.engine;\n\nimport \"engine/datasource/datasource.proto\";\n\n// `db.table` --> data source\n// `db` and `table` value can be asterisk wildcard \"*\"\n// Example:\n// Having following rules:\n// ```\n//     (db=\"db1\", table=\"t1\", datasource_id=\"ds001\")\n//     (db=\"db1\", table=\"t2\", datasource_id=\"ds002\")\n//     (db=\"db1\", table=\"*\", datasource_id=\"ds003\")\n//     (db=\"db2\", table=\"*\", datasource_id=\"ds004\")\n// ```\n// If request (db=\"db1\", table=\"t1\"), route to \"ds001\".\n// If request (db=\"db1\", table=\"t3\"), route to \"ds003\".\n// If request (db=\"db2\", table=\"t1\"), route to \"ds004\".\n// If request (db=\"db3\", table=\"t4\"), no route rules match, fallback to default\n// route datasource.\nmessage RouteRule {\n  string db = 1;\n  string table = 2;\n  string datasource_id = 3;\n}\n\n// EmbedRouterConf is used to bootstrap EmbedRouter from scratch\nmessage EmbedRouterConf {\n  repeated DataSource datasources = 1;\n  repeated RouteRule rules = 2;\n}"
  },
  {
    "path": "engine/datasource/embed_router_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/embed_router.h\"\n\n#include \"gtest/gtest.h\"\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine {\n\nclass EmbedRouterTest : public ::testing::Test {};\n\nTEST_F(EmbedRouterTest, FromJsonStr) {\n  // Given\n  const std::string conf = R\"json({\n    \"datasources\": [\n        {\n            \"id\": \"ds001\",\n            \"name\": \"mysql db\",\n            \"kind\": \"MYSQL\",\n            \"connection_str\": \"host=127.0.0.1 db=test\"\n        },\n        {\n            \"id\": \"ds002\",\n            \"name\": \"sqlite db\",\n            \"kind\": \"SQLITE\",\n            \"connection_str\": \"file:obdc_adaptor_test?mode=memory&cache=shared\"\n        },\n        {\n            \"id\": \"ds003\",\n            \"name\": \"postgresql db\",\n            \"kind\": \"POSTGRESQL\",\n            \"connection_str\": \"test str for postgresql\"\n        }\n    ],\n    \"rules\": [\n        {\n            \"db\": \"d1\",\n            \"table\": \"t1\",\n            \"datasource_id\": \"ds001\"\n        },\n        {\n            \"db\": \"d2\",\n            \"table\": \"*\",\n            \"datasource_id\": \"ds001\"\n        },\n        {\n            \"db\": \"d3\",\n            \"table\": \"*\",\n            \"datasource_id\": \"ds002\"\n        },\n        {\n            \"db\": \"*\",\n            \"table\": \"*\",\n            \"datasource_id\": \"ds001\"\n        },\n        {\n            \"db\": \"postgresql\",\n            \"table\": \"t1\",\n            \"datasource_id\": \"ds003\"\n        }\n    ]\n}\n)json\";\n\n  // When\n  std::unique_ptr<EmbedRouter> router;\n\n  EXPECT_NO_THROW({ router = EmbedRouter::FromJsonStr(conf); });\n\n  EXPECT_TRUE(router != nullptr);\n\n  std::vector<DataSource> datasources;\n  EXPECT_NO_THROW({\n    datasources = router->Route(std::vector<std::string>{\n        \"d1.t1\", \"d1.t2\", \"d2.t1\", \"d3.t3\", \"postgresql.t1\"});\n  });\n\n  // Then\n  EXPECT_EQ(datasources.size(), 5);\n  EXPECT_EQ(datasources[0].id(), \"ds001\");\n  EXPECT_EQ(datasources[0].kind(), DataSourceKind::MYSQL);\n\n  EXPECT_EQ(datasources[1].id(), \"ds001\");\n\n  EXPECT_EQ(datasources[2].id(), \"ds001\");\n\n  EXPECT_EQ(datasources[3].id(), \"ds002\");\n  EXPECT_EQ(datasources[3].kind(), DataSourceKind::SQLITE);\n\n  EXPECT_EQ(datasources[4].id(), \"ds003\");\n  EXPECT_EQ(datasources[4].kind(), DataSourceKind::POSTGRESQL);\n}\n\nTEST_F(EmbedRouterTest, FromConnectionStr) {\n  // Given\n  const std::string connection_str = \"host=127.0.0.1 db=test\";\n\n  // When\n  std::unique_ptr<EmbedRouter> router;\n\n  EXPECT_NO_THROW({ router = EmbedRouter::FromConnectionStr(connection_str); });\n\n  EXPECT_TRUE(router != nullptr);\n\n  std::vector<DataSource> datasources;\n  EXPECT_NO_THROW({\n    datasources =\n        router->Route(std::vector<std::string>{\"d1.t1\", \"d1.*\", \"*.*\"});\n  });\n\n  // Then\n  EXPECT_EQ(datasources.size(), 3);\n  for (size_t i = 0; i < datasources.size(); ++i) {\n    EXPECT_EQ(datasources[i].id(), \"ds001\");\n    EXPECT_EQ(datasources[i].kind(), DataSourceKind::MYSQL);\n  }\n}\n\nTEST_F(EmbedRouterTest, FromFilePaths_SingleTableNames_ShouldThrow) {\n  // Given: Input with single table names\n  google::protobuf::Map<std::string, std::string> input_file_paths;\n  input_file_paths[\"table1\"] = \"/path/to/table1.csv\";\n\n  // When & Then: Should throw exception for invalid format\n  std::unique_ptr<EmbedRouter> router;\n  EXPECT_THROW(\n      { router = EmbedRouter::FromFilePaths(input_file_paths); },\n      yacl::Exception);\n}\n\nTEST_F(EmbedRouterTest, FromFilePaths_SingleDbMultipleTables) {\n  // Given: Input with single database and multiple tables\n  google::protobuf::Map<std::string, std::string> input_file_paths;\n  input_file_paths[\"testdb.table1\"] = \"/path/to/table1.csv\";\n  input_file_paths[\"testdb.table2\"] = \"/path/to/table2.csv\";\n  input_file_paths[\"testdb.tbl_0\"] = \"/data/tbl_0.csv\";\n\n  // When\n  std::unique_ptr<EmbedRouter> router;\n  EXPECT_NO_THROW({ router = EmbedRouter::FromFilePaths(input_file_paths); });\n\n  EXPECT_TRUE(router != nullptr);\n\n  // Then: Test routing for db.table format\n  std::vector<DataSource> datasources;\n  EXPECT_NO_THROW({\n    datasources = router->Route(std::vector<std::string>{\n        \"testdb.table1\", \"testdb.table2\", \"testdb.tbl_0\"});\n  });\n\n  EXPECT_EQ(datasources.size(), 3);\n  for (const auto& datasource : datasources) {\n    EXPECT_EQ(datasource.id(), \"csvdb_testdb\");\n    EXPECT_EQ(datasource.kind(), DataSourceKind::CSVDB);\n  }\n}\n\nTEST_F(EmbedRouterTest, FromFilePaths_MultipleDatabases_ShouldThrow) {\n  // Given: Input with multiple databases\n  google::protobuf::Map<std::string, std::string> input_file_paths;\n  input_file_paths[\"db1.table1\"] = \"/path/to/db1_table1.csv\";\n  input_file_paths[\"db2.table2\"] = \"/path/to/db2_table2.csv\";\n\n  // When & Then: Should throw exception for multiple databases\n  std::unique_ptr<EmbedRouter> router;\n  EXPECT_THROW(\n      { router = EmbedRouter::FromFilePaths(input_file_paths); },\n      yacl::Exception);\n}\n\nTEST_F(EmbedRouterTest, FromFilePaths_InvalidFormat) {\n  // Given: Invalid table reference format (too many dots)\n  google::protobuf::Map<std::string, std::string> input_file_paths;\n  input_file_paths[\"db.table.invalid\"] = \"/path/to/invalid.csv\";\n\n  // When & Then: Should throw exception\n  std::unique_ptr<EmbedRouter> router;\n  EXPECT_THROW(\n      { router = EmbedRouter::FromFilePaths(input_file_paths); },\n      yacl::Exception);\n}\n\nTEST_F(EmbedRouterTest, FromFilePaths_EmptyInput_ShouldThrow) {\n  // Given: Empty input map\n  google::protobuf::Map<std::string, std::string> input_file_paths;\n\n  // When & Then: Should throw exception for empty input\n  std::unique_ptr<EmbedRouter> router;\n  EXPECT_THROW(\n      { router = EmbedRouter::FromFilePaths(input_file_paths); },\n      yacl::Exception);\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/http_router.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/http_router.h\"\n\n#include \"absl/strings/str_split.h\"\n#include \"brpc/channel.h\"\n#include \"google/protobuf/util/json_util.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/datasource/http_router.pb.h\"\n\nnamespace scql::engine {\n\nHttpRouter::HttpRouter(const HttpRouterOptions& options) : options_(options) {\n  if (options_.endpoint.empty()) {\n    throw std::invalid_argument(\"endpoint field of options cannot be empty\");\n  }\n}\n\nstd::vector<DataSource> HttpRouter::Route(\n    const std::vector<std::string>& table_refs) {\n  // 1. build request\n  ::router::RouteRequest request;\n\n  for (const auto& table_ref : table_refs) {\n    std::vector<std::string> fields = absl::StrSplit(table_ref, '.');\n    if (fields.size() != 2) {\n      YACL_THROW(\"invalid '$db.$table' format: {}\", table_ref);\n    }\n\n    auto tb = request.add_tables();\n    tb->set_db(fields[0]);\n    tb->set_table(fields[1]);\n  }\n\n  // 2. issue rpc\n  brpc::Channel channel;\n  brpc::ChannelOptions channel_options;\n\n  channel_options.protocol = \"http\";\n  channel_options.timeout_ms = options_.timeout_ms;\n  channel_options.max_retry = options_.max_retry;\n  if (channel.Init(options_.endpoint.c_str(), \"rr\", &channel_options) != 0) {\n    YACL_THROW(\"Failed to init channel to router with addr={}\",\n               options_.endpoint);\n  }\n\n  brpc::Controller cntl;\n\n  cntl.http_request().uri() = options_.endpoint;\n  cntl.http_request().set_method(brpc::HTTP_METHOD_POST);\n  cntl.http_request().set_content_type(\"application/json\");\n\n  {\n    std::string req;\n    auto status = google::protobuf::util::MessageToJsonString(request, &req);\n    if (!status.ok()) {\n      YACL_THROW(\n          \"Failed to converts request from protobuf message to JSON, reason={}\",\n          status.ToString());\n    }\n\n    cntl.request_attachment().append(req);\n  }\n  channel.CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr);\n\n  if (cntl.Failed()) {\n    YACL_THROW(\"Failed to request http router service {}, code={}, msg={}\",\n               options_.endpoint, cntl.ErrorCode(), cntl.ErrorText());\n  }\n\n  ::router::RouteResponse response;\n  {\n    std::string res = cntl.response_attachment().to_string();\n    google::protobuf::util::JsonParseOptions opts;\n    opts.case_insensitive_enum_parsing = true;\n    auto status =\n        google::protobuf::util::JsonStringToMessage(res, &response, opts);\n\n    if (!status.ok()) {\n      YACL_THROW(\"Failed to parse rpc response to RouteResponse, reason={}\",\n                 status.ToString());\n    }\n  }\n\n  if (response.status().code() != 0) {\n    YACL_THROW(\"router returns error: code={}, msg={}\",\n               response.status().code(), response.status().message());\n  }\n\n  if (table_refs.size() !=\n      static_cast<size_t>(response.datasource_ids_size())) {\n    YACL_THROW(\n        \"Mismatched size between response datasource_ids and request \"\n        \"table_refs, expect \"\n        \"{}, but got {}\",\n        table_refs.size(), response.datasource_ids_size());\n  }\n\n  std::vector<DataSource> result(table_refs.size());\n  for (size_t i = 0; i < table_refs.size(); i++) {\n    auto iter = response.datasources().find(response.datasource_ids(i));\n    if (iter == response.datasources().end()) {\n      YACL_THROW(\"Unable to find datasource id={} in response\",\n                 response.datasource_ids(i));\n    }\n    result[i].CopyFrom(iter->second);\n  }\n  return result;\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/http_router.h",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/datasource/router.h\"\n\nnamespace scql::engine {\n\nstruct HttpRouterOptions {\n  std::string endpoint;\n  int32_t timeout_ms = 3000;\n  int max_retry = 3;\n};\n\nclass HttpRouter final : public Router {\n public:\n  HttpRouter(const HttpRouterOptions& options);\n\n  std::vector<DataSource> Route(\n      const std::vector<std::string>& table_refs) override;\n\n private:\n  const HttpRouterOptions options_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/http_router.proto",
    "content": "//\n// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage router;\n\nimport \"engine/datasource/datasource.proto\";\nimport \"api/status.proto\";\nimport \"api/common.proto\";\n\noption cc_generic_services = true;\n\nservice RouterService {\n  rpc Route(RouteRequest) returns (RouteResponse);\n}\n\nmessage RouteRequest {\n  message Table {\n    string db = 1;\n    string table = 2;\n  }\n  scql.pb.RequestHeader header = 1;\n  repeated Table tables = 2;\n}\n\nmessage RouteResponse {\n  scql.pb.Status status = 1;\n  // datasource_ids should have the same size as argument `tables` in\n  // RouteRequest.\n  repeated string datasource_ids = 2;\n  // datasource_ids --> DataSouorce map\n  map<string, scql.engine.DataSource> datasources = 3;\n}"
  },
  {
    "path": "engine/datasource/kuscia_datamesh_router.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/kuscia_datamesh_router.h\"\n\n#include <cctype>\n#include <string>\n#include <utility>\n\n#include \"absl/strings/ascii.h\"\n#include \"absl/strings/str_split.h\"\n#include \"butil/files/file_path.h\"\n#include \"google/protobuf/util/json_util.h\"\n#include \"grpcpp/grpcpp.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/util/datamesh_helper.h\"\n#include \"engine/util/filepath_helper.h\"\n\n#include \"engine/datasource/csvdb_conf.pb.h\"\n\nnamespace scql::engine {\n\nnamespace dm = kuscia::proto::api::v1alpha1::datamesh;\n\nnamespace {\n\nDataSource MakeCSVDataSourceFromLocalfs(\n    const std::string& datasource_id, const std::string& name,\n    const dm::DomainData& domaindata, const dm::LocalDataSourceInfo& localfs) {\n  DataSource result;\n  result.set_id(datasource_id);\n  result.set_name(domaindata.name());\n  result.set_kind(DataSourceKind::CSVDB);\n  // constuct connection str\n  {\n    csv::CsvdbConf csv_conf;\n    auto csv_tbl = csv_conf.add_tables();\n\n    csv_tbl->set_table_name(domaindata.domaindata_id());\n    butil::FilePath path(localfs.path());\n    path = path.Append(domaindata.relative_uri());\n    csv_tbl->set_data_path(path.value());\n    for (const auto& column : domaindata.columns()) {\n      auto new_col = csv_tbl->add_columns();\n      new_col->set_column_name(column.name());\n      new_col->set_column_type(column.type());\n    }\n\n    std::string connection_str;\n    auto status =\n        google::protobuf::util::MessageToJsonString(csv_conf, &connection_str);\n    YACL_ENFORCE(status.ok(), \"failed to convert CsvdbConf to json string: {}\",\n                 status.ToString());\n    result.set_connection_str(connection_str);\n  }\n\n  return result;\n}\n\nDataSource MakeCSVDataSourceFromOSS(const std::string& datasource_id,\n                                    const std::string& name,\n                                    const dm::DomainData& domaindata,\n                                    const dm::OssDataSourceInfo& oss) {\n  DataSource result;\n  result.set_id(datasource_id);\n  result.set_name(domaindata.name());\n  result.set_kind(DataSourceKind::CSVDB);\n  // constuct connection str\n  {\n    csv::CsvdbConf csv_conf;\n\n    auto s3_conf = csv_conf.mutable_s3_conf();\n    s3_conf->set_endpoint(oss.endpoint());\n    s3_conf->set_access_key_id(oss.access_key_id());\n    s3_conf->set_secret_access_key(oss.access_key_secret());\n    s3_conf->set_virtualhost(oss.virtualhost());\n\n    auto csv_tbl = csv_conf.add_tables();\n    csv_tbl->set_table_name(domaindata.domaindata_id());\n    std::string s3_url = util::kSchemeS3 + oss.bucket();\n    if (!oss.prefix().empty()) {\n      s3_url += \"/\" + oss.prefix();\n    }\n    s3_url += \"/\" + domaindata.relative_uri();\n    csv_tbl->set_data_path(s3_url);\n    for (const auto& column : domaindata.columns()) {\n      auto new_col = csv_tbl->add_columns();\n      new_col->set_column_name(column.name());\n      new_col->set_column_type(column.type());\n    }\n\n    std::string connection_str;\n    auto status =\n        google::protobuf::util::MessageToJsonString(csv_conf, &connection_str);\n    YACL_ENFORCE(status.ok(), \"failed to convert CsvdbConf to json string: {}\",\n                 status.ToString());\n    result.set_connection_str(connection_str);\n  }\n\n  return result;\n}\n\nstd::pair<std::string, std::string> SplitHost(const std::string& host) {\n  std::string host_str = host;\n  std::string port_str;\n  size_t pos = host.find_last_of(':');\n  if (pos != std::string::npos) {\n    host_str = host.substr(0, pos);\n    port_str = host.substr(pos + 1);\n  }\n  return std::make_pair(host_str, port_str);\n}\n\nDataSource MakeMYSQLDataSource(const std::string& datasource_id,\n                               const dm::DomainData& domaindata,\n                               const dm::DomainDataSource& domaindata_source) {\n  DataSource result;\n  // use datasource_id due to domaindata in same datasource must have same id\n  result.set_id(datasource_id);\n  result.set_name(domaindata.name());\n  result.set_kind(DataSourceKind::MYSQL);\n  /// Connection string format:\n  ///     <str> == <assignment> | <assignment> ';' <str>\n  ///     <assignment> == <name> '=' <value>\n  ///     <name> == 'host' | 'port' | 'user' | 'password' | 'db' | 'compress' |\n  ///     'auto-reconnect' | 'reset' | 'fail-readonly'\n  ///     <value> == [~;]*\n  const auto database_source = domaindata_source.info().database();\n  std::string host;\n  std::string port;\n  std::tie(host, port) = SplitHost(database_source.endpoint());\n  auto connection_str = fmt::format(\n      \"db={};user={};password={};host={};\", database_source.database(),\n      database_source.user(), database_source.password(), host);\n  if (port != \"\") {\n    connection_str += fmt::format(\"port={};\", port);\n  }\n  connection_str += \"auto-reconnect=true\";\n  result.set_connection_str(connection_str);\n  return result;\n}\n\nDataSource MakePgDataSource(const std::string& datasource_id,\n                            const dm::DomainData& domaindata,\n                            const dm::DomainDataSource& domaindata_source) {\n  DataSource result;\n  // use datasource_id due to domaindata in same datasource must have same id\n  result.set_id(datasource_id);\n  result.set_name(domaindata.name());\n  result.set_kind(DataSourceKind::POSTGRESQL);\n  /// Connection string format:\n  /// <str> == <assignment> | <assignment> ' ' <str>\n  /// <assignment> == <name> '=' <value>\n  /// <name> == 'host' | 'port' | 'user' | 'password' | 'dbname' |\n  /// 'connect_timeout' <value> == [~;]*\n  const auto database_source = domaindata_source.info().database();\n  std::string host;\n  std::string port;\n  std::tie(host, port) = SplitHost(database_source.endpoint());\n  auto connection_str = fmt::format(\n      \"host={} dbname={} user={} password={}\", host, database_source.database(),\n      database_source.user(), database_source.password());\n  if (port != \"\") {\n    connection_str += fmt::format(\" port={}\", port);\n  }\n  result.set_connection_str(connection_str);\n  return result;\n}\n\nDataSource MakeDataMeshDataSource(\n    const std::string& datasource_id, const dm::DomainData& domaindata,\n    const dm::DomainDataSource& domaindata_source) {\n  DataSource result;\n  // use datasource_id due to domaindata in same datasource must have same id\n  result.set_id(datasource_id);\n  result.set_name(domaindata.name());\n  result.set_kind(DataSourceKind::DATAMESH);\n  // dataproxy use datasource_id to get ak/sk\n  result.set_connection_str(datasource_id);\n  return result;\n}\n\n}  // namespace\n\nKusciaDataMeshRouter::KusciaDataMeshRouter(\n    const std::string& endpoint,\n    const std::shared_ptr<grpc::ChannelCredentials>& credentials)\n    : endpoint_(endpoint), creds_(credentials) {}\n\nstd::vector<DataSource> KusciaDataMeshRouter::Route(\n    const std::vector<std::string>& table_refs) {\n  std::vector<DataSource> result;\n  // TODO: set timeout and retry policy\n  auto channel = grpc::CreateChannel(endpoint_, creds_);\n  for (auto table_ref : table_refs) {\n    result.push_back(SingleRoute(channel, table_ref));\n  }\n  return result;\n}\n\nDataSource KusciaDataMeshRouter::SingleRoute(\n    std::shared_ptr<grpc::Channel> channel, const std::string& domaindata_id) {\n  auto domaindata = util::QueryDomainData(channel, domaindata_id);\n  if (domaindata.datasource_id().empty()) {\n    YACL_THROW(\"datasource_id is empty for domaindata_id={}\", domaindata_id);\n  }\n\n  // TODO(optimization): use cache to speed-up\n  auto datasource =\n      util::QueryDomainDataSource(channel, domaindata.datasource_id());\n  std::string lower_type = absl::AsciiStrToLower(datasource.type());\n  // TODO(xiaoyuan): Determines whether to use access_directly to select the\n  // data source type\n  if (lower_type == \"localfs\") {\n    return MakeCSVDataSourceFromLocalfs(datasource.datasource_id(),\n                                        datasource.name(), domaindata,\n                                        datasource.info().localfs());\n  } else if (lower_type == \"oss\") {\n    return MakeCSVDataSourceFromOSS(datasource.datasource_id(),\n                                    datasource.name(), domaindata,\n                                    datasource.info().oss());\n  } else if (lower_type == \"mysql\") {\n    return MakeMYSQLDataSource(datasource.datasource_id(), domaindata,\n                               datasource);\n  } else if (lower_type == \"postgresql\" || lower_type == \"postgres\") {\n    return MakePgDataSource(datasource.datasource_id(), domaindata, datasource);\n  } else if (lower_type == \"odps\") {\n    return MakeDataMeshDataSource(datasource.datasource_id(), domaindata,\n                                  datasource);\n  } else {\n    YACL_THROW(\"unsupported datasource type: {}\", datasource.type());\n  }\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/kuscia_datamesh_router.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"grpcpp/channel.h\"\n#include \"grpcpp/security/credentials.h\"\n\n#include \"engine/datasource/router.h\"\n\nnamespace scql::engine {\n\nclass KusciaDataMeshRouter final : public Router {\n public:\n  KusciaDataMeshRouter(\n      const std::string& endpoint,\n      const std::shared_ptr<grpc::ChannelCredentials>& credentials);\n\n  std::vector<DataSource> Route(\n      const std::vector<std::string>& table_refs) override;\n\n private:\n  DataSource SingleRoute(std::shared_ptr<grpc::Channel> channel,\n                         const std::string& domaindata_id);\n\n private:\n  const std::string endpoint_;\n  std::shared_ptr<grpc::ChannelCredentials> creds_;\n};\n\n};  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/kuscia_datamesh_router_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/kuscia_datamesh_router.h\"\n\n#include \"absl/debugging/failure_signal_handler.h\"\n#include \"absl/debugging/symbolize.h\"\n#include \"absl/strings/str_split.h\"\n#include \"butil/file_util.h\"\n#include \"gflags/gflags.h\"\n#include \"yacl/base/exception.h\"\n\nDEFINE_string(kuscia_datamesh_endpoint, \"\", \"kuscia datamesh server endpoint\");\nDEFINE_string(domaindata_id, \"\", \"domain data id split by ','\");\nDEFINE_string(ca_cert, \"\", \"\");\nDEFINE_string(key, \"\", \"\");\nDEFINE_string(cert, \"\", \"\");\n\nusing namespace scql::engine;\n\ngrpc::SslCredentialsOptions read_credential_options() {\n  grpc::SslCredentialsOptions opts;\n  std::string content;\n  YACL_ENFORCE(\n      butil::ReadFileToString(butil::FilePath(FLAGS_ca_cert), &content));\n  opts.pem_root_certs = content;\n  YACL_ENFORCE(butil::ReadFileToString(butil::FilePath(FLAGS_key), &content));\n  opts.pem_private_key = content;\n  YACL_ENFORCE(butil::ReadFileToString(butil::FilePath(FLAGS_cert), &content));\n  opts.pem_cert_chain = content;\n  return opts;\n}\n\nint main(int argc, char* argv[]) {\n  {\n    absl::InitializeSymbolizer(argv[0]);\n\n    absl::FailureSignalHandlerOptions options;\n    absl::InstallFailureSignalHandler(options);\n  }\n\n  gflags::ParseCommandLineFlags(&argc, &argv, true);\n\n  auto ssl_opts = read_credential_options();\n  auto channel_creds = grpc::SslCredentials(ssl_opts);\n  KusciaDataMeshRouter router(FLAGS_kuscia_datamesh_endpoint, channel_creds);\n\n  try {\n    auto datasources = router.Route(absl::StrSplit(FLAGS_domaindata_id, ','));\n    // check datasource id coming from runsql\n    if (datasources.size() > 1) {\n      for (size_t i = 1; i < datasources.size(); ++i) {\n        if (datasources[i].id() != datasources[0].id()) {\n          YACL_THROW(\n              \"RunSQL operator could not handle query across datasource, \"\n              \"table_refs=[{}]\",\n              FLAGS_domaindata_id);\n        }\n      }\n    }\n    for (const auto& datasource : datasources) {\n      std::cout << \"Datasource: \" << datasource.ShortDebugString() << std::endl;\n    }\n  } catch (const std::exception& e) {\n    std::cerr << \"Something bad happend: \" << e.what() << std::endl;\n  }\n  return 0;\n}"
  },
  {
    "path": "engine/datasource/mock_router_readme.md",
    "content": "mock router\n===========\n\n1. start mock router server\n\n    ```shell\n    pip install -r ./requirements.txt\n\n    uvicorn --port 8000 mock_router_server:app\n    ```\n\n2. open <http://127.0.0.1:8000/> in browser to see the mock router\n\n3. register datasource & add route rule\n\n```shell\ncurl -X POST -H 'Content-Type: application/json' http://127.0.0.1:8000/datasource/register \\\n    -d '{\"name\": \"mysql source\", \"kind\": \"mysql\", \"connection_str\": \"xxx\"}'\n\ncurl -X POST -H 'Content-Type: application/json' http://127.0.0.1:8000/datasource/route_rule \\\n    -d '{\"db\": \"*\", \"table\": \"*\", \"datasource_id\": \"ds_0\"}'\n\n# test with route request\ncurl -X POST -H 'Content-Type: application/json' http://127.0.0.1:8000/datasource/route \\\n    -d '{\"tables\": [{\"db\": \"mydb\", \"table\": \"mytbl\"}]}'\n```\n"
  },
  {
    "path": "engine/datasource/mock_router_server.py",
    "content": "#!/usr/bin/env python3\n# Copyright 2024 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\nfrom jinja2 import Template\nfrom fastapi.responses import HTMLResponse\n\n\nclass Table(BaseModel):\n    db: str\n    table: str\n\n\nclass RouteRequest(BaseModel):\n    header: dict[str, str] | None\n    tables: list[Table]\n\n\nclass Status(BaseModel):\n    code: int = 0\n    message: str = \"ok\"\n\n\nclass DataSource(BaseModel):\n    id: str | None\n    name: str\n    kind: str\n    connection_str: str\n\n\nclass RouteResponse(BaseModel):\n    status: Status = Status()\n    datasource_ids: list[str]\n    datasources: dict[str, DataSource]\n\n\nclass RouteRule(BaseModel):\n    db: str\n    table: str\n    datasource_id: str\n\n\nclass MyStore:\n    def __init__(self):\n        self.ds = dict()\n        # mapping `dbName.tableName` to datasource ID\n        self.routeRules = dict()\n        # mapping `dbName.*` to datasource IDs\n        self.databaseRouteRules = dict()\n        self.defaultDataSourceID = \"\"\n        self.idx = 0\n\n    # return added datasource with new id\n    def add_datasource(self, ds):\n        ds.id = \"ds_{id}\".format(id=self.idx)\n        self.idx += 1\n        self.ds[ds.id] = ds\n        return ds\n\n    def add_route_rule(self, dbName, tableName, dsID):\n        if dbName == \"*\" and tableName == \"*\":\n            # overwrite default datasource if exists\n            self.defaultDataSourceID = dsID\n        elif tableName == \"*\":\n            self.databaseRouteRules[dbName] = dsID\n        else:\n            self.routeRules[\"{}.{}\".format(dbName, tableName)] = dsID\n\n    def route(self, dbName, tableName):\n        if f\"{dbName}.{tableName}\" in self.routeRules.keys():\n            return self.routeRules[f\"{dbName}.{tableName}\"]\n        elif dbName in self.databaseRouteRules.keys():\n            return self.databaseRouteRules[dbName]\n        elif self.defaultDataSourceID != \"\":\n            return self.defaultDataSourceID\n        return None\n\n\nstore = MyStore()\napp = FastAPI()\n\n\n@app.post(\"/datasource/route\")\ndef route(req: RouteRequest) -> RouteResponse:\n    if req.tables is None or len(req.tables) == 0:\n        return RouteResponse(\n            status=Status(code=100, message=\"bad request: empty tables in request\")\n        )\n\n    dsList = list()\n    for tbl in req.tables:\n        dsID = store.route(tbl.db, tbl.table)\n        if dsID is None:\n            return RouteResponse(\n                status=Status(code=140, message=\"route rule not found\")\n            )\n        else:\n            dsList.append(dsID)\n\n    datasources = dict()\n    for dsID in dsList:\n        if dsID in store.ds.keys():\n            datasources[dsID] = store.ds[dsID]\n        else:\n            return RouteResponse(\n                status=Status(code=141, message=\"datasource not found\")\n            )\n\n    return RouteResponse(\n        status=Status(code=0, message=\"ok\"),\n        datasource_ids=dsList,\n        datasources=datasources,\n    )\n\n\n@app.post(\"/datasource/register\")\ndef register(ds: DataSource):\n    return store.add_datasource(ds)\n\n\n@app.post(\"/datasource/route_rule\")\ndef add_route_rule(rule: RouteRule):\n    return store.add_route_rule(rule.db, rule.table, rule.datasource_id)\n\n\nindexTemplateContent = \"\"\"\n<html>\n<head>\n  <title> Mock Router Service </title>\n</head>\n<body>\n  <h1> Mock Router Service </h1>\n  <p> NOTE: only used for debug/testing purpose, please do not use it in production environment!!! </p>\n  <div class=\"datasource-list\">\n   <h1> Data Source List </h1>\n   <table border=\"1\">\n    <tr>\n      <td> id </td>\n      <td> name </td>\n      <td> kind </td>\n      <td> connection string </td>\n    </tr>\n    {% for key, value in datasources.items() %}\n      <tr>\n        <td> {{ value.id }} </td>\n        <td> {{ value.name }} </td>\n        <td> {{ value.kind }} </td>\n        <td> {{ value.connection_str }} </td>\n      </tr>\n    {% endfor %}\n   </table>\n  </div>\n  <div class=\"routerule-list\">\n    <h1> Route Rule List </h1>\n    <table border=\"1\">\n    <tr>\n      <td> rule </td>\n      <td> datasource id </td>\n    </tr>\n    {% for key, value in tableRoutingRules.items() %}\n     <tr>\n        <td> {{ key }} </td>\n        <td> {{ value }} </td>\n      </tr>\n    {% endfor %}\n    {% for key, value in dbRoutingRules.items() %}\n     <tr>\n        <td> {{ key }}.* </td>\n        <td> {{ value }} </td>\n      </tr>\n    {% endfor %}\n    {% if defaultRoutingRule != \"\" %}\n      <tr>\n        <td> *.* </td>\n        <td> {{ defaultRoutingRule }} </td>\n      </tr>\n    {% endif %}\n    </table>\n  </div>\n</body>\n</html>\n\"\"\"\n\nindexTemplate = Template(indexTemplateContent)\n\n\n@app.get(\"/\", response_class=HTMLResponse)\ndef index():\n    return indexTemplate.render(\n        datasources=store.ds,\n        tableRoutingRules=store.routeRules,\n        dbRoutingRules=store.databaseRouteRules,\n        defaultRoutingRule=store.defaultDataSourceID,\n    )\n"
  },
  {
    "path": "engine/datasource/odbc_adaptor.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/odbc_adaptor.h\"\n\n#include <cstddef>\n#include <cstdint>\n#include <functional>\n#include <memory>\n#include <optional>\n#include <vector>\n\n#include \"Poco/Data/MetaColumn.h\"\n#include \"Poco/Data/Range.h\"\n#include \"Poco/DateTime.h\"\n#include \"Poco/Dynamic/Var.h\"\n#include \"Poco/Timestamp.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/string_tensor_builder.h\"\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/spu_io.h\"\n\nnamespace scql::engine {\n\nOdbcAdaptor::OdbcAdaptor(const std::string& db_kind,\n                         const std::string& connection_str, ConnectionType type,\n                         size_t pool_size) {\n  connector_ =\n      std::make_unique<OdbcConnector>(db_kind, connection_str, type, pool_size);\n}\n\nnamespace {\nusing Poco::Data::MetaColumn;\n#define META_COLUMN_TYPE_CASE(type) case MetaColumn::ColumnDataType::type:\n\n#define SWITCH_DATE_BRANCH        \\\n  META_COLUMN_TYPE_CASE(FDT_DATE) \\\n  META_COLUMN_TYPE_CASE(FDT_TIME) \\\n  META_COLUMN_TYPE_CASE(FDT_TIMESTAMP)\n\n#define SWITCH_BOOL_BRANCH META_COLUMN_TYPE_CASE(FDT_BOOL)\n\n// FIXME: convert uint64 to int64 may overflow\n#define SWITCH_INT64_BRANCH         \\\n  META_COLUMN_TYPE_CASE(FDT_INT8)   \\\n  META_COLUMN_TYPE_CASE(FDT_UINT8)  \\\n  META_COLUMN_TYPE_CASE(FDT_INT16)  \\\n  META_COLUMN_TYPE_CASE(FDT_UINT16) \\\n  META_COLUMN_TYPE_CASE(FDT_INT32)  \\\n  META_COLUMN_TYPE_CASE(FDT_UINT32) \\\n  META_COLUMN_TYPE_CASE(FDT_INT64)  \\\n  META_COLUMN_TYPE_CASE(FDT_UINT64)\n\n#define SWITCH_FLOAT_BRANCH META_COLUMN_TYPE_CASE(FDT_FLOAT)\n#define SWITCH_DOUBLE_BRANCH META_COLUMN_TYPE_CASE(FDT_DOUBLE)\n#define SWITCH_STRING_BRANCH         \\\n  META_COLUMN_TYPE_CASE(FDT_STRING)  \\\n  META_COLUMN_TYPE_CASE(FDT_WSTRING) \\\n  META_COLUMN_TYPE_CASE(FDT_BLOB)    \\\n  META_COLUMN_TYPE_CASE(FDT_CLOB)\n\ntemplate <typename builder_type, typename data_type>\nvoid ConvertDataToArray(\n    const std::unique_ptr<Poco::Data::RecordSet>& recordset,\n    const int64_t col_index, const int64_t begin, const int64_t end,\n    const int64_t chunk_size,\n    const std::function<data_type(const Poco::Dynamic::Var&)>& convert_func,\n    TensorPtr* t) {\n  auto builder = builder_type();\n  for (int64_t row_index = begin * chunk_size;\n       row_index < end * chunk_size &&\n       static_cast<size_t>(row_index) < recordset->rowCount();\n       ++row_index) {\n    if (recordset->isNull(col_index, row_index)) {\n      builder.AppendNull();\n    } else {\n      builder.Append(convert_func(recordset->value(col_index, row_index)));\n    }\n  }\n  builder.Finish(t);\n};\n\n}  // namespace\n\nvoid OdbcChunkedResult::Init(const std::string& query) {\n  select_ = std::make_shared<Poco::Data::Statement>(session_);\n  *select_ << query, Poco::Data::Keywords::limit(OdbcChunkedResult::kBatchSize);\n  rs_ = std::make_unique<Poco::Data::RecordSet>(*select_);\n  // execute to get first batch\n  select_->execute();\n  rs_->moveFirst();\n  more_ = rs_->totalRowCount() > 0;\n  using Poco::Data::MetaColumn;\n  try {\n    arrow::FieldVector fields;\n    std::size_t column_cnt = rs_->columnCount();\n    for (std::size_t i = 0; i < column_cnt; ++i) {\n      std::shared_ptr<arrow::DataType> field_arrow_type;\n      switch (rs_->columnType(i)) {\n        SWITCH_BOOL_BRANCH {\n          field_arrow_type = arrow::boolean();\n          break;\n        }\n        SWITCH_DATE_BRANCH\n        SWITCH_INT64_BRANCH {\n          field_arrow_type = arrow::int64();\n          break;\n        }\n        SWITCH_FLOAT_BRANCH {\n          field_arrow_type = arrow::float32();\n          break;\n        }\n        SWITCH_DOUBLE_BRANCH {\n          field_arrow_type = arrow::float64();\n          break;\n        }\n        SWITCH_STRING_BRANCH {\n          field_arrow_type = arrow::large_utf8();\n          break;\n        }\n        default:\n          YACL_THROW(\"unsupported Poco::Data::MetaColumn::ColumnDataType {}\",\n                     fmt::underlying(rs_->columnType(i)));\n      }\n      auto field =\n          std::make_shared<arrow::Field>(rs_->columnName(i), field_arrow_type);\n      fields.push_back(field);\n    }\n    schema_ = std::make_shared<arrow::Schema>(fields);\n  } catch (const Poco::Data::DataException& e) {\n    YACL_THROW(\"catch unexpected Poco::Data::DataException: {}\",\n               e.displayText());\n  }\n}\n\nstd::optional<arrow::ChunkedArrayVector> OdbcChunkedResult::Fetch() {\n  if (!more_) {\n    return std::nullopt;\n  }\n  select_->wait();\n  more_ = !select_->done();\n  auto batch_num = yacl::get_num_threads();\n  // if row number in one batch is too small, we will use single thread to\n  // convert\n  if (rs_->rowCount() < kBatchSize / batch_num) {\n    batch_num = 1;\n  }\n  auto chunk_size = yacl::divup(rs_->rowCount(), batch_num);\n  std::vector<std::vector<TensorPtr>> tensor_vecs(\n      rs_->columnCount(), std::vector<TensorPtr>(batch_num));\n  try {\n    yacl::parallel_for(0, batch_num, 1, [&](int64_t begin, int64_t end) {\n      for (size_t col_index = 0; col_index < rs_->columnCount(); ++col_index) {\n        TensorPtr t;\n        switch (rs_->columnType(col_index)) {\n          SWITCH_BOOL_BRANCH {\n            ConvertDataToArray<BooleanTensorBuilder, bool>(\n                rs_, col_index, begin, end, chunk_size,\n                [](const Poco::Dynamic::Var& value) {\n                  return value.convert<bool>();\n                },\n                &t);\n            break;\n          }\n          SWITCH_INT64_BRANCH {\n            ConvertDataToArray<Int64TensorBuilder, int64_t>(\n                rs_, col_index, begin, end, chunk_size,\n                [](const Poco::Dynamic::Var& value) {\n                  return value.convert<int64_t>();\n                },\n                &t);\n            break;\n          }\n          SWITCH_DATE_BRANCH {\n            ConvertDataToArray<Int64TensorBuilder, int64_t>(\n                rs_, col_index, begin, end, chunk_size,\n                [](const Poco::Dynamic::Var& value) {\n                  return value.convert<Poco::DateTime>()\n                      .timestamp()\n                      .epochTime();\n                },\n                &t);\n            break;\n          }\n          SWITCH_FLOAT_BRANCH {\n            ConvertDataToArray<FloatTensorBuilder, float>(\n                rs_, col_index, begin, end, chunk_size,\n                [](const Poco::Dynamic::Var& value) {\n                  return value.convert<float>();\n                },\n                &t);\n            break;\n          }\n          SWITCH_DOUBLE_BRANCH {\n            ConvertDataToArray<DoubleTensorBuilder, double>(\n                rs_, col_index, begin, end, chunk_size,\n                [](const Poco::Dynamic::Var& value) {\n                  return value.convert<double>();\n                },\n                &t);\n            break;\n          }\n          SWITCH_STRING_BRANCH {\n            ConvertDataToArray<StringTensorBuilder, std::string>(\n                rs_, col_index, begin, end, chunk_size,\n                [](const Poco::Dynamic::Var& value) {\n                  return value.convert<std::string>();\n                },\n                &t);\n            break;\n          }\n          default:\n            YACL_THROW(\"unsupported Poco::Data::MetaColumn::ColumnDataType {}\",\n                       fmt::underlying(rs_->columnType(col_index)));\n        }\n        tensor_vecs[col_index][begin] = t;\n      }\n    });\n  } catch (const Poco::Data::DataException& e) {\n    YACL_THROW(\"catch unexpected Poco::Data::DataException: {}\",\n               e.displayText());\n  }\n  if (more_) {\n    select_->executeAsync();\n  }\n  arrow::ChunkedArrayVector chunked_arrs;\n  for (auto& tensor_v : tensor_vecs) {\n    chunked_arrs.push_back(ConcatTensors(tensor_v)->ToArrowChunkedArray());\n  }\n  return chunked_arrs;\n}\n\nstd::shared_ptr<ChunkedResult> OdbcAdaptor::SendQuery(\n    const std::string& query) {\n  try {\n    auto session = connector_->CreateSession();\n    return std::make_shared<OdbcChunkedResult>(session, query);\n  } catch (const Poco::Data::DataException& e) {\n    YACL_THROW(\"catch unexpected Poco::Data::DataException: {}\",\n               e.displayText());\n  }\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/odbc_adaptor.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n#include <utility>\n\n#include \"Poco/Data/RecordSet.h\"\n#include \"Poco/Data/Session.h\"\n#include \"Poco/Data/SessionPool.h\"\n#include \"arrow/type_fwd.h\"\n\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/string_tensor_builder.h\"\n#include \"engine/datasource/datasource_adaptor.h\"\n#include \"engine/datasource/odbc_connector.h\"\n\n#include \"engine/datasource/datasource.pb.h\"\n\nnamespace scql::engine {\n\nclass OdbcChunkedResult : public ChunkedResult {\n public:\n  explicit OdbcChunkedResult(Poco::Data::Session session,\n                             const std::string& query)\n      : session_(std::move(session)) {\n    Init(query);\n  }\n\n  std::optional<arrow::ChunkedArrayVector> Fetch() override;\n  std::shared_ptr<arrow::Schema> GetSchema() override { return schema_; };\n  // 1M\n  static const size_t kBatchSize = 1024 * 1024;\n\n private:\n  void Init(const std::string& query);\n  Poco::Data::Session session_;\n  std::shared_ptr<Poco::Data::Statement> select_;\n  std::unique_ptr<Poco::Data::RecordSet> rs_;\n  std::shared_ptr<arrow::Schema> schema_;\n  bool more_ = false;\n};\n\n/// @brief OdbcAdaptor provides a way to access general SQL databases.\n/// It is powered by [POCO Data](https://pocoproject.org/)\n/// The following database systems are supported:\n///   - MySQL\n///   - SQLite\nclass OdbcAdaptor : public DatasourceAdaptor {\n public:\n  explicit OdbcAdaptor(const std::string& db_kind,\n                       const std::string& connection_str)\n      : OdbcAdaptor(db_kind, connection_str, ConnectionType::Short, 0) {}\n  explicit OdbcAdaptor(const std::string& db_kind,\n                       const std::string& connection_str, ConnectionType type,\n                       size_t pool_size);\n\n  ~OdbcAdaptor() override = default;\n\n private:\n  void Init();\n\n  // Send query and return schema\n  std::shared_ptr<ChunkedResult> SendQuery(const std::string& query) override;\n\n private:\n  std::unique_ptr<OdbcConnector> connector_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/odbc_adaptor_factory.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/odbc_adaptor_factory.h\"\n\nnamespace scql::engine {\n\nstd::unique_ptr<DatasourceAdaptor> OdbcAdaptorFactory::CreateAdaptor(\n    const DataSource& datasource_spec) {\n  return std::make_unique<OdbcAdaptor>(\n      DataSourceKind_Name(datasource_spec.kind()),\n      datasource_spec.connection_str(), connection_type_, pool_size_);\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/odbc_adaptor_factory.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/datasource/datasource_adaptor_factory.h\"\n#include \"engine/datasource/odbc_adaptor.h\"\n\nnamespace scql::engine {\n\nclass OdbcAdaptorFactory final : public DatasourceAdaptorFactory {\n public:\n  OdbcAdaptorFactory() : OdbcAdaptorFactory(ConnectionType::Short, 0) {}\n\n  OdbcAdaptorFactory(ConnectionType connection_type, std::size_t pool_size)\n      : connection_type_(connection_type), pool_size_(pool_size) {}\n\n  std::unique_ptr<DatasourceAdaptor> CreateAdaptor(\n      const DataSource& datasource_spec) override;\n\n private:\n  ConnectionType connection_type_;\n  size_t pool_size_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/odbc_adaptor_mysql_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"Poco/Data/MySQL/Connector.h\"\n#include \"Poco/Data/MySQL/MySQLException.h\"\n#include \"absl/flags/flag.h\"\n#include \"absl/flags/parse.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/datasource/odbc_adaptor.h\"\n#include \"engine/operator/test_util.h\"\n\nABSL_FLAG(\n    std::string, connection_str, \"\",\n    \"connection string for mysql, checkout it's format on: \"\n    \"https://docs.pocoproject.org/current/Poco.Data.MySQL.SessionImpl.html\");\n\nnamespace scql::engine {\n\nclass OdbcAdaptorMySQLTest : public ::testing::Test {\n protected:\n  void SetUp() override {\n    Poco::Data::MySQL::Connector::registerConnector();\n\n    std::string connection_str = getConnectionStr();\n    try {\n      session_ = std::make_unique<Poco::Data::Session>(\"mysql\", connection_str);\n\n      using Poco::Data::Keywords::now;\n      // set timezone\n      *session_ << \"SET time_zone = '+08:00';\", now;\n      // create table\n      *session_ << \"DROP TABLE IF EXISTS person\", now;\n      *session_ << \"CREATE TABLE person(name VARCHAR(30), age INTEGER(3), dt \"\n                   \"DATETIME, tt TIMESTAMP)\",\n          now;\n      // insert some rows\n      *session_ << \"INSERT INTO person VALUES(\\\"alice\\\", 18, \\\"2025-06-06 \"\n                   \"13:00:00\\\", \\\"2025-06-06 13:00:00\\\")\",\n          now;\n      *session_ << \"INSERT INTO person VALUES(\\\"bob\\\", 20, \\\"2025-06-16 \"\n                   \"16:00:00\\\", \\\"2025-06-16 16:00:00\\\")\",\n          now;\n      *session_ << \"INSERT INTO person VALUES(\\\"carol\\\", NULL, \\\"2025-06-26 \"\n                   \"16:00:00\\\", \\\"2025-06-26 16:00:00\\\")\",\n          now;\n      *session_ << \"INSERT INTO person VALUES(NULL, NULL, NULL, NULL)\", now;\n    } catch (const Poco::Data::MySQL::MySQLException& e) {\n      FAIL() << \"catch MySQL exception: \" << e.displayText();\n    } catch (const Poco::Data::DataException& e) {\n      FAIL() << \"catch poco data exception: \" << e.displayText();\n    } catch (const std::exception& e) {\n      FAIL() << \"catch std::exception: \" << e.what();\n    }\n  }\n\n  std::string getConnectionStr() { return absl::GetFlag(FLAGS_connection_str); }\n\n  std::unique_ptr<Poco::Data::Session> session_;\n};\n\nTEST_F(OdbcAdaptorMySQLTest, works) {\n  // Given\n  OdbcAdaptor adaptor(\"mysql\", getConnectionStr());\n\n  // When\n  const std::string query = \"SELECT name, age, dt, tt FROM person\";\n  std::vector<ColumnDesc> outputs{{\"name\", pb::PrimitiveDataType::STRING},\n                                  {\"age\", pb::PrimitiveDataType::INT32},\n                                  {\"dt\", pb::PrimitiveDataType::DATETIME},\n                                  {\"tt\", pb::PrimitiveDataType::TIMESTAMP}};\n\n  auto results = adaptor.ExecQuery(query, outputs);\n\n  // Then\n  EXPECT_EQ(results.size(), 4);\n\n  // column name\n  EXPECT_EQ(results[0]->Length(), 4);\n  EXPECT_EQ(results[0]->GetNullCount(), 1);\n\n  // column age\n  EXPECT_EQ(results[1]->Length(), 4);\n  EXPECT_EQ(results[1]->GetNullCount(), 2);\n\n  scql::engine::op::test::CheckTensorEqual(\n      results[2],\n      TensorFrom(arrow::int64(), \"[1749214800,1750089600,1750953600,null]\"));\n  scql::engine::op::test::CheckTensorEqual(\n      results[3],\n      TensorFrom(arrow::int64(), \"[1749186000,1750060800,1750924800,null]\"));\n}\n\n}  // namespace scql::engine\n\nint main(int argc, char* argv[]) {\n  ::testing::InitGoogleTest(&argc, argv);\n\n  absl::ParseCommandLine(argc, argv);\n  return RUN_ALL_TESTS();\n}\n"
  },
  {
    "path": "engine/datasource/odbc_adaptor_sqlite_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"Poco/Data/SQLite/Connector.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/datasource/odbc_adaptor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine {\n\nclass OdbcAdaptorSQLiteTest : public ::testing::Test {\n protected:\n  void SetUp() override {\n    Poco::Data::SQLite::Connector::registerConnector();\n\n    session_ =\n        std::make_unique<Poco::Data::Session>(\"SQLite\", db_connection_str_);\n\n    using Poco::Data::Keywords::now;\n    // create table\n    *session_ << \"CREATE TABLE person(name VARCHAR(30), age INTEGER(3), credit \"\n                 \"REAL, dt datetime, tt timestamp)\",\n        now;\n    // insert some rows\n    *session_ << \"INSERT INTO person VALUES(\\\"alice\\\", 18, 675.0, \\\"2025-06-06 \"\n                 \"13:00:00\\\", \\\"2025-06-06 13:00:00\\\")\",\n        now;\n    *session_ << \"INSERT INTO person VALUES(\\\"bob\\\", 20, 798.0, \\\"2025-06-16 \"\n                 \"16:00:00\\\", \\\"2025-06-16 16:00:00\\\")\",\n        now;\n    *session_ << \"INSERT INTO person VALUES(\\\"carol\\\", NULL, 880, \\\"2025-06-26 \"\n                 \"16:00:00\\\", \\\"2025-06-26 16:00:00\\\")\",\n        now;\n    *session_ << \"INSERT INTO person VALUES(NULL, NULL, NULL, NULL, NULL)\", now;\n  }\n\n  // https://www.sqlite.org/inmemorydb.html\n  std::string db_connection_str_ =\n      \"file:obdc_adaptor_test?mode=memory&cache=shared\";\n  std::unique_ptr<Poco::Data::Session> session_;\n};\n\nTEST_F(OdbcAdaptorSQLiteTest, works) {\n  // Given\n  OdbcAdaptor adaptor(\"sqlite\", db_connection_str_);\n\n  // When\n  const std::string query = \"SELECT name, age, credit, dt, tt FROM person\";\n  std::vector<ColumnDesc> outputs{{\"name\", pb::PrimitiveDataType::STRING},\n                                  {\"age\", pb::PrimitiveDataType::INT32},\n                                  {\"credit\", pb::PrimitiveDataType::FLOAT64},\n                                  {\"dt\", pb::PrimitiveDataType::DATETIME},\n                                  {\"tt\", pb::PrimitiveDataType::TIMESTAMP}};\n\n  auto results = adaptor.ExecQuery(query, outputs);\n\n  // Then\n  EXPECT_EQ(results.size(), 5);\n\n  // column name\n  EXPECT_EQ(results[0]->Length(), 4);\n  EXPECT_EQ(results[0]->GetNullCount(), 1);\n\n  // column age\n  EXPECT_EQ(results[1]->Length(), 4);\n  EXPECT_EQ(results[1]->GetNullCount(), 2);\n\n  // column credit\n  EXPECT_EQ(results[2]->Length(), 4);\n  EXPECT_EQ(results[2]->GetNullCount(), 1);\n\n  scql::engine::op::test::CheckTensorEqual(\n      results[3],\n      TensorFrom(arrow::int64(), \"[1749214800,1750089600,1750953600,null]\"));\n  // sqlite treats timestamp as text\n  scql::engine::op::test::CheckTensorEqual(\n      results[4],\n      TensorFrom(arrow::int64(), \"[1749214800,1750089600,1750953600,null]\"));\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/odbc_connector.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/datasource/odbc_connector.h\"\n\n#include <algorithm>\n#include <mutex>\n\n#include \"Poco/Data/MySQL/Connector.h\"\n#include \"Poco/Data/PostgreSQL/Connector.h\"\n#include \"Poco/Data/SQLite/Connector.h\"\n#include \"spdlog/spdlog.h\"\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine {\n\nnamespace {\nstd::once_flag mysql_register_flag;\n}\n\nOdbcConnector::OdbcConnector(const std::string& db_kind,\n                             const std::string& connection_str,\n                             ConnectionType type, size_t pool_size)\n    : db_kind_(db_kind), connection_str_(connection_str) {\n  std::transform(db_kind_.begin(), db_kind_.end(), db_kind_.begin(), ::tolower);\n  try {\n    if (db_kind_ == \"mysql\") {\n      // `mysql_library_init` is not thread-safe in multithread environment,\n      // see: https://dev.mysql.com/doc/c-api/5.7/en/mysql-library-init.html\n      // MySQL::Connector::registerConnector() invokes `mysql_library_init`\n      // refer to\n      // https://github.com/pocoproject/poco/blob/poco-1.12.2-release/Data/MySQL/src/Connector.cpp#L55\n      std::call_once(mysql_register_flag,\n                     Poco::Data::MySQL::Connector::registerConnector);\n    } else if (db_kind_ == \"sqlite\") {\n      Poco::Data::SQLite::Connector::registerConnector();\n    } else if (db_kind_ == \"postgresql\") {\n      Poco::Data::PostgreSQL::Connector::registerConnector();\n    } else {\n      YACL_THROW(\"unsupported DatabaseKind: {}\", db_kind_);\n    }\n\n    if (type == ConnectionType::Pooled) {\n      pool_ = std::make_unique<Poco::Data::SessionPool>(\n          db_kind_, connection_str_, 1, pool_size);\n    }\n  } catch (const Poco::Data::DataException& e) {\n    // NOTE: Poco Exception's what() method only return the exception category\n    // without detail information, so we rethrow it with displayText() method.\n    // https://docs.pocoproject.org/current/Poco.Exception.html#13533\n    YACL_THROW(\"catch unexpected Poco::Data::DataException: {}\",\n               e.displayText());\n  }\n}\n\nvoid OdbcConnector::SetUtcTimezone(Poco::Data::Session& session) {\n  Poco::Data::Statement timezone_stmt(session);\n  std::string set_utc_time_zone = \"\";\n\n  if (db_kind_ == \"mysql\") {\n    set_utc_time_zone = \"SET time_zone = 'UTC';\";\n  } else if (db_kind_ == \"postgresql\") {\n    set_utc_time_zone = \"SET TIME ZONE 'UTC';\";\n  } else if (db_kind_ == \"sqlite\") {\n    return;\n  } else {\n    SPDLOG_WARN(\"unsupported DatabaseKind: {}\", db_kind_);\n    return;\n  }\n\n  timezone_stmt << set_utc_time_zone;\n  timezone_stmt.execute();\n}\n\nPoco::Data::Session OdbcConnector::CreateSession() {\n  try {\n    if (pool_) {\n      Poco::Data::Session session = pool_->get();\n      SetUtcTimezone(session);\n      return session;\n    }\n\n    Poco::Data::Session session =\n        Poco::Data::Session(db_kind_, connection_str_);\n    SetUtcTimezone(session);\n    return session;\n  } catch (const Poco::Data::DataException& e) {\n    YACL_THROW(\"create session catch unexpected Poco::Data::DataException: {}\",\n               e.displayText());\n  }\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/odbc_connector.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n\n#include \"Poco/Data/Session.h\"\n#include \"Poco/Data/SessionPool.h\"\n\nnamespace scql::engine {\n\nenum ConnectionType {\n  Unknown = 0,\n  Short = 1,\n  Pooled = 2,\n};\n\n/// @brief OdbcAdaptor provides a way to access general SQL databases.\n/// It is powered by [POCO Data](https://pocoproject.org/)\n/// The following database systems are supported:\n///   - MySQL\n///   - SQLite\n///   - PostgreSQL\nclass OdbcConnector {\n public:\n  explicit OdbcConnector(const std::string& db_kind,\n                         const std::string& connection_str)\n      : OdbcConnector(db_kind, connection_str, ConnectionType::Short, 0) {}\n\n  explicit OdbcConnector(const std::string& db_kind,\n                         const std::string& connection_str, ConnectionType type,\n                         size_t pool_size);\n\n  // Returns a session from session pool if using pooled session,\n  // Otherwise, creates a new session.\n  Poco::Data::Session CreateSession();\n\n private:\n  std::string db_kind_;\n  std::string connection_str_;\n  std::unique_ptr<Poco::Data::SessionPool> pool_;\n  void SetUtcTimezone(Poco::Data::Session& session);\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/datasource/requirements.txt",
    "content": "fastapi\nuvicorn\njinja2"
  },
  {
    "path": "engine/datasource/router.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/datasource/datasource.pb.h\"\n\nnamespace scql::engine {\n\n/// @brief Datasource router\nclass Router {\n public:\n  virtual ~Router() = default;\n\n  /// @return DataSources which the table_refs belong to.\n  virtual std::vector<DataSource> Route(\n      const std::vector<std::string>& table_refs) = 0;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/datasource/run_odbc_adaptor_mysql_test.sh",
    "content": "#!/usr/bin/bash\n#\n# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -ex\n\nCONNECTION_STR=$1\n\nbazel run //engine/datasource:odbc_adaptor_mysql_test -- --connection_str=${CONNECTION_STR}\n"
  },
  {
    "path": "engine/exe/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncc_library(\n    name = \"flags\",\n    srcs = [\"flags.cc\"],\n    hdrs = [\"flags.h\"],\n    deps = [\n        \"@gflags\",\n    ],\n)\n\ncc_binary(\n    name = \"scqlengine\",\n    srcs = [\n        \"main.cc\",\n        \"version.h\",\n    ],\n    copts = select({\n        \"@platforms//os:osx\": [\n            # Fix nil_t error in msgpack,\n            # See: https://github.com/msgpack/msgpack-c/issues/699\n            \"-DMSGPACK_DISABLE_LEGACY_NIL\",\n        ],\n        \"//conditions:default\": [],\n    }),\n    linkopts = [\"-pie\"],\n    deps = [\n        \"//api:scql_task_cc_proto\",\n        \"//engine/auth:authenticator\",\n        \"//engine/datasource:http_router\",\n        \"//engine/datasource:kuscia_datamesh_router\",\n        \"//engine/exe:flags\",\n        \"//engine/link:mux_link_factory\",\n        \"//engine/link:mux_receiver_service\",\n        \"//engine/link:rpc_helper\",\n        \"//engine/services:engine_service_impl\",\n        \"//engine/services:error_collector_service_impl\",\n        \"//engine/services:prometheus_service_impl\",\n        \"//engine/util:kpad_task_helper\",\n        \"//engine/util:logging\",\n        \"//engine/util:prometheus_monitor\",\n        \"//engine/util:ssl_helper\",\n        \"@abseil-cpp//absl/debugging:failure_signal_handler\",\n        \"@abseil-cpp//absl/debugging:symbolize\",\n        \"@brpc\",\n    ],\n)\n"
  },
  {
    "path": "engine/exe/flags.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n#include \"gflags/gflags.h\"\n\n// Log flags\nDEFINE_string(\n    log_level, \"info\",\n    \"log level, can be trace, debug, info, warning, error, critical, off\");\nDEFINE_string(log_dir, \"logs\", \"log directory\");\nDEFINE_bool(log_enable_console_logger, true,\n            \"whether logging to stdout while logging to file\");\nDEFINE_bool(log_enable_session_logger_separation, false,\n            \"whether output session-related logs to a dedicated file\");\n\n// Brpc channel flags for peer engine.\nDEFINE_string(peer_engine_protocol, \"baidu_std\", \"rpc protocol\");\nDEFINE_string(peer_engine_connection_type, \"single\", \"connection type\");\nDEFINE_string(peer_engine_load_balancer, \"\", \"load balancer: \\\"rr\\\" or empty\");\nDEFINE_int32(peer_engine_timeout_ms, 300000, \"rpc timeout in milliseconds.\");\nDEFINE_int32(peer_engine_max_retry, 3,\n             \"rpc max retries(not including the first rpc)\");\nDEFINE_bool(peer_engine_enable_ssl_as_client, true,\n            \"enable ssl encryption as client\");\nDEFINE_bool(peer_engine_enable_ssl_client_verification, false,\n            \"enable ssl client verification\");\nDEFINE_string(peer_engine_ssl_client_ca_certificate, \"\",\n              \"certificate Authority file path to verify SSL as client\");\nDEFINE_int32(link_recv_timeout_ms, 30 * 1000,\n             \"the max time that a party will wait for a given event\");\nDEFINE_int32(\n    link_throttle_window_size, 16,\n    \"throttle window size for channel, set to limit the number of messages \"\n    \"sent asynchronously to avoid network congestion, set 0 to disable\");\n// TODO(zhihe): for rpc stabilization in 100M bandwidth, the default\n// link_chunked_send_parallel_size is 1, should find a tradeoff value between\n// bandwidth and send speed\nDEFINE_int32(link_chunked_send_parallel_size, 1,\n             \"parallel size when send chunked value\");\nDEFINE_int32(http_max_payload_size, 1024 * 1024,\n             \"max payload to decide whether to send value chunked, default 1M\");\n// Brpc channel flags for driver(for example, SCQLBroker)\nDEFINE_string(driver_protocol, \"http:proto\", \"rpc protocol\");\nDEFINE_string(driver_connection_type, \"pooled\", \"connection type\");\nDEFINE_string(driver_load_balancer, \"\", \"load balancer: \\\"rr\\\" or empty\");\nDEFINE_int32(driver_timeout_ms, 5000, \"rpc timeout in milliseconds.\");\nDEFINE_int32(driver_max_retry, 3,\n             \"rpc max retries(not including the first rpc)\");\nDEFINE_bool(driver_enable_ssl_as_client, true,\n            \"enable ssl encryption as client\");\nDEFINE_bool(driver_enable_ssl_client_verification, false,\n            \"enable ssl client verification\");\nDEFINE_string(driver_ssl_client_ca_certificate, \"\",\n              \"certificate Authority file path to verify SSL as client\");\n// Brpc server flags.\nDEFINE_int32(listen_port, 8003, \"\");\nDEFINE_bool(enable_builtin_service, false,\n            \"whether brpc builtin service is enable/disable\");\nDEFINE_int32(internal_port, 9527, \"which port the builtin services server on\");\nDEFINE_bool(enable_separate_link_port, false,\n            \"whether use a separate port for link service\");\nDEFINE_int32(link_port, 8004, \"port for link service\");\nDEFINE_int32(idle_timeout_s, 30, \"connections idle close delay in seconds\");\nDEFINE_bool(server_enable_ssl, true,\n            \"whether brpc server's ssl enable/disable\");\nDEFINE_bool(server_enable_ssl_client_verification, false,\n            \"enable ssl client verification\");\nDEFINE_string(server_ssl_certificate, \"\",\n              \"Certificate file path to enable SSL\");\nDEFINE_string(server_ssl_private_key, \"\",\n              \"Private key file path to enable SSL\");\nDEFINE_string(server_ssl_client_ca_certificate, \"\",\n              \"the trusted CA file to verity the client's certificate\");\n// Common flags for Brpc server and channel of peer engine.\nDEFINE_bool(enable_client_authorization, false,\n            \"if set true, server will check all requests' http header.\");\nDEFINE_string(auth_credential, \"\", \"authorization credential\");\nDEFINE_bool(enable_driver_authorization, false,\n            \"if set to true, the engine will verify the HTTP header \"\n            \"'credential' field of requests from driver\");\nDEFINE_string(engine_credential, \"\", \"driver authorization credential\");\n// Session flags\nDEFINE_int32(session_timeout_s, 1800,\n             \"TTL for session, should be greater than the typical runtime of \"\n             \"the specific tasks.\");\nDEFINE_string(spu_allowed_protocols, \"SEMI2K,ABY3,CHEETAH\",\n              \"spu allowed protocols\");\n\n// Kpad task mode flags\nDEFINE_string(kpad_job_id, \"\", \"job identifier for kpad task mode execution\");\nDEFINE_string(kpad_scql_config, \"\",\n              \"SCQL configuration in JSON format for kpad task mode\");\nDEFINE_string(kpad_cluster_def, \"\",\n              \"cluster definition in JSON format for kpad task mode\");\n\n// DataSource connection flags.\nDEFINE_string(datasource_router, \"embed\",\n              \"datasource router type: embed | http | kusciadatamesh\");\nDEFINE_string(\n    embed_router_conf, \"\",\n    R\"text(configuration for embed router in json format. For example: --embed_router_conf={\"datasources\":[{\"id\":\"ds001\",\"name\":\"mysql db\",\"kind\":\"MYSQL\",\"connection_str\":\"host=127.0.0.1 db=test user=root password='qwerty'\"}],\"rules\":[{\"db\":\"*\",\"table\":\"*\",\"datasource_id\":\"ds001\"}]} )text\");\nDEFINE_string(http_router_endpoint, \"\", \"http datasource router endpoint url\");\nDEFINE_string(kuscia_datamesh_endpoint, \"datamesh:8071\",\n              \"kuscia datamesh grpc endpoint\");\nDEFINE_string(kuscia_datamesh_client_key_path, \"\",\n              \"kuscia datamesh client key file\");\nDEFINE_string(kuscia_datamesh_client_cert_path, \"\",\n              \"kuscia datamesh client cert file\");\nDEFINE_string(kuscia_datamesh_cacert_path, \"\",\n              \"kuscia datamesh server cacert file\");\nDEFINE_string(db_connection_info, \"\",\n              \"connection string used to connect to mysql...\");\n// Party authentication flags\nDEFINE_bool(enable_self_auth, true,\n            \"whether enable self identity authentication\");\nDEFINE_string(private_key_pem_path, \"\", \"path to private key pem file\");\nDEFINE_bool(enable_peer_auth, true,\n            \"whether enable peer parties identity authentication\");\nDEFINE_string(authorized_profile_path, \"\",\n              \"path to authorized profile, in json format\");\nDEFINE_bool(enable_psi_detail_logger, false, \"whether enable detail log\");\nDEFINE_string(psi_detail_logger_dir, \"logs/detail\", \"log dir\");\nDEFINE_bool(enable_trace, false, \"whether enable tracing\");\nDEFINE_string(trace_log_path, \"logs/trace.trace\", \"trace log path\");\nDEFINE_int32(rr22_mode, 2, \"rr22 comm mode, use fast mode by default\");\nDEFINE_int32(queue_max_block_seconds, 300, \"max seconds for queue block wait\");\n"
  },
  {
    "path": "engine/exe/flags.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n#pragma once\n\n#include <gflags/gflags_declare.h>\n\n// Log flags\nDECLARE_string(log_level);\nDECLARE_string(log_dir);\nDECLARE_bool(log_enable_console_logger);\nDECLARE_bool(log_enable_session_logger_separation);\n\n// Brpc channel flags for peer engine.\nDECLARE_string(peer_engine_protocol);\nDECLARE_string(peer_engine_connection_type);\nDECLARE_string(peer_engine_load_balancer);\nDECLARE_int32(peer_engine_timeout_ms);\nDECLARE_int32(peer_engine_max_retry);\nDECLARE_bool(peer_engine_enable_ssl_as_client);\nDECLARE_bool(peer_engine_enable_ssl_client_verification);\nDECLARE_string(peer_engine_ssl_client_ca_certificate);\nDECLARE_int32(link_recv_timeout_ms);\nDECLARE_int32(link_throttle_window_size);\nDECLARE_int32(link_chunked_send_parallel_size);\nDECLARE_int32(http_max_payload_size);\n\n// Brpc channel flags for driver(for example, SCQLBroker)\nDECLARE_string(driver_protocol);\nDECLARE_string(driver_connection_type);\nDECLARE_string(driver_load_balancer);\nDECLARE_int32(driver_timeout_ms);\nDECLARE_int32(driver_max_retry);\nDECLARE_bool(driver_enable_ssl_as_client);\nDECLARE_bool(driver_enable_ssl_client_verification);\nDECLARE_string(driver_ssl_client_ca_certificate);\n\n// Brpc server flags.\nDECLARE_int32(listen_port);\nDECLARE_bool(enable_builtin_service);\nDECLARE_int32(internal_port);\nDECLARE_bool(enable_separate_link_port);\nDECLARE_int32(link_port);\nDECLARE_int32(idle_timeout_s);\nDECLARE_bool(server_enable_ssl);\nDECLARE_bool(server_enable_ssl_client_verification);\nDECLARE_string(server_ssl_certificate);\nDECLARE_string(server_ssl_private_key);\nDECLARE_string(server_ssl_client_ca_certificate);\n\n// Common flags for Brpc server and channel of peer engine.\nDECLARE_bool(enable_client_authorization);\nDECLARE_string(auth_credential);\nDECLARE_bool(enable_driver_authorization);\nDECLARE_string(engine_credential);\n\n// Session flags\nDECLARE_int32(session_timeout_s);\nDECLARE_string(spu_allowed_protocols);\n\n// Kpad task mode flags\nDECLARE_string(kpad_job_id);\nDECLARE_string(kpad_scql_config);\nDECLARE_string(kpad_cluster_def);\n\n// DataSource connection flags.\nDECLARE_string(datasource_router);\nDECLARE_string(embed_router_conf);\nDECLARE_string(http_router_endpoint);\nDECLARE_string(kuscia_datamesh_endpoint);\nDECLARE_string(kuscia_datamesh_client_key_path);\nDECLARE_string(kuscia_datamesh_client_cert_path);\nDECLARE_string(kuscia_datamesh_cacert_path);\nDECLARE_string(db_connection_info);\n\n// Party authentication flags\nDECLARE_bool(enable_self_auth);\nDECLARE_string(private_key_pem_path);\nDECLARE_bool(enable_peer_auth);\nDECLARE_string(authorized_profile_path);\nDECLARE_bool(enable_psi_detail_logger);\nDECLARE_string(psi_detail_logger_dir);\nDECLARE_bool(enable_trace);\nDECLARE_string(trace_log_path);\nDECLARE_int32(rr22_mode);\nDECLARE_int32(queue_max_block_seconds);\n"
  },
  {
    "path": "engine/exe/main.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <signal.h>\n\n#include <atomic>\n#include <chrono>\n#include <future>\n#include <memory>\n#include <thread>\n\n#include \"absl/debugging/failure_signal_handler.h\"\n#include \"absl/debugging/symbolize.h\"\n#include \"absl/strings/str_split.h\"\n#include \"arrow/filesystem/s3fs.h\"\n#include \"brpc/controller.h\"\n#include \"brpc/server.h\"\n#include \"butil/file_util.h\"\n#include \"flags.h\"\n\n#include \"engine/auth/authenticator.h\"\n#include \"engine/datasource/datasource_adaptor_mgr.h\"\n#include \"engine/datasource/embed_router.h\"\n#include \"engine/datasource/http_router.h\"\n#include \"engine/datasource/kuscia_datamesh_router.h\"\n#include \"engine/exe/flags.h\"\n#include \"engine/exe/version.h\"\n#include \"engine/framework/session.h\"\n#include \"engine/link/mux_link_factory.h\"\n#include \"engine/link/mux_receiver_service.h\"\n#include \"engine/link/rpc_helper.h\"\n#include \"engine/services/engine_service_impl.h\"\n#include \"engine/services/error_collector_service_impl.h\"\n#include \"engine/services/prometheus_service_impl.h\"\n#include \"engine/util/kpad_task_helper.h\"\n#include \"engine/util/logging.h\"\n#include \"engine/util/prometheus_monitor.h\"\n#include \"engine/util/ssl_helper.h\"\n#include \"engine/util/trace_categories.h\"\n\n#include \"api/scql_task.pb.h\"\n\nnamespace brpc {\n\nDECLARE_bool(graceful_quit_on_sigterm);\n\n}\n\ngrpc::SslCredentialsOptions LoadSslCredentialsOptions(\n    const std::string& key_file, const std::string& cert_file,\n    const std::string& cacert_file);\n\nvoid AddChannelOptions(scql::engine::ChannelManager* channel_manager) {\n  // PeerEngine Options\n  {\n    brpc::ChannelOptions brpc_options;\n    brpc_options.protocol = FLAGS_peer_engine_protocol;\n    brpc_options.connection_type = FLAGS_peer_engine_connection_type;\n    brpc_options.timeout_ms = FLAGS_peer_engine_timeout_ms;\n\n    if (FLAGS_peer_engine_enable_ssl_as_client) {\n      brpc_options.mutable_ssl_options()->ciphers = \"\";\n      if (FLAGS_peer_engine_enable_ssl_client_verification) {\n        if (FLAGS_peer_engine_ssl_client_ca_certificate.empty()) {\n          SPDLOG_WARN(\"peer_engine_ssl_client_ca_certificate is empty\");\n        }\n        // All certificate are directly signed by our CA, depth = 1 is enough.\n        brpc_options.mutable_ssl_options()->verify.verify_depth = 1;\n        brpc_options.mutable_ssl_options()->verify.ca_file_path =\n            FLAGS_peer_engine_ssl_client_ca_certificate;\n      }\n    }\n\n    if (FLAGS_enable_client_authorization) {\n      brpc_options.auth = scql::engine::DefaultAuthenticator();\n    }\n\n    scql::engine::ChannelOptions options;\n    options.brpc_options = brpc_options;\n    options.load_balancer = FLAGS_peer_engine_load_balancer;\n\n    channel_manager->AddChannelOptions(scql::engine::RemoteRole::PeerEngine,\n                                       options);\n  }\n\n  // Driver Options\n  {\n    brpc::ChannelOptions brpc_options;\n    brpc_options.protocol = FLAGS_driver_protocol;\n    brpc_options.connection_type = FLAGS_driver_connection_type;\n    brpc_options.timeout_ms = FLAGS_driver_timeout_ms;\n    brpc_options.max_retry = FLAGS_driver_max_retry;\n\n    if (FLAGS_driver_enable_ssl_as_client) {\n      brpc_options.mutable_ssl_options()->ciphers = \"\";\n      if (FLAGS_driver_enable_ssl_client_verification) {\n        brpc_options.mutable_ssl_options()->verify.verify_depth = 1;\n        brpc_options.mutable_ssl_options()->verify.ca_file_path =\n            FLAGS_driver_ssl_client_ca_certificate;\n      }\n    }\n\n    scql::engine::ChannelOptions options;\n    options.brpc_options = brpc_options;\n    options.load_balancer = FLAGS_driver_load_balancer;\n\n    channel_manager->AddChannelOptions(scql::engine::RemoteRole::Driver,\n                                       options);\n  }\n}\n\nstd::unique_ptr<scql::engine::Router> BuildRouter() {\n  if (FLAGS_datasource_router == \"embed\") {\n    if (!FLAGS_embed_router_conf.empty()) {\n      SPDLOG_INFO(\"Building EmbedRouter from json conf\");\n      return scql::engine::EmbedRouter::FromJsonStr(FLAGS_embed_router_conf);\n    }\n\n    // Check for task mode with ScqlConfig input_file_paths\n    auto scql_config =\n        scql::engine::util::ParseScqlConfig(FLAGS_kpad_scql_config);\n    if (scql_config) {\n      if (scql_config->input_file_paths_size() > 0) {\n        SPDLOG_INFO(\"Building EmbedRouter from ScqlConfig input_file_paths\");\n        return scql::engine::EmbedRouter::FromFilePaths(\n            scql_config->input_file_paths());\n      } else {\n        SPDLOG_ERROR(\n            \"Fail to build embed router: No input_file_paths found in \"\n            \"ScqlConfig\");\n        return nullptr;\n      }\n    }\n\n    std::string db_connection_str = FLAGS_db_connection_info;\n    if (char* env_p = std::getenv(\"DB_CONNECTION_INFO\")) {\n      if (strlen(env_p) != 0) {\n        db_connection_str = env_p;\n        SPDLOG_INFO(\"Getting DB_CONNECTION_INFO from ENV\");\n      }\n    }\n\n    if (!db_connection_str.empty()) {\n      SPDLOG_INFO(\"Building EmbedRouter from connection string\");\n      return scql::engine::EmbedRouter::FromConnectionStr(db_connection_str);\n    }\n\n    SPDLOG_ERROR(\n        \"Fail to build embed router, set \"\n        \"embed_router_conf/db_connection_info(gflags) or \"\n        \"DB_CONNECTION_INFO(ENV) or provide input_file_paths in task mode\");\n    return nullptr;\n  } else if (FLAGS_datasource_router == \"http\") {\n    scql::engine::HttpRouterOptions options;\n    options.endpoint = FLAGS_http_router_endpoint;\n    return std::make_unique<scql::engine::HttpRouter>(options);\n  } else if (FLAGS_datasource_router == \"kusciadatamesh\") {\n    auto ssl_opts = scql::engine::util::LoadSslCredentialsOptions(\n        FLAGS_kuscia_datamesh_client_key_path,\n        FLAGS_kuscia_datamesh_client_cert_path,\n        FLAGS_kuscia_datamesh_cacert_path);\n    auto channel_creds = grpc::SslCredentials(ssl_opts);\n    return std::make_unique<scql::engine::KusciaDataMeshRouter>(\n        FLAGS_kuscia_datamesh_endpoint, channel_creds);\n\n  } else {\n    SPDLOG_ERROR(\"Fail to build router, unsupported datasource router type={}\",\n                 FLAGS_datasource_router);\n    return nullptr;\n  }\n}\n\nstd::unique_ptr<scql::engine::auth::Authenticator> BuildAuthenticator() {\n  scql::engine::auth::AuthOption option;\n  option.enable_self_auth = FLAGS_enable_self_auth;\n  option.enable_peer_auth = FLAGS_enable_peer_auth;\n  option.private_key_pem_path = FLAGS_private_key_pem_path;\n  option.authorized_profile_path = FLAGS_authorized_profile_path;\n\n  return std::make_unique<scql::engine::auth::Authenticator>(option);\n}\n\nstd::unique_ptr<scql::engine::EngineServiceImpl> BuildEngineService(\n    scql::engine::ListenerManager* listener_manager,\n    scql::engine::ChannelManager* channel_manager) {\n  auto link_factory = std::make_unique<scql::engine::MuxLinkFactory>(\n      channel_manager, listener_manager);\n\n  std::unique_ptr<scql::engine::Router> ds_router = BuildRouter();\n  YACL_ENFORCE(ds_router);\n\n  std::unique_ptr<scql::engine::DatasourceAdaptorMgr> ds_mgr =\n      std::make_unique<scql::engine::DatasourceAdaptorMgr>();\n\n  scql::engine::SessionOptions session_opt;\n  session_opt.link_config.link_recv_timeout_ms = FLAGS_link_recv_timeout_ms;\n  if (FLAGS_link_throttle_window_size > 0) {\n    session_opt.link_config.link_throttle_window_size =\n        FLAGS_link_throttle_window_size;\n  }\n  if (FLAGS_link_chunked_send_parallel_size > 0) {\n    session_opt.link_config.link_chunked_send_parallel_size =\n        FLAGS_link_chunked_send_parallel_size;\n  }\n  if (FLAGS_http_max_payload_size > 0) {\n    session_opt.link_config.http_max_payload_size = FLAGS_http_max_payload_size;\n  }\n  // NOTE: use yacl retry options to replace brpc retry policy\n  yacl::link::RetryOptions retry_opt;\n  retry_opt.max_retry = FLAGS_peer_engine_max_retry;\n  retry_opt.http_codes = {\n      brpc::HTTP_STATUS_INTERNAL_SERVER_ERROR,\n      brpc::HTTP_STATUS_GATEWAY_TIMEOUT, brpc::HTTP_STATUS_BAD_GATEWAY,\n      brpc::HTTP_STATUS_REQUEST_TIMEOUT, brpc::HTTP_STATUS_SERVICE_UNAVAILABLE,\n      // too many connections\n      429};\n  retry_opt.error_codes = {brpc::Errno::EFAILEDSOCKET,\n                           brpc::Errno::EEOF,\n                           brpc::Errno::ELOGOFF,\n                           brpc::Errno::ELIMIT,\n                           ETIMEDOUT,\n                           ENOENT,\n                           EPIPE,\n                           ECONNREFUSED,\n                           ECONNRESET,\n                           ENODATA,\n                           brpc::Errno::EOVERCROWDED,\n                           brpc::Errno::EH2RUNOUTSTREAMS};\n  session_opt.link_config.link_retry_options = retry_opt;\n  scql::engine::util::LogOptions opts;\n  if (FLAGS_enable_psi_detail_logger) {\n    opts.enable_psi_detail_logger = true;\n    opts.log_dir = FLAGS_psi_detail_logger_dir;\n  }\n  if (FLAGS_log_enable_console_logger) {\n    opts.enable_console_logger = true;\n  }\n  if (FLAGS_log_enable_session_logger_separation) {\n    opts.enable_session_logger_separation = true;\n  }\n  session_opt.log_options = opts;\n\n  std::vector<spu::ProtocolKind> allowed_protocols;\n\n  std::vector<absl::string_view> protocols_str =\n      absl::StrSplit(FLAGS_spu_allowed_protocols, ',');\n  for (auto& protocol_str : protocols_str) {\n    std::string stripped_str(absl::StripAsciiWhitespace(protocol_str));\n    spu::ProtocolKind protocol_kind;\n\n    YACL_ENFORCE(spu::ParseProtocolKind(stripped_str, &protocol_kind),\n                 fmt::format(\"invalid protocol provided: {}\", stripped_str));\n    allowed_protocols.push_back(protocol_kind);\n  }\n\n  auto session_manager = std::make_unique<scql::engine::SessionManager>(\n      session_opt, listener_manager, std::move(link_factory),\n      std::move(ds_router), std::move(ds_mgr), FLAGS_session_timeout_s,\n      allowed_protocols);\n\n  auto authenticator = BuildAuthenticator();\n\n  scql::engine::EngineServiceOptions engine_service_opt;\n  engine_service_opt.enable_authorization = FLAGS_enable_driver_authorization;\n  engine_service_opt.credential = FLAGS_engine_credential;\n  return std::make_unique<scql::engine::EngineServiceImpl>(\n      engine_service_opt, std::move(session_manager), channel_manager,\n      std::move(authenticator));\n}\n\nbrpc::ServerOptions BuildServerOptions() {\n  brpc::ServerOptions options;\n  options.has_builtin_services = FLAGS_enable_builtin_service;\n  options.internal_port = FLAGS_internal_port;\n  options.idle_timeout_sec = FLAGS_idle_timeout_s;\n  if (FLAGS_server_enable_ssl) {\n    if (FLAGS_server_ssl_certificate.empty() ||\n        FLAGS_server_ssl_private_key.empty()) {\n      SPDLOG_WARN(\"server ssl cert or key file is empty\");\n    }\n    auto* ssl_options = options.mutable_ssl_options();\n    ssl_options->default_cert.certificate = FLAGS_server_ssl_certificate;\n    ssl_options->default_cert.private_key = FLAGS_server_ssl_private_key;\n    ssl_options->ciphers = \"\";\n    if (FLAGS_server_enable_ssl_client_verification) {\n      ssl_options->verify.verify_depth = 2;\n      ssl_options->verify.ca_file_path = FLAGS_server_ssl_client_ca_certificate;\n    }\n  }\n  if (FLAGS_enable_client_authorization) {\n    options.auth = scql::engine::DefaultAuthenticator();\n  }\n\n  return options;\n}\n\nvoid termination_handler(int signum) {\n  SPDLOG_WARN(\"Received signal: {}, shutting down\", strsignal(signum));\n}\n\n// Run kpad task in background thread and wait for completion or signal\n// Returns true if task completed successfully, false otherwise\nbool ExecuteKpadTask(scql::engine::EngineServiceImpl* engine_svc,\n                     const scql::engine::util::ClusterDef& cluster_def,\n                     const std::string& job_id, brpc::Server& server) {\n  SPDLOG_INFO(\"Kpad task detected, executing task in background thread\");\n\n  bool task_success = false;\n  std::atomic<bool> task_finished{false};\n\n  std::future<void> task_future = std::async(std::launch::async, [&]() {\n    try {\n      engine_svc->RunKpadTask(cluster_def);\n      task_success = true;\n    } catch (const std::exception& e) {\n      SPDLOG_ERROR(\"Kpad task failed: {}\", e.what());\n    }\n    task_finished = true;\n  });\n\n  // Wait for task completion or signal (SIGTERM/SIGINT)\n  while (!task_finished && !brpc::IsAskedToQuit()) {\n    std::this_thread::sleep_for(std::chrono::milliseconds(100));\n  }\n\n  if (brpc::IsAskedToQuit() && !task_finished) {\n    // Signal received before task completion, stop the running session\n    SPDLOG_WARN(\"Kpad task interrupted by signal\");\n    engine_svc->GetSessionManager()->StopSession(job_id);\n  }\n\n  // Wait for task thread to finish (either completed or interrupted)\n  task_future.get();\n\n  // Stop server after task completion\n  server.Stop(0);\n  server.Join();\n\n  return task_success;\n}\n\nint main(int argc, char* argv[]) {\n  // Initialize the symbolizer to get a human-readable stack trace\n  {\n    absl::InitializeSymbolizer(argv[0]);\n\n    absl::FailureSignalHandlerOptions options;\n    absl::InstallFailureSignalHandler(options);\n  }\n\n  gflags::SetVersionString(ENGINE_VERSION_STRING);\n  gflags::ParseCommandLineFlags(&argc, &argv, true);\n\n  // Setup Logger.\n  try {\n    scql::engine::util::LogOptions opts;\n    opts.log_dir = FLAGS_log_dir;\n    opts.log_level = FLAGS_log_level;\n    if (FLAGS_log_enable_console_logger) {\n      opts.enable_console_logger = true;\n    }\n    scql::engine::util::SetupLogger(opts);\n  } catch (const std::exception& e) {\n    SPDLOG_ERROR(\"Fail to setup logger, msg={}\", e.what());\n    return -1;\n  }\n  SPDLOG_INFO(\"Engine version: {}\", ENGINE_VERSION_STRING);\n\n  // Validate kpad task parameters\n  if (!scql::engine::util::ValidateKpadTaskParams(\n          FLAGS_kpad_cluster_def, FLAGS_kpad_job_id, FLAGS_kpad_scql_config)) {\n    return -1;\n  }\n\n  auto cluster_def =\n      scql::engine::util::ParseClusterDef(FLAGS_kpad_cluster_def);\n  if (!cluster_def && !FLAGS_kpad_cluster_def.empty()) {\n    SPDLOG_ERROR(\"Failed to parse kpad_cluster_def\");\n    return -1;\n  }\n\n  // Set default authenticator for brpc channel.\n  if (FLAGS_enable_client_authorization) {\n    auto auth = std::make_unique<scql::engine::SimpleAuthenticator>(\n        FLAGS_auth_credential);\n    scql::engine::SetDefaultAuthenticator(std::move(auth));\n  }\n\n  // Setup brpc server\n  brpc::Server server;\n  server.set_version(ENGINE_VERSION_STRING);\n\n  scql::engine::ListenerManager listener_manager;\n\n  scql::engine::ChannelManager channel_manager;\n  try {\n    AddChannelOptions(&channel_manager);\n  } catch (const std::exception& e) {\n    SPDLOG_ERROR(\"Fail to add channel options, msg={}\", e.what());\n    return -1;\n  }\n\n  scql::engine::util::TracingSessionGuard tracing_guard(\n      FLAGS_enable_trace, \"scql\", FLAGS_trace_log_path);\n\n  std::unique_ptr<scql::engine::EngineServiceImpl> engine_svc;\n  try {\n    engine_svc = BuildEngineService(&listener_manager, &channel_manager);\n    YACL_ENFORCE(engine_svc);\n  } catch (const std::exception& e) {\n    SPDLOG_ERROR(\"Fail to build engine service, msg={}\", e.what());\n    return -1;\n  }\n  SPDLOG_INFO(\"Adding EngineService into brpc server\");\n  if (server.AddService(engine_svc.get(), brpc::SERVER_DOESNT_OWN_SERVICE) !=\n      0) {\n    SPDLOG_ERROR(\"Fail to add EngineService to server\");\n    return -1;\n  }\n\n  scql::engine::MetricsService metrics_exposer;\n  metrics_exposer.RegisterCollectable(\n      scql::engine::util::PrometheusMonitor::GetInstance()->GetRegistry());\n  SPDLOG_INFO(\"Adding MetricsService into brpc server\");\n  if (server.AddService(&metrics_exposer, brpc::SERVER_DOESNT_OWN_SERVICE) !=\n      0) {\n    SPDLOG_ERROR(\"Fail to add MetricsService to server\");\n    return -1;\n  }\n\n  scql::engine::ErrorCollectorServiceImpl err_svc(\n      engine_svc->GetSessionManager());\n\n  brpc::Server link_svr;\n  scql::engine::MuxReceiverServiceImpl rcv_svc(&listener_manager);\n  if (!FLAGS_enable_separate_link_port) {\n    SPDLOG_INFO(\"Adding MuxReceiverService into main server...\");\n    if (server.AddService(&rcv_svc, brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {\n      SPDLOG_ERROR(\"Fail to add MuxReceiverService to main server\");\n      return -1;\n    }\n    SPDLOG_INFO(\"Adding ErrorCollectorService into main server...\");\n    if (server.AddService(&err_svc, brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {\n      SPDLOG_ERROR(\"Fail to add ErrorCollectorService to server\");\n      return -1;\n    }\n  } else {\n    SPDLOG_INFO(\"Adding MuxReceiverService into seperate link server...\");\n    if (link_svr.AddService(&rcv_svc, brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {\n      SPDLOG_ERROR(\"Fail to add MuxReceiverService to seperate link server\");\n      return -1;\n    }\n    SPDLOG_INFO(\"Adding ErrorCollectorService into seperate link server...\");\n    if (link_svr.AddService(&err_svc, brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {\n      SPDLOG_ERROR(\"Fail to add ErrorCollectorService to seperate link server\");\n      return -1;\n    }\n  }\n\n  // Start brpc server.\n  brpc::ServerOptions options = BuildServerOptions();\n  if (server.Start(FLAGS_listen_port, &options) != 0) {\n    SPDLOG_ERROR(\"Fail to start engine rpc server on port={}\",\n                 FLAGS_listen_port);\n    return -1;\n  }\n  SPDLOG_INFO(\"Started engine rpc server success, listen on: {}\",\n              butil::endpoint2str(server.listen_address()).c_str());\n\n  if (FLAGS_enable_separate_link_port) {\n    if (FLAGS_link_port == FLAGS_listen_port) {\n      SPDLOG_ERROR(\n          \"conf invalid, link_port should not be same as \"\n          \"listen_port if \"\n          \"--enable_separate_link_port=true\");\n      return -1;\n    }\n\n    brpc::ServerOptions link_svr_opts = BuildServerOptions();\n    link_svr_opts.has_builtin_services = false;\n\n    if (link_svr.Start(FLAGS_link_port, &link_svr_opts) != 0) {\n      SPDLOG_ERROR(\"Fail to start link server on port={}\", FLAGS_link_port);\n      return -1;\n    }\n\n    SPDLOG_INFO(\"Started link server success, listen on: {}\",\n                butil::endpoint2str(link_svr.listen_address()).c_str());\n  }\n\n  {\n    // replace SIGTERM handler in absl\n    struct sigaction action;\n    action.sa_handler = termination_handler;\n    sigemptyset(&action.sa_mask);\n    action.sa_flags = 0;\n    sigaction(SIGTERM, &action, nullptr);\n    // enable graceful quit on SIGTERM in brpc\n    brpc::FLAGS_graceful_quit_on_sigterm = true;\n  }\n\n  bool kpad_task_success = false;\n  if (cluster_def) {\n    kpad_task_success = ExecuteKpadTask(engine_svc.get(), *cluster_def,\n                                        FLAGS_kpad_job_id, server);\n  } else {\n    // Wait until Ctrl-C is pressed or SIGTERM received, then Stop() and Join()\n    // the server.\n    server.RunUntilAskedToQuit();\n  }\n\n  if (FLAGS_enable_separate_link_port) {\n    link_svr.Stop(0);\n    link_svr.Join();\n  }\n\n  // Release arrow s3 file resources safely.\n  // TODO(jingshi): remove to DumpFile operator to reduce coupling\n  if (arrow::fs::IsS3Initialized()) {\n    auto status = arrow::fs::FinalizeS3();\n    if (!status.ok()) {\n      SPDLOG_ERROR(\"Fail to FinalizeS3, msg={}\", status.ToString());\n    }\n  }\n\n  // Return appropriate result based on mode\n  if (cluster_def) {\n    return kpad_task_success ? 0 : -1;\n  }\n  return 0;\n}\n\ngrpc::SslCredentialsOptions LoadSslCredentialsOptions(\n    const std::string& key_file, const std::string& cert_file,\n    const std::string& cacert_file) {\n  grpc::SslCredentialsOptions opts;\n\n  std::string content;\n  YACL_ENFORCE(butil::ReadFileToString(butil::FilePath(cacert_file), &content));\n  opts.pem_root_certs = content;\n\n  YACL_ENFORCE(butil::ReadFileToString(butil::FilePath(key_file), &content));\n  opts.pem_private_key = content;\n\n  YACL_ENFORCE(butil::ReadFileToString(butil::FilePath(cert_file), &content));\n  opts.pem_cert_chain = content;\n  return opts;\n}\n"
  },
  {
    "path": "engine/exe/version.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#define ENGINE_VERSION_STRING \"SCQL_VERSION\"\n"
  },
  {
    "path": "engine/framework/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncc_library(\n    name = \"operator\",\n    srcs = [\"operator.cc\"],\n    hdrs = [\"operator.h\"],\n    deps = [\n        \":exec\",\n        \"@gflags\",\n    ],\n)\n\ncc_library(\n    name = \"registry\",\n    srcs = [\"registry.cc\"],\n    hdrs = [\"registry.h\"],\n    deps = [\n        \":operator\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"tensor_table\",\n    srcs = [\"tensor_table.cc\"],\n    hdrs = [\"tensor_table.h\"],\n    deps = [\n        \"//engine/core:tensor\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"exec\",\n    srcs = [\"exec.cc\"],\n    hdrs = [\"exec.h\"],\n    deps = [\n        \":session\",\n        \":tensor_table\",\n        \"//api:core_cc_proto\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\ncc_library(\n    name = \"executor\",\n    srcs = [\"executor.cc\"],\n    hdrs = [\"executor.h\"],\n    deps = [\n        \":registry\",\n    ],\n)\n\ncc_library(\n    name = \"session\",\n    srcs = [\"session.cc\"],\n    hdrs = [\"session.h\"],\n    deps = [\n        \":party_info\",\n        \":tensor_table\",\n        \"//api:common_cc_proto\",\n        \"//api:engine_cc_proto\",\n        \"//engine/datasource:datasource_adaptor_mgr\",\n        \"//engine/datasource:router\",\n        \"//engine/exe:flags\",\n        \"//engine/util:logging\",\n        \"//engine/util:progress_util\",\n        \"//engine/util:prometheus_monitor\",\n        \"//engine/util/psi:detail_logger\",\n        \"@openssl\",\n        \"@spulib//libspu/core:config\",\n        \"@spulib//libspu/core:context\",\n        \"@spulib//libspu/device:symbol_table\",\n        \"@spulib//libspu/mpc:factory\",\n        \"@yacl//yacl/link\",\n    ],\n)\n\nconfig_setting(\n    name = \"unset_tcmalloc\",\n    define_values = {\"disable_tcmalloc\": \"true\"},\n)\n\ncc_library(\n    name = \"session_manager\",\n    srcs = [\"session_manager.cc\"],\n    hdrs = [\"session_manager.h\"],\n    copts = select({\n        \"unset_tcmalloc\": [\"-DDISABLE_TCMALLOC\"],\n        \"//conditions:default\": [],\n    }),\n    deps = [\n        \":session\",\n        \"//engine/link:listener\",\n        \"//engine/util:trace_categories\",\n    ] + select({\n        \"unset_tcmalloc\": [],\n        \"//conditions:default\": [\"@com_github_gperftools_gperftools//:gperftools\"],\n    }),\n)\n\nscql_cc_test(\n    name = \"session_manager_test\",\n    srcs = [\"session_manager_test.cc\"],\n    deps = [\n        \":session_manager\",\n        \"//engine/operator:test_util\",\n    ],\n)\n\ncc_library(\n    name = \"party_info\",\n    srcs = [\"party_info.cc\"],\n    hdrs = [\"party_info.h\"],\n    deps = [\n        \"//api:engine_cc_proto\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\nscql_cc_test(\n    name = \"party_info_test\",\n    srcs = [\"party_info_test.cc\"],\n    deps = [\n        \":party_info\",\n        \"//engine/operator:test_util\",\n    ],\n)\n"
  },
  {
    "path": "engine/framework/exec.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/framework/exec.h\"\n\n#include \"yacl/base/exception.h\"\n\n#include \"engine/framework/session.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine {\n\nExecContext::ExecContext(const pb::ExecNode& node, Session* session)\n    : node_(node), session_(session) {}\n\nstd::shared_ptr<spdlog::logger> ExecContext::GetActiveLogger() const {\n  return ActiveLogger(session_);\n}\n\nconst std::string& ExecContext::GetNodeName() const {\n  return node_.node_name();\n}\n\nconst std::string& ExecContext::GetOpType() const { return node_.op_type(); }\n\nconst RepeatedPbTensor& ExecContext::GetInput(const std::string& name) const {\n  YACL_ENFORCE(node_.inputs().count(name) > 0,\n               \"the input {} of op {} does not exist\", name, node_.op_type());\n  return node_.inputs().at(name).tensors();\n}\n\nconst RepeatedPbTensor& ExecContext::GetOutput(const std::string& name) const {\n  YACL_ENFORCE(node_.outputs().count(name) > 0,\n               \"the output {} of op {} does not exist\", name, node_.op_type());\n  return node_.outputs().at(name).tensors();\n}\n\nRepeatedPbTensor ExecContext::GetInputPbs() const {\n  RepeatedPbTensor tensors;\n  for (const auto& pair : node_.inputs()) {\n    tensors.Add(pair.second.tensors().begin(), pair.second.tensors().end());\n  }\n  return tensors;\n}\n\nRepeatedPbTensor ExecContext::GetOutputPbs() const {\n  RepeatedPbTensor tensors;\n  for (const auto& pair : node_.outputs()) {\n    tensors.Add(pair.second.tensors().begin(), pair.second.tensors().end());\n  }\n  return tensors;\n}\n\nconst pb::AttributeValue& ExecContext::GetAttribute(\n    const std::string& name) const {\n  YACL_ENFORCE(node_.attributes().count(name) > 0,\n               \"The attribute {} of op {} does not exist\", name,\n               node_.op_type());\n  return node_.attributes().at(name);\n}\n\nstd::vector<std::string> ExecContext::GetStringValuesFromAttribute(\n    const std::string& name) const {\n  const auto& attr = GetAttribute(name);\n  return util::GetStringValues(attr.t());\n}\n\nstd::string ExecContext::GetStringValueFromAttribute(\n    const std::string& name) const {\n  const auto& attr = GetAttribute(name);\n  return util::GetStringValue(attr.t());\n}\n\nint64_t ExecContext::GetInt64ValueFromAttribute(const std::string& name) const {\n  const auto& attr = GetAttribute(name);\n  return util::GetInt64Value(attr.t());\n}\n\nbool ExecContext::GetBooleanValueFromAttribute(const std::string& name) const {\n  const auto& attr = GetAttribute(name);\n  return util::GetBooleanValue(attr.t());\n}\n\nstd::vector<bool> ExecContext::GetBooleanValuesFromAttribute(\n    const std::string& name) const {\n  const auto& attr = GetAttribute(name);\n  return util::GetBooleanValues(attr.t());\n}\n\ndouble ExecContext::GetDoubleValueFromAttribute(const std::string& name) const {\n  const auto& attr = GetAttribute(name);\n  return util::GetDoubleValue(attr.t());\n}\n\nstd::optional<std::vector<std::string>>\nExecContext::TryGetStringValuesFromAttribute(const std::string& name) const {\n  if (!HasAttribute(name)) {\n    return {};\n  }\n  const auto& attr = GetAttribute(name);\n  return util::GetStringValues(attr.t());\n}\n\nstd::optional<std::string> ExecContext::TryGetStringValueFromAttribute(\n    const std::string& name) const {\n  if (!HasAttribute(name)) {\n    return {};\n  }\n  const auto& attr = GetAttribute(name);\n  return util::GetStringValue(attr.t());\n}\n\nstd::optional<int64_t> ExecContext::TryGetInt64ValueFromAttribute(\n    const std::string& name) const {\n  if (!HasAttribute(name)) {\n    return {};\n  }\n  const auto& attr = GetAttribute(name);\n  return util::GetInt64Value(attr.t());\n}\n\nstd::optional<bool> ExecContext::TryGetBooleanValueFromAttribute(\n    const std::string& name) const {\n  if (!HasAttribute(name)) {\n    return {};\n  }\n  const auto& attr = GetAttribute(name);\n  return util::GetBooleanValue(attr.t());\n}\n\nstd::optional<double> ExecContext::TryGetDoubleValueFromAttribute(\n    const std::string& name) const {\n  if (!HasAttribute(name)) {\n    return {};\n  }\n  const auto& attr = GetAttribute(name);\n  return util::GetDoubleValue(attr.t());\n}\n\n// Tensor access implementations\nstd::shared_ptr<Tensor> ExecContext::GetInputTensor(\n    const std::string& input_name, size_t index) {\n  const auto& input_pbs = GetInput(input_name);\n  YACL_ENFORCE(index < input_pbs.size(),\n               \"input index out of range for input: {}\", input_name);\n\n  auto tensor = GetTensorTable()->GetTensor(input_pbs[index].name());\n  YACL_ENFORCE(tensor, \"get private tensor failed, name={}\",\n               input_pbs[index].name());\n  return tensor;\n}\n\nstd::vector<std::shared_ptr<Tensor>> ExecContext::GetInputTensors(\n    const std::string& input_name) {\n  const auto& input_pbs = GetInput(input_name);\n  std::vector<std::shared_ptr<Tensor>> tensors;\n  tensors.reserve(input_pbs.size());\n\n  for (const auto& input_pb : input_pbs) {\n    auto tensor = GetTensorTable()->GetTensor(input_pb.name());\n    YACL_ENFORCE(tensor, \"get private tensor failed, name={}\", input_pb.name());\n    tensors.push_back(tensor);\n  }\n  return tensors;\n}\n\nvoid ExecContext::SetOutputTensor(const std::string& output_name,\n                                  std::shared_ptr<Tensor> tensor,\n                                  size_t index) {\n  const auto& output_pbs = GetOutput(output_name);\n  YACL_ENFORCE(index < output_pbs.size(),\n               \"output index out of range for output: {}\", output_name);\n\n  GetTensorTable()->AddTensor(output_pbs[index].name(), std::move(tensor));\n}\n\nvoid ExecContext::SetOutputTensors(\n    const std::string& output_name,\n    const std::vector<std::shared_ptr<Tensor>>& tensors) {\n  const auto& output_pbs = GetOutput(output_name);\n  YACL_ENFORCE(tensors.size() == output_pbs.size(),\n               \"tensor count {} doesn't match output count {} for output: {}\",\n               tensors.size(), output_pbs.size(), output_name);\n\n  for (size_t i = 0; i < tensors.size(); ++i) {\n    GetTensorTable()->AddTensor(output_pbs[i].name(), tensors[i]);\n  }\n}\n\n// SPU Value access implementations\nspu::Value ExecContext::GetInputValue(const std::string& input_name,\n                                      size_t index) {\n  const auto& input_pbs = GetInput(input_name);\n  YACL_ENFORCE(index < input_pbs.size(),\n               \"input index out of range for input: {}\", input_name);\n\n  auto device_symbols = GetSession()->GetDeviceSymbols();\n  return device_symbols->getVar(\n      util::SpuVarNameEncoder::GetValueName(input_pbs[index].name()));\n}\n\nstd::vector<spu::Value> ExecContext::GetInputValues(\n    const std::string& input_name) {\n  const auto& input_pbs = GetInput(input_name);\n  std::vector<spu::Value> values;\n  values.reserve(input_pbs.size());\n\n  auto device_symbols = GetSession()->GetDeviceSymbols();\n  for (const auto& input_pb : input_pbs) {\n    values.push_back(device_symbols->getVar(\n        util::SpuVarNameEncoder::GetValueName(input_pb.name())));\n  }\n  return values;\n}\n\nvoid ExecContext::SetOutputValue(const std::string& output_name,\n                                 const spu::Value& value, size_t index) {\n  const auto& output_pbs = GetOutput(output_name);\n  YACL_ENFORCE(index < output_pbs.size(),\n               \"output index out of range for output: {}\", output_name);\n\n  auto device_symbols = GetSession()->GetDeviceSymbols();\n  device_symbols->setVar(\n      util::SpuVarNameEncoder::GetValueName(output_pbs[index].name()), value);\n}\n\nvoid ExecContext::SetOutputValues(const std::string& output_name,\n                                  const std::vector<spu::Value>& values) {\n  const auto& output_pbs = GetOutput(output_name);\n  YACL_ENFORCE(values.size() == output_pbs.size(),\n               \"value count {} doesn't match output count {} for output: {}\",\n               values.size(), output_pbs.size(), output_name);\n\n  auto device_symbols = GetSession()->GetDeviceSymbols();\n  for (size_t i = 0; i < values.size(); ++i) {\n    device_symbols->setVar(\n        util::SpuVarNameEncoder::GetValueName(output_pbs[i].name()), values[i]);\n  }\n}\n\n#ifdef SCQL_WITH_NULL\n// SPU Validity access implementations\nspu::Value ExecContext::GetInputValidity(const std::string& input_name,\n                                         size_t index) {\n  const auto& input_pbs = GetInput(input_name);\n  YACL_ENFORCE(index < input_pbs.size(),\n               \"input index out of range for input: {}\", input_name);\n\n  auto device_symbols = GetSession()->GetDeviceSymbols();\n  return device_symbols->getVar(\n      util::SpuVarNameEncoder::GetValidityName(input_pbs[index].name()));\n}\n\nstd::vector<spu::Value> ExecContext::GetInputValidities(\n    const std::string& input_name) {\n  const auto& input_pbs = GetInput(input_name);\n  std::vector<spu::Value> validities;\n  validities.reserve(input_pbs.size());\n\n  auto device_symbols = GetSession()->GetDeviceSymbols();\n  for (const auto& input_pb : input_pbs) {\n    validities.push_back(device_symbols->getVar(\n        util::SpuVarNameEncoder::GetValidityName(input_pb.name())));\n  }\n  return validities;\n}\n\nvoid ExecContext::SetOutputValidity(const std::string& output_name,\n                                    const spu::Value& validity, size_t index) {\n  const auto& output_pbs = GetOutput(output_name);\n  YACL_ENFORCE(index < output_pbs.size(),\n               \"output index out of range for output: {}\", output_name);\n\n  auto device_symbols = GetSession()->GetDeviceSymbols();\n  device_symbols->setVar(\n      util::SpuVarNameEncoder::GetValidityName(output_pbs[index].name()),\n      validity);\n}\n\nvoid ExecContext::SetOutputValidities(\n    const std::string& output_name, const std::vector<spu::Value>& validities) {\n  const auto& output_pbs = GetOutput(output_name);\n  YACL_ENFORCE(validities.size() == output_pbs.size(),\n               \"validity count {} doesn't match output count {} for output: {}\",\n               validities.size(), output_pbs.size(), output_name);\n\n  auto device_symbols = GetSession()->GetDeviceSymbols();\n  for (size_t i = 0; i < validities.size(); ++i) {\n    device_symbols->setVar(\n        util::SpuVarNameEncoder::GetValidityName(output_pbs[i].name()),\n        validities[i]);\n  }\n}\n#endif  // SCQL_WITH_NULL\n\n// Status query implementations\npb::TensorStatus ExecContext::GetInputStatus(const std::string& input_name,\n                                             size_t index) {\n  const auto& input_pbs = GetInput(input_name);\n  YACL_ENFORCE(index < input_pbs.size(),\n               \"input index out of range for input: {}\", input_name);\n\n  return util::GetTensorStatus(input_pbs[index]);\n}\n\npb::TensorStatus ExecContext::GetOutputStatus(const std::string& output_name,\n                                              size_t index) {\n  const auto& output_pbs = GetOutput(output_name);\n  YACL_ENFORCE(index < output_pbs.size(),\n               \"output index out of range for output: {}\", output_name);\n\n  return util::GetTensorStatus(output_pbs[index]);\n}\n\nstd::shared_ptr<Tensor> ExecContext::GetPrivateOrPublicTensor(\n    const pb::Tensor& t) {\n  std::shared_ptr<Tensor> ret;\n  if (util::IsTensorStatusMatched(t, pb::TENSORSTATUS_PUBLIC)) {\n    // read public tensor from spu device symbol table\n    auto spu_io = util::SpuOutfeedHelper(GetSession()->GetSpuContext(),\n                                         GetSession()->GetDeviceSymbols());\n    ret = spu_io.DumpPublic(t.name());\n\n    if (t.elem_type() == pb::PrimitiveDataType::STRING) {\n      ret = GetSession()->HashToString(*ret);\n    }\n  } else {\n    ret = GetTensorTable()->GetTensor(t.name());\n    YACL_ENFORCE(ret, \"get private tensor failed, name={}\", t.name());\n  }\n  return ret;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/framework/exec.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <optional>\n#include <vector>\n\n#include \"engine/core/tensor.h\"\n#include \"engine/framework/session.h\"\n\n#include \"api/core.pb.h\"\n\n// Forward declarations\nnamespace spu {\nclass SPUContext;\nclass Value;\n}  // namespace spu\n\nnamespace scql::engine {\n\n/// @brief Operator Execute Context\nclass ExecContext {\n public:\n  ExecContext(const pb::ExecNode& node, Session* session);\n\n  TensorTable* GetTensorTable() const { return session_->GetTensorTable(); }\n\n  Router* GetDatasourceRouter() const { return session_->GetRouter(); }\n\n  DatasourceAdaptorMgr* GetDatasourceAdaptorMgr() const {\n    return session_->GetDatasourceAdaptorMgr();\n  }\n\n  Session* GetSession() const { return session_; }\n\n  std::shared_ptr<spdlog::logger> GetActiveLogger() const;\n\n  // interface for ExecNode\n  const std::string& GetNodeName() const;\n\n  const std::string& GetOpType() const;\n  // Input/Output\n  const RepeatedPbTensor& GetInput(const std::string& name) const;\n\n  const RepeatedPbTensor& GetOutput(const std::string& name) const;\n\n  // Input/Output\n  RepeatedPbTensor GetInputPbs() const;\n\n  RepeatedPbTensor GetOutputPbs() const;\n\n  // attributes\n  // get attribute value by name\n  const pb::AttributeValue& GetAttribute(const std::string& name) const;\n  std::vector<std::string> GetStringValuesFromAttribute(\n      const std::string& name) const;\n  std::string GetStringValueFromAttribute(const std::string& name) const;\n  int64_t GetInt64ValueFromAttribute(const std::string& name) const;\n  bool GetBooleanValueFromAttribute(const std::string& name) const;\n  std::vector<bool> GetBooleanValuesFromAttribute(\n      const std::string& name) const;\n  double GetDoubleValueFromAttribute(const std::string& name) const;\n  bool HasAttribute(const std::string& name) const {\n    return node_.attributes().count(name) > 0;\n  }\n  std::optional<std::vector<std::string>> TryGetStringValuesFromAttribute(\n      const std::string& name) const;\n  std::optional<std::string> TryGetStringValueFromAttribute(\n      const std::string& name) const;\n  std::optional<int64_t> TryGetInt64ValueFromAttribute(\n      const std::string& name) const;\n  std::optional<bool> TryGetBooleanValueFromAttribute(\n      const std::string& name) const;\n  std::optional<double> TryGetDoubleValueFromAttribute(\n      const std::string& name) const;\n\n  // Tensor access interfaces\n  std::shared_ptr<Tensor> GetInputTensor(const std::string& input_name,\n                                         size_t index = 0);\n  std::vector<std::shared_ptr<Tensor>> GetInputTensors(\n      const std::string& input_name);\n  void SetOutputTensor(const std::string& output_name,\n                       std::shared_ptr<Tensor> tensor, size_t index = 0);\n  void SetOutputTensors(const std::string& output_name,\n                        const std::vector<std::shared_ptr<Tensor>>& tensors);\n\n  // Get tensor for private/public status based on tensor status\n  std::shared_ptr<Tensor> GetPrivateOrPublicTensor(const pb::Tensor& t);\n\n  // SPU Value access interfaces (for public/secret status)\n  spu::Value GetInputValue(const std::string& input_name, size_t index = 0);\n  std::vector<spu::Value> GetInputValues(const std::string& input_name);\n  void SetOutputValue(const std::string& output_name, const spu::Value& value,\n                      size_t index = 0);\n  void SetOutputValues(const std::string& output_name,\n                       const std::vector<spu::Value>& values);\n\n#ifdef SCQL_WITH_NULL\n  // SPU Validity access interfaces\n  spu::Value GetInputValidity(const std::string& input_name, size_t index = 0);\n  std::vector<spu::Value> GetInputValidities(const std::string& input_name);\n  void SetOutputValidity(const std::string& output_name,\n                         const spu::Value& validity, size_t index = 0);\n  void SetOutputValidities(const std::string& output_name,\n                           const std::vector<spu::Value>& validities);\n#endif\n\n  // Status query interface\n  pb::TensorStatus GetInputStatus(const std::string& input_name,\n                                  size_t index = 0);\n  pb::TensorStatus GetOutputStatus(const std::string& output_name,\n                                   size_t index = 0);\n\n private:\n  const pb::ExecNode& node_;\n  Session* session_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/framework/executor.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/framework/executor.h\"\n\n#include \"engine/framework/registry.h\"\n\nnamespace scql::engine {\n\nvoid Executor::RunExecNode(ExecContext* context) {\n  const std::string& type_name = context->GetOpType();\n  auto op = GetOpRegistry()->GetOperator(type_name);\n  if (op == nullptr) {\n    YACL_THROW_LOGIC_ERROR(\"fail to instantiate operator {}\", type_name);\n  }\n  op->Run(context);\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/framework/executor.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/exec.h\"\n\nnamespace scql::engine {\n\n/// @brief Executor executes the ops defined in DAG\nclass Executor {\n public:\n  Executor() = default;\n\n  ~Executor() = default;\n\n  static void RunExecNode(ExecContext* context);\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/framework/operator.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/framework/operator.h\"\n\n#include \"gflags/gflags.h\"\n\nDEFINE_bool(enable_tensor_life_cycle_manage, true,\n            \"whether tensor life cycle manage is enable/disable\");\n\nnamespace scql::engine {\n\nvoid Operator::ManageTensorLifecycle(ExecContext *ctx) {\n  if (!FLAGS_enable_tensor_life_cycle_manage) {\n    return;\n  }\n  auto in_tensors = ctx->GetInputPbs();\n  auto out_tensors = ctx->GetOutputPbs();\n  std::vector<std::string> in_tensor_names;\n  for (const auto &tensor : in_tensors) {\n    in_tensor_names.emplace_back(tensor.name());\n  }\n  Session::RefNums output_ref_nums;\n  for (const auto &tensor : out_tensors) {\n    output_ref_nums.emplace_back(tensor.name(), tensor.ref_num());\n  }\n  ctx->GetSession()->UpdateRefName(in_tensor_names, output_ref_nums);\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/framework/operator.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <string>\n\n#include \"engine/framework/exec.h\"\n\nnamespace scql::engine {\n\nclass Operator {\n public:\n  virtual ~Operator() = default;\n\n  // operator type name.\n  virtual const std::string& Type() const = 0;\n\n  void Run(ExecContext* ctx) {\n    Validate(ctx);\n    Execute(ctx);\n    ManageTensorLifecycle(ctx);\n  }\n\n protected:\n  // It will throw exception if validation fails\n  virtual void Validate(ExecContext* ctx) {}\n  virtual void Execute(ExecContext* ctx) = 0;\n  static void ManageTensorLifecycle(ExecContext* ctx);\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/framework/party_info.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/framework/party_info.h\"\n\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine {\n\nPartyInfo::PartyInfo(const pb::JobStartParams& params) {\n  my_party_code_ = params.party_code();\n\n  parties_.resize(params.parties_size());\n\n  std::vector<bool> found(params.parties_size(), false);\n\n  for (int i = 0; i < params.parties_size(); ++i) {\n    const auto& party = params.parties(i);\n    if (party.rank() < 0 || party.rank() >= params.parties_size()) {\n      YACL_THROW(\"party({}) rank is out of range [0, {})\",\n                 party.ShortDebugString(), params.parties_size());\n    }\n    if (found[party.rank()]) {\n      YACL_THROW(\"party({}) rank already exists\", party.ShortDebugString());\n    }\n    size_t rank = party.rank();\n\n    found[rank] = true;\n\n    parties_[rank].id = party.code();\n    parties_[rank].host = party.host();\n\n    code_rank_map_[party.code()] = rank;\n  }\n\n  auto iter = code_rank_map_.find(my_party_code_);\n  if (iter == code_rank_map_.end()) {\n    YACL_THROW(\n        \"invalid JobStartParams, self party code not found in the parties \"\n        \"list: {}\",\n        params.ShortDebugString());\n  }\n}\n\nsize_t PartyInfo::SelfRank() const {\n  ssize_t rank = GetRank(SelfPartyCode());\n  YACL_ENFORCE(rank != -1, \"invalid PartyInfo, self party info not found\");\n  return rank;\n}\n\nssize_t PartyInfo::GetRank(const std::string& party_code) const {\n  auto iter = code_rank_map_.find(party_code);\n  if (iter != code_rank_map_.end()) {\n    return iter->second;\n  }\n  return -1;\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/framework/party_info.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <map>\n#include <string>\n#include <vector>\n\n#include \"api/engine.pb.h\"\n\nnamespace scql::engine {\n\n/// @brief Computational parties information\nclass PartyInfo {\n public:\n  struct Party {\n    std::string id;\n    std::string host;\n  };\n\n public:\n  explicit PartyInfo(const pb::JobStartParams& params);\n\n  // Only used in Python binding, host info is not needed\n  PartyInfo(const std::string& self_party_code,\n            const google::protobuf::RepeatedPtrField<pb::PartyId>& parties) {\n    my_party_code_ = self_party_code;\n    for (int i = 0; i < parties.size(); ++i) {\n      Party party;\n      party.id = parties.Get(i).code();\n      parties_.push_back(party);\n      code_rank_map_[party.id] = i;\n    }\n  }\n\n  PartyInfo() = delete;\n\n  size_t SelfRank() const;\n\n  size_t WorldSize() const { return parties_.size(); }\n\n  const std::string& SelfPartyCode() const { return my_party_code_; }\n\n  /// @brief query the rank of given party code, returns -1 if not found.\n  ssize_t GetRank(const std::string& party_code) const;\n\n  const std::vector<PartyInfo::Party>& AllParties() const { return parties_; }\n\n private:\n  std::string my_party_code_;\n\n  std::vector<Party> parties_;\n  // party code -> rank map\n  std::map<std::string, size_t> code_rank_map_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/framework/party_info_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/framework/party_info.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine {\n\nTEST(PartyInfoTest, normal) {\n  // Given\n  pb::JobStartParams params;\n  {\n    params.set_party_code(op::test::kPartyAlice);\n\n    auto* alice = params.add_parties();\n    alice->CopyFrom(op::test::BuildParty(op::test::kPartyAlice, 0));\n\n    auto* bob = params.add_parties();\n    bob->CopyFrom(op::test::BuildParty(op::test::kPartyBob, 1));\n  }\n\n  // When\n  PartyInfo parties(params);\n\n  // Then\n  EXPECT_EQ(parties.SelfRank(), 0);\n  EXPECT_EQ(parties.WorldSize(), 2);\n  EXPECT_EQ(parties.SelfPartyCode(), op::test::kPartyAlice);\n  EXPECT_EQ(parties.GetRank(op::test::kPartyBob), 1);\n  EXPECT_EQ(parties.GetRank(op::test::kPartyCarol), -1);\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/framework/registry.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/framework/registry.h\"\n\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine {\n\nstd::unique_ptr<OpRegistry> OpRegistry::Make() {\n  return std::unique_ptr<OpRegistry>(new OpRegistry());\n}\n\nvoid OpRegistry::AddOperator(const std::string& type_name,\n                             OperatorCreator op_creator) {\n  std::lock_guard<std::mutex> guard(lock_);\n  auto it = ops_.find(type_name);\n  if (it != ops_.end()) {\n    YACL_THROW(\"\\\"{}\\\" operator has been already registered\", type_name);\n  }\n  ops_[type_name] = std::move(op_creator);\n}\n\nstd::unique_ptr<Operator> OpRegistry::GetOperator(\n    const std::string& type_name) {\n  auto iter = ops_.find(type_name);\n  if (iter == ops_.end()) {\n    return nullptr;\n  }\n  return (iter->second)();\n}\n\nOpRegistry* GetOpRegistry() {\n  static auto g_registry = OpRegistry::Make();\n  return g_registry.get();\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/framework/registry.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n#include <mutex>\n#include <unordered_map>\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine {\n\n// operator registry\nclass OpRegistry {\n public:\n  using OperatorCreator = std::function<std::unique_ptr<Operator>()>;\n\n  ~OpRegistry() = default;\n\n  // Make a new registry. Most users should use the global registry\n  static std::unique_ptr<OpRegistry> Make();\n\n  // Add a new operator creator to the registry\n  void AddOperator(const std::string& type_name, OperatorCreator op_creator);\n\n  // Returns a new operator instance of type_name\n  std::unique_ptr<Operator> GetOperator(const std::string& type_name);\n\n private:\n  OpRegistry() = default;\n\n  std::mutex lock_;\n  // map operator type --> OperatorCreator\n  std::unordered_map<std::string, OperatorCreator> ops_;\n};\n\n// Return the global operator registry\nOpRegistry* GetOpRegistry();\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/framework/session.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/framework/session.h\"\n\n#include <cstdint>\n#include <memory>\n#include <mutex>\n\n#include \"algorithm\"\n#include \"arrow/visit_array_inline.h\"\n#include \"google/protobuf/util/json_util.h\"\n#include \"libspu/core/config.h\"\n#include \"libspu/mpc/factory.h\"\n#include \"openssl/sha.h\"\n#include \"spdlog/spdlog.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/string_tensor_builder.h\"\n#include \"engine/util/filepath_helper.h\"\n#include \"engine/util/logging.h\"\n#include \"engine/util/prometheus_monitor.h\"\n#include \"engine/util/psi/detail_logger.h\"\n\nDEFINE_string(tmp_file_path, \"/tmp\", \"dir to out tmp files\");\nDEFINE_uint64(\n    streaming_row_num_threshold, 30 * 1000 * 1000,\n    \"if input row num of join is more than threshold, use streaming mode\");\nDEFINE_uint64(batch_row_num, 10 * 1000 * 1000,\n              \"max row num in one batch, working when row num is more than \"\n              \"streaming_row_num_threshold\");\n\nnamespace scql::engine {\n\npb::JobState ConvertSessionStateToJobState(SessionState state) {\n  switch (state) {\n    case SessionState::INITIALIZED:\n      return pb::JOB_INITIALIZED;\n    case SessionState::RUNNING:\n    case SessionState::COMP_FINISHED:\n    // ABORTING job is treated as running\n    case SessionState::ABORTING:\n      return pb::JOB_RUNNING;\n    case SessionState::SUCCEEDED:\n      return pb::JOB_SUCCEEDED;\n    case SessionState::FAILED:\n      return pb::JOB_FAILED;\n    default:\n      return pb::JOB_STATE_UNSPECIFIED;\n  }\n}\n\nstd::string SessionStateToString(SessionState state) {\n  switch (state) {\n    case SessionState::INITIALIZED:\n      return \"INITIALIZED\";\n    case SessionState::RUNNING:\n      return \"RUNNING\";\n    case SessionState::COMP_FINISHED:\n      return \"COMPUTATION_FINISHED\";\n    case SessionState::SUCCEEDED:\n      return \"SUCCEEDED\";\n    case SessionState::FAILED:\n      return \"FAILED\";\n    case SessionState::ABORTING:\n      return \"ABORTING\";\n    default:\n      return \"UNKNOWN_STATE_\" + std::to_string(static_cast<int>(state));\n  }\n}\n\nbool Session::ValidateSPUContext() {\n  YACL_ENFORCE(spu_ctx_ != nullptr,\n               \"SPU context is not initialized successfully.\");\n  return std::find(allowed_spu_protocols_.begin(), allowed_spu_protocols_.end(),\n                   spu_ctx_->config().protocol) != allowed_spu_protocols_.end();\n}\n\nSession::Session(const SessionOptions& session_opt,\n                 const pb::JobStartParams& params, pb::DebugOptions debug_opts,\n                 yacl::link::ILinkFactory* link_factory, Router* router,\n                 DatasourceAdaptorMgr* ds_mgr,\n                 const std::vector<spu::ProtocolKind>& allowed_spu_protocols)\n    : id_(params.job_id()),\n      session_opt_(session_opt),\n      time_zone_(params.time_zone()),\n      parties_(params),\n      state_(SessionState::INITIALIZED),\n      link_factory_(link_factory),\n      router_(router),\n      ds_mgr_(ds_mgr),\n      debug_opts_(std::move(debug_opts)),\n      allowed_spu_protocols_(allowed_spu_protocols) {\n  start_time_ = std::chrono::system_clock::now();\n\n  std::string logger_name = \"job(\" + id_ + \")\";\n  if (session_opt.log_options.enable_session_logger_separation ||\n      session_opt.log_config.enable_session_logger_separation) {\n    std::string logger_file_name = logger_name + \".log\";\n    logger_ = util::CreateLogger(logger_name, logger_file_name,\n                                 session_opt.log_options);\n  } else {\n    logger_ = util::DupDefaultLogger(logger_name);\n  }\n\n  tensor_table_ = std::make_unique<TensorTable>();\n\n  InitLink();\n  if (lctx_->WorldSize() >= 2) {\n    // spu SPUContext valid only when world_size >= 2\n    auto config = spu::RuntimeConfig(params.spu_runtime_cfg());\n    spu::populateRuntimeConfig(config);\n    spu_ctx_ = std::make_unique<spu::SPUContext>(config, lctx_);\n    YACL_ENFORCE(\n        ValidateSPUContext(),\n        \"SPU runtime validation failed. Protocol {} is \"\n        \"not allowed in current scenario, only [{}] are allowed\",\n        spu::GetProtocolKindName(spu_ctx_->config().protocol),\n        std::accumulate(\n            allowed_spu_protocols_.begin(), allowed_spu_protocols_.end(),\n            std::string{},\n            [](const std::string& acc, const spu::ProtocolKind& protocol) {\n              return acc.empty()\n                         ? std::string(spu::GetProtocolKindName(protocol))\n                         : fmt::format(\"{},{}\", acc,\n                                       spu::GetProtocolKindName(protocol));\n            }));\n    spu::mpc::Factory::RegisterProtocol(spu_ctx_.get(), lctx_);\n  }\n\n  // create detail logger for session if need\n  if (session_opt.log_options.enable_psi_detail_logger &&\n      debug_opts_.enable_psi_detail_log()) {\n    psi_logger_ = std::make_shared<util::PsiDetailLogger>(\n        util::CreateDetailLogger(id_, id_ + \".log\", session_opt.log_options));\n  }\n  session_opt_.streaming_options.batch_row_num = FLAGS_batch_row_num;\n  session_opt_.streaming_options.dump_file_dir =\n      util::CreateDirWithRandSuffix(FLAGS_tmp_file_path, id_);\n  Negotiate();\n  util::PrometheusMonitor::GetInstance()->IncSessionNumberTotal();\n}\n\nSession::Session(const PartyInfo& party_info,\n                 const spu::pb::RuntimeConfig& spu_cfg, Router* router,\n                 DatasourceAdaptorMgr* ds_mgr,\n                 const std::shared_ptr<yacl::link::Context>& link_context)\n    : id_(link_context->Id()),\n      session_opt_(SessionOptions{}),  // TODO: support SessionOptions\n      time_zone_(\"+08:00\"),            // TODO: support timezone\n      parties_(party_info),\n      state_(SessionState::INITIALIZED),\n      link_factory_(nullptr),  // not used in this constructor\n      router_(router),\n      ds_mgr_(ds_mgr) {\n  start_time_ = std::chrono::system_clock::now();\n\n  // Create logger\n  std::string logger_name = \"job(\" + id_ + \")\";\n  if (session_opt_.log_options.enable_session_logger_separation ||\n      session_opt_.log_config.enable_session_logger_separation) {\n    std::string logger_file_name = logger_name + \".log\";\n    logger_ = util::CreateLogger(logger_name, logger_file_name,\n                                 session_opt_.log_options);\n  } else {\n    logger_ = util::DupDefaultLogger(logger_name);\n  }\n\n  // Create tensor table\n  tensor_table_ = std::make_unique<TensorTable>();\n\n  lctx_ = link_context;\n  if (lctx_->WorldSize() >= 2) {\n    // spu SPUContext valid only when world_size >= 2\n    auto config = spu::RuntimeConfig(spu_cfg);\n    spu::populateRuntimeConfig(config);\n    spu_ctx_ = std::make_unique<spu::SPUContext>(config, lctx_);\n    // TODO: check allowed_spu_protocols_\n    spu::mpc::Factory::RegisterProtocol(spu_ctx_.get(), lctx_);\n  }\n\n  session_opt_.streaming_options.batched = false;\n}\n\nSession::~Session() {\n  util::PrometheusMonitor::GetInstance()->DecSessionNumberTotal();\n  if (session_opt_.streaming_options.batched) {\n    std::error_code ec;\n    std::filesystem::remove_all(session_opt_.streaming_options.dump_file_dir,\n                                ec);\n    if (ec.value() != 0) {\n      SPDLOG_WARN(\"can not remove tmp dir: {}, msg: {}\",\n                  session_opt_.streaming_options.dump_file_dir.string(),\n                  ec.message());\n    }\n  }\n}\n\nvoid Session::InitLink() {\n  yacl::link::ContextDesc ctx_desc;\n  {\n    ctx_desc.id = id_;\n    ctx_desc.retry_opts = session_opt_.link_config.link_retry_options;\n    ctx_desc.recv_timeout_ms = session_opt_.link_config.link_recv_timeout_ms;\n    ctx_desc.http_max_payload_size =\n        session_opt_.link_config.http_max_payload_size;\n    ctx_desc.parties.reserve(parties_.WorldSize());\n    // connect interval 100ms\n    ctx_desc.connect_retry_interval_ms = 100;\n    // connect retry times 100, then max waiting time = 10s\n    ctx_desc.connect_retry_times = 100;\n    for (const auto& party : parties_.AllParties()) {\n      yacl::link::ContextDesc::Party p;\n      p.id = party.id;\n      p.host = party.host;\n      SPDLOG_INFO(\"party-host: ({})-({})\", p.id, p.host);\n      ctx_desc.parties.push_back(std::move(p));\n    }\n  }\n  YACL_ENFORCE(link_factory_ != nullptr);\n  lctx_ = link_factory_->CreateContext(ctx_desc, parties_.SelfRank());\n  lctx_->SetThrottleWindowSize(\n      session_opt_.link_config.link_throttle_window_size);\n  lctx_->SetChunkParallelSendSize(\n      session_opt_.link_config.link_chunked_send_parallel_size);\n  lctx_->ConnectToMesh();\n}\n\nvoid Session::MergeDeviceSymbolsFrom(const spu::device::SymbolTable& other) {\n  for (const auto& kv : other) {\n    YACL_ENFORCE(!device_symbols_.hasVar(kv.first), \"symbol {} already exists\",\n                 kv.first);\n    device_symbols_.setVar(kv.first, kv.second);\n  }\n}\n\nvoid Session::EnableStreamingBatched() {\n  session_opt_.streaming_options.batched = true;\n}\n\nvoid Session::Negotiate() {\n  if (lctx_->WorldSize() <= 1) {\n    return;\n  }\n  pb::NegotiationOptions options;\n  auto* psi_options = options.mutable_psi_options();\n  psi_options->mutable_psi_curve_types()->Add(\n      session_opt_.psi_config.psi_curve_type);\n  psi_options->set_rr22_mode(session_opt_.psi_config.rr22_mode);\n  auto* streaming_options = options.mutable_streaming_options();\n  streaming_options->set_streaming_row_num_threshold(\n      session_opt_.streaming_options.streaming_row_num_threshold);\n  streaming_options->set_batch_row_num(\n      session_opt_.streaming_options.batch_row_num);\n  // negotiation\n  std::vector<pb::NegotiationOptions> negotiation_options_v;\n  {\n    std::string option_str;\n    YACL_ENFORCE(options.SerializeToString(&option_str),\n                 \"failed to serialize NegotiationOptions to string\");\n    yacl::ByteContainerView buffer(option_str);\n    auto buffers = yacl::link::AllGather(lctx_, buffer, \"negotiate\");\n    // parse\n    for (const auto& value : buffers) {\n      pb::NegotiationOptions tmp_options;\n      YACL_ENFORCE(tmp_options.ParseFromArray(value.data(), value.size()),\n                   \"failed to parse NegotiationOptions from received buffer\");\n      negotiation_options_v.push_back(std::move(tmp_options));\n    }\n  }\n\n  // set rr22_mode as default value\n  session_opt_.psi_config.rr22_mode = pb::FAST_MODE;\n  for (auto& negotiation_options : negotiation_options_v) {\n    // use low mode if any party set rr22_mode as low mode\n    if (negotiation_options.psi_options().rr22_mode() == pb::LOW_MODE) {\n      session_opt_.psi_config.rr22_mode = pb::LOW_MODE;\n    }\n    // choose min streaming_row_num_threshold\n    session_opt_.streaming_options.streaming_row_num_threshold =\n        std::min(session_opt_.streaming_options.streaming_row_num_threshold,\n                 static_cast<size_t>(negotiation_options.streaming_options()\n                                         .streaming_row_num_threshold()));\n    // choose min batch_row_num\n    session_opt_.streaming_options.batch_row_num =\n        std::min(session_opt_.streaming_options.batch_row_num,\n                 static_cast<size_t>(\n                     negotiation_options.streaming_options().batch_row_num()));\n    // TODO: support psi curve type list\n    YACL_ENFORCE(\n        negotiation_options.psi_options().psi_curve_types().size() == 1,\n        \"only support one psi curve type but got {}\",\n        negotiation_options.psi_options().psi_curve_types().size());\n    if (negotiation_options.psi_options().psi_curve_types()[0] !=\n        session_opt_.psi_config.psi_curve_type) {\n      session_opt_.psi_config.psi_curve_type = psi::CURVE_INVALID_TYPE;\n    }\n  }\n}\n\n// The std::hash for std::string is not crypto-safe. Hence it cannot be used to\n// simulate a random oracle. Currently we still want the hash function to\n// generate a 64 bits fingerprint. Now we choose SHA256 and treat the first 64\n// bits as the hash bits. It is not perfect but could be considered random\n// enough given the 64 bits output constraint.\n//\n// Q: Why not std::hash ?\n// A: std::hash has a much higher confliction possibility than taking 64bit from\n// SHA256 results.\n//\n// Q: Why `std::hash` is not crypto-safe?\n// A: Most compiler choose to implement std::hash by `fast` hashing algo like\n// murmurhash .\n// See\n// https://stackoverflow.com/questions/19411742/what-is-the-default-hash-function-used-in-c-stdunordered-map\n\nstatic_assert(sizeof(size_t) == 8);\nsize_t CryptoHash(const std::string& str) {\n  // If md is NULL, the digest is placed in a static array. Note: setting md to\n  // NULL is not thread safe.\n  unsigned char md[SHA256_DIGEST_LENGTH];\n  auto* hash = SHA256(reinterpret_cast<const unsigned char*>(str.data()),\n                      str.size(), md);\n\n  size_t ret;\n  std::memcpy(&ret, hash, sizeof(ret));\n  return ret >> 1;  // spu FM64 only used 63 bit to calculate\n}\n\nnamespace {\n\nclass StringToHashConverter {\n public:\n  explicit StringToHashConverter(\n      absl::flat_hash_map<size_t, std::string>* hash_to_string)\n      : hash_to_string_(hash_to_string) {\n    YACL_ENFORCE(hash_to_string, \"hash_to_string can not be null.\");\n    builder_ = std::make_unique<UInt64TensorBuilder>();\n  }\n\n  void GetHashResult(std::shared_ptr<Tensor>* tensor) {\n    builder_->Finish(tensor);\n  }\n\n  template <typename T>\n  arrow::Status Visit(const T& array) {\n    return arrow::Status::NotImplemented(\n        fmt::format(\"type {} is not implemented in StringToHashConverter\",\n                    array.type()->name()));\n  }\n\n  arrow::Status Visit(const arrow::LargeStringArray& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      const std::string& cur_str = array.GetString(i);\n      size_t hash_value = CryptoHash(cur_str);\n\n      hash_to_string_->emplace(hash_value, cur_str);\n      builder_->Append(hash_value);\n    }\n    return arrow::Status::OK();\n  }\n\n private:\n  absl::flat_hash_map<size_t, std::string>* hash_to_string_;\n  std::unique_ptr<UInt64TensorBuilder> builder_;\n};\n\nclass HashToStringConverter {\n public:\n  explicit HashToStringConverter(\n      absl::flat_hash_map<size_t, std::string>* hash_to_string)\n      : hash_to_string_(hash_to_string) {\n    YACL_ENFORCE(hash_to_string, \"hash_to_string can not be null.\");\n    builder_ = std::make_unique<StringTensorBuilder>();\n  }\n\n  void GetStringResult(std::shared_ptr<Tensor>* tensor) {\n    builder_->Finish(tensor);\n  }\n\n  template <typename T>\n  arrow::Status Visit(const T& array) {\n    return arrow::Status::NotImplemented(\n        fmt::format(\"type {} is not implemented in HashToStringConverter\",\n                    array.type()->name()));\n  }\n\n  arrow::Status Visit(const arrow::NumericArray<arrow::UInt64Type>& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      const auto& hash_value = array.GetView(i);\n      auto iter = hash_to_string_->find(hash_value);\n      if (iter == hash_to_string_->end()) {\n        builder_->Append(kStringPlaceHolder);\n      } else {\n        builder_->Append(iter->second);\n      }\n    }\n    return arrow::Status::OK();\n  }\n\n private:\n  absl::flat_hash_map<size_t, std::string>* hash_to_string_;\n  std::unique_ptr<StringTensorBuilder> builder_;\n  static constexpr char kStringPlaceHolder[] = \"__null__\";\n};\n\n}  // namespace\n\nTensorPtr Session::StringToHash(const Tensor& string_tensor) {\n  StringToHashConverter converter(&hash_to_string_values_);\n  const auto& chunked_arr = string_tensor.ToArrowChunkedArray();\n  for (int i = 0; i < chunked_arr->num_chunks(); ++i) {\n    THROW_IF_ARROW_NOT_OK(\n        arrow::VisitArrayInline(*(chunked_arr->chunk(i)), &converter));\n  }\n\n  TensorPtr result;\n  converter.GetHashResult(&result);\n  return result;\n}\n\nTensorPtr Session::HashToString(const Tensor& hash_tensor) {\n  HashToStringConverter converter(&hash_to_string_values_);\n  const auto& chunked_arr = hash_tensor.ToArrowChunkedArray();\n  for (int i = 0; i < chunked_arr->num_chunks(); ++i) {\n    THROW_IF_ARROW_NOT_OK(\n        arrow::VisitArrayInline(*(chunked_arr->chunk(i)), &converter));\n  }\n\n  TensorPtr result;\n  converter.GetStringResult(&result);\n  return result;\n}\n\nvoid Session::DelTensors(const std::vector<std::string>& tensor_names) {\n  for (const auto& name : tensor_names) {\n    logger_->debug(\"remove tensor {}\", name);\n    if (tensor_table_->GetTensor(name) != nullptr) {\n      tensor_table_->RemoveTensor(name);\n    } else {\n      // FIXME(xiaoyuan), if run dag parallel, there is no lock in SymbolTable,\n      // may cause race condition\n      device_symbols_.delVar(name);\n    }\n  }\n}\n\n// ref_num_ = ref_num_ - 1 when this tensor is consumed\nvoid Session::UpdateRefName(const std::vector<std::string>& input_ref_names,\n                            const RefNums& output_ref_nums) {\n  std::vector<std::string> remove_tensor_names;\n  {\n    std::unique_lock<std::mutex> lock(mutex_);\n    for (const auto& name : input_ref_names) {\n      auto iter = tensor_ref_nums_.find(name);\n      if (iter != tensor_ref_nums_.end()) {\n        iter->second--;\n        if (iter->second == 0) {\n          remove_tensor_names.emplace_back(name);\n          tensor_ref_nums_.erase(name);\n        }\n      }\n    }\n    for (const auto& ref_tuple : output_ref_nums) {\n      auto name = std::get<0>(ref_tuple);\n      auto ref_count = std::get<1>(ref_tuple);\n      if (ref_count == 0) {\n        // ref by no one\n        remove_tensor_names.emplace_back(name);\n        continue;\n      }\n      auto iter = tensor_ref_nums_.find(name);\n      if (!session_opt_.streaming_options.batched) {\n        YACL_ENFORCE(iter == tensor_ref_nums_.end(),\n                     \"ref num of {} was set before created\", name);\n      }\n      tensor_ref_nums_[name] = std::get<1>(ref_tuple);\n    }\n  }\n  DelTensors(remove_tensor_names);\n}\n\nstd::shared_ptr<spdlog::logger> ActiveLogger(const Session* session) {\n  if (session == nullptr) {\n    SPDLOG_WARN(\"can not get valid session\");\n    return spdlog::default_logger();\n  }\n  auto session_logger = session->GetLogger();\n  if (session_logger == nullptr) {\n    SPDLOG_WARN(\"null session logger\");\n    return spdlog::default_logger();\n  }\n  return session_logger;\n}\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/framework/session.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <atomic>\n#include <chrono>\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n#include <mutex>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"absl/container/flat_hash_map.h\"\n#include \"libspu/core/context.h\"\n#include \"libspu/device/symbol_table.h\"\n#include \"yacl/link/link.h\"\n\n#include \"engine/datasource/datasource_adaptor_mgr.h\"\n#include \"engine/datasource/router.h\"\n#include \"engine/framework/party_info.h\"\n#include \"engine/framework/tensor_table.h\"\n#include \"engine/util/logging.h\"\n#include \"engine/util/progress_util.h\"\n#include \"engine/util/psi/detail_logger.h\"\n\n#include \"api/common.pb.h\"\n#include \"api/engine.pb.h\"\n\nnamespace scql::engine {\n\n// The normal state transition process is:\n//   INITIALIZED -> RUNNING -> COMP_FINISHED -> SUCCEEDED/FAILED\n// When the user manually terminates the query, the transition process will be:\n//   INITIALIZED -> RUNNING -> ABORTING -> FAILED\nenum class SessionState {\n  INITIALIZED = 0,\n  RUNNING = 1,\n  COMP_FINISHED = 2,\n  ABORTING = 3,\n  SUCCEEDED = 4,\n  FAILED = 5\n};\n\npb::JobState ConvertSessionStateToJobState(SessionState state);\n\nstd::string SessionStateToString(SessionState state);\n\nstruct LinkConfig {\n  uint32_t link_recv_timeout_ms = 30 * 1000;  // 30s\n  size_t link_throttle_window_size = 0;\n  size_t link_chunked_send_parallel_size = 8;\n  yacl::link::RetryOptions link_retry_options;\n  size_t http_max_payload_size = 1024 * 1024;  // 1M\n};\n\nstruct PsiConfig {\n  // if the value here is 0, it would use the gflags config instead\n  psi::CurveType psi_curve_type = psi::CURVE_INVALID_TYPE;\n  pb::Rr22Mode rr22_mode = pb::UNDEFINED;\n};\n\nstruct LogConfig {\n  bool enable_session_logger_separation = false;\n};\n\nstruct StreamingOptions {\n  std::filesystem::path dump_file_dir;\n  bool batched = false;\n  // if row num is less than this threshold, close streaming mode and keep all\n  // data in memory\n  size_t streaming_row_num_threshold = 0;\n  // if working in streaming mode, max row num in one batch\n  size_t batch_row_num = 0;\n};\n\nstruct SessionOptions {\n  util::LogOptions log_options;\n  LinkConfig link_config;\n  PsiConfig psi_config;\n  LogConfig log_config;\n  StreamingOptions streaming_options;\n};\n\n/// @brief Session holds everything needed to run the execution plan.\nclass Session {\n public:\n  explicit Session(const SessionOptions& session_opt,\n                   const pb::JobStartParams& params,\n                   pb::DebugOptions debug_opts,\n                   yacl::link::ILinkFactory* link_factory, Router* router,\n                   DatasourceAdaptorMgr* ds_mgr,\n                   const std::vector<spu::ProtocolKind>& allowed_spu_protocols);\n\n  // Used in Python binding, simplified version without link factory\n  explicit Session(const PartyInfo& party_info,\n                   const spu::pb::RuntimeConfig& spu_cfg, Router* router,\n                   DatasourceAdaptorMgr* ds_mgr,\n                   const std::shared_ptr<yacl::link::Context>& link_context);\n\n  ~Session();\n  /// @return session id\n  std::string Id() const { return id_; }\n\n  std::string TimeZone() const { return time_zone_; }\n\n  const std::string& SelfPartyCode() const { return parties_.SelfPartyCode(); }\n\n  size_t SelfRank() const { return parties_.SelfRank(); }\n\n  // each session has its own logger, it may contain session id in each log\n  // message.\n  std::shared_ptr<spdlog::logger> GetLogger() const { return logger_; }\n\n  std::shared_ptr<util::PsiDetailLogger> GetPsiLogger() const {\n    return psi_logger_;\n  }\n\n  Router* GetRouter() const { return router_; }\n\n  DatasourceAdaptorMgr* GetDatasourceAdaptorMgr() const { return ds_mgr_; }\n\n  ssize_t GetPartyRank(const std::string& party_code) const {\n    return parties_.GetRank(party_code);\n  }\n\n  std::shared_ptr<yacl::link::Context> GetLink() const { return lctx_; }\n\n  TensorTable* GetTensorTable() const { return tensor_table_.get(); }\n\n  spu::SPUContext* GetSpuContext() const { return spu_ctx_.get(); }\n\n  spu::device::SymbolTable* GetDeviceSymbols() { return &device_symbols_; }\n\n  SessionState GetState() const { return state_.load(); }\n\n  void SetState(SessionState new_state) { state_.store(new_state); }\n\n  // compare and swap state_ to avoid race condition\n  bool CASState(SessionState old_state, SessionState new_state) {\n    return state_.compare_exchange_strong(old_state, new_state);\n  }\n\n  std::chrono::time_point<std::chrono::system_clock> GetStartTime() const {\n    return start_time_;\n  }\n\n  void SetAffectedRows(int64_t affected_rows) {\n    affected_rows_ = affected_rows;\n  }\n\n  int64_t GetAffectedRows() const { return affected_rows_; }\n\n  std::shared_ptr<engine::util::ProgressStats> GetProgressStats() {\n    if (progres_stats_ == nullptr) {\n      SPDLOG_WARN(\"progress stats is not initialized\");\n      progres_stats_ = std::make_shared<engine::util::DefaultProgressStats>();\n    }\n    return progres_stats_;\n  }\n\n  void InitProgressStats(const ::scql::pb::SchedulingPolicy& policy) {\n    if (policy.pipelines().size() <= 1) {\n      size_t total_nodes_cnt = 0;\n      for (const auto& pipeline : policy.pipelines()) {\n        for (const auto& subdag : pipeline.subdags()) {\n          for (const auto& job : subdag.jobs()) {\n            total_nodes_cnt += job.node_ids().size();\n          }\n        }\n      }\n      progres_stats_ =\n          std::make_shared<engine::util::NormalProgressStats>(total_nodes_cnt);\n    } else {\n      std::vector<size_t> pipeline_nodes_cnt;\n      for (const auto& pipeline : policy.pipelines()) {\n        size_t nodes_cnt = 0;\n        for (const auto& subdag : pipeline.subdags()) {\n          for (const auto& job : subdag.jobs()) {\n            nodes_cnt += job.node_ids().size();\n          }\n        }\n        pipeline_nodes_cnt.push_back(nodes_cnt);\n      }\n      progres_stats_ = std::make_shared<engine::util::BatchedProgressStats>(\n          pipeline_nodes_cnt);\n    }\n  }\n\n  void StorePeerError(const std::string& party_code, const pb::Status& status) {\n    std::lock_guard<std::mutex> guard(peer_error_mutex_);\n    peer_errors_.emplace_back(party_code, status);\n  }\n\n  std::vector<std::pair<std::string, pb::Status>> GetPeerErrors() const {\n    std::lock_guard<std::mutex> guard(peer_error_mutex_);\n    return peer_errors_;\n  }\n\n  void AddPublishResult(std::shared_ptr<pb::Tensor> pb) {\n    publish_results_.emplace_back(std::move(pb));\n  }\n\n  std::vector<std::shared_ptr<pb::Tensor>> GetPublishResults() const {\n    return publish_results_;\n  }\n\n  std::shared_ptr<const yacl::link::Statistics> GetLinkStats() const {\n    return lctx_->GetStats();\n  }\n\n  void MergeDeviceSymbolsFrom(const spu::device::SymbolTable& other);\n\n  TensorPtr StringToHash(const Tensor& string_tensor);\n\n  TensorPtr HashToString(const Tensor& hash_tensor);\n\n  using RefNums = std::vector<std::tuple<std::string, int>>;\n  // set origin ref num\n  void UpdateRefName(const std::vector<std::string>& input_ref_names,\n                     const RefNums& output_ref_nums);\n\n  void DelTensors(const std::vector<std::string>& tensor_names);\n\n  const SessionOptions& GetSessionOptions() const { return session_opt_; }\n\n  StreamingOptions GetStreamingOptions() const {\n    return session_opt_.streaming_options;\n  }\n  void SetStreamingOptions(const StreamingOptions& streaming_options) {\n    session_opt_.streaming_options = streaming_options;\n  }\n  void EnableStreamingBatched();\n\n  std::vector<spu::ProtocolKind> GetAllowedSpuProtocols() const {\n    return allowed_spu_protocols_;\n  }\n\n private:\n  void InitLink();\n  bool ValidateSPUContext();\n  void Negotiate();\n\n  const std::string id_;\n  SessionOptions session_opt_;\n  const std::string time_zone_;\n  PartyInfo parties_;\n  std::atomic<SessionState> state_;\n  std::chrono::time_point<std::chrono::system_clock> start_time_;\n\n  yacl::link::ILinkFactory* link_factory_;\n  std::shared_ptr<spdlog::logger> logger_;  // session's own logger\n  Router* router_;\n  DatasourceAdaptorMgr* ds_mgr_;\n\n  // private (plaintext) tensors\n  std::unique_ptr<TensorTable> tensor_table_;\n\n  std::shared_ptr<yacl::link::Context> lctx_;\n  std::unique_ptr<spu::SPUContext> spu_ctx_;  // SPUContext\n  spu::device::SymbolTable device_symbols_;   // spu device symbols table\n\n  absl::flat_hash_map<size_t, std::string> hash_to_string_values_;\n\n  std::vector<std::shared_ptr<pb::Tensor>> publish_results_;\n  int64_t affected_rows_ = 0;\n\n  mutable std::mutex mutex_;\n  absl::flat_hash_map<std::string, int> tensor_ref_nums_;\n\n  mutable std::mutex peer_error_mutex_;\n  std::vector<std::pair<std::string, pb::Status>> peer_errors_;\n  std::shared_ptr<util::PsiDetailLogger> psi_logger_ = nullptr;\n  pb::DebugOptions debug_opts_;\n\n  const std::vector<spu::ProtocolKind> allowed_spu_protocols_;\n\n  // for progress exposure\n  std::atomic_int32_t nodes_count_ = -1;\n  std::atomic_int32_t executed_nodes_ = -1;\n  mutable std::mutex progress_mutex_;\n  std::string current_node_name_;\n  std::chrono::time_point<std::chrono::system_clock> node_start_time_;\n  std::shared_ptr<engine::util::ProgressStats> progres_stats_;\n};\n\nstd::shared_ptr<spdlog::logger> ActiveLogger(const Session* session);\n\nsize_t CryptoHash(const std::string& str);\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/framework/session_manager.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/framework/session_manager.h\"\n\n#include <memory>\n#include <thread>\n#include <utility>\n\n#include \"engine/exe/flags.h\"\n#include \"engine/framework/session.h\"\n#include \"engine/util/trace_categories.h\"\n\n#ifndef DISABLE_TCMALLOC\n#include \"gperftools/malloc_extension.h\"\n#endif\n\nDEFINE_int32(psi_curve_type, psi::CURVE_FOURQ, \"curve type used in PSI\");\nDEFINE_bool(disable_release_mem_to_sys_actively, false,\n            \"default false, release memory to \"\n            \"system when no session is \"\n            \"running\");\nnamespace scql::engine {\nSessionManager::SessionManager(\n    SessionOptions session_opt, ListenerManager* listener_manager,\n    std::unique_ptr<yacl::link::ILinkFactory> link_factory,\n    std::unique_ptr<Router> ds_router,\n    std::unique_ptr<DatasourceAdaptorMgr> ds_mgr, int32_t session_timeout_s,\n    const std::vector<spu::ProtocolKind>& allowed_spu_protocols)\n    : session_opt_(std::move(session_opt)),\n      listener_manager_(listener_manager),\n      link_factory_(std::move(link_factory)),\n      ds_router_(std::move(ds_router)),\n      ds_mgr_(std::move(ds_mgr)),\n      session_default_timeout_s_(session_timeout_s),\n      allowed_spu_protocols_(allowed_spu_protocols) {\n  watch_thread_.reset(\n      new std::thread([this]() { this->WatchSessionTimeoutThread(); }));\n}\n\nSessionManager::~SessionManager() {\n  if (watch_thread_) {\n    {\n      std::unique_lock<std::mutex> lock(mutex_);\n      to_stop_ = true;\n    }\n    cv_stop_.notify_one();\n    SPDLOG_INFO(\"session manager notify watch thread to stop\");\n    try {\n      watch_thread_->join();\n      SPDLOG_INFO(\"session manager joined the watch thread\");\n    } catch (std::exception& ex) {\n      SPDLOG_ERROR(\"session manager wait watch thread failed, err={}\",\n                   ex.what());\n    }\n  }\n}\n\nscql::engine::SessionOptions SessionManager::GenerateUpdatedSessionOptions(\n    const pb::JobStartParams& job_params) {\n  struct SessionOptions session_opt = session_opt_;\n  // to make the config unit consistent, here to use second instead of\n  // miliseconds\n  if (job_params.link_cfg().link_recv_timeout_sec() > 0) {\n    session_opt.link_config.link_recv_timeout_ms =\n        job_params.link_cfg().link_recv_timeout_sec() * 1000;\n  }\n\n  if (job_params.link_cfg().link_throttle_window_size() > 0) {\n    session_opt.link_config.link_throttle_window_size =\n        job_params.link_cfg().link_throttle_window_size();\n  }\n\n  if (job_params.link_cfg().link_chunked_send_parallel_size() > 0) {\n    session_opt.link_config.link_chunked_send_parallel_size =\n        job_params.link_cfg().link_chunked_send_parallel_size();\n  }\n\n  if (job_params.link_cfg().http_max_payload_size() > 0) {\n    session_opt.link_config.http_max_payload_size =\n        job_params.link_cfg().http_max_payload_size();\n  }\n\n  if (job_params.psi_cfg().psi_curve_type() > 0) {\n    session_opt.psi_config.psi_curve_type =\n        static_cast<psi::CurveType>(job_params.psi_cfg().psi_curve_type());\n  } else {\n    session_opt.psi_config.psi_curve_type =\n        static_cast<psi::CurveType>(FLAGS_psi_curve_type);\n  }\n\n  session_opt.log_config.enable_session_logger_separation =\n      job_params.log_cfg().enable_session_logger_separation();\n\n  if (job_params.psi_cfg().rr22_mode() > 0) {\n    session_opt.psi_config.rr22_mode = job_params.psi_cfg().rr22_mode();\n  } else {\n    session_opt.psi_config.rr22_mode =\n        static_cast<pb::Rr22Mode>(FLAGS_rr22_mode);\n  }\n\n  return session_opt;\n}\n\nvoid SessionManager::CreateSession(const pb::JobStartParams& params,\n                                   const pb::DebugOptions& debug_opts) {\n  const std::string& job_id = params.job_id();\n  TRACE_EVENT_DEFAULT_TRACK(\n      OTHER_CATEGORY,\n      ::perfetto::DynamicString(fmt::format(\"CreateSession: {}\", job_id)));\n  YACL_ENFORCE(!job_id.empty(), \"job_id is empty.\");\n\n  auto session_opt = GenerateUpdatedSessionOptions(params);\n\n  auto new_session = std::make_unique<Session>(\n      session_opt, params, debug_opts, link_factory_.get(), ds_router_.get(),\n      ds_mgr_.get(), allowed_spu_protocols_);\n  {\n    std::unique_lock<std::mutex> lock(mutex_);\n    if (id_to_session_.find(job_id) != id_to_session_.end()) {\n      YACL_THROW_LOGIC_ERROR(\"Session for job_id={} exists.\", job_id);\n    }\n\n    auto end = std::chrono::system_clock::now();\n    auto time_cost = std::chrono::duration_cast<std::chrono::milliseconds>(\n                         end - new_session->GetStartTime())\n                         .count();\n\n    id_to_session_.emplace(job_id, std::move(new_session));\n\n    session_timeout_queue_.push(job_id);\n\n    SPDLOG_INFO(\n        \"create session({}) succ, cost({}ms), current running session={}\",\n        job_id, time_cost, id_to_session_.size());\n  }\n}\n\nSession* SessionManager::GetSession(const std::string& session_id) {\n  if (session_id.empty()) {\n    SPDLOG_WARN(\"session_id is empty, default return nullptr.\");\n    return nullptr;\n  }\n  std::unique_lock<std::mutex> lock(mutex_);\n  auto iter = id_to_session_.find(session_id);\n  if (iter == id_to_session_.end()) {\n    SPDLOG_WARN(\"session({}) not exists. default return nullptr.\", session_id);\n    return nullptr;\n  }\n\n  return iter->second.get();\n}\n\nvoid SessionManager::StopSession(const std::string& session_id) {\n  TRACE_EVENT_DEFAULT_TRACK(\n      OTHER_CATEGORY,\n      ::perfetto::DynamicString(fmt::format(\"StopSession: {}\", session_id)));\n  if (session_id.empty()) {\n    SPDLOG_WARN(\"session_id is empty.\");\n    return;\n  }\n\n  std::unique_lock<std::mutex> lock(mutex_);\n  auto iter = id_to_session_.find(session_id);\n  lock.unlock();\n\n  if (iter == id_to_session_.end()) {\n    SPDLOG_WARN(\"session({}) not exists.\", session_id);\n    return;\n  }\n\n  if (iter->second->GetState() == SessionState::RUNNING) {\n    // CAS to avoid RunPlanSync setting state concurrently\n    if (iter->second->CASState(SessionState::RUNNING, SessionState::ABORTING)) {\n      iter->second->GetLink()->AbortLink();\n    }\n  }\n\n  SPDLOG_INFO(\"session({}) is stopping, waiting for task finish...\",\n              session_id);\n}\n\nvoid SessionManager::RemoveSession(const std::string& session_id) {\n  TRACE_EVENT_DEFAULT_TRACK(\n      OTHER_CATEGORY,\n      ::perfetto::DynamicString(fmt::format(\"RemoveSession: {}\", session_id)));\n  if (session_id.empty()) {\n    SPDLOG_WARN(\"session_id is empty.\");\n    return;\n  }\n\n  {\n    std::unique_lock<std::mutex> lock(mutex_);\n\n    auto iter = id_to_session_.find(session_id);\n    if (iter == id_to_session_.end()) {\n      SPDLOG_WARN(\"session({}) not exists.\", session_id);\n      return;\n    }\n\n    auto session_state = iter->second->GetState();\n\n    if (session_state != SessionState::FAILED &&\n        session_state != SessionState::SUCCEEDED) {\n      YACL_THROW_LOGIC_ERROR(\n          \"session({}), status({}) not belong to FAILED/SUCCEEDED, so can't \"\n          \"remove.\",\n          session_id, SessionStateToString(session_state));\n    }\n\n    auto node_handle = id_to_session_.extract(iter);\n#ifndef DISABLE_TCMALLOC\n    if (id_to_session_.empty() && !FLAGS_disable_release_mem_to_sys_actively) {\n      MallocExtension::instance()->ReleaseFreeMemory();\n    }\n#endif\n\n    // unlock in time, since the following WaitLinkTaskFinish() may take a\n    // while to run\n    lock.unlock();\n\n    auto end = std::chrono::system_clock::now();\n    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(\n        end - node_handle.mapped()->GetStartTime());\n    SPDLOG_INFO(\n        \"session({}) removed, running_cost({}ms), current running session={}\",\n        session_id, duration.count(), id_to_session_.size());\n  }\n\n  listener_manager_->RemoveListener(session_id);\n}\n\nbool SessionManager::SetSessionState(const std::string& session_id,\n                                     SessionState state) {\n  std::unique_lock<std::mutex> lock(mutex_);\n  auto iter = id_to_session_.find(session_id);\n  if (iter == id_to_session_.end()) {\n    SPDLOG_WARN(\"session({}) not exists.\", session_id);\n    return false;\n  }\n\n  iter->second->SetState(state);\n  SPDLOG_INFO(\"session({}), set state={}\", session_id,\n              SessionStateToString(state));\n  return true;\n}\n\nbool SessionManager::CompareAndSetState(const std::string& session_id,\n                                        SessionState expected_state,\n                                        SessionState desired_state) {\n  if (session_id.empty()) {\n    SPDLOG_WARN(\"session_id is empty, cannot perform CAS state.\");\n    return false;\n  }\n\n  std::unique_lock<std::mutex> lock(mutex_);\n  auto iter = id_to_session_.find(session_id);\n  if (iter == id_to_session_.end()) {\n    SPDLOG_WARN(\"session({}) not exists, cannot perform CAS state.\",\n                session_id);\n    return false;\n  }\n\n  Session* session = iter->second.get();\n  bool success = session->CASState(expected_state, desired_state);\n\n  if (success) {\n    SPDLOG_INFO(\"session({}), state transitioned from {} to {} successfully.\",\n                session_id, SessionStateToString(expected_state),\n                SessionStateToString(desired_state));\n  } else {\n    SPDLOG_WARN(\n        \"session({}), failed to transition state from {} to {}. Current state \"\n        \"was not the expected one.\",\n        session_id, SessionStateToString(expected_state),\n        SessionStateToString(desired_state));\n  }\n\n  return success;\n}\n\nvoid SessionManager::WatchSessionTimeoutThread() {\n  SPDLOG_INFO(\"WatchSessionTimeoutThread startup, session default timeout={}s\",\n              session_default_timeout_s_.count());\n  while (!to_stop_) {\n    // 1.get next check time.\n    auto next_check_time = NextCheckTime();\n\n    // 2.sleep until next check time and break if to_stop_ marked.\n    {\n      std::unique_lock<std::mutex> lock(mutex_);\n\n      while (!to_stop_ && std::chrono::system_clock::now() < next_check_time) {\n        cv_stop_.wait_until(lock, next_check_time);\n      }\n    }\n\n    if (to_stop_) {\n      break;\n    }\n\n    // 3.find one timeout session.\n    std::optional<std::string> timeout_session = GetTimeoutSession();\n\n    using namespace std::chrono_literals;\n    // 4.remove session.\n    if (timeout_session.has_value()) {\n      try {\n        RemoveSession(timeout_session.value());\n        SPDLOG_WARN(\"[TIMEOUT] session({}) removed due to timeout\",\n                    timeout_session.value());\n      } catch (std::exception& ex) {\n        SPDLOG_WARN(\n            \"[TIMEOUT] remove session({}) failed, err={}, sleep 60s before \"\n            \"retry\",\n            timeout_session.value(), ex.what());\n        std::this_thread::sleep_for(60s);\n      }\n    }\n  }\n  SPDLOG_INFO(\"Watch thread stopped.\");\n}\n\nstd::chrono::time_point<std::chrono::system_clock>\nSessionManager::NextCheckTime() {\n  // set default-check-interval to 60s empirically to avoid growth of\n  // session_timeout_queue_.\n  auto default_check_interval =\n      std::min(session_default_timeout_s_, std::chrono::seconds(60));\n  auto result = std::chrono::system_clock::now() + default_check_interval;\n  std::unique_lock<std::mutex> lock(mutex_);\n  while (!session_timeout_queue_.empty()) {\n    const auto& session = session_timeout_queue_.front();\n    auto iter = id_to_session_.find(session);\n    if (iter == id_to_session_.end()) {\n      session_timeout_queue_.pop();\n    } else {\n      return std::min(\n          result, iter->second->GetStartTime() + session_default_timeout_s_);\n    }\n  }\n\n  return result;\n}\n\nstd::optional<std::string> SessionManager::GetTimeoutSession() {\n  auto now = std::chrono::system_clock::now();\n  std::unique_lock<std::mutex> lock(mutex_);\n  while (!session_timeout_queue_.empty()) {\n    const auto& session = session_timeout_queue_.front();\n    auto iter = id_to_session_.find(session);\n    if (iter == id_to_session_.end()) {\n      session_timeout_queue_.pop();\n      continue;\n    }\n\n    if (iter->second->GetStartTime() + session_default_timeout_s_ <= now) {\n      return session;\n    } else {\n      return std::nullopt;\n    }\n  }\n\n  return std::nullopt;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/framework/session_manager.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <chrono>\n#include <mutex>\n#include <optional>\n#include <queue>\n#include <thread>\n\n#include \"engine/datasource/datasource_adaptor_mgr.h\"\n#include \"engine/datasource/router.h\"\n#include \"engine/framework/session.h\"\n#include \"engine/link/listener.h\"\n\nnamespace scql::engine {\n\nclass SessionManager {\n public:\n  SessionManager(SessionOptions session_opt, ListenerManager* listener_manager,\n                 std::unique_ptr<yacl::link::ILinkFactory> link_factory,\n                 std::unique_ptr<Router> ds_router,\n                 std::unique_ptr<DatasourceAdaptorMgr> ds_mgr,\n                 int32_t session_timeout_s,\n                 const std::vector<spu::ProtocolKind>& allowed_spu_protocols);\n\n  ~SessionManager();\n\n  SessionManager(const SessionManager&) = delete;\n  SessionManager& operator=(const SessionManager&) = delete;\n\n  void CreateSession(const pb::JobStartParams& params,\n                     const pb::DebugOptions& debug_opts);\n\n  Session* GetSession(const std::string& session_id);\n\n  void StopSession(const std::string& session_id);\n\n  void RemoveSession(const std::string& session_id);\n\n  // Set Session state\n  // return false if session not found\n  bool SetSessionState(const std::string& session_id, SessionState dest_state);\n\n  // This method atomically transitions the session state from an expected state\n  // to a desired state. It will fail if the session's current state is not\n  // equal to the expected state.\n  bool CompareAndSetState(const std::string& session_id,\n                          SessionState expected_state,\n                          SessionState desired_state);\n\n private:\n  void WatchSessionTimeoutThread();\n\n  std::chrono::time_point<std::chrono::system_clock> NextCheckTime();\n\n  std::optional<std::string> GetTimeoutSession();\n\n  scql::engine::SessionOptions GenerateUpdatedSessionOptions(\n      const pb::JobStartParams& job_params);\n\n private:\n  // used to construct session\n  const SessionOptions session_opt_;\n  ListenerManager* listener_manager_;\n  std::unique_ptr<yacl::link::ILinkFactory> link_factory_;\n  std::unique_ptr<Router> ds_router_;\n  std::unique_ptr<DatasourceAdaptorMgr> ds_mgr_;\n  mutable std::mutex mutex_;\n  std::map<std::string, std::unique_ptr<Session>> id_to_session_;\n\n  // variables for session TTL management.\n  std::chrono::seconds session_default_timeout_s_;\n  std::condition_variable cv_stop_;\n  std::atomic<bool> to_stop_{false};\n  std::unique_ptr<std::thread> watch_thread_;\n  std::queue<std::string> session_timeout_queue_;\n  const std::vector<spu::ProtocolKind> allowed_spu_protocols_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/framework/session_manager_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/framework/session_manager.h\"\n\n#include <future>\n#include <memory>\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/framework/session.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine {\n\nclass TestFactory : public yacl::link::ILinkFactory {\n public:\n  explicit TestFactory(ListenerManager* listener_manager)\n      : listener_manager_(listener_manager) {}\n\n  std::shared_ptr<yacl::link::Context> CreateContext(\n      const yacl::link::ContextDesc& desc, size_t self_rank) override {\n    auto listener = std::make_shared<Listener>();\n    listener_manager_->AddListener(desc.id, listener);\n    return mem_link_factory_.CreateContext(desc, self_rank);\n  }\n\n private:\n  ListenerManager* listener_manager_;\n  static yacl::link::FactoryMem mem_link_factory_;\n};\n\nyacl::link::FactoryMem TestFactory::mem_link_factory_;\n\nclass SessionManagerTest : public ::testing::Test {\n protected:\n  void SetUp() override {\n    factory = std::make_unique<TestFactory>(&listener_manager);\n    EXPECT_NE(nullptr, factory.get());\n    SessionOptions options;\n    std::vector<spu::ProtocolKind> allowed_spu_protocols = {\n        spu::ProtocolKind::SEMI2K, spu::ProtocolKind::CHEETAH};\n    mgr = std::make_unique<SessionManager>(options, &listener_manager,\n                                           std::move(factory), nullptr, nullptr,\n                                           1, allowed_spu_protocols);\n    EXPECT_NE(nullptr, mgr.get());\n  }\n\n public:\n  ListenerManager listener_manager;\n  std::unique_ptr<TestFactory> factory;\n  std::unique_ptr<SessionManager> mgr;\n};\n\nTEST_F(SessionManagerTest, Works) {\n  // Given\n  std::string session_id = \"session_id\";\n  pb::JobStartParams params;\n  {\n    params.set_job_id(session_id);\n\n    params.set_party_code(op::test::kPartyAlice);\n    auto* alice = params.add_parties();\n    alice->CopyFrom(op::test::BuildParty(op::test::kPartyAlice, 0));\n\n    params.mutable_spu_runtime_cfg()->CopyFrom(\n        op::test::MakeSpuRuntimeConfigForTest(spu::ProtocolKind::SEMI2K)\n            .ToProto());\n  }\n  pb::DebugOptions debug_opts;\n  // When\n  EXPECT_NO_THROW(mgr->CreateSession(params, debug_opts));\n  // Then\n  EXPECT_NE(nullptr, listener_manager.GetListener(session_id));\n  // duplicate creation error.\n  EXPECT_THROW(mgr->CreateSession(params, debug_opts), ::yacl::LogicError);\n  // GetSession.\n  EXPECT_EQ(nullptr, mgr->GetSession(\"not exist session_id\"));\n  Session* session = nullptr;\n  EXPECT_NO_THROW(session = mgr->GetSession(session_id));\n  EXPECT_NE(nullptr, session);\n  // SetSessionState\n  EXPECT_TRUE(mgr->SetSessionState(session_id, SessionState::INITIALIZED));\n  EXPECT_TRUE(mgr->SetSessionState(session_id, SessionState::RUNNING));\n  // StopSession/RemoveSession\n  EXPECT_THROW(mgr->RemoveSession(session_id), ::yacl::LogicError);\n  EXPECT_NO_THROW(mgr->StopSession(session_id));\n  EXPECT_TRUE(mgr->SetSessionState(session_id, SessionState::FAILED));\n  EXPECT_NO_THROW(mgr->RemoveSession(session_id));\n  EXPECT_EQ(nullptr, listener_manager.GetListener(session_id));\n\n  // test timeout.\n  session_id = session_id + \"_timeout\";\n  params.set_job_id(session_id);\n  EXPECT_NO_THROW(mgr->CreateSession(params, debug_opts));\n  EXPECT_TRUE(mgr->SetSessionState(session_id, SessionState::SUCCEEDED));\n  EXPECT_NE(nullptr, listener_manager.GetListener(session_id));\n  sleep(5);\n  EXPECT_EQ(nullptr, listener_manager.GetListener(session_id));\n}\n\nTEST_F(SessionManagerTest, TestSessionCreation) {\n  pb::JobStartParams common_params;\n  common_params.set_job_id(\"session_multi_pc\");\n  common_params.add_parties()->CopyFrom(\n      op::test::BuildParty(op::test::kPartyAlice, 0));\n  common_params.add_parties()->CopyFrom(\n      op::test::BuildParty(op::test::kPartyBob, 1));\n\n  yacl::link::FactoryMem g_mem_link_factory;\n  SessionOptions options;\n\n  common_params.mutable_spu_runtime_cfg()->CopyFrom(\n      op::test::MakeSpuRuntimeConfigForTest(spu::ProtocolKind::REF2K)\n          .ToProto());\n  auto create_session = [&](const pb::JobStartParams& params) {\n    pb::DebugOptions debug_opts;\n\n    // not allowed to create session with REF2K.\n    std::vector<spu::ProtocolKind> allowed_protocols{spu::ProtocolKind::CHEETAH,\n                                                     spu::ProtocolKind::SEMI2K,\n                                                     spu::ProtocolKind::ABY3};\n    EXPECT_THROW(std::make_shared<Session>(options, params, debug_opts,\n                                           &g_mem_link_factory, nullptr,\n                                           nullptr, allowed_protocols),\n                 ::yacl::EnforceNotMet);\n  };\n\n  std::vector<std::future<void>> futures;\n\n  pb::JobStartParams alice_params;\n  alice_params.CopyFrom(common_params);\n  alice_params.set_party_code(op::test::kPartyAlice);\n  futures.push_back(std::async(create_session, alice_params));\n\n  pb::JobStartParams bob_params;\n  bob_params.CopyFrom(common_params);\n  bob_params.set_party_code(op::test::kPartyBob);\n  futures.push_back(std::async(create_session, bob_params));\n\n  futures[0].get();\n  futures[1].get();\n}\n\nTEST_F(SessionManagerTest, CompareAndSetStateWorks) {\n  // Given\n  std::string session_id = \"test_cas_session\";\n  pb::JobStartParams params;\n  {\n    params.set_job_id(session_id);\n    params.set_party_code(op::test::kPartyAlice);\n    auto* alice = params.add_parties();\n    alice->CopyFrom(op::test::BuildParty(op::test::kPartyAlice, 0));\n    params.mutable_spu_runtime_cfg()->CopyFrom(\n        op::test::MakeSpuRuntimeConfigForTest(spu::ProtocolKind::SEMI2K)\n            .ToProto());\n  }\n  pb::DebugOptions debug_opts;\n\n  // Create session\n  mgr->CreateSession(params, debug_opts);\n  Session* session = mgr->GetSession(session_id);\n  ASSERT_NE(nullptr, session);\n\n  // Test 1: Successful CAS from INITIALIZED to RUNNING\n  EXPECT_TRUE(mgr->CompareAndSetState(session_id, SessionState::INITIALIZED,\n                                      SessionState::RUNNING));\n  EXPECT_EQ(SessionState::RUNNING, session->GetState());\n\n  // Test 2: Failed CAS - wrong expected state\n  EXPECT_FALSE(mgr->CompareAndSetState(session_id, SessionState::INITIALIZED,\n                                       SessionState::COMP_FINISHED));\n  EXPECT_EQ(SessionState::RUNNING, session->GetState());\n\n  // Test 3: Successful CAS from RUNNING to COMP_FINISHED\n  EXPECT_TRUE(mgr->CompareAndSetState(session_id, SessionState::RUNNING,\n                                      SessionState::COMP_FINISHED));\n  EXPECT_EQ(SessionState::COMP_FINISHED, session->GetState());\n\n  // Test 4: Successful CAS from COMP_FINISHED to SUCCEEDED\n  EXPECT_TRUE(mgr->CompareAndSetState(session_id, SessionState::COMP_FINISHED,\n                                      SessionState::SUCCEEDED));\n  EXPECT_EQ(SessionState::SUCCEEDED, session->GetState());\n\n  // Test 5: CAS with non-existent session\n  EXPECT_FALSE(mgr->CompareAndSetState(\"non_existent_session\",\n                                       SessionState::INITIALIZED,\n                                       SessionState::RUNNING));\n\n  // Test 6: CAS with empty session_id\n  EXPECT_FALSE(mgr->CompareAndSetState(\"\", SessionState::INITIALIZED,\n                                       SessionState::RUNNING));\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/framework/tensor_table.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/framework/tensor_table.h\"\n\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine {\n\nvoid TensorTable::AddTensor(const std::string& name,\n                            std::shared_ptr<Tensor> tensor) {\n  std::lock_guard<std::mutex> guard(lock_);\n\n  auto it = tensors_.find(name);\n  if (it != tensors_.end()) {\n    YACL_THROW(\"tensor named \\\"{}\\\" already exists in TensorTable\", name);\n  }\n  tensors_[name] = std::move(tensor);\n}\n\nvoid TensorTable::AddOrUpdateTensor(const std::string& name,\n                                    std::shared_ptr<Tensor> tensor) {\n  std::lock_guard<std::mutex> guard(lock_);\n  tensors_[name] = std::move(tensor);\n}\n\nstd::shared_ptr<Tensor> TensorTable::GetTensor(const std::string& name) const {\n  std::lock_guard<std::mutex> guard(lock_);\n\n  auto it = tensors_.find(name);\n  if (it != tensors_.end()) {\n    return it->second;\n  }\n  return nullptr;\n}\n\nvoid TensorTable::RemoveTensor(const std::string& name) {\n  std::lock_guard<std::mutex> guard(lock_);\n  tensors_.erase(name);\n}\n\nvoid TensorTable::Clear() {\n  std::lock_guard<std::mutex> guard(lock_);\n  tensors_.clear();\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/framework/tensor_table.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n#include <mutex>\n#include <unordered_map>\n\n#include \"engine/core/tensor.h\"\n\nnamespace scql::engine {\n\nclass TensorTable {\n public:\n  // check tensor not existing before inserting to tensor table\n  void AddTensor(const std::string& name, std::shared_ptr<Tensor> tensor);\n\n  // insert to tensor table without checking\n  void AddOrUpdateTensor(const std::string& name,\n                         std::shared_ptr<Tensor> tensor);\n\n  std::shared_ptr<Tensor> GetTensor(const std::string& name) const;\n\n  void RemoveTensor(const std::string& name);\n\n  void Clear();\n\n private:\n  mutable std::mutex lock_;\n  std::unordered_map<std::string, std::shared_ptr<Tensor>> tensors_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/link/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nproto_library(\n    name = \"mux_receiver_proto\",\n    srcs = [\"mux_receiver.proto\"],\n)\n\ncc_proto_library(\n    name = \"mux_receiver_cc_proto\",\n    deps = [\":mux_receiver_proto\"],\n)\n\ncc_library(\n    name = \"channel_manager\",\n    srcs = [\"channel_manager.cc\"],\n    hdrs = [\"channel_manager.h\"],\n    deps = [\n        \"@abseil-cpp//absl/strings\",\n        \"@brpc\",\n        \"@spdlog\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"rpc_helper\",\n    srcs = [\"rpc_helper.cc\"],\n    hdrs = [\"rpc_helper.h\"],\n    deps = [\n        \":mux_receiver_cc_proto\",\n        \"@brpc\",\n        \"@spdlog\",\n    ],\n)\n\nscql_cc_test(\n    name = \"rpc_helper_test\",\n    srcs = [\"rpc_helper_test.cc\"],\n    deps = [\n        \":rpc_helper\",\n    ],\n)\n\ncc_library(\n    name = \"listener\",\n    srcs = [\"listener.cc\"],\n    hdrs = [\"listener.h\"],\n    deps = [\n        \":mux_receiver_cc_proto\",\n        \"@yacl//yacl/link/transport:channel\",\n    ],\n)\n\nscql_cc_test(\n    name = \"listener_test\",\n    srcs = [\"listener_test.cc\"],\n    # add -lm for channel_mem\n    linkopts = [\"-lm\"],\n    deps = [\n        \":listener\",\n        \"@yacl//yacl/link/transport:channel_mem\",\n    ],\n)\n\ncc_library(\n    name = \"mux_receiver_service\",\n    srcs = [\"mux_receiver_service.cc\"],\n    hdrs = [\"mux_receiver_service.h\"],\n    deps = [\n        \":listener\",\n        \":mux_receiver_cc_proto\",\n        \"@brpc\",\n    ],\n)\n\nscql_cc_test(\n    name = \"mux_receiver_service_test\",\n    srcs = [\"mux_receiver_service_test.cc\"],\n    env = {\n        \"ASAN_OPTIONS\": \"detect_leaks=0\",\n    },\n    deps = [\n        \":mux_link_factory\",\n        \":mux_receiver_service\",\n        \"@yacl//yacl/link\",\n    ],\n)\n\ncc_library(\n    name = \"mux_link_factory\",\n    srcs = [\"mux_link_factory.cc\"],\n    hdrs = [\"mux_link_factory.h\"],\n    deps = [\n        \":channel_manager\",\n        \":listener\",\n        \":mux_receiver_cc_proto\",\n        \"@brpc\",\n        \"@yacl//yacl/link:factory\",\n    ],\n)\n\n# FIXME(shunde.csd): Add mux_link_factory_test back\n# scql_cc_test(\n#     name = \"mux_link_factory_test\",\n#     srcs = [\"mux_link_factory_test.cc\"],\n#     deps = [\n#         \":mux_link_factory\",\n#\n#     ],\n# )\n"
  },
  {
    "path": "engine/link/channel_manager.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/link/channel_manager.h\"\n\n#include \"absl/strings/match.h\"\n#include \"spdlog/spdlog.h\"\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine {\n\nvoid ChannelManager::AddChannelOptions(const RemoteRole role,\n                                       const ChannelOptions& options) {\n  auto iter = options_.find(role);\n  if (iter != options_.end()) {\n    YACL_THROW_LOGIC_ERROR(\"options already exist for role={}\",\n                           static_cast<int>(role));\n  }\n  options_.emplace(role, options);\n}\n\nstd::shared_ptr<google::protobuf::RpcChannel> ChannelManager::Create(\n    const std::shared_ptr<spdlog::logger>& logger,\n    const std::string& remote_addr, RemoteRole role) {\n  ChannelOptions options;\n  auto iter = options_.find(role);\n  if (iter != options_.end()) {\n    options = iter->second;\n  } else {\n    SPDLOG_LOGGER_WARN(\n        logger, \"not found options for role={}, default use http protocol\",\n        static_cast<int>(role));\n    options.brpc_options.protocol = \"http:proto\";\n  }\n  auto result = std::make_shared<brpc::Channel>();\n  auto addr = remote_addr;\n  // add \"http://\" prefix if protocol is http:proto/http or load balancer is not\n  // empty\n  // reference:\n  // https://github.com/apache/brpc/pull/1973/files#diff-2a8e66afb2c4f2cbc0c9d5dca8180a1f9ef53b0d4ce8649bd64ee602fec44165R430\n  bool need_prefix_for_http =\n      std::string(options.brpc_options.protocol.name()) == \"http:proto\" ||\n      std::string(options.brpc_options.protocol.name()) == \"http\" ||\n      std::string(options.brpc_options.protocol.name()) == \"http:json\" ||\n      options.load_balancer != \"\";\n  if (need_prefix_for_http && !absl::StartsWith(addr, \"http://\") &&\n      !absl::StartsWith(addr, \"https://\")) {\n    addr = absl::StrCat(\"http://\", addr);\n  }\n  int init_result = result->Init(addr.c_str(), options.load_balancer.c_str(),\n                                 &(options.brpc_options));\n  if (init_result != 0) {\n    YACL_THROW(\n        \"BrpcChannel Init failed, ret={}, remote_addr={}, load_balancer={}, \"\n        \"role={}, protocol={}\",\n        init_result, addr, static_cast<int>(role), options.load_balancer,\n        options.brpc_options.protocol.name());\n  }\n  return result;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/link/channel_manager.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n\n#include \"brpc/channel.h\"\n#include \"spdlog/logger.h\"\n\nnamespace scql::engine {\n\nenum class RemoteRole {\n  Invalid = 0,\n  PeerEngine = 1,\n  Driver = 2,  // Driver could be SCQLBroker for now\n};\n\n// A wrapper for brpc channel options\nstruct ChannelOptions {\n  brpc::ChannelOptions brpc_options;\n  std::string load_balancer;\n};\n\nclass ChannelManager {\n public:\n  void AddChannelOptions(RemoteRole role, const ChannelOptions& options);\n\n  std::shared_ptr<google::protobuf::RpcChannel> Create(\n      const std::shared_ptr<spdlog::logger>& logger,\n      const std::string& remote_addr, RemoteRole role);\n\n private:\n  std::map<RemoteRole, ChannelOptions> options_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/link/listener.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/link/listener.h\"\n\n#include \"spdlog/spdlog.h\"\n\nnamespace scql::engine {\n\nvoid Listener::AddChannel(\n    size_t rank, std::shared_ptr<yacl::link::transport::Channel> channel) {\n  YACL_ENFORCE(channel, \"add channel failed, channel can't be nullptr.\");\n  YACL_ENFORCE(channels_.count(rank) == 0,\n               \"add channel failed, rank={} exists before add.\", rank);\n  channels_.emplace(rank, channel);\n}\n\nvoid Listener::OnRequest(size_t rank, const link::pb::MuxPushRequest* request,\n                         link::pb::MuxPushResponse* response) {\n  auto iter = channels_.find(rank);\n  YACL_ENFORCE(iter != channels_.end(), \"channel for rank:{} not exist\", rank);\n  YACL_ENFORCE(iter->second, \"channel for rank:{} is nullptr\", rank);\n  iter->second->OnRequest(*request, response);\n}\n\nvoid ListenerManager::AddListener(const std::string& link_id,\n                                  std::shared_ptr<Listener> listener) {\n  std::unique_lock lock(mutex_);\n  if (listeners_.count(link_id) != 0) {\n    YACL_THROW_LOGIC_ERROR(\"link_id:{} exist before add Listener.\", link_id);\n  }\n  listeners_.emplace(link_id, listener);\n}\n\nvoid ListenerManager::RemoveListener(const std::string& link_id) {\n  std::unique_lock lock(mutex_);\n  if (listeners_.count(link_id) == 0) {\n    SPDLOG_WARN(\"link_id:{} not exist before remove Listener.\", link_id);\n    return;\n  }\n  listeners_.erase(link_id);\n}\n\nstd::shared_ptr<Listener> ListenerManager::GetListener(\n    const std::string& link_id) {\n  std::shared_lock lock(mutex_);\n  auto iter = listeners_.find(link_id);\n  if (iter == listeners_.end()) {\n    SPDLOG_WARN(\"Listener for link_id:{} not exist.\", link_id);\n    return nullptr;\n  }\n  return iter->second;\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/link/listener.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <shared_mutex>\n\n#include \"yacl/link/transport/channel.h\"\n\n#include \"engine/link/mux_receiver.pb.h\"\n\nnamespace scql::engine {\n\n// Listener contains the Channels belong to the same Context.\nclass Listener {\n public:\n  Listener() = default;\n\n  ~Listener() = default;\n\n  void AddChannel(size_t rank,\n                  std::shared_ptr<yacl::link::transport::Channel> channel);\n\n  void OnRequest(size_t rank, const link::pb::MuxPushRequest* request,\n                 link::pb::MuxPushResponse* response);\n\n private:\n  std::map<size_t, std::shared_ptr<yacl::link::transport::Channel>> channels_;\n};\n\n// thread safe, and will be used concurrently.\nclass ListenerManager {\n public:\n  ListenerManager() = default;\n\n  ~ListenerManager() = default;\n\n  void AddListener(const std::string& link_id,\n                   std::shared_ptr<Listener> listener);\n\n  void RemoveListener(const std::string& link_id);\n\n  std::shared_ptr<Listener> GetListener(const std::string& link_id);\n\n private:\n  std::shared_mutex mutex_;\n  std::map<std::string, std::shared_ptr<Listener>> listeners_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/link/listener_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/link/listener.h\"\n\n#include \"gtest/gtest.h\"\n\nnamespace scql::engine {\n\nTEST(ListenerManagerTest, works) {\n  // Given\n  auto listener = std::make_shared<Listener>();\n  ListenerManager mgr;\n  std::string link_id = \"test-link-id\";\n  std::string not_exist_link_id = \"not-exist-link-id\";\n\n  // When\n  EXPECT_NO_THROW(mgr.AddListener(link_id, listener));\n  // Then\n  EXPECT_THROW(mgr.AddListener(link_id, listener), ::yacl::LogicError);\n  EXPECT_EQ(nullptr, mgr.GetListener(not_exist_link_id));\n  EXPECT_NE(nullptr, mgr.GetListener(link_id));\n\n  // When\n  mgr.RemoveListener(link_id);\n  // Then\n  EXPECT_EQ(nullptr, mgr.GetListener(link_id));\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/link/mux_link_factory.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/link/mux_link_factory.h\"\n\n#include \"brpc/controller.h\"\n#include \"spdlog/spdlog.h\"\n\nnamespace scql::engine {\n\n// NOTE: Throw NetworkError for ErrorCode::LINKID_NOT_FOUND:\n// since peer's Context corresponding to link_id_ may be available later,\n// while ConnectToMesh() in lib-yacl only catch NetworkError and\n// retry.\n#ifndef THROW_IF_RPC_NOT_OK\n#define THROW_IF_RPC_NOT_OK(cntl, response, request_info)                     \\\n  do {                                                                        \\\n    if ((cntl).Failed()) {                                                    \\\n      if ((cntl).ErrorCode() == brpc::EHTTP) {                                \\\n        YACL_THROW_LINK_ERROR(                                                \\\n            0, (cntl).http_response().status_code(),                          \\\n            \"send failed: {}, http code={}, message={}.\", request_info,       \\\n            static_cast<int>((cntl).http_response().status_code()),           \\\n            (cntl).ErrorText());                                              \\\n      }                                                                       \\\n      YACL_THROW_LINK_ERROR((cntl).ErrorCode(), 0,                            \\\n                            \"send failed: {}, rpc failed={}, message={}.\",    \\\n                            request_info, (cntl).ErrorCode(),                 \\\n                            (cntl).ErrorText());                              \\\n    } else if ((response).error_code() != link::pb::ErrorCode::SUCCESS) {     \\\n      std::string error_info = fmt::format(                                   \\\n          \"send failed: {}, peer failed code={}, message={}.\", request_info,  \\\n          static_cast<int>((response).error_code()), (response).error_msg()); \\\n      if ((response).error_code() == link::pb::ErrorCode::LINKID_NOT_FOUND) { \\\n        YACL_THROW_NETWORK_ERROR(\"{}\", error_info);                           \\\n      }                                                                       \\\n      YACL_THROW(\"{}\", error_info);                                           \\\n    }                                                                         \\\n  } while (false)\n#endif\n\nstd::shared_ptr<yacl::link::Context> MuxLinkFactory::CreateContext(\n    const yacl::link::ContextDesc& desc, size_t self_rank) {\n  const size_t world_size = desc.parties.size();\n  YACL_ENFORCE(self_rank < world_size,\n               \"invalid arg: self rank={} not small than world_size={}\",\n               self_rank, world_size);\n  // 1. create channels.\n  std::vector<std::shared_ptr<yacl::link::transport::IChannel>> channels(\n      world_size);\n  auto listener = std::make_shared<Listener>();\n  for (size_t rank = 0; rank < world_size; rank++) {\n    if (rank == self_rank) {\n      continue;\n    }\n    const auto& peer_host = desc.parties[rank].host;\n    auto rpc_channel = channel_manager_->Create(\n        spdlog::default_logger(), peer_host, RemoteRole::PeerEngine);\n    YACL_ENFORCE(rpc_channel, \"create rpc channel failed for rank={}\", rank);\n    auto link = std::make_shared<MuxLink>(\n        self_rank, rank, desc.http_max_payload_size, desc.id, rpc_channel);\n\n    auto link_channel = std::make_shared<yacl::link::transport::Channel>(\n        link, desc.recv_timeout_ms, false, desc.retry_opts);\n    channels[rank] = link_channel;\n    listener->AddChannel(rank, link_channel);\n  }\n  listener_manager_->AddListener(desc.id, listener);\n  // 3. construct Context.\n  auto ctx = std::make_shared<yacl::link::Context>(\n      desc, self_rank, std::move(channels), nullptr, false);\n  return ctx;\n}\n\nsize_t MuxLink::GetMaxBytesPerChunk() const { return http_max_payload_size_; }\n\nvoid MuxLink::SetMaxBytesPerChunk(size_t bytes) {\n  http_max_payload_size_ = bytes;\n}\n\nstd::unique_ptr<::google::protobuf::Message> MuxLink::PackMonoRequest(\n    const std::string& key, yacl::ByteContainerView value) const {\n  auto request = std::make_unique<link::pb::MuxPushRequest>();\n  {\n    request->set_link_id(link_id_);\n    auto* msg = request->mutable_msg();\n    msg->set_sender_rank(self_rank_);\n    msg->set_key(key);\n    msg->set_value(value.data(), value.size());\n    msg->set_trans_type(link::pb::TransType::MONO);\n  }\n  return request;\n}\n\nstd::unique_ptr<::google::protobuf::Message> MuxLink::PackChunkedRequest(\n    const std::string& key, yacl::ByteContainerView value, size_t offset,\n    size_t total_length) const {\n  auto request = std::make_unique<link::pb::MuxPushRequest>();\n  {\n    request->set_link_id(link_id_);\n    auto* msg = request->mutable_msg();\n    msg->set_sender_rank(self_rank_);\n    msg->set_key(key);\n    msg->set_value(value.data(), value.size());\n    msg->set_trans_type(link::pb::TransType::CHUNKED);\n    msg->mutable_chunk_info()->set_chunk_offset(offset);\n    msg->mutable_chunk_info()->set_message_length(total_length);\n  }\n  return request;\n}\n\nvoid MuxLink::UnpackMonoRequest(const ::google::protobuf::Message& request,\n                                std::string* key,\n                                yacl::ByteContainerView* value) const {\n  const auto* real_request =\n      static_cast<const link::pb::MuxPushRequest*>(&request);\n  *key = real_request->msg().key();\n  *value = real_request->msg().value();\n}\n\nvoid MuxLink::UnpackChunckRequest(const ::google::protobuf::Message& request,\n                                  std::string* key,\n                                  yacl::ByteContainerView* value,\n                                  size_t* offset, size_t* total_length) const {\n  const auto* real_request =\n      static_cast<const link::pb::MuxPushRequest*>(&request);\n  *key = real_request->msg().key();\n  *value = real_request->msg().value();\n  *offset = real_request->msg().chunk_info().chunk_offset();\n  *total_length = real_request->msg().chunk_info().message_length();\n}\n\nvoid MuxLink::FillResponseOk(const ::google::protobuf::Message& request,\n                             ::google::protobuf::Message* response) const {\n  auto* real_response = static_cast<link::pb::MuxPushResponse*>(response);\n  real_response->set_error_code(link::pb::ErrorCode::SUCCESS);\n  real_response->set_error_msg(\"\");\n}\n\nvoid MuxLink::FillResponseError(const ::google::protobuf::Message& request,\n                                ::google::protobuf::Message* response) const {\n  auto* real_response = static_cast<link::pb::MuxPushResponse*>(response);\n  const auto* real_request =\n      static_cast<const link::pb::MuxPushRequest*>(&request);\n\n  real_response->set_error_code(link::pb::ErrorCode::INVALID_REQUEST);\n  real_response->set_error_msg(\n      fmt::format(\"Error: trans type={}, from link_id={} rank={}\",\n                  TransType_Name(real_request->msg().trans_type()), link_id_,\n                  real_request->msg().sender_rank()));\n}\n\nbool MuxLink::IsChunkedRequest(\n    const ::google::protobuf::Message& request) const {\n  const auto* real_request =\n      static_cast<const link::pb::MuxPushRequest*>(&request);\n  return real_request->msg().trans_type() == link::pb::TransType::CHUNKED;\n}\n\nbool MuxLink::IsMonoRequest(const ::google::protobuf::Message& request) const {\n  const auto* real_request =\n      static_cast<const link::pb::MuxPushRequest*>(&request);\n  return real_request->msg().trans_type() == link::pb::TransType::MONO;\n}\n\nvoid MuxLink::SendRequest(const ::google::protobuf::Message& request,\n                          uint32_t timeout) const {\n  link::pb::MuxPushResponse response;\n  brpc::Controller cntl;\n  if (timeout != 0) {\n    cntl.set_timeout_ms(timeout);\n  }\n  link::pb::MuxReceiverService::Stub stub(rpc_channel_.get());\n  const auto* push_request =\n      static_cast<const link::pb::MuxPushRequest*>(&request);\n  stub.Push(&cntl, push_request, &response, nullptr);\n\n  std::string request_info =\n      fmt::format(\"link_id={} sender_rank={} send key={}\", link_id_,\n                  LocalRank(), push_request->msg().key());\n  THROW_IF_RPC_NOT_OK(cntl, response, request_info);\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/link/mux_link_factory.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n\n#include \"yacl/link/factory.h\"\n\n#include \"engine/link/channel_manager.h\"\n#include \"engine/link/listener.h\"\n\n#include \"engine/link/mux_receiver.pb.h\"\n\nnamespace scql::engine {\n\nclass MuxLinkFactory : public yacl::link::ILinkFactory {\n public:\n  explicit MuxLinkFactory(ChannelManager* channel_manager,\n                          ListenerManager* listener_manager)\n      : channel_manager_(channel_manager),\n        listener_manager_(listener_manager) {}\n\n  /// @brief add listener to listener manager after link context created.\n  std::shared_ptr<yacl::link::Context> CreateContext(\n      const yacl::link::ContextDesc& desc, size_t self_rank) override;\n\n private:\n  ChannelManager* channel_manager_;\n  ListenerManager* listener_manager_;\n};\n\nclass MuxLink : public yacl::link::transport::TransportLink {\n public:\n  MuxLink(size_t self_rank, size_t peer_rank, size_t http_max_payload_size,\n          std::string link_id,\n          std::shared_ptr<::google::protobuf::RpcChannel> rpc_channel)\n      : TransportLink(self_rank, peer_rank),\n        http_max_payload_size_(http_max_payload_size),\n        link_id_(std::move(link_id)),\n        rpc_channel_(std::move(rpc_channel)) {}\n\n  size_t GetMaxBytesPerChunk() const override;\n  void SetMaxBytesPerChunk(size_t bytes) override;\n  std::unique_ptr<::google::protobuf::Message> PackMonoRequest(\n      const std::string& key, yacl::ByteContainerView value) const override;\n  std::unique_ptr<::google::protobuf::Message> PackChunkedRequest(\n      const std::string& key, yacl::ByteContainerView value, size_t offset,\n      size_t total_length) const override;\n  void UnpackMonoRequest(const ::google::protobuf::Message& request,\n                         std::string* key,\n                         yacl::ByteContainerView* value) const override;\n  void UnpackChunckRequest(const ::google::protobuf::Message& request,\n                           std::string* key, yacl::ByteContainerView* value,\n                           size_t* offset, size_t* total_length) const override;\n  void FillResponseOk(const ::google::protobuf::Message& request,\n                      ::google::protobuf::Message* response) const override;\n  void FillResponseError(const ::google::protobuf::Message& request,\n                         ::google::protobuf::Message* response) const override;\n  bool IsChunkedRequest(\n      const ::google::protobuf::Message& request) const override;\n  bool IsMonoRequest(const ::google::protobuf::Message& request) const override;\n\n  void SendRequest(const ::google::protobuf::Message& request,\n                   uint32_t timeout_override_ms) const override;\n\n private:\n  size_t http_max_payload_size_;\n  std::string link_id_;\n  const std::shared_ptr<::google::protobuf::RpcChannel> rpc_channel_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/link/mux_receiver.proto",
    "content": "//\n// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.engine.link.pb;\n\noption cc_generic_services = true;\n\n// Multiplexing Receiver Service\nservice MuxReceiverService {\n  // push the data to receiver's local database.\n  rpc Push(MuxPushRequest) returns (MuxPushResponse);\n}\n\nmessage MuxPushRequest {\n  // uuid, for multi link context multiplexing\n  // usually, it is session id\n  string link_id = 1;\n\n  Message msg = 2;\n}\n\nmessage MuxPushResponse {\n  ErrorCode error_code = 1;\n  string error_msg = 2;\n}\n\n// Message pushed to receiver\nmessage Message {\n  uint64 sender_rank = 1;\n  // key of the message.\n  string key = 2;\n  // value of the message.\n  bytes value = 3;\n  // chunk related.\n  TransType trans_type = 4;\n  ChunkInfo chunk_info = 5;\n}\n\nenum TransType {\n  MONO = 0;\n  CHUNKED = 1;\n}\n\nenum ErrorCode {\n  SUCCESS = 0;\n  UNEXPECTED_ERROR = 1;\n  INVALID_REQUEST = 2;\n  INVALID_RESOURCE = 3;\n  NETWORK_ERROR = 4;\n  LINKID_NOT_FOUND = 5;\n}\n\nmessage ChunkInfo {\n  uint64 message_length = 1;\n  uint64 chunk_offset = 2;\n}\n"
  },
  {
    "path": "engine/link/mux_receiver_service.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/link/mux_receiver_service.h\"\n\n#include \"brpc/closure_guard.h\"\n\nnamespace scql::engine {\n\nvoid MuxReceiverServiceImpl::Push(::google::protobuf::RpcController* cntl,\n                                  const link::pb::MuxPushRequest* request,\n                                  link::pb::MuxPushResponse* response,\n                                  ::google::protobuf::Closure* done) {\n  brpc::ClosureGuard done_guard(done);\n  try {\n    // get listener from listener_manager_.\n    const std::string& link_id = request->link_id();\n    const auto& msg = request->msg();\n    const size_t sender_rank = msg.sender_rank();\n    const auto& listener = listener_manager_->GetListener(link_id);\n    if (!listener) {\n      response->set_error_code(link::pb::ErrorCode::LINKID_NOT_FOUND);\n      response->set_error_msg(\n          fmt::format(\"no exist Listener for link_id={}\", link_id));\n      return;\n    }\n    listener->OnRequest(sender_rank, request, response);\n    return;\n  } catch (const std::exception& e) {\n    response->set_error_code(link::pb::ErrorCode::UNEXPECTED_ERROR);\n    response->set_error_msg(fmt::format(\"dispatch error, link_id={}, error={}\",\n                                        request->link_id(), e.what()));\n    return;\n  }\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/link/mux_receiver_service.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/link/listener.h\"\n\n#include \"engine/link/mux_receiver.pb.h\"\n\nnamespace scql::engine {\n\n// Multiplexing Receiver Service\nclass MuxReceiverServiceImpl : public link::pb::MuxReceiverService {\n public:\n  explicit MuxReceiverServiceImpl(ListenerManager* listener_manager)\n      : listener_manager_(listener_manager) {}\n\n  void Push(::google::protobuf::RpcController* cntl,\n            const link::pb::MuxPushRequest* request,\n            link::pb::MuxPushResponse* response,\n            ::google::protobuf::Closure* done) override;\n\n private:\n  ListenerManager* listener_manager_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/link/mux_receiver_service_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/link/mux_receiver_service.h\"\n\n#include <future>\n\n#include \"brpc/server.h\"\n#include \"gtest/gtest.h\"\n#include \"yacl/link/link.h\"  // NOLINT\n\n#include \"engine/link/mux_link_factory.h\"\n\nnamespace scql::engine {\n\n//  test with MuxLinkChannel.\nclass MuxReceiverServiceImplTest : public ::testing::Test {};\n\nTEST_F(MuxReceiverServiceImplTest, Works) {\n  constexpr size_t kWorldSize = 3U;\n  std::vector<std::unique_ptr<ListenerManager>> listener_managers;\n  std::vector<std::unique_ptr<MuxReceiverServiceImpl>> services;\n  std::vector<brpc::Server> servers(kWorldSize);\n  for (size_t rank = 0; rank < kWorldSize; rank++) {\n    listener_managers.emplace_back(new ListenerManager());\n\n    services.emplace_back(\n        new MuxReceiverServiceImpl(listener_managers[rank].get()));\n    servers[rank].AddService(services[rank].get(),\n                             brpc::SERVER_DOESNT_OWN_SERVICE);\n\n    brpc::ServerOptions options;\n    servers[rank].Start(\"127.0.0.1:0\", &options);\n  }\n\n  yacl::link::ContextDesc link_desc;\n  for (size_t rank = 0; rank < kWorldSize; rank++) {\n    const std::string rank_host =\n        butil::endpoint2str(servers[rank].listen_address()).c_str();\n    link_desc.parties.emplace_back(fmt::format(\"party{}\", rank), rank_host);\n  }\n  std::string new_id = link_desc.id + \"new\";\n\n  auto proc = [&](yacl::link::ILinkFactory* factory, size_t self_rank) -> void {\n    std::shared_ptr<yacl::link::Context> lc0;\n    std::shared_ptr<yacl::link::Context> lc1;\n    EXPECT_NO_THROW(lc0 = factory->CreateContext(link_desc, self_rank));\n    EXPECT_TRUE(lc0 != nullptr);\n    EXPECT_NO_THROW(lc0->ConnectToMesh());\n    EXPECT_NO_THROW(\n        yacl::link::Barrier(lc0, \"ba-0\"));  // simple function works.\n\n    // create with same link id failed.\n    EXPECT_THROW(lc1 = factory->CreateContext(link_desc, self_rank),\n                 ::yacl::LogicError);\n\n    // lc0 still works\n    EXPECT_NO_THROW(\n        yacl::link::Barrier(lc0, \"ba-1\"));  // simple function works.\n\n    // release lc0\n    lc0->WaitLinkTaskFinish();\n    lc0.reset();\n    // create with a new id.\n    link_desc.id = new_id;\n    EXPECT_NO_THROW(lc1 = factory->CreateContext(link_desc, self_rank));\n    EXPECT_TRUE(lc1 != nullptr);\n    EXPECT_NO_THROW(lc1->ConnectToMesh());\n    EXPECT_NO_THROW(\n        yacl::link::Barrier(lc1, \"ba-2\"));  // simple function works.\n    lc1->WaitLinkTaskFinish();\n  };\n\n  std::vector<std::future<void>> futures(kWorldSize);\n  ChannelManager channel_manager;\n  std::vector<std::unique_ptr<MuxLinkFactory>> mux_link_factorys;\n  for (size_t rank = 0; rank < kWorldSize; rank++) {\n    mux_link_factorys.emplace_back(\n        new MuxLinkFactory(&channel_manager, listener_managers[rank].get()));\n    futures[rank] = std::async(proc, mux_link_factorys[rank].get(), rank);\n  }\n  for (size_t rank = 0; rank < kWorldSize; rank++) {\n    futures[rank].get();\n  }\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/link/rpc_helper.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/link/rpc_helper.h\"\n\nnamespace scql::engine {\nstatic std::unique_ptr<brpc::Authenticator> default_authenticator;\n\nvoid SetDefaultAuthenticator(std::unique_ptr<brpc::Authenticator> auth) {\n  default_authenticator.swap(auth);\n}\n\nconst brpc::Authenticator* DefaultAuthenticator() {\n  return default_authenticator.get();\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/link/rpc_helper.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n#include <string>\n\n#include \"brpc/authenticator.h\"\n\nnamespace scql::engine {\n\n// NOTE: Using Singleton for SimpleAuthenticator to\n// remain accessible at all times\nclass SimpleAuthenticator : public brpc::Authenticator {\n public:\n  explicit SimpleAuthenticator(std::string credential)\n      : credential_(std::move(credential)) {}\n\n  virtual ~SimpleAuthenticator() = default;\n\n  int GenerateCredential(std::string* auth_str) const override {\n    *auth_str = credential_;\n    return 0;\n  }\n\n  int VerifyCredential(const std::string& auth_str,\n                       const butil::EndPoint& client_addr,\n                       brpc::AuthContext* out_ctx) const override {\n    if (auth_str == credential_) {\n      return 0;\n    }\n    return 1;\n  }\n\n private:\n  const std::string credential_;\n};\n\nvoid SetDefaultAuthenticator(std::unique_ptr<brpc::Authenticator> auth);\n\nconst brpc::Authenticator* DefaultAuthenticator();\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/link/rpc_helper_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/link/rpc_helper.h\"\n\n#include \"brpc/channel.h\"\n#include \"brpc/server.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/link/mux_receiver.pb.h\"\n\n// disable detect leaks for brpc's \"acceptable mem leak\"\n// https://github.com/apache/incubator-brpc/blob/0.9.6/src/brpc/server.cpp#L1138\nextern \"C\" const char* __asan_default_options() { return \"detect_leaks=0\"; }\n\nnamespace scql::engine {\n\nnamespace {\n\n// brpc receiver service for test.\nclass RecvTestImpl : public link::pb::MuxReceiverService {\n public:\n  void Push(::google::protobuf::RpcController* cntl,\n            const link::pb::MuxPushRequest* request,\n            link::pb::MuxPushResponse* response,\n            ::google::protobuf::Closure* done) {\n    brpc::ClosureGuard done_guard(done);\n\n    if (request->link_id() == \"\") {\n      response->set_error_code(link::pb::ErrorCode::INVALID_REQUEST);\n      response->set_error_msg(\"no link_id.\");\n      return;\n    }\n\n    response->set_error_code(link::pb::ErrorCode::SUCCESS);\n    response->set_error_msg(\"no error.\");\n  }\n};\n\nSimpleAuthenticator g_my_auth(\"test\");\n}  // namespace\n\nclass RpcHelperTest : public testing::Test {\n public:\n  void SetUp() override {\n    service_.reset(new RecvTestImpl);\n    ASSERT_EQ(\n        server_.AddService(service_.get(), brpc::SERVER_DOESNT_OWN_SERVICE), 0)\n        << \"Fail to add service\";\n\n    brpc::ServerOptions server_options;\n    server_options.auth = &g_my_auth;\n    ASSERT_EQ(server_.Start(\"127.0.0.1:0\", &server_options), 0)\n        << \"Fail to start server at 127.0.0.1:0\";\n    host_ = butil::endpoint2str(server_.listen_address()).c_str();\n  }\n\n protected:\n  brpc::Server server_;\n  std::unique_ptr<RecvTestImpl> service_;\n  std::string host_;\n};\n\nTEST_F(RpcHelperTest, RpcNoAuth) {\n  brpc::ChannelOptions options;\n  brpc::Controller cntl;\n  brpc::Channel channel;\n\n  options.protocol = \"baidu_std\";\n  ASSERT_EQ(channel.Init(host_.c_str(), &options), 0);\n  link::pb::MuxReceiverService::Stub stub(&channel);\n\n  link::pb::MuxPushRequest request;\n  request.set_link_id(\"link_id\");\n  link::pb::MuxPushResponse response;\n\n  stub.Push(&cntl, &request, &response, nullptr);\n\n  EXPECT_TRUE(cntl.Failed());\n  EXPECT_EQ(brpc::ERPCAUTH, cntl.ErrorCode());\n}\n\nTEST_F(RpcHelperTest, RpcWithRetryAndAuth) {\n  brpc::ChannelOptions options;\n  brpc::Controller cntl;\n  brpc::Channel channel;\n\n  options.protocol = \"baidu_std\";\n  options.auth = &g_my_auth;\n  ASSERT_EQ(channel.Init(host_.c_str(), &options), 0);\n  link::pb::MuxReceiverService::Stub stub(&channel);\n\n  link::pb::MuxPushRequest request;\n  request.set_link_id(\"link_id\");\n  link::pb::MuxPushResponse response;\n\n  stub.Push(&cntl, &request, &response, nullptr);\n\n  EXPECT_FALSE(cntl.Failed());\n  EXPECT_EQ(response.error_code(), link::pb::ErrorCode::SUCCESS);\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/operator/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncc_library(\n    name = \"all_ops_register\",\n    srcs = [\"all_ops_register.cc\"],\n    hdrs = [\"all_ops_register.h\"],\n    deps = [\n        \":arithmetic\",\n        \":arrow_func\",\n        \":broadcast_to\",\n        \":bucket\",\n        \":case_when\",\n        \":cast\",\n        \":coalesce\",\n        \":compare\",\n        \":concat\",\n        \":constant\",\n        \":copy\",\n        \":dump_file\",\n        \":filter\",\n        \":filter_by_index\",\n        \":group\",\n        \":group_agg\",\n        \":group_secret_agg\",\n        \":if\",\n        \":if_null\",\n        \":in\",\n        \":insert_table\",\n        \":is_null\",\n        \":join\",\n        \":limit\",\n        \":logical\",\n        \":make_private\",\n        \":make_public\",\n        \":make_share\",\n        \":oblivious_group_agg\",\n        \":oblivious_group_mark\",\n        \":publish\",\n        \":reduce\",\n        \":replicate\",\n        \":run_sql\",\n        \":secret_join\",\n        \":shape\",\n        \":shuffle\",\n        \":sort\",\n        \":trigonometric\",\n        \":unary\",\n        \":unique\",\n        \":window\",\n        \"//engine/framework:registry\",\n    ],\n)\n\nscql_cc_test(\n    name = \"all_ops_register_test\",\n    srcs = [\"all_ops_register_test.cc\"],\n    deps = [\n        \":all_ops_register\",\n    ],\n)\n\ncc_library(\n    name = \"run_sql\",\n    srcs = [\"run_sql.cc\"],\n    hdrs = [\"run_sql.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n    ],\n)\n\nscql_cc_test(\n    name = \"run_sql_test\",\n    srcs = [\"run_sql_test.cc\"],\n    deps = [\n        \":run_sql\",\n        \":test_util\",\n        \"//engine/datasource:datasource_adaptor_mgr\",\n        \"//engine/datasource:embed_router\",\n        \"@abseil-cpp//absl/debugging:failure_signal_handler\",\n        \"@abseil-cpp//absl/debugging:symbolize\",\n        \"@abseil-cpp//absl/flags:parse\",\n        \"@org_pocoproject_poco//:poco\",\n    ],\n)\n\ncc_library(\n    name = \"join\",\n    srcs = [\"join.cc\"],\n    hdrs = [\"join.h\"],\n    deps = [\n        \"//engine/core:tensor_slice\",\n        \"//engine/exe:flags\",\n        \"//engine/framework:operator\",\n        \"//engine/util:communicate_helper\",\n        \"//engine/util/psi:batch_provider\",\n        \"//engine/util/psi:cipher_intersection\",\n        \"//engine/util/psi:detail_logger\",\n        \"//engine/util/psi:ub_helper\",\n        \"@msgpack-c//:msgpack\",\n        \"@psi//psi/algorithm/ecdh:ecdh_psi\",\n        \"@psi//psi/algorithm/ecdh/ub_psi:ecdh_oprf_psi\",\n        \"@psi//psi/algorithm/rr22:common\",\n        \"@psi//psi/cryptor:cryptor_selector\",\n    ],\n)\n\nscql_cc_test(\n    name = \"join_test\",\n    srcs = [\"join_test.cc\"],\n    deps = [\n        \":join\",\n        \":test_util\",\n        \"//engine/core:primitive_builder\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"test_util\",\n    srcs = [\"test_util.cc\"],\n    hdrs = [\"test_util.h\"],\n    deps = [\n        \"//engine/datasource:datasource_adaptor_mgr\",\n        \"//engine/datasource:router\",\n        \"//engine/framework:exec\",\n        \"//engine/framework:operator\",\n        \"//engine/framework:session\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@googletest//:gtest\",\n        \"@spulib//libspu/core:config\",\n    ],\n)\n\ncc_library(\n    name = \"filter_by_index\",\n    srcs = [\"filter_by_index.cc\"],\n    hdrs = [\"filter_by_index.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"filter_by_index_test\",\n    srcs = [\"filter_by_index_test.cc\"],\n    deps = [\n        \":filter_by_index\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"make_share\",\n    srcs = [\"make_share.cc\"],\n    hdrs = [\"make_share.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"@spulib//libspu/device:io\",\n    ],\n)\n\nscql_cc_test(\n    name = \"make_share_test\",\n    srcs = [\"make_share_test.cc\"],\n    deps = [\n        \":make_share\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"publish\",\n    srcs = [\"publish.cc\"],\n    hdrs = [\"publish.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n    ],\n)\n\nscql_cc_test(\n    name = \"publish_test\",\n    srcs = [\"publish_test.cc\"],\n    deps = [\n        \":publish\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"binary_base\",\n    srcs = [\"binary_base.cc\"],\n    hdrs = [\"binary_base.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:context_util\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n    ],\n)\n\ncc_library(\n    name = \"binary_test\",\n    hdrs = [\"binary_test.h\"],\n    deps = [\n        \":all_ops_register\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n        \"@googletest//:gtest\",\n    ],\n)\n\ncc_library(\n    name = \"arithmetic\",\n    srcs = [\"arithmetic.cc\"],\n    hdrs = [\"arithmetic.h\"],\n    deps = [\n        \":binary_base\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n    ],\n)\n\nscql_cc_test(\n    name = \"arithmetic_test\",\n    srcs = [\"arithmetic_test.cc\"],\n    deps = [\n        \":arithmetic\",\n        \":binary_test\",\n    ],\n)\n\ncc_library(\n    name = \"make_private\",\n    srcs = [\"make_private.cc\"],\n    hdrs = [\"make_private.h\"],\n    deps = [\n        \"//engine/core:string_tensor_builder\",\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"make_private_test\",\n    srcs = [\"make_private_test.cc\"],\n    deps = [\n        \":make_private\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"filter\",\n    srcs = [\"filter.cc\"],\n    hdrs = [\"filter.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hal:public_helper\",\n        \"@spulib//libspu/kernel/hlo:indexing\",\n    ],\n)\n\nscql_cc_test(\n    name = \"filter_test\",\n    srcs = [\"filter_test.cc\"],\n    deps = [\n        \":filter\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"make_public\",\n    srcs = [\"make_public.cc\"],\n    hdrs = [\"make_public.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hal:type_cast\",\n    ],\n)\n\nscql_cc_test(\n    name = \"make_public_test\",\n    srcs = [\"make_public_test.cc\"],\n    deps = [\n        \":make_public\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"compare\",\n    srcs = [\"compare.cc\"],\n    hdrs = [\"compare.h\"],\n    deps = [\n        \":binary_base\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n    ],\n)\n\nscql_cc_test(\n    name = \"compare_test\",\n    srcs = [\"compare_test.cc\"],\n    deps = [\n        \":binary_test\",\n        \":compare\",\n    ],\n)\n\ncc_library(\n    name = \"logical\",\n    srcs = [\"logical.cc\"],\n    hdrs = [\"logical.h\"],\n    deps = [\n        \":binary_base\",\n        \"//engine/util:spu_io\",\n        \"@spulib//libspu/kernel/hlo:basic_unary\",\n    ],\n)\n\nscql_cc_test(\n    name = \"logical_test\",\n    srcs = [\"logical_test.cc\"],\n    deps = [\n        \":binary_test\",\n        \":logical\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"copy\",\n    srcs = [\"copy.cc\"],\n    hdrs = [\"copy.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:table_util\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"copy_test\",\n    srcs = [\"copy_test.cc\"],\n    deps = [\n        \":copy\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"in\",\n    srcs = [\"in.cc\"],\n    hdrs = [\"in.h\"],\n    deps = [\n        \"//engine/exe:flags\",\n        \"//engine/framework:operator\",\n        \"//engine/util/psi:batch_provider\",\n        \"//engine/util/psi:cipher_intersection\",\n        \"//engine/util/psi:detail_logger\",\n        \"//engine/util/psi:ub_helper\",\n        \"@psi//psi/algorithm/ecdh:ecdh_psi\",\n        \"@psi//psi/algorithm/ecdh/ub_psi:ecdh_oprf_psi\",\n        \"@psi//psi/algorithm/rr22:common\",\n        \"@psi//psi/cryptor:cryptor_selector\",\n    ],\n)\n\nscql_cc_test(\n    name = \"in_test\",\n    srcs = [\"in_test.cc\"],\n    deps = [\n        \":in\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"constant\",\n    srcs = [\"constant.cc\"],\n    hdrs = [\"constant.h\"],\n    deps = [\n        \"//engine/core:primitive_builder\",\n        \"//engine/core:string_tensor_builder\",\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"constant_test\",\n    srcs = [\"constant_test.cc\"],\n    deps = [\n        \":constant\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"dump_file\",\n    srcs = [\"dump_file.cc\"],\n    hdrs = [\"dump_file.h\"],\n    deps = [\n        \"//engine/exe:flags\",\n        \"//engine/framework:operator\",\n        \"//engine/util:datamesh_helper\",\n        \"//engine/util:filepath_helper\",\n        \"//engine/util:ssl_helper\",\n        \"//engine/util:tensor_util\",\n        \"//engine/util:upload_info_helper\",\n        \"@brpc//:butil\",\n        \"@dataproxy_sdk_cc//dataproxy_sdk:data_proxy_file\",\n    ],\n)\n\nscql_cc_test(\n    name = \"dump_file_test\",\n    srcs = [\"dump_file_test.cc\"],\n    deps = [\n        \":dump_file\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n        \"@brpc//:butil\",\n    ],\n)\n\ncc_library(\n    name = \"insert_table\",\n    srcs = [\"insert_table.cc\"],\n    hdrs = [\"insert_table.h\"],\n    deps = [\n        \"//engine/datasource:odbc_connector\",\n        \"//engine/framework:operator\",\n        \"//engine/util:tensor_util\",\n        \"@abseil-cpp//absl/strings\",\n    ],\n)\n\nscql_cc_test(\n    name = \"insert_table_test\",\n    srcs = [\"insert_table_test.cc\"],\n    deps = [\n        \":insert_table\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_binary(\n    name = \"insert_table_mysql_pg_test\",\n    srcs = [\"insert_table_mysql_pg_test.cc\"],\n    deps = [\n        \":insert_table\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n        \"@googletest//:gtest\",\n    ],\n)\n\ncc_library(\n    name = \"reduce\",\n    srcs = [\"reduce.cc\"],\n    hdrs = [\"reduce.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hal:shape_ops\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n        \"@spulib//libspu/kernel/hlo:const\",\n        \"@spulib//libspu/kernel/hlo:reduce\",\n        \"@spulib//libspu/kernel/hlo:sort\",\n    ],\n)\n\nscql_cc_test(\n    name = \"reduce_test\",\n    # 60 min\n    timeout = \"eternal\",\n    srcs = [\"reduce_test.cc\"],\n    shard_count = 4,\n    deps = [\n        \":all_ops_register\",\n        \":reduce\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"shape\",\n    srcs = [\"shape.cc\"],\n    hdrs = [\"shape.h\"],\n    deps = [\n        \"//engine/core:primitive_builder\",\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"shape_test\",\n    srcs = [\"shape_test.cc\"],\n    deps = [\n        \":shape\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"sort\",\n    srcs = [\"sort.cc\"],\n    hdrs = [\"sort.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:table_util\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n        \"@spulib//libspu/kernel/hlo:const\",\n        \"@spulib//libspu/kernel/hlo:sort\",\n    ],\n)\n\nscql_cc_test(\n    name = \"sort_test\",\n    srcs = [\"sort_test.cc\"],\n    deps = [\n        \":sort\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"oblivious_group_mark\",\n    srcs = [\"oblivious_group_mark.cc\"],\n    hdrs = [\"oblivious_group_mark.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hal:shape_ops\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n        \"@spulib//libspu/kernel/hlo:casting\",\n        \"@spulib//libspu/kernel/hlo:const\",\n        \"@spulib//libspu/kernel/hlo:geometrical\",\n    ],\n)\n\nscql_cc_test(\n    name = \"oblivious_group_mark_test\",\n    srcs = [\"oblivious_group_mark_test.cc\"],\n    deps = [\n        \":oblivious_group_mark\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"oblivious_group_agg\",\n    srcs = [\"oblivious_group_agg.cc\"],\n    hdrs = [\"oblivious_group_agg.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:prefix_sum\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hal:constants\",\n        \"@spulib//libspu/kernel/hal:shape_ops\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n        \"@spulib//libspu/kernel/hlo:basic_ternary\",\n        \"@spulib//libspu/kernel/hlo:casting\",\n        \"@spulib//libspu/kernel/hlo:const\",\n        \"@spulib//libspu/kernel/hlo:geometrical\",\n    ],\n)\n\nscql_cc_test(\n    name = \"oblivious_group_agg_test\",\n    srcs = [\"oblivious_group_agg_test.cc\"],\n    shard_count = 4,\n    deps = [\n        \":all_ops_register\",\n        \":oblivious_group_agg\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"shuffle\",\n    srcs = [\"shuffle.cc\"],\n    hdrs = [\"shuffle.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hlo:shuffle\",\n    ],\n)\n\nscql_cc_test(\n    name = \"shuffle_test\",\n    srcs = [\"shuffle_test.cc\"],\n    deps = [\n        \":shuffle\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/util/psi:batch_provider\",\n    ],\n)\n\ncc_library(\n    name = \"broadcast_to\",\n    srcs = [\"broadcast_to.cc\"],\n    hdrs = [\"broadcast_to.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hal:shape_ops\",\n    ],\n)\n\nscql_cc_test(\n    name = \"broadcast_to_test\",\n    srcs = [\"broadcast_to_test.cc\"],\n    deps = [\n        \":broadcast_to\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"unique\",\n    srcs = [\"unique.cc\"],\n    hdrs = [\"unique.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"unique_test\",\n    srcs = [\"unique_test.cc\"],\n    deps = [\n        \":test_util\",\n        \":unique\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"concat\",\n    srcs = [\"concat.cc\"],\n    hdrs = [\"concat.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hlo:geometrical\",\n    ],\n)\n\nscql_cc_test(\n    name = \"concat_test\",\n    srcs = [\"concat_test.cc\"],\n    deps = [\n        \":concat\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"group\",\n    srcs = [\"group.cc\"],\n    hdrs = [\"group.h\"],\n    deps = [\n        \"//engine/core:primitive_builder\",\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:table_util\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"group_test\",\n    srcs = [\"group_test.cc\"],\n    deps = [\n        \":group\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"group_agg\",\n    srcs = [\"group_agg.cc\"],\n    hdrs = [\"group_agg.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"group_agg_test\",\n    srcs = [\"group_agg_test.cc\"],\n    deps = [\n        \":all_ops_register\",\n        \":group_agg\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"group_secret_agg\",\n    srcs = [\"group_secret_agg.cc\"],\n    hdrs = [\"group_secret_agg.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hal:public_helper\",\n        \"@spulib//libspu/kernel/hlo:geometrical\",\n        \"@spulib//libspu/kernel/hlo:group_by_agg\",\n    ],\n)\n\nscql_cc_test(\n    name = \"group_secret_agg_test\",\n    srcs = [\"group_secret_agg_test.cc\"],\n    deps = [\n        \":group_secret_agg\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"cast\",\n    srcs = [\"cast.cc\"],\n    hdrs = [\"cast.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"cast_test\",\n    srcs = [\"cast_test.cc\"],\n    deps = [\n        \":cast\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"case_when\",\n    srcs = [\"case_when.cc\"],\n    hdrs = [\"case_when.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hal:shape_ops\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n        \"@spulib//libspu/kernel/hlo:const\",\n    ],\n)\n\nscql_cc_test(\n    name = \"case_when_test\",\n    srcs = [\"case_when_test.cc\"],\n    deps = [\n        \":case_when\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"if\",\n    srcs = [\"if.cc\"],\n    hdrs = [\"if.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hal:shape_ops\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n        \"@spulib//libspu/kernel/hlo:casting\",\n        \"@spulib//libspu/kernel/hlo:const\",\n    ],\n)\n\nscql_cc_test(\n    name = \"if_test\",\n    srcs = [\"if_test.cc\"],\n    deps = [\n        \":if\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"limit\",\n    srcs = [\"limit.cc\"],\n    hdrs = [\"limit.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hlo:geometrical\",\n    ],\n)\n\nscql_cc_test(\n    name = \"limit_test\",\n    srcs = [\"limit_test.cc\"],\n    deps = [\n        \":limit\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"arrow_func\",\n    srcs = [\"arrow_func.cc\"],\n    hdrs = [\"arrow_func.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"arrow_func_test\",\n    srcs = [\"arrow_func_test.cc\"],\n    deps = [\n    ] + [\n        \":arrow_func\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"is_null\",\n    srcs = [\"is_null.cc\"],\n    hdrs = [\"is_null.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"is_null_test\",\n    srcs = [\"is_null_test.cc\"],\n    deps = [\n        \":is_null\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"if_null\",\n    srcs = [\"if_null.cc\"],\n    hdrs = [\"if_null.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"if_null_test\",\n    srcs = [\"if_null_test.cc\"],\n    deps = [\n        \":if_null\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"coalesce\",\n    srcs = [\"coalesce.cc\"],\n    hdrs = [\"coalesce.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"coalesce_test\",\n    srcs = [\"coalesce_test.cc\"],\n    deps = [\n        \":coalesce\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"trigonometric\",\n    srcs = [\"trigonometric.cc\"],\n    hdrs = [\"trigonometric.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/operator:binary_base\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n        \"@spulib//libspu/kernel/hlo:basic_unary\",\n    ],\n)\n\nscql_cc_test(\n    name = \"trigonometric_test\",\n    srcs = [\"trigonometric_test.cc\"],\n    deps = [\n        \":test_util\",\n        \":trigonometric\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"bucket\",\n    srcs = [\"bucket.cc\"],\n    hdrs = [\"bucket.h\"],\n    deps = [\n        \"//engine/core:primitive_builder\",\n        \"//engine/framework:operator\",\n        \"//engine/util:concurrent_queue\",\n        \"//engine/util:table_util\",\n        \"//engine/util:tensor_util\",\n        \"//engine/util/psi:batch_provider\",\n        \"@org_apache_arrow//:arrow\",\n    ],\n)\n\nscql_cc_test(\n    name = \"bucket_test\",\n    srcs = [\"bucket_test.cc\"],\n    deps = [\n        \":bucket\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_binary(\n    name = \"bucket_bench\",\n    srcs = [\"bucket_bench.cc\"],\n    deps = [\n        \"@google_benchmark//:benchmark_main\",\n    ] + [\n        \":bucket\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/util:filepath_helper\",\n        \"//engine/util/disk:arrow_reader\",\n        \"//engine/util/disk:arrow_writer\",\n        \"@yacl//yacl/utils:parallel\",\n    ],\n)\n\ncc_library(\n    name = \"window\",\n    srcs = [\"window.cc\"],\n    hdrs = [\"window.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:table_util\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"window_test\",\n    srcs = [\"window_test.cc\"],\n    deps = [\n        \":all_ops_register\",\n        \":test_util\",\n        \":window\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"secret_join\",\n    srcs = [\"secret_join.cc\"],\n    hdrs = [\"secret_join.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:prefix_sum\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n        \"@spulib//libspu/kernel/hal:debug\",\n        \"@spulib//libspu/kernel/hal:public_helper\",\n        \"@spulib//libspu/kernel/hal:shape_ops\",\n        \"@spulib//libspu/kernel/hal:type_cast\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n        \"@spulib//libspu/kernel/hlo:basic_ternary\",\n        \"@spulib//libspu/kernel/hlo:basic_unary\",\n        \"@spulib//libspu/kernel/hlo:casting\",\n        \"@spulib//libspu/kernel/hlo:const\",\n        \"@spulib//libspu/kernel/hlo:geometrical\",\n        \"@spulib//libspu/kernel/hlo:indexing\",\n        \"@spulib//libspu/kernel/hlo:permute\",\n        \"@spulib//libspu/kernel/hlo:shuffle\",\n        \"@spulib//libspu/kernel/hlo:soprf\",\n        \"@spulib//libspu/kernel/hlo:sort\",\n    ],\n)\n\nscql_cc_test(\n    name = \"secret_join_test\",\n    srcs = [\"secret_join_test.cc\"],\n    deps = [\n        \":secret_join\",\n        \":test_util\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\ncc_library(\n    name = \"unary_base\",\n    srcs = [\"unary_base.cc\"],\n    hdrs = [\"unary_base.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:context_util\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\ncc_library(\n    name = \"unary\",\n    srcs = [\"unary.cc\"],\n    hdrs = [\"unary.h\"],\n    deps = [\n        \":unary_base\",\n        \"//engine/core:tensor_constructor\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n        \"@spulib//libspu/kernel/hlo:basic_unary\",\n        \"@spulib//libspu/kernel/hlo:const\",\n    ],\n)\n\nscql_cc_test(\n    name = \"unary_test\",\n    srcs = [\"unary_test.cc\"],\n    deps = [\n        \":all_ops_register\",\n        \":test_util\",\n        \":unary\",\n        \"//engine/framework:registry\",\n    ],\n)\n\ncc_library(\n    name = \"replicate\",\n    srcs = [\"replicate.cc\"],\n    hdrs = [\"replicate.h\"],\n    deps = [\n        \"//engine/framework:operator\",\n        \"//engine/util:context_util\",\n        \"//engine/util:tensor_util\",\n    ],\n)\n\nscql_cc_test(\n    name = \"replicate_test\",\n    srcs = [\"replicate_test.cc\"],\n    deps = [\n        \":replicate\",\n        \":test_util\",\n        \":unary\",\n    ],\n)\n"
  },
  {
    "path": "engine/operator/all_ops_register.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/all_ops_register.h\"\n\n#include <mutex>\n\n#include \"engine/framework/registry.h\"\n#include \"engine/operator/arithmetic.h\"\n#include \"engine/operator/arrow_func.h\"\n#include \"engine/operator/broadcast_to.h\"\n#include \"engine/operator/bucket.h\"\n#include \"engine/operator/case_when.h\"\n#include \"engine/operator/cast.h\"\n#include \"engine/operator/coalesce.h\"\n#include \"engine/operator/compare.h\"\n#include \"engine/operator/concat.h\"\n#include \"engine/operator/constant.h\"\n#include \"engine/operator/copy.h\"\n#include \"engine/operator/dump_file.h\"\n#include \"engine/operator/filter.h\"\n#include \"engine/operator/filter_by_index.h\"\n#include \"engine/operator/group.h\"\n#include \"engine/operator/group_agg.h\"\n#include \"engine/operator/group_secret_agg.h\"\n#include \"engine/operator/if.h\"\n#include \"engine/operator/if_null.h\"\n#include \"engine/operator/in.h\"\n#include \"engine/operator/insert_table.h\"\n#include \"engine/operator/is_null.h\"\n#include \"engine/operator/join.h\"\n#include \"engine/operator/limit.h\"\n#include \"engine/operator/logical.h\"\n#include \"engine/operator/make_private.h\"\n#include \"engine/operator/make_public.h\"\n#include \"engine/operator/make_share.h\"\n#include \"engine/operator/oblivious_group_agg.h\"\n#include \"engine/operator/oblivious_group_mark.h\"\n#include \"engine/operator/publish.h\"\n#include \"engine/operator/reduce.h\"\n#include \"engine/operator/replicate.h\"\n#include \"engine/operator/run_sql.h\"\n#include \"engine/operator/secret_join.h\"\n#include \"engine/operator/shape.h\"\n#include \"engine/operator/shuffle.h\"\n#include \"engine/operator/sort.h\"\n#include \"engine/operator/trigonometric.h\"\n#include \"engine/operator/unary.h\"\n#include \"engine/operator/unique.h\"\n#include \"engine/operator/window.h\"\n\n#ifndef ADD_OPERATOR_TO_REGISTRY\n#define ADD_OPERATOR_TO_REGISTRY(op_type)                                \\\n  do {                                                                   \\\n    GetOpRegistry()->AddOperator(                                        \\\n        op_type::kOpType, []() { return std::make_unique<op_type>(); }); \\\n  } while (false)\n#endif  // ADD_OPERATOR_TO_REGISTRY\n\nnamespace scql::engine::op {\n\nnamespace {\n\nvoid RegisterAllOpsImpl() {\n  ADD_OPERATOR_TO_REGISTRY(RunSQL);\n  ADD_OPERATOR_TO_REGISTRY(Constant);\n  ADD_OPERATOR_TO_REGISTRY(BroadcastTo);\n\n  ADD_OPERATOR_TO_REGISTRY(Publish);\n  ADD_OPERATOR_TO_REGISTRY(DumpFile);\n  ADD_OPERATOR_TO_REGISTRY(InsertTable);\n\n  ADD_OPERATOR_TO_REGISTRY(Join);\n  ADD_OPERATOR_TO_REGISTRY(FilterByIndex);\n  ADD_OPERATOR_TO_REGISTRY(SecretJoin);\n  ADD_OPERATOR_TO_REGISTRY(Replicate);\n\n  ADD_OPERATOR_TO_REGISTRY(In);\n  ADD_OPERATOR_TO_REGISTRY(Filter);\n\n  ADD_OPERATOR_TO_REGISTRY(MakeShare);\n  ADD_OPERATOR_TO_REGISTRY(MakePrivate);\n  ADD_OPERATOR_TO_REGISTRY(MakePublic);\n\n  ADD_OPERATOR_TO_REGISTRY(Add);\n  ADD_OPERATOR_TO_REGISTRY(Minus);\n  ADD_OPERATOR_TO_REGISTRY(Mul);\n  ADD_OPERATOR_TO_REGISTRY(Div);\n  ADD_OPERATOR_TO_REGISTRY(IntDiv);\n  ADD_OPERATOR_TO_REGISTRY(Mod);\n  ADD_OPERATOR_TO_REGISTRY(Pow);\n\n  ADD_OPERATOR_TO_REGISTRY(Equal);\n  ADD_OPERATOR_TO_REGISTRY(NotEqual);\n  ADD_OPERATOR_TO_REGISTRY(Less);\n  ADD_OPERATOR_TO_REGISTRY(LessEqual);\n  ADD_OPERATOR_TO_REGISTRY(GreaterEqual);\n  ADD_OPERATOR_TO_REGISTRY(Greater);\n  ADD_OPERATOR_TO_REGISTRY(Greatest);\n  ADD_OPERATOR_TO_REGISTRY(Least);\n\n  ADD_OPERATOR_TO_REGISTRY(Not);\n  ADD_OPERATOR_TO_REGISTRY(LogicalAnd);\n  ADD_OPERATOR_TO_REGISTRY(LogicalOr);\n\n  ADD_OPERATOR_TO_REGISTRY(Copy);\n\n  // aggregation\n  ADD_OPERATOR_TO_REGISTRY(ReduceSum);\n  ADD_OPERATOR_TO_REGISTRY(ReduceCount);\n  ADD_OPERATOR_TO_REGISTRY(ReduceAvg);\n  ADD_OPERATOR_TO_REGISTRY(ReduceMin);\n  ADD_OPERATOR_TO_REGISTRY(ReduceMax);\n  ADD_OPERATOR_TO_REGISTRY(ReducePercentileDisc);\n\n  ADD_OPERATOR_TO_REGISTRY(Shape);\n  ADD_OPERATOR_TO_REGISTRY(Limit);\n  ADD_OPERATOR_TO_REGISTRY(Unique);\n\n  ADD_OPERATOR_TO_REGISTRY(Sort);\n  ADD_OPERATOR_TO_REGISTRY(Shuffle);\n  ADD_OPERATOR_TO_REGISTRY(CaseWhen);\n\n  // private groupby\n  ADD_OPERATOR_TO_REGISTRY(Group);\n  ADD_OPERATOR_TO_REGISTRY(GroupFirstOf);\n  ADD_OPERATOR_TO_REGISTRY(GroupCountDistinct);\n  ADD_OPERATOR_TO_REGISTRY(GroupCount);\n  ADD_OPERATOR_TO_REGISTRY(GroupSum);\n  ADD_OPERATOR_TO_REGISTRY(GroupAvg);\n  ADD_OPERATOR_TO_REGISTRY(GroupMin);\n  ADD_OPERATOR_TO_REGISTRY(GroupMax);\n  ADD_OPERATOR_TO_REGISTRY(GroupSecretSum);\n  ADD_OPERATOR_TO_REGISTRY(GroupSecretAvg);\n  ADD_OPERATOR_TO_REGISTRY(GroupPercentileDisc);\n\n  // oblivious groupby\n  ADD_OPERATOR_TO_REGISTRY(ObliviousGroupMark);\n  ADD_OPERATOR_TO_REGISTRY(ObliviousGroupSum);\n  ADD_OPERATOR_TO_REGISTRY(ObliviousGroupCount);\n  ADD_OPERATOR_TO_REGISTRY(ObliviousGroupAvg);\n  ADD_OPERATOR_TO_REGISTRY(ObliviousGroupMax);\n  ADD_OPERATOR_TO_REGISTRY(ObliviousGroupMin);\n\n  ADD_OPERATOR_TO_REGISTRY(ObliviousPercentRank);\n  ADD_OPERATOR_TO_REGISTRY(ObliviousPercentileDisc);\n  ADD_OPERATOR_TO_REGISTRY(ObliviousRank);\n\n  ADD_OPERATOR_TO_REGISTRY(Concat);\n  ADD_OPERATOR_TO_REGISTRY(Cast);\n  ADD_OPERATOR_TO_REGISTRY(If);\n  ADD_OPERATOR_TO_REGISTRY(IfNull);\n  ADD_OPERATOR_TO_REGISTRY(IsNull);\n  ADD_OPERATOR_TO_REGISTRY(Coalesce);\n\n  ADD_OPERATOR_TO_REGISTRY(Sine);\n  ADD_OPERATOR_TO_REGISTRY(Cosine);\n  ADD_OPERATOR_TO_REGISTRY(ACosine);\n  ADD_OPERATOR_TO_REGISTRY(ASine);\n  ADD_OPERATOR_TO_REGISTRY(Tan);\n  ADD_OPERATOR_TO_REGISTRY(ATan);\n  ADD_OPERATOR_TO_REGISTRY(ATan2);\n\n  ADD_OPERATOR_TO_REGISTRY(Bucket);\n\n  ADD_OPERATOR_TO_REGISTRY(RowNumber);\n  ADD_OPERATOR_TO_REGISTRY(PercentRank);\n  ADD_OPERATOR_TO_REGISTRY(Rank);\n\n  ADD_OPERATOR_TO_REGISTRY(Abs);\n  ADD_OPERATOR_TO_REGISTRY(Ceil);\n  ADD_OPERATOR_TO_REGISTRY(Floor);\n  ADD_OPERATOR_TO_REGISTRY(Round);\n  ADD_OPERATOR_TO_REGISTRY(Radians);\n  ADD_OPERATOR_TO_REGISTRY(Degrees);\n  ADD_OPERATOR_TO_REGISTRY(Ln);\n  ADD_OPERATOR_TO_REGISTRY(Log10);\n  ADD_OPERATOR_TO_REGISTRY(Log2);\n  ADD_OPERATOR_TO_REGISTRY(Sqrt);\n  ADD_OPERATOR_TO_REGISTRY(Exp);\n\n  ADD_OPERATOR_TO_REGISTRY(ArrowFunc);\n}\n\n}  // namespace\n\nvoid RegisterAllOps() {\n  static std::once_flag flag;\n  std::call_once(flag, RegisterAllOpsImpl);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/all_ops_register.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/registry.h\"  // NOLINT\n\nnamespace scql::engine::op {\n\nvoid RegisterAllOps();\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/all_ops_register_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/all_ops_register.h\"\n\n#include \"gtest/gtest.h\"\n\nnamespace scql::engine::op {\n\nTEST(AllOpsRegisterTest, Works) {\n  const std::string test_op_type = \"FilterByIndex\";\n  auto op = GetOpRegistry()->GetOperator(test_op_type);\n  EXPECT_EQ(op, nullptr);\n\n  EXPECT_NO_THROW(RegisterAllOps());\n  EXPECT_NO_THROW(RegisterAllOps());\n\n  op = GetOpRegistry()->GetOperator(test_op_type);\n  EXPECT_NE(op, nullptr);\n  EXPECT_EQ(test_op_type, op->Type());\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/arithmetic.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/arithmetic.h\"\n\n#include \"arrow/compute/api_scalar.h\"\n#include \"arrow/compute/cast.h\"\n#include \"arrow/datum.h\"\n#include \"arrow/result.h\"\n#include \"libspu/kernel/hal/type_cast.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n\nnamespace scql::engine::op {\n\nvoid ArithmeticBase::ValidateIoDataTypes(ExecContext* ctx) {\n  // TODO(shunde.csd): check input and output data types for arithmetic ops\n}\n\n// ===========================\n//   Add impl\n// ===========================\n\nconst std::string Add::kOpType(\"Add\");\n\nconst std::string& Add::Type() const { return kOpType; }\n\nspu::Value Add::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                             const spu::Value& rhs) {\n  return spu::kernel::hlo::Add(sctx, lhs, rhs);\n}\n\nTensorPtr Add::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"add\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow add function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   Minus impl\n// ===========================\n\nconst std::string Minus::kOpType(\"Minus\");\n\nconst std::string& Minus::Type() const { return kOpType; }\n\nspu::Value Minus::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                               const spu::Value& rhs) {\n  return spu::kernel::hlo::Sub(sctx, lhs, rhs);\n}\n\nTensorPtr Minus::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"subtract\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow subtract function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   Mul impl\n// ===========================\n\nconst std::string Mul::kOpType(\"Mul\");\n\nconst std::string& Mul::Type() const { return kOpType; }\n\nspu::Value Mul::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                             const spu::Value& rhs) {\n  return spu::kernel::hlo::Mul(sctx, lhs, rhs);\n}\n\nTensorPtr Mul::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"multiply\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow multiply function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   Div impl\n// ===========================\n\nconst std::string Div::kOpType(\"Div\");\n\nconst std::string& Div::Type() const { return kOpType; }\n\nspu::Value Div::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                             const spu::Value& rhs) {\n  if (lhs.isInt() && rhs.isInt()) {\n    // if lhs and rhs are both integers, the result will be integer.\n    // so we convert lhs to float here.\n    const auto lhs_f = spu::kernel::hal::dtype_cast(sctx, lhs, spu::DT_F64);\n    return spu::kernel::hlo::Div(sctx, lhs_f, rhs);\n  }\n  return spu::kernel::hlo::Div(sctx, lhs, rhs);\n}\n\nTensorPtr Div::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  // cast lhs to float64 if both lhs and rhs are integer\n  auto left = lhs.ToArrowChunkedArray();\n  auto right = rhs.ToArrowChunkedArray();\n  if (arrow::is_integer(left->type()->id()) &&\n      arrow::is_integer(right->type()->id())) {\n    auto cast_options =\n        arrow::compute::CastOptions::Safe(arrow::TypeHolder(arrow::float64()));\n    auto result = arrow::compute::Cast(left, cast_options);\n    YACL_ENFORCE(result.ok(), \"Fail to cast lhs type to float64: {}\",\n                 result.status().ToString());\n    left = result.ValueOrDie().chunked_array();\n  }\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::CallFunction(\"divide\", {left, right});\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow divide function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   IntDiv impl\n// ===========================\n\nconst std::string IntDiv::kOpType(\"IntDiv\");\n\nconst std::string& IntDiv::Type() const { return kOpType; }\n\nspu::Value IntDiv::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                                const spu::Value& rhs) {\n  // NOTE(shunde.csd): if lhs and rhs are both integers,\n  // `spu::kernel::hlo::Div` will behave like `IntDiv`\n  return spu::kernel::hlo::Div(sctx, lhs, rhs);\n}\n\nTensorPtr IntDiv::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  // NOTE(shunde.csd): if lhs and rhs are both integers,\n  // arrow `divide` function will behave like `IntDiv`\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"divide\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow divide function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   Mod impl\n// ===========================\n\nconst std::string Mod::kOpType(\"Mod\");\n\nconst std::string& Mod::Type() const { return kOpType; }\n\nspu::Value Mod::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                             const spu::Value& rhs) {\n  YACL_ENFORCE(lhs.isInt(), \"op {} left data type is not integer\", Type());\n  YACL_ENFORCE(rhs.isInt(), \"op {} right data type is not integer\", Type());\n  return spu::kernel::hlo::Remainder(sctx, lhs, rhs);\n}\n\nTensorPtr Mod::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  auto left = lhs.ToArrowChunkedArray();\n  auto right = rhs.ToArrowChunkedArray();\n  YACL_ENFORCE(arrow::is_integer(left->type()->id()),\n               \"op {} left data type is not integer\", Type());\n  YACL_ENFORCE(arrow::is_integer(right->type()->id()),\n               \"op {} right data type is not integer\", Type());\n\n  auto div_result = arrow::compute::CallFunction(\"divide\", {left, right});\n  YACL_ENFORCE(div_result.ok(),\n               \"caught error while invoking arrow divide function: {}\",\n               div_result.status().ToString());\n\n  auto div_chunk_arr = div_result.ValueOrDie().chunked_array();\n  auto mul_result =\n      arrow::compute::CallFunction(\"multiply\", {div_chunk_arr, right});\n  YACL_ENFORCE(mul_result.ok(),\n               \"caught error while invoking arrow multiply function: {}\",\n               mul_result.status().ToString());\n\n  auto mul_chunk_arr = mul_result.ValueOrDie().chunked_array();\n  auto result = arrow::compute::CallFunction(\"subtract\", {left, mul_chunk_arr});\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow subtract function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   Pow impl\n// ===========================\nconst std::string Pow::kOpType(\"Pow\");\nconst std::string& Pow::Type() const { return kOpType; }\n\nspu::Value Pow::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                             const spu::Value& rhs) {\n  return spu::kernel::hlo::Power(sctx, lhs, rhs);\n}\n\nTensorPtr Pow::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  auto left = lhs.ToArrowChunkedArray();\n  auto right = rhs.ToArrowChunkedArray();\n\n  auto result = arrow::compute::Power(left, right);\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow pow function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/arithmetic.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/operator/binary_base.h\"\n\nnamespace scql::engine::op {\n\n/// @brief ArithmeticBase is base class of operator {+/-/*/DIV/INTDIV/MOD}\nclass ArithmeticBase : public BinaryBase {\n protected:\n  void ValidateIoDataTypes(ExecContext* ctx) override;\n};\n\nclass Add : public ArithmeticBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass Minus : public ArithmeticBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass Mul : public ArithmeticBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass Div : public ArithmeticBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass IntDiv : public ArithmeticBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass Mod : public ArithmeticBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass Pow : public ArithmeticBase {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/arithmetic_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/arithmetic.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/operator/binary_test.h\"\n\nnamespace scql::engine::op {\n\n// TODO: add more test values\nINSTANTIATE_TEST_SUITE_P(\n    ArithmeticBatchTest, BinaryComputeInSecretTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = Add::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1,2,3]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[1,2,3]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[2,4,6]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Minus::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[100,123,999]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[-1,100,1000]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[101,23,-1]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Mul::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[100,123,12]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[-1,100,12]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\n                    \"z\", TensorFrom(arrow::int64(), \"[-100,12300,144]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Div::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[100,9]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[3,3]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::float64(),\n                                                              \"[33.33,3.0]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = IntDiv::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[100,9,5,5,3]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[3,3,2,3,2]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[33,3,2,1,1]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Mod::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(),\n                                    \"[100,9,5,-100,-9,-5,100,9,5,-100,-9,-\"\n                                    \"5]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(),\n                                    \"[33,3,5,33,3,5,-33,-3,-5,-33,-3,-5]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\n                    \"z\",\n                    TensorFrom(arrow::int64(), \"[1,0,0,-1,0,0,1,0,0,-1,0,0]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Pow::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1,2,3]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[2,2,2]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[1,4,9]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            // testcase with empty inputs\n            BinaryTestCase{\n                .op_type = Add::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Minus::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Mul::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Div::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::float64(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = IntDiv::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Mod::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Pow::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            })),\n    TestParamNameGenerator(BinaryComputeInSecretTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    ArithmeticBatchTest, BinaryComputeInPlainTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = Add::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1,2,3]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[1,null,3]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[2,null,6]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = Minus::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[100,123,999,4,null]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[-1,100,1000,null,5]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\", TensorFrom(arrow::int64(), \"[101,23,-1,null,null]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = Mul::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[100,123,12,4,null]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[-1,100,12,null,5]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\",\n                    TensorFrom(arrow::int64(), \"[-100,12300,144,null,null]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = Div::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float64(), \"[100.0,9,4,null]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[3,3,null,5]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\",\n                    TensorFrom(arrow::float64(), \"[33.33333333,3,null,null]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = IntDiv::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[100,9,5,4,null]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[3,3,2,null,5]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\", TensorFrom(arrow::int64(), \"[33,3,2,null,null]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = Mod::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(),\n                                    \"[100,9,5,-100,-9,-5,100,9,5,-100,-9,-\"\n                                    \"5,null,1,null]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\",\n                    TensorFrom(\n                        arrow::int64(),\n                        \"[33,3,5,33,3,5,-33,-3,-5,-33,-3,-5,1,null,null]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\",\n                    TensorFrom(arrow::int64(),\n                               \"[1,0,0,-1,0,0,1,0,0,-1,0,0,null,null,null]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = Pow::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1,2,3,4]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[2,2,2,null]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[1,4,9,null]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            })),\n    TestParamNameGenerator(BinaryComputeInPlainTest));\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/arrow_func.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/arrow_func.h\"\n\n#include \"absl/strings/escaping.h\"\n#include \"arrow/compute/api.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string ArrowFunc::kOpType(\"ArrowFunc\");\n\nconst std::string& ArrowFunc::Type() const { return kOpType; }\n\nvoid ArrowFunc::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(outputs.size() > 0, \"ArrowFunc output size must > 0\");\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   inputs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"ArrowFunc input tensors' status should be private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   outputs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"ArrowFunc output tensors' status should be private\");\n}\n\nvoid ArrowFunc::Execute(ExecContext* ctx) {\n  auto func_name = ctx->GetStringValueFromAttribute(kFuncNameAttr);\n  auto func_opt_type = ctx->TryGetStringValueFromAttribute(kFuncOptTypeAttr);\n\n  auto input_tensors = ctx->GetInputTensors(kIn);\n  std::vector<arrow::Datum> inputs;\n  inputs.reserve(input_tensors.size());\n  for (const auto& input_tensor : input_tensors) {\n    inputs.emplace_back(input_tensor->ToArrowChunkedArray());\n  }\n\n  arrow::Result<arrow::Datum> result;\n  if (func_opt_type.has_value()) {\n    std::string func_opt_decoded;\n    YACL_ENFORCE(\n        absl::Base64Unescape(ctx->GetStringValueFromAttribute(kFuncOptionsAttr),\n                             &func_opt_decoded),\n        \"Base64 decode arrow func options failed\");\n    std::unique_ptr<arrow::compute::FunctionOptions> opt;\n    ASSIGN_OR_THROW_ARROW_STATUS(\n        opt, arrow::compute::FunctionOptions::Deserialize(\n                 func_opt_type.value(), arrow::Buffer(func_opt_decoded)));\n    result = arrow::compute::CallFunction(func_name, inputs, opt.get());\n  } else {\n    result = arrow::compute::CallFunction(func_name, inputs);\n  }\n\n  YACL_ENFORCE(result.ok(), \"invoking arrow func '{}' caught error: {}\",\n               func_name, result.status().ToString());\n\n  const auto& val = result.ValueOrDie();\n  YACL_ENFORCE(val.is_chunked_array(),\n               \"unsupported arrow func result type: {}, func_name: {}\",\n               arrow::ToString(val.kind()), func_name);\n\n  const auto& arr = val.chunked_array();\n\n  if (func_name == \"strptime\") {\n    ctx->SetOutputTensor(kOut, util::ConvertDateTimeToInt64(arr));\n  } else {\n    ctx->SetOutputTensor(kOut, TensorFrom(arr));\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/arrow_func.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass ArrowFunc : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kFuncNameAttr[] = \"func_name\";\n  static constexpr char kFuncOptTypeAttr[] = \"func_opt_type\";\n  static constexpr char kFuncOptionsAttr[] = \"func_options\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/arrow_func_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/arrow_func.h\"\n\n#include \"absl/strings/escaping.h\"\n#include \"arrow/compute/api.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct ArrowFuncTestCase {\n  std::vector<test::NamedTensor> ins;\n  std::string func_name;\n  std::shared_ptr<arrow::compute::FunctionOptions> func_opt;\n  std::vector<test::NamedTensor> expect_outs;\n};\n\nclass ArrowFuncTest\n    : public testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, ArrowFuncTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const ArrowFuncTestCase& tc);\n  static void FeedInputs(ExecContext* ctx, const ArrowFuncTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    ArrowFuncBatchTest, ArrowFuncTest,\n    testing::Combine(\n        testing::Values(test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2}),\n        testing::Values(\n            ArrowFuncTestCase{\n                .ins = {test::NamedTensor(\n                    \"in0\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"A\", \"B\", \"\"])json\")),test::NamedTensor(\n                    \"in1\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"\", \"2\", \"3\"])json\")),test::NamedTensor(\n                    \"sep\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"*\", \"?\", \"\"])json\"))},\n                .func_name = \"binary_join_element_wise\",\n                .expect_outs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"A*\", \"B?2\", \"3\"])json\"))}},\n            ArrowFuncTestCase{\n                .ins = {test::NamedTensor(\n                    \"in_date_str\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"2024-06-18\", null, \"2025-01-01\", \"invalid-date\"])json\"))},\n                .func_name = \"strptime\",\n                .func_opt = std::make_shared<arrow::compute::StrptimeOptions>(\n                    \"%Y-%m-%d\",\n                    arrow::TimeUnit::SECOND,\n                    true),\n                .expect_outs = {test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::int64(),\n                               R\"json([1718668800, null, 1735689600, null])json\"))}},\n            ArrowFuncTestCase{\n                .ins = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"alice  \", \"  Bob\", \" CAROL \",\n                        \" \"])json\"))},\n                .func_name = \"utf8_trim\",\n                .func_opt = std::make_shared<arrow::compute::TrimOptions>(\" \"),\n                .expect_outs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"alice\", \"Bob\", \"CAROL\",\n                        \"\"])json\"))}},\n            ArrowFuncTestCase{\n                .ins = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"alice\", \"Bob\", \"CAROL\",\n                        \"AA#Bb.cc\"])json\"))},\n                .func_name = \"utf8_slice_codeunits\",\n                .func_opt = std::make_shared<arrow::compute::SliceOptions>(4 /* start */, 10 /* stop */,\n                                           1 /* step */),\n                .expect_outs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"e\", \"\", \"L\",\n                        \"b.cc\"])json\"))}},\n            ArrowFuncTestCase{\n                .ins = {test::NamedTensor(\n                    \"in\",\n                    TensorFrom(\n                        arrow::large_utf8(),\n                        R\"json([\"alice\", \"Bob\", \"CAROL\", \"AA#Bb.cc\"])json\"))},\n                .func_name = \"utf8_lower\",\n                .expect_outs = {test::NamedTensor(\n                    \"out\",\n                    TensorFrom(\n                        arrow::large_utf8(),\n                        R\"json([\"alice\", \"bob\", \"carol\", \"aa#bb.cc\"])json\"))}},\n            ArrowFuncTestCase{\n                .ins = {test::NamedTensor(\n                    \"in\",\n                    TensorFrom(\n                        arrow::large_utf8(),\n                        R\"json([\"alice\", \"Bob\", \"CAROL\", \"AA#Bb.cc\"])json\"))},\n                .func_name = \"utf8_upper\",\n                .expect_outs = {test::NamedTensor(\n                    \"out\",\n                    TensorFrom(\n                        arrow::large_utf8(),\n                        R\"json([\"ALICE\", \"BOB\", \"CAROL\", \"AA#BB.CC\"])json\"))}},\n            ArrowFuncTestCase{\n                .ins = {test::NamedTensor(\"in0\", TensorFrom(arrow::float64(),\n                                                            \"[null, 2.4]\")),\n                        test::NamedTensor(\"in1\", TensorFrom(arrow::float64(),\n                                                            \"[2.4, 100100]\"))},\n                .func_name = \"multiply\",\n                .expect_outs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[null, 240240]\"))}},\n            ArrowFuncTestCase{\n                .ins = {test::NamedTensor(\n                    \"in\",\n                    TensorFrom(arrow::float64(), \"[1.3, null, 2.4, null]\"))},\n                .func_name = \"is_null\",\n                .expect_outs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::boolean(), \"[0, 1, 0, 1]\"))}})),\n    TestParamNameGenerator(ArrowFuncTest));\n\nTEST_P(ArrowFuncTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto session = test::Make1PCSession();\n  ExecContext ctx(node, session.get());\n\n  FeedInputs(&ctx, tc);\n\n  // When\n  ArrowFunc op;\n  ASSERT_NO_THROW(op.Run(&ctx));\n\n  // Then\n  // check alice output\n  for (auto& out : tc.expect_outs) {\n    TensorPtr t = session->GetTensorTable()->GetTensor(out.name);\n    ASSERT_TRUE(t);\n    auto out_arr = t->ToArrowChunkedArray();\n\n    auto expect_arr = out.tensor->ToArrowChunkedArray();\n\n    // compare tensor content\n    EXPECT_TRUE(out_arr->Equals(expect_arr))\n        << \"expect type = \" << expect_arr->type()->ToString()\n        << \", got type = \" << out_arr->type()->ToString()\n        << \"\\nexpect result = \" << expect_arr->ToString()\n        << \"\\nbut actual got result = \" << out_arr->ToString();\n  }\n}\n\n/// ===================\n/// ArrowFuncTest impl\n/// ===================\n\npb::ExecNode ArrowFuncTest::MakeExecNode(const ArrowFuncTestCase& tc) {\n  test::ExecNodeBuilder builder(ArrowFunc::kOpType);\n  builder.SetNodeName(\"arrow-func-test\");\n  builder.AddStringAttr(ArrowFunc::kFuncNameAttr, tc.func_name);\n  if (tc.func_opt != nullptr) {\n    builder.AddStringAttr(ArrowFunc::kFuncOptTypeAttr,\n                          tc.func_opt->type_name());\n    std::shared_ptr<arrow::Buffer> buf;\n    ASSIGN_OR_THROW_ARROW_STATUS(buf, tc.func_opt->Serialize());\n    builder.AddStringAttr(ArrowFunc::kFuncOptionsAttr,\n                          absl::Base64Escape(buf->ToString()));\n  }\n\n  std::vector<pb::Tensor> inputs;\n  for (auto& in : tc.ins) {\n    auto t = test::MakePrivateTensorReference(in.name, in.tensor->Type());\n    inputs.push_back(t);\n  }\n  builder.AddInput(ArrowFunc::kIn, inputs);\n\n  std::vector<pb::Tensor> outputs;\n  for (auto& out : tc.expect_outs) {\n    auto t = test::MakePrivateTensorReference(out.name, out.tensor->Type());\n    outputs.push_back(t);\n  }\n  builder.AddOutput(ArrowFunc::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid ArrowFuncTest::FeedInputs(ExecContext* ctx, const ArrowFuncTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, tc.ins);\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/binary_base.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/binary_base.h\"\n\n#include \"libspu/kernel/hlo/basic_binary.h\"\n\n#include \"engine/util/context_util.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nvoid BinaryBase::Validate(ExecContext* ctx) {\n  const auto& left = ctx->GetInput(kInLeft);\n  const auto& right = ctx->GetInput(kInRight);\n  const auto& out = ctx->GetOutput(kOut);\n  YACL_ENFORCE(left.size() == right.size(),\n               \"op {} input left and right must have the same size\", Type());\n  YACL_ENFORCE(out.size() == left.size(),\n               \"op {} output must have the same size as input\", Type());\n\n  auto left_input_status = util::GetTensorStatus(left[0]);\n  YACL_ENFORCE(util::AreTensorsStatusMatched(left, left_input_status),\n               \"op {} input left should have the same status\", Type());\n\n  switch (left_input_status) {\n    case pb::TENSORSTATUS_PRIVATE: {\n      YACL_ENFORCE(util::AreTensorsStatusEqualAndOneOf(\n          right, {pb::TENSORSTATUS_PRIVATE, pb::TENSORSTATUS_PUBLIC}));\n      YACL_ENFORCE(\n          util::AreTensorsStatusMatched(out, pb::TENSORSTATUS_PRIVATE));\n      break;\n    }\n    case pb::TENSORSTATUS_SECRET: {\n      YACL_ENFORCE(util::AreTensorsStatusEqualAndOneOf(\n          right, {pb::TENSORSTATUS_SECRET, pb::TENSORSTATUS_PUBLIC}));\n      YACL_ENFORCE(util::AreTensorsStatusMatched(out, pb::TENSORSTATUS_SECRET));\n      break;\n    }\n    case pb::TENSORSTATUS_PUBLIC: {\n      YACL_ENFORCE(util::AreTensorsStatusEqualAndOneOf(\n          right, {pb::TENSORSTATUS_SECRET, pb::TENSORSTATUS_PRIVATE}));\n      if (util::IsTensorStatusMatched(right[0], pb::TENSORSTATUS_SECRET)) {\n        YACL_ENFORCE(\n            util::AreTensorsStatusMatched(out, pb::TENSORSTATUS_SECRET));\n      } else {\n        YACL_ENFORCE(\n            util::AreTensorsStatusMatched(out, pb::TENSORSTATUS_PRIVATE));\n      }\n      break;\n    }\n    default:\n      YACL_THROW(\"unsupported input status: {}\",\n                 pb::TensorStatus_Name(util::GetTensorStatus(left[0])));\n  }\n  ValidateIoDataTypes(ctx);\n}\n\nvoid BinaryBase::Execute(ExecContext* ctx) {\n  if (ctx->GetOutputStatus(kOut) == pb::TENSORSTATUS_PRIVATE) {\n    ExecuteInPlain(ctx);\n  } else {\n    ExecuteInSecret(ctx);\n  }\n}\n\nvoid BinaryBase::ExecuteInSecret(ExecContext* ctx) {\n  const auto& left_inputs = ctx->GetInputValues(kInLeft);\n  const auto& right_inputs = ctx->GetInputValues(kInRight);\n\n  // TODO(shunde.csd): possible optimization\n  // maybe we should concatenate values together to reduce communication\n  // round-trip\n  for (int i = 0; i < left_inputs.size(); ++i) {\n    auto result_value = ComputeOnSpu(ctx->GetSession()->GetSpuContext(),\n                                     left_inputs[i], right_inputs[i]);\n    ctx->SetOutputValue(kOut, result_value, i);\n\n#ifdef SCQL_WITH_NULL\n    auto left_validity = ctx->GetInputValidity(kInLeft, i);\n    auto right_validity = ctx->GetInputValidity(kInRight, i);\n    auto result_validity = PropagateNulls(left_validity, right_validity);\n    ctx->SetOutputValidity(kOut, result_validity, i);\n#endif  // SCQL_WITH_NULL\n  }\n}\n\nvoid BinaryBase::ExecuteInPlain(ExecContext* ctx) {\n  const auto& left_pbs = ctx->GetInput(kInLeft);\n  const auto& right_pbs = ctx->GetInput(kInRight);\n  const auto& out_pbs = ctx->GetOutput(kOut);\n\n  for (int i = 0; i < left_pbs.size(); ++i) {\n    const auto& left_param = left_pbs[i];\n    const auto& right_param = right_pbs[i];\n    const auto& out_param = out_pbs[i];\n\n    TensorPtr left = ctx->GetPrivateOrPublicTensor(left_param);\n    TensorPtr right = ctx->GetPrivateOrPublicTensor(right_param);\n    YACL_ENFORCE(left != nullptr);\n    YACL_ENFORCE(right != nullptr);\n\n    auto result = ComputeInPlain(*left, *right);\n    ctx->SetOutputTensor(kOut, std::move(result), i);\n  }\n}\n\nspu::Value BinaryBase::PropagateNulls(spu::SPUContext* sctx,\n                                      const spu::Value& lhs,\n                                      const spu::Value& rhs) {\n  return spu::kernel::hlo::And(sctx, lhs, rhs);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/binary_base.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/// @brief base class for binary operators.\n/// <Out> = <Left> op <Right>\n///\n/// Input and Output status relationship:\n///   - If <Left> is private, <Right> could be private or public, <Out> status\n///   would be private too.\n///   - If <Left> is secret, <Right> could be secret or public, <Out> status\n///   would be secret too.\n///   - If <Left> is public, <Right> could be private or secret, <Out> status\n///   would be the same as <Right>.\nclass BinaryBase : public Operator {\n public:\n  static constexpr char kInLeft[] = \"Left\";\n  static constexpr char kInRight[] = \"Right\";\n  static constexpr char kOut[] = \"Out\";\n\n protected:\n  void Validate(ExecContext* ctx) override;\n\n  void Execute(ExecContext* ctx) override;\n\n  // validate input/output data types\n  virtual void ValidateIoDataTypes(ExecContext* ctx) = 0;\n\n  void ExecuteInSecret(ExecContext* ctx);\n\n  void ExecuteInPlain(ExecContext* ctx);\n\n  virtual TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) = 0;\n\n  virtual spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                                  const spu::Value& rhs) = 0;\n\n  // propagate nulls for arithmetic op\n  static spu::Value PropagateNulls(spu::SPUContext* sctx, const spu::Value& lhs,\n                                   const spu::Value& rhs);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/binary_test.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"arrow/type.h\"  // NOLINT\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"  // NOLINT\n#include \"engine/operator/all_ops_register.h\"\n#include \"engine/operator/binary_base.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct BinaryTestCase {\n  std::string op_type;\n\n  std::vector<test::NamedTensor> left_inputs;\n  pb::TensorStatus left_input_status;\n\n  std::vector<test::NamedTensor> right_inputs;\n  pb::TensorStatus right_input_status;\n\n  std::vector<test::NamedTensor> outputs;\n  pb::TensorStatus output_status;\n};\n\nclass BinaryTest : public testing::TestWithParam<\n                       std::tuple<test::SpuRuntimeTestCase, BinaryTestCase>> {\n protected:\n  void SetUp() override { RegisterAllOps(); }\n\n public:\n  static pb::ExecNode MakeExecNode(const BinaryTestCase& tc);\n\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const BinaryTestCase& tc);\n\n  static std::unique_ptr<Operator> CreateOp(const std::string& op_type);\n};\n\nclass BinaryComputeInSecretTest : public BinaryTest {};\nclass BinaryComputeInPlainTest : public BinaryTest {};\n\nTEST_P(BinaryComputeInSecretTest, Works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  EXPECT_NO_THROW(\n      test::RunOpAsync(ctx_ptrs, [&]() { return CreateOp(node.op_type()); }));\n\n  for (const auto& named_tensor : tc.outputs) {\n    TensorPtr t = nullptr;\n    EXPECT_NO_THROW({ t = test::RevealSecret(ctx_ptrs, named_tensor.name); });\n    ASSERT_TRUE(t != nullptr);\n    EXPECT_TRUE(t->ToArrowChunkedArray()->ApproxEquals(\n        *named_tensor.tensor->ToArrowChunkedArray(),\n        arrow::EqualOptions::Defaults().atol(0.05)))\n        << \"expect type = \"\n        << named_tensor.tensor->ToArrowChunkedArray()->type()->ToString()\n        << \", got type = \" << t->ToArrowChunkedArray()->type()->ToString()\n        << \"\\nexpect result = \"\n        << named_tensor.tensor->ToArrowChunkedArray()->ToString()\n        << \"\\nbut actual got result = \" << t->ToArrowChunkedArray()->ToString();\n  }\n}\n\nTEST_P(BinaryComputeInPlainTest, Works) {\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  auto alice_op = CreateOp(node.op_type());\n  ASSERT_TRUE(alice_op != nullptr)\n      << \"failed to create operator for op_type = \" << node.op_type();\n\n  // Then\n  EXPECT_NO_THROW({ alice_op->Run(ctx_ptrs[0]); });\n\n  auto* tensor_table = ctx_ptrs[0]->GetTensorTable();\n  for (const auto& named_tensor : tc.outputs) {\n    auto t = tensor_table->GetTensor(named_tensor.name);\n    EXPECT_TRUE(t != nullptr) << named_tensor.name << \" not found\";\n\n    EXPECT_TRUE(t->ToArrowChunkedArray()->ApproxEquals(\n        *named_tensor.tensor->ToArrowChunkedArray()))\n        << \"expect type = \"\n        << named_tensor.tensor->ToArrowChunkedArray()->type()->ToString()\n        << \", got type = \" << t->ToArrowChunkedArray()->type()->ToString()\n        << \"\\nexpect result = \"\n        << named_tensor.tensor->ToArrowChunkedArray()->ToString()\n        << \"\\nbut actual got result = \" << t->ToArrowChunkedArray()->ToString();\n  }\n}\n\n// ==========================\n// BinaryTest impl\n// ==========================\n\npb::ExecNode BinaryTest::MakeExecNode(const BinaryTestCase& tc) {\n  test::ExecNodeBuilder builder(tc.op_type);\n\n  builder.SetNodeName(tc.op_type + \"-test\");\n\n  auto build_io = [](const std::vector<test::NamedTensor>& ts,\n                     pb::TensorStatus visibility) -> std::vector<pb::Tensor> {\n    std::vector<pb::Tensor> tensors;\n    for (const auto& named_tensor : ts) {\n      auto t = test::MakeTensorReference(\n          named_tensor.name, named_tensor.tensor->Type(), visibility);\n      tensors.push_back(std::move(t));\n    }\n    return tensors;\n  };\n\n  builder.AddInput(BinaryBase::kInLeft,\n                   build_io(tc.left_inputs, tc.left_input_status));\n  builder.AddInput(BinaryBase::kInRight,\n                   build_io(tc.right_inputs, tc.right_input_status));\n  builder.AddOutput(BinaryBase::kOut, build_io(tc.outputs, tc.output_status));\n\n  return builder.Build();\n}\n\nvoid BinaryTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                            const BinaryTestCase& tc) {\n  auto infeed = [](const std::vector<ExecContext*>& ctxs,\n                   pb::TensorStatus input_status,\n                   const std::vector<test::NamedTensor>& inputs) {\n    if (input_status == pb::TENSORSTATUS_PRIVATE) {\n      // feed private inputs into ctxs[0]\n      test::FeedInputsAsPrivate(ctxs[0], inputs);\n    } else if (input_status == pb::TENSORSTATUS_SECRET) {\n      test::FeedInputsAsSecret(ctxs, inputs);\n    } else {\n      test::FeedInputsAsPublic(ctxs, inputs);\n    }\n  };\n\n  infeed(ctxs, tc.left_input_status, tc.left_inputs);\n  infeed(ctxs, tc.right_input_status, tc.right_inputs);\n}\n\nstd::unique_ptr<Operator> BinaryTest::CreateOp(const std::string& op_type) {\n  return GetOpRegistry()->GetOperator(op_type);\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/broadcast_to.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/broadcast_to.h\"\n\n#include \"libspu/device/symbol_table.h\"\n#include \"libspu/kernel/hal/shape_ops.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string BroadcastTo::kOpType(\"BroadcastTo\");\n\nconst std::string& BroadcastTo::Type() const { return kOpType; }\n\nvoid BroadcastTo::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& ref_tensors = ctx->GetInput(kShapeRefTensor);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() > 0, \"BroadcastTo input size must > 0\");\n  YACL_ENFORCE(ref_tensors.size() == 1,\n               \"BroadcastTo ref_tensor size must == 1\");\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"BroadcastTo input {} and output {} should have the same size\",\n               kIn, kOut);\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(inputs, pb::TENSORSTATUS_PUBLIC),\n               \"BroadcastTo inputs' statuses must be public\");\n  auto ref_tensor_status = util::GetTensorStatus(ref_tensors[0]);\n  if (ref_tensor_status == pb::TENSORSTATUS_PRIVATE) {\n    YACL_ENFORCE(\n        util::AreTensorsStatusMatched(outputs, pb::TENSORSTATUS_PRIVATE),\n        \"BroadcastTo outputs' statuses must be private when ref_tensor is \"\n        \"private\");\n  } else {\n    YACL_ENFORCE(\n        util::AreTensorsStatusMatched(outputs, pb::TENSORSTATUS_PUBLIC),\n        \"BroadcastTo outputs' statuses must be public when ref_tensor is \"\n        \"not private\");\n  }\n}\n\nvoid BroadcastTo::Execute(ExecContext* ctx) {\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  const auto& ref_pb = ctx->GetInput(kShapeRefTensor)[0];\n  if (util::GetTensorStatus(ref_pb) == pb::TENSORSTATUS_PRIVATE) {\n    auto ref_tensor = ctx->GetTensorTable()->GetTensor(ref_pb.name());\n    YACL_ENFORCE(ref_tensor, \"get private shape ref tensor {} failed\",\n                 ref_pb.name());\n\n    return BroadcastToPrivate(ctx, input_pbs, output_pbs, ref_tensor->Length());\n  } else {\n    const auto ref_tensor_name =\n        util::SpuVarNameEncoder::GetValueName(ref_pb.name());\n    auto symbols = ctx->GetSession()->GetDeviceSymbols();\n    auto ref_tensor = symbols->getVar(ref_tensor_name);\n    auto to_length = ref_tensor.shape().size() > 0 ? ref_tensor.shape()[0]\n                                                   : ref_tensor.numel();\n    return BroadcastToPublic(ctx, input_pbs, output_pbs, to_length);\n  }\n}\n\nvoid BroadcastTo::BroadcastToPrivate(ExecContext* ctx,\n                                     const RepeatedPbTensor& input_pbs,\n                                     const RepeatedPbTensor& output_pbs,\n                                     const int64_t to_length) {\n  auto spu_io = util::SpuOutfeedHelper(ctx->GetSession()->GetSpuContext(),\n                                       ctx->GetSession()->GetDeviceSymbols());\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    auto ret = spu_io.DumpPublic(input_pbs[i].name());\n    YACL_ENFORCE(ret, \"dump public for {} failed\", input_pbs[i].name());\n    // convert hash to string for string tensor in spu\n    if (input_pbs[i].elem_type() == pb::PrimitiveDataType::STRING) {\n      ret = ctx->GetSession()->HashToString(*ret);\n    }\n\n    std::shared_ptr<arrow::Scalar> scalar;\n    ASSIGN_OR_THROW_ARROW_STATUS(scalar,\n                                 ret->ToArrowChunkedArray()->GetScalar(0));\n\n    std::shared_ptr<arrow::Array> array;\n    ASSIGN_OR_THROW_ARROW_STATUS(\n        array, arrow::MakeArrayFromScalar(*scalar, to_length));\n\n    auto chunked_arr = std::make_shared<arrow::ChunkedArray>(array);\n    ctx->GetTensorTable()->AddTensor(output_pbs[i].name(),\n                                     TensorFrom(chunked_arr));\n  }\n}\n\nvoid BroadcastTo::BroadcastToPublic(ExecContext* ctx,\n                                    const RepeatedPbTensor& input_pbs,\n                                    const RepeatedPbTensor& output_pbs,\n                                    const int64_t to_length) {\n  auto* symbols = ctx->GetSession()->GetDeviceSymbols();\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    const auto value_name =\n        util::SpuVarNameEncoder::GetValueName(input_pbs[i].name());\n    auto value = symbols->getVar(value_name);\n\n    auto result = spu::kernel::hal::broadcast_to(sctx, value, {to_length});\n\n    symbols->setVar(util::SpuVarNameEncoder::GetValueName(output_pbs[i].name()),\n                    result);\n  }\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/broadcast_to.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass BroadcastTo : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kShapeRefTensor[] = \"ShapeRefTensor\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static void BroadcastToPrivate(ExecContext* ctx,\n                                 const RepeatedPbTensor& input_pbs,\n                                 const RepeatedPbTensor& output_pbs,\n                                 int64_t to_length);\n\n  static void BroadcastToPublic(ExecContext* ctx,\n                                const RepeatedPbTensor& input_pbs,\n                                const RepeatedPbTensor& output_pbs,\n                                int64_t to_length);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/broadcast_to_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/broadcast_to.h\"\n\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n#include \"engine/util/spu_io.h\"\n\nnamespace scql::engine::op {\n\nstruct BroadcastToTestCase {\n  std::vector<test::NamedTensor> inputs;\n  test::NamedTensor ref_tensor;\n  pb::TensorStatus ref_tensor_status;\n  std::vector<test::NamedTensor> expect_outs;\n};\n\nclass BroadcastToTest\n    : public testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, BroadcastToTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const BroadcastToTestCase& tc);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const BroadcastToTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    BroadcastToBatchTest, BroadcastToTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BroadcastToTestCase{\n                .inputs =\n                    {test::NamedTensor(\"a\", TensorFrom(arrow::int64(), \"[3]\")),\n                     test::NamedTensor(\"b\",\n                                       TensorFrom(arrow::float32(), \"[-3.14]\")),\n                     test::NamedTensor(\"c\",\n                                       TensorFrom(arrow::boolean(), \"[true]\")),\n                     test::NamedTensor(\"d\", TensorFrom(arrow::large_utf8(),\n                                                       R\"json([\"bob\"])json\"))},\n                .ref_tensor = test::NamedTensor(\n                    \"ref\", TensorFrom(arrow::int64(), \"[1, 2, 3]\")),\n                .ref_tensor_status = pb::TENSORSTATUS_PRIVATE,\n                .expect_outs =\n                    {test::NamedTensor(\"a_out\",\n                                       TensorFrom(arrow::int64(), \"[3, 3, 3]\")),\n                     test::NamedTensor(\"b_out\",\n                                       TensorFrom(arrow::float32(),\n                                                  \"[-3.14, -3.14, -3.14]\")),\n                     test::NamedTensor(\"c_out\",\n                                       TensorFrom(arrow::boolean(),\n                                                  \"[true, true, true]\")),\n                     test::NamedTensor(\n                         \"d_out\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"bob\",\"bob\",\"bob\"])json\"))}},\n            BroadcastToTestCase{\n                .inputs = {test::NamedTensor(\"a\",\n                                             TensorFrom(arrow::int64(), \"[3]\")),\n                           test::NamedTensor(\"b\", TensorFrom(arrow::float32(),\n                                                             \"[-3.14]\")),\n                           test::NamedTensor(\"c\", TensorFrom(arrow::boolean(),\n                                                             \"[true]\"))},\n                .ref_tensor = test::NamedTensor(\n                    \"ref\", TensorFrom(arrow::boolean(), \"[true, false, true]\")),\n                .ref_tensor_status = pb::TENSORSTATUS_PUBLIC,\n                .expect_outs =\n                    {test::NamedTensor(\"a_out\",\n                                       TensorFrom(arrow::int64(), \"[3, 3, 3]\")),\n                     test::NamedTensor(\"b_out\",\n                                       TensorFrom(arrow::float32(),\n                                                  \"[-3.14, -3.14, -3.14]\")),\n                     test::NamedTensor(\"c_out\",\n                                       TensorFrom(arrow::boolean(),\n                                                  \"[true, true, true]\"))}},\n            BroadcastToTestCase{\n                .inputs = {test::NamedTensor(\"a\",\n                                             TensorFrom(arrow::int64(), \"[3]\")),\n                           test::NamedTensor(\"b\", TensorFrom(arrow::float32(),\n                                                             \"[-3.14]\")),\n                           test::NamedTensor(\"c\", TensorFrom(arrow::boolean(),\n                                                             \"[true]\"))},\n                .ref_tensor = test::NamedTensor(\n                    \"ref\", TensorFrom(arrow::boolean(), \"[true, false, true]\")),\n                .ref_tensor_status = pb::TENSORSTATUS_SECRET,\n                .expect_outs =\n                    {test::NamedTensor(\"a_out\",\n                                       TensorFrom(arrow::int64(), \"[3, 3, 3]\")),\n                     test::NamedTensor(\"b_out\",\n                                       TensorFrom(arrow::float32(),\n                                                  \"[-3.14, -3.14, -3.14]\")),\n                     test::NamedTensor(\"c_out\",\n                                       TensorFrom(arrow::boolean(),\n                                                  \"[true, true, true]\"))}})),\n    TestParamNameGenerator(BroadcastToTest));\n\nTEST_P(BroadcastToTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  BroadcastTo op;\n  EXPECT_NO_THROW(op.Run(exec_ctxs.data()));\n\n  // Then\n  // check alice output\n  for (const auto& expect_t : tc.expect_outs) {\n    TensorPtr actual_out;\n    if (tc.ref_tensor_status == pb::TENSORSTATUS_PRIVATE) {\n      actual_out = exec_ctxs[0].GetTensorTable()->GetTensor(expect_t.name);\n    } else {\n      auto* sctx = exec_ctxs[0].GetSession()->GetSpuContext();\n      auto* device_symbols = exec_ctxs[0].GetSession()->GetDeviceSymbols();\n      util::SpuOutfeedHelper outfeed_helper(sctx, device_symbols);\n\n      actual_out = outfeed_helper.DumpPublic(expect_t.name);\n    }\n    ASSERT_TRUE(actual_out);\n    auto actual_arr = actual_out->ToArrowChunkedArray();\n\n    auto expect_arr = expect_t.tensor->ToArrowChunkedArray();\n    // compare tensor content\n    EXPECT_TRUE(actual_arr->ApproxEquals(*expect_arr))\n        << \"expect type = \" << expect_arr->type()->ToString()\n        << \", got type = \" << actual_arr->type()->ToString()\n        << \"\\nexpect result = \" << expect_arr->ToString()\n        << \"\\nbut actual got result = \" << actual_arr->ToString();\n  }\n}\n\n/// ===================\n/// BroadcastToTest impl\n/// ===================\n\npb::ExecNode BroadcastToTest::MakeExecNode(const BroadcastToTestCase& tc) {\n  test::ExecNodeBuilder builder(BroadcastTo::kOpType);\n\n  builder.SetNodeName(\"broadcast-to-test\");\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    auto t = test::MakeTensorReference(named_tensor.name,\n                                       named_tensor.tensor->Type(),\n                                       pb::TENSORSTATUS_PUBLIC);\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(BroadcastTo::kIn, inputs);\n  {\n    auto t = test::MakeTensorReference(\n        tc.ref_tensor.name, tc.ref_tensor.tensor->Type(), tc.ref_tensor_status);\n    builder.AddInput(BroadcastTo::kShapeRefTensor, {t});\n  }\n\n  std::vector<pb::Tensor> outputs;\n  const auto& out_status = tc.ref_tensor_status == pb::TENSORSTATUS_PRIVATE\n                               ? pb::TENSORSTATUS_PRIVATE\n                               : pb::TENSORSTATUS_PUBLIC;\n  for (const auto& named_tensor : tc.expect_outs) {\n    auto t = test::MakeTensorReference(named_tensor.name,\n                                       named_tensor.tensor->Type(), out_status);\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(BroadcastTo::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid BroadcastToTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                                 const BroadcastToTestCase& tc) {\n  test::FeedInputsAsPublic(ctxs, tc.inputs);\n  if (tc.ref_tensor_status == pb::TENSORSTATUS_PRIVATE) {\n    test::FeedInputsAsPrivate(ctxs[0], {tc.ref_tensor});\n  } else if (tc.ref_tensor_status == pb::TENSORSTATUS_SECRET) {\n    test::FeedInputsAsSecret(ctxs, {tc.ref_tensor});\n  } else {\n    test::FeedInputsAsPublic(ctxs, {tc.ref_tensor});\n  }\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/bucket.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/bucket.h\"\n\n#include <atomic>\n#include <boost/container_hash/hash.hpp>\n#include <cstddef>\n#include <cstdint>\n#include <filesystem>\n#include <future>\n#include <memory>\n#include <optional>\n#include <queue>\n#include <string>\n\n#include \"arrow/array/concatenate.h\"\n#include \"arrow/compute/exec.h\"\n#include \"arrow/result.h\"\n#include \"spdlog/spdlog.h\"\n\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_batch_reader.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/core/type.h\"\n#include \"engine/util/concurrent_queue.h\"\n#include \"engine/util/disk/arrow_writer.h\"\n#include \"engine/util/filepath_helper.h\"\n#include \"engine/util/psi/batch_provider.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Bucket::kOpType(\"Bucket\");\n\nconst std::string& Bucket::Type() const { return kOpType; }\n\nvoid Bucket::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n  const auto& join_keys = ctx->GetInput(kJoinKey);\n\n  YACL_ENFORCE(\n      inputs.size() == outputs.size() && inputs.size() > 0,\n      \"Bucket input {} and output {} should have the same size and size > 0\",\n      kIn, kOut);\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   inputs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"Bucket input tensors' status should all be private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   join_keys, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"Bucket join key tensors' status should all be private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   outputs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"Bucket output tensors' status should all be private\");\n}\n\nsize_t GetMaxRowNum(ExecContext* ctx, size_t local_row_num,\n                    const std::vector<std::string>& input_party_codes) {\n  auto tag = ctx->GetNodeName() + \"-ExchangeRowNum\";\n  auto link = ctx->GetSession()->GetLink();\n  if (link->WorldSize() > 2) {\n    link = link->SubWorld(tag, input_party_codes);\n  }\n  auto length_bufs = yacl::link::AllGather(\n      link, yacl::ByteContainerView(&local_row_num, sizeof(size_t)), tag);\n  size_t max_length = 0;\n  for (const auto& o : length_bufs) {\n    max_length = std::max(max_length, o.data<size_t>()[0]);\n  }\n  return max_length;\n}\n\n// return false, if no more batch to read\nbool ReadArrays(std::vector<std::shared_ptr<TensorBatchReader>>& readers,\n                arrow::ArrayVector* arrays) {\n  arrow::ChunkedArrayVector read_datas;\n  for (const auto& reader : readers) {\n    auto data = reader->Next();\n    if (data == nullptr) {\n      return false;\n    }\n    read_datas.push_back(data);\n  }\n  for (auto& read_data : read_datas) {\n    arrays->push_back(arrow::Concatenate(read_data->chunks()).ValueOrDie());\n  }\n  return true;\n}\n\nvoid WriteArrays(std::vector<std::shared_ptr<BucketTensorConstructor>>& writers,\n                 std::vector<arrow::ChunkedArrayVector>& arrays,\n                 size_t bucket_num) {\n  for (size_t i = 0; i < writers.size(); i++) {\n    for (size_t j = 0; j < bucket_num; j++) {\n      writers[i]->InsertBucket(arrays[i][j], j);\n      // delete immediately to save memory\n      arrays[i][j].reset();\n    }\n  }\n}\n\nstd::vector<arrow::ChunkedArrayVector> FilterByIndex(\n    const arrow::ArrayVector& arrays, const arrow::ChunkedArrayVector& indices,\n    const scql::engine::RepeatedPbTensor& output_pbs, size_t bucket_num) {\n  std::vector<arrow::ChunkedArrayVector> result(output_pbs.size());\n  for (int i = 0; i < output_pbs.size(); i++) {\n    // when calling function take, it will concatenate input array.\n    // to avoid duplicated concatenating chunk, concatenate it when reading\n    auto arr = arrow::ChunkedArray::Make({arrays[i]}).ValueOrDie();\n    arrow::ChunkedArrayVector arrays(bucket_num);\n    yacl::parallel_for(0, bucket_num, [&](int64_t begin, int64_t end) {\n      for (int64_t j = begin; j < end; j++) {\n        arrow::Result<arrow::Datum> tmp;\n        // delegate to apache arrow's take function\n        tmp = arrow::compute::CallFunction(\"take\", {arr, indices[j]});\n        YACL_ENFORCE(tmp.ok(),\n                     \"caught error while invoking arrow take function:{}\",\n                     tmp.status().ToString());\n        arrays[j] = tmp.ValueOrDie().chunked_array();\n      }\n    });\n    result[i] = std::move(arrays);\n  }\n\n  return result;\n}\n\nvoid Bucket::Execute(ExecContext* ctx) {\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& join_key_pbs = ctx->GetInput(kJoinKey);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  auto streaming_options = ctx->GetSession()->GetStreamingOptions();\n  std::vector<TensorPtr> input_tensors;\n  size_t length = 0;\n  for (int i = 0; i < input_pbs.size(); i++) {\n    auto tensor = ctx->GetTensorTable()->GetTensor(input_pbs[i].name());\n    if (i == 0) {\n      length = tensor->Length();\n    }\n    input_tensors.push_back(tensor);\n  }\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  auto max_length = GetMaxRowNum(ctx, length, input_party_codes);\n  SPDLOG_INFO(\"max bucket input size: {}\", max_length);\n  // bucket runs for scenes length is large than FLAGS_batch_row_num\n  if (max_length <= streaming_options.streaming_row_num_threshold) {\n    for (int i = 0; i < input_pbs.size(); i++) {\n      ctx->GetTensorTable()->AddTensor(output_pbs[i].name(), input_tensors[i]);\n    }\n    return;\n  }\n  // create readers\n  std::vector<std::shared_ptr<TensorBatchReader>> readers(input_pbs.size());\n  for (int i = 0; i < input_pbs.size(); i++) {\n    readers[i] = (input_tensors[i]->CreateBatchReader(\n        streaming_options.batch_row_num / kBatchParallelism));\n  }\n  // create writer\n  std::vector<std::shared_ptr<BucketTensorConstructor>> tensor_constructors(\n      output_pbs.size());\n  auto bucket_num = (max_length + streaming_options.batch_row_num - 1) /\n                    streaming_options.batch_row_num;\n\n  SPDLOG_INFO(\"bucket num: {}\", bucket_num);\n  for (int i = 0; i < output_pbs.size(); i++) {\n    std::filesystem::path out_dir = util::CreateDirWithRandSuffix(\n        streaming_options.dump_file_dir, output_pbs[i].name());\n    tensor_constructors[i] = std::make_shared<DiskBucketTensorConstructor>(\n        output_pbs[i].name(), ToArrowDataType(output_pbs[i].elem_type()),\n        output_pbs[i].elem_type(), out_dir, bucket_num);\n  }\n  std::vector<int> key_pos;\n  for (int i = 0; i < join_key_pbs.size(); i++) {\n    bool found = false;\n    for (int j = 0; j < input_pbs.size(); j++) {\n      if (join_key_pbs[i].name() == input_pbs[j].name()) {\n        key_pos.emplace_back(j);\n        found = true;\n        break;\n      }\n    }\n    YACL_ENFORCE(found, \"join key {} not found in input_pbs\",\n                 join_key_pbs[i].name());\n  }\n\n  auto cal_future = std::async(std::launch::async, [&] {\n    std::vector<std::future<void>> futures;\n    int i = 0;\n    auto read_result = read_queue_.Pop();\n    while (read_result.has_value()) {\n      SPDLOG_INFO(\"Take batch: {}\", i);\n      auto out_arrays =\n          FilterByIndex(read_result.value().data_arrays,\n                        read_result.value().indice, output_pbs, bucket_num);\n      write_queue_.Push(out_arrays);\n      i++;\n      read_result = read_queue_.Pop();\n    }\n    write_queue_.Close();\n  });\n\n  auto write_future = std::async(std::launch::async, [&] {\n    int i = 0;\n    auto data = write_queue_.Pop();\n    while (data.has_value()) {\n      SPDLOG_INFO(\"Write batch: {}\", i);\n      WriteArrays(tensor_constructors, data.value(), bucket_num);\n      i++;\n      data = write_queue_.Pop();\n    }\n  });\n\n  try {\n    std::queue<std::future<void>> futures;\n    int num = 0;\n    while (true) {\n      arrow::ArrayVector batch_arrays;\n      if (!ReadArrays(readers, &batch_arrays)) {\n        break;\n      }\n      SPDLOG_INFO(\"Read batch {}\", num);\n      // parallel calculate filter indices\n      auto f = std::async(\n          std::launch::async,\n          [&](arrow::ArrayVector&& batch_arrays) {\n            arrow::ChunkedArrayVector indices(bucket_num);\n            std::vector<UInt64TensorBuilder> result_builder(indices.size());\n            {\n              std::vector<std::string> keys;\n              {\n                keys = util::Stringify(batch_arrays[key_pos[0]]);\n                for (size_t i = 1; i < key_pos.size(); ++i) {\n                  auto another_keys = util::Stringify(batch_arrays[key_pos[i]]);\n                  YACL_ENFORCE(keys.size() == another_keys.size(),\n                               \"tensor #{} batch size not equals with previous\",\n                               i);\n\n                  keys = util::Combine(keys, another_keys);\n                }\n              }\n              boost::hash<std::string> hasher;\n              for (size_t i = 0; i < keys.size(); i++) {\n                result_builder[hasher(keys[i]) % indices.size()].Append(i);\n              }\n            }\n            for (size_t i = 0; i < indices.size(); i++) {\n              TensorPtr indice;\n              result_builder[i].Finish(&indice);\n              indices[i] = indice->ToArrowChunkedArray();\n            }\n            read_queue_.Push({batch_arrays, indices});\n          },\n          std::move(batch_arrays));\n      futures.push(std::move(f));\n      if (futures.size() >= kBatchParallelism) {\n        futures.front().get();\n        futures.pop();\n      }\n      num++;\n    }\n    while (!futures.empty()) {\n      futures.front().get();\n      futures.pop();\n    }\n    // close read queue\n    read_queue_.Close();\n    cal_future.get();\n  } catch (const std::exception& e) {\n    SPDLOG_ERROR(\"read/cal error: {}\", e.what());\n    // close read queue\n    read_queue_.Close();\n    throw e;\n  }\n  write_future.get();\n  for (int i = 0; i < output_pbs.size(); i++) {\n    TensorPtr tensor;\n    tensor_constructors[i]->Finish(&tensor);\n    ctx->GetTensorTable()->AddTensor(output_pbs[i].name(), tensor);\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/bucket.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <utility>\n\n#include \"arrow/array/array_base.h\"\n#include \"arrow/type_fwd.h\"\n\n#include \"engine/exe/flags.h\"\n#include \"engine/framework/operator.h\"\n#include \"engine/util/concurrent_queue.h\"\n\nnamespace scql::engine::op {\n\n/// @brief put data into buckets by hash of join key.\nclass Bucket : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kJoinKey[] = \"Key\";\n  static constexpr char kOut[] = \"Out\";\n  static constexpr char kInputPartyCodesAttr[] = \"input_party_codes\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  struct ReadResult {\n    arrow::ArrayVector data_arrays;\n    arrow::ChunkedArrayVector indice;\n\n   public:\n    ReadResult() = default;\n    ReadResult(arrow::ArrayVector data_arrays, arrow::ChunkedArrayVector indice)\n        : data_arrays(std::move(data_arrays)),\n\n          indice(std::move(indice)) {}\n  };\n  static constexpr int kBatchParallelism = 10;\n  util::SimpleChannel<ReadResult> read_queue_{kBatchParallelism,\n                                              FLAGS_queue_max_block_seconds};\n  util::SimpleChannel<std::vector<arrow::ChunkedArrayVector>> write_queue_{\n      kBatchParallelism, FLAGS_queue_max_block_seconds};\n};\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/bucket_bench.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <cstddef>\n#include <filesystem>\n#include <memory>\n#include <utility>\n\n#include \"arrow/testing/random.h\"\n#include \"arrow/type.h\"\n#include \"benchmark/benchmark.h\"\n\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/bucket.h\"\n#include \"engine/operator/test_util.h\"\n#include \"engine/util/filepath_helper.h\"\n\nnamespace scql::engine::op {\n\nstruct BucketTestCase {\n  std::vector<test::NamedTensor> keys;\n  std::vector<test::NamedTensor> datas;\n  std::vector<std::string> output_names;\n};\n\ntest::NamedTensor CreateNamedTensor(const std::string& name, TensorPtr t) {\n  return test::NamedTensor(name, std::move(t));\n};\n\npb::ExecNode MakeBucketExecNode(const BucketTestCase& tc) {\n  test::ExecNodeBuilder builder(Bucket::kOpType);\n\n  builder.SetNodeName(\"bucket-test\");\n\n  // Add join keys\n  std::vector<pb::Tensor> key_datas;\n  std::vector<pb::Tensor> input_datas;\n  std::vector<pb::Tensor> outputs;\n  for (const auto& named_tensor : tc.keys) {\n    auto data = test::MakePrivateTensorReference(named_tensor.name,\n                                                 named_tensor.tensor->Type());\n    key_datas.push_back(data);\n    input_datas.push_back(data);\n  }\n  builder.AddInput(Bucket::kJoinKey, key_datas);\n  // Add inputs\n  for (const auto& named_tensor : tc.datas) {\n    auto data = test::MakePrivateTensorReference(named_tensor.name,\n                                                 named_tensor.tensor->Type());\n    input_datas.push_back(std::move(data));\n  }\n  builder.AddInput(Bucket::kIn, input_datas);\n  // Add outputs\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto out = test::MakeTensorAs(tc.output_names[i], input_datas[i]);\n    outputs.push_back(std::move(out));\n  }\n  builder.AddOutput(Bucket::kOut, outputs);\n  builder.AddStringsAttr(\n      Bucket::kInputPartyCodesAttr,\n      std::vector<std::string>{test::kPartyAlice, test::kPartyBob});\n\n  return builder.Build();\n}\n\nvoid FeedInputs(ExecContext* ctx, const BucketTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, tc.datas);\n  test::FeedInputsAsPrivate(ctx, tc.keys);\n}\n\nvoid RunBucketBench(std::vector<TensorPtr>& join_keys,\n                    std::vector<TensorPtr>& payloads) {\n  // Given\n  BucketTestCase tc;\n  for (size_t i = 0; i < join_keys.size(); ++i) {\n    std::string t_name = absl::StrCat(\"key_\", i);\n    tc.keys.push_back(CreateNamedTensor(t_name, join_keys[i]));\n    tc.output_names.push_back(absl::StrCat(t_name, \"_out\"));\n  }\n  for (size_t i = 0; i < payloads.size(); ++i) {\n    std::string t_name = absl::StrCat(\"payload_\", i);\n    tc.datas.push_back(CreateNamedTensor(t_name, join_keys[i]));\n    tc.output_names.push_back(absl::StrCat(t_name, \"_out\"));\n  }\n  auto node = MakeBucketExecNode(tc);\n  auto session = test::Make1PCSession();\n  auto options = session->GetStreamingOptions();\n  // 1kw\n  options.batch_row_num = 20 * 1000 * 1000;\n  options.streaming_row_num_threshold = 20 * 1000 * 1000;\n  session->SetStreamingOptions(options);\n  ExecContext ctx(node, session.get());\n  // feed inputs, test copy from alice to bob.\n  FeedInputs(&ctx, tc);\n  Bucket op;\n  // When\n  op.Run(&ctx);\n}\n\nTensorPtr CreateTmpTensor(const std::filesystem::path& path,\n                          const std::shared_ptr<arrow::Field>& field,\n                          size_t num) {\n  constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n  constexpr size_t batch_size = 1000 * 1000;\n  arrow::ArrayVector arrays;\n  for (size_t i = 0; i < num; i += batch_size) {\n    arrays.push_back(\n        arrow::random::GenerateArray(*field, batch_size, randomSeed));\n  }\n  arrow::FieldVector fields = {field};\n  auto schema = std::make_shared<arrow::Schema>(fields);\n  auto expected_chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n  scql::engine::TensorWriter writer(schema, path.string());\n  writer.WriteBatch(*expected_chunked_array);\n  scql::engine::TensorPtr t;\n  writer.Finish(&t);\n  return t;\n}\n\n}  // namespace scql::engine::op\n\nstatic void BM_BucketTest(benchmark::State& state) {\n  for (auto _ : state) {\n    state.PauseTiming();\n    size_t array_num_rows = state.range(0);\n    auto path = scql::engine::util::CreateDirWithRandSuffix(\n        std::filesystem::temp_directory_path(), \"test\");\n    std::vector<scql::engine::TensorPtr> join_keys;\n    auto field = std::make_shared<arrow::Field>(\"a\", arrow::large_utf8());\n    join_keys.push_back(scql::engine::op::CreateTmpTensor(\n        scql::engine::util::CreateDirWithRandSuffix(path, \"keys\"), field,\n        array_num_rows));\n    field = std::make_shared<arrow::Field>(\"b\", arrow::large_utf8());\n    std::vector<scql::engine::TensorPtr> payloads;\n    payloads.push_back(scql::engine::op::CreateTmpTensor(\n        scql::engine::util::CreateDirWithRandSuffix(path, \"payload\"), field,\n        array_num_rows));\n    state.ResumeTiming();\n    scql::engine::op::RunBucketBench(join_keys, payloads);\n    state.PauseTiming();\n    std::error_code ec;\n    std::filesystem::remove_all(path, ec);\n    state.ResumeTiming();\n  }\n}\n\nBENCHMARK(BM_BucketTest)->Unit(benchmark::kMillisecond)->Arg(500 * 1000 * 1000);\n"
  },
  {
    "path": "engine/operator/bucket_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/bucket.h\"\n\n#include \"arrow/array/concatenate.h\"\n#include \"arrow/compute/api_vector.h\"\n#include \"arrow/compute/exec.h\"  // NOLINT\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct BucketTestCase {\n  std::vector<test::NamedTensor> keys;\n  std::vector<test::NamedTensor> datas;\n  std::vector<std::string> output_names;\n};\n\ntest::NamedTensor MockInt32Tensor(const std::string& name,\n                                  const size_t tensor_length) {\n  std::vector<test::NamedTensor> tensors;\n  std::string tensor_str = \"[\";\n  for (size_t i = 0; i < tensor_length; i++) {\n    tensor_str += std::to_string(i);\n    if (i < tensor_length - 1) {\n      tensor_str += \",\";\n    }\n  }\n  tensor_str += \"]\";\n  return test::NamedTensor(name, TensorFrom(arrow::int32(), tensor_str));\n};\n\ntest::NamedTensor MockStringTensor(const std::string& name,\n                                   const size_t tensor_length) {\n  BucketTestCase test_case;\n  std::string tensor_str = \"[\";\n  for (size_t i = 0; i < tensor_length; i++) {\n    tensor_str += \"\\\"\" + std::to_string(i) + \"\\\"\";\n    if (i < tensor_length - 1) {\n      tensor_str += \",\";\n    }\n  }\n  tensor_str += \"]\";\n  return test::NamedTensor(name, TensorFrom(arrow::large_utf8(), tensor_str));\n};\n\nBucketTestCase MockTestCase(const size_t tensor_length) {\n  BucketTestCase tc;\n  tc.keys.push_back(MockStringTensor(\"key\", tensor_length));\n  tc.datas.push_back(MockInt32Tensor(\"data1\", tensor_length));\n  tc.datas.push_back(MockStringTensor(\"data2\", tensor_length));\n  tc.output_names.emplace_back(\"data1_out\");\n  tc.output_names.emplace_back(\"data2_out\");\n  return tc;\n}\n\nclass BucketTest : public ::testing::TestWithParam<BucketTestCase> {\n protected:\n  static pb::ExecNode MakeBucketExecNode(const BucketTestCase& tc);\n\n  static void FeedInputs(ExecContext* ctx, const BucketTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    BucketPrivateTest, BucketTest,\n    testing::Values(\n        BucketTestCase{\n            .keys = {test::NamedTensor(\n                \"k1\", TensorFrom(arrow::large_utf8(),\n                                 R\"json([\"A\",\"C\",\"B\",\"A\"])json\"))},\n            .datas = {test::NamedTensor(\n                          \"x1\", TensorFrom(arrow::float64(),\n                                           \"[-3.1415, 0.1, 99.999, null]\")),\n                      test::NamedTensor(\"x2\", TensorFrom(arrow::boolean(),\n                                                         \"[1,0,0,1]\"))},\n            .output_names = {\"x1_out\", \"x2_out\"}},\n        BucketTestCase{\n            .keys = {test::NamedTensor(\"k1\", TensorFrom(arrow::int64(), \"[]\"))},\n            .datas = {test::NamedTensor(\"x1\",\n                                        TensorFrom(arrow::int64(), \"[]\"))},\n            .output_names = {\"x1_out\"}},\n        MockTestCase(100), MockTestCase(1100), MockTestCase(10000)));\n\nstd::shared_ptr<arrow::Array> SortChunkedArray(\n    const std::shared_ptr<arrow::ChunkedArray>& arr) {\n  auto indices =\n      arrow::compute::SortIndices(*arr, arrow::compute::SortOrder::Ascending)\n          .ValueOrDie();\n  auto concat_array = arrow::Concatenate(arr->chunks()).ValueOrDie();\n  return arrow::compute::Take(*concat_array, *indices).ValueOrDie();\n}\n\nTEST_P(BucketTest, works) {\n  // Given\n  auto tc = GetParam();\n  auto node = MakeBucketExecNode(tc);\n  auto session = test::Make1PCSession();\n  auto options = session->GetStreamingOptions();\n  options.batch_row_num = 1000;\n  options.streaming_row_num_threshold = 1000;\n  session->SetStreamingOptions(options);\n  ExecContext ctx(node, session.get());\n  // feed inputs, test copy from alice to bob.\n  FeedInputs(&ctx, tc);\n  Bucket op;\n  // When\n  EXPECT_NO_THROW({ op.Run(&ctx); });\n\n  // Then check bob output\n  auto* tensor_table = ctx.GetTensorTable();\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto in_arr = tc.datas[i].tensor->ToArrowChunkedArray();\n    auto out = tensor_table->GetTensor(tc.output_names[i]);\n    ASSERT_TRUE(out);\n    // compare tensor content\n    auto sorted_in_arr = SortChunkedArray(in_arr);\n    auto sorted_out_arr = SortChunkedArray(out->ToArrowChunkedArray());\n    EXPECT_TRUE(sorted_out_arr->Equals(sorted_in_arr))\n        << \"expect type = \" << in_arr->type()->ToString()\n        << \", got type = \" << out->ToArrowChunkedArray()->type()->ToString()\n        << \"\\nexpect result = \" << sorted_in_arr->ToString()\n        << \"\\nbut actual got result = \" << sorted_out_arr->ToString();\n  }\n}\n\n/// ===========================\n/// BucketTest impl\n/// ===========================\n\npb::ExecNode BucketTest::MakeBucketExecNode(const BucketTestCase& tc) {\n  test::ExecNodeBuilder builder(Bucket::kOpType);\n\n  builder.SetNodeName(\"bucket-test\");\n\n  // Add join keys\n  std::vector<pb::Tensor> key_datas;\n  std::vector<pb::Tensor> input_datas;\n  std::vector<pb::Tensor> outputs;\n  for (const auto& named_tensor : tc.keys) {\n    auto data = test::MakePrivateTensorReference(named_tensor.name,\n                                                 named_tensor.tensor->Type());\n    key_datas.push_back(data);\n    input_datas.push_back(data);\n    // mock name\n    *data.mutable_name() = data.name() + \"_out\";\n    outputs.push_back(data);\n  }\n  builder.AddInput(Bucket::kJoinKey, key_datas);\n\n  // Add inputs\n  for (const auto& named_tensor : tc.datas) {\n    auto data = test::MakePrivateTensorReference(named_tensor.name,\n                                                 named_tensor.tensor->Type());\n    input_datas.push_back(std::move(data));\n  }\n  builder.AddInput(Bucket::kIn, input_datas);\n\n  // Add outputs\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto out =\n        test::MakeTensorAs(tc.output_names[i], input_datas[i + tc.keys.size()]);\n    outputs.push_back(std::move(out));\n  }\n  builder.AddOutput(Bucket::kOut, outputs);\n\n  builder.AddStringsAttr(\n      Bucket::kInputPartyCodesAttr,\n      std::vector<std::string>{test::kPartyAlice, test::kPartyBob});\n\n  return builder.Build();\n}\n\nvoid BucketTest::FeedInputs(ExecContext* ctx, const BucketTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, tc.datas);\n  test::FeedInputsAsPrivate(ctx, tc.keys);\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/case_when.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/case_when.h\"\n\n#include <cstddef>\n#include <string>\n#include <vector>\n\n#include \"arrow/compute/exec.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/const.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/framework/exec.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string CaseWhen::kOpType(\"CaseWhen\");\nconst std::string& CaseWhen::Type() const { return kOpType; }\n\nvoid CaseWhen::Validate(ExecContext* ctx) {\n  const auto& conds = ctx->GetInput(kCond);\n  const auto& values = ctx->GetInput(kValue);\n  const auto& output = ctx->GetOutput(kOut);\n  const auto& value_else = ctx->GetInput(kValueElse);\n\n  // check elem size\n  YACL_ENFORCE(!conds.empty(), \"cond shouldn't be empty\");\n  YACL_ENFORCE(conds.size() == values.size(),\n               \"{} size = {} not equal to {} size = {}\", kValue, values.size(),\n               kCond, conds.size());\n  YACL_ENFORCE(value_else.size() == 1, \"{} size = {} not equal to 1\",\n               kValueElse, value_else.size());\n  YACL_ENFORCE(output.size() == 1, \"{} size = {} not equal to 1\", kOut,\n               output.size());\n\n  // check elem type\n  for (int i = 0; i < conds.size(); i++) {\n    YACL_ENFORCE(conds[i].elem_type() == pb::INT8 ||\n                     conds[i].elem_type() == pb::INT32 ||\n                     conds[i].elem_type() == pb::INT64 ||\n                     conds[i].elem_type() == pb::BOOL,\n                 \"condition type is {}, only support int8 int32 int64 and bool\",\n                 pb::PrimitiveDataType_Name(conds[i].elem_type()));\n    if (i > 0) {\n      YACL_ENFORCE(values[i].elem_type() == values[0].elem_type(),\n                   \"tensor {} type is {} which should be equal to {}\",\n                   values[i].name(),\n                   pb::PrimitiveDataType_Name(values[i].elem_type()),\n                   pb::PrimitiveDataType_Name(values[0].elem_type()));\n    }\n  }\n  YACL_ENFORCE(value_else[0].elem_type() == values[0].elem_type(),\n               \"tensor {} type is {} which should be equal to {}\",\n               value_else[0].name(),\n               pb::PrimitiveDataType_Name(value_else[0].elem_type()),\n               pb::PrimitiveDataType_Name(values[0].elem_type()));\n\n  std::vector<pb::TensorStatus> input_status;\n  pb::TensorStatus out_status;\n  if (util::OneOfTensorsStatusMatched(conds, pb::TENSORSTATUS_PRIVATE)) {\n    input_status = {pb::TENSORSTATUS_PRIVATE};\n    out_status = pb::TENSORSTATUS_PRIVATE;\n  } else if (util::OneOfTensorsStatusMatched(conds, pb::TENSORSTATUS_SECRET)) {\n    input_status = {pb::TENSORSTATUS_SECRET, pb::TENSORSTATUS_PUBLIC};\n    out_status = pb::TENSORSTATUS_SECRET;\n  } else {\n    if (util::OneOfTensorsStatusMatched(values, pb::TENSORSTATUS_SECRET) ||\n        util::IsTensorStatusMatched(value_else[0], pb::TENSORSTATUS_SECRET)) {\n      input_status = {pb::TENSORSTATUS_SECRET, pb::TENSORSTATUS_PUBLIC};\n      out_status = pb::TENSORSTATUS_SECRET;\n    } else {\n      input_status = {pb::TENSORSTATUS_PUBLIC};\n      out_status = pb::TENSORSTATUS_PUBLIC;\n    }\n  }\n  YACL_ENFORCE(util::AreTensorsStatusMatchedOneOf(conds, input_status));\n  YACL_ENFORCE(util::AreTensorsStatusMatchedOneOf(values, input_status));\n  YACL_ENFORCE(util::AreTensorsStatusMatchedOneOf(value_else, input_status));\n  YACL_ENFORCE(util::IsTensorStatusMatched(output[0], out_status));\n}\n\nvoid CaseWhen::Execute(ExecContext* ctx) {\n  ctx->GetOutputStatus(kOut) == pb::TensorStatus::TENSORSTATUS_PRIVATE\n      ? CaseWhenPrivate(ctx)\n      : CaseWhenShare(ctx);\n}\n\nvoid CaseWhen::CaseWhenPrivate(ExecContext* ctx) {\n  const auto& cond_pb = ctx->GetInput(kCond);\n  const auto& value_pb = ctx->GetInput(kValue);\n  std::vector<arrow::Datum> conds_datum;\n  std::vector<arrow::Datum> values_datum;\n  std::vector<std::shared_ptr<arrow::ChunkedArray>> conds_array;\n  for (int i = 0; i < cond_pb.size(); i++) {\n    auto cond = ctx->GetInputTensor(kCond, i);\n    YACL_ENFORCE(cond, \"get tensor {} failed\", cond_pb[i].name());\n    auto cond_array = cond->ToArrowChunkedArray();\n    if (cond->Type() != pb::BOOL) {\n      auto cond_nqz = arrow::compute::CallFunction(\n          \"not_equal\", {cond->ToArrowChunkedArray(), arrow::Datum{0}});\n      YACL_ENFORCE(cond_nqz.ok(),\n                   \"caught error while invoking arrow make_struct function: {}\",\n                   cond_nqz.status().ToString());\n      cond_array = cond_nqz.ValueOrDie().chunked_array();\n    }\n    conds_datum.emplace_back(cond_array);\n    auto value = ctx->GetInputTensor(kValue, i);\n    YACL_ENFORCE(value, \"get tensor {} failed\", value_pb[i].name());\n    auto value_array = value->ToArrowChunkedArray();\n    values_datum.emplace_back(value_array);\n  }\n\n  auto cond_struct = arrow::compute::CallFunction(\"make_struct\", conds_datum);\n  YACL_ENFORCE(cond_struct.ok(),\n               \"caught error while invoking arrow make_struct function: {}\",\n               cond_struct.status().ToString());\n  auto cond_array = cond_struct.ValueOrDie().chunked_array();\n  auto value_else = ctx->GetInputTensor(kValueElse);\n  YACL_ENFORCE(value_else, \"get tensor {} failed\", cond_pb[0].name());\n  auto value_else_array = value_else->ToArrowChunkedArray();\n\n  std::vector<arrow::Datum> inputs;\n  // cond(1) + values(n) + value_else(1)\n  inputs.reserve(values_datum.size() + 2);\n  inputs.emplace_back(cond_array);\n  inputs.insert(inputs.end(), values_datum.begin(), values_datum.end());\n  inputs.emplace_back(value_else_array);\n\n  auto result = arrow::compute::CallFunction(\"case_when\", inputs);\n  YACL_ENFORCE(result.ok(),\n               \"invoking arrow case_when function failed: err_msg={}\",\n               result.status().ToString());\n\n  ctx->SetOutputTensor(kOut, TensorFrom(result.ValueOrDie().chunked_array()));\n}\n\n// condition:\n//      origin              transfer\n//   |1,  0, -1,  2|     |1, 0, 0, 0, 0|\n//   |0, -1,  1,  0|     |0, 1, 0, 0, 0|\n//   |1,  0,  1,  1| ==> |1, 0, 0, 0, 0|\n//   |0,  0,  0,  1|     |0, 0, 0, 1, 0|\n//   |0,  0,  0 , 0|     |0, 0, 0, 0, 1|\nstd::vector<spu::Value> CaseWhen::TransformConditionData(ExecContext* ctx) {\n  const auto& cond_pb = ctx->GetInput(kCond);\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto cond_values = ctx->GetInputValues(kCond);\n  std::vector<spu::Value> result;\n  result.reserve(cond_pb.size());\n  spu::Value cond_pre;\n  for (int i = 0; i < cond_pb.size(); i++) {\n    auto cond_cur = cond_values[i];\n    auto zero = spu::kernel::hlo::Constant(sctx, 0, {cond_cur.shape()});\n    if (cond_pb[i].elem_type() != pb::BOOL) {\n      cond_cur = spu::kernel::hlo::NotEqual(sctx, cond_cur, zero);\n    }\n    if (i == 0) {\n      cond_pre = cond_cur;\n    } else {\n      cond_cur = spu::kernel::hlo::Or(sctx, cond_cur, cond_pre);\n      cond_pre = cond_cur;\n    }\n    result.emplace_back(cond_cur);\n  }\n  auto one_value = spu::kernel::hlo::Constant(sctx, true, {result[0].shape()});\n  result.emplace_back(one_value);\n  for (size_t i = result.size() - 1; i > 0; i--) {\n    result[i] = spu::kernel::hlo::Xor(sctx, result[i], result[i - 1]);\n  }\n  return result;\n}\n\nvoid CaseWhen::CaseWhenShare(ExecContext* ctx) {\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto conds = TransformConditionData(ctx);\n  auto values = ctx->GetInputValues(kValue);\n  spu::Value result_value =\n      spu::kernel::hlo::Constant(sctx, 0, {conds[0].shape()});\n  for (int i = 0; i < values.size(); i++) {\n    auto cur_value = spu::kernel::hlo::Mul(sctx, conds[i], values[i]);\n    result_value = spu::kernel::hlo::Add(sctx, result_value, cur_value);\n  }\n  auto value_else = ctx->GetInputValue(kValueElse);\n  auto cur_value = spu::kernel::hlo::Mul(sctx, conds.back(), value_else);\n  result_value = spu::kernel::hlo::Add(sctx, result_value, cur_value);\n  ctx->SetOutputValue(kOut, result_value);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/case_when.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <string>\n\n#include \"engine/framework/exec.h\"\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass CaseWhen : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kCond[] = \"Condition\";\n  static constexpr char kValue[] = \"Value\";\n  static constexpr char kValueElse[] = \"ValueElse\";\n  static constexpr char kOut[] = \"Out\";\n  const std::string& Type() const override;\n  static std::vector<spu::Value> TransformConditionData(ExecContext* ctx);\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static void CaseWhenPrivate(ExecContext* ctx);\n  void CaseWhenShare(ExecContext* ctx);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/case_when_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/case_when.h\"\n\n#include \"gtest/gtest.h\"\n#include \"libspu/kernel/hal/public_helper.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n#include \"engine/util/ndarray_to_arrow.h\"\n\nnamespace scql::engine::op {\n\nstruct CaseWhenTestCase {\n  std::vector<test::NamedTensor> conds;\n  std::vector<pb::TensorStatus> cond_status;\n  std::vector<test::NamedTensor> values;\n  std::vector<pb::TensorStatus> value_status;\n  test::NamedTensor value_else;\n  pb::TensorStatus value_else_status;\n  test::NamedTensor expect_out;\n  pb::TensorStatus expect_out_status;\n};\n\nclass CaseWhenTest\n    : public ::testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, CaseWhenTestCase>> {\n protected:\n  static pb::ExecNode MakeCaseWhenExecNode(const CaseWhenTestCase& tc);\n\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const CaseWhenTestCase& tc);\n  static void FeedTensors(const std::vector<ExecContext*>& ctxs,\n                          const std::vector<test::NamedTensor>& ts,\n                          const std::vector<pb::TensorStatus>& status);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    CaseWhenPrivateTest, CaseWhenTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            CaseWhenTestCase{\n                .conds = {test::NamedTensor(\"cond1\", TensorFrom(arrow::int64(),\n                                                                \"[1,0,0,0]\")),\n                          test::NamedTensor(\n                              \"cond2\", TensorFrom(arrow::boolean(),\n                                                  \"[true,true,false,false]\")),\n                          test::NamedTensor(\"cond3\",\n                                            TensorFrom(arrow::int64(),\n                                                       \"[11,11,11,0]\"))},\n                .cond_status = {pb::TENSORSTATUS_PUBLIC,\n                                pb::TENSORSTATUS_PUBLIC,\n                                pb::TENSORSTATUS_PUBLIC},\n                .values =\n                    {test::NamedTensor(\"value1\",\n                                       TensorFrom(arrow::int64(), \"[1,1,1,1]\")),\n                     test::NamedTensor(\"value2\",\n                                       TensorFrom(arrow::int64(), \"[2,2,2,2]\")),\n                     test::NamedTensor(\"value3\", TensorFrom(arrow::int64(),\n                                                            \"[3,3,3,3]\"))},\n                .value_status = {pb::TENSORSTATUS_PUBLIC,\n                                 pb::TENSORSTATUS_PUBLIC,\n                                 pb::TENSORSTATUS_PUBLIC},\n                .value_else = test::NamedTensor(\n                    \"value_else\", TensorFrom(arrow::int64(), \"[4,4,4,4]\")),\n                .value_else_status = pb::TENSORSTATUS_PUBLIC,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1,2,3,4]\")),\n                .expect_out_status = pb::TENSORSTATUS_PUBLIC},\n            CaseWhenTestCase{\n                .conds =\n                    {test::NamedTensor(\"cond1\", TensorFrom(arrow::int64(),\n                                                           \"[1,null,0,0]\")),\n                     test::NamedTensor(\n                         \"cond2\", TensorFrom(arrow::boolean(),\n                                             \"[true,true,null,false]\")),\n                     test::NamedTensor(\"cond3\", TensorFrom(arrow::int64(),\n                                                           \"[11,11,11,null]\"))},\n                .cond_status = {pb::TENSORSTATUS_PRIVATE,\n                                pb::TENSORSTATUS_PRIVATE,\n                                pb::TENSORSTATUS_PRIVATE},\n                .values =\n                    {test::NamedTensor(\"value1\",\n                                       TensorFrom(arrow::int64(), \"[1,1,1,1]\")),\n                     test::NamedTensor(\"value2\",\n                                       TensorFrom(arrow::int64(), \"[2,2,2,2]\")),\n                     test::NamedTensor(\"value3\", TensorFrom(arrow::int64(),\n                                                            \"[3,3,3,3]\"))},\n                .value_status = {pb::TENSORSTATUS_PRIVATE,\n                                 pb::TENSORSTATUS_PRIVATE,\n                                 pb::TENSORSTATUS_PRIVATE},\n                .value_else = test::NamedTensor(\n                    \"value_else\", TensorFrom(arrow::int64(), \"[4,4,4,4]\")),\n                .value_else_status = pb::TENSORSTATUS_PRIVATE,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1,2,3,4]\")),\n                .expect_out_status = pb::TENSORSTATUS_PRIVATE},\n            CaseWhenTestCase{\n                .conds = {test::NamedTensor(\"cond1\", TensorFrom(arrow::int64(),\n                                                                \"[1,0,0,0]\")),\n                          test::NamedTensor(\n                              \"cond2\", TensorFrom(arrow::boolean(),\n                                                  \"[true,true,false,false]\")),\n                          test::NamedTensor(\"cond3\",\n                                            TensorFrom(arrow::int64(),\n                                                       \"[11,11,11,0]\"))},\n                .cond_status = {pb::TENSORSTATUS_SECRET,\n                                pb::TENSORSTATUS_PUBLIC,\n                                pb::TENSORSTATUS_PUBLIC},\n                .values =\n                    {test::NamedTensor(\"value1\",\n                                       TensorFrom(arrow::int64(), \"[1,1,1,1]\")),\n                     test::NamedTensor(\"value2\",\n                                       TensorFrom(arrow::int64(), \"[2,2,2,2]\")),\n                     test::NamedTensor(\"value3\", TensorFrom(arrow::int64(),\n                                                            \"[3,3,3,3]\"))},\n                .value_status = {pb::TENSORSTATUS_SECRET,\n                                 pb::TENSORSTATUS_SECRET,\n                                 pb::TENSORSTATUS_PUBLIC},\n                .value_else = test::NamedTensor(\n                    \"value_else\", TensorFrom(arrow::int64(), \"[4,4,4,4]\")),\n                .value_else_status = pb::TENSORSTATUS_PUBLIC,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1,2,3,4]\")),\n                .expect_out_status = pb::TENSORSTATUS_SECRET},\n            CaseWhenTestCase{\n                .conds = {test::NamedTensor(\"cond1\", TensorFrom(arrow::int64(),\n                                                                \"[-1,0,0,0]\")),\n                          test::NamedTensor(\n                              \"cond2\", TensorFrom(arrow::boolean(),\n                                                  \"[true,true,false,false]\")),\n                          test::NamedTensor(\"cond3\",\n                                            TensorFrom(arrow::int64(),\n                                                       \"[-11,-11,-11,0]\"))},\n                .cond_status = {pb::TENSORSTATUS_PRIVATE,\n                                pb::TENSORSTATUS_PRIVATE,\n                                pb::TENSORSTATUS_PRIVATE},\n                .values =\n                    {test::NamedTensor(\n                         \"value1\", TensorFrom(arrow::large_utf8(),\n                                              R\"json([\"A\",\"A\",\"A\",\"A\"])json\")),\n                     test::NamedTensor(\n                         \"value2\", TensorFrom(arrow::large_utf8(),\n                                              R\"json([\"B\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\n                         \"value3\", TensorFrom(arrow::large_utf8(),\n                                              R\"json([\"C\",\"C\",\"C\",\"C\"])json\"))},\n                .value_status = {pb::TENSORSTATUS_PRIVATE,\n                                 pb::TENSORSTATUS_PRIVATE,\n                                 pb::TENSORSTATUS_PRIVATE},\n                .value_else = test::NamedTensor(\n                    \"value_else\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"D\",\"D\",\"D\",\"D\"])json\")),\n                .value_else_status = pb::TENSORSTATUS_PRIVATE,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"A\",\"B\",\"C\",\"D\"])json\")),\n                .expect_out_status = pb::TENSORSTATUS_PRIVATE},\n            CaseWhenTestCase{\n                .conds = {test::NamedTensor(\"cond1\", TensorFrom(arrow::int64(),\n                                                                \"[1,0,0,0]\")),\n                          test::NamedTensor(\n                              \"cond2\", TensorFrom(arrow::boolean(),\n                                                  \"[true,true,false,false]\")),\n                          test::NamedTensor(\"cond3\",\n                                            TensorFrom(arrow::int64(),\n                                                       \"[-11,-11,-11,0]\"))},\n                .cond_status = {pb::TENSORSTATUS_SECRET,\n                                pb::TENSORSTATUS_PUBLIC,\n                                pb::TENSORSTATUS_PUBLIC},\n                .values =\n                    {test::NamedTensor(\n                         \"value1\", TensorFrom(arrow::large_utf8(),\n                                              R\"json([\"A\",\"A\",\"A\",\"A\"])json\")),\n                     test::NamedTensor(\n                         \"value2\", TensorFrom(arrow::large_utf8(),\n                                              R\"json([\"B\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\n                         \"value3\", TensorFrom(arrow::large_utf8(),\n                                              R\"json([\"C\",\"C\",\"C\",\"C\"])json\"))},\n                .value_status = {pb::TENSORSTATUS_PUBLIC,\n                                 pb::TENSORSTATUS_SECRET,\n                                 pb::TENSORSTATUS_SECRET},\n                .value_else = test::NamedTensor(\n                    \"value_else\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"D\",\"D\",\"D\",\"D\"])json\")),\n                .value_else_status = pb::TENSORSTATUS_PUBLIC,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"A\",\"B\",\"C\",\"D\"])json\")),\n                .expect_out_status = pb::TENSORSTATUS_SECRET})),\n    TestParamNameGenerator(CaseWhenTest));\n\nTEST_P(CaseWhenTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto test_case = std::get<1>(parm);\n  auto node = MakeCaseWhenExecNode(test_case);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n  std::vector<ExecContext> exec_ctxs;\n  for (size_t idx = 0; idx < sessions.size(); ++idx) {\n    exec_ctxs.emplace_back(node, sessions[idx].get());\n  }\n  std::vector<ExecContext*> ctx_ptrs;\n  for (size_t idx = 0; idx < exec_ctxs.size(); ++idx) {\n    ctx_ptrs.emplace_back(&exec_ctxs[idx]);\n  }\n  FeedInputs(ctx_ptrs, test_case);\n\n  // When\n  if (test_case.expect_out_status == pb::TENSORSTATUS_PRIVATE) {\n    EXPECT_NO_THROW(test::RunAsync<CaseWhen>({ctx_ptrs[0]}));\n  } else {\n    EXPECT_NO_THROW(test::RunAsync<CaseWhen>(ctx_ptrs));\n  }\n\n  // Then check outputs\n  auto tensor_table = ctx_ptrs[0]->GetTensorTable();\n\n  TensorPtr out;\n  if (test_case.expect_out_status == pb::TENSORSTATUS_PRIVATE) {\n    EXPECT_NO_THROW(out = tensor_table->GetTensor(test_case.expect_out.name));\n\n  } else {\n    EXPECT_NO_THROW(\n        out = test::RevealSecret(ctx_ptrs, test_case.expect_out.name));\n    // convert hash to string for string tensor in spu\n    if (test_case.expect_out.tensor->Type() == pb::PrimitiveDataType::STRING) {\n      out = ctx_ptrs[0]->GetSession()->HashToString(*out);\n    }\n  }\n  EXPECT_TRUE(out != nullptr);\n  EXPECT_EQ(out->Length(), test_case.expect_out.tensor->Length());\n  EXPECT_EQ(out->GetNullCount(), test_case.expect_out.tensor->GetNullCount());\n  EXPECT_EQ(out->Type(), test_case.expect_out.tensor->Type());\n  // compare tensor content\n  EXPECT_TRUE(out->ToArrowChunkedArray()->Equals(\n      test_case.expect_out.tensor->ToArrowChunkedArray()));\n}\n\nstruct CaseWhenConditionTestCase {\n  std::vector<test::NamedTensor> conds;\n  std::vector<test::NamedTensor> expect_out;\n};\n\nclass CaseWhenConditionTest\n    : public ::testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, CaseWhenConditionTestCase>> {};\n\nINSTANTIATE_TEST_SUITE_P(\n    CaseWhenConditionShareTest, CaseWhenConditionTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            CaseWhenConditionTestCase{\n                .conds = {test::NamedTensor(\"cond1\", TensorFrom(arrow::int64(),\n                                                                \"[1,0,0,0]\")),\n                          test::NamedTensor(\n                              \"cond2\", TensorFrom(arrow::boolean(),\n                                                  \"[true,true,false,false]\")),\n                          test::NamedTensor(\"cond3\",\n                                            TensorFrom(arrow::int64(),\n                                                       \"[11,11,11,0]\"))},\n                .expect_out =\n                    {test::NamedTensor(\"out1\",\n                                       TensorFrom(arrow::boolean(),\n                                                  \"[true,false,false,false]\")),\n                     test::NamedTensor(\"out2\",\n                                       TensorFrom(arrow::boolean(),\n                                                  \"[false,true,false,false]\")),\n                     test::NamedTensor(\n                         \"out3\", TensorFrom(arrow::boolean(),\n                                            \"[false,false,true,false]\")),\n                     test::NamedTensor(\n                         \"out4\", TensorFrom(arrow::boolean(),\n                                            \"[false,false,false,true]\"))}},\n            CaseWhenConditionTestCase{\n                .conds = {test::NamedTensor(\"cond1\", TensorFrom(arrow::int64(),\n                                                                \"[-1,0,1,0]\")),\n                          test::NamedTensor(\n                              \"cond2\", TensorFrom(arrow::boolean(),\n                                                  \"[true,false,false,false]\")),\n                          test::NamedTensor(\"cond3\", TensorFrom(arrow::int64(),\n                                                                \"[3,3,3,3]\"))},\n                .expect_out =\n                    {test::NamedTensor(\n                         \"out1\", TensorFrom(arrow::boolean(),\n                                            \"[true,false,true,false]\")),\n                     test::NamedTensor(\n                         \"out2\", TensorFrom(arrow::boolean(),\n                                            \"[false,false,false,false]\")),\n                     test::NamedTensor(\n                         \"out3\", TensorFrom(arrow::boolean(),\n                                            \"[false,true,false,true]\")),\n                     test::NamedTensor(\n                         \"out4\", TensorFrom(arrow::boolean(),\n                                            \"[false,false,false,false]\"))}},\n            CaseWhenConditionTestCase{\n                .conds = {test::NamedTensor(\"cond1\", TensorFrom(arrow::int64(),\n                                                                \"[0,0,0,0]\")),\n                          test::NamedTensor(\n                              \"cond2\", TensorFrom(arrow::boolean(),\n                                                  \"[false,false,false,false]\")),\n                          test::NamedTensor(\"cond3\", TensorFrom(arrow::int64(),\n                                                                \"[0,0,0,0]\"))},\n                .expect_out =\n                    {test::NamedTensor(\n                         \"out1\", TensorFrom(arrow::boolean(),\n                                            \"[false,false,false,false]\")),\n                     test::NamedTensor(\n                         \"out2\", TensorFrom(arrow::boolean(),\n                                            \"[false,false,false,false]\")),\n                     test::NamedTensor(\n                         \"out3\", TensorFrom(arrow::boolean(),\n                                            \"[false,false,false,false]\")),\n                     test::NamedTensor(\n                         \"out4\", TensorFrom(arrow::boolean(),\n                                            \"[true,true,true,true]\"))}})),\n    TestParamNameGenerator(CaseWhenConditionTest));\n\nTEST_P(CaseWhenConditionTest, condition) {\n  // Given\n  auto parm = GetParam();\n  auto test_case = std::get<1>(parm);\n  test::ExecNodeBuilder builder(CaseWhen::kOpType);\n  builder.SetNodeName(\"case_when_condition-test\");\n  // Build node\n  std::vector<pb::Tensor> conds;\n  for (size_t i = 0; i < test_case.conds.size(); i++) {\n    auto t = test::MakeTensorReference(test_case.conds[i].name,\n                                       test_case.conds[i].tensor->Type(),\n                                       pb::TENSORSTATUS_PUBLIC);\n    conds.push_back(std::move(t));\n  }\n  builder.AddInput(CaseWhen::kCond, conds);\n  auto node = builder.Build();\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n  std::vector<ExecContext> exec_ctxs;\n  for (size_t idx = 0; idx < sessions.size(); ++idx) {\n    exec_ctxs.emplace_back(node, sessions[idx].get());\n  }\n  std::vector<ExecContext*> ctx_ptrs;\n  for (size_t idx = 0; idx < exec_ctxs.size(); ++idx) {\n    ctx_ptrs.emplace_back(&exec_ctxs[idx]);\n  }\n\n  test::FeedInputsAsPublic(ctx_ptrs, test_case.conds);\n\n  auto CaseWhenOp = std::make_unique<CaseWhen>();\n  auto result = CaseWhenOp->TransformConditionData(ctx_ptrs[0]);\n  for (size_t i = 0; i < result.size(); i++) {\n    spu::NdArrayRef arr = spu::kernel::hal::dump_public(\n        ctx_ptrs[0]->GetSession()->GetSpuContext(), result[i]);\n    auto arrow = util::NdArrayToArrow(arr);\n    EXPECT_TRUE(arrow->Equals(\n        test_case.expect_out.at(i).tensor->ToArrowChunkedArray()));\n  }\n}\n\n/// ===========================\n/// CaseWhenTest impl\n/// ===========================\n\npb::ExecNode CaseWhenTest::MakeCaseWhenExecNode(const CaseWhenTestCase& tc) {\n  test::ExecNodeBuilder builder(CaseWhen::kOpType);\n\n  builder.SetNodeName(\"case_when-test\");\n  // Add inputs\n  std::vector<pb::Tensor> conds;\n  for (size_t i = 0; i < tc.conds.size(); i++) {\n    auto t = test::MakeTensorReference(\n        tc.conds[i].name, tc.conds[i].tensor->Type(), tc.cond_status[i]);\n    conds.push_back(std::move(t));\n  }\n\n  builder.AddInput(CaseWhen::kCond, conds);\n\n  std::vector<pb::Tensor> values;\n  for (size_t i = 0; i < tc.values.size(); i++) {\n    auto t = test::MakeTensorReference(\n        tc.values[i].name, tc.values[i].tensor->Type(), tc.value_status[i]);\n    values.push_back(std::move(t));\n  }\n  builder.AddInput(CaseWhen::kValue, values);\n\n  auto value_else = test::MakeTensorReference(\n      tc.value_else.name, tc.value_else.tensor->Type(), tc.value_else_status);\n  builder.AddInput(CaseWhen::kValueElse, std::vector<pb::Tensor>{value_else});\n\n  // Add outputs\n  auto out = test::MakeTensorReference(\n      tc.expect_out.name, tc.expect_out.tensor->Type(), tc.expect_out_status);\n  builder.AddOutput(CaseWhen::kOut, std::vector<pb::Tensor>{out});\n\n  return builder.Build();\n}\n\nvoid CaseWhenTest::FeedTensors(const std::vector<ExecContext*>& ctxs,\n                               const std::vector<test::NamedTensor>& ts,\n                               const std::vector<pb::TensorStatus>& status) {\n  for (size_t i = 0; i < ts.size(); i++) {\n    if (status[i] == pb::TENSORSTATUS_PRIVATE) {\n      test::FeedInputsAsPrivate(ctxs[0], {ts[i]});\n    } else if (status[i] == pb::TENSORSTATUS_SECRET) {\n      test::FeedInputsAsSecret(ctxs, {ts[i]});\n    } else {\n      test::FeedInputsAsPublic(ctxs, {ts[i]});\n    }\n  }\n}\n\nvoid CaseWhenTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                              const CaseWhenTestCase& tc) {\n  FeedTensors(ctxs, tc.conds, tc.cond_status);\n  FeedTensors(ctxs, tc.values, tc.value_status);\n  FeedTensors(ctxs, {tc.value_else}, {tc.value_else_status});\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/cast.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/cast.h\"\n\n#include \"arrow/compute/cast.h\"\n#include \"libspu/core/encoding.h\"\n#include \"libspu/kernel/hlo/casting.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/core/type.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Cast::kOpType(\"Cast\");\n\nconst std::string& Cast::Type() const { return kOpType; }\n\nvoid Cast::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() == 1, \"Cast input size={} not equal to 1\",\n               inputs.size());\n  YACL_ENFORCE(outputs.size() == 1, \"Cast output size={} not equal to 1\",\n               outputs.size());\n\n  YACL_ENFORCE(\n      util::IsTensorStatusMatched(outputs[0], util::GetTensorStatus(inputs[0])),\n      \"Cast output tensor's status should  be the same with input\");\n}\n\nvoid Cast::Execute(ExecContext* ctx) {\n  const auto& output_pb = ctx->GetOutput(kOut)[0];\n  if (ctx->GetInputStatus(kIn) == pb::TensorStatus::TENSORSTATUS_PRIVATE) {\n    auto tensor = ctx->GetInputTensor(kIn);\n    YACL_ENFORCE(tensor != nullptr, \"get tensor from tensor table failed\");\n\n    auto in_type = tensor->ArrowType();\n    auto to_type = ToArrowDataType(output_pb.elem_type());\n    YACL_ENFORCE(to_type, \"no arrow type for tensor type={}\",\n                 pb::PrimitiveDataType_Name(output_pb.elem_type()));\n\n    arrow::compute::CastOptions options;\n    options.allow_float_truncate = true;\n\n    arrow::Result<arrow::Datum> result;\n\n    if ((in_type->id() == arrow::Type::STRING ||\n         in_type->id() == arrow::Type::LARGE_STRING) &&\n        output_pb.elem_type() == pb::PrimitiveDataType::DATETIME) {\n      auto intermediate_type = arrow::timestamp(arrow::TimeUnit::SECOND);\n      auto intermediate_result = arrow::compute::Cast(\n          tensor->ToArrowChunkedArray(), intermediate_type);\n      YACL_ENFORCE(intermediate_result.ok(),\n                   \"caught error while invoking arrow cast: {}\",\n                   intermediate_result.status().ToString());\n\n      result = arrow::compute::Cast(\n          intermediate_result.ValueOrDie().chunked_array(), to_type, options);\n    } else {\n      result =\n          arrow::compute::Cast(tensor->ToArrowChunkedArray(), to_type, options);\n    }\n\n    YACL_ENFORCE(result.ok(), \"caught error while invoking arrow cast: {}\",\n                 result.status().ToString());\n\n    auto t = TensorFrom(result.ValueOrDie().chunked_array());\n    ctx->SetOutputTensor(kOut, std::move(t));\n    return;\n  }\n\n  YACL_ENFORCE(\n      ctx->GetInput(kIn)[0].elem_type() != pb::PrimitiveDataType::STRING &&\n          output_pb.elem_type() != pb::PrimitiveDataType::STRING,\n      \"string in spu is hash, not support cast\");\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto to_type = spu::getEncodeType(DataTypeToSpuPtType(output_pb.elem_type()));\n\n  auto value = ctx->GetInputValue(kIn);\n\n  auto result_value =\n      spu::kernel::hlo::Cast(sctx, value, value.vtype(), to_type);\n\n  ctx->SetOutputValue(kOut, result_value);\n\n#ifdef SCQL_WITH_NULL\n  auto validity = ctx->GetInputValidity(kIn);\n\n  ctx->SetOutputValidity(kOut, validity);\n#endif  // SCQL_WITH_NULL\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/cast.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass Cast : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/cast_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/cast.h\"\n\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n#include \"engine/util/spu_io.h\"\n\nnamespace scql::engine::op {\n\nstruct CastTestCase {\n  test::NamedTensor input;\n  pb::TensorStatus input_status;\n  bool string2datetime;\n  test::NamedTensor expect_out;\n};\n\nclass CastTest : public testing::TestWithParam<\n                     std::tuple<test::SpuRuntimeTestCase, CastTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const CastTestCase& tc);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const CastTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    CastBatchTest, CastTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            // test private status\n            CastTestCase{\n                .input = test::NamedTensor(\"in\", TensorFrom(arrow::int64(),\n                                                            \"[1, 2, 3, null]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .expect_out = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::float64(), \"[1.0, 2.0, 3.0, null]\"))},\n            CastTestCase{\n                .input = test::NamedTensor(\n                    \"in\", TensorFrom(arrow::float64(),\n                                     \"[-1.5, -0.1, 1.1, 2.3, 3.5, null]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .expect_out = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::int64(), \"[-1, 0, 1, 2, 3, null]\"))},\n            CastTestCase{.input = test::NamedTensor(\n                             \"in\", TensorFrom(arrow::float64(), \"[]\")),\n                         .input_status = pb::TENSORSTATUS_PRIVATE,\n                         .expect_out = test::NamedTensor(\n                             \"out\", TensorFrom(arrow::int64(), \"[]\"))},\n            CastTestCase{\n                .input = test::NamedTensor(\n                    \"in\",\n                    TensorFrom(\n                        arrow::large_utf8(),\n                        R\"json([\"2023-01-01T12:30:45\", \"2021-12-01\", \"2023-10-27 15:45:00\"])json\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .string2datetime = true,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(),\n                                      \"[1672576245, 1638316800, 1698421500]\"))},\n            CastTestCase{\n                .input = test::NamedTensor(\n                    \"in\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"123\", \"456\", \"789\"])json\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[123, 456, 789]\"))},\n            // test public status\n            CastTestCase{\n                .input = test::NamedTensor(\"in\", TensorFrom(arrow::int64(),\n                                                            \"[1, 2, 3]\")),\n                .input_status = pb::TENSORSTATUS_PUBLIC,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[1.0, 2.0, 3.0]\"))},\n            CastTestCase{\n                .input = test::NamedTensor(\n                    \"in\", TensorFrom(arrow::float64(),\n                                     \"[-1.5, -0.1, 1.1, 2.3, 3.5]\")),\n                .input_status = pb::TENSORSTATUS_PUBLIC,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[-1, 0, 1, 2, 3]\"))},\n            CastTestCase{.input = test::NamedTensor(\n                             \"in\", TensorFrom(arrow::float64(), \"[]\")),\n                         .input_status = pb::TENSORSTATUS_PUBLIC,\n                         .expect_out = test::NamedTensor(\n                             \"out\", TensorFrom(arrow::int64(), \"[]\"))},\n            // test secret status\n            CastTestCase{\n                .input = test::NamedTensor(\"in\", TensorFrom(arrow::int64(),\n                                                            \"[1, 2, 3]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[1.0, 2.0, 3.0]\"))},\n            CastTestCase{\n                .input = test::NamedTensor(\n                    \"in\", TensorFrom(arrow::float64(),\n                                     \"[-1.5, -0.1, 1.1, 2.3, 3.5]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[-1, 0, 1, 2, 3]\"))},\n            CastTestCase{.input = test::NamedTensor(\n                             \"in\", TensorFrom(arrow::float64(), \"[]\")),\n                         .input_status = pb::TENSORSTATUS_SECRET,\n                         .expect_out = test::NamedTensor(\n                             \"out\", TensorFrom(arrow::int64(), \"[]\"))})),\n    TestParamNameGenerator(CastTest));\n\nTEST_P(CastTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  for (size_t idx = 0; idx < sessions.size(); ++idx) {\n    exec_ctxs.emplace_back(node, sessions[idx].get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  for (size_t idx = 0; idx < exec_ctxs.size(); ++idx) {\n    ctx_ptrs.emplace_back(&exec_ctxs[idx]);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  EXPECT_NO_THROW(test::RunAsync<Cast>(ctx_ptrs));\n\n  // Then\n  // check alice output\n  TensorPtr t = nullptr;\n  if (tc.input_status == pb::TENSORSTATUS_PRIVATE) {\n    t = ctx_ptrs[0]->GetTensorTable()->GetTensor(tc.expect_out.name);\n  } else if (tc.input_status == pb::TENSORSTATUS_PUBLIC) {\n    auto spu_io =\n        util::SpuOutfeedHelper(ctx_ptrs[0]->GetSession()->GetSpuContext(),\n                               ctx_ptrs[0]->GetSession()->GetDeviceSymbols());\n    EXPECT_NO_THROW(t = spu_io.DumpPublic(tc.expect_out.name));\n  } else {\n    EXPECT_NO_THROW(t = test::RevealSecret(ctx_ptrs, tc.expect_out.name));\n  }\n  ASSERT_TRUE(t);\n  auto out_arr = t->ToArrowChunkedArray();\n\n  auto expect_arr = tc.expect_out.tensor->ToArrowChunkedArray();\n\n  // compare tensor content\n  EXPECT_TRUE(out_arr->Equals(expect_arr))\n      << \"expect type = \" << expect_arr->type()->ToString()\n      << \", got type = \" << out_arr->type()->ToString()\n      << \"\\nexpect result = \" << expect_arr->ToString()\n      << \"\\nbut actual got result = \" << out_arr->ToString();\n}\n\n/// ===================\n/// CastTest impl\n/// ===================\n\npb::ExecNode CastTest::MakeExecNode(const CastTestCase& tc) {\n  test::ExecNodeBuilder builder(Cast::kOpType);\n  builder.SetNodeName(\"cast-test\");\n\n  {\n    auto t = test::MakeTensorReference(tc.input.name, tc.input.tensor->Type(),\n                                       tc.input_status);\n    builder.AddInput(Cast::kIn, {t});\n  }\n\n  {\n    pb::Tensor t;\n    if (tc.string2datetime) {\n      t = test::MakeTensorReference(\n          tc.expect_out.name, pb::PrimitiveDataType::DATETIME, tc.input_status);\n    } else {\n      t = test::MakeTensorReference(\n          tc.expect_out.name, tc.expect_out.tensor->Type(), tc.input_status);\n    }\n    builder.AddOutput(Cast::kOut, {t});\n  }\n\n  return builder.Build();\n}\n\nvoid CastTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                          const CastTestCase& tc) {\n  if (tc.input_status == pb::TensorStatus::TENSORSTATUS_PRIVATE) {\n    for (auto* ctx : ctxs) {\n      test::FeedInputsAsPrivate(ctx, {tc.input});\n    }\n  } else if (tc.input_status == pb::TensorStatus::TENSORSTATUS_SECRET) {\n    test::FeedInputsAsSecret(ctxs, {tc.input});\n  } else {\n    test::FeedInputsAsPublic(ctxs, {tc.input});\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/coalesce.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/coalesce.h\"\n\n#include \"arrow/compute/api.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Coalesce::kOpType(\"Coalesce\");\n\nconst std::string& Coalesce::Type() const { return kOpType; }\n\nvoid Coalesce::Validate(ExecContext* ctx) {\n  const auto& exprs = ctx->GetInput(kExprs);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(exprs.size() > 0, \"Coalesce input Exprs size be greater than 0\",\n               exprs.size());\n  YACL_ENFORCE(outputs.size() == 1, \"Coalesce output size={} not equal to 1\",\n               outputs.size());\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   exprs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"Coalesce input exprs tensors' status should be private\");\n  YACL_ENFORCE(util::IsTensorStatusMatched(\n                   outputs[0], pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"Coalesce output tensor's status should be private\");\n}\n\nvoid Coalesce::Execute(ExecContext* ctx) {\n  auto exprs = ctx->GetInputTensors(kExprs);\n  std::vector<arrow::Datum> datums;\n  for (const auto& expr : exprs) {\n    datums.emplace_back(expr->ToArrowChunkedArray());\n  }\n\n  auto result = arrow::compute::CallFunction(\"coalesce\", datums);\n  YACL_ENFORCE(result.ok(), \"caught error while invoking arrow coalesce: {}\",\n               result.status().ToString());\n\n  ctx->SetOutputTensor(kOut, TensorFrom(result.ValueOrDie().chunked_array()));\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/coalesce.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass Coalesce : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kExprs[] = \"Exprs\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/coalesce_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/coalesce.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct CoalesceTestCase {\n  std::vector<test::NamedTensor> exprs;\n  test::NamedTensor expect_out;\n};\n\nclass CoalesceTest\n    : public testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, CoalesceTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const CoalesceTestCase& tc);\n  static void FeedInputs(ExecContext* ctx, const CoalesceTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    CoalesceBatchTest, CoalesceTest,\n    testing::Combine(\n        testing::Values(test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2}),\n        testing::Values(\n            // test private status\n            CoalesceTestCase{\n                .exprs = {test::NamedTensor(\"expr1\",\n                                            TensorFrom(arrow::int64(),\n                                                       \"[null, 2, 3, null]\")),\n                          test::NamedTensor(\"expr2\",\n                                            TensorFrom(arrow::int64(),\n                                                       \"[null, 12, 13, 14]\"))},\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[null, 2, 3, 14]\"))},\n            CoalesceTestCase{\n                .exprs = {test::NamedTensor(\n                    \"expr\",\n                    TensorFrom(arrow::float64(), \"[null, -0.1, 1.1, null]\"))},\n                .expect_out = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::float64(), \"[null, -0.1, 1.1, null]\"))},\n            CoalesceTestCase{\n                .exprs = {test::NamedTensor(\n                              \"expr1\",\n                              TensorFrom(arrow::large_utf8(),\n                                         R\"json([\"B\", null, null ,\"B\"])json\")),\n                          test::NamedTensor(\n                              \"expr2\",\n                              TensorFrom(\n                                  arrow::large_utf8(),\n                                  R\"json([\"CC\", null, \"CC\" ,\"C\"])json\"))},\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"B\", null, \"CC\" ,\"B\"])json\"))},\n            CoalesceTestCase{\n                .exprs = {test::NamedTensor(\"expr1\",\n                                            TensorFrom(arrow::float64(), \"[]\")),\n                          test::NamedTensor(\n                              \"expr2\", TensorFrom(arrow::float64(), \"[]\"))},\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[]\"))})),\n    TestParamNameGenerator(CoalesceTest));\n\nTEST_P(CoalesceTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto session = test::Make1PCSession();\n  ExecContext ctx(node, session.get());\n\n  FeedInputs(&ctx, tc);\n\n  // When\n  Coalesce op;\n  ASSERT_NO_THROW(op.Run(&ctx));\n\n  // Then\n  // check alice output\n  TensorPtr t = session->GetTensorTable()->GetTensor(tc.expect_out.name);\n  ASSERT_TRUE(t);\n  auto out_arr = t->ToArrowChunkedArray();\n\n  auto expect_arr = tc.expect_out.tensor->ToArrowChunkedArray();\n\n  // compare tensor content\n  EXPECT_TRUE(out_arr->Equals(expect_arr))\n      << \"expect type = \" << expect_arr->type()->ToString()\n      << \", got type = \" << out_arr->type()->ToString()\n      << \"\\nexpect result = \" << expect_arr->ToString()\n      << \"\\nbut actual got result = \" << out_arr->ToString();\n}\n\n/// ===================\n/// CoalesceTest impl\n/// ===================\n\npb::ExecNode CoalesceTest::MakeExecNode(const CoalesceTestCase& tc) {\n  test::ExecNodeBuilder builder(Coalesce::kOpType);\n  builder.SetNodeName(\"if-null-test\");\n\n  std::vector<pb::Tensor> inputs;\n  for (auto expr : tc.exprs) {\n    auto t = test::MakePrivateTensorReference(expr.name, expr.tensor->Type());\n    inputs.push_back(t);\n  }\n  builder.AddInput(Coalesce::kExprs, inputs);\n\n  {\n    auto t = test::MakePrivateTensorReference(tc.expect_out.name,\n                                              tc.expect_out.tensor->Type());\n    builder.AddOutput(Coalesce::kOut, {t});\n  }\n\n  return builder.Build();\n}\n\nvoid CoalesceTest::FeedInputs(ExecContext* ctx, const CoalesceTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, tc.exprs);\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/compare.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/compare.h\"\n\n#include \"arrow/compute/api.h\"\n#include \"arrow/compute/api_vector.h\"\n#include \"arrow/compute/exec.h\"\n#include \"arrow/datum.h\"\n#include \"arrow/result.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/casting.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/context_util.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nvoid CompareBase::ValidateIoDataTypes(ExecContext* ctx) {\n  // TODO(jingshi) : add input type checks, maybe we should override this in\n  // operators.\n\n  const auto& outputs = ctx->GetOutput(kOut);\n  const auto& output_type = outputs[0].elem_type();\n  YACL_ENFORCE(output_type == pb::PrimitiveDataType::BOOL,\n               \"outputs' data type={}, only {} supported\",\n               pb::PrimitiveDataType_Name(output_type),\n               pb::PrimitiveDataType_Name(pb::PrimitiveDataType::BOOL));\n}\n\n// ===========================\n//   Equal impl\n// ===========================\n\nconst std::string Equal::kOpType(\"Equal\");\n\nconst std::string& Equal::Type() const { return kOpType; }\n\nspu::Value Equal::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                               const spu::Value& rhs) {\n  return spu::kernel::hlo::Equal(sctx, lhs, rhs);\n}\n\nTensorPtr Equal::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"equal\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow equal function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   NotEqual impl\n// ===========================\n\nconst std::string NotEqual::kOpType(\"NotEqual\");\n\nconst std::string& NotEqual::Type() const { return kOpType; }\n\nspu::Value NotEqual::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                                  const spu::Value& rhs) {\n  return spu::kernel::hlo::NotEqual(sctx, lhs, rhs);\n}\n\nTensorPtr NotEqual::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"not_equal\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow not_equal function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   Less impl\n// ===========================\n\nconst std::string Less::kOpType(\"Less\");\n\nconst std::string& Less::Type() const { return kOpType; }\n\nspu::Value Less::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                              const spu::Value& rhs) {\n  return spu::kernel::hlo::Less(sctx, lhs, rhs);\n}\n\nTensorPtr Less::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"less\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow less function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   LessEqual impl\n// ===========================\n\nconst std::string LessEqual::kOpType(\"LessEqual\");\n\nconst std::string& LessEqual::Type() const { return kOpType; }\n\nspu::Value LessEqual::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                                   const spu::Value& rhs) {\n  return spu::kernel::hlo::LessEqual(sctx, lhs, rhs);\n}\n\nTensorPtr LessEqual::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"less_equal\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow less_equal function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   GreaterEqual impl\n// ===========================\n\nconst std::string GreaterEqual::kOpType(\"GreaterEqual\");\n\nconst std::string& GreaterEqual::Type() const { return kOpType; }\n\nspu::Value GreaterEqual::ComputeOnSpu(spu::SPUContext* sctx,\n                                      const spu::Value& lhs,\n                                      const spu::Value& rhs) {\n  return spu::kernel::hlo::GreaterEqual(sctx, lhs, rhs);\n}\n\nTensorPtr GreaterEqual::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"greater_equal\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow greater_equal function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   Greater impl\n// ===========================\n\nconst std::string Greater::kOpType(\"Greater\");\n\nconst std::string& Greater::Type() const { return kOpType; }\n\nspu::Value Greater::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                                 const spu::Value& rhs) {\n  return spu::kernel::hlo::Greater(sctx, lhs, rhs);\n}\n\nTensorPtr Greater::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"greater\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow greater function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   Variadic definition\n// ===========================\n\nvoid Variadic::Validate(ExecContext* ctx) {\n  YACL_ENFORCE(ctx, \"context is null\");\n  auto inputs = ctx->GetInput(kIn);\n  YACL_ENFORCE(inputs.size() >= 2,\n               \"variadic compare requires at least 2 inputs\");\n  auto output = ctx->GetOutput(kOut);\n  YACL_ENFORCE(output.size() == 1, \"multi-input compare requires one output\");\n}\n\nvoid Variadic::ExecuteInPlain(ExecContext* ctx) {\n  auto inputs = ctx->GetInputTensors(kIn);\n\n  auto output_ptr = ComputeInPlain(inputs);\n  ctx->SetOutputTensor(kOut, std::move(output_ptr));\n}\n\nvoid Variadic::ExecuteOnSpu(ExecContext* ctx) {\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  YACL_ENFORCE(sctx != nullptr, \"spu context is nullptr\");\n\n  auto input_values = ctx->GetInputValues(kIn);\n  auto output_value = ComputeOnSpu(sctx, input_values);\n  ctx->SetOutputValue(kOut, output_value);\n}\n\nvoid Variadic::Execute(ExecContext* ctx) {\n  if (ctx->GetOutputStatus(kOut) == pb::TENSORSTATUS_PRIVATE) {\n    ExecuteInPlain(ctx);\n  } else {\n    ExecuteOnSpu(ctx);\n  }\n}\n\n// ===========================\n//   Greatest impl\n// ===========================\nconst std::string Greatest::kOpType(\"Greatest\");\nconst std::string& Greatest::Type() const { return kOpType; }\n\nTensorPtr Greatest::ComputeInPlain(const std::vector<TensorPtr>& inputs) {\n  std::vector<arrow::Datum> input_datums;\n  input_datums.reserve(inputs.size());\n  for (const auto& input : inputs) {\n    input_datums.emplace_back(input->ToArrowChunkedArray());\n  }\n\n  auto status = arrow::compute::MaxElementWise(input_datums);\n  YACL_ENFORCE(status.ok(),\n               \"caught error while invoking arrow max function: {}\",\n               status->ToString());\n\n  return TensorFrom(status.ValueOrDie().chunked_array());\n}\n\nspu::Value Greatest::ComputeOnSpu(spu::SPUContext* sctx,\n                                  const std::vector<spu::Value>& inputs) {\n  spu::Value greatest_value = inputs[0];\n  bool mix_type = false;\n  spu::DataType output_type = greatest_value.dtype();\n  for (size_t i = 1; i < inputs.size(); i++) {\n    if (greatest_value.dtype() != inputs[i].dtype()) {\n      mix_type = true;\n    }\n\n    spu::Value next_value = inputs[i];\n    output_type = util::GetWiderSpuType(output_type, inputs[i].dtype());\n    if (mix_type) {\n      if (greatest_value.dtype() != output_type) {\n        greatest_value = spu::kernel::hlo::Cast(\n            sctx, greatest_value, greatest_value.vtype(), output_type);\n      }\n\n      if (next_value.dtype() != output_type) {\n        next_value = spu::kernel::hlo::Cast(sctx, inputs[i], inputs[i].vtype(),\n                                            output_type);\n      }\n    }\n    greatest_value = spu::kernel::hlo::Max(sctx, greatest_value, next_value);\n  }\n\n  return greatest_value;\n}\n\n// ===========================\n//   Least impl\n// ===========================\nconst std::string Least::kOpType(\"Least\");\nconst std::string& Least::Type() const { return kOpType; }\n\nTensorPtr Least::ComputeInPlain(const std::vector<TensorPtr>& inputs) {\n  std::vector<arrow::Datum> input_datums;\n  input_datums.reserve(inputs.size());\n  for (const auto& input : inputs) {\n    input_datums.emplace_back(input->ToArrowChunkedArray());\n  }\n\n  auto status = arrow::compute::MinElementWise(input_datums);\n  YACL_ENFORCE(status.ok(),\n               \"caught error while invoking arrow min function: {}\",\n               status->ToString());\n\n  return TensorFrom(status.ValueOrDie().chunked_array());\n}\n\nspu::Value Least::ComputeOnSpu(spu::SPUContext* sctx,\n                               const std::vector<spu::Value>& inputs) {\n  spu::Value least_value = inputs[0];\n  bool mix_type = false;\n  spu::DataType output_type = least_value.dtype();\n  for (size_t i = 1; i < inputs.size(); i++) {\n    if (least_value.dtype() != inputs[i].dtype()) {\n      mix_type = true;\n    }\n\n    spu::Value next_value = inputs[i];\n    output_type = util::GetWiderSpuType(output_type, inputs[i].dtype());\n    if (mix_type) {\n      if (least_value.dtype() != output_type) {\n        least_value = spu::kernel::hlo::Cast(sctx, least_value,\n                                             least_value.vtype(), output_type);\n      }\n      if (next_value.dtype() != output_type) {\n        next_value = spu::kernel::hlo::Cast(sctx, inputs[i], inputs[i].vtype(),\n                                            output_type);\n      }\n    }\n    least_value = spu::kernel::hlo::Min(sctx, least_value, next_value);\n  }\n\n  return least_value;\n}\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/compare.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/operator/binary_base.h\"\n\nnamespace scql::engine::op {\n\n/// @brief CompareBase is the base class of operators:\n/// {<Equal/NotEqual/Less/LessEqual/GreaterEqual/Greater>}\nclass CompareBase : public BinaryBase {\n protected:\n  void ValidateIoDataTypes(ExecContext* ctx) override;\n};\n\nclass Equal : public CompareBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass NotEqual : public CompareBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass Less : public CompareBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass LessEqual : public CompareBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass GreaterEqual : public CompareBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass Greater : public CompareBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass Variadic : public Operator {\n public:\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n  void ExecuteInPlain(ExecContext* ctx);\n  void ExecuteOnSpu(ExecContext* ctx);\n  virtual TensorPtr ComputeInPlain(const std::vector<TensorPtr>& inputs) = 0;\n  virtual spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                                  const std::vector<spu::Value>& inputs) = 0;\n};\n\nclass Greatest : public Variadic {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n protected:\n  TensorPtr ComputeInPlain(const std::vector<TensorPtr>& inputs) override;\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                          const std::vector<spu::Value>& inputs) override;\n};\n\nclass Least : public Variadic {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n protected:\n  TensorPtr ComputeInPlain(const std::vector<TensorPtr>& inputs) override;\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                          const std::vector<spu::Value>& inputs) override;\n};\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/compare_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/compare.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/operator/binary_test.h\"\n\nnamespace scql::engine::op {\n\nstruct VariadicCompareTestCase {\n  std::string op_type;\n  std::vector<test::NamedTensor> inputs;\n  pb::TensorStatus input_status;\n\n  std::vector<test::NamedTensor> outputs;\n  pb::TensorStatus output_status;\n};\n\nclass VariadicCompareTest\n    : public testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, VariadicCompareTestCase>> {\n protected:\n  void SetUp() override { RegisterAllOps(); }\n\n public:\n  static pb::ExecNode MakeExecNode(const VariadicCompareTestCase& tc);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const VariadicCompareTestCase& tc);\n\n  static std::unique_ptr<Operator> CreateOp(const std::string& op_type) {\n    return GetOpRegistry()->GetOperator(op_type);\n  }\n};\n\npb::ExecNode VariadicCompareTest::MakeExecNode(\n    const VariadicCompareTestCase& tc) {\n  test::ExecNodeBuilder builder(tc.op_type);\n  builder.SetNodeName(tc.op_type + \"-test\");\n  std::vector<pb::Tensor> inputs;\n  std::vector<pb::Tensor> outputs;\n  for (const auto& tensor : tc.inputs) {\n    auto t = test::MakeTensorReference(tensor.name, tensor.tensor->Type(),\n                                       tc.input_status);\n    inputs.push_back(t);\n  }\n\n  {\n    auto t = test::MakeTensorReference(\n        tc.outputs[0].name, tc.outputs[0].tensor->Type(), tc.output_status);\n    outputs.push_back(t);\n  }\n\n  builder.AddInput(Variadic::kIn, inputs);\n  builder.AddOutput(Variadic::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid VariadicCompareTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                                     const VariadicCompareTestCase& tc) {\n  auto infeed = [](const std::vector<ExecContext*>& ctxs,\n                   pb::TensorStatus input_status,\n                   const std::vector<test::NamedTensor>& inputs) {\n    if (input_status == pb::TENSORSTATUS_PRIVATE) {\n      // feed private inputs into ctxs[0]\n      test::FeedInputsAsPrivate(ctxs[0], inputs);\n    } else if (input_status == pb::TENSORSTATUS_SECRET) {\n      test::FeedInputsAsSecret(ctxs, inputs);\n    } else {\n      test::FeedInputsAsPublic(ctxs, inputs);\n    }\n  };\n\n  infeed(ctxs, tc.input_status, tc.inputs);\n}\n\n// ===========================\n//   Greatest test suit\n// ===========================\nINSTANTIATE_TEST_SUITE_P(\n    VariadicCompareTests, VariadicCompareTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            VariadicCompareTestCase{\n                .op_type = Greatest::kOpType,\n                .inputs = {test::NamedTensor(\"x\", TensorFrom(arrow::int64(),\n                                                             \"[1, 2, 3]\")),\n                           test::NamedTensor(\"y\", TensorFrom(arrow::int64(),\n                                                             \"[0, 2, 4]\"))},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[1, 2, 4]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            VariadicCompareTestCase{\n                .op_type = Greatest::kOpType,\n                .inputs = {test::NamedTensor(\"x\", TensorFrom(arrow::int64(),\n                                                             \"[1, 2, 3]\")),\n                           test::NamedTensor(\"y\", TensorFrom(arrow::int64(),\n                                                             \"[0, 2, 4]\"))},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[1, 2, 4]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            VariadicCompareTestCase{\n                .op_type = Least::kOpType,\n                .inputs = {test::NamedTensor(\"x\", TensorFrom(arrow::int64(),\n                                                             \"[1, 2, 3]\")),\n                           test::NamedTensor(\"y\", TensorFrom(arrow::int64(),\n                                                             \"[0, 2, 4]\"))},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[0, 2, 3]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            VariadicCompareTestCase{\n                .op_type = Least::kOpType,\n                .inputs = {test::NamedTensor(\"x\", TensorFrom(arrow::int64(),\n                                                             \"[1, 2, 3]\")),\n                           test::NamedTensor(\"y\", TensorFrom(arrow::int64(),\n                                                             \"[0, 2, 4]\"))},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::int64(),\n                                                              \"[0, 2, 3]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            })));\n\n// ===========================\n//   Equal test suit\n// ===========================\n\nINSTANTIATE_TEST_SUITE_P(\n    EqualBatchTest, BinaryComputeInSecretTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = Equal::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, 2, 4]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, 1, 0]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Equal::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, 2.0, 3.14]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.1415, 2.01, 3.1415]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, 1, 0, 0]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Equal::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"B\", \"C\", \"D\"])json\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"C\", \"B\", \"D\"])json\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, 0, 0, 1]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            // testcase with empty inputs\n            BinaryTestCase{\n                .op_type = Equal::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            })),\n    TestParamNameGenerator(BinaryComputeInSecretTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    EqualBatchTest, BinaryComputeInPlainTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = Equal::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, null, 3]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, null, 1]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = Equal::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, null, 3.14, 100]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.1415, 1.999, 3.1415, 99.9]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(), \"[0, 1, null, 0, 0]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = Equal::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"B\", \"C\", \"D\"])json\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"C\", \"B\", \"D\"])json\"))},\n                .right_input_status = pb::TENSORSTATUS_PUBLIC,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, 0, 0, 1]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = Equal::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            })),\n    TestParamNameGenerator(BinaryComputeInSecretTest));\n\n// ===========================\n//   NotEqual test suit\n// ===========================\n\nINSTANTIATE_TEST_SUITE_P(\n    NotEqualBatchTest, BinaryComputeInSecretTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = NotEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, 2, 4]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, 0, 1]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = NotEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, 2.0, 3.14]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.1415, 2.01, 3.1415]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, 0, 1, 1]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = NotEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"B\", \"C\", \"D\"])json\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"C\", \"B\", \"D\"])json\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, 1, 1, 0]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            // testcase with empty inputs\n            BinaryTestCase{\n                .op_type = NotEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            })),\n    TestParamNameGenerator(BinaryComputeInSecretTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    NotEqualBatchTest, BinaryComputeInPlainTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = NotEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, null, 3]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, null, 0]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = NotEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, null, 3.14, 100]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.1415, 1.999, 3.1415, 99.9]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(), \"[1, 0, null, 1, 1]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = NotEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"B\", \"C\", \"D\"])json\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"C\", \"B\", \"D\"])json\"))},\n                .right_input_status = pb::TENSORSTATUS_PUBLIC,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, 1, 1, 0]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            })),\n    TestParamNameGenerator(BinaryComputeInPlainTest));\n\n// ===========================\n//   Less test suit\n// ===========================\n\nINSTANTIATE_TEST_SUITE_P(\n    LessBatchTest, BinaryComputeInSecretTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = Less::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, 2, 4]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, 0, 1]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Less::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, 2.0, 3.14]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.14, 1.999, 3.1415]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, 1, 0, 1]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            // testcase: with empty inputs\n            BinaryTestCase{\n                .op_type = Less::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            })),\n    TestParamNameGenerator(BinaryComputeInSecretTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    LessBatchTest, BinaryComputeInPlainTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = Less::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, null, 4]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, null, 1]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = Less::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, null, 3.14, 100]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.14, 1.999, 3.1415, 99.9]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(), \"[0, 1, null, 1, 0]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            })),\n    TestParamNameGenerator(BinaryComputeInPlainTest));\n\n// ===========================\n//   LessEqual test suit\n// ===========================\n\nINSTANTIATE_TEST_SUITE_P(\n    LessEqualBatchTest, BinaryComputeInSecretTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = LessEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, 2, 4]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, 1, 1]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = LessEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, 2.0, 3.14]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.14, 1.999, 3.1415]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, 1, 0, 1]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            // testcase with empty inputs\n            BinaryTestCase{\n                .op_type = LessEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            })),\n    TestParamNameGenerator(BinaryComputeInSecretTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    LessEqualBatchTest, BinaryComputeInPlainTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = LessEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, null, 4]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[0, null, 1]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = LessEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, null, 3.14, 100]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.14, 1.999, 3.1415, 99.9]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(), \"[0, 1, null, 1, 0]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            })),\n    TestParamNameGenerator(BinaryComputeInPlainTest));\n\n// ===========================\n//   GreaterEqual test suit\n// ===========================\n\nINSTANTIATE_TEST_SUITE_P(\n    GreaterEqualBatchTest, BinaryComputeInSecretTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = GreaterEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, 2, 4]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, 1, 0]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = GreaterEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, 2.0, 3.14]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.14, 1.999, 3.1415]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, 0, 1, 0]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            // testcase with empty inputs\n            BinaryTestCase{\n                .op_type = GreaterEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            })),\n    TestParamNameGenerator(BinaryComputeInSecretTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    GreaterEqualBatchTest, BinaryComputeInPlainTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = GreaterEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, null, 4]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, null, 0]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = GreaterEqual::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, null, 3.14, 100]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.14, 1.999, 3.1415, 99.9]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(), \"[1, 0, null, 0, 1]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            })),\n    TestParamNameGenerator(BinaryComputeInPlainTest));\n\n// ===========================\n//   Greater test suit\n// ===========================\n\nINSTANTIATE_TEST_SUITE_P(\n    GreaterBatchTest, BinaryComputeInSecretTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = Greater::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, 2, 4]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, 0, 0]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            BinaryTestCase{\n                .op_type = Greater::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, 2.0, 3.14]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.14, 1.999, 3.1415]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, 0, 1, 0]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            },\n            // testcase with empty inputs\n            BinaryTestCase{\n                .op_type = Greater::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET,\n            })),\n    TestParamNameGenerator(BinaryComputeInSecretTest));\n\nTEST_P(VariadicCompareTest, Works) {\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  auto op = CreateOp(tc.op_type);\n  if (tc.output_status == pb::TENSORSTATUS_PRIVATE) {\n    EXPECT_NO_THROW(op->Run(ctx_ptrs[0]));\n  } else {\n    EXPECT_NO_THROW(\n        test::RunOpAsync(ctx_ptrs, [&]() { return CreateOp(tc.op_type); }));\n  }\n\n  for (const auto& named_tensor : tc.outputs) {\n    TensorPtr t = nullptr;\n    if (tc.output_status == pb::TENSORSTATUS_PRIVATE) {\n      EXPECT_NO_THROW(\n          t = ctx_ptrs[0]->GetTensorTable()->GetTensor(named_tensor.name));\n    } else {\n      EXPECT_NO_THROW({ t = test::RevealSecret(ctx_ptrs, named_tensor.name); });\n    }\n\n    ASSERT_TRUE(t != nullptr);\n    EXPECT_TRUE(t->ToArrowChunkedArray()->ApproxEquals(\n        *named_tensor.tensor->ToArrowChunkedArray(),\n        arrow::EqualOptions::Defaults().atol(0.05)))\n        << \"expect type = \"\n        << named_tensor.tensor->ToArrowChunkedArray()->type()->ToString()\n        << \", got type = \" << t->ToArrowChunkedArray()->type()->ToString()\n        << \"\\nexpect result = \"\n        << named_tensor.tensor->ToArrowChunkedArray()->ToString()\n        << \"\\nbut actual got result = \" << t->ToArrowChunkedArray()->ToString();\n  }\n}\n\nINSTANTIATE_TEST_SUITE_P(\n    GreaterBatchTest, BinaryComputeInPlainTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = Greater::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::int64(), \"[0, null, 4]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                              \"[1, null, 0]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            },\n            BinaryTestCase{\n                .op_type = Greater::kOpType,\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[-100.0, -3.1415, null, 3.14, 100]\"))},\n                .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(),\n                                    \"[-200, -3.14, 1.999, 3.1415, 99.9]\"))},\n                .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(), \"[1, 0, null, 0, 1]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE,\n            })),\n    TestParamNameGenerator(BinaryComputeInPlainTest));\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/concat.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/concat.h\"\n\n#include \"libspu/core/encoding.h\"\n#include \"libspu/kernel/hlo/casting.h\"\n#include \"libspu/kernel/hlo/geometrical.h\"\n\n#include \"engine/core/type.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Concat::kOpType(\"Concat\");\n\nconst std::string& Concat::Type() const { return kOpType; }\n\nvoid Concat::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() > 0, \"Concat input size must > 0\");\n  YACL_ENFORCE(outputs.size() == 1, \"Concatoutput size={} not equal to 1\",\n               outputs.size());\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   inputs, pb::TensorStatus::TENSORSTATUS_SECRET),\n               \"Concat input tensors' statuses should all be secret\");\n  YACL_ENFORCE(util::IsTensorStatusMatched(\n                   outputs[0], pb::TensorStatus::TENSORSTATUS_SECRET),\n               \"Concat output tensor's status should  be secret\");\n}\n\nvoid Concat::Execute(ExecContext* ctx) {\n  const auto& output_pb = ctx->GetOutput(kOut)[0];\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n\n  spu::DataType output_type = spu::DataType::DT_INVALID;\n  if (output_pb.elem_type() != pb::PrimitiveDataType::STRING) {\n    output_type =\n        spu::getEncodeType(DataTypeToSpuPtType(output_pb.elem_type()));\n  }\n\n  auto values = ctx->GetInputValues(kIn);\n  for (size_t i = 0; i < values.size(); ++i) {\n    if (output_type != spu::DataType::DT_INVALID &&\n        output_type != values[i].dtype()) {\n      values[i] = spu::kernel::hlo::Cast(sctx, values[i], values[i].vtype(),\n                                         output_type);\n    }\n  }\n\n  int64_t axis = ctx->GetInt64ValueFromAttribute(kAxis);\n  auto result_value = spu::kernel::hlo::Concatenate(sctx, values, axis);\n\n  ctx->SetOutputValue(kOut, result_value);\n\n#ifdef SCQL_WITH_NULL\n  auto validities = ctx->GetInputValidities(kIn);\n  auto result_validity = spu::kernel::hlo::Concatenate(sctx, validities, axis);\n\n  ctx->SetOutputValidity(kOut, result_validity);\n#endif  // SCQL_WITH_NULL\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/concat.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass Concat : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n  static constexpr char kAxis[] = \"axis\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/concat_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/concat.h\"\n\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct ConcatTestCase {\n  std::vector<test::NamedTensor> inputs;\n  test::NamedTensor expect_out;\n};\n\nclass ConcatTest : public testing::TestWithParam<\n                       std::tuple<test::SpuRuntimeTestCase, ConcatTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const ConcatTestCase& tc);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const ConcatTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    ConcatBatchTest, ConcatTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ConcatTestCase{\n                .inputs = {test::NamedTensor(\"a\", TensorFrom(arrow::int64(),\n                                                             \"[1, 2]\")),\n                           test::NamedTensor(\"b\", TensorFrom(arrow::int64(),\n                                                             \"[3]\"))},\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1, 2, 3]\"))},\n            ConcatTestCase{\n                .inputs = {test::NamedTensor(\n                               \"a\", TensorFrom(arrow::large_utf8(),\n                                               R\"json([\"A\", \"B\", \"C\"])json\")),\n                           test::NamedTensor(\"b\",\n                                             TensorFrom(arrow::large_utf8(),\n                                                        R\"json([])json\"))},\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"A\", \"B\", \"C\"])json\"))})),\n    TestParamNameGenerator(ConcatTest));\n\nTEST_P(ConcatTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  for (size_t idx = 0; idx < sessions.size(); ++idx) {\n    exec_ctxs.emplace_back(node, sessions[idx].get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  for (size_t idx = 0; idx < exec_ctxs.size(); ++idx) {\n    ctx_ptrs.emplace_back(&exec_ctxs[idx]);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  EXPECT_NO_THROW(test::RunAsync<Concat>(ctx_ptrs));\n\n  // Then\n  // check alice output\n  TensorPtr t = nullptr;\n  EXPECT_NO_THROW(t = test::RevealSecret(ctx_ptrs, tc.expect_out.name));\n  ASSERT_TRUE(t);\n  // convert hash to string for string tensor in spu\n  if (tc.expect_out.tensor->Type() == pb::PrimitiveDataType::STRING) {\n    t = ctx_ptrs[0]->GetSession()->HashToString(*t);\n  }\n  auto out_arr = t->ToArrowChunkedArray();\n\n  auto expect_arr = tc.expect_out.tensor->ToArrowChunkedArray();\n\n  // compare tensor content\n  EXPECT_TRUE(out_arr->Equals(expect_arr))\n      << \"expect type = \" << expect_arr->type()->ToString()\n      << \", got type = \" << out_arr->type()->ToString()\n      << \"\\nexpect result = \" << expect_arr->ToString()\n      << \"\\nbut actual got result = \" << out_arr->ToString();\n}\n\n/// ===================\n/// ConcatTest impl\n/// ===================\n\npb::ExecNode ConcatTest::MakeExecNode(const ConcatTestCase& tc) {\n  test::ExecNodeBuilder builder(Concat::kOpType);\n\n  builder.SetNodeName(\"concat-test\");\n  builder.AddInt64Attr(Concat::kAxis, 0);\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    auto t = test::MakeSecretTensorReference(named_tensor.name,\n                                             named_tensor.tensor->Type());\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(Concat::kIn, inputs);\n\n  {\n    auto t = test::MakeSecretTensorReference(tc.expect_out.name,\n                                             tc.expect_out.tensor->Type());\n    builder.AddOutput(Concat::kOut, {t});\n  }\n\n  return builder.Build();\n}\n\nvoid ConcatTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                            const ConcatTestCase& tc) {\n  test::FeedInputsAsSecret(ctxs, tc.inputs);\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/constant.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/constant.h\"\n\n#include \"libspu/device/io.h\"\n#include \"libspu/device/symbol_table.h\"\n\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/string_tensor_builder.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Constant::kOpType(\"Constant\");\n\nconst std::string& Constant::Type() const { return kOpType; }\n\nvoid Constant::Validate(ExecContext* ctx) {\n  const auto& outputs = ctx->GetOutput(kOut);\n  YACL_ENFORCE(outputs.size() == 1, \"Constant output size={} not equal to 1\",\n               outputs.size());\n\n  const auto& output_status = util::GetTensorStatus(outputs[0]);\n  YACL_ENFORCE(output_status == pb::TensorStatus::TENSORSTATUS_PRIVATE ||\n                   output_status == pb::TensorStatus::TENSORSTATUS_PUBLIC,\n               \"Constant output tensor' status should be private/public\");\n}\n\nvoid Constant::Execute(ExecContext* ctx) {\n  const auto& scalar_attr = ctx->GetAttribute(kScalarAttr);\n  const auto& output = ctx->GetOutput(kOut)[0];\n  const auto& output_status = util::GetTensorStatus(output);\n  if (output_status == pb::TensorStatus::TENSORSTATUS_PRIVATE) {\n    auto tensor = BuildTensorFromScalar(scalar_attr);\n    YACL_ENFORCE(tensor != nullptr,\n                 \"build tensor from scalar attribute failed\");\n\n    ctx->GetTensorTable()->AddTensor(output.name(), std::move(tensor));\n  } else if (output_status == pb::TensorStatus::TENSORSTATUS_PUBLIC) {\n    auto* sctx = ctx->GetSession()->GetSpuContext();\n    spu::device::ColocatedIo cio(sctx);\n    util::SpuInfeedHelper infeed_helper(&cio);\n\n    auto tensor = BuildTensorFromScalar(scalar_attr);\n    YACL_ENFORCE(tensor != nullptr,\n                 \"build tensor from scalar attribute failed\");\n    // NOTE: if tensor' type is string, we should convert it to\n    // integer first, currently use hash value of string.\n    if (tensor->Type() == pb::PrimitiveDataType::STRING) {\n      tensor = ctx->GetSession()->StringToHash(*tensor);\n    }\n    infeed_helper.InfeedTensorAsPublic(output.name(), *tensor);\n\n    // all parties calculate public value locally to avoid network interaction\n    const auto& value_name =\n        util::SpuVarNameEncoder::GetValueName(output.name());\n    auto nd_arr = cio.hostGetVar(value_name);\n    spu::PtBufferView bv(nd_arr.data(),\n                         nd_arr.eltype().as<spu::PtTy>()->pt_type(),\n                         nd_arr.shape(), nd_arr.strides());\n\n    auto lctx = ctx->GetSession()->GetLink();\n    spu::device::IoClient io(lctx->WorldSize(), sctx->config());\n    auto shares = io.makeShares(bv, spu::VIS_PUBLIC);\n\n    auto* device_symbols = ctx->GetSession()->GetDeviceSymbols();\n    device_symbols->setVar(value_name, shares[ctx->GetSession()->SelfRank()]);\n#ifdef SCQL_WITH_NULL\n    const auto validity_name =\n        SpuVarNameEncoder::GetValidityName(output.name());\n    auto validity_arr = cio.hostGetVar(validity_name);\n    spu::PtBufferView validity_bv(\n        validity_arr.data(), validity_arr.eltype().as<spu::PtTy>()->pt_type(),\n        validity_arr.shape(), validity_arr.strides());\n\n    auto validity_shares = io.makeShares(validity_bv, spu::VIS_PUBLIC);\n\n    device_symbols->setVar(validity_name,\n                           validity_shares[ctx->GetSession()->SelfRank()]);\n#endif  // SCQL_WITH_NULL\n  }\n}\n\nstd::shared_ptr<Tensor> Constant::BuildTensorFromScalar(\n    const pb::AttributeValue& scalar_attr) {\n  std::shared_ptr<Tensor> result;\n  const auto& pb_tensor = scalar_attr.t();\n  // check pb_tensor\n  switch (pb_tensor.elem_type()) {\n    case pb::PrimitiveDataType::STRING: {\n      StringTensorBuilder builder;\n      YACL_ENFORCE(pb_tensor.string_data_size() == 1,\n                   \"scalar size={} not equal 1\", pb_tensor.string_data_size());\n      builder.Append(pb_tensor.string_data(0));\n      builder.Finish(&result);\n      break;\n    }\n    case pb::PrimitiveDataType::BOOL: {\n      BooleanTensorBuilder builder;\n      YACL_ENFORCE(pb_tensor.bool_data_size() == 1,\n                   \"scalar size={} not equal 1\", pb_tensor.bool_data_size());\n      builder.Append(pb_tensor.bool_data(0));\n      builder.Finish(&result);\n      break;\n    }\n    case pb::PrimitiveDataType::FLOAT32: {\n      FloatTensorBuilder builder;\n      YACL_ENFORCE(pb_tensor.float_data_size() == 1,\n                   \"scalar size={} not equal 1\", pb_tensor.float_data_size());\n      builder.Append(pb_tensor.float_data(0));\n      builder.Finish(&result);\n      break;\n    }\n    case pb::PrimitiveDataType::FLOAT64: {\n      DoubleTensorBuilder builder;\n      YACL_ENFORCE(pb_tensor.double_data_size() == 1,\n                   \"scalar size={} not equal 1\", pb_tensor.double_data_size());\n      builder.Append(pb_tensor.double_data(0));\n      builder.Finish(&result);\n      break;\n    }\n    case pb::PrimitiveDataType::INT8:\n    case pb::PrimitiveDataType::INT16:\n    case pb::PrimitiveDataType::INT32: {\n      Int64TensorBuilder builder;\n      YACL_ENFORCE(pb_tensor.int32_data_size() == 1,\n                   \"scalar size={} not equal 1\", pb_tensor.int32_data_size());\n      builder.Append(pb_tensor.int32_data(0));\n      builder.Finish(&result);\n      break;\n    }\n    case pb::PrimitiveDataType::INT64: {\n      Int64TensorBuilder builder;\n      YACL_ENFORCE(pb_tensor.int64_data_size() == 1,\n                   \"scalar size={} not equal 1\", pb_tensor.int64_data_size());\n      builder.Append(pb_tensor.int64_data(0));\n      builder.Finish(&result);\n      break;\n    }\n    default:\n      YACL_THROW(\"not supported elem_type:{}\",\n                 pb::PrimitiveDataType_Name(pb_tensor.elem_type()));\n      break;\n  }\n  return result;\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/constant.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/// @brief Constant construct Scalar data from attribute\nclass Constant : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kScalarAttr[] = \"scalar\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static std::shared_ptr<Tensor> BuildTensorFromScalar(\n      const pb::AttributeValue& scalar_attr);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/constant_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/constant.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nstruct ConstantTestCase {\n  test::NamedTensor scalar;\n  pb::TensorStatus output_status;\n};\n\nclass ConstantTest\n    : public ::testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, ConstantTestCase>> {\n protected:\n  static pb::ExecNode MakeConstantExecNode(const ConstantTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    ConstantPrivateTest, ConstantTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ConstantTestCase{.scalar = {test::NamedTensor(\n                                 \"x\", TensorFrom(arrow::int64(), \"[3]\"))},\n                             .output_status = pb::TENSORSTATUS_PRIVATE},\n            ConstantTestCase{.scalar = {test::NamedTensor(\n                                 \"y\", TensorFrom(arrow::large_utf8(),\n                                                 R\"json([\"2022-11-22\"])json\"))},\n                             .output_status = pb::TENSORSTATUS_PRIVATE},\n            ConstantTestCase{.scalar = {test::NamedTensor(\n                                 \"z\", TensorFrom(arrow::boolean(), \"[true]\"))},\n                             .output_status = pb::TENSORSTATUS_PRIVATE},\n            ConstantTestCase{\n                .scalar = {test::NamedTensor(\"zz\", TensorFrom(arrow::float32(),\n                                                              \"[3.1415]\"))},\n                .output_status = pb::TENSORSTATUS_PRIVATE})),\n    TestParamNameGenerator(ConstantTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    ConstantPublicTest, ConstantTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ConstantTestCase{.scalar = {test::NamedTensor(\n                                 \"x\", TensorFrom(arrow::int64(), \"[3]\"))},\n                             .output_status = pb::TENSORSTATUS_PUBLIC},\n            ConstantTestCase{.scalar = {test::NamedTensor(\n                                 \"y\", TensorFrom(arrow::large_utf8(),\n                                                 R\"json([\"2022-11-22\"])json\"))},\n                             .output_status = pb::TENSORSTATUS_PUBLIC},\n            ConstantTestCase{.scalar = {test::NamedTensor(\n                                 \"z\", TensorFrom(arrow::boolean(), \"[true]\"))},\n                             .output_status = pb::TENSORSTATUS_PUBLIC},\n            ConstantTestCase{\n                .scalar = {test::NamedTensor(\"zz\", TensorFrom(arrow::float32(),\n                                                              \"[3.1415]\"))},\n                .output_status = pb::TENSORSTATUS_PUBLIC})),\n    TestParamNameGenerator(ConstantTest));\n\nTEST_P(ConstantTest, Works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeConstantExecNode(tc);\n\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n\n  // When\n  EXPECT_NO_THROW(test::RunAsync<Constant>(ctx_ptrs));\n\n  // check alice output\n  auto expect_arr = tc.scalar.tensor->ToArrowChunkedArray();\n  TensorPtr out;\n  if (tc.output_status == pb::TENSORSTATUS_PRIVATE) {\n    out = exec_ctxs[0].GetTensorTable()->GetTensor(tc.scalar.name);\n  } else {\n    auto* sctx = exec_ctxs[0].GetSession()->GetSpuContext();\n    auto* device_symbols = exec_ctxs[0].GetSession()->GetDeviceSymbols();\n    util::SpuOutfeedHelper outfeed_helper(sctx, device_symbols);\n    out = outfeed_helper.DumpPublic(tc.scalar.name);\n    // convert hash to string for string tensor in spu\n    if (tc.scalar.tensor->Type() == pb::PrimitiveDataType::STRING) {\n      out = exec_ctxs[0].GetSession()->HashToString(*out);\n    }\n  }\n  ASSERT_TRUE(out);\n  EXPECT_TRUE(out->ToArrowChunkedArray()->ApproxEquals(*expect_arr))\n      << \"expect type = \" << expect_arr->type()->ToString()\n      << \", got type = \" << out->ToArrowChunkedArray()->type()->ToString()\n      << \"\\nexpect result = \" << expect_arr->ToString()\n      << \"\\nbut actual got result = \" << out->ToArrowChunkedArray()->ToString();\n}\n\n/// ===========================\n/// ConstantTest impl\n/// ===========================\n\npb::ExecNode ConstantTest::MakeConstantExecNode(const ConstantTestCase& tc) {\n  test::ExecNodeBuilder builder(Constant::kOpType);\n\n  builder.SetNodeName(\"constant-test\");\n\n  auto pb_tensor = std::make_shared<pb::Tensor>();\n  pb_tensor->set_elem_type(tc.scalar.tensor->Type());\n  util::CopyValuesToProto(tc.scalar.tensor, pb_tensor.get());\n  builder.AddAttr(Constant::kScalarAttr, *pb_tensor);\n\n  auto t = test::MakeTensorReference(tc.scalar.name, pb_tensor->elem_type(),\n                                     tc.output_status);\n  builder.AddOutput(Constant::kOut, {t});\n\n  return builder.Build();\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/copy.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/copy.h\"\n\n#include \"arrow/buffer.h\"\n#include \"arrow/io/memory.h\"\n#include \"arrow/ipc/reader.h\"\n#include \"arrow/ipc/writer.h\"\n#include \"arrow/table.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/table_util.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nnamespace {\n\n// the TakeYaclBuffer will take ownership of the yacl buffer to avoid copying\nclass TakeYaclBuffer : public arrow::Buffer {\n public:\n  explicit TakeYaclBuffer(yacl::Buffer buf)\n      : arrow::Buffer(nullptr, 0), buf_(std::move(buf)) {\n    is_mutable_ = false;\n    data_ = buf_.data<const uint8_t>();\n    size_ = buf_.size();\n    capacity_ = size_;\n    is_cpu_ = true;\n  }\n\n  ~TakeYaclBuffer() = default;\n\n private:\n  yacl::Buffer buf_;\n};\n\n}  // namespace\n\nconst std::string Copy::kOpType(\"Copy\");\n\nconst std::string& Copy::Type() const { return kOpType; }\n\nvoid Copy::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"Copy input {} and output {} should have the same size\", kIn,\n               kOut);\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   inputs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"Copy input tensors' status should all be private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   outputs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"Copy output tensors' status should all be private\");\n}\n\nvoid Copy::Execute(ExecContext* ctx) {\n  auto logger = ctx->GetActiveLogger();\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  const std::string& from_party =\n      ctx->GetStringValueFromAttribute(kInputPartyCodesAttr);\n  const std::string& to_party =\n      ctx->GetStringValueFromAttribute(kOutputPartyCodesAttr);\n  const std::string self_party = ctx->GetSession()->SelfPartyCode();\n\n  auto lctx = ctx->GetSession()->GetLink();\n\n  if (self_party == from_party) {\n    auto table = util::ConstructTableFromTensors(ctx, input_pbs);\n    YACL_ENFORCE(table, \"construct table failed\");\n\n    auto send_to_rank = ctx->GetSession()->GetPartyRank(to_party);\n    YACL_ENFORCE(send_to_rank != -1, \"unknown rank for party={}\", to_party);\n\n    auto reader = arrow::TableBatchReader(table);\n    reader.set_chunksize(batch_size_);\n\n    std::shared_ptr<arrow::RecordBatch> batch;\n    int count = 0;\n    int64_t total = 0;\n    while (reader.ReadNext(&batch).ok() && batch != nullptr) {\n      count++;\n      size_t current_rows = batch->num_rows();\n      total += current_rows;\n\n      auto buffer = SerializeRecordBatch(std::move(batch));\n      YACL_ENFORCE(buffer, \"serialize record batch failed\");\n\n      lctx->Send(\n          send_to_rank,\n          yacl::ByteContainerView(buffer->mutable_data(), buffer->size()),\n          ctx->GetNodeName());\n\n      SPDLOG_LOGGER_INFO(logger, \"sent {} rows in batch {}, {} rows in total.\",\n                         current_rows, count, total);\n    }\n\n    // append a dummy batch to the tail of the batch to indicate\n    // the batching is done\n    {\n      std::shared_ptr<arrow::RecordBatch> dummy_batch;\n      ASSIGN_OR_THROW_ARROW_STATUS(\n          dummy_batch, arrow::RecordBatch::MakeEmpty(table->schema()));\n      auto buffer = SerializeRecordBatch(std::move(dummy_batch));\n      YACL_ENFORCE(buffer, \"serialize record batch failed\");\n\n      lctx->Send(\n          send_to_rank,\n          yacl::ByteContainerView(buffer->mutable_data(), buffer->size()),\n          ctx->GetNodeName());\n    }\n  } else {\n    auto recv_from_rank = ctx->GetSession()->GetPartyRank(from_party);\n    YACL_ENFORCE(recv_from_rank != -1, \"unknown rank for party={}\", from_party);\n    std::shared_ptr<arrow::Table> merged_table;\n    int count = 0;\n    int64_t total = 0;\n    while (true) {\n      yacl::Buffer value = lctx->Recv(recv_from_rank, ctx->GetNodeName());\n      std::shared_ptr<arrow::Table> table = DeserializeTable(std::move(value));\n      YACL_ENFORCE(table, \"deserialize table failed\");\n\n      auto current_rows = table->num_rows();\n      total += current_rows;\n\n      if (!merged_table) {\n        merged_table = table;\n      } else if (table->num_rows() > 0) {\n        auto result = arrow::ConcatenateTables({merged_table, table});\n        YACL_ENFORCE(result.ok(), \"concatenate table failed\");\n        merged_table = result.ValueOrDie();\n      }\n\n      if (table->num_rows() == 0) {\n        break;\n      }\n\n      count++;\n      SPDLOG_LOGGER_INFO(logger,\n                         \"received {} rows in batch {}, {} rows in total.\",\n                         current_rows, count, total);\n    }\n\n    InsertTensorsFromTable(ctx, output_pbs, std::move(merged_table));\n  }\n}\n\nstd::shared_ptr<arrow::Buffer> Copy::SerializeRecordBatch(\n    std::shared_ptr<arrow::RecordBatch> batch) {\n  std::shared_ptr<arrow::io::BufferOutputStream> output_stream;\n  ASSIGN_OR_THROW_ARROW_STATUS(output_stream,\n                               arrow::io::BufferOutputStream::Create());\n\n  std::shared_ptr<arrow::ipc::RecordBatchWriter> writer;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      writer, arrow::ipc::MakeStreamWriter(output_stream, batch->schema()));\n\n  THROW_IF_ARROW_NOT_OK(writer->WriteRecordBatch(*batch));\n  THROW_IF_ARROW_NOT_OK(writer->Close());\n\n  std::shared_ptr<arrow::Buffer> buffer;\n  ASSIGN_OR_THROW_ARROW_STATUS(buffer, output_stream->Finish());\n\n  return buffer;\n}\n\nstd::shared_ptr<arrow::Table> Copy::DeserializeTable(yacl::Buffer value) {\n  auto buffer = std::make_shared<TakeYaclBuffer>(std::move(value));\n\n  auto buffer_reader = std::make_shared<arrow::io::BufferReader>(buffer);\n\n  std::shared_ptr<arrow::ipc::RecordBatchStreamReader> reader;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      reader, arrow::ipc::RecordBatchStreamReader::Open(buffer_reader));\n\n  std::shared_ptr<arrow::Table> table;\n  ASSIGN_OR_THROW_ARROW_STATUS(table, reader->ToTable());\n  THROW_IF_ARROW_NOT_OK(table->Validate());\n\n  return table;\n}\n\nvoid Copy::InsertTensorsFromTable(ExecContext* ctx,\n                                  const RepeatedPbTensor& output_pbs,\n                                  std::shared_ptr<arrow::Table> table) {\n  YACL_ENFORCE(table->num_columns() == output_pbs.size(),\n               \"receive table column size={} not equal to output size={}\",\n               table->num_columns(), output_pbs.size());\n  for (int i = 0; i < output_pbs.size(); ++i) {\n    auto chunked_arr = table->column(i);\n    YACL_ENFORCE(chunked_arr, \"get column(idx={}) from table failed\", i);\n    auto tensor = TensorFrom(std::move(chunked_arr));\n\n    ctx->GetTensorTable()->AddTensor(output_pbs[i].name(), tensor);\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/copy.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/// @brief Copy send private data from one party to another.\nclass Copy : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n  static constexpr char kInputPartyCodesAttr[] = \"input_party_codes\";\n  static constexpr char kOutputPartyCodesAttr[] = \"output_party_codes\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static std::shared_ptr<arrow::Buffer> SerializeRecordBatch(\n      std::shared_ptr<arrow::RecordBatch> batch);\n\n  static std::shared_ptr<arrow::Table> DeserializeTable(yacl::Buffer value);\n\n  static void InsertTensorsFromTable(ExecContext* ctx,\n                                     const RepeatedPbTensor& output_pbs,\n                                     std::shared_ptr<arrow::Table> table);\n\n  size_t batch_size_ = 1000 * 1000;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/copy_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/copy.h\"\n\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct CopyTestCase {\n  std::vector<test::NamedTensor> datas;\n  std::vector<std::string> output_names;\n};\n\nCopyTestCase MockInt32TensorCase(const size_t tensor_length) {\n  CopyTestCase test_case;\n  test_case.output_names = {\"x1_copy\"};\n  std::vector<test::NamedTensor> tensors;\n  std::string tensor_str = \"[\";\n  for (size_t i = 0; i < tensor_length; i++) {\n    if (i % 7 == 0) {\n      tensor_str += \"null\";\n    } else {\n      tensor_str += std::to_string(i);\n    }\n    if (i < tensor_length - 1) {\n      tensor_str += \",\";\n    }\n  }\n  tensor_str += \"]\";\n  test_case.datas = {\n      test::NamedTensor(\"x1\", TensorFrom(arrow::int32(), tensor_str))};\n  return test_case;\n};\n\nCopyTestCase MockStringTensorCase(const size_t tensor_length) {\n  CopyTestCase test_case;\n  test_case.output_names = {\"x1_copy\"};\n  std::vector<test::NamedTensor> tensors;\n  std::string tensor_str = \"[\";\n  for (size_t i = 0; i < tensor_length; i++) {\n    if (i % 7 == 0) {\n      tensor_str += \"null\";\n    } else {\n      tensor_str += \"\\\"\" + std::to_string(i) + \"\\\"\";\n    }\n    if (i < tensor_length - 1) {\n      tensor_str += \",\";\n    }\n  }\n  tensor_str += \"]\";\n  test_case.datas = {\n      test::NamedTensor(\"x1\", TensorFrom(arrow::large_utf8(), tensor_str))};\n  return test_case;\n};\n\nclass CopyTest : public ::testing::TestWithParam<\n                     std::tuple<test::SpuRuntimeTestCase, CopyTestCase>> {\n protected:\n  static pb::ExecNode MakeCopyExecNode(const CopyTestCase& tc);\n\n  static void FeedInputs(ExecContext* ctx, const CopyTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    CopyPrivateTest, CopyTest,\n    testing::Combine(\n        test::SpuTestValues2PC,\n        testing::Values(\n            CopyTestCase{\n                .datas = {test::NamedTensor(\n                              \"x1\", TensorFrom(arrow::float64(),\n                                               \"[-3.1415, 0.1, 99.999, null]\")),\n                          test::NamedTensor(\"x2\", TensorFrom(arrow::boolean(),\n                                                             \"[1,0,0,1]\"))},\n                .output_names = {\"x1_copy\", \"x2_copy\"}},\n            CopyTestCase{\n                .datas = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"D\",\"C\",null,\"B\",\"A\"])json\"))},\n                .output_names = {\"x1_copy\"}},\n            CopyTestCase{.datas = {test::NamedTensor(\n                             \"x1\", TensorFrom(arrow::int64(),\n                                              \"[null,0,1,2,3,10,11,12,13]\"))},\n                         .output_names = {\"x1_copy\"}},\n            CopyTestCase{.datas = {test::NamedTensor(\n                             \"x1\", TensorFrom(arrow::int64(), \"[]\"))},\n                         .output_names = {\"x1_copy\"}},\n            MockInt32TensorCase(100), MockStringTensorCase(500),\n            MockInt32TensorCase(2000), MockStringTensorCase(12000),\n            MockInt32TensorCase(1000 * 1000 + 2),\n            MockStringTensorCase(1000 * 1000 + 3))),\n    TestParamNameGenerator(CopyTest));\n\nTEST_P(CopyTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeCopyExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  ExecContext alice_ctx(node, sessions[0].get());\n  ExecContext bob_ctx(node, sessions[1].get());\n\n  // feed inputs, test copy from alice to bob.\n  FeedInputs(&alice_ctx, tc);\n\n  // When\n  EXPECT_NO_THROW(test::RunAsync<Copy>({&alice_ctx, &bob_ctx}));\n\n  // Then check bob output\n  auto* tensor_table = bob_ctx.GetTensorTable();\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto in_arr = tc.datas[i].tensor->ToArrowChunkedArray();\n    auto out = tensor_table->GetTensor(tc.output_names[i]);\n    ASSERT_TRUE(out);\n    // compare tensor content\n    EXPECT_TRUE(out->ToArrowChunkedArray()->Equals(in_arr))\n        << \"expect type = \" << in_arr->type()->ToString()\n        << \", got type = \" << out->ToArrowChunkedArray()->type()->ToString()\n        << \"\\nexpect result = \" << in_arr->ToString()\n        << \"\\nbut actual got result = \"\n        << out->ToArrowChunkedArray()->ToString();\n  }\n}\n\n/// ===========================\n/// CopyTest impl\n/// ===========================\n\npb::ExecNode CopyTest::MakeCopyExecNode(const CopyTestCase& tc) {\n  test::ExecNodeBuilder builder(Copy::kOpType);\n\n  builder.SetNodeName(\"copy-test\");\n  builder.AddStringsAttr(Copy::kInputPartyCodesAttr,\n                         std::vector<std::string>{test::kPartyAlice});\n  builder.AddStringsAttr(Copy::kOutputPartyCodesAttr,\n                         std::vector<std::string>{test::kPartyBob});\n  // Add inputs\n  std::vector<pb::Tensor> input_datas;\n  for (const auto& named_tensor : tc.datas) {\n    auto data = test::MakePrivateTensorReference(named_tensor.name,\n                                                 named_tensor.tensor->Type());\n    input_datas.push_back(std::move(data));\n  }\n  builder.AddInput(Copy::kIn, input_datas);\n\n  // Add outputs\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto out = test::MakeTensorAs(tc.output_names[i], input_datas[i]);\n    outputs.push_back(std::move(out));\n  }\n  builder.AddOutput(Copy::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid CopyTest::FeedInputs(ExecContext* ctx, const CopyTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, tc.datas);\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/dump_file.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/dump_file.h\"\n\n#include <filesystem>\n\n#include \"absl/strings/match.h\"\n#include \"arrow/array/concatenate.h\"\n#include \"arrow/compute/cast.h\"\n#include \"arrow/csv/writer.h\"\n#include \"arrow/filesystem/filesystem.h\"\n#include \"arrow/filesystem/s3fs.h\"\n#include \"arrow/flight/client.h\"\n#include \"arrow/io/file.h\"\n#include \"arrow/ipc/writer.h\"\n#include \"butil/base64.h\"\n#include \"dataproxy_sdk/data_proxy_file.h\"\n#include \"gflags/gflags.h\"\n#include \"google/protobuf/util/json_util.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_batch_reader.h\"\n#include \"engine/exe/flags.h\"\n#include \"engine/framework/exec.h\"\n#include \"engine/util/datamesh_helper.h\"\n#include \"engine/util/filepath_helper.h\"\n#include \"engine/util/ssl_helper.h\"\n#include \"engine/util/tensor_util.h\"\n#include \"engine/util/time_util.h\"\n#include \"engine/util/upload_info_helper.h\"\n\n#include \"engine/datasource/dataproxy_conf.pb.h\"\n#include \"engine/util/dp/flight.pb.h\"\n#include \"google/protobuf/any.pb.h\"\n\nnamespace scql::engine::op {\n\n// TODO(jingshi) : temporary add flags here to keep the simplicity of op's\n// initialization, modify it later.(maybe add options in session)\nDEFINE_bool(enable_restricted_write_path, true,\n            \"whether restrict path for file to write\");\nDEFINE_string(\n    restricted_write_path, \"./data\",\n    \"in where the file is allowed to write if enable restricted write path\");\nDEFINE_string(null_string_to_write, \"NULL\",\n              \"the string to write for null values\");\n// TODO: 1)work with kuscia, 2)support set in ENV\nDEFINE_string(output_s3_endpoint, \"\", \"the endpoint of output s3/minio/oss\");\nDEFINE_string(output_s3_access_key, \"\",\n              \"the access key id of output s3/minio/oss\");\nDEFINE_string(output_s3_secret_key, \"\",\n              \"the secret access key of output s3/minio/oss\");\nDEFINE_bool(output_s3_enalbe_ssl, true,\n            \"default enable ssl, if s3 server not enable ssl, set to false\");\nDEFINE_string(output_s3_ca_dir_path, \"/etc/ssl/certs/\",\n              \"directory where the certificates stored to verify s3 server\");\nDEFINE_bool(\n    output_s3_force_virtual_addressing, true,\n    \"default set to true to work with oss, for minio please set to false\");\nDEFINE_string(dataproxy_upload_info, \"\",\n              \"If not empty, the local temporary csv file will be \"\n              \"uploaded via dataproxy according to the uplode info, which is \"\n              \"used to set the domaindata\");\nDEFINE_string(\n    output_dataproxy_json, \"\",\n    \"JSON-formatted DataProxy configuration for direct writing, e.g:\"\n    R\"json('{\"dp_uri\":\"grpc+tcp://host:port\",\"datasource\":{\"type\":\"odps\",\"info\":{\"odps\":{\"endpoint\":\"xxx\",\"project\":\"xxx\",\"accessKeyId\":\"xxx\",\"accessKeySecret\":\"xxx\"}}}}')json\");\n\nconst std::string DumpFile::kOpType(\"DumpFile\");\nconst std::string& DumpFile::Type() const { return kOpType; }\n\nnamespace {\n\nvoid InitS3Once() {\n  static std::once_flag flag;\n  std::call_once(flag, []() {\n    arrow::fs::FileSystemGlobalOptions global_options;\n    global_options.tls_ca_dir_path = FLAGS_output_s3_ca_dir_path;\n    THROW_IF_ARROW_NOT_OK(arrow::fs::Initialize(global_options));\n\n    arrow::fs::S3GlobalOptions output_s3_options;\n    output_s3_options.log_level = arrow::fs::S3LogLevel::Warn;\n    THROW_IF_ARROW_NOT_OK(arrow::fs::InitializeS3(output_s3_options));\n  });\n}\n\nstd::shared_ptr<arrow::io::OutputStream> BuildStreamFromS3(\n    const std::shared_ptr<spdlog::logger>& logger, const std::string& prefix,\n    std::string path_without_prefix) {\n  InitS3Once();\n  arrow::fs::S3Options options;\n  options.force_virtual_addressing = FLAGS_output_s3_force_virtual_addressing;\n  options.ConfigureAccessKey(FLAGS_output_s3_access_key,\n                             FLAGS_output_s3_secret_key);\n\n  std::string s3_endpoint = FLAGS_output_s3_endpoint;\n  bool use_ssl = util::GetAndRemoveS3EndpointPrefix(s3_endpoint);\n  options.endpoint_override = s3_endpoint;\n  if (!use_ssl || !FLAGS_output_s3_enalbe_ssl) {\n    options.scheme = \"http\";\n  }\n\n  SPDLOG_LOGGER_INFO(\n      logger, \"s3_endpoint({}), scheme({}), path_without_prefix({})\",\n      options.endpoint_override, options.scheme, path_without_prefix);\n\n  std::shared_ptr<arrow::fs::S3FileSystem> fs;\n  ASSIGN_OR_THROW_ARROW_STATUS(fs, arrow::fs::S3FileSystem::Make(options));\n\n  arrow::fs::FileInfo info;\n  ASSIGN_OR_THROW_ARROW_STATUS(info, fs->GetFileInfo(path_without_prefix));\n  YACL_ENFORCE(info.type() == arrow::fs::FileType::NotFound,\n               \"s3 file={}{} exists before write\", prefix, path_without_prefix);\n\n  std::shared_ptr<arrow::io::OutputStream> out_stream;\n  ASSIGN_OR_THROW_ARROW_STATUS(out_stream,\n                               fs->OpenOutputStream(path_without_prefix));\n\n  SPDLOG_LOGGER_INFO(logger, \"s3 output stream created\");\n  return out_stream;\n}\n\nstd::shared_ptr<arrow::io::OutputStream> BuildOutputStream(\n    const std::shared_ptr<spdlog::logger>& logger,\n    const std::string& in_filepath, bool is_restricted,\n    const std::string& restricted_filepath) {\n  auto prefix = util::GetS3LikeScheme(in_filepath);\n  auto filepath_without_prefix = in_filepath.substr(prefix.length());\n\n  if (!prefix.empty()) {\n    // s3 file\n    util::CheckS3LikeUrl(filepath_without_prefix, is_restricted,\n                         restricted_filepath);\n    return BuildStreamFromS3(logger, prefix, filepath_without_prefix);\n  }\n\n  // local file\n  auto absolute_path_file = util::CheckAndGetAbsoluteLocalPath(\n      in_filepath, is_restricted, restricted_filepath);\n  YACL_ENFORCE(!std::filesystem::exists(absolute_path_file),\n               \"file={} exists before write\", absolute_path_file);\n  std::filesystem::create_directories(\n      std::filesystem::path(absolute_path_file).parent_path());\n  std::shared_ptr<arrow::io::OutputStream> out_stream;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      out_stream, arrow::io::FileOutputStream::Open(absolute_path_file, false));\n\n  SPDLOG_LOGGER_INFO(logger, \"local output stream created, absolute path({})\",\n                     absolute_path_file);\n  return out_stream;\n}\n\n// handles the generation of RecordBatches from TensorBatchReaders and processes\n// them via callbacks\nvoid ProcessRecordBatchesFromTensors(\n    const std::shared_ptr<arrow::Schema>& schema,\n    const std::vector<std::shared_ptr<TensorBatchReader>>& readers,\n    std::function<void(const std::shared_ptr<arrow::RecordBatch>&)>\n        batch_handler) {\n  while (true) {\n    arrow::ArrayVector arrays;\n    bool read_to_end = false;\n    for (size_t i = 0; i < readers.size(); ++i) {\n      auto chunked_arr = readers[i]->Next();\n      if (chunked_arr == nullptr) {\n        read_to_end = true;\n        break;\n      }\n\n      const auto& target_field = schema->field(i);\n      if (arrow::is_temporal(target_field->type()->id()) &&\n          !chunked_arr->type()->Equals(target_field->type())) {\n        auto cast_result =\n            arrow::compute::Cast(chunked_arr, target_field->type());\n        YACL_ENFORCE(cast_result.ok(), \"Cast to {} failed for column {}: {}\",\n                     target_field->type()->ToString(), target_field->name(),\n                     cast_result.status().ToString());\n        chunked_arr = cast_result.ValueOrDie().chunked_array();\n      }\n\n      auto concatenate_result = arrow::Concatenate(chunked_arr->chunks());\n      YACL_ENFORCE(concatenate_result.ok(),\n                   \"Failed to concatenate chunks for column {}: {}\",\n                   target_field->name(),\n                   concatenate_result.status().ToString());\n      arrays.emplace_back(concatenate_result.ValueOrDie());\n    }\n\n    if (read_to_end) {\n      break;\n    }\n\n    int64_t length = arrays[0]->length();\n    auto record_batch = arrow::RecordBatch::Make(schema, length, arrays);\n    batch_handler(record_batch);\n  }\n}\n\nvoid WriteToCsvStream(\n    const std::shared_ptr<arrow::Schema>& schema,\n    const arrow::csv::WriteOptions& options,\n    const std::shared_ptr<arrow::io::OutputStream>& out_stream,\n    const std::vector<std::shared_ptr<TensorBatchReader>>& readers) {\n  std::shared_ptr<arrow::ipc::RecordBatchWriter> writer;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      writer, arrow::csv::MakeCSVWriter(out_stream, schema, options));\n\n  ProcessRecordBatchesFromTensors(\n      schema, readers, [&](const std::shared_ptr<arrow::RecordBatch>& batch) {\n        THROW_IF_ARROW_NOT_OK(writer->WriteRecordBatch(*batch));\n      });\n\n  THROW_IF_ARROW_NOT_OK(writer->Close());\n}\n\nvoid UploadViaDataProxy(dataproxy_sdk::proto::UploadInfo& upload_info,\n                        const std::string& file_path) {\n  dataproxy_sdk::proto::DataProxyConfig config;\n  config.set_data_proxy_addr(FLAGS_kuscia_datamesh_endpoint);\n  config.mutable_tls_config()->set_certificate_path(\n      FLAGS_kuscia_datamesh_client_cert_path);\n  config.mutable_tls_config()->set_private_key_path(\n      FLAGS_kuscia_datamesh_client_key_path);\n  config.mutable_tls_config()->set_ca_file_path(\n      FLAGS_kuscia_datamesh_cacert_path);\n  auto dp_file = dataproxy_sdk::DataProxyFile::Make(config);\n  YACL_ENFORCE(dp_file != nullptr, \"Failed to create DataProxyFile instance.\");\n\n  dp_file->UploadFile(upload_info, file_path,\n                      dataproxy_sdk::proto::FileFormat::CSV);\n}\n\nvoid WriteDpDirectly(\n    const std::string& table_name,\n    const std::vector<std::shared_ptr<arrow::Field>>& fields,\n    const std::vector<std::shared_ptr<TensorBatchReader>>& readers) {\n  // 1. parse output_dataproxy_json\n  datasource::DataProxyConf dp_conf;\n  auto status = google::protobuf::util::JsonStringToMessage(\n      FLAGS_output_dataproxy_json, &dp_conf);\n  YACL_ENFORCE(status.ok(), \"failed to parse json to dataproxy conf: error={}\",\n               status.ToString());\n  YACL_ENFORCE(dp_conf.datasource().type() == \"odps\",\n               \"datasouce type: {} != 'odps', only support write odps now\",\n               dp_conf.datasource().type());\n\n  kuscia::proto::api::v1alpha1::datamesh::CommandDataMeshUpdate command;\n  command.mutable_datasource()->CopyFrom(dp_conf.datasource());\n  command.mutable_update()->set_content_type(\n      kuscia::proto::api::v1alpha1::datamesh::Table);\n  auto* domaindata = command.mutable_domaindata();\n  domaindata->set_type(\"table\");  // TODO support more types\n  domaindata->set_relative_uri(table_name);\n  // TODO: support partitions\n  for (const auto& field : fields) {\n    auto column = domaindata->add_columns();\n    column->set_name(field->name());\n    column->set_type(scql::engine::util::ArrowToKusciaType(field->type()));\n  }\n\n  // 2. connect to dataproxy\n  arrow::flight::Location location;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      location, arrow::flight::Location::Parse(dp_conf.dp_uri()));\n  // TODO: support tls and more options\n  arrow::flight::FlightClientOptions options;\n  std::unique_ptr<arrow::flight::FlightClient> client;\n  // TODO: reuse connection\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      client, arrow::flight::FlightClient::Connect(location, options));\n\n  google::protobuf::Any any_msg;\n  any_msg.PackFrom(command);\n  std::string serialized_data;\n  YACL_ENFORCE(any_msg.SerializeToString(&serialized_data),\n               \"failed to serialize the flight command\");\n  auto descriptor = arrow::flight::FlightDescriptor::Command(serialized_data);\n  std::unique_ptr<arrow::flight::FlightInfo> flight_info;\n  ASSIGN_OR_THROW_ARROW_STATUS(flight_info, client->GetFlightInfo(descriptor));\n\n  auto endpoionts = flight_info->endpoints();\n  YACL_ENFORCE(!endpoionts.empty(), \"endpoints should not be empty\");\n  auto dp_descriptor =\n      arrow::flight::FlightDescriptor::Command(endpoionts[0].ticket.ticket);\n\n  arrow::flight::FlightClient::DoPutResult put_result;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      put_result, client->DoPut(dp_descriptor, arrow::schema(fields)));\n\n  // 3. write datas to dataproxy\n  ProcessRecordBatchesFromTensors(\n      arrow::schema(fields), readers,\n      [&](const std::shared_ptr<arrow::RecordBatch>& batch) {\n        THROW_IF_ARROW_NOT_OK(put_result.writer->WriteRecordBatch(*batch));\n      });\n\n  // 4. close writer\n  THROW_IF_ARROW_NOT_OK(put_result.writer->Close());\n}\n\n}  // namespace\n\nvoid DumpFile::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  YACL_ENFORCE(inputs.size() > 0, \"DumpFile input size cannot be 0\");\n\n  const auto& outputs = ctx->GetOutput(kOut);\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"DumpFile inputs' size={} and outputs' size={} not equal\",\n               inputs.size(), outputs.size());\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(inputs, pb::TENSORSTATUS_PRIVATE),\n               \"DumpFile inputs' status are not all private\");\n}\n\nvoid DumpFile::Execute(ExecContext* ctx) {\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n\n  // 1.construct data to table\n  std::vector<std::shared_ptr<arrow::Field>> fields;\n  int32_t batch_size = 1024 * 100;  // default 1024 is too small for large data\n  std::vector<std::shared_ptr<TensorBatchReader>> readers;\n  auto total_len = 0;\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    const auto& input_pb = input_pbs[i];\n    auto tensor = ctx->GetTensorTable()->GetTensor(input_pb.name());\n    YACL_ENFORCE(tensor != nullptr, \"get tensor={} from tensor table failed\",\n                 input_pb.name());\n    if (input_pb.elem_type() == pb::PrimitiveDataType::TIMESTAMP &&\n        !ctx->GetSession()->TimeZone().empty()) {\n      // FIXME(jingshi): avoid memory cost when time_zone set\n      tensor = util::CompensateTimeZone(tensor, ctx->GetSession()->TimeZone());\n    }\n    if (i == 0) {\n      total_len = tensor->Length();\n    } else {\n      YACL_ENFORCE(tensor->Length() == total_len,\n                   \"input tensor length not equal\");\n    }\n    auto reader = tensor->CreateBatchReader(batch_size);\n    readers.push_back(reader);\n    auto column_out = util::GetStringValue(output_pbs[i]);\n    auto arrow_type = tensor->ArrowType();\n    if (input_pb.elem_type() == pb::PrimitiveDataType::TIMESTAMP ||\n        input_pb.elem_type() == pb::PrimitiveDataType::DATETIME) {\n      arrow_type = arrow::timestamp(arrow::TimeUnit::SECOND);\n    }\n    fields.emplace_back(arrow::field(column_out, arrow_type));\n  }\n\n  auto file_path = ctx->GetStringValueFromAttribute(kFilePathAttr);\n  std::string dp_prefix = \"dataproxy://\";\n  if (absl::StartsWithIgnoreCase(file_path, dp_prefix)) {\n    // TODO: the WriteOptions should works when write csv through dataproxy,\n    // currently only support write ODPS\n    WriteDpDirectly(file_path.substr(dp_prefix.length()), fields, readers);\n    ctx->GetSession()->SetAffectedRows(total_len);\n    return;\n  }\n\n  auto schema = arrow::schema(fields);\n  auto logger = ctx->GetActiveLogger();\n\n  arrow::csv::WriteOptions options;\n  options.null_string = FLAGS_null_string_to_write;\n  options.batch_size = batch_size;\n  options.delimiter =\n      ctx->GetStringValueFromAttribute(kFieldDeliminatorAttr).front();\n  options.eol = ctx->GetStringValueFromAttribute(kLineTerminatorAttr);\n  const auto quoting = ctx->GetInt64ValueFromAttribute(kQuotingStyleAttr);\n  if (quoting == kQuotingNone) {\n    options.quoting_style = arrow::csv::QuotingStyle::None;\n  } else if (quoting == kQuotingNeeded) {\n    options.quoting_style = arrow::csv::QuotingStyle::Needed;\n  } else if (quoting == kQuotingAllValid) {\n    options.quoting_style = arrow::csv::QuotingStyle::AllValid;\n  } else {\n    YACL_THROW(\"unsupported quoting style {}\", quoting);\n  }\n\n  auto out_stream =\n      BuildOutputStream(logger, file_path, FLAGS_enable_restricted_write_path,\n                        FLAGS_restricted_write_path);\n  YACL_ENFORCE(out_stream, \"create output stream failed\");\n\n  WriteToCsvStream(schema, options, out_stream, readers);\n  SPDLOG_LOGGER_INFO(logger, \"write to csv stream completed\");\n\n  if (!FLAGS_dataproxy_upload_info.empty()) {\n    SPDLOG_LOGGER_INFO(logger, \"start uploading via DataProxy\");\n    std::string decoded_string;\n    bool decode_success =\n        butil::Base64Decode(FLAGS_dataproxy_upload_info, &decoded_string);\n    YACL_ENFORCE(decode_success, \"decode upload info failed\");\n\n    std::optional<dataproxy_sdk::pb::UploadInfo> parsed_upload_info_opt =\n        scql::engine::util::ParseUploadInfoFromString(decoded_string);\n    YACL_ENFORCE(\n        parsed_upload_info_opt.has_value(),\n        \"Failed to parse FLAGS_dataproxy_upload_info. The string might be \"\n        \"malformed or not represent a valid UploadInfo.\");\n    dataproxy_sdk::proto::UploadInfo upload_info =\n        scql::engine::util::ConvertProtoToClass(parsed_upload_info_opt.value());\n\n    scql::engine::util::ResetColumnsFromSchema(schema, upload_info);\n\n    UploadViaDataProxy(upload_info, file_path);\n    SPDLOG_LOGGER_INFO(logger, \"upload via DataProxy completed\");\n\n    SPDLOG_LOGGER_INFO(logger, \"start clean file {}\", file_path);\n    if (std::remove(file_path.c_str()) != 0) {\n      SPDLOG_LOGGER_ERROR(logger, \"failed to delete file: {}\", file_path);\n    } else {\n      SPDLOG_LOGGER_INFO(logger, \"file deleted successfully: {}\", file_path);\n    }\n  }\n\n  ctx->GetSession()->SetAffectedRows(total_len);\n}\n};  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/dump_file.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/// @brief DumpFile write private data to a specific file path in CSV format\nclass DumpFile : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n  static constexpr char kFilePathAttr[] = \"file_path\";\n  static constexpr char kLineTerminatorAttr[] = \"line_terminator\";\n  static constexpr char kFieldDeliminatorAttr[] = \"field_deliminator\";\n  static constexpr char kQuotingStyleAttr[] = \"quoting_style\";\n\n  static constexpr int64_t kQuotingNone = 0;\n  static constexpr int64_t kQuotingNeeded = 1;\n  static constexpr int64_t kQuotingAllValid = 2;\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/dump_file_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/dump_file.h\"\n\n#include <cstdio>\n#include <filesystem>\n\n#include \"absl/strings/match.h\"\n#include \"butil/file_util.h\"\n#include \"gflags/gflags.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nDECLARE_bool(enable_restricted_write_path);\nDECLARE_string(restricted_write_path);\nDECLARE_string(output_dataproxy_json);\n\nstruct DumpFileTestCase {\n  std::vector<test::NamedTensor> inputs;\n  std::vector<pb::PrimitiveDataType> input_types;\n  std::vector<std::string> output_names;\n  std::string output_file_path;\n  std::string line_terminator = \"\\n\";\n  std::string field_deliminator = \",\";\n  int64_t quoting = 1;\n  std::string output_file_content;\n};\n\nclass DumpFileTest : public ::testing::TestWithParam<DumpFileTestCase> {\n protected:\n  static pb::ExecNode MakeDumpFileExecNode(const DumpFileTestCase& tc);\n\n  static void FeedInputs(ExecContext* ctx, const DumpFileTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    DumpPrivateTest, DumpFileTest,\n    testing::Values(\n        DumpFileTestCase{\n            .inputs =\n                {test::NamedTensor(\n                     \"x1\", TensorFrom(arrow::float64(),\n                                      \"[-3.1415, 0.1, 99.999, 1000, null]\")),\n                 test::NamedTensor(\"x2\",\n                                   TensorFrom(arrow::boolean(),\n                                              \"[true,false,false,true, null]\")),\n                 test::NamedTensor(\n                     \"x3\",\n                     TensorFrom(arrow::large_utf8(),\n                                R\"json([\"test str\",\"\",\"A\",\"B\", null])json\"))},\n            .input_types = {pb::PrimitiveDataType::FLOAT64,\n                            pb::PrimitiveDataType::BOOL,\n                            pb::PrimitiveDataType::STRING},\n            .output_names = {\"x1_dump\", \"x2_dump\", \"x3_dump\"},\n            .output_file_path = \"./dumpfile_out.1\",\n            .output_file_content = R\"csv(\"x1_dump\",\"x2_dump\",\"x3_dump\"\n-3.1415,true,\"test str\"\n0.1,false,\"\"\n99.999,false,\"A\"\n1000,true,\"B\"\nNULL,NULL,NULL\n)csv\"},\n        DumpFileTestCase{\n            .inputs =\n                {test::NamedTensor(\"x1\",\n                                   TensorFrom(arrow::float64(),\n                                              \"[-3.1415, 0.1, 99.999, 1000]\")),\n                 test::NamedTensor(\"x2\", TensorFrom(arrow::boolean(),\n                                                    \"[true,false,false,true]\")),\n                 test::NamedTensor(\n                     \"x3\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"test str\",\"\",\"A\",\"B\"])json\"))},\n            .input_types = {pb::PrimitiveDataType::FLOAT64,\n                            pb::PrimitiveDataType::BOOL,\n                            pb::PrimitiveDataType::STRING},\n            .output_names = {\"x1_dump\", \"x2_dump\", \"x3_dump\"},\n            .output_file_path = \"./dumpfile_out.2\",\n            .line_terminator = \";\\n\",\n            .field_deliminator = \"|\",\n            .quoting = 0,\n            .output_file_content = R\"csv(\"x1_dump\"|\"x2_dump\"|\"x3_dump\";\n-3.1415|true|test str;\n0.1|false|;\n99.999|false|A;\n1000|true|B;\n)csv\"},\n        DumpFileTestCase{\n            .inputs = {test::NamedTensor(\n                \"x1\", TensorFrom(arrow::large_utf8(),\n                                 R\"json([\"D\",\"C\",\"\",\"B\",\"A\"])json\"))},\n            .input_types = {pb::PrimitiveDataType::STRING},\n            .output_names = {\"x1_dump\"},\n            .output_file_path = \"./dumpfile_out.3\",\n            .output_file_content = R\"csv(\"x1_dump\"\n\"D\"\n\"C\"\n\"\"\n\"B\"\n\"A\"\n)csv\"},\n        DumpFileTestCase{\n            .inputs =\n                {\n                    test::NamedTensor(\n                        \"x1\", TensorFrom(arrow::int64(),\n                                         \"[10,946656000,null,1722244717]\")),\n                    test::NamedTensor(\n                        \"x2\", TensorFrom(arrow::int64(),\n                                         \"[10,946656000,null,1722244717]\")),\n                    test::NamedTensor(\n                        \"x3\", TensorFrom(arrow::int64(),\n                                         \"[10,946656000,null,1722244717]\"))},\n            .input_types =\n                {pb::PrimitiveDataType::INT64,\n                 // affected by timezone, we use Beijing time in test_util\n                 pb::PrimitiveDataType::TIMESTAMP,\n                 pb::PrimitiveDataType::DATETIME},\n            .output_names = {\"int64\", \"timestamp\", \"datetime\"},\n            .output_file_path = \"./dump_test/time_dump.csv\",\n            .output_file_content = R\"csv(\"int64\",\"timestamp\",\"datetime\"\n10,1970-01-01 08:00:10,1970-01-01 00:00:10\n946656000,2000-01-01 00:00:00,1999-12-31 16:00:00\nNULL,NULL,NULL\n1722244717,2024-07-29 17:18:37,2024-07-29 09:18:37\n)csv\"},\n        DumpFileTestCase{\n            .inputs =\n                {test::NamedTensor(\n                     \"x1\",\n                     TensorFrom(arrow::float64(),\n                                \"[-3.1415, 0.1, 99.999, 1000, null]\")),\n                 test::NamedTensor(\"x2\",\n                                   TensorFrom(arrow::boolean(),\n                                              \"[true,false,false,true, null]\")),\n                 test::NamedTensor(\n                     \"x3\",\n                     TensorFrom(arrow::large_utf8(),\n                                R\"json([\"test str\",\"\",\"A\",\"B\", null])json\"))},\n            .input_types = {pb::PrimitiveDataType::FLOAT64,\n                            pb::PrimitiveDataType::BOOL,\n                            pb::PrimitiveDataType::STRING},\n            .output_names = {\"x1_dump\", \"x2_dump\", \"x3_dump\"},\n            .output_file_path = \"dataproxy://dumpfile_test\",\n            .output_file_content = R\"csv(\"x1_dump\",\"x2_dump\",\"x3_dump\"\n-3.1415,true,\"test str\"\n0.1,false,\"\"\n99.999,false,\"A\"\n1000,true,\"B\"\nNULL,NULL,NULL\n)csv\"}));\n\nTEST_P(DumpFileTest, works) {\n  // Given\n  FLAGS_restricted_write_path = std::filesystem::current_path().string();\n  auto tc = GetParam();\n  auto node = MakeDumpFileExecNode(tc);\n  auto session = test::Make1PCSession();\n  ExecContext ctx(node, session.get());\n\n  FeedInputs(&ctx, tc);\n\n  // When\n  DumpFile op;\n  if (absl::StartsWithIgnoreCase(tc.output_file_path, \"dataproxy://\")) {\n    FLAGS_output_dataproxy_json =\n        R\"json({\"dp_uri\":\"grpc+tcp://localhost:8989\",\"datasource\":{\"type\":\"odps\",\"info\":{\"odps\":{\"endpoint\":\"xxx\",\"project\":\"xxx\",\"accessKeyId\":\"xxx\",\"accessKeySecret\":\"xxx\"}}}})json\";\n    ASSERT_THROW(op.Run(&ctx), yacl::RuntimeError);\n    return;\n  }\n  ASSERT_NO_THROW(op.Run(&ctx));\n\n  // Then\n  std::string file_path =\n      FLAGS_restricted_write_path + \"/\" + tc.output_file_path;\n  std::string file_content;\n  ASSERT_TRUE(\n      butil::ReadFileToString(butil::FilePath(file_path), &file_content));\n  ASSERT_EQ(file_content, tc.output_file_content);\n  remove(file_path.c_str());\n}\n\n/// ===========================\n/// DumpFileTest impl\n/// ===========================\n\npb::ExecNode DumpFileTest::MakeDumpFileExecNode(const DumpFileTestCase& tc) {\n  test::ExecNodeBuilder builder(DumpFile::kOpType);\n\n  builder.SetNodeName(\"dump-file-test\");\n  builder.AddStringsAttr(DumpFile::kFilePathAttr,\n                         std::vector<std::string>{tc.output_file_path});\n  builder.AddStringsAttr(DumpFile::kLineTerminatorAttr,\n                         std::vector<std::string>{tc.line_terminator});\n  builder.AddStringsAttr(DumpFile::kFieldDeliminatorAttr,\n                         std::vector<std::string>{tc.field_deliminator});\n  builder.AddInt64Attr(DumpFile::kQuotingStyleAttr, tc.quoting);\n  // Add inputs\n  std::vector<pb::Tensor> input_datas;\n  for (size_t i = 0; i < tc.inputs.size(); ++i) {\n    auto data =\n        test::MakePrivateTensorReference(tc.inputs[i].name, tc.input_types[i]);\n    input_datas.push_back(std::move(data));\n  }\n  builder.AddInput(DumpFile::kIn, input_datas);\n\n  // Add outputs\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto out = test::MakeTensorAs(tc.output_names[i], input_datas[i]);\n    out.set_option(pb::TensorOptions::VALUE);\n    out.add_string_data(tc.output_names[i]);\n    out.set_elem_type(pb::PrimitiveDataType::STRING);\n    outputs.push_back(std::move(out));\n  }\n  builder.AddOutput(DumpFile::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid DumpFileTest::FeedInputs(ExecContext* ctx, const DumpFileTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, tc.inputs);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/filter.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/filter.h\"\n\n#include \"arrow/compute/exec.h\"\n#include \"libspu/device/symbol_table.h\"\n#include \"libspu/kernel/hal/public_helper.h\"\n#include \"libspu/kernel/hlo/indexing.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Filter::kOpType(\"Filter\");\n\nconst std::string& Filter::Type() const { return kOpType; }\n\nvoid Filter::Validate(ExecContext* ctx) {\n  const auto& input_filter = ctx->GetInput(kInFilter);\n  YACL_ENFORCE(input_filter.size() == 1, \"{} size={} not equal to 1\", kInFilter,\n               input_filter.size());\n\n  const auto& input_datas = ctx->GetInput(kInData);\n  const auto& outputs = ctx->GetOutput(kOut);\n  YACL_ENFORCE(input_datas.size() == outputs.size(),\n               \"{} size={} and {} size={} not equal\", kInData,\n               input_datas.size(), kOut, outputs.size());\n  YACL_ENFORCE(input_datas.size() > 0, \"size of ({}) cannot be 0\", kInData);\n\n  // all input_datas and outputs must be the same status.\n  auto data_status = util::GetTensorStatus(input_datas[0]);\n  YACL_ENFORCE(util::AreTensorsStatusMatched(input_datas, data_status));\n  YACL_ENFORCE(util::AreTensorsStatusMatched(outputs, data_status));\n\n  // currently supported: 1.filter Private data with PRIVATE/PUBLIC filters\n  // 2.filter SECRET data with PUBLIC filter\n  auto filter_status = util::GetTensorStatus(input_filter[0]);\n  switch (data_status) {\n    case pb::TENSORSTATUS_PRIVATE: {\n      YACL_ENFORCE(filter_status == pb::TENSORSTATUS_PRIVATE ||\n                   filter_status == pb::TENSORSTATUS_PUBLIC);\n      break;\n    }\n    case pb::TENSORSTATUS_SECRET: {\n      YACL_ENFORCE(filter_status == pb::TENSORSTATUS_PUBLIC);\n      break;\n    }\n    default:\n      YACL_THROW(\"unsupported data status={}\",\n                 pb::TensorStatus_Name(data_status));\n  }\n}\n\nvoid Filter::Execute(ExecContext* ctx) {\n  const auto& filter_pb = ctx->GetInput(kInFilter)[0];\n  const auto& data_pbs = ctx->GetInput(kInData);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  auto data_status = util::GetTensorStatus(data_pbs[0]);\n  if (data_status == pb::TENSORSTATUS_PRIVATE) {\n    FilterPrivate(ctx, filter_pb, data_pbs, output_pbs);\n  } else if (data_status == pb::TENSORSTATUS_SECRET) {\n    FilterSecret(ctx, filter_pb, data_pbs, output_pbs);\n  } else {\n    YACL_THROW(\"not support to filter data with status={}\",\n               pb::TensorStatus_Name(data_status));\n  }\n}\n\n// filter status: PUBLIC/PRIVATE, data status: PRIVATE, output status: PRIVATE\nvoid Filter::FilterPrivate(ExecContext* ctx, const pb::Tensor& filter_pb,\n                           const RepeatedPbTensor& data_pbs,\n                           const RepeatedPbTensor& output_pbs) {\n  auto filter = GetPrivateOrPublicTensor(ctx, filter_pb);\n  YACL_ENFORCE(filter != nullptr, \"get null tensor {}\", filter_pb.name());\n  for (int idx = 0; idx < data_pbs.size(); ++idx) {\n    const auto& data_pb = data_pbs[idx];\n    const auto& data = ctx->GetTensorTable()->GetTensor(data_pb.name());\n    YACL_ENFORCE(data != nullptr, \"not find tensor {} in symbol table\",\n                 data_pb.name());\n    auto result = arrow::compute::CallFunction(\n        \"filter\", {data->ToArrowChunkedArray(), filter->ToArrowChunkedArray()});\n    YACL_ENFORCE(result.ok(),\n                 \"invoking arrow filter function failed: err_msg={}\",\n                 result.status().ToString());\n    auto output_name = output_pbs[idx].name();\n    ctx->GetTensorTable()->AddTensor(\n        output_name, TensorFrom(result.ValueOrDie().chunked_array()));\n  }\n}\n\n// filter status: PUBLIC, data status: SECRET, output status: SECRET\nvoid Filter::FilterSecret(ExecContext* ctx, const pb::Tensor& filter_pb,\n                          const RepeatedPbTensor& data_pbs,\n                          const RepeatedPbTensor& output_pbs) {\n  auto* symbols = ctx->GetSession()->GetDeviceSymbols();\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n\n  const auto filter_value_name =\n      util::SpuVarNameEncoder::GetValueName(filter_pb.name());\n  auto filter_value = symbols->getVar(filter_value_name);\n  spu::NdArrayRef filter_arr =\n      spu::kernel::hal::dump_public(sctx, filter_value);\n  auto filter_span = absl::MakeSpan(static_cast<uint8_t*>(filter_arr.data()),\n                                    filter_arr.numel());\n#ifdef SCQL_WITH_NULL\n  const auto filter_validity_name =\n      util::SpuVarNameEncoder::GetValidityName(filter_pb.name());\n  auto filter_validity = symbols->getVar(filter_validity_name);\n  spu::NdArrayRef filter_validity_arr =\n      spu::kernel::hal::dump_public(sctx, filter_validity);\n  YACL_ENFORCE(filter_validity_arr.numel() == filter_span.size());\n  for (int i = 0; i < filter_validity_arr.numel(); ++i) {\n    filter_span[i] = filter_span[i] && filter_validity_arr.at<bool>({i});\n  }\n#endif  // SCQL_WITH_NULL\n\n  for (int idx = 0; idx < data_pbs.size(); ++idx) {\n    const auto& data_pb = data_pbs[idx];\n    const auto data_value_name =\n        util::SpuVarNameEncoder::GetValueName(data_pb.name());\n    const auto& output_name = output_pbs[idx].name();\n    auto data_value = symbols->getVar(data_value_name);\n\n    auto result = spu::kernel::hlo::FilterByMask(sctx, data_value, filter_span);\n\n    symbols->setVar(util::SpuVarNameEncoder::GetValueName(output_name), result);\n\n#ifdef SCQL_WITH_NULL\n    const auto data_validity_name =\n        util::SpuVarNameEncoder::GetValidityName(data_pb.name());\n    auto data_validity = symbols->getVar(data_validity_name);\n\n    auto result_validity =\n        spu::kernel::hlo::FilterByMask(sctx, data_validity, filter_span);\n\n    symbols->setVar(util::SpuVarNameEncoder::GetValidityName(output_name),\n                    result_validity);\n#endif  // SCQL_WITH_NULL\n  }\n}\n\nTensorPtr Filter::GetPrivateOrPublicTensor(ExecContext* ctx,\n                                           const pb::Tensor& input_pb) {\n  TensorPtr ret;\n  if (util::IsTensorStatusMatched(input_pb, pb::TENSORSTATUS_PRIVATE)) {\n    ret = ctx->GetTensorTable()->GetTensor(input_pb.name());\n  } else if (util::IsTensorStatusMatched(input_pb, pb::TENSORSTATUS_PUBLIC)) {\n    // read public tensor from spu device symbol table\n    auto spu_io = util::SpuOutfeedHelper(ctx->GetSession()->GetSpuContext(),\n                                         ctx->GetSession()->GetDeviceSymbols());\n    ret = spu_io.DumpPublic(input_pb.name());\n  } else {\n    YACL_THROW(\"status (\\\"{}\\\") must be either private or public\",\n               input_pb.name());\n  }\n  return ret;\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/filter.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/// @brief Filter using a filter tensor to choose the specific rows of data\n/// tensors.(tensors including filter tensor have the same number of rows,\n/// unlike the FilterByIndex Operator)\n/// e.g: when Filter tensor = {1, 0, 1, 0, 0}, In tensor = {0, 1, 2, 3, 4},\n/// after filtering the Out tensor = {0, 2}\nclass Filter : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kInFilter[] = \"Filter\";\n  static constexpr char kInData[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static void FilterPrivate(ExecContext* ctx, const pb::Tensor& filter_pb,\n                            const RepeatedPbTensor& data_pbs,\n                            const RepeatedPbTensor& output_pbs);\n  static void FilterSecret(ExecContext* ctx, const pb::Tensor& filter_pb,\n                           const RepeatedPbTensor& data_pbs,\n                           const RepeatedPbTensor& output_pbs);\n\n  static TensorPtr GetPrivateOrPublicTensor(ExecContext* ctx,\n                                            const pb::Tensor& input_pb);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/filter_by_index.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/filter_by_index.h\"\n\n#include \"arrow/compute/exec.h\"\n#include \"arrow/datum.h\"\n#include \"arrow/result.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string FilterByIndex::kOpType(\"FilterByIndex\");\n\nconst std::string& FilterByIndex::Type() const { return kOpType; }\n\nvoid FilterByIndex::Validate(ExecContext* ctx) {\n  // check visibility of i/o\n  const auto& indice = ctx->GetInput(kInRowsIndexFilter)[0];\n  YACL_ENFORCE(util::IsTensorStatusMatched(\n                   indice, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"{} tensor {} status should be private, but got {}\",\n               kInRowsIndexFilter, indice.name(),\n               pb::TensorStatus_Name(util::GetTensorStatus(indice)));\n\n  const auto& data = ctx->GetInput(kInData);\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n      data, pb::TensorStatus::TENSORSTATUS_PRIVATE));\n\n  const auto& out = ctx->GetOutput(kOut);\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n      out, pb::TensorStatus::TENSORSTATUS_PRIVATE));\n\n  YACL_ENFORCE(data.size() == out.size(),\n               \"input {} and output {} should have the same size\", kInData,\n               kOut);\n}\n\nvoid FilterByIndex::Execute(ExecContext* ctx) {\n  auto indice = ctx->GetInputTensor(kInRowsIndexFilter);\n  auto data_tensors = ctx->GetInputTensors(kInData);\n\n  std::vector<std::shared_ptr<Tensor>> results;\n  results.reserve(data_tensors.size());\n  for (const auto& data_tensor : data_tensors) {\n    results.push_back(Take(*data_tensor, *indice));\n  }\n\n  ctx->SetOutputTensors(kOut, results);\n}\n\nTensorPtr FilterByIndex::Take(const Tensor& value, const Tensor& indice) {\n  arrow::Result<arrow::Datum> result;\n  // delegate to apache arrow's take function\n  result = arrow::compute::CallFunction(\n      \"take\", {value.ToArrowChunkedArray(), indice.ToArrowChunkedArray()});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow take function: {}\",\n               result.status().ToString());\n\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n};  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/filter_by_index.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass FilterByIndex : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kInRowsIndexFilter[] = \"RowsIndexFilter\";\n  static constexpr char kInData[] = \"Data\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n  /// @brief For each element i in @param[in] indice,\n  /// the i'th  element in the @param[in] value is appended to the output.\n  static TensorPtr Take(const Tensor& value, const Tensor& indice);\n};\n\n};  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/filter_by_index_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/filter_by_index.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct FilterByIndexTestCase {\n  test::NamedTensor indice;\n  std::vector<test::NamedTensor> datas;\n  std::vector<test::NamedTensor> expect_outs;\n};\n\nclass FilterByIndexTest\n    : public ::testing::TestWithParam<FilterByIndexTestCase> {\n protected:\n  static pb::ExecNode MakeFilterByIndexExecNode(\n      const FilterByIndexTestCase& tc);\n\n  static void FeedInputs(ExecContext* ctx, const FilterByIndexTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    FilterByIndexBatchTest, FilterByIndexTest,\n    testing::Values(\n        FilterByIndexTestCase{\n            .indice = test::NamedTensor(\"indice\", TensorFrom(arrow::int64(),\n                                                             \"[3,2,1,0]\")),\n            .datas = {test::NamedTensor(\n                          \"x1\", TensorFrom(arrow::large_utf8(),\n                                           R\"json([\"A\",null,\"C\",\"D\"])json\")),\n                      test::NamedTensor(\"x2\", TensorFrom(arrow::int64(),\n                                                         \"[10,11,12,13]\"))},\n            .expect_outs =\n                {test::NamedTensor(\"y1\",\n                                   TensorFrom(arrow::large_utf8(),\n                                              R\"json([\"D\",\"C\",null,\"A\"])json\")),\n                 test::NamedTensor(\"y2\", TensorFrom(arrow::int64(),\n                                                    \"[13,12,11,10]\"))}},\n        FilterByIndexTestCase{\n            .indice = test::NamedTensor(\"indice\", TensorFrom(arrow::int64(),\n                                                             \"[3,2,2,0,null]\")),\n            .datas = {test::NamedTensor(\n                \"x1\", TensorFrom(arrow::large_utf8(),\n                                 R\"json([\"A\",\"B\",\"C\",null,\"E\"])json\"))},\n            .expect_outs = {test::NamedTensor(\n                \"y1\", TensorFrom(arrow::large_utf8(),\n                                 R\"json([null,\"C\",\"C\",\"A\",null])json\"))}},\n        // testcase: empty indice\n        FilterByIndexTestCase{\n            .indice = test::NamedTensor(\"indice\",\n                                        TensorFrom(arrow::int64(), \"[]\")),\n            .datas = {test::NamedTensor(\n                \"x1\", TensorFrom(arrow::large_utf8(),\n                                 R\"json([\"A\",\"B\",\"C\",null,\"E\"])json\"))},\n            .expect_outs = {test::NamedTensor(\n                \"y1\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))}}));\n\nTEST_P(FilterByIndexTest, works) {\n  // Given\n  auto test_case = GetParam();\n  pb::ExecNode node = MakeFilterByIndexExecNode(test_case);\n  auto session = test::Make1PCSession();\n\n  ExecContext ctx(node, session.get());\n\n  FeedInputs(&ctx, test_case);\n\n  // When\n  FilterByIndex op;\n\n  // Then\n  EXPECT_NO_THROW({ op.Run(&ctx); });\n\n  // check output\n  auto* tensor_table = ctx.GetTensorTable();\n  for (const auto& expect_t : test_case.expect_outs) {\n    auto out = tensor_table->GetTensor(expect_t.name);\n    EXPECT_TRUE(out != nullptr);\n    EXPECT_EQ(out->Length(), expect_t.tensor->Length());\n    EXPECT_EQ(out->GetNullCount(), expect_t.tensor->GetNullCount());\n    EXPECT_EQ(out->Type(), expect_t.tensor->Type());\n    // compare tensor content\n    EXPECT_TRUE(out->ToArrowChunkedArray()->Equals(\n        expect_t.tensor->ToArrowChunkedArray()));\n  }\n}\n\n/// ===========================\n/// FilterByIndexTest impl\n/// ===========================\n\npb::ExecNode FilterByIndexTest::MakeFilterByIndexExecNode(\n    const FilterByIndexTestCase& tc) {\n  test::ExecNodeBuilder builder(FilterByIndex::kOpType);\n\n  builder.SetNodeName(\"filter-by-index-test\");\n  // Add inputs\n  auto indice = test::MakePrivateTensorReference(tc.indice.name,\n                                                 tc.indice.tensor->Type());\n  builder.AddInput(FilterByIndex::kInRowsIndexFilter,\n                   std::vector<pb::Tensor>{indice});\n\n  std::vector<pb::Tensor> input_datas;\n  for (const auto& named_tensor : tc.datas) {\n    auto data = test::MakePrivateTensorReference(named_tensor.name,\n                                                 named_tensor.tensor->Type());\n    input_datas.push_back(std::move(data));\n  }\n  builder.AddInput(FilterByIndex::kInData, input_datas);\n\n  // Add outputs\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.expect_outs.size(); ++i) {\n    auto out = test::MakeTensorAs(tc.expect_outs[i].name, input_datas[i]);\n    outputs.push_back(std::move(out));\n  }\n  builder.AddOutput(FilterByIndex::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid FilterByIndexTest::FeedInputs(ExecContext* ctx,\n                                   const FilterByIndexTestCase& tc) {\n  auto* tensor_table = ctx->GetTensorTable();\n  tensor_table->AddTensor(tc.indice.name, tc.indice.tensor);\n  for (const auto& named_tensor : tc.datas) {\n    tensor_table->AddTensor(named_tensor.name, named_tensor.tensor);\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/filter_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/filter.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct FilterTestCase {\n  test::NamedTensor filter;\n  pb::TensorStatus filter_status;\n  std::vector<test::NamedTensor> datas;\n  pb::TensorStatus data_status;\n  std::vector<test::NamedTensor> expect_outs;\n};\n\nclass FilterTest : public ::testing::TestWithParam<\n                       std::tuple<test::SpuRuntimeTestCase, FilterTestCase>> {\n protected:\n  static pb::ExecNode MakeFilterExecNode(const FilterTestCase& tc);\n\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const FilterTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    FilterPrivateTest, FilterTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            FilterTestCase{\n                .filter = test::NamedTensor(\n                    \"filter\", TensorFrom(arrow::boolean(), \"[1,0,0,1]\")),\n                .filter_status = pb::TENSORSTATUS_PRIVATE,\n                .datas = {test::NamedTensor(\n                              \"x1\",\n                              TensorFrom(arrow::large_utf8(),\n                                         R\"json([\"A\",\"B\",\"C\",null])json\")),\n                          test::NamedTensor(\"x2\", TensorFrom(arrow::int64(),\n                                                             \"[10,11,12,13]\"))},\n                .data_status = pb::TENSORSTATUS_PRIVATE,\n                .expect_outs = {test::NamedTensor(\n                                    \"y1\", TensorFrom(arrow::large_utf8(),\n                                                     R\"json([\"A\",null])json\")),\n                                test::NamedTensor(\"y2\",\n                                                  TensorFrom(arrow::int64(),\n                                                             \"[10,13]\"))}},\n            // TODO: enable when support null in spu\n            // FilterTestCase{\n            //     .filter = test::NamedTensor(\"filter\",\n            //                                 TensorFrom(arrow::boolean(),\n            //                                                \"[0,0,1,1,null]\")),\n            //     .filter_status = pb::TENSORSTATUS_PUBLIC,\n            //     .datas = {test::NamedTensor(\n            //         \"x1\", TensorFrom(arrow::large_utf8(),\n            //                              R\"json([\"A\",\"B\",\"C\",\"null\",\"E\"])json\"))},\n            //     .data_status = pb::TENSORSTATUS_PRIVATE,\n            //     .expect_outs = {test::NamedTensor(\n            //         \"y1\", TensorFrom(arrow::large_utf8(),\n            //                              R\"json([\"C\",null])json\"))}},\n            FilterTestCase{\n                .filter = test::NamedTensor(\n                    \"filter\", TensorFrom(arrow::boolean(), \"[0,0,1,1,0]\")),\n                .filter_status = pb::TENSORSTATUS_PUBLIC,\n                .datas = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"A\",\"B\",\"C\",\"D\",\"E\"])json\"))},\n                .data_status = pb::TENSORSTATUS_SECRET,\n                .expect_outs = {test::NamedTensor(\n                    \"y1\",\n                    TensorFrom(arrow::large_utf8(), R\"json([\"C\",\"D\"])json\"))}},\n            FilterTestCase{\n                .filter = test::NamedTensor(\n                    \"filter\", TensorFrom(arrow::boolean(), \"[1,0,0,1]\")),\n                .filter_status = pb::TENSORSTATUS_PUBLIC,\n                .datas = {test::NamedTensor(\"x1\", TensorFrom(arrow::int64(),\n                                                             \"[10,11,12,13]\"))},\n                .data_status = pb::TENSORSTATUS_SECRET,\n                .expect_outs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::int64(), \"[10,13]\"))}})),\n    TestParamNameGenerator(FilterTest));\n\nTEST_P(FilterTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeFilterExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  if (tc.data_status == pb::TENSORSTATUS_PRIVATE) {\n    EXPECT_NO_THROW(test::RunAsync<Filter>({ctx_ptrs[0]}));\n  } else {\n    EXPECT_NO_THROW(test::RunAsync<Filter>(ctx_ptrs));\n  }\n\n  // Then check alice's outputs\n  auto* tensor_table = ctx_ptrs[0]->GetTensorTable();\n  for (const auto& expect_t : tc.expect_outs) {\n    TensorPtr out;\n    if (tc.data_status == pb::TENSORSTATUS_PRIVATE) {\n      EXPECT_NO_THROW(out = tensor_table->GetTensor(expect_t.name));\n\n    } else {\n      EXPECT_NO_THROW(out = test::RevealSecret(ctx_ptrs, expect_t.name));\n      // convert hash to string for string tensor in spu\n      if (expect_t.tensor->Type() == pb::PrimitiveDataType::STRING) {\n        out = ctx_ptrs[0]->GetSession()->HashToString(*out);\n      }\n    }\n    EXPECT_TRUE(out != nullptr);\n    EXPECT_EQ(out->Length(), expect_t.tensor->Length());\n    EXPECT_EQ(out->GetNullCount(), expect_t.tensor->GetNullCount());\n    EXPECT_EQ(out->Type(), expect_t.tensor->Type());\n    // compare tensor content\n    EXPECT_TRUE(out->ToArrowChunkedArray()->Equals(\n        expect_t.tensor->ToArrowChunkedArray()));\n  }\n}\n\n/// ===========================\n/// FilterTest impl\n/// ===========================\n\npb::ExecNode FilterTest::MakeFilterExecNode(const FilterTestCase& tc) {\n  test::ExecNodeBuilder builder(Filter::kOpType);\n\n  builder.SetNodeName(\"filter-test\");\n  // Add inputs\n  auto filter = test::MakeTensorReference(\n      tc.filter.name, tc.filter.tensor->Type(), tc.filter_status);\n  builder.AddInput(Filter::kInFilter, std::vector<pb::Tensor>{filter});\n\n  std::vector<pb::Tensor> input_datas;\n  for (const auto& named_tensor : tc.datas) {\n    auto data = test::MakeTensorReference(\n        named_tensor.name, named_tensor.tensor->Type(), tc.data_status);\n    input_datas.push_back(std::move(data));\n  }\n  builder.AddInput(Filter::kInData, input_datas);\n\n  // Add outputs\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.expect_outs.size(); ++i) {\n    auto out = test::MakeTensorAs(tc.expect_outs[i].name, input_datas[i]);\n    outputs.push_back(std::move(out));\n  }\n  builder.AddOutput(Filter::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid FilterTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                            const FilterTestCase& tc) {\n  if (tc.filter_status == pb::TENSORSTATUS_PRIVATE) {\n    test::FeedInputsAsPrivate(ctxs[0], {tc.filter});\n  } else {\n    test::FeedInputsAsPublic(ctxs, {tc.filter});\n  }\n\n  if (tc.data_status == pb::TENSORSTATUS_PRIVATE) {\n    test::FeedInputsAsPrivate(ctxs[0], tc.datas);\n  } else {\n    test::FeedInputsAsSecret(ctxs, tc.datas);\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/group.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/group.h\"\n\n#include \"arrow/compute/exec.h\"\n#include \"arrow/compute/row/grouper.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/table_util.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Group::kOpType(\"Group\");\nconst std::string& Group::Type() const { return kOpType; }\n\nvoid Group::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  YACL_ENFORCE(inputs.size() > 0, \"input size cannot be 0\");\n  const auto& out_id = ctx->GetOutput(kOutId);\n  YACL_ENFORCE(out_id.size() == 1, \"output group id's size={} not equal to 1\",\n               out_id.size());\n  const auto& out_num = ctx->GetOutput(kOutNum);\n  YACL_ENFORCE(out_num.size() == 1, \"output group num's size={} not equal to 1\",\n               out_num.size());\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(inputs, pb::TENSORSTATUS_PRIVATE),\n               \"inputs' status are not all private\");\n  YACL_ENFORCE(util::IsTensorStatusMatched(out_id[0], pb::TENSORSTATUS_PRIVATE),\n               \"output's status is not private\");\n  YACL_ENFORCE(\n      util::IsTensorStatusMatched(out_num[0], pb::TENSORSTATUS_PRIVATE),\n      \"output's status is not private\");\n}\n\nvoid Group::Execute(ExecContext* ctx) {\n  const auto& input_pbs = ctx->GetInput(kIn);\n  auto table = util::ConstructTableFromTensors(ctx, input_pbs);\n  YACL_ENFORCE(table, \"construct table failed\");\n\n  std::vector<arrow::TypeHolder> key_types;\n  for (const auto& field : table->schema()->fields()) {\n    key_types.emplace_back(field->type());\n  }\n  std::unique_ptr<arrow::compute::Grouper> grouper;\n  ASSIGN_OR_THROW_ARROW_STATUS(grouper,\n                               arrow::compute::Grouper::Make(key_types));\n\n  auto reader = arrow::TableBatchReader(table);\n  // NOTE: limit chunk size to 1000W to avoid overflow in Grouper::Consume\n  // TODO: make chunk size configurable\n  reader.set_chunksize(1000 * 10000);\n  arrow::ArrayVector id_chunks;\n  while (true) {\n    std::shared_ptr<arrow::RecordBatch> batch;\n    ASSIGN_OR_THROW_ARROW_STATUS(batch, reader.Next());\n    if (batch == nullptr) {\n      break;\n    }\n    arrow::Datum id_batch;\n    ASSIGN_OR_THROW_ARROW_STATUS(id_batch,\n                                 grouper->Consume(arrow::compute::ExecSpan(\n                                     arrow::compute::ExecBatch(*batch))));\n    id_chunks.push_back(id_batch.make_array());\n  }\n  auto chunked_arr =\n      std::make_shared<arrow::ChunkedArray>(id_chunks, arrow::uint32());\n  ctx->GetTensorTable()->AddTensor(ctx->GetOutput(kOutId)[0].name(),\n                                   TensorFrom(chunked_arr));\n\n  UInt32TensorBuilder builder;\n  builder.Append(grouper->num_groups());\n  std::shared_ptr<Tensor> num;\n  builder.Finish(&num);\n  ctx->GetTensorTable()->AddTensor(ctx->GetOutput(kOutNum)[0].name(), num);\n}\n\n};  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/group.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass Group : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"Key\";\n  static constexpr char kOutId[] = \"GroupId\";\n  static constexpr char kOutNum[] = \"GroupNum\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/group_agg.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/group_agg.h\"\n\n#include \"arrow/compute/api.h\"\n#include \"arrow/compute/exec.h\"\n#include \"arrow/compute/row/grouper.h\"\n#include \"arrow/scalar.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/core/type.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nvoid GroupAggBase::Validate(ExecContext* ctx) {\n  const auto& group_id = ctx->GetInput(kGroupId);\n  YACL_ENFORCE(group_id.size() == 1, \"group id size must be 1\");\n  const auto& group_num = ctx->GetInput(kGroupNum);\n  YACL_ENFORCE(group_num.size() == 1, \"group num size must be 1\");\n  const auto& inputs = ctx->GetInput(kIn);\n  YACL_ENFORCE(inputs.size() > 0, \"input size cannot be 0\");\n  const auto& outputs = ctx->GetOutput(kOut);\n  YACL_ENFORCE(outputs.size() == inputs.size(),\n               \"outputs' size={} not equal to inputs' size={}\", outputs.size(),\n               inputs.size());\n\n  YACL_ENFORCE(\n      util::IsTensorStatusMatched(group_id[0], pb::TENSORSTATUS_PRIVATE),\n      \"group id status is not private\");\n  YACL_ENFORCE(\n      util::IsTensorStatusMatched(group_num[0], pb::TENSORSTATUS_PRIVATE),\n      \"group num status is not private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(inputs, pb::TENSORSTATUS_PRIVATE),\n               \"inputs' status are not all private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(outputs, pb::TENSORSTATUS_PRIVATE),\n               \"outputs' status  are not all private\");\n}\n\nvoid GroupAggBase::Execute(ExecContext* ctx) {\n  auto group_array = GetGroupId(ctx);\n  const auto* group_cast =\n      dynamic_cast<const arrow::UInt32Array*>(group_array.get());\n  YACL_ENFORCE(group_cast, \"cast group id to uint32_t failed\");\n  std::shared_ptr<arrow::ListArray> groupings;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      groupings,\n      arrow::compute::Grouper::MakeGroupings(*group_cast, GetGroupNum(ctx)));\n\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    const auto& input_pb = input_pbs[i];\n    auto in_t = ctx->GetTensorTable()->GetTensor(input_pb.name());\n    YACL_ENFORCE(in_t, \"no input tensor={}\", input_pb.name());\n\n    auto in_array = util::ConcatenateChunkedArray(in_t->ToArrowChunkedArray());\n\n    std::shared_ptr<arrow::ListArray> grouped_in;\n    ASSIGN_OR_THROW_ARROW_STATUS(\n        grouped_in,\n        arrow::compute::Grouper::ApplyGroupings(*groupings, *in_array));\n\n    arrow::ScalarVector aggregated_scalars;\n    for (uint32_t group_i = 0; group_i < GetGroupNum(ctx); ++group_i) {\n      auto slice = grouped_in->value_slice(group_i);\n      if (slice->length() == 0) {\n        continue;\n      }\n      aggregated_scalars.push_back(AggImpl(ctx, slice));\n    }\n\n    auto t = BuildTensorFromScalarVector(\n        aggregated_scalars, ToArrowDataType(output_pbs[i].elem_type()));\n    YACL_ENFORCE(t);\n    ctx->GetTensorTable()->AddTensor(output_pbs[i].name(), t);\n  }\n}\n\nuint32_t GroupAggBase::GetGroupNum(ExecContext* ctx) {\n  const auto& group_num = ctx->GetInput(kGroupNum)[0];\n  auto group_num_t = ctx->GetTensorTable()->GetTensor(group_num.name());\n  YACL_ENFORCE(group_num_t, \"no group_num={}\", group_num.name());\n  auto num_array =\n      util::ConcatenateChunkedArray(group_num_t->ToArrowChunkedArray());\n  const auto* num_array_ptr =\n      dynamic_cast<const arrow::UInt32Array*>(num_array.get());\n  YACL_ENFORCE(num_array_ptr, \"cast group num to uint32_t failed\");\n  return num_array_ptr->Value(0);\n}\n\nstd::shared_ptr<arrow::Array> GroupAggBase::GetGroupId(ExecContext* ctx) {\n  const auto& group = ctx->GetInput(kGroupId)[0];\n  auto group_t = ctx->GetTensorTable()->GetTensor(group.name());\n  YACL_ENFORCE(group_t, \"no group id={}\", group.name());\n  return util::ConcatenateChunkedArray(group_t->ToArrowChunkedArray());\n}\n\nTensorPtr GroupAggBase::BuildTensorFromScalarVector(\n    const arrow::ScalarVector& scalars,\n    std::shared_ptr<arrow::DataType> empty_type) {\n  std::unique_ptr<arrow::ArrayBuilder> builder;\n  std::shared_ptr<arrow::DataType> type =\n      scalars.size() > 0 ? scalars[0]->type : empty_type;\n  YACL_ENFORCE(type, \"no arrow type for proto type={}\", type->ToString());\n  THROW_IF_ARROW_NOT_OK(\n      arrow::MakeBuilder(arrow::default_memory_pool(), type, &builder));\n\n  THROW_IF_ARROW_NOT_OK(builder->AppendScalars(scalars));\n\n  std::shared_ptr<arrow::Array> array;\n  THROW_IF_ARROW_NOT_OK(builder->Finish(&array));\n\n  auto chunked_arr = std::make_shared<arrow::ChunkedArray>(array);\n  return TensorFrom(chunked_arr);\n}\n\n// ===========================\n//   GroupFirstOf impl\n// ===========================\n\nconst std::string GroupFirstOf::kOpType(\"GroupFirstOf\");\n\nstd::shared_ptr<arrow::Scalar> GroupFirstOf::AggImpl(\n    ExecContext* ctx, std::shared_ptr<arrow::Array> arr) {\n  std::shared_ptr<arrow::Scalar> ret;\n  ASSIGN_OR_THROW_ARROW_STATUS(ret, arr->GetScalar(0));\n  return ret;\n}\n\n// ===========================\n//   GroupCountDistinct impl\n// ===========================\n\nconst std::string GroupCountDistinct::kOpType(\"GroupCountDistinct\");\n\nstd::shared_ptr<arrow::Scalar> GroupCountDistinct::AggImpl(\n    ExecContext* ctx, std::shared_ptr<arrow::Array> arr) {\n  auto ret = arrow::compute::CallFunction(\"count_distinct\", {arr});\n  YACL_ENFORCE(ret.ok(),\n               \"invoking arrow function 'count_distinct' failed: err_msg = {} \",\n               ret.status().ToString());\n  return ret.ValueOrDie().scalar();\n}\n\n// ===========================\n//   GroupCount impl\n// ===========================\n\nconst std::string GroupCount::kOpType(\"GroupCount\");\n\nstd::shared_ptr<arrow::Scalar> GroupCount::AggImpl(\n    ExecContext* ctx, std::shared_ptr<arrow::Array> arr) {\n  auto ret = arrow::compute::CallFunction(\"count\", {arr});\n  YACL_ENFORCE(ret.ok(),\n               \"invoking arrow function 'count' failed: err_msg = {} \",\n               ret.status().ToString());\n  return ret.ValueOrDie().scalar();\n}\n\n// ===========================\n//   GroupSum impl\n// ===========================\n\nconst std::string GroupSum::kOpType(\"GroupSum\");\n\nstd::shared_ptr<arrow::Scalar> GroupSum::AggImpl(\n    ExecContext* ctx, std::shared_ptr<arrow::Array> arr) {\n  auto ret = arrow::compute::CallFunction(\"sum\", {arr});\n  YACL_ENFORCE(ret.ok(), \"invoking arrow function 'sum' failed: err_msg = {} \",\n               ret.status().ToString());\n  return ret.ValueOrDie().scalar();\n}\n\n// ===========================\n//   GroupAvg impl\n// ===========================\n\nconst std::string GroupAvg::kOpType(\"GroupAvg\");\n\nstd::shared_ptr<arrow::Scalar> GroupAvg::AggImpl(\n    ExecContext* ctx, std::shared_ptr<arrow::Array> arr) {\n  auto ret = arrow::compute::CallFunction(\"mean\", {arr});\n  YACL_ENFORCE(ret.ok(), \"invoking arrow function 'mean' failed: err_msg = {} \",\n               ret.status().ToString());\n  return ret.ValueOrDie().scalar();\n}\n\n// ===========================\n//   GroupMin impl\n// ===========================\n\nconst std::string GroupMin::kOpType(\"GroupMin\");\n\nstd::shared_ptr<arrow::Scalar> GroupMin::AggImpl(\n    ExecContext* ctx, std::shared_ptr<arrow::Array> arr) {\n  auto ret = arrow::compute::CallFunction(\"min\", {arr});\n  YACL_ENFORCE(ret.ok(), \"invoking arrow function 'min' failed: err_msg = {} \",\n               ret.status().ToString());\n  return ret.ValueOrDie().scalar();\n}\n\n// ===========================\n//   GroupMax impl\n// ===========================\n\nconst std::string GroupMax::kOpType(\"GroupMax\");\n\nstd::shared_ptr<arrow::Scalar> GroupMax::AggImpl(\n    ExecContext* ctx, std::shared_ptr<arrow::Array> arr) {\n  auto ret = arrow::compute::CallFunction(\"max\", {arr});\n  YACL_ENFORCE(ret.ok(), \"invoking arrow function 'max' failed: err_msg = {} \",\n               ret.status().ToString());\n  return ret.ValueOrDie().scalar();\n}\n\n// ===========================\n//   GroupPercentileDisc impl\n// ===========================\nconst std::string GroupPercentileDisc::kOpType(\"GroupPercentileDisc\");\n\nstd::shared_ptr<arrow::Scalar> GroupPercentileDisc::AggImpl(\n    ExecContext* ctx, std::shared_ptr<arrow::Array> arr) {\n  YACL_ENFORCE(arr != nullptr && arr->length() > 0,\n               \"input array should not be null or empty\");\n  double percent = ctx->GetDoubleValueFromAttribute(kPercent);\n  YACL_ENFORCE(percent >= 0.0 && percent <= 1.0,\n               \"percent should be in [0.0, 1.0], but got {}\", percent);\n  int64_t length = arr->length();\n\n  int pos =\n      static_cast<int>(std::ceil(percent * static_cast<double>(length)) - 1);\n  pos = std::max(pos, 0);\n  pos = std::min(pos, static_cast<int>(length - 1));\n\n  arrow::compute::PartitionNthOptions options(pos);\n  auto result =\n      arrow::compute::CallFunction(\"partition_nth_indices\", {arr}, &options);\n\n  YACL_ENFORCE(result.ok(),\n               \"failed to call partition_nth_indices function, error = {}\",\n               result.status().ToString());\n  auto partitioned_indices = std::static_pointer_cast<arrow::UInt64Array>(\n      result.ValueOrDie().make_array());\n  auto value = arr->GetScalar(partitioned_indices->Value(pos));\n  YACL_ENFORCE(value.ok(), \"failed to get scalar from array, error = {}\",\n               value.status().ToString());\n  return value.ValueOrDie();\n}\n};  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/group_agg.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass GroupAggBase : public Operator {\n public:\n  static constexpr char kGroupId[] = \"GroupId\";\n  static constexpr char kGroupNum[] = \"GroupNum\";\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n public:\n  virtual std::shared_ptr<arrow::Scalar> AggImpl(\n      ExecContext* ctx, std::shared_ptr<arrow::Array> arr) = 0;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static uint32_t GetGroupNum(ExecContext* ctx);\n\n  static std::shared_ptr<arrow::Array> GetGroupId(ExecContext* ctx);\n\n  // default use type of 'scalars' to build Tensor, if 'scalars' is empty, use\n  // 'empty_type'\n  TensorPtr BuildTensorFromScalarVector(\n      const arrow::ScalarVector& scalars,\n      std::shared_ptr<arrow::DataType> empty_type);\n};\n\nclass GroupFirstOf : public GroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override { return kOpType; }\n\n public:\n  std::shared_ptr<arrow::Scalar> AggImpl(\n      ExecContext* ctx, std::shared_ptr<arrow::Array> arr) override;\n};\n\nclass GroupCountDistinct : public GroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override { return kOpType; }\n\n  std::shared_ptr<arrow::Scalar> AggImpl(\n      ExecContext* ctx, std::shared_ptr<arrow::Array> arr) override;\n};\n\nclass GroupCount : public GroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override { return kOpType; }\n\n  std::shared_ptr<arrow::Scalar> AggImpl(\n      ExecContext* ctx, std::shared_ptr<arrow::Array> arr) override;\n};\n\nclass GroupSum : public GroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override { return kOpType; }\n\n  std::shared_ptr<arrow::Scalar> AggImpl(\n      ExecContext* ctx, std::shared_ptr<arrow::Array> arr) override;\n};\n\nclass GroupAvg : public GroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override { return kOpType; }\n\n  std::shared_ptr<arrow::Scalar> AggImpl(\n      ExecContext* ctx, std::shared_ptr<arrow::Array> arr) override;\n};\n\nclass GroupMin : public GroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override { return kOpType; }\n\n  std::shared_ptr<arrow::Scalar> AggImpl(\n      ExecContext* ctx, std::shared_ptr<arrow::Array> arr) override;\n};\n\nclass GroupMax : public GroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override { return kOpType; }\n\n  std::shared_ptr<arrow::Scalar> AggImpl(\n      ExecContext* ctx, std::shared_ptr<arrow::Array> arr) override;\n};\n\nclass GroupPercentileDisc : public GroupAggBase {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override { return kOpType; }\n  static constexpr char kPercent[] = \"percent\";\n\n  std::shared_ptr<arrow::Scalar> AggImpl(\n      ExecContext* ctx, std::shared_ptr<arrow::Array> arr) override;\n};\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/group_agg_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/group_agg.h\"\n\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/all_ops_register.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct GroupAggTestCase {\n  std::string op_type;\n  std::vector<test::NamedTensor> inputs;\n  test::NamedTensor group_id;\n  test::NamedTensor group_num;\n  std::vector<test::NamedTensor> outputs;\n  std::optional<std::pair<std::string, double>> double_attr;\n};\n\nclass GroupAggTest : public testing::TestWithParam<GroupAggTestCase> {\n protected:\n  void SetUp() override { RegisterAllOps(); }\n\n  static pb::ExecNode MakeExecNode(const GroupAggTestCase& tc);\n};\n\nTEST_P(GroupAggTest, works) {\n  // Given\n  auto tc = GetParam();\n  auto node = MakeExecNode(tc);\n  auto session = test::Make1PCSession();\n  ExecContext ctx(node, session.get());\n\n  test::FeedInputsAsPrivate(&ctx, tc.inputs);\n  test::FeedInputsAsPrivate(&ctx, {tc.group_id, tc.group_num});\n\n  // When\n  auto op = GetOpRegistry()->GetOperator(node.op_type());\n  ASSERT_TRUE(op);\n  EXPECT_NO_THROW(op->Run(&ctx));\n\n  // Then\n  for (size_t i = 0; i < tc.inputs.size(); ++i) {\n    auto actual_output = ctx.GetTensorTable()->GetTensor(tc.outputs[i].name);\n    ASSERT_TRUE(actual_output);\n    auto actual_arr = actual_output->ToArrowChunkedArray();\n    auto expect_arr = tc.outputs[i].tensor->ToArrowChunkedArray();\n    EXPECT_TRUE(actual_arr->ApproxEquals(\n        *expect_arr, arrow::EqualOptions::Defaults().atol(0.01)))\n        << \"\\nexpect result = \" << expect_arr->ToString()\n        << \"\\nbut actual got result = \" << actual_arr->ToString();\n  }\n}\n\n/// ===================\n/// GroupAggTest impl\n/// ===================\n\npb::ExecNode GroupAggTest::MakeExecNode(const GroupAggTestCase& tc) {\n  test::ExecNodeBuilder builder(tc.op_type);\n\n  builder.SetNodeName(\"plaintext-group-agg-test\");\n  if (tc.double_attr.has_value()) {\n    builder.AddDoubleAttr(tc.double_attr->first, tc.double_attr->second);\n  }\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    pb::Tensor t = test::MakePrivateTensorReference(\n        named_tensor.name, named_tensor.tensor->Type());\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(GroupAggBase::kIn, inputs);\n\n  pb::Tensor t_id = test::MakePrivateTensorReference(\n      tc.group_id.name, tc.group_id.tensor->Type());\n  builder.AddInput(GroupAggBase::kGroupId, {t_id});\n  pb::Tensor t_num = test::MakePrivateTensorReference(\n      tc.group_num.name, tc.group_num.tensor->Type());\n  builder.AddInput(GroupAggBase::kGroupNum, {t_num});\n\n  std::vector<pb::Tensor> outputs;\n  for (const auto& named_tensor : tc.outputs) {\n    pb::Tensor t = test::MakePrivateTensorReference(\n        named_tensor.name, named_tensor.tensor->Type());\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(GroupAggBase::kOut, outputs);\n\n  return builder.Build();\n}\n\nstatic GroupAggTestCase GeneratePercentileDiscTestCase(\n    double percent, std::vector<int> input_sizes) {\n  std::string op_type = GroupPercentileDisc::kOpType;\n  std::string input_name = \"x\";\n  std::string output_name = \"y\";\n\n  std::string group_id_str = \"[\";\n  std::string output_str = \"[\";\n  std::string input_str = \"[\";\n  int group_num = 0;\n  for (const auto input_size : input_sizes) {\n    std::vector<int> input;\n    std::vector<int> group_id;\n    int start_value = 0;\n    while (input.size() < input_size) {\n      input.push_back(start_value);\n      start_value += 1;\n      group_id.push_back(group_num);\n    }\n    group_num++;\n    int expected_index = static_cast<int>(std::ceil(percent * input_size)) - 1;\n    expected_index = std::min(input_size - 1, expected_index);\n    int expected_value = input[expected_index];\n    std::random_device rd;\n    std::mt19937 g(rd());\n    std::shuffle(input.begin(), input.end(), g);\n    for (size_t i = 0; i < input.size(); ++i) {\n      input_str += std::to_string(input[i]);\n      input_str += \",\";\n\n      group_id_str += std::to_string(group_id[i]);\n      group_id_str += \",\";\n    }\n    output_str += std::to_string(expected_value) + \",\";\n  }\n\n  input_str.pop_back();\n  input_str += \"]\";\n  output_str.pop_back();\n  output_str += \"]\";\n  group_id_str.pop_back();\n  group_id_str += \"]\";\n\n  auto group_id_tensor = TensorFrom(arrow::uint32(), group_id_str);\n\n  return GroupAggTestCase{\n      .op_type = op_type,\n      .inputs = {test::NamedTensor(input_name,\n                                   TensorFrom(arrow::int32(), input_str))},\n      .group_id = test::NamedTensor(\"group_id\", group_id_tensor),\n      .group_num = test::NamedTensor(\n          \"group_num\",\n          TensorFrom(arrow::uint32(),\n                     \"[\" + std::to_string(input_sizes.size()) + \"]\")),\n      .outputs = {test::NamedTensor(output_name,\n                                    TensorFrom(arrow::int32(), output_str))},\n      .double_attr = std::make_pair(GroupPercentileDisc::kPercent, percent)};\n}\n\nINSTANTIATE_TEST_SUITE_P(\n    GroupBatchTest, GroupAggTest,\n    testing::Values(\n        GroupAggTestCase{\n            .op_type = GroupFirstOf::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                      \"[null, 0, 1, 1, 2]\")),\n                 test::NamedTensor(\"in_b\", TensorFrom(arrow::float32(),\n                                                      \"[0, 0, 1.1, 1.1, 2.2]\")),\n                 test::NamedTensor(\n                     \"in_c\", TensorFrom(arrow::large_utf8(),\n                                        R\"json([\"A\",\"A\",\"B\",\"B\",\"CCC\"])json\"))},\n            .group_id = test::NamedTensor(\n                \"group_id\", TensorFrom(arrow::uint32(), \"[0, 0, 1, 1, 2]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(),\n                                                              \"[null, 1, 2]\")),\n                        test::NamedTensor(\"out_b\", TensorFrom(arrow::float32(),\n                                                              \"[0, 1.1, 2.2]\")),\n                        test::NamedTensor(\n                            \"out_c\",\n                            TensorFrom(arrow::large_utf8(),\n                                       R\"json([\"A\",\"B\",\"CCC\"])json\"))}},\n        GroupAggTestCase{\n            .op_type = GroupCountDistinct::kOpType,\n            .inputs = {test::NamedTensor(\"in_a\",\n                                         TensorFrom(arrow::int64(),\n                                                    \"[null, 0, 1, 1, 2]\")),\n                       test::NamedTensor(\"in_b\",\n                                         TensorFrom(arrow::float32(),\n                                                    \"[0, 0, 1.1, 1.1, 2.2]\"))},\n            .group_id = test::NamedTensor(\n                \"group_id\", TensorFrom(arrow::uint32(), \"[0, 0, 1, 1, 2]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(),\n                                                              \"[1, 1, 1]\")),\n                        test::NamedTensor(\"out_b\", TensorFrom(arrow::int64(),\n                                                              \"[1, 1, 1]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupCount::kOpType,\n            .inputs = {test::NamedTensor(\"in_a\",\n                                         TensorFrom(arrow::int64(),\n                                                    \"[null, 0, 1, 1, 2]\")),\n                       test::NamedTensor(\"in_b\",\n                                         TensorFrom(arrow::float32(),\n                                                    \"[0, 0, 1.1, 1.1, 2.2]\"))},\n            .group_id = test::NamedTensor(\n                \"group_id\", TensorFrom(arrow::uint32(), \"[0, 0, 1, 1, 2]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(),\n                                                              \"[1, 2, 1]\")),\n                        test::NamedTensor(\"out_b\", TensorFrom(arrow::int64(),\n                                                              \"[2, 2, 1]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupSum::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                      \"[0, 1, 2, 3, null]\")),\n                 test::NamedTensor(\n                     \"in_b\",\n                     TensorFrom(arrow::float32(), \"[0, 1.1, 2.2, 3.3, 4.4]\"))},\n            .group_id = test::NamedTensor(\n                \"group_id\", TensorFrom(arrow::uint32(), \"[0, 0, 1, 1, 2]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(),\n                                                              \"[1, 5, null]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float64(),\n                                                     \"[1.1, 5.5, 4.4]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupAvg::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                      \"[0, 1, 2, 3, null]\")),\n                 test::NamedTensor(\n                     \"in_b\",\n                     TensorFrom(arrow::float32(), \"[0, 1.1, 2.2, 3.3, 4.4]\"))},\n            .group_id = test::NamedTensor(\n                \"group_id\", TensorFrom(arrow::uint32(), \"[0, 0, 1, 1, 2]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\"out_a\",\n                                          TensorFrom(arrow::float64(),\n                                                     \"[0.5, 2.5, null]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float64(),\n                                                     \"[0.55, 2.75, 4.4]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupMin::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                      \"[0, 1, 2, 3, null]\")),\n                 test::NamedTensor(\n                     \"in_b\",\n                     TensorFrom(arrow::float32(), \"[0, 1.1, 2.2, 3.3, 4.4]\"))},\n            .group_id = test::NamedTensor(\n                \"group_id\", TensorFrom(arrow::uint32(), \"[0, 0, 1, 1, 2]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(),\n                                                              \"[0, 2, null]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float32(),\n                                                     \"[0, 2.2, 4.4]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupMax::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                      \"[0, 1, 2, 3, null]\")),\n                 test::NamedTensor(\n                     \"in_b\",\n                     TensorFrom(arrow::float32(), \"[0, 1.1, 2.2, 3.3, 4.4]\"))},\n            .group_id = test::NamedTensor(\n                \"group_id\", TensorFrom(arrow::uint32(), \"[0, 0, 1, 1, 2]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(),\n                                                              \"[1, 3, null]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float32(),\n                                                     \"[1.1, 3.3, 4.4]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupPercentileDisc::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                      \"[0, 1, 2, 3, 4, null]\")),\n                 test::NamedTensor(\n                     \"in_b\", TensorFrom(arrow::float32(),\n                                        \"[0, 1.1, 3.3, 2.2, 4.4, 5.5]\"))},\n            .group_id = test::NamedTensor(\n                \"group_id\", TensorFrom(arrow::uint32(), \"[0, 0, 1, 1, 1, 2]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(),\n                                                              \"[0, 3, null]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float32(),\n                                                     \"[0, 3.3, 5.5]\"))},\n            .double_attr = std::make_pair(\n                GroupPercentileDisc::kPercent,\n                0.5)  // the index of each group should be [0, 0, 0]\n        },\n        GroupAggTestCase{\n            .op_type = GroupPercentileDisc::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                      \"[0, 1, 2, 3, 4, null]\")),\n                 test::NamedTensor(\n                     \"in_b\", TensorFrom(arrow::float32(),\n                                        \"[0, 1.1, 2.2, 3.3, 4.4, 5.5]\"))},\n            .group_id = test::NamedTensor(\n                \"group_id\", TensorFrom(arrow::uint32(), \"[0, 0, 1, 1, 1, 2]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(),\n                                                              \"[0, 2, null]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float32(),\n                                                     \"[0, 2.2, 5.5]\"))},\n            .double_attr = std::make_pair(\n                \"percent\", 0)  // the index of each group should be [0, 0, 0]\n        },\n        GroupAggTestCase{\n            .op_type = GroupPercentileDisc::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                      \"[0, 1, 2, 3, 4, null]\")),\n                 test::NamedTensor(\n                     \"in_b\", TensorFrom(arrow::float32(),\n                                        \"[0, 1.1, 2.2, 3.3, 4.4, 5.5]\"))},\n            .group_id = test::NamedTensor(\n                \"group_id\", TensorFrom(arrow::uint32(), \"[0, 0, 1, 1, 1, 2]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(),\n                                                              \"[1, 4, null]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float32(),\n                                                     \"[1.1, 4.4, 5.5]\"))},\n            .double_attr = std::make_pair(\n                \"percent\", 1)  // the index of each group should be [1, 2, 0]\n        },\n        GeneratePercentileDiscTestCase(0.333, {1000, 200, 1}),\n        GeneratePercentileDiscTestCase(0.43, {2, 987, 1241, 876})));\n\nINSTANTIATE_TEST_SUITE_P(\n    GroupBatchEmptyTest, GroupAggTest,\n    testing::Values(\n        GroupAggTestCase{\n            .op_type = GroupFirstOf::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"in_b\", TensorFrom(arrow::float32(), \"[]\")),\n                 test::NamedTensor(\"in_c\", TensorFrom(arrow::large_utf8(),\n                                                      R\"json([])json\"))},\n            .group_id = test::NamedTensor(\"group_id\",\n                                          TensorFrom(arrow::uint32(), \"[]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[0]\")),\n            .outputs =\n                {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"out_b\", TensorFrom(arrow::float32(), \"[]\")),\n                 test::NamedTensor(\"out_c\", TensorFrom(arrow::large_utf8(),\n                                                       R\"json([])json\"))}},\n        GroupAggTestCase{\n            .op_type = GroupCountDistinct::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"in_b\", TensorFrom(arrow::float32(), \"[]\"))},\n            .group_id = test::NamedTensor(\"group_id\",\n                                          TensorFrom(arrow::uint32(), \"[]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[0]\")),\n            .outputs =\n                {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"out_b\", TensorFrom(arrow::int64(), \"[]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupCount::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"in_b\", TensorFrom(arrow::float32(), \"[]\"))},\n            .group_id = test::NamedTensor(\"group_id\",\n                                          TensorFrom(arrow::uint32(), \"[]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[0]\")),\n            .outputs =\n                {test::NamedTensor(\"out_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"out_b\", TensorFrom(arrow::int64(), \"[]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupSum::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"in_b\", TensorFrom(arrow::float32(), \"[]\"))},\n            .group_id = test::NamedTensor(\"group_id\",\n                                          TensorFrom(arrow::uint32(), \"[]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[0]\")),\n            .outputs = {test::NamedTensor(\"out_a\",\n                                          TensorFrom(arrow::int64(), \"[]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float64(), \"[]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupAvg::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"in_b\", TensorFrom(arrow::float32(), \"[]\"))},\n            .group_id = test::NamedTensor(\"group_id\",\n                                          TensorFrom(arrow::uint32(), \"[]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[0]\")),\n            .outputs = {test::NamedTensor(\"out_a\",\n                                          TensorFrom(arrow::float64(), \"[]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float64(), \"[]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupMin::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"in_b\", TensorFrom(arrow::float32(), \"[]\"))},\n            .group_id = test::NamedTensor(\"group_id\",\n                                          TensorFrom(arrow::uint32(), \"[]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[0]\")),\n            .outputs = {test::NamedTensor(\"out_a\",\n                                          TensorFrom(arrow::int64(), \"[]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float32(), \"[]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupMax::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"in_b\", TensorFrom(arrow::float32(), \"[]\"))},\n            .group_id = test::NamedTensor(\"group_id\",\n                                          TensorFrom(arrow::uint32(), \"[]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[0]\")),\n            .outputs = {test::NamedTensor(\"out_a\",\n                                          TensorFrom(arrow::int64(), \"[]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float32(), \"[]\"))}},\n        GroupAggTestCase{\n            .op_type = GroupPercentileDisc::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(), \"[]\")),\n                 test::NamedTensor(\"in_b\", TensorFrom(arrow::float32(), \"[]\"))},\n            .group_id = test::NamedTensor(\"group_id\",\n                                          TensorFrom(arrow::uint32(), \"[]\")),\n            .group_num = test::NamedTensor(\"group_num\",\n                                           TensorFrom(arrow::uint32(), \"[0]\")),\n            .outputs = {test::NamedTensor(\"out_a\",\n                                          TensorFrom(arrow::int64(), \"[]\")),\n                        test::NamedTensor(\"out_b\",\n                                          TensorFrom(arrow::float32(), \"[]\"))},\n            .double_attr = std::make_pair(GroupPercentileDisc::kPercent,\n                                          0.5)}));\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/group_secret_agg.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/group_secret_agg.h\"\n\n#include \"libspu/kernel/hlo/group_by_agg.h\"\n\nnamespace scql::engine::op {\n\n// GroupSecretAggBase implementation\nvoid GroupSecretAggBase::Validate(ExecContext* ctx) {\n  const auto& group_num = ctx->GetInput(kGroupNum);\n  const auto& group_id = ctx->GetInput(kGroupId);\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(group_num.size() == 1,\n               \"operator {} input GroupNum size {} must be 1\", Type(),\n               group_num.size());\n  YACL_ENFORCE(group_id.size() == 1,\n               \"operator {} input GroupId size {} must be 1\", Type(),\n               group_id.size());\n  YACL_ENFORCE(inputs.size() == 1, \"operator {} input In size {} must be 1\",\n               Type(), inputs.size());\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"operator {} output and input should have the same size\",\n               Type());\n\n  YACL_ENFORCE(\n      util::IsTensorStatusMatched(group_num[0], pb::TENSORSTATUS_PUBLIC));\n  YACL_ENFORCE(\n      util::IsTensorStatusMatched(group_id[0], pb::TENSORSTATUS_SECRET));\n  YACL_ENFORCE(util::IsTensorStatusMatched(inputs[0], pb::TENSORSTATUS_SECRET));\n  YACL_ENFORCE(\n      util::IsTensorStatusMatched(outputs[0], pb::TENSORSTATUS_SECRET));\n\n  YACL_ENFORCE(ctx->GetSession()\n                   ->GetSpuContext()\n                   ->config()\n                   .experimental_enable_colocated_optimization,\n               \"{} must enable spu colocated optimization\", Type());\n}\n\nvoid GroupSecretAggBase::Execute(ExecContext* ctx) {\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto group_id = ctx->GetInputValue(kGroupId);\n  auto input = ctx->GetInputValue(kIn);\n  auto group_num = ctx->GetInputValue(kGroupNum);\n  if (group_id.numel() == 0) {\n    auto result = HandleEmptyInput(sctx, input);\n    ctx->SetOutputValue(kOut, result);\n    return;\n  }\n\n  auto outputs = spu::kernel::hlo::GroupByAgg(sctx, {group_id}, {input},\n                                              GetAggregationFunction(),\n                                              {} /* useless valid bits */);\n  YACL_ENFORCE(outputs.size() == 2, \"GroupByAgg output size must be 2\");\n\n  // slice to get the result\n  spu::NdArrayRef num_arr = spu::kernel::hal::dump_public(sctx, group_num);\n  int64_t num = num_arr.at<uint32_t>(0);\n\n  auto result = spu::kernel::hlo::Slice(sctx, outputs[1], {0}, {num}, {});\n  ctx->SetOutputValue(kOut, result);\n}\n\n// GroupSecretSum implementation\nconst std::string GroupSecretSum::kOpType(\"GroupSecretSum\");\n\nspu::kernel::hlo::AggFunc GroupSecretSum::GetAggregationFunction() const {\n  return spu::kernel::hlo::AggFunc::Sum;\n}\n\n// GroupSecretAvg implementation\nconst std::string GroupSecretAvg::kOpType(\"GroupSecretAvg\");\n\nspu::kernel::hlo::AggFunc GroupSecretAvg::GetAggregationFunction() const {\n  return spu::kernel::hlo::AggFunc::Avg;\n}\n\nspu::Value GroupSecretAvg::HandleEmptyInput(spu::SPUContext* sctx,\n                                            const spu::Value& in) {\n  return in.clone().setDtype(spu::DT_F64, true);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/group_secret_agg.h",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <string>\n\n#include \"libspu/kernel/hal/public_helper.h\"\n#include \"libspu/kernel/hlo/geometrical.h\"\n#include \"libspu/kernel/hlo/group_by_agg.h\"\n\n#include \"engine/framework/operator.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nclass GroupSecretAggBase : public Operator {\n public:\n  virtual ~GroupSecretAggBase() = default;\n\n  static constexpr char kGroupNum[] = \"GroupNum\";\n  static constexpr char kGroupId[] = \"GroupId\";\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n protected:\n  virtual spu::kernel::hlo::AggFunc GetAggregationFunction() const = 0;\n  virtual spu::Value HandleEmptyInput(spu::SPUContext* sctx,\n                                      const spu::Value& in) {\n    return in.clone();\n  }\n};\n\nclass GroupSecretSum : public GroupSecretAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override { return kOpType; }\n\n protected:\n  spu::kernel::hlo::AggFunc GetAggregationFunction() const override;\n};\n\n// FIXME: currently GroupSecretAvg default outputs float32 tensor, but\n// Interpreter expects float64 tensor.\nclass GroupSecretAvg : public GroupSecretAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override { return kOpType; }\n\n protected:\n  spu::kernel::hlo::AggFunc GetAggregationFunction() const override;\n  spu::Value HandleEmptyInput(spu::SPUContext* sctx,\n                              const spu::Value& in) override;\n};\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/group_secret_agg_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/group_secret_agg.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct GroupSecretAggTestCase {\n  test::NamedTensor group_num;\n  test::NamedTensor group_id;\n  test::NamedTensor input;\n  test::NamedTensor output;\n  std::string op_type;\n};\n\nclass GroupSecretAggTest\n    : public testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, GroupSecretAggTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const GroupSecretAggTestCase& tc) {\n    test::ExecNodeBuilder builder(tc.op_type);\n\n    builder.SetNodeName(\"group-secret-test\");\n    {\n      auto t = test::MakeTensorReference(tc.group_num.name,\n                                         tc.group_num.tensor->Type(),\n                                         pb::TensorStatus::TENSORSTATUS_PUBLIC);\n      builder.AddInput(\"GroupNum\", {t});\n    }\n    {\n      auto t = test::MakeSecretTensorReference(tc.group_id.name,\n                                               tc.group_id.tensor->Type());\n      builder.AddInput(\"GroupId\", {t});\n    }\n    {\n      auto t = test::MakeSecretTensorReference(tc.input.name,\n                                               tc.input.tensor->Type());\n      builder.AddInput(\"In\", {t});\n    }\n\n    {\n      auto t = test::MakeSecretTensorReference(tc.output.name,\n                                               tc.output.tensor->Type());\n      builder.AddOutput(\"Out\", {t});\n    }\n\n    return builder.Build();\n  }\n\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const GroupSecretAggTestCase& tc) {\n    test::FeedInputsAsSecret(ctxs, {tc.group_id, tc.input});\n    test::FeedInputsAsPublic(ctxs, {tc.group_num});\n  }\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    GroupSecretSumBatchTest, GroupSecretAggTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPCEnableColocated,\n        testing::Values(\n            GroupSecretAggTestCase{\n                .group_num = test::NamedTensor(\n                    \"num\", TensorFrom(arrow::uint32(), \"[3]\")),\n                .group_id = test::NamedTensor(\n                    \"id\", TensorFrom(arrow::int32(), \"[0, 1, 2, 1, 0]\")),\n                .input = test::NamedTensor(\n                    \"val\", TensorFrom(arrow::int64(), \"[1, 2, 3, 20, 10]\")),\n                .output = test::NamedTensor(\"agg\", TensorFrom(arrow::int64(),\n                                                              \"[11, 22, 3]\")),\n                .op_type = GroupSecretSum::kOpType},\n            GroupSecretAggTestCase{\n                .group_num = test::NamedTensor(\n                    \"num\", TensorFrom(arrow::uint32(), \"[3]\")),\n                .group_id = test::NamedTensor(\n                    \"id\", TensorFrom(arrow::int32(), \"[0, 1, 2, 1, 0]\")),\n                .input = test::NamedTensor(\n                    \"val\", TensorFrom(arrow::float64(),\n                                      \"[-1, 2.2, 3.333, -20.2, 2.2]\")),\n                .output = test::NamedTensor(\n                    \"agg\", TensorFrom(arrow::float64(), \"[1.2, -18, 3.333]\")),\n                .op_type = GroupSecretSum::kOpType},\n            GroupSecretAggTestCase{\n                .group_num = test::NamedTensor(\n                    \"num\", TensorFrom(arrow::uint32(), \"[0]\")),\n                .group_id = test::NamedTensor(\"id\",\n                                              TensorFrom(arrow::int32(), \"[]\")),\n                .input = test::NamedTensor(\"val\",\n                                           TensorFrom(arrow::int64(), \"[]\")),\n                .output = test::NamedTensor(\"agg\",\n                                            TensorFrom(arrow::int64(), \"[]\")),\n                .op_type = GroupSecretSum::kOpType})),\n    TestParamNameGenerator(GroupSecretAggTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    GroupSecretAvgBatchTest, GroupSecretAggTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPCEnableColocated,\n        testing::Values(\n            GroupSecretAggTestCase{\n                .group_num = test::NamedTensor(\n                    \"num\", TensorFrom(arrow::uint32(), \"[3]\")),\n                .group_id = test::NamedTensor(\n                    \"id\", TensorFrom(arrow::int32(), \"[0, 1, 2, 1, 0]\")),\n                .input = test::NamedTensor(\n                    \"val\", TensorFrom(arrow::int64(), \"[1, 2, 3, 20, 10]\")),\n                .output = test::NamedTensor(\"agg\", TensorFrom(arrow::float32(),\n                                                              \"[5.5, 11, 3]\")),\n                .op_type = GroupSecretAvg::kOpType},\n            GroupSecretAggTestCase{\n                .group_num = test::NamedTensor(\n                    \"num\", TensorFrom(arrow::uint32(), \"[3]\")),\n                .group_id = test::NamedTensor(\n                    \"id\", TensorFrom(arrow::int32(), \"[0, 1, 2, 1, 0]\")),\n                .input = test::NamedTensor(\n                    \"val\", TensorFrom(arrow::float64(),\n                                      \"[-1, 2.2, 3.333, -20.2, 2.2]\")),\n                .output = test::NamedTensor(\n                    \"agg\", TensorFrom(arrow::float64(), \"[0.6, -9, 3.333]\")),\n                .op_type = GroupSecretAvg::kOpType},\n            GroupSecretAggTestCase{\n                .group_num = test::NamedTensor(\n                    \"num\", TensorFrom(arrow::uint32(), \"[0]\")),\n                .group_id = test::NamedTensor(\"id\",\n                                              TensorFrom(arrow::int32(), \"[]\")),\n                .input = test::NamedTensor(\"val\",\n                                           TensorFrom(arrow::int64(), \"[]\")),\n                .output = test::NamedTensor(\"agg\",\n                                            TensorFrom(arrow::float64(), \"[]\")),\n                .op_type = GroupSecretAvg::kOpType})),\n    TestParamNameGenerator(GroupSecretAggTest));\n\nTEST_P(GroupSecretAggTest, Works) {\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n\n  auto node = MakeExecNode(tc);\n\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  if (tc.op_type == GroupSecretSum::kOpType) {\n    ASSERT_NO_THROW(test::RunAsync<GroupSecretSum>(ctx_ptrs));\n  } else if (tc.op_type == GroupSecretAvg::kOpType) {\n    ASSERT_NO_THROW(test::RunAsync<GroupSecretAvg>(ctx_ptrs));\n  } else {\n    ASSERT_TRUE(false) << \"unsupported op type: \" << tc.op_type;\n  }\n\n  std::vector<TensorPtr> outs;\n  EXPECT_NO_THROW({\n    auto t = test::RevealSecret(ctx_ptrs, tc.output.name);\n    ASSERT_TRUE(t != nullptr);\n    auto out_arr = t->ToArrowChunkedArray();\n    auto expect_arr = tc.output.tensor->ToArrowChunkedArray();\n    arrow::EqualOptions eqOption;\n    EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr, eqOption.atol(0.001)))\n        << \"expect type = \" << expect_arr->type()->ToString()\n        << \", got type = \" << out_arr->type()->ToString()\n        << \"\\nexpect result = \" << expect_arr->ToString()\n        << \"\\nbut actual got result = \" << out_arr->ToString();\n  });\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/group_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/group.h\"\n\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct GroupTestCase {\n  std::vector<test::NamedTensor> inputs;\n  test::NamedTensor group_id;\n  test::NamedTensor group_num;\n};\n\nclass GroupTest : public testing::TestWithParam<GroupTestCase> {\n protected:\n  static pb::ExecNode MakeExecNode(const GroupTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    GroupBatchTest, GroupTest,\n    testing::Values(\n        GroupTestCase{\n            .inputs = {test::NamedTensor(\n                \"in\",\n                TensorFrom(arrow::int64(), \"[2, 1, 1, 1, null, 0, null]\"))},\n            .group_id = test::NamedTensor(\n                \"out_id\", TensorFrom(arrow::uint32(), \"[0, 1, 1, 1, 2, 3, 2]\")),\n            .group_num = test::NamedTensor(\"out_num\",\n                                           TensorFrom(arrow::uint32(), \"[4]\"))},\n        GroupTestCase{\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                      \"[0, 0, 1, 1, 1, 1]\")),\n                 test::NamedTensor(\"in_b\",\n                                   TensorFrom(arrow::float32(),\n                                              \"[-1, 0, 0, 3.14, 3.14, 3.14]\")),\n                 test::NamedTensor(\n                     \"in_c\",\n                     TensorFrom(arrow::large_utf8(),\n                                R\"json([\"A\",\"B\",\"B\",\"CCC\",\"CCC\",\"CCC\"])json\"))},\n            .group_id = test::NamedTensor(\n                \"out_id\", TensorFrom(arrow::uint32(), \"[0, 1, 2, 3, 3, 3]\")),\n            .group_num = test::NamedTensor(\"out_num\",\n                                           TensorFrom(arrow::uint32(), \"[4]\"))},\n        GroupTestCase{\n            .inputs = {test::NamedTensor(\"in\",\n                                         TensorFrom(arrow::int64(), \"[1]\"))},\n            .group_id = test::NamedTensor(\"out_id\",\n                                          TensorFrom(arrow::uint32(), \"[0]\")),\n            .group_num = test::NamedTensor(\"out_num\",\n                                           TensorFrom(arrow::uint32(), \"[1]\"))},\n        GroupTestCase{\n            .inputs = {test::NamedTensor(\"in\",\n                                         TensorFrom(arrow::int64(), \"[]\"))},\n            .group_id = test::NamedTensor(\"out_id\",\n                                          TensorFrom(arrow::uint32(), \"[]\")),\n            .group_num = test::NamedTensor(\n                \"out_num\", TensorFrom(arrow::uint32(), \"[0]\"))}));\n\nTEST_P(GroupTest, works) {\n  // Given\n  auto tc = GetParam();\n  auto node = MakeExecNode(tc);\n  auto session = test::Make1PCSession();\n  ExecContext ctx(node, session.get());\n\n  test::FeedInputsAsPrivate(&ctx, tc.inputs);\n\n  // When\n  Group op;\n  EXPECT_NO_THROW(op.Run(&ctx));\n\n  // Then\n  for (const auto& check_tensor :\n       std::vector<test::NamedTensor>{tc.group_id, tc.group_num}) {\n    auto expect_arr = check_tensor.tensor->ToArrowChunkedArray();\n    auto out = ctx.GetTensorTable()->GetTensor(check_tensor.name);\n    ASSERT_TRUE(out);\n    auto out_arr = out->ToArrowChunkedArray();\n    // compare tensor content\n    EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr))\n        << \"expect type = \" << expect_arr->type()->ToString()\n        << \", got type = \" << out_arr->type()->ToString()\n        << \"\\nexpect result = \" << expect_arr->ToString()\n        << \"\\nbut actual got result = \" << out_arr->ToString();\n  }\n}\n\n/// ===================\n/// GroupTest impl\n/// ===================\n\npb::ExecNode GroupTest::MakeExecNode(const GroupTestCase& tc) {\n  test::ExecNodeBuilder builder(Group::kOpType);\n\n  builder.SetNodeName(\"plaintext-group-test\");\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    pb::Tensor t = test::MakePrivateTensorReference(\n        named_tensor.name, named_tensor.tensor->Type());\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(Group::kIn, inputs);\n\n  pb::Tensor group_id = test::MakePrivateTensorReference(\n      tc.group_id.name, tc.group_id.tensor->Type());\n  builder.AddOutput(Group::kOutId, {group_id});\n  pb::Tensor group_num = test::MakePrivateTensorReference(\n      tc.group_num.name, tc.group_num.tensor->Type());\n  builder.AddOutput(Group::kOutNum, {group_num});\n\n  return builder.Build();\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/if.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/if.h\"\n\n#include <string>\n#include <vector>\n\n#include \"arrow/compute/exec.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/const.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/framework/exec.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string If::kOpType(\"If\");\nconst std::string& If::Type() const { return kOpType; }\n\nvoid If::Validate(ExecContext* ctx) {\n  const auto& cond = ctx->GetInput(kCond);\n  YACL_ENFORCE(cond.size() == 1, \"{} size = {} not equal to 1\", kCond,\n               cond.size());\n  const auto& valueFalse = ctx->GetInput(kValueFalse);\n  YACL_ENFORCE(valueFalse.size() == 1, \"{} size = {} not equal to 1\",\n               kValueFalse, valueFalse.size());\n  const auto& valueTrue = ctx->GetInput(kValueTrue);\n  YACL_ENFORCE(valueTrue.size() == 1, \"{} size = {} not equal to 1\", kValueTrue,\n               valueTrue.size());\n  const auto& output = ctx->GetOutput(kOut);\n  YACL_ENFORCE(output.size() == 1, \"{} size = {} not equal to 1\", kOut,\n               output.size());\n\n  YACL_ENFORCE(cond[0].elem_type() != pb::STRING,\n               \"unsupported condition type {} for tensor {}\",\n               pb::PrimitiveDataType_Name(cond[0].elem_type()), cond[0].name());\n\n  std::vector<pb::Tensor> ts = {cond[0], valueFalse[0], valueTrue[0],\n                                output[0]};\n  if (util::OneOfTensorsStatusMatched({ts.begin(), ts.end()},\n                                      pb::TensorStatus::TENSORSTATUS_PRIVATE)) {\n    YACL_ENFORCE(util::AreTensorsStatusMatched(\n        {ts.begin(), ts.end()}, pb::TensorStatus::TENSORSTATUS_PRIVATE));\n  } else if (util::OneOfTensorsStatusMatched(\n                 {ts.begin(), ts.end()},\n                 pb::TensorStatus::TENSORSTATUS_SECRET)) {\n    YACL_ENFORCE(util::IsTensorStatusMatched(\n        output[0], pb::TensorStatus::TENSORSTATUS_SECRET));\n  }\n}\n\nvoid If::Execute(ExecContext* ctx) {\n  if (ctx->GetOutputStatus(kOut) == pb::TensorStatus::TENSORSTATUS_PRIVATE) {\n    IfPrivate(ctx);\n  } else {\n    IfSecret(ctx);\n  }\n}\n\nvoid If::IfPrivate(ExecContext* ctx) {\n  auto cond = ctx->GetInputTensor(kCond);\n  auto value_true = ctx->GetInputTensor(kValueTrue);\n  auto value_false = ctx->GetInputTensor(kValueFalse);\n  auto cond_array = cond->ToArrowChunkedArray();\n  if (cond->Type() != pb::BOOL) {\n    cond_array =\n        arrow::compute::CallFunction(\n            \"not_equal\", {cond->ToArrowChunkedArray(), arrow::Datum{0}})\n            .ValueOrDie()\n            .chunked_array();\n  }\n  auto result = arrow::compute::CallFunction(\n      \"if_else\", {cond_array, value_true->ToArrowChunkedArray(),\n                  value_false->ToArrowChunkedArray()});\n  YACL_ENFORCE(result.ok(),\n               \"invoking arrow if_else function failed: err_msg={}\",\n               result.status().ToString());\n  ctx->SetOutputTensor(kOut, TensorFrom(result.ValueOrDie().chunked_array()));\n}\n\nvoid If::IfSecret(ExecContext* ctx) {\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n\n  auto cond = ctx->GetInputValue(kCond);\n  auto value_true = ctx->GetInputValue(kValueTrue);\n  auto value_false = ctx->GetInputValue(kValueFalse);\n  auto zero = spu::kernel::hlo::Constant(sctx, 0, {cond.shape()});\n  auto cond_equal_zero = spu::kernel::hlo::Equal(sctx, cond, zero);\n  auto result_value = spu::kernel::hlo::Add(\n      sctx,\n      spu::kernel::hlo::Mul(\n          sctx, spu::kernel::hlo::Sub(sctx, value_false, value_true),\n          cond_equal_zero),\n      value_true);\n  ctx->SetOutputValue(kOut, result_value);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/if.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <string>\n\n#include \"engine/framework/exec.h\"\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass If : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kCond[] = \"Condition\";\n  static constexpr char kValueTrue[] = \"ValueIfTrue\";\n  static constexpr char kValueFalse[] = \"ValueIfFalse\";\n  static constexpr char kOut[] = \"Out\";\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static void IfPrivate(ExecContext* ctx);\n  static void IfSecret(ExecContext* ctx);\n};\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/if_null.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/if_null.h\"\n\n#include \"arrow/compute/api.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string IfNull::kOpType(\"IfNull\");\n\nconst std::string& IfNull::Type() const { return kOpType; }\n\nvoid IfNull::Validate(ExecContext* ctx) {\n  const auto& expr = ctx->GetInput(kExpr);\n  const auto& alt_value = ctx->GetInput(kAltValue);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(expr.size() == 1, \"IfNull input Expr size={} not equal to 1\",\n               expr.size());\n  YACL_ENFORCE(alt_value.size() == 1,\n               \"IfNull input altValue size={} not equal to 1\",\n               alt_value.size());\n  YACL_ENFORCE(outputs.size() == 1, \"IfNull output size={} not equal to 1\",\n               outputs.size());\n\n  YACL_ENFORCE(util::IsTensorStatusMatched(\n                   expr[0], pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"IfNull input expr tensor's status should be private\");\n  YACL_ENFORCE(util::IsTensorStatusMatched(\n                   alt_value[0], pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"IfNull input altValue tensor's status should be private\");\n  YACL_ENFORCE(util::IsTensorStatusMatched(\n                   outputs[0], pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"IfNull output tensor's status should be private\");\n}\n\nvoid IfNull::Execute(ExecContext* ctx) {\n  auto expr = ctx->GetInputTensor(kExpr);\n  auto alt_value = ctx->GetInputTensor(kAltValue);\n\n  auto result = arrow::compute::CallFunction(\n      \"coalesce\",\n      {expr->ToArrowChunkedArray(), alt_value->ToArrowChunkedArray()});\n  YACL_ENFORCE(result.ok(), \"caught error while invoking arrow coalesce: {}\",\n               result.status().ToString());\n\n  ctx->SetOutputTensor(kOut, TensorFrom(result.ValueOrDie().chunked_array()));\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/if_null.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass IfNull : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kExpr[] = \"Expr\";\n  static constexpr char kAltValue[] = \"AltValue\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/if_null_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/if_null.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct IfNullTestCase {\n  test::NamedTensor exp;\n  test::NamedTensor alt;\n  test::NamedTensor expect_out;\n};\n\nclass IfNullTest : public testing::TestWithParam<\n                       std::tuple<test::SpuRuntimeTestCase, IfNullTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const IfNullTestCase& tc);\n  static void FeedInputs(ExecContext* ctx, const IfNullTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    IfNullBatchTest, IfNullTest,\n    testing::Combine(\n        testing::Values(test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2}),\n        testing::Values(\n            // test private status\n            IfNullTestCase{\n                .exp = test::NamedTensor(\n                    \"exp\", TensorFrom(arrow::int64(), \"[null, 2, 3, null]\")),\n                .alt = test::NamedTensor(\n                    \"alt\", TensorFrom(arrow::int64(), \"[null, 12, 13, 14]\")),\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[null, 2, 3, 14]\"))},\n            IfNullTestCase{\n                .exp = test::NamedTensor(\"exp\",\n                                         TensorFrom(arrow::float64(),\n                                                    \"[null, -0.1, 1.1, null]\")),\n                .alt = test::NamedTensor(\n                    \"alt\",\n                    TensorFrom(arrow::float64(), \"[null, -10.1, 11.1, 12.1]\")),\n                .expect_out = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::float64(), \"[null, -0.1, 1.1, 12.1]\"))},\n            IfNullTestCase{\n                .exp = test::NamedTensor(\n                    \"exp\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"B\", null, null ,\"B\"])json\")),\n                .alt = test::NamedTensor(\n                    \"alt\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"CC\", null, \"CC\" ,\"C\"])json\")),\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"B\", null, \"CC\" ,\"B\"])json\"))},\n            IfNullTestCase{\n                .exp = test::NamedTensor(\"exp\",\n                                         TensorFrom(arrow::float64(), \"[]\")),\n                .alt = test::NamedTensor(\"alt\",\n                                         TensorFrom(arrow::float64(), \"[]\")),\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[]\"))})),\n    TestParamNameGenerator(IfNullTest));\n\nTEST_P(IfNullTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto session = test::Make1PCSession();\n  ExecContext ctx(node, session.get());\n\n  FeedInputs(&ctx, tc);\n\n  // When\n  IfNull op;\n  ASSERT_NO_THROW(op.Run(&ctx));\n\n  // Then\n  // check alice output\n  TensorPtr t = session->GetTensorTable()->GetTensor(tc.expect_out.name);\n  ASSERT_TRUE(t);\n  auto out_arr = t->ToArrowChunkedArray();\n\n  auto expect_arr = tc.expect_out.tensor->ToArrowChunkedArray();\n\n  // compare tensor content\n  EXPECT_TRUE(out_arr->Equals(expect_arr))\n      << \"expect type = \" << expect_arr->type()->ToString()\n      << \", got type = \" << out_arr->type()->ToString()\n      << \"\\nexpect result = \" << expect_arr->ToString()\n      << \"\\nbut actual got result = \" << out_arr->ToString();\n}\n\n/// ===================\n/// IfNullTest impl\n/// ===================\n\npb::ExecNode IfNullTest::MakeExecNode(const IfNullTestCase& tc) {\n  test::ExecNodeBuilder builder(IfNull::kOpType);\n  builder.SetNodeName(\"if-null-test\");\n\n  {\n    auto t =\n        test::MakePrivateTensorReference(tc.exp.name, tc.exp.tensor->Type());\n    builder.AddInput(IfNull::kExpr, {t});\n  }\n  {\n    auto t =\n        test::MakePrivateTensorReference(tc.alt.name, tc.alt.tensor->Type());\n    builder.AddInput(IfNull::kAltValue, {t});\n  }\n\n  {\n    auto t = test::MakePrivateTensorReference(tc.expect_out.name,\n                                              tc.expect_out.tensor->Type());\n    builder.AddOutput(IfNull::kOut, {t});\n  }\n\n  return builder.Build();\n}\n\nvoid IfNullTest::FeedInputs(ExecContext* ctx, const IfNullTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, {tc.exp, tc.alt});\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/if_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/if.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct IfTestCase {\n  test::NamedTensor cond;\n  pb::TensorStatus cond_status;\n  test::NamedTensor value_true;\n  pb::TensorStatus value_true_status;\n  test::NamedTensor value_false;\n  pb::TensorStatus value_false_status;\n  test::NamedTensor out;\n  pb::TensorStatus out_status;\n};\n\nclass IfTest : public ::testing::TestWithParam<\n                   std::tuple<test::SpuRuntimeTestCase, IfTestCase>> {\n protected:\n  static pb::ExecNode MakeIfExecNode(const IfTestCase& tc);\n\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const IfTestCase& tc);\n  static void FeedTensors(const std::vector<ExecContext*>& ctxs,\n                          const std::vector<test::NamedTensor>& ts,\n                          pb::TensorStatus status);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    IfPrivateTest, IfTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            IfTestCase{\n                .cond = test::NamedTensor(\n                    \"Condition\", TensorFrom(arrow::boolean(), \"[1,0,1,null]\")),\n                .cond_status = pb::TENSORSTATUS_PRIVATE,\n                .value_true = test::NamedTensor(\"ValueIfTrue\",\n                                                TensorFrom(arrow::int64(),\n                                                           \"[10,11,null,13]\")),\n                .value_true_status = pb::TENSORSTATUS_PRIVATE,\n                .value_false = test::NamedTensor(\"ValueIfFalse\",\n                                                 TensorFrom(arrow::int64(),\n                                                            \"[16,17,18,19]\")),\n                .value_false_status = pb::TENSORSTATUS_PRIVATE,\n                .out = test::NamedTensor(\n                    \"Out\", TensorFrom(arrow::int64(), \"[10,17,null,null]\")),\n                .out_status = pb::TENSORSTATUS_PRIVATE},\n            IfTestCase{\n                .cond = test::NamedTensor(\n                    \"Condition\", TensorFrom(arrow::int64(), \"[5,0,6,-1]\")),\n                .cond_status = pb::TENSORSTATUS_PRIVATE,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::int64(), \"[10,11,12,13]\")),\n                .value_true_status = pb::TENSORSTATUS_PRIVATE,\n                .value_false = test::NamedTensor(\"ValueIfFalse\",\n                                                 TensorFrom(arrow::int64(),\n                                                            \"[16,17,18,19]\")),\n                .value_false_status = pb::TENSORSTATUS_PRIVATE,\n                .out = test::NamedTensor(\"Out\", TensorFrom(arrow::int64(),\n                                                           \"[10,17,12,13]\")),\n                .out_status = pb::TENSORSTATUS_PRIVATE},\n            IfTestCase{\n                .cond = test::NamedTensor(\n                    \"Condition\", TensorFrom(arrow::int64(), \"[5,0,6,-1]\")),\n                .cond_status = pb::TENSORSTATUS_PRIVATE,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::large_utf8(),\n                                              R\"json([\"A\",\"B\",\"C\",\"D\"])json\")),\n                .value_true_status = pb::TENSORSTATUS_PRIVATE,\n                .value_false = test::NamedTensor(\n                    \"ValueIfFalse\", TensorFrom(arrow::large_utf8(),\n                                               R\"json([\"E\",\"F\",\"G\",\"H\"])json\")),\n                .value_false_status = pb::TENSORSTATUS_PRIVATE,\n                .out = test::NamedTensor(\n                    \"Out\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"A\",\"F\",\"C\",\"D\"])json\")),\n                .out_status = pb::TENSORSTATUS_PRIVATE},\n            IfTestCase{\n                .cond = test::NamedTensor(\n                    \"Condition\", TensorFrom(arrow::int64(), \"[5,0,6,-1]\")),\n                .cond_status = pb::TENSORSTATUS_SECRET,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::large_utf8(),\n                                              R\"json([\"A\",\"B\",\"C\",\"D\"])json\")),\n                .value_true_status = pb::TENSORSTATUS_SECRET,\n                .value_false = test::NamedTensor(\n                    \"ValueIfFalse\", TensorFrom(arrow::large_utf8(),\n                                               R\"json([\"E\",\"F\",\"G\",\"H\"])json\")),\n                .value_false_status = pb::TENSORSTATUS_SECRET,\n                .out = test::NamedTensor(\n                    \"Out\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"A\",\"F\",\"C\",\"D\"])json\")),\n                .out_status = pb::TENSORSTATUS_SECRET},\n            IfTestCase{\n                .cond = test::NamedTensor(\n                    \"Condition\", TensorFrom(arrow::boolean(), \"[1,0,1,1]\")),\n                .cond_status = pb::TENSORSTATUS_SECRET,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::int64(), \"[10,11,12,13]\")),\n                .value_true_status = pb::TENSORSTATUS_SECRET,\n                .value_false = test::NamedTensor(\"ValueIfFalse\",\n                                                 TensorFrom(arrow::int64(),\n                                                            \"[16,17,18,19]\")),\n                .value_false_status = pb::TENSORSTATUS_SECRET,\n                .out = test::NamedTensor(\"Out\", TensorFrom(arrow::int64(),\n                                                           \"[10,17,12,13]\")),\n                .out_status = pb::TENSORSTATUS_SECRET},\n            IfTestCase{\n                .cond = test::NamedTensor(\n                    \"Condition\", TensorFrom(arrow::int64(), \"[5,0,6,-1]\")),\n                .cond_status = pb::TENSORSTATUS_SECRET,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::int64(), \"[10,11,12,13]\")),\n                .value_true_status = pb::TENSORSTATUS_SECRET,\n                .value_false = test::NamedTensor(\"ValueIfFalse\",\n                                                 TensorFrom(arrow::int64(),\n                                                            \"[16,17,18,19]\")),\n                .value_false_status = pb::TENSORSTATUS_SECRET,\n                .out = test::NamedTensor(\"Out\", TensorFrom(arrow::int64(),\n                                                           \"[10,17,12,13]\")),\n                .out_status = pb::TENSORSTATUS_SECRET},\n            IfTestCase{\n                .cond = test::NamedTensor(\n                    \"Condition\", TensorFrom(arrow::boolean(), \"[1,0,1,1]\")),\n                .cond_status = pb::TENSORSTATUS_PUBLIC,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::int64(), \"[10,11,12,13]\")),\n                .value_true_status = pb::TENSORSTATUS_PUBLIC,\n                .value_false = test::NamedTensor(\"ValueIfFalse\",\n                                                 TensorFrom(arrow::int64(),\n                                                            \"[16,17,18,19]\")),\n                .value_false_status = pb::TENSORSTATUS_SECRET,\n                .out = test::NamedTensor(\"Out\", TensorFrom(arrow::int64(),\n                                                           \"[10,17,12,13]\")),\n                .out_status = pb::TENSORSTATUS_SECRET},\n            IfTestCase{\n                .cond = test::NamedTensor(\n                    \"Condition\", TensorFrom(arrow::boolean(), \"[1,0,1,1]\")),\n                .cond_status = pb::TENSORSTATUS_PUBLIC,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::int64(), \"[10,11,12,13]\")),\n                .value_true_status = pb::TENSORSTATUS_PUBLIC,\n                .value_false = test::NamedTensor(\"ValueIfFalse\",\n                                                 TensorFrom(arrow::int64(),\n                                                            \"[16,17,18,19]\")),\n                .value_false_status = pb::TENSORSTATUS_PUBLIC,\n                .out = test::NamedTensor(\"Out\", TensorFrom(arrow::int64(),\n                                                           \"[10,17,12,13]\")),\n                .out_status = pb::TENSORSTATUS_PUBLIC},\n            IfTestCase{\n                .cond = test::NamedTensor(\n                    \"Condition\", TensorFrom(arrow::boolean(), \"[1,0,1,1]\")),\n                .cond_status = pb::TENSORSTATUS_SECRET,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::int64(), \"[10,11,12,13]\")),\n                .value_true_status = pb::TENSORSTATUS_SECRET,\n                .value_false = test::NamedTensor(\n                    \"ValueIfFalse\",\n                    TensorFrom(arrow::float32(), \"[16,17.5,18,19.5]\")),\n                .value_false_status = pb::TENSORSTATUS_SECRET,\n                .out = test::NamedTensor(\"Out\", TensorFrom(arrow::float32(),\n                                                           \"[10,17.5,12,13]\")),\n                .out_status = pb::TENSORSTATUS_SECRET},\n            IfTestCase{\n                .cond = test::NamedTensor(\"Condition\",\n                                          TensorFrom(arrow::float32(),\n                                                     \"[1.5,0,-1.5,1]\")),\n                .cond_status = pb::TENSORSTATUS_SECRET,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::int64(), \"[10,11,12,13]\")),\n                .value_true_status = pb::TENSORSTATUS_SECRET,\n                .value_false = test::NamedTensor(\n                    \"ValueIfFalse\",\n                    TensorFrom(arrow::float32(), \"[16,17.5,18,19.5]\")),\n                .value_false_status = pb::TENSORSTATUS_SECRET,\n                .out = test::NamedTensor(\"Out\", TensorFrom(arrow::float32(),\n                                                           \"[10,17.5,12,13]\")),\n                .out_status = pb::TENSORSTATUS_SECRET},\n            IfTestCase{\n                .cond = test::NamedTensor(\"Condition\",\n                                          TensorFrom(arrow::float32(),\n                                                     \"[1.5,0,-1.5,1]\")),\n                .cond_status = pb::TENSORSTATUS_PRIVATE,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::int64(), \"[10,11,12,13]\")),\n                .value_true_status = pb::TENSORSTATUS_PRIVATE,\n                .value_false = test::NamedTensor(\n                    \"ValueIfFalse\",\n                    TensorFrom(arrow::float32(), \"[16,17.5,18,19.5]\")),\n                .value_false_status = pb::TENSORSTATUS_PRIVATE,\n                .out = test::NamedTensor(\"Out\", TensorFrom(arrow::float32(),\n                                                           \"[10,17.5,12,13]\")),\n                .out_status = pb::TENSORSTATUS_PRIVATE},\n            IfTestCase{\n                .cond = test::NamedTensor(\n                    \"Condition\", TensorFrom(arrow::boolean(), \"[1,0,1,1]\")),\n                .cond_status = pb::TENSORSTATUS_PRIVATE,\n                .value_true = test::NamedTensor(\n                    \"ValueIfTrue\", TensorFrom(arrow::int64(), \"[10,11,12,13]\")),\n                .value_true_status = pb::TENSORSTATUS_PRIVATE,\n                .value_false = test::NamedTensor(\n                    \"ValueIfFalse\",\n                    TensorFrom(arrow::float32(), \"[16,17.5,18,19.5]\")),\n                .value_false_status = pb::TENSORSTATUS_PRIVATE,\n                .out = test::NamedTensor(\"Out\", TensorFrom(arrow::float32(),\n                                                           \"[10,17.5,12,13]\")),\n                .out_status = pb::TENSORSTATUS_PRIVATE})),\n    TestParamNameGenerator(IfTest));\n\nTEST_P(IfTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeIfExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  if (tc.value_false_status == pb::TENSORSTATUS_PRIVATE) {\n    EXPECT_NO_THROW(test::RunAsync<If>({ctx_ptrs[0]}));\n  } else {\n    EXPECT_NO_THROW(test::RunAsync<If>(ctx_ptrs));\n  }\n\n  // Then check alice's outputs\n  auto* tensor_table = ctx_ptrs[0]->GetTensorTable();\n\n  TensorPtr out;\n  if (tc.value_false_status == pb::TENSORSTATUS_PRIVATE) {\n    EXPECT_NO_THROW(out = tensor_table->GetTensor(tc.out.name));\n\n  } else {\n    EXPECT_NO_THROW(out = test::RevealSecret(ctx_ptrs, tc.out.name));\n    // convert hash to string for string tensor in spu\n    if (tc.out.tensor->Type() == pb::PrimitiveDataType::STRING) {\n      out = ctx_ptrs[0]->GetSession()->HashToString(*out);\n    }\n  }\n  EXPECT_TRUE(out != nullptr);\n  EXPECT_EQ(out->Length(), tc.out.tensor->Length());\n  EXPECT_EQ(out->GetNullCount(), tc.out.tensor->GetNullCount());\n  EXPECT_EQ(out->Type(), tc.out.tensor->Type());\n  // compare tensor content\n  EXPECT_TRUE(\n      out->ToArrowChunkedArray()->Equals(tc.out.tensor->ToArrowChunkedArray()));\n}\n\n/// ===========================\n/// IfTest impl\n/// ===========================\n\npb::ExecNode IfTest::MakeIfExecNode(const IfTestCase& tc) {\n  test::ExecNodeBuilder builder(If::kOpType);\n\n  builder.SetNodeName(\"if-test\");\n  // Add inputs\n  auto cond = test::MakeTensorReference(tc.cond.name, tc.cond.tensor->Type(),\n                                        tc.cond_status);\n  builder.AddInput(If::kCond, std::vector<pb::Tensor>{cond});\n\n  auto value_true = test::MakeTensorReference(\n      tc.value_true.name, tc.value_true.tensor->Type(), tc.value_true_status);\n  builder.AddInput(If::kValueTrue, std::vector<pb::Tensor>{value_true});\n\n  auto value_false = test::MakeTensorReference(tc.value_false.name,\n                                               tc.value_false.tensor->Type(),\n                                               tc.value_false_status);\n  builder.AddInput(If::kValueFalse, std::vector<pb::Tensor>{value_false});\n\n  // Add outputs\n  auto out = test::MakeTensorReference(tc.out.name, tc.out.tensor->Type(),\n                                       tc.out_status);\n  builder.AddOutput(If::kOut, std::vector<pb::Tensor>{out});\n\n  return builder.Build();\n}\n\nvoid IfTest::FeedTensors(const std::vector<ExecContext*>& ctxs,\n                         const std::vector<test::NamedTensor>& ts,\n                         pb::TensorStatus status) {\n  if (status == pb::TENSORSTATUS_PRIVATE) {\n    test::FeedInputsAsPrivate(ctxs[0], ts);\n  } else if (status == pb::TENSORSTATUS_SECRET) {\n    test::FeedInputsAsSecret(ctxs, ts);\n  } else {\n    test::FeedInputsAsPublic(ctxs, ts);\n  }\n}\n\nvoid IfTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                        const IfTestCase& tc) {\n  FeedTensors(ctxs, {tc.cond}, tc.cond_status);\n  FeedTensors(ctxs, {tc.value_true}, tc.value_true_status);\n  FeedTensors(ctxs, {tc.value_false}, tc.value_false_status);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/in.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/in.h\"\n\n#include <sys/types.h>\n\n#include <cstddef>\n#include <cstdint>\n#include <future>\n#include <memory>\n#include <optional>\n#include <unordered_set>\n#include <vector>\n\n#include \"arrow/compute/api.h\"\n#include \"butil/files/scoped_temp_dir.h\"\n#include \"psi/algorithm/ecdh/ecdh_psi.h\"\n#include \"psi/algorithm/ecdh/ub_psi/ecdh_oprf_psi.h\"\n#include \"psi/algorithm/rr22/common.h\"\n#include \"psi/algorithm/rr22/rr22_psi.h\"\n#include \"psi/cryptor/cryptor_selector.h\"\n#include \"psi/utils/ec_point_store.h\"\n#include \"yacl/crypto/rand/rand.h\"\n\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/exe/flags.h\"\n#include \"engine/framework/exec.h\"\n#include \"engine/util/psi/common.h\"\n#include \"engine/util/tensor_util.h\"\n\nDECLARE_int64(provider_batch_size);\n\nnamespace scql::engine::op {\n\nconst std::string In::kOpType(\"In\");\n\nconst std::string& In::Type() const { return kOpType; }\n\nconst std::vector<In::InType> In::ImplementedInTypes = {InType::kPsiIn,\n                                                        InType::kLocalIn};\n\nvoid In::Validate(ExecContext* ctx) {\n  int64_t in_type = ctx->GetInt64ValueFromAttribute(kInType);\n  if (in_type < 0 || in_type >= static_cast<int64_t>(InType::kInTypeNums)) {\n    YACL_THROW(\"Unknown in type: {}\", in_type);\n  }\n  auto type = static_cast<InType>(in_type);\n\n  if (std::find(ImplementedInTypes.begin(), ImplementedInTypes.end(), type) !=\n      ImplementedInTypes.end()) {\n    if (type == InType::kPsiIn) {\n      int64_t algorithm = ctx->GetInt64ValueFromAttribute(kAlgorithmAttr);\n      if (algorithm < 0 ||\n          algorithm >= static_cast<int64_t>(util::PsiAlgo::kAlgoNums)) {\n        YACL_THROW(\"Unknown psi algorithm value: {}\", algorithm);\n      }\n    }\n\n    ValidateInputAndOutput(ctx);\n    ValidatePartyCodes(ctx);\n  } else {\n    // TODO(shunde.csd): implement other in algorithm\n    YACL_THROW(\"to be implemented\");\n  }\n}\n\nvoid In::Execute(ExecContext* ctx) {\n  auto logger = ctx->GetActiveLogger();\n  int64_t in_type = ctx->GetInt64ValueFromAttribute(kInType);\n  switch (in_type) {\n    case static_cast<int64_t>(InType::kSecretShareIn):\n      SPDLOG_LOGGER_INFO(logger, \"Execute In, In type = SecretShareIn\");\n      return SecretShareIn(ctx);\n    case static_cast<int64_t>(InType::kPsiIn):\n      SPDLOG_LOGGER_INFO(logger, \"Execute In, In type = PsiIn\");\n      return PsiIn(ctx);\n    case static_cast<int64_t>(InType::kLocalIn):\n      SPDLOG_LOGGER_INFO(logger, \"Execute In, In type = {}\", \"LocalIn\");\n      return LocalIn(ctx);\n    default:\n      YACL_THROW(\"unsupported In type id: {}\", in_type);\n  }\n}\n\nvoid In::ValidateInputAndOutput(ExecContext* ctx) {\n  const auto& left = ctx->GetInput(kInLeft);\n  const auto& right = ctx->GetInput(kInRight);\n  const auto& out = ctx->GetOutput(kOut);\n\n  // operator In only supports the comparison of one column\n  YACL_ENFORCE(left.size() == 1 && right.size() == 1,\n               \"In operator inputs Left and Right both size should be 1, but \"\n               \"got size(Left)={}, size(Right)={}\",\n               left.size(), right.size());\n  YACL_ENFORCE(out.size() == 1,\n               \"In operator output size should be 1, but got={}\", out.size());\n\n  // check tensor status\n  YACL_ENFORCE(util::AreTensorsStatusMatched(left, pb::TENSORSTATUS_PRIVATE),\n               \"In operator with psi-in algorithm input Left status should \"\n               \"be private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(right, pb::TENSORSTATUS_PRIVATE),\n               \"In operator with psi-in algorithm input Right status should \"\n               \"be private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(out, pb::TENSORSTATUS_PRIVATE),\n               \"In operator with psi-in algorithm output status should \"\n               \"be private\");\n}\n\nvoid In::ValidatePartyCodes(ExecContext* ctx) {\n  // only support 2 party\n  const auto& input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  YACL_ENFORCE(input_party_codes.size() == 2,\n               \"invalid attribute {} value size, expect 2 but got={}\",\n               kInputPartyCodesAttr, input_party_codes.size());\n\n  const auto& reveal_to = ctx->GetStringValuesFromAttribute(kRevealToAttr);\n  // reveal_to must have one element\n  YACL_ENFORCE(reveal_to.size() == 1,\n               \"In operator with psi-in algorithm should only reveal to 1 \"\n               \"party, but got={}\",\n               reveal_to.size());\n  // InAlgo::PsiIn supports revealing only to the right party, but this action\n  // itself is meaningless\n  YACL_ENFORCE(reveal_to[0] == input_party_codes[0],\n               \"In result should only reveal to left party\");\n}\n\nbool In::IsOprfServerAccordToHint(ExecContext* ctx, int64_t server_hint) {\n  YACL_ENFORCE(server_hint >= 0 && server_hint <= 1, \"invalid server hint: {}\",\n               server_hint);\n\n  const auto& my_party_code = ctx->GetSession()->SelfPartyCode();\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  bool is_left = my_party_code == input_party_codes.at(0);\n\n  return (is_left && server_hint == 0) || (!is_left && server_hint == 1);\n}\n\nvoid In::PsiIn(ExecContext* ctx) {\n  auto logger = ctx->GetActiveLogger();\n\n  auto algorithm = ctx->GetInt64ValueFromAttribute(kAlgorithmAttr);\n  switch (algorithm) {\n    case static_cast<int64_t>(util::PsiAlgo::kOprfPsi): {\n      SPDLOG_LOGGER_INFO(logger, \"use OprfPsi for In according to attribute\");\n      auto server_hint = ctx->TryGetInt64ValueFromAttribute(kUbPsiServerHint);\n      if (server_hint.has_value()) {\n        SPDLOG_LOGGER_INFO(logger, \"OprfPsi: use server hint\");\n        return OprfPsiIn(ctx,\n                         IsOprfServerAccordToHint(ctx, server_hint.value()));\n      }\n      auto psi_plan = util::CoordinatePsiPlan(ctx);\n      return OprfPsiIn(ctx, psi_plan.is_server, psi_plan.psi_size_info);\n    }\n    case static_cast<int64_t>(util::PsiAlgo::kEcdhPsi):\n      SPDLOG_LOGGER_INFO(logger, \"use EcdhPsi for In according to attribute\");\n      return EcdhPsiIn(ctx);\n    case static_cast<int64_t>(util::PsiAlgo::kRr22Psi):\n      SPDLOG_LOGGER_INFO(logger, \"use Rr22Psi for In according to attribute\");\n      return Rr22PsiIn(ctx);\n    // use rr22 as default\n    case static_cast<int64_t>(util::PsiAlgo::kAutoPsi):\n      SPDLOG_LOGGER_INFO(logger, \"use Rr22Psi as default psi type\");\n      return Rr22PsiIn(ctx);\n    default:\n      YACL_THROW(\"unsupported in algorithm id: {}\", algorithm);\n  }\n}\n\nvoid In::OprfPsiIn(ExecContext* ctx, bool is_server,\n                   std::optional<util::PsiSizeInfo> psi_size_info) {\n  auto logger = ctx->GetActiveLogger();\n  util::PsiExecutionInfoTable psi_info_table;\n  psi_info_table.start_time = std::chrono::system_clock::now();\n  // a temporary solution, related SPU-codes need to be modified someday\n  if (psi_size_info.has_value()) {\n    psi_info_table.self_size = psi_size_info->self_size;\n    psi_info_table.peer_size = psi_size_info->peer_size;\n  } else {\n    psi_info_table.self_size = 0;\n    psi_info_table.peer_size = 0;\n  }\n\n  const auto& my_party_code = ctx->GetSession()->SelfPartyCode();\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  bool is_left = my_party_code == input_party_codes.at(0);\n\n  // prepare input\n  const auto* input_name = is_left ? kInLeft : kInRight;\n  auto param_name = ctx->GetInput(input_name)[0].name();\n  auto in_tensor = ctx->GetTensorTable()->GetTensor(param_name);\n  YACL_ENFORCE(in_tensor != nullptr, \"{} not found in tensor table\",\n               param_name);\n  auto batch_provider = std::make_shared<util::BatchProvider>(\n      std::vector<TensorPtr>{in_tensor}, FLAGS_provider_batch_size);\n\n  // check reveal condition\n  std::string reveal_to_party_code =\n      ctx->GetStringValueFromAttribute(kRevealToAttr);\n  YACL_ENFORCE(reveal_to_party_code == input_party_codes[0],\n               \"In result should only reveal to left party\");\n  auto target_rank = ctx->GetSession()->GetPartyRank(reveal_to_party_code);\n  YACL_ENFORCE(target_rank != -1, \"unknown rank for party {}\",\n               reveal_to_party_code);\n  bool reveal_to_me = reveal_to_party_code == my_party_code;\n  bool reveal_to_server =\n      (is_server && reveal_to_me) || (!is_server && !reveal_to_me);\n\n  // set EcdhOprfPsiOptions\n  psi::ecdh::EcdhOprfPsiOptions psi_options;\n  auto psi_link = ctx->GetSession()->GetLink();\n  if (psi_link->WorldSize() > 2) {\n    psi_link = psi_link->SubWorld(ctx->GetNodeName() + \"-OprfPsiIn\",\n                                  input_party_codes);\n  }\n  psi_options.cache_transfer_link = psi_link;\n  YACL_ENFORCE(psi_options.cache_transfer_link,\n               \"fail to create cache_transfer_link for OprfPsiIn\");\n  psi_options.online_link = psi_options.cache_transfer_link->Spawn();\n  YACL_ENFORCE(psi_options.online_link,\n               \"fail to create online_link for OprfPsiIn\");\n\n  psi_options.curve_type = static_cast<psi::CurveType>(\n      ctx->GetSession()->GetSessionOptions().psi_config.psi_curve_type);\n\n  // create temp dir\n  butil::ScopedTempDir tmp_dir;\n  YACL_ENFORCE(tmp_dir.CreateUniqueTempDir(), \"fail to create temp dir\");\n\n  if (is_server) {\n    OprfPsiServer(ctx, reveal_to_server, tmp_dir.path().value(), psi_options,\n                  batch_provider, &psi_info_table, psi_link);\n  } else {\n    OprfPsiClient(ctx, reveal_to_server, tmp_dir.path().value(), psi_options,\n                  batch_provider, &psi_info_table, psi_link);\n  }\n\n  SPDLOG_LOGGER_INFO(\n      logger,\n      \"OPRF PSI In finish, my_party_code:{}, my_rank:{}, total \"\n      \"self_item_count:{}, total peer_item_count:{}, result size:{}\",\n      ctx->GetSession()->SelfPartyCode(), ctx->GetSession()->SelfRank(),\n      psi_info_table.self_size, psi_info_table.peer_size,\n      psi_info_table.result_size);\n}\n\nint64_t In::OprfServerHandleResult(ExecContext* ctx,\n                                   const std::vector<uint64_t>& matched_indices,\n                                   size_t self_item_count) {\n  auto logger = ctx->GetActiveLogger();\n  SPDLOG_LOGGER_INFO(\n      logger,\n      \"Server handle result, matched_indices size={}, self_item_count={}\",\n      matched_indices.size(), self_item_count);\n  std::unordered_set<uint64_t> matched_indices_set(matched_indices.begin(),\n                                                   matched_indices.end());\n  BooleanTensorBuilder result_builder;\n  result_builder.Reserve(static_cast<int64_t>(self_item_count));\n  for (uint64_t indice = 0; indice < self_item_count; ++indice) {\n    if (matched_indices_set.count(indice) > 0) {\n      result_builder.UnsafeAppend(true);\n    } else {\n      result_builder.UnsafeAppend(false);\n    }\n  }\n\n  TensorPtr result_tensor;\n  result_builder.Finish(&result_tensor);\n  int64_t result_size = result_tensor->Length();\n\n  const auto& output_pb = ctx->GetOutput(In::kOut)[0];\n  ctx->GetSession()->GetTensorTable()->AddTensor(output_pb.name(),\n                                                 std::move(result_tensor));\n  return result_size;\n}\n\nvoid In::OprfPsiServer(\n    ExecContext* ctx, bool reveal_to_server, const std::string& tmp_dir,\n    const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n    const std::shared_ptr<util::BatchProvider>& batch_provider,\n    util::PsiExecutionInfoTable* psi_info_table,\n    std::shared_ptr<yacl::link::Context> psi_link) {\n  std::vector<uint8_t> private_key =\n      yacl::crypto::SecureRandBytes(psi::kEccKeySize);\n  auto ec_oprf_psi_server =\n      std::make_shared<psi::ecdh::EcdhOprfPsiServer>(psi_options, private_key);\n  YACL_ENFORCE(ec_oprf_psi_server, \"Fail to create EcdhOprfPsiServer\");\n  if (reveal_to_server) {\n    // Create UbPsiCache\n    std::string server_cache_path = fmt::format(\"{}/tmp-server-cache\", tmp_dir);\n    std::shared_ptr<psi::IUbPsiCache> ub_cache;\n    std::vector<std::string> dummy_fields{};\n    ub_cache = std::make_shared<psi::UbPsiCache>(\n        server_cache_path, ec_oprf_psi_server->GetCompareLength(), dummy_fields,\n        private_key);\n\n    util::OprfPsiServerTransferServerItems(ctx, psi_link, batch_provider,\n                                           ec_oprf_psi_server, ub_cache);\n\n    std::vector<uint64_t> matched_indices;\n    size_t self_item_count{};\n    util::OprfServerTransferShuffledClientItems(\n        ctx, ec_oprf_psi_server, server_cache_path, &matched_indices,\n        &self_item_count);\n    psi_info_table->result_size =\n        OprfServerHandleResult(ctx, matched_indices, self_item_count);\n  } else {\n    auto transfer_server_items_future =\n        std::async(std::launch::async, util::OprfPsiServerTransferServerItems,\n                   ctx, psi_link, batch_provider, ec_oprf_psi_server, nullptr);\n    util::OprfPsiServerTransferClientItems(ctx, ec_oprf_psi_server);\n    transfer_server_items_future.get();\n    psi_info_table->result_size = 0;\n  }\n}\n\nvoid In::OprfPsiClient(\n    ExecContext* ctx, bool reveal_to_server, const std::string& tmp_dir,\n    const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n    const std::shared_ptr<util::BatchProvider>& batch_provider,\n    util::PsiExecutionInfoTable* psi_info_table,\n    std::shared_ptr<yacl::link::Context> psi_link) {\n  std::string server_cipher_store_path =\n      fmt::format(\"{}/tmp-server-cipher-store.csv\", tmp_dir);\n  auto server_store =\n      std::make_shared<util::UbPsiCipherStore>(server_cipher_store_path, false);\n\n  std::string client_cipher_store_path =\n      fmt::format(\"{}/tmp-client-cipher-store.csv\", tmp_dir);\n  auto client_store =\n      std::make_shared<util::UbPsiCipherStore>(client_cipher_store_path, true);\n\n  if (reveal_to_server) {\n    util::OprfPsiClientTransferServerItems(ctx, psi_link, psi_options,\n                                           server_store);\n    util::OprfCLientTransferShuffledClientItems(\n        ctx, batch_provider, psi_options, client_store, server_store);\n    psi_info_table->result_size = 0;\n  } else {\n    auto transfer_server_items_future =\n        std::async(std::launch::async, util::OprfPsiClientTransferServerItems,\n                   ctx, psi_link, psi_options, server_store);\n    OprfPsiClientTransferClientItems(ctx, batch_provider, psi_options,\n                                     client_store);\n    transfer_server_items_future.get();\n    psi_info_table->result_size =\n        OprfClientHandleResult(ctx, client_store, server_store);\n  }\n}\n\nint64_t In::OprfClientHandleResult(\n    ExecContext* ctx,\n    const std::shared_ptr<util::UbPsiCipherStore>& client_store,\n    const std::shared_ptr<util::UbPsiCipherStore>& server_store) {\n  auto result_tensor =\n      util::FinalizeAndComputeOprfInResult(client_store, server_store);\n  int64_t result_size = result_tensor->Length();\n\n  const auto& output_pb = ctx->GetOutput(In::kOut)[0];\n  ctx->GetSession()->GetTensorTable()->AddTensor(output_pb.name(),\n                                                 std::move(result_tensor));\n  return result_size;\n}\n\nvoid In::EcdhPsiIn(ExecContext* ctx) {\n  auto logger = ctx->GetActiveLogger();\n\n  const auto& my_party_code = ctx->GetSession()->SelfPartyCode();\n\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  std::string reveal_to = ctx->GetStringValueFromAttribute(kRevealToAttr);\n\n  bool is_left = my_party_code == input_party_codes.at(0);\n  auto target_rank = ctx->GetSession()->GetPartyRank(reveal_to);\n  YACL_ENFORCE(target_rank != -1, \"unknown rank for party {}\", reveal_to);\n\n  auto param_name = ctx->GetInput(kInLeft)[0].name();\n  if (!is_left) {\n    param_name = ctx->GetInput(kInRight)[0].name();\n  }\n  auto in_tensor = ctx->GetTensorTable()->GetTensor(param_name);\n  YACL_ENFORCE(in_tensor != nullptr, \"{} not found in tensor table\",\n               param_name);\n  if (ctx->GetSession()->GetPsiLogger()) {\n    ctx->GetSession()->GetPsiLogger()->LogInput({in_tensor});\n  }\n  auto batch_provider = std::make_shared<util::BatchProvider>(\n      std::vector<TensorPtr>{in_tensor}, FLAGS_provider_batch_size);\n  auto self_store =\n      std::make_shared<psi::HashBucketEcPointStore>(\"/tmp\", util::kNumBins);\n  auto peer_store =\n      std::make_shared<psi::HashBucketEcPointStore>(\"/tmp\", util::kNumBins);\n  {\n    psi::ecdh::EcdhPsiOptions options;\n    options.link_ctx = ctx->GetSession()->GetLink();\n    if (options.link_ctx->WorldSize() > 2) {\n      options.link_ctx = options.link_ctx->SubWorld(\n          ctx->GetNodeName() + \"-EcdhPsiIn\", input_party_codes);\n      // update target rank since link_ctx changed.\n      if (reveal_to == input_party_codes[0]) {\n        target_rank = 0;\n      } else {\n        target_rank = 1;\n      }\n    }\n\n    options.ecc_cryptor = psi::CreateEccCryptor(static_cast<psi::CurveType>(\n        ctx->GetSession()->GetSessionOptions().psi_config.psi_curve_type));\n    options.target_rank = target_rank;\n    options.on_batch_finished = util::BatchFinishedCb(\n        logger, ctx->GetSession()->Id(),\n        (in_tensor->Length() + options.batch_size - 1) / options.batch_size);\n    if (ctx->GetSession()->GetPsiLogger()) {\n      options.ecdh_logger = ctx->GetSession()->GetPsiLogger()->GetEcdhLogger();\n    }\n\n    psi::ecdh::RunEcdhPsi(options, batch_provider, self_store, peer_store);\n  }\n  // reveal to me\n\n  size_t self_size = 0;\n  size_t peer_size = 0;\n  int64_t result_size = 0;\n  if (reveal_to == my_party_code) {\n    auto result =\n        util::FinalizeAndComputeInResult(is_left, self_store, peer_store);\n    self_size = self_store->ItemCount();\n    peer_size = peer_store->ItemCount();\n    result_size = result->Length();\n    SPDLOG_LOGGER_INFO(\n        logger,\n        \"ECDH PSI In finish, my_party_code:{}, my_rank:{}, total \"\n        \"self_item_count:{}, total peer_item_count:{}, result size:{}\",\n        ctx->GetSession()->SelfPartyCode(), ctx->GetSession()->SelfRank(),\n        self_size, peer_size, result_size);\n    const auto& output_pb = ctx->GetOutput(kOut)[0];\n    if (ctx->GetSession()->GetPsiLogger()) {\n      ctx->GetSession()->GetPsiLogger()->LogOutput(result);\n    }\n    ctx->GetSession()->GetTensorTable()->AddTensor(output_pb.name(),\n                                                   std::move(result));\n  }\n}\n\nvoid In::Rr22PsiIn(ExecContext* ctx) {\n  auto logger = ctx->GetActiveLogger();\n\n  const auto& my_party_code = ctx->GetSession()->SelfPartyCode();\n\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  std::string reveal_to = ctx->GetStringValueFromAttribute(kRevealToAttr);\n\n  bool is_left = my_party_code == input_party_codes.at(0);\n  auto target_rank = ctx->GetSession()->GetPartyRank(reveal_to);\n  YACL_ENFORCE(target_rank != -1, \"unknown rank for party {}\", reveal_to);\n\n  auto param_name = ctx->GetInput(kInLeft)[0].name();\n  if (!is_left) {\n    param_name = ctx->GetInput(kInRight)[0].name();\n  }\n  auto in_tensor = ctx->GetTensorTable()->GetTensor(param_name);\n  YACL_ENFORCE(in_tensor != nullptr, \"{} not found in tensor table\",\n               param_name);\n  auto psi_link = ctx->GetSession()->GetLink();\n  if (psi_link->WorldSize() > 2) {\n    psi_link = psi_link->SubWorld(ctx->GetNodeName() + \"-Rr22PsiJoin\",\n                                  input_party_codes);\n  }\n  auto self_size = static_cast<size_t>(in_tensor->Length());\n  auto peer_size = util::ExchangeSetSize(psi_link, self_size);\n  auto provider = util::BucketProvider({in_tensor});\n  provider.InitBucket(psi_link, self_size, peer_size);\n  auto bucket_num = provider.GetBucketNum();\n  std::shared_ptr<util::InResultResolverWithBucket> result_solver;\n  if (reveal_to == my_party_code) {\n    result_solver =\n        std::make_shared<util::InResultResolverWithBucket>(self_size);\n  }\n  psi::rr22::PreProcessFunc pre_f =\n      [&](size_t idx) -> std::vector<psi::HashBucketCache::BucketItem> {\n    YACL_ENFORCE(idx < bucket_num);\n    return provider.GetDeDupItemsInBucket(idx);\n  };\n  psi::rr22::PostProcessFunc post_f =\n      [&](size_t bucket_idx,\n          const std::vector<psi::HashBucketCache::BucketItem>& bucket_items,\n          const std::vector<uint32_t>& indices,\n          const std::vector<uint32_t>& peer_cnt) {\n        if (reveal_to == my_party_code) {\n          result_solver->FeedBucketData(bucket_idx, bucket_items, indices,\n                                        provider.GetDupIndices(bucket_idx));\n        }\n        provider.CleanBucket(bucket_idx);\n      };\n  psi::rr22::Rr22Runner runner(\n      psi_link,\n      psi::rr22::GenerateRr22PsiOptions(\n          ctx->GetSession()->GetSessionOptions().psi_config.rr22_mode ==\n          pb::LOW_MODE),\n      bucket_num, false, pre_f, post_f);\n  // reveal party as receiver\n  runner.ParallelRun(0, reveal_to != my_party_code);\n  // reveal to me\n  int64_t result_size = 0;\n  if (reveal_to == my_party_code) {\n    auto result = result_solver->ComputeInResult();\n    result_size = result->Length();\n    SPDLOG_LOGGER_INFO(\n        logger,\n        \"ECDH PSI In finish, my_party_code:{}, my_rank:{}, total \"\n        \"self_item_count:{}, total peer_item_count:{}, result size:{}\",\n        ctx->GetSession()->SelfPartyCode(), ctx->GetSession()->SelfRank(),\n        self_size, peer_size, result_size);\n    const auto& output_pb = ctx->GetOutput(kOut)[0];\n    if (ctx->GetSession()->GetPsiLogger()) {\n      ctx->GetSession()->GetPsiLogger()->LogOutput(result);\n    }\n    ctx->GetSession()->GetTensorTable()->AddTensor(output_pb.name(),\n                                                   std::move(result));\n  }\n}\n\nvoid In::LocalIn(ExecContext* ctx) {\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  std::string my_party_code = ctx->GetSession()->SelfPartyCode();\n  YACL_ENFORCE(input_party_codes.size() == 2,\n               \"input_party_codes size must be 2\");\n  YACL_ENFORCE(input_party_codes[0] == input_party_codes[1],\n               \"input_party_codes must be same\");\n  if (input_party_codes[0] == my_party_code) {\n    auto left = ctx->GetInputTensor(kInLeft);\n    auto right = ctx->GetInputTensor(kInRight);\n    auto result_status = arrow::compute::IsIn(left->ToArrowChunkedArray(),\n                                              right->ToArrowChunkedArray());\n    YACL_ENFORCE(result_status.ok(), \"failed to compute isin, error:{}\",\n                 result_status->ToString());\n    ctx->SetOutputTensor(\n        kOut, TensorFrom(result_status.ValueOrDie().chunked_array()));\n  } else {\n    YACL_THROW(\"tensors are in {}'s side\", my_party_code);\n  }\n}\nvoid In::SecretShareIn(ExecContext* ctx) { YACL_THROW(\"unimplemented\"); }\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/in.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <cstdint>\n#include <optional>\n\n#include \"engine/framework/exec.h\"\n#include \"engine/framework/operator.h\"\n#include \"engine/util/psi/batch_provider.h\"\n#include \"engine/util/psi/cipher_intersection.h\"\n#include \"engine/util/psi/common.h\"\n#include \"engine/util/psi/ub_helper.h\"\n\nnamespace scql::engine::op {\n\nclass In : public Operator {\n public:\n  enum class InType : int64_t {\n    kPsiIn = 0,\n    kSecretShareIn = 1,\n    kLocalIn = 2,\n    kInTypeNums,  // Sentinel Value, must be placed last\n  };\n\n  static const std::string kOpType;\n\n  static constexpr char kInLeft[] = \"Left\";\n  static constexpr char kInRight[] = \"Right\";\n  static constexpr char kOut[] = \"Out\";\n  static constexpr char kInType[] = \"in_type\";\n  static constexpr char kAlgorithmAttr[] = \"psi_algorithm\";\n  static constexpr char kInputPartyCodesAttr[] = \"input_party_codes\";\n  static constexpr char kRevealToAttr[] = \"reveal_to\";\n\n  static constexpr char kUbPsiServerHint[] = \"ub_psi_server_hint\";\n  const static std::vector<InType> ImplementedInTypes;\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static void SecretShareIn(ExecContext* ctx);\n  static void PsiIn(ExecContext* ctx);\n  static void LocalIn(ExecContext* ctx);\n  static void EcdhPsiIn(ExecContext* ctx);\n  static void Rr22PsiIn(ExecContext* ctx);\n  static void OprfPsiIn(ExecContext* ctx, bool is_server,\n                        std::optional<util::PsiSizeInfo> = {});\n\n  static void ValidateInputAndOutput(ExecContext* ctx);\n  static void ValidatePartyCodes(ExecContext* ctx);\n\n  // oprf psi\n  static bool IsOprfServerAccordToHint(ExecContext* ctx, int64_t server_hint);\n  static void OprfPsiServer(\n      ExecContext* ctx, bool reveal_to_server, const std::string& tmp_dir,\n      const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n      const std::shared_ptr<util::BatchProvider>& batch_provider,\n      util::PsiExecutionInfoTable* psi_info_table,\n      std::shared_ptr<yacl::link::Context> psi_link);\n  static void OprfPsiClient(\n      ExecContext* ctx, bool reveal_to_server, const std::string& tmp_dir,\n      const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n      const std::shared_ptr<util::BatchProvider>& batch_provider,\n      util::PsiExecutionInfoTable* psi_info_table,\n      std::shared_ptr<yacl::link::Context> psi_link);\n\n  static int64_t OprfServerHandleResult(\n      ExecContext* ctx, const std::vector<uint64_t>& matched_indices,\n      size_t self_item_count);\n  static int64_t OprfClientHandleResult(\n      ExecContext* ctx,\n      const std::shared_ptr<util::UbPsiCipherStore>& client_store,\n      const std::shared_ptr<util::UbPsiCipherStore>& server_store);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/in_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/in.h\"\n\n#include <cstdint>\n#include <vector>\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct InTestCase {\n  test::NamedTensor left_input;\n  test::NamedTensor right_input;\n  int64_t in_algo;\n  int64_t in_type;\n  std::string left_party;\n  std::string right_party;\n  std::string reveal_to;\n  test::NamedTensor output;\n  int64_t ub_server;\n};\n\nclass InTest : public ::testing::TestWithParam<\n                   std::tuple<test::SpuRuntimeTestCase, InTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const InTestCase& tc);\n\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const InTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    InBatchTest, InTest,\n    ::testing::Combine(\n        test::SpuTestValues2PC,\n        testing::Values(\n            // EcdhPsi\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\",\n                    TensorFrom(arrow::int64(), \"[10, 100, 2, -1, 34, 42]\")),\n                .right_input = test::NamedTensor(\n                    \"y\",\n                    TensorFrom(arrow::int64(), \"[1, 2, 3, -1, 34, 43, 99]\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kRr22Psi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\",\n                    TensorFrom(arrow::boolean(),\n                               \"[false, false, true, true, true, false]\"))},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"C\", \"D\", \"B\", \"A\", \"G\"])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kRr22Psi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(),\n                                    \"[true, false, true, false, true]\"))},\n            // testcase: right input empty\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(), R\"json([])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kRr22Psi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(),\n                                    \"[false, false, false, false, false]\"))},\n            // testcase: left input empty\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kRr22Psi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                            \"[]\"))},\n            // EcdhPsi\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\",\n                    TensorFrom(arrow::int64(), \"[10, 100, 2, -1, 34, 42]\")),\n                .right_input = test::NamedTensor(\n                    \"y\",\n                    TensorFrom(arrow::int64(), \"[1, 2, 3, -1, 34, 43, 99]\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kEcdhPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\",\n                    TensorFrom(arrow::boolean(),\n                               \"[false, false, true, true, true, false]\"))},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"C\", \"D\", \"B\", \"A\", \"G\"])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kEcdhPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(),\n                                    \"[true, false, true, false, true]\"))},\n            // testcase: right input empty\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(), R\"json([])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kEcdhPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(),\n                                    \"[false, false, false, false, false]\"))},\n            // testcase: left input empty\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kEcdhPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\"z\", TensorFrom(arrow::boolean(),\n                                                            \"[]\"))},\n\n            // unbalanced PSI\n            // reveal to client\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\",\n                    TensorFrom(arrow::int64(), \"[10, 100, 2, -1, 34, 42]\")),\n                .right_input = test::NamedTensor(\n                    \"y\",\n                    TensorFrom(arrow::int64(), \"[1, 2, 3, -1, 34, 43, 99]\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kOprfPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(),\n                                    \"[false, false, true, true, true, false]\")),\n                .ub_server = 1},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(\n                             arrow::large_utf8(),\n                             R\"json([\"A\", \"E\", \"D\", \"F\", \"D\", \"A\", \"C\"])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"C\", \"D\", \"B\", \"A\", \"G\"])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kOprfPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\",\n                    TensorFrom(arrow::boolean(),\n                               \"[true, false, true, false, true, true, true]\")),\n                .ub_server = 1},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(), R\"json([])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kOprfPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(),\n                                    \"[false, false, false, false, false]\")),\n                .ub_server = 1},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kOprfPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\"z\",\n                                            TensorFrom(arrow::boolean(), \"[]\")),\n                .ub_server = 1},\n\n            // reveal to server\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\",\n                    TensorFrom(arrow::int64(), \"[10, 100, 2, -1, 34, 42]\")),\n                .right_input = test::NamedTensor(\n                    \"y\",\n                    TensorFrom(arrow::int64(), \"[1, 2, 3, -1, 34, 43, 99]\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kOprfPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(),\n                                    \"[false, false, true, true, true, false]\")),\n                .ub_server = 0},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(\n                             arrow::large_utf8(),\n                             R\"json([\"A\", \"E\", \"D\", \"F\", \"D\", \"A\", \"C\"])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"C\", \"D\", \"B\", \"A\", \"G\"])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kOprfPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\",\n                    TensorFrom(arrow::boolean(),\n                               \"[true, false, true, false, true, true, true]\")),\n                .ub_server = 0},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(), R\"json([])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kOprfPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(),\n                                    \"[false, false, false, false, false]\")),\n                .ub_server = 0},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kOprfPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\"z\",\n                                            TensorFrom(arrow::boolean(), \"[]\")),\n                .ub_server = 0},\n\n            // without hint\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\",\n                    TensorFrom(arrow::int64(), \"[10, 100, 2, -1, 34, 42]\")),\n                .right_input = test::NamedTensor(\n                    \"y\",\n                    TensorFrom(arrow::int64(), \"[1, 2, 3, -1, 34, 43, 99]\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kAutoPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(),\n                                    \"[false, false, true, true, true, false]\")),\n                .ub_server = -1},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(\n                             arrow::large_utf8(),\n                             R\"json([\"A\", \"E\", \"D\", \"F\", \"D\", \"A\", \"C\"])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"C\", \"D\", \"B\", \"A\", \"G\"])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kAutoPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\",\n                    TensorFrom(arrow::boolean(),\n                               \"[true, false, true, false, true, true, true]\")),\n                .ub_server = -1},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(), R\"json([])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kAutoPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\", TensorFrom(arrow::boolean(),\n                                    \"[false, false, false, false, false]\")),\n                .ub_server = -1},\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\")),\n                .right_input = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\", \"E\", \"D\", \"F\", \"A\"])json\")),\n                .in_algo = static_cast<int64_t>(util::PsiAlgo::kAutoPsi),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyBob,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\"z\",\n                                            TensorFrom(arrow::boolean(), \"[]\")),\n                .ub_server = -1},\n            // local\n            InTestCase{\n                .left_input = test::NamedTensor(\n                    \"x\",\n                    TensorFrom(arrow::int64(), \"[10, 100, 2, -1, 34, 42]\")),\n                .right_input = test::NamedTensor(\n                    \"y\",\n                    TensorFrom(arrow::int64(), \"[1, 2, 3, -1, 34, 43, 99]\")),\n                //.in_algo = static_cast<int64_t>(util::PsiAlgo::kRr22Psi),\n                .in_type = static_cast<int64_t>(In::InType::kLocalIn),\n                .left_party = test::kPartyAlice,\n                .right_party = test::kPartyAlice,\n                .reveal_to = test::kPartyAlice,\n                .output = test::NamedTensor(\n                    \"z\",\n                    TensorFrom(arrow::boolean(),\n                               \"[false, false, true, true, true, false]\"))})),\n    TestParamNameGenerator(InTest));\n\nTEST_P(InTest, Works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  std::unordered_set<int64_t> supported_algos{\n      static_cast<int64_t>(util::PsiAlgo::kAutoPsi),\n      static_cast<int64_t>(util::PsiAlgo::kOprfPsi),\n      static_cast<int64_t>(util::PsiAlgo::kEcdhPsi),\n      static_cast<int64_t>(util::PsiAlgo::kRr22Psi)};\n  if (supported_algos.count(tc.in_algo) == 0) {\n    FAIL() << \"In algorithm \" << tc.in_algo << \" not supported yet\";\n  }\n  auto node = MakeExecNode(tc);\n  std::vector<std::shared_ptr<Session>> sessions;\n  if (tc.in_type == static_cast<int64_t>(In::InType::kLocalIn)) {\n    sessions = {test::Make1PCSession()};\n  } else {\n    sessions = test::MakeMultiPCSession(std::get<0>(parm));\n  }\n\n  ExecContext alice_ctx(node, sessions[0].get());\n  ExecContext bob_ctx(node, sessions[0].get());\n\n  if (tc.in_type == static_cast<int64_t>(In::InType::kLocalIn)) {\n    FeedInputs({&alice_ctx}, tc);\n    EXPECT_NO_THROW(test::RunAsync<In>({&alice_ctx}));\n  } else {\n    ExecContext bob_ctx(node, sessions[1].get());\n\n    FeedInputs({&alice_ctx, &bob_ctx}, tc);\n\n    // When\n    EXPECT_NO_THROW(test::RunAsync<In>({&alice_ctx, &bob_ctx}));\n  }\n\n  // Then\n  if (supported_algos.count(tc.in_algo) > 0) {\n    auto* tensor_table = alice_ctx.GetSession()->GetTensorTable();\n    if (tc.reveal_to != test::kPartyAlice) {\n      tensor_table = bob_ctx.GetSession()->GetTensorTable();\n    }\n    auto out_t = tensor_table->GetTensor(tc.output.name);\n    ASSERT_TRUE(out_t != nullptr);\n    auto out_chunked_arr = out_t->ToArrowChunkedArray();\n    auto expect_chunked_arr = tc.output.tensor->ToArrowChunkedArray();\n    EXPECT_TRUE(out_chunked_arr->Equals(expect_chunked_arr))\n        << \"\\nexpect=\" << expect_chunked_arr->ToString()\n        << \"\\n,but got=\" << out_chunked_arr->ToString();\n\n  } else {\n    FAIL() << \"In algorithm \" << tc.in_algo << \" not supported yet\";\n  }\n}\n\n// ===============\n//   InTest impl\n// ===============\n\npb::ExecNode InTest::MakeExecNode(const InTestCase& tc) {\n  test::ExecNodeBuilder builder(In::kOpType);\n\n  builder.SetNodeName(\"in-test\");\n\n  // set in_algo\n  builder.AddInt64Attr(In::kAlgorithmAttr, tc.in_algo);\n  builder.AddInt64Attr(In::kInType, tc.in_type);\n\n  // Add input left\n  auto left = test::MakePrivateTensorReference(tc.left_input.name,\n                                               tc.left_input.tensor->Type());\n  builder.AddInput(In::kInLeft, std::vector<pb::Tensor>{left});\n  // Add input right\n  auto right = test::MakePrivateTensorReference(tc.right_input.name,\n                                                tc.right_input.tensor->Type());\n  builder.AddInput(In::kInRight, std::vector<pb::Tensor>{right});\n  // Add output\n  auto output = test::MakePrivateTensorReference(tc.output.name,\n                                                 tc.output.tensor->Type());\n  builder.AddOutput(In::kOut, std::vector<pb::Tensor>{output});\n\n  builder.AddStringsAttr(\n      In::kInputPartyCodesAttr,\n      std::vector<std::string>{tc.left_party, tc.right_party});\n  builder.AddStringAttr(In::kRevealToAttr, tc.reveal_to);\n\n  builder.AddInt64Attr(In::kUbPsiServerHint, tc.ub_server);\n\n  return builder.Build();\n}\n\nvoid InTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                        const InTestCase& tc) {\n  for (const auto& ctx : ctxs) {\n    auto party_code = ctx->GetSession()->SelfPartyCode();\n    if (party_code == tc.left_party) {\n      test::FeedInputsAsPrivate(ctx, {tc.left_input});\n    }\n\n    if (party_code == tc.right_party) {\n      test::FeedInputsAsPrivate(ctx, {tc.right_input});\n    }\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/insert_table.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/insert_table.h\"\n\n#include \"arrow/visit_array_inline.h\"\n#include \"gflags/gflags.h\"\n\n#include \"engine/datasource/odbc_connector.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n#include \"engine/util/time_util.h\"\n\nnamespace scql::engine::op {\n\nDEFINE_string(output_db_kind, \"\",\n              \"the kind of output db, support mysql/sqlite/postgresql\");\nDEFINE_string(output_db_connection_str, \"\",\n              \"the connection str to connect to output db\");\n\nnamespace {\n\nconstexpr int64_t kBatchSize = 1000;\n\nclass ValueVistor {\n public:\n  ValueVistor() = delete;\n\n  explicit ValueVistor(std::vector<std::string>* result_vector, bool is_time)\n      : result_vector_(result_vector), is_time_(is_time) {\n    YACL_ENFORCE(result_vector_, \"result_vector_ can not be null\");\n    result_vector_->clear();\n  }\n\n  template <typename T>\n  arrow::Status Visit(const T& array) {\n    return arrow::Status::NotImplemented(fmt::format(\n        \"type {} is not implemented in ValueVistor\", array.type()->name()));\n  }\n\n  template <typename TYPE>\n  arrow::Status Visit(const arrow::NumericArray<TYPE>& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      result_vector_->push_back(\n          array.IsNull(i) ? \"NULL\" : std::to_string(array.GetView(i)));\n    }\n    return arrow::Status::OK();\n  }\n\n  arrow::Status Visit(const arrow::BooleanArray& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      result_vector_->emplace_back(array.IsNull(i)    ? \"NULL\"\n                                   : array.GetView(i) ? \"TRUE\"\n                                                      : \"FALSE\");\n    }\n    return arrow::Status::OK();\n  }\n\n  arrow::Status Visit(const arrow::NumericArray<arrow::Int64Type>& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      if (array.IsNull(i)) {\n        result_vector_->emplace_back(\"NULL\");\n      } else {\n        if (is_time_) {\n          auto time_str = QuotingString(\n              util::ConvertEpochToStr(static_cast<time_t>(array.GetView(i))));\n          result_vector_->push_back(std::move(time_str));\n        } else {\n          result_vector_->push_back(std::to_string(array.GetView(i)));\n        }\n      }\n    }\n    return arrow::Status::OK();\n  }\n\n  arrow::Status Visit(const arrow::LargeStringArray& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      if (array.IsNull(i)) {\n        result_vector_->push_back(\"NULL\");\n      } else {\n        auto quoted_str = QuotingString(array.Value(i));\n        result_vector_->push_back(std::move(quoted_str));\n      }\n    }\n    return arrow::Status::OK();\n  }\n\n private:\n  std::string static QuotingString(std::string_view str) {\n    // FIXME(jingshi): the string may cantain \"'\", which should be escaped\n    return absl::StrCat(\"'\", str, \"'\");\n  }\n\n private:\n  std::vector<std::string>* result_vector_;\n  bool is_time_;\n};\n\n// concatenate columns to insert values, e.g:\n// columns = [[\"a\", \"b\", \"c\"], [\"1\", \"2\", \"3\"]]\n// return \"(a,1),(b,2),(c,3)\"\nstd::string ColumnsToValues(\n    const std::vector<std::vector<std::string>>& columns) {\n  YACL_ENFORCE(columns.size() > 0 && columns[0].size() > 0,\n               \"columns can not be empty\");\n  std::vector<std::string> rows;\n  for (size_t i = 0; i < columns[0].size(); ++i) {\n    std::string row = absl::StrCat(\"(\", columns[0][i]);\n    for (size_t j = 1; j < columns.size(); ++j) {\n      absl::StrAppend(&row, \",\", columns[j][i]);\n    }\n    absl::StrAppend(&row, \")\");\n    rows.push_back(std::move(row));\n  }\n  return absl::StrJoin(rows, \",\");\n}\n\n}  // namespace\n\nconst std::string InsertTable::kOpType(\"InsertTable\");\n\nconst std::string& InsertTable::Type() const { return kOpType; }\n\nvoid InsertTable::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n\n  YACL_ENFORCE(inputs.size() > 0, \"inputs can not be empty\");\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   inputs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"input tensors status should be private\");\n}\n\nvoid InsertTable::Execute(ExecContext* ctx) {\n  std::vector<TensorPtr> tensors;\n  std::vector<pb::PrimitiveDataType> input_types;\n  int64_t num_rows = 0;\n  const auto& input_pbs = ctx->GetInput(kIn);\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    const auto& input_pb = input_pbs[i];\n    auto from_tensor = ctx->GetTensorTable()->GetTensor(input_pb.name());\n    YACL_ENFORCE(from_tensor, \"get private tensor={} failed\", input_pb.name());\n    if (i == 0) {\n      num_rows = from_tensor->Length();\n    } else {\n      YACL_ENFORCE_EQ(num_rows, from_tensor->Length(),\n                      \"num rows in tensor#{}: {} not matched previous {}\", i,\n                      from_tensor->Length(), num_rows);\n    }\n\n    tensors.push_back(from_tensor);\n    input_types.push_back(input_pbs[i].elem_type());\n  }\n\n  InsertInTransaction(ctx, tensors, input_types);\n  ctx->GetSession()->SetAffectedRows(num_rows);\n}\n\nvoid InsertTable::InsertInTransaction(\n    ExecContext* ctx, const std::vector<TensorPtr>& tensors,\n    const std::vector<pb::PrimitiveDataType>& input_types) {\n  // 1. connect to db\n  OdbcConnector connector(FLAGS_output_db_kind, FLAGS_output_db_connection_str);\n  auto session = connector.CreateSession();\n  session.begin();\n\n  // 2. insert in batch\n  auto tableName = ctx->GetStringValueFromAttribute(kAttrTableName);\n  auto columnNames =\n      absl::StrJoin(ctx->GetStringValuesFromAttribute(kAttrColumnNames), \",\");\n  try {\n    int64_t offset = 0;\n    while (offset < tensors[0]->Length()) {\n      std::vector<std::vector<std::string>> columns;\n      for (size_t i = 0; i < tensors.size(); ++i) {\n        auto cur_chunk =\n            tensors[i]->ToArrowChunkedArray()->Slice(offset, kBatchSize);\n        auto array = util::ConcatenateChunkedArray(cur_chunk);\n        std::vector<std::string> column;\n        ValueVistor vistor(\n            &column, input_types[i] == pb::PrimitiveDataType::DATETIME ||\n                         input_types[i] == pb::PrimitiveDataType::TIMESTAMP);\n        THROW_IF_ARROW_NOT_OK(arrow::VisitArrayInline(*array, &vistor));\n        columns.push_back(std::move(column));\n      }\n\n      auto values = ColumnsToValues(columns);\n      auto insert_stmt = absl::StrCat(\"INSERT INTO \", tableName, \" (\",\n                                      columnNames, \") VALUES \", values);\n      Poco::Data::Statement stmt(session);\n      stmt << insert_stmt, Poco::Data::Keywords::now;\n      // TODO(jingshi): try bind to prevent SQL injection\n      offset += columns[0].size();\n    }\n\n    session.commit();\n  } catch (const Poco::Data::DataException& e) {\n    session.rollback();\n    std::string err_txt = e.displayText();\n    auto idx = err_txt.find(\"INSERT INTO\");\n    if (idx != std::string::npos) {\n      err_txt = err_txt.substr(0, idx);  // hide statement in error message\n    }\n    YACL_THROW(\"insert catch unexpected Poco::Data::DataException: {}\",\n               err_txt);\n  }\n\n  SPDLOG_INFO(\"inserted {} rows into table {}\", tensors[0]->Length(),\n              tableName);\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/insert_table.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\n#include \"api/core.pb.h\"\n\nnamespace scql::engine::op {\n\nclass InsertTable : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  static constexpr char kAttrTableName[] = \"table_name\";\n  static constexpr char kAttrColumnNames[] = \"column_names\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static void InsertInTransaction(\n      ExecContext* ctx, const std::vector<TensorPtr>& tensors,\n      const std::vector<pb::PrimitiveDataType>& input_types);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/insert_table_mysql_pg_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"Poco/Data/RecordSet.h\"\n#include \"gflags/gflags.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/datasource/odbc_connector.h\"\n#include \"engine/operator/insert_table.h\"\n#include \"engine/operator/test_util.h\"\n\n// clang-format off\n\n// NOTE: 1. you need to prepare table before test insert mysql/pg, like:\n//   CREATE DATABASE IF NOT EXISTS test_db;\n//   DROP TABLE IF EXISTS test_db.test_insert_table;\n//   CREATE TABLE test_db.test_insert_table (c0 integer, c1 timestamp, c2 datetime, c3 varchar(64), c4 double, c5 boolean);\n// 2. specify db_kind and db_connection_str in commond like below: (please replace the '?' to correct value)\n//   bazel-bin/engine/operator/insert_table_mysql_pg_test --output_db_kind=\"mysql\"  --output_db_connection_str=\"db=test_db;user=?;password=?;host=?;port=?;\"\n\n// clang-format on\nnamespace scql::engine::op {\n\nDECLARE_string(output_db_kind);\nDECLARE_string(output_db_connection_str);\n\nstruct InsertMysqlOrPgTestCase {\n  std::vector<test::NamedTensor> inputs;\n  std::vector<pb::PrimitiveDataType> input_types;\n  std::string tableName;\n  std::vector<std::string> columnNames;\n};\n\nclass InsertMysqlOrPgTest\n    : public ::testing::TestWithParam<InsertMysqlOrPgTestCase> {\n protected:\n  static void AssertColumnContentEquals(\n      Poco::Data::RecordSet& rs, const std::string& column_name,\n      const std::vector<Poco::Dynamic::Var>& expected_values) {\n    ASSERT_EQ(rs.rowCount(), expected_values.size())\n        << \"Mismatch in row count for column '\" << column_name << \"'.\";\n\n    for (size_t i = 0; i < rs.rowCount(); ++i) {\n      const auto& actual_value = rs.value(column_name, i);\n      const auto& expected_value = expected_values[i];\n\n      ASSERT_EQ(actual_value.isEmpty(), expected_value.isEmpty())\n          << \"Mismatch in NULL status at row \" << i << \" for column '\"\n          << column_name << \"'.\";\n\n      if (!actual_value.isEmpty()) {\n        ASSERT_EQ(actual_value.convert<std::string>(),\n                  expected_value.convert<std::string>())\n            << \"Mismatch in value at row \" << i << \" for column '\"\n            << column_name << \"'.\";\n      }\n    }\n  }\n  static pb::ExecNode MakeInsertTableExecNode(\n      const InsertMysqlOrPgTestCase& tc);\n\n  static void FeedInputs(ExecContext* ctxs, const InsertMysqlOrPgTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    InsertMysqlOrPgPrivateTest, InsertMysqlOrPgTest,\n    testing::Values(InsertMysqlOrPgTestCase{\n        .inputs =\n            {\n                test::NamedTensor(\"c0\",\n                                  TensorFrom(arrow::int64(), \"[0,1,null,3]\")),\n                test::NamedTensor(\n                    \"c1\",\n                    TensorFrom(arrow::int64(),\n                               \"[1749186000, 1749186000, 1749186000, \"\n                               \"1749186000]\")),  // user inserted \"2025-06-06\n                                                 // 13:00:00\"(timestamp) while\n                                                 // operating in the UTC+8 time\n                                                 // zone\n                test::NamedTensor(\n                    \"c2\",\n                    TensorFrom(arrow::int64(),\n                               \"[1749214800, 1749214800, 1749214800, \"\n                               \"1749214800]\")),  // user inserted \"2025-06-06\n                                                 // 13:00:00\"(datetime) while\n                                                 // operating in the UTC+8 time\n                                                 // zone\n                test::NamedTensor(\"c3\",\n                                  TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"B\",\"A\",\"CCC\",\"B\"])json\")),\n                test::NamedTensor(\n                    \"c4\", TensorFrom(arrow::float32(),\n                                     \"[1.1025, 100.245, -10.2, 3.1415926]\")),\n                test::NamedTensor(\"c5\",\n                                  TensorFrom(arrow::boolean(),\n                                             \"[true, false, null, false]\")),\n            },\n\n        .input_types =\n            {pb::PrimitiveDataType::INT64, pb::PrimitiveDataType::TIMESTAMP,\n             pb::PrimitiveDataType::DATETIME, pb::PrimitiveDataType::STRING,\n             pb::PrimitiveDataType::FLOAT32, pb::PrimitiveDataType::BOOL},\n        .tableName = \"test_insert_table\",\n        .columnNames = {\"c0\", \"c1\", \"c2\", \"c3\", \"c4\", \"c5\"}}));\n\nTEST_P(InsertMysqlOrPgTest, Works) {\n  // Give\n  auto tc = GetParam();\n  auto node = MakeInsertTableExecNode(tc);\n  auto session = test::Make1PCSession();  // execution time zone is UTC+8\n  ExecContext ctx(node, session.get());\n  FeedInputs(&ctx, tc);\n\n  // When\n  InsertTable op;\n  ASSERT_NO_THROW(op.Run(&ctx););\n\n  // Then check output\n  OdbcConnector connector(FLAGS_output_db_kind, FLAGS_output_db_connection_str);\n  auto sess = connector.CreateSession();  // connection time zone is UTC\n  Poco::Data::Statement select(sess);\n  select << \"select * from \" << tc.tableName << \";\", Poco::Data::Keywords::now;\n\n  Poco::Data::RecordSet rs(select);\n  ASSERT_EQ(rs.columnCount(), tc.inputs.size());\n  ASSERT_EQ(rs.rowCount(), tc.inputs[0].tensor->Length());\n\n  // the result of timestamp should change according to the odbc connection time\n  // zone\n  std::vector<Poco::Dynamic::Var> expected_c1 = {\n      \"2025-06-06T05:00:00Z\", \"2025-06-06T05:00:00Z\", \"2025-06-06T05:00:00Z\",\n      \"2025-06-06T05:00:00Z\"};\n  AssertColumnContentEquals(rs, \"c1\", expected_c1);\n  std::vector<Poco::Dynamic::Var> expected_c2 = {\n      \"2025-06-06T13:00:00Z\", \"2025-06-06T13:00:00Z\", \"2025-06-06T13:00:00Z\",\n      \"2025-06-06T13:00:00Z\"};\n  AssertColumnContentEquals(rs, \"c2\", expected_c2);\n}\n\n/// ===========================\n/// InsertMysqlOrPgTest impl\n/// ===========================\n\npb::ExecNode InsertMysqlOrPgTest::MakeInsertTableExecNode(\n    const InsertMysqlOrPgTestCase& tc) {\n  test::ExecNodeBuilder builder(InsertTable::kOpType);\n\n  builder.SetNodeName(\"insert-mysql-pg-test\");\n  builder.AddStringAttr(InsertTable::kAttrTableName, tc.tableName);\n  builder.AddStringsAttr(InsertTable::kAttrColumnNames, tc.columnNames);\n  // Add inputs\n  std::vector<pb::Tensor> input_datas;\n  for (size_t i = 0; i < tc.inputs.size(); ++i) {\n    auto data =\n        test::MakePrivateTensorReference(tc.inputs[i].name, tc.input_types[i]);\n    input_datas.push_back(std::move(data));\n  }\n  builder.AddInput(InsertTable::kIn, input_datas);\n\n  return builder.Build();\n}\n\nvoid InsertMysqlOrPgTest::FeedInputs(ExecContext* ctx,\n                                     const InsertMysqlOrPgTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, tc.inputs);\n}\n\n}  // namespace scql::engine::op\n\nint main(int argc, char* argv[]) {\n  ::testing::InitGoogleTest(&argc, argv);\n\n  gflags::ParseCommandLineFlags(&argc, &argv, true);\n  return RUN_ALL_TESTS();\n}\n"
  },
  {
    "path": "engine/operator/insert_table_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/insert_table.h\"\n\n#include \"Poco/Data/SQLite/Connector.h\"\n#include \"Poco/Data/Session.h\"\n#include \"absl/strings/str_format.h\"\n#include \"gflags/gflags.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nDECLARE_string(output_db_kind);\nDECLARE_string(output_db_connection_str);\n\nstruct InsertTableTestCase {\n  std::vector<test::NamedTensor> inputs;\n  std::vector<pb::PrimitiveDataType> input_types;\n  std::string tableName;\n  std::vector<std::string> columnNames;\n};\n\nclass InsertTableTest : public ::testing::TestWithParam<InsertTableTestCase> {\n protected:\n  void SetUp() override {\n    Poco::Data::SQLite::Connector::registerConnector();\n    session_ =\n        std::make_unique<Poco::Data::Session>(\"SQLite\", db_connection_str_);\n  }\n  static pb::ExecNode MakeInsertTableExecNode(const InsertTableTestCase& tc);\n\n  static void FeedInputs(ExecContext* ctxs, const InsertTableTestCase& tc);\n  void CreateTable(const InsertTableTestCase& tc);\n\n  std::string db_connection_str_ =\n      \"file:obdc_adaptor_test?mode=memory&cache=shared\";\n  std::unique_ptr<Poco::Data::Session> session_;\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    InsertTablePrivateTest, InsertTableTest,\n    testing::Values(InsertTableTestCase{\n        .inputs =\n            {test::NamedTensor(\"c0\",\n                               TensorFrom(arrow::int64(), \"[0,1,null,3]\")),\n             test::NamedTensor(\"c1\",\n                               TensorFrom(arrow::int64(), \"[0,10,null,1000]\")),\n             test::NamedTensor(\"c2\",\n                               TensorFrom(arrow::int64(), \"[0,10,null,1000]\")),\n             test::NamedTensor(\"c3\",\n                               TensorFrom(arrow::large_utf8(),\n                                          R\"json([\"B\",\"A\",\"CCC\",\"B\"])json\")),\n             test::NamedTensor(\n                 \"c4\", TensorFrom(arrow::float32(),\n                                  \"[1.1025, 100.245, -10.2, 3.1415926]\")),\n             test::NamedTensor(\"c5\", TensorFrom(arrow::boolean(),\n                                                \"[true, false, null, false]\"))},\n        .input_types =\n            {pb::PrimitiveDataType::INT64, pb::PrimitiveDataType::TIMESTAMP,\n             pb::PrimitiveDataType::DATETIME, pb::PrimitiveDataType::STRING,\n             pb::PrimitiveDataType::FLOAT32, pb::PrimitiveDataType::BOOL},\n        .tableName = \"test_table\",\n        .columnNames = {\"c0\", \"c1\", \"c2\", \"c3\", \"c4\", \"c5\"}}));\n\nTEST_P(InsertTableTest, Works) {\n  // Give\n  auto tc = GetParam();\n  CreateTable(tc);\n  auto node = MakeInsertTableExecNode(tc);\n  auto session = test::Make1PCSession();\n  ExecContext ctx(node, session.get());\n  FeedInputs(&ctx, tc);\n  FLAGS_output_db_kind = \"sqlite\";\n  FLAGS_output_db_connection_str = db_connection_str_;\n\n  // When\n  InsertTable op;\n  ASSERT_NO_THROW(op.Run(&ctx););\n\n  // Then check output\n  Poco::Data::Statement select(*session_);\n  select << \"select * from \" << tc.tableName << \";\", Poco::Data::Keywords::now;\n  EXPECT_EQ(select.columnsExtracted(), tc.inputs.size());\n  EXPECT_EQ(select.rowsExtracted(), tc.inputs[0].tensor->Length());\n}\n\n/// ===========================\n/// InsertTableTest impl\n/// ===========================\n\npb::ExecNode InsertTableTest::MakeInsertTableExecNode(\n    const InsertTableTestCase& tc) {\n  test::ExecNodeBuilder builder(InsertTable::kOpType);\n\n  builder.SetNodeName(\"InsertTable-test\");\n  builder.AddStringAttr(InsertTable::kAttrTableName, tc.tableName);\n  builder.AddStringsAttr(InsertTable::kAttrColumnNames, tc.columnNames);\n  // Add inputs\n  std::vector<pb::Tensor> input_datas;\n  for (size_t i = 0; i < tc.inputs.size(); ++i) {\n    auto data =\n        test::MakePrivateTensorReference(tc.inputs[i].name, tc.input_types[i]);\n    input_datas.push_back(std::move(data));\n  }\n  builder.AddInput(InsertTable::kIn, input_datas);\n\n  return builder.Build();\n}\n\nvoid InsertTableTest::FeedInputs(ExecContext* ctx,\n                                 const InsertTableTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, tc.inputs);\n}\n\nvoid InsertTableTest::CreateTable(const InsertTableTestCase& tc) {\n  if (tc.inputs.size() == 0) {\n    return;\n  }\n\n  auto sqlite_type = [](pb::PrimitiveDataType type) {\n    switch (type) {\n      case pb::PrimitiveDataType::BOOL:\n        return \"BOOLEAN\";\n      case pb::PrimitiveDataType::INT32:\n      case pb::PrimitiveDataType::INT64:\n      case pb::PrimitiveDataType::TIMESTAMP:\n        return \"INTEGER\";\n      case pb::PrimitiveDataType::FLOAT32:\n      case pb::PrimitiveDataType::FLOAT64:\n        return \"REAL\";\n      case pb::PrimitiveDataType::STRING:\n      case pb::PrimitiveDataType::DATETIME:\n        return \"TEXT\";\n      default:\n        YACL_THROW(\"unsupported type {}\", pb::PrimitiveDataType_Name(type));\n    }\n  };\n\n  std::string stmt =\n      absl::StrFormat(\"CREATE TABLE %s (%s %s\", tc.tableName, tc.inputs[0].name,\n                      sqlite_type(tc.inputs[0].tensor->Type()));\n  for (size_t i = 1; i < tc.inputs.size(); ++i) {\n    absl::StrAppend(&stmt,\n                    absl::StrFormat(\", %s %s\", tc.inputs[i].name,\n                                    sqlite_type(tc.inputs[i].tensor->Type())));\n  }\n  absl::StrAppend(&stmt, \")\");\n  SPDLOG_INFO(\"create table sql: {}\", stmt);\n\n  *session_ << stmt, Poco::Data::Keywords::now;\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/is_null.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/is_null.h\"\n\n#include \"arrow/compute/api.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string IsNull::kOpType(\"IsNull\");\n\nconst std::string& IsNull::Type() const { return kOpType; }\n\nvoid IsNull::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() == 1, \"IsNull input size={} not equal to 1\",\n               inputs.size());\n  YACL_ENFORCE(outputs.size() == 1, \"IsNull output size={} not equal to 1\",\n               outputs.size());\n\n  YACL_ENFORCE(util::IsTensorStatusMatched(\n                   inputs[0], pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"IsNull input tensor's status should be private\");\n  YACL_ENFORCE(util::IsTensorStatusMatched(\n                   outputs[0], pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"IsNull output tensor's status should be private\");\n}\n\nvoid IsNull::Execute(ExecContext* ctx) {\n  auto tensor = ctx->GetInputTensor(kIn);\n\n  arrow::compute::NullOptions options;\n  auto result = arrow::compute::IsNull(tensor->ToArrowChunkedArray(), options);\n  YACL_ENFORCE(result.ok(), \"caught error while invoking arrow IsNull: {}\",\n               result.status().ToString());\n\n  ctx->SetOutputTensor(kOut, TensorFrom(result.ValueOrDie().chunked_array()));\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/is_null.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass IsNull : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/is_null_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/is_null.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct IsNullTestCase {\n  test::NamedTensor input;\n  test::NamedTensor expect_out;\n};\n\nclass IsNullTest : public testing::TestWithParam<\n                       std::tuple<test::SpuRuntimeTestCase, IsNullTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const IsNullTestCase& tc);\n  static void FeedInputs(ExecContext* ctx, const IsNullTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    IsNullBatchTest, IsNullTest,\n    testing::Combine(\n        testing::Values(test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2}),\n        testing::Values(\n            // test private status\n            IsNullTestCase{\n                .input = test::NamedTensor(\n                    \"in\", TensorFrom(arrow::int64(), \"[null, 2, 3, null]\")),\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::boolean(),\n                                      \"[true, false, false, true]\"))},\n            IsNullTestCase{\n                .input = test::NamedTensor(\n                    \"in\",\n                    TensorFrom(arrow::float64(), \"[null, -0.1, 1.1, null]\")),\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::boolean(),\n                                      \"[true, false, false, true]\"))},\n            IsNullTestCase{\n                .input = test::NamedTensor(\n                    \"in\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"B\", null, null ,\"B\"])json\")),\n                .expect_out = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::boolean(),\n                                      \"[false, true, true, false]\"))},\n            IsNullTestCase{.input = test::NamedTensor(\n                               \"in\", TensorFrom(arrow::float64(), \"[]\")),\n                           .expect_out = test::NamedTensor(\n                               \"out\", TensorFrom(arrow::boolean(), \"[]\"))})),\n    TestParamNameGenerator(IsNullTest));\n\nTEST_P(IsNullTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto session = test::Make1PCSession();\n  ExecContext ctx(node, session.get());\n\n  FeedInputs(&ctx, tc);\n\n  // When\n  IsNull op;\n  ASSERT_NO_THROW(op.Run(&ctx));\n\n  // Then\n  // check alice output\n  TensorPtr t = session->GetTensorTable()->GetTensor(tc.expect_out.name);\n  ASSERT_TRUE(t);\n  auto out_arr = t->ToArrowChunkedArray();\n\n  auto expect_arr = tc.expect_out.tensor->ToArrowChunkedArray();\n\n  // compare tensor content\n  EXPECT_TRUE(out_arr->Equals(expect_arr))\n      << \"expect type = \" << expect_arr->type()->ToString()\n      << \", got type = \" << out_arr->type()->ToString()\n      << \"\\nexpect result = \" << expect_arr->ToString()\n      << \"\\nbut actual got result = \" << out_arr->ToString();\n}\n\n/// ===================\n/// IsNullTest impl\n/// ===================\n\npb::ExecNode IsNullTest::MakeExecNode(const IsNullTestCase& tc) {\n  test::ExecNodeBuilder builder(IsNull::kOpType);\n  builder.SetNodeName(\"is-null-test\");\n\n  {\n    auto t = test::MakePrivateTensorReference(tc.input.name,\n                                              tc.input.tensor->Type());\n    builder.AddInput(IsNull::kIn, {t});\n  }\n\n  {\n    auto t = test::MakePrivateTensorReference(tc.expect_out.name,\n                                              tc.expect_out.tensor->Type());\n    builder.AddOutput(IsNull::kOut, {t});\n  }\n\n  return builder.Build();\n}\n\nvoid IsNullTest::FeedInputs(ExecContext* ctx, const IsNullTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, {tc.input});\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/join.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/join.h\"\n\n#include <sys/types.h>\n\n#include <cstddef>\n#include <cstdint>\n#include <future>\n#include <memory>\n#include <optional>\n#include <string>\n#include <tuple>\n#include <unordered_set>\n#include <vector>\n\n#include \"butil/files/scoped_temp_dir.h\"\n#include \"msgpack.hpp\"\n#include \"psi/algorithm/ecdh/ecdh_psi.h\"\n#include \"psi/algorithm/ecdh/ub_psi/ecdh_oprf_psi.h\"\n#include \"psi/algorithm/rr22/common.h\"\n#include \"psi/algorithm/rr22/rr22_psi.h\"\n#include \"psi/cryptor/cryptor_selector.h\"\n#include \"yacl/crypto/rand/rand.h\"\n\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/core/tensor_slice.h\"\n#include \"engine/exe/flags.h\"\n#include \"engine/framework/exec.h\"\n#include \"engine/util/communicate_helper.h\"\n#include \"engine/util/filepath_helper.h\"\n#include \"engine/util/psi/batch_provider.h\"\n#include \"engine/util/tensor_util.h\"\n\nDECLARE_int64(provider_batch_size);\n\nnamespace scql::engine::op {\n\nconst std::string Join::kOpType(\"Join\");\n\nconst std::string& Join::Type() const { return kOpType; }\n\nvoid Join::Validate(ExecContext* ctx) {\n  ValidateJoinTypeAndAlgo(ctx);\n  // Currently, only support psi join algorithm.\n  ValidatePsiTensors(ctx);\n\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  YACL_ENFORCE(input_party_codes.size() == 2,\n               \"Join operator attribute {} must have exactly 2 elements\",\n               kInputPartyCodesAttr);\n}\n\nvoid Join::Execute(ExecContext* ctx) {\n  auto logger = ctx->GetActiveLogger();\n\n  int64_t algorithm = ctx->GetInt64ValueFromAttribute(kAlgorithmAttr);\n  switch (algorithm) {\n    case static_cast<int64_t>(util::PsiAlgo::kOprfPsi): {\n      SPDLOG_LOGGER_INFO(logger, \"use OprfPsi for join according to attribute\");\n      auto server_hint = ctx->TryGetInt64ValueFromAttribute(kUbPsiServerHint);\n      if (server_hint.has_value()) {\n        SPDLOG_LOGGER_INFO(logger, \"OprfPsi: use server hint\");\n        return OprfPsiJoin(ctx,\n                           IsOprfServerAccordToHint(ctx, server_hint.value()));\n      }\n      auto psi_plan = util::CoordinatePsiPlan(ctx);\n      return OprfPsiJoin(ctx, psi_plan.is_server, psi_plan.psi_size_info);\n    }\n    case static_cast<int64_t>(util::PsiAlgo::kEcdhPsi):\n      SPDLOG_LOGGER_INFO(logger, \"use EcdhPsi for join according to attribute\");\n      return Join::EcdhPsiJoin(ctx);\n    // use rr22 as default\n    case static_cast<int64_t>(util::PsiAlgo::kAutoPsi):\n      SPDLOG_LOGGER_INFO(logger, \"use Rr22Psi as default psi type\");\n      return Rr22PsiJoin(ctx);\n    case static_cast<int64_t>(util::PsiAlgo::kRr22Psi):\n      SPDLOG_LOGGER_INFO(logger, \"use Rr22Psi for join according to attribute\");\n      return Rr22PsiJoin(ctx);\n    default:\n      YACL_THROW(\"unsupported in algorithm id: {}\", algorithm);\n  }\n}\n\nvoid Join::ValidateJoinTypeAndAlgo(ExecContext* ctx) {\n  int64_t join_type = ctx->GetInt64ValueFromAttribute(kJoinTypeAttr);\n  static std::unordered_set<int64_t> supported_types{\n      static_cast<int64_t>(JoinType::kInnerJoin),\n      static_cast<int64_t>(JoinType::kLeftJoin),\n      static_cast<int64_t>(JoinType::kRightJoin)};\n  YACL_ENFORCE(supported_types.count(join_type) > 0, \"Invalid join type: {}\",\n               join_type);\n  int64_t algorithm = ctx->GetInt64ValueFromAttribute(kAlgorithmAttr);\n  static std::unordered_set<int64_t> supported_algorithms{\n      static_cast<int64_t>(util::PsiAlgo::kAutoPsi),\n      static_cast<int64_t>(util::PsiAlgo::kEcdhPsi),\n      static_cast<int64_t>(util::PsiAlgo::kOprfPsi),\n      static_cast<int64_t>(util::PsiAlgo::kRr22Psi)};\n  YACL_ENFORCE(supported_algorithms.count(algorithm) > 0,\n               \"Invalid join algorithm: {}\", algorithm);\n}\n\nvoid Join::ValidatePsiTensors(ExecContext* ctx) {\n  const auto& left = ctx->GetInput(kInLeft);\n  const auto& right = ctx->GetInput(kInRight);\n  const auto& left_out = ctx->GetOutput(kOutLeftJoinIndex);\n  const auto& right_out = ctx->GetOutput(kOutRightJoinIndex);\n  YACL_ENFORCE(left.size() >= 1 && right.size() == left.size(),\n               \"Join operator inputs Left and Right should be the same and \"\n               \"larger than 1, but got size(Left)={}, size(Right)={}\",\n               left.size(), right.size());\n  YACL_ENFORCE(util::AreTensorsStatusMatched(left, pb::TENSORSTATUS_PRIVATE),\n               \"Join operator with psi-join algorithm input Left status should \"\n               \"be private\");\n  YACL_ENFORCE(\n      util::AreTensorsStatusMatched(right, pb::TENSORSTATUS_PRIVATE),\n      \"Join operator with psi-join algorithm input Right status should \"\n      \"be private\");\n  YACL_ENFORCE(\n      util::AreTensorsStatusMatched(left_out, pb::TENSORSTATUS_PRIVATE),\n      \"Join operator with psi-join algorithm output Left status should \"\n      \"be private\");\n  YACL_ENFORCE(\n      util::AreTensorsStatusMatched(right_out, pb::TENSORSTATUS_PRIVATE),\n      \"Join operator with psi-join algorithm output Right status should \"\n      \"be private\");\n}\n\nbool Join::IsOprfServerAccordToHint(ExecContext* ctx, int64_t server_hint) {\n  YACL_ENFORCE(server_hint >= 0 && server_hint <= 1, \"invalid server hint: {}\",\n               server_hint);\n\n  const auto& my_party_code = ctx->GetSession()->SelfPartyCode();\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  bool is_left = my_party_code == input_party_codes.at(0);\n\n  return (is_left && server_hint == 0) || (!is_left && server_hint == 1);\n}\n\nsize_t Join::GetTargetRank(ExecContext* ctx,\n                           const std::shared_ptr<yacl::link::Context>& lctx) {\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  const auto& my_party_code = ctx->GetSession()->SelfPartyCode();\n  bool is_left = my_party_code == input_party_codes.at(0);\n  if (ctx->GetOutput(kOutLeftJoinIndex).size() == 0 ||\n      ctx->GetOutput(kOutRightJoinIndex).size() == 0) {\n    if ((ctx->GetOutput(kOutLeftJoinIndex).size() != 0 && is_left) ||\n        (ctx->GetOutput(kOutRightJoinIndex).size() != 0 && !is_left)) {\n      return lctx->Rank();\n    } else {\n      return lctx->NextRank();\n    }\n  }\n  return yacl::link::kAllRank;\n}\n\nbool TouchResult(const std::shared_ptr<yacl::link::Context>& lctx,\n                 size_t target_rank) {\n  return target_rank == yacl::link::kAllRank || lctx->Rank() == target_rank;\n}\n\nstd::shared_ptr<BucketTensorConstructor> CreateBucketTensorConstructor(\n    ExecContext* ctx, bool touch_result, bool is_bucket_tensor,\n    const std::string& output_name, size_t bucket_num) {\n  if (!touch_result) {\n    return nullptr;\n  }\n  const auto& output_pb = ctx->GetOutput(output_name)[0];\n  if (is_bucket_tensor) {\n    auto streaming_options = ctx->GetSession()->GetStreamingOptions();\n    std::filesystem::path out_dir = util::CreateDirWithRandSuffix(\n        streaming_options.dump_file_dir, output_pb.name());\n    return std::make_shared<DiskBucketTensorConstructor>(\n        output_pb.name(), arrow::uint64(), output_pb.elem_type(), out_dir,\n        bucket_num);\n  } else {\n    return std::make_shared<MemoryBucketTensorConstructor>(bucket_num);\n  }\n}\n\nvoid Join::EcdhPsiJoin(ExecContext* ctx) {\n  auto logger = ctx->GetActiveLogger();\n\n  const auto& my_party_code = ctx->GetSession()->SelfPartyCode();\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  bool is_left = my_party_code == input_party_codes.at(0);\n  auto join_keys = GetJoinKeys(ctx, is_left);\n  if (ctx->GetSession()->GetPsiLogger()) {\n    ctx->GetSession()->GetPsiLogger()->LogInput(join_keys);\n  }\n  std::vector<std::shared_ptr<TensorSlice>> slices(join_keys.size());\n  for (size_t i = 0; i < join_keys.size(); ++i) {\n    slices[i] = CreateTensorSlice(join_keys[i]);\n  }\n  std::string output_name = kOutLeftJoinIndex;\n  if (!is_left) {\n    output_name = kOutRightJoinIndex;\n  }\n  size_t total_self_size = 0;\n  size_t total_peer_size = 0;\n  auto psi_link = ctx->GetSession()->GetLink();\n  if (psi_link->WorldSize() > 2) {\n    psi_link = psi_link->SubWorld(ctx->GetNodeName() + \"-EcdhPsiJoin\",\n                                  input_party_codes);\n  }\n  size_t target_rank = GetTargetRank(ctx, psi_link);\n  bool touch_result = TouchResult(psi_link, target_rank);\n  bool is_bucket_tensor = util::AreAllBucketTensor(join_keys);\n  std::shared_ptr<BucketTensorConstructor> tensor_constructor =\n      CreateBucketTensorConstructor(ctx, touch_result, is_bucket_tensor,\n                                    output_name, slices[0]->GetSliceNum());\n  for (size_t i = 0; i < slices[0]->GetSliceNum(); ++i) {\n    std::vector<TensorPtr> keys(join_keys.size());\n    for (size_t j = 0; j < slices.size(); ++j) {\n      keys[j] = slices[j]->GetSlice(i);\n    }\n    auto batch_provider =\n        std::make_shared<util::BatchProvider>(keys, FLAGS_provider_batch_size);\n    // NOTE(shunde.csd): There are some possible ways to optimize the\n    // performance of compute join indices.\n    //   1. Try to adjust bins number based on the both input sizes and memory\n    // amounts.\n    //   2. Try to use pure memory store when the input size is small.\n    // TODO: modify num of bins by data num\n    auto self_store =\n        std::make_shared<psi::HashBucketEcPointStore>(\"/tmp\", util::kNumBins);\n    auto peer_store =\n        std::make_shared<psi::HashBucketEcPointStore>(\"/tmp\", util::kNumBins);\n    {\n      psi::ecdh::EcdhPsiOptions options;\n      options.link_ctx = psi_link;\n      options.ecc_cryptor = psi::CreateEccCryptor(static_cast<psi::CurveType>(\n          ctx->GetSession()->GetSessionOptions().psi_config.psi_curve_type));\n      options.target_rank = target_rank;\n      if (join_keys.size() > 0) {\n        options.on_batch_finished = util::BatchFinishedCb(\n            logger, ctx->GetSession()->Id(),\n            (join_keys[0]->Length() + options.batch_size - 1) /\n                options.batch_size);\n      }\n      if (ctx->GetSession()->GetPsiLogger()) {\n        options.ecdh_logger =\n            ctx->GetSession()->GetPsiLogger()->GetEcdhLogger();\n      }\n      psi::ecdh::RunEcdhPsi(options, batch_provider, self_store, peer_store);\n    }\n    if (touch_result) {\n      YACL_ENFORCE(tensor_constructor != nullptr);\n      int64_t join_type = ctx->GetInt64ValueFromAttribute(kJoinTypeAttr);\n      auto join_indices = util::FinalizeAndComputeJoinIndices(\n          is_left, self_store, peer_store, join_type);\n      tensor_constructor->InsertBucket(join_indices, i);\n    }\n    total_self_size += self_store->ItemCount();\n    // TODO(FIXME): @xiaoyuan fix peer size if self doesn't touch result\n    total_peer_size += peer_store->ItemCount();\n  }\n  if (touch_result) {\n    YACL_ENFORCE(tensor_constructor != nullptr);\n    TensorPtr join_indices;\n    tensor_constructor->Finish(&join_indices);\n    auto result_size = join_indices->Length();\n    SPDLOG_LOGGER_INFO(\n        logger,\n        \"ECDH PSI Join finish, my_party_code:{}, my_rank:{}, total \"\n        \"self_item_count:{}, total peer_item_count:{}, result_size:{}\",\n        ctx->GetSession()->SelfPartyCode(), ctx->GetSession()->SelfRank(),\n        total_self_size, total_peer_size, result_size);\n    if (ctx->GetSession()->GetPsiLogger()) {\n      ctx->GetSession()->GetPsiLogger()->LogOutput(join_indices, join_keys);\n    }\n    SetJoinResult(ctx, is_left, std::move(join_indices));\n  } else {\n    SPDLOG_LOGGER_INFO(\n        logger,\n        \"ECDH PSI Join finish, my_party_code:{}, my_rank:{}, total \"\n        \"self_item_count:{}, total peer_item_count:{}, self doesn't touch \"\n        \"result\",\n        ctx->GetSession()->SelfPartyCode(), ctx->GetSession()->SelfRank(),\n        total_self_size, total_peer_size);\n  }\n}\n\nvoid Join::Rr22PsiJoin(ExecContext* ctx) {\n  auto logger = ctx->GetActiveLogger();\n  const auto& my_party_code = ctx->GetSession()->SelfPartyCode();\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n\n  bool is_left = my_party_code == input_party_codes.at(0);\n  auto join_keys = GetJoinKeys(ctx, is_left);\n  if (ctx->GetSession()->GetPsiLogger()) {\n    ctx->GetSession()->GetPsiLogger()->LogInput(join_keys);\n  }\n  auto psi_link = ctx->GetSession()->GetLink();\n  if (psi_link->WorldSize() > 2) {\n    psi_link = psi_link->SubWorld(ctx->GetNodeName() + \"-Rr22PsiJoin\",\n                                  input_party_codes);\n  }\n  auto target_rank = GetTargetRank(ctx, psi_link);\n  bool touch_result = TouchResult(psi_link, target_rank);\n  std::string output_name = kOutLeftJoinIndex;\n  if (!is_left) {\n    output_name = kOutRightJoinIndex;\n  }\n  auto self_size = static_cast<size_t>(join_keys[0]->Length());\n  auto provider = util::BucketProvider(join_keys);\n  auto peer_size = util::ExchangeSetSize(psi_link, self_size);\n  provider.InitBucket(psi_link, self_size, peer_size);\n  auto bucket_num = provider.GetBucketNum();\n  std::vector<TensorPtr> result_ts(bucket_num);\n  int64_t join_type = ctx->GetInt64ValueFromAttribute(kJoinTypeAttr);\n  std::shared_ptr<BucketTensorConstructor> tensor_constructor =\n      CreateBucketTensorConstructor(ctx, touch_result,\n                                    provider.IsBucketTensor(), output_name,\n                                    bucket_num);\n  psi::rr22::PreProcessFunc pre_f =\n      [&](size_t idx) -> std::vector<psi::HashBucketCache::BucketItem> {\n    YACL_ENFORCE(idx < bucket_num);\n    return provider.GetDeDupItemsInBucket(idx);\n  };\n  psi::rr22::PostProcessFunc post_f =\n      [&](size_t bucket_idx,\n          const std::vector<psi::HashBucketCache::BucketItem>& bucket_items,\n          const std::vector<uint32_t>& indices,\n          const std::vector<uint32_t>& peer_cnt) {\n        if (touch_result) {\n          YACL_ENFORCE(tensor_constructor != nullptr);\n          auto indices_t = provider.CalIntersection(\n              psi_link->Spawn(std::to_string(bucket_idx)), bucket_idx, is_left,\n              join_type, bucket_items, indices, peer_cnt);\n          tensor_constructor->InsertBucket(indices_t, bucket_idx);\n        }\n        provider.CleanBucket(bucket_idx);\n      };\n  psi::rr22::Rr22Runner runner(\n      psi_link,\n      psi::rr22::GenerateRr22PsiOptions(\n          ctx->GetSession()->GetSessionOptions().psi_config.rr22_mode ==\n          pb::LOW_MODE),\n      bucket_num, target_rank == yacl::link::kAllRank, pre_f, post_f);\n  bool is_sender = is_left;\n  // receiver should be the one who has more data\n  // It is more efficient to set the party with the larger data volume as the\n  // receiver.\n  if (target_rank != yacl::link::kAllRank) {\n    // receiver get result\n    is_sender = !touch_result;\n  } else if (peer_size > self_size) {\n    is_sender = true;\n  } else if (self_size > peer_size) {\n    is_sender = false;\n  }\n  runner.ParallelRun(0, is_sender);\n  size_t result_size = 0;\n  if (touch_result) {\n    YACL_ENFORCE(tensor_constructor != nullptr);\n    TensorPtr join_indices;\n    tensor_constructor->Finish(&join_indices);\n    result_size = join_indices->Length();\n    SPDLOG_LOGGER_INFO(\n        logger,\n        \"RR22 PSI Join finish, my_party_code:{}, my_rank:{}, total \"\n        \"self_item_count:{}, total peer_item_count:{}, result_size:{}\",\n        ctx->GetSession()->SelfPartyCode(), ctx->GetSession()->SelfRank(),\n        self_size, peer_size, result_size);\n    SetJoinResult(ctx, is_left, std::move(join_indices));\n  } else {\n    SPDLOG_LOGGER_INFO(\n        logger,\n        \"RR22 PSI Join finish, my_party_code:{}, my_rank:{}, total \"\n        \"self_item_count:{}, total peer_item_count:{}, self doesn't touch \"\n        \"result\",\n        ctx->GetSession()->SelfPartyCode(), ctx->GetSession()->SelfRank(),\n        self_size, peer_size);\n  }\n}\n\nvoid Join::OprfPsiJoin(ExecContext* ctx, bool is_server,\n                       std::optional<util::PsiSizeInfo> psi_size_info) {\n  auto logger = ctx->GetActiveLogger();\n  util::PsiExecutionInfoTable psi_info_table;\n  psi_info_table.start_time = std::chrono::system_clock::now();\n  if (psi_size_info.has_value()) {\n    psi_info_table.self_size = psi_size_info->self_size;\n    psi_info_table.peer_size = psi_size_info->peer_size;\n  } else {\n    psi_info_table.self_size = 0;\n    psi_info_table.peer_size = 0;\n  }\n\n  // get related party codes and ranks\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  const auto& my_party_code = ctx->GetSession()->SelfPartyCode();\n  bool is_left = my_party_code == input_party_codes.at(0);\n  const auto& peer_party_code = input_party_codes.at(is_left ? 1 : 0);\n  auto my_rank = ctx->GetSession()->GetPartyRank(my_party_code);\n  YACL_ENFORCE(my_rank != -1, \"unknown rank for party={}\", my_party_code);\n  auto peer_rank = ctx->GetSession()->GetPartyRank(peer_party_code);\n  YACL_ENFORCE(peer_rank != -1, \"unknown rank for party={}\", peer_party_code);\n\n  // prepare input\n  auto join_keys = GetJoinKeys(ctx, is_left);\n\n  // set EcdhOprfPsiOptions\n  psi::ecdh::EcdhOprfPsiOptions psi_options;\n  auto psi_link = ctx->GetSession()->GetLink();\n  if (psi_link->WorldSize() > 2) {\n    psi_link = psi_link->SubWorld(ctx->GetNodeName() + \"-OprfPsiJoin\",\n                                  input_party_codes);\n  }\n  psi_options.cache_transfer_link = psi_link;\n  YACL_ENFORCE(psi_options.cache_transfer_link,\n               \"fail to create cache_transfer_link for OprfPsiJoin\");\n  psi_options.online_link = psi_options.cache_transfer_link->Spawn();\n  YACL_ENFORCE(psi_options.online_link,\n               \"fail to create online_link for OprfPsiJoin\");\n\n  psi_options.curve_type = static_cast<psi::CurveType>(\n      ctx->GetSession()->GetSessionOptions().psi_config.psi_curve_type);\n\n  int64_t join_type = ctx->GetInt64ValueFromAttribute(kJoinTypeAttr);\n  JoinRole join_role = GetJoinRole(join_type, is_left);\n  std::vector<std::shared_ptr<TensorSlice>> slices(join_keys.size());\n  for (size_t i = 0; i < join_keys.size(); ++i) {\n    slices[i] = CreateTensorSlice(join_keys[i]);\n  }\n  std::string output_name = kOutLeftJoinIndex;\n  if (!is_left) {\n    output_name = kOutRightJoinIndex;\n  }\n  bool is_bucket_tensor = util::AreAllBucketTensor(join_keys);\n  // ub psi always touch result\n  bool touch_result = true;\n  std::shared_ptr<BucketTensorConstructor> tensor_constructor =\n      CreateBucketTensorConstructor(ctx, touch_result, is_bucket_tensor,\n                                    output_name, slices[0]->GetSliceNum());\n  for (size_t i = 0; i < slices[0]->GetSliceNum(); ++i) {\n    std::vector<TensorPtr> keys(join_keys.size());\n    for (size_t j = 0; j < slices.size(); ++j) {\n      keys[j] = slices[j]->GetSlice(i);\n    }\n    // create temp dir\n    butil::ScopedTempDir tmp_dir;\n    YACL_ENFORCE(tmp_dir.CreateUniqueTempDir(), \"fail to create temp dir\");\n    auto batch_provider =\n        std::make_shared<util::BatchProvider>(keys, FLAGS_provider_batch_size);\n    TensorPtr indices;\n    if (is_server) {\n      indices = OprfPsiServer(ctx, join_role, tmp_dir.path().value(),\n                              psi_options, batch_provider, is_left, peer_rank,\n                              &psi_info_table, psi_link);\n    } else {\n      indices = OprfPsiClient(ctx, join_role, tmp_dir.path().value(),\n                              psi_options, batch_provider, is_left, peer_rank,\n                              &psi_info_table, psi_link);\n    }\n    tensor_constructor->InsertBucket(indices, i);\n  }\n  TensorPtr join_indices;\n  tensor_constructor->Finish(&join_indices);\n  SetJoinResult(ctx, is_left, join_indices);\n  psi_info_table.result_size = join_indices->Length();\n  SPDLOG_LOGGER_INFO(\n      logger,\n      \"OPRF PSI Join finish, my_party_code:{}, my_rank:{}, total \"\n      \"self_item_count:{}, total peer_item_count:{}, result size:{}\",\n      ctx->GetSession()->SelfPartyCode(), ctx->GetSession()->SelfRank(),\n      psi_info_table.self_size, psi_info_table.peer_size,\n      psi_info_table.result_size);\n}\n\nstd::vector<TensorPtr> Join::GetJoinKeys(ExecContext* ctx, bool is_left) {\n  std::string input_name = kInLeft;\n  if (!is_left) {\n    input_name = kInRight;\n  }\n\n  std::vector<TensorPtr> result;\n  auto* table = ctx->GetTensorTable();\n  const auto& input_pbs = ctx->GetInput(input_name);\n  for (const auto& input_pb : input_pbs) {\n    auto t = table->GetTensor(input_pb.name());\n    YACL_ENFORCE(t != nullptr, \"tensor not found in tensor table\",\n                 input_pb.name());\n    result.push_back(std::move(t));\n  }\n  return result;\n}\n\nvoid Join::SetJoinResult(ExecContext* ctx, bool is_left,\n                         TensorPtr result_tensor) {\n  std::string output_name = kOutLeftJoinIndex;\n  if (!is_left) {\n    output_name = kOutRightJoinIndex;\n  }\n  const auto& output_pb = ctx->GetOutput(output_name)[0];\n\n  ctx->GetTensorTable()->AddTensor(output_pb.name(), std::move(result_tensor));\n}\n\nauto Join::GetJoinRole(int64_t join_type, bool is_left) -> JoinRole {\n  if ((join_type == static_cast<int64_t>(JoinType::kLeftJoin) && is_left) ||\n      (join_type == static_cast<int64_t>(JoinType::kRightJoin) && !is_left)) {\n    return JoinRole::kLeftOrRightJoinFullParty;\n  }\n  if ((join_type == static_cast<int64_t>(JoinType::kLeftJoin) && !is_left) ||\n      (join_type == static_cast<int64_t>(JoinType::kRightJoin) && is_left)) {\n    return JoinRole::kLeftOrRightJoinNullParty;\n  }\n  if (join_type == static_cast<int64_t>(JoinType::kInnerJoin)) {\n    return JoinRole::kInnerJoinParty;\n  }\n  return JoinRole::kInValid;\n}\n\nTensorPtr Join::OprfPsiServer(\n    ExecContext* ctx, JoinRole join_role, const std::string& tmp_dir,\n    const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n    const std::shared_ptr<util::BatchProvider>& batch_provider, bool is_left,\n    int64_t peer_rank, util::PsiExecutionInfoTable* psi_info_table,\n    std::shared_ptr<yacl::link::Context> psi_link) {\n  std::vector<uint8_t> private_key =\n      yacl::crypto::SecureRandBytes(psi::kEccKeySize);\n  auto ec_oprf_psi_server =\n      std::make_shared<psi::ecdh::EcdhOprfPsiServer>(psi_options, private_key);\n  YACL_ENFORCE(ec_oprf_psi_server, \"Fail to create EcdhOprfPsiServer\");\n  auto ub_cache =\n      std::make_shared<util::UbPsiJoinCache>(batch_provider->TotalLength());\n\n  auto transfer_server_items_future =\n      std::async(std::launch::async, util::OprfPsiServerTransferServerItems,\n                 ctx, psi_link, batch_provider, ec_oprf_psi_server, ub_cache);\n  util::OprfPsiServerTransferClientItems(ctx, ec_oprf_psi_server);\n  transfer_server_items_future.get();\n\n  uint64_t client_unmatched_count = 0;\n  if (join_role == JoinRole::kLeftOrRightJoinNullParty) {\n    client_unmatched_count = RecvNullCount(ctx, peer_rank);\n  }\n\n  auto matched_seqs = RecvMatchedSeqs(ctx, peer_rank);\n  return BuildServerResult(matched_seqs, ub_cache, client_unmatched_count,\n                           join_role, batch_provider);\n}\n\nTensorPtr Join::OprfPsiClient(\n    ExecContext* ctx, JoinRole join_role, const std::string& tmp_dir,\n    const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n    const std::shared_ptr<util::BatchProvider>& batch_provider, bool is_left,\n    int64_t peer_rank, util::PsiExecutionInfoTable* psi_info_table,\n    std::shared_ptr<yacl::link::Context> psi_link) {\n  std::string server_cipher_store_path =\n      fmt::format(\"{}/tmp-server-cipher-store.csv\", tmp_dir);\n  auto server_cipher_store =\n      std::make_shared<util::UbPsiCipherStore>(server_cipher_store_path, false);\n  auto transfer_server_items_future =\n      std::async(std::launch::async, util::OprfPsiClientTransferServerItems,\n                 ctx, psi_link, psi_options, server_cipher_store);\n\n  std::string client_cipher_store_path =\n      fmt::format(\"{}/tmp-client-cipher-store.csv\", tmp_dir);\n  auto client_cipher_store =\n      std::make_shared<util::UbPsiCipherStore>(client_cipher_store_path, true);\n  util::OprfPsiClientTransferClientItems(ctx, batch_provider, psi_options,\n                                         client_cipher_store);\n  transfer_server_items_future.get();\n\n  std::vector<uint64_t> match_server_seqs;\n\n  TensorPtr result_tensor;\n  std::vector<uint64_t> matched_seqs;\n\n  auto lctx = ctx->GetSession()->GetLink();\n  if (join_role == JoinRole::kLeftOrRightJoinFullParty) {\n    uint64_t client_unmatched_count = 0;\n    std::tie(result_tensor, matched_seqs) =\n        util::FinalizeAndComputeOprfJoinResult(server_cipher_store,\n                                               client_cipher_store, nullptr,\n                                               &client_unmatched_count);\n    SendNullCount(ctx, peer_rank, client_unmatched_count);\n  } else if (join_role == JoinRole::kLeftOrRightJoinNullParty) {\n    uint64_t server_unmatched_count = 0;\n    std::tie(result_tensor, matched_seqs) =\n        util::FinalizeAndComputeOprfJoinResult(\n            server_cipher_store, client_cipher_store, &server_unmatched_count,\n            nullptr);\n  } else if (join_role == JoinRole::kInnerJoinParty) {\n    std::tie(result_tensor, matched_seqs) =\n        util::FinalizeAndComputeOprfJoinResult(\n            server_cipher_store, client_cipher_store, nullptr, nullptr);\n  } else {\n    YACL_THROW(\"unexpected condition: join_role={}\",\n               static_cast<int64_t>(join_role));\n  };\n\n  SendMatchedSeqs(ctx, peer_rank, matched_seqs);\n  return result_tensor;\n}\n\nuint64_t Join::RecvNullCount(ExecContext* ctx, int64_t peer_rank) {\n  auto lctx = ctx->GetSession()->GetLink();\n  auto tag = ctx->GetNodeName() + \"-JoinNullCount\";\n  yacl::Buffer null_count_buf = lctx->Recv(peer_rank, tag);\n  msgpack::object_handle oh = msgpack::unpack(\n      static_cast<char*>(null_count_buf.data()), null_count_buf.size());\n  return oh.get().as<uint64_t>();\n}\n\nvoid Join::SendNullCount(ExecContext* ctx, int64_t peer_rank,\n                         uint64_t null_count) {\n  auto lctx = ctx->GetSession()->GetLink();\n  msgpack::sbuffer sbuf;\n  msgpack::pack(sbuf, null_count);\n  auto tag = ctx->GetNodeName() + \"-JoinNullCount\";\n  lctx->Send(peer_rank, yacl::ByteContainerView(sbuf.data(), sbuf.size()), tag);\n}\n\nvoid Join::SendMatchedSeqs(ExecContext* ctx, int64_t peer_rank,\n                           const std::vector<uint64_t>& matched_seqs) {\n  auto logger = ctx->GetActiveLogger();\n  SPDLOG_LOGGER_INFO(logger,\n                     \"OPRF Join: start sending matched seqs, total count: {}\",\n                     matched_seqs.size());\n\n  auto lctx = ctx->GetSession()->GetLink();\n  auto tag = ctx->GetNodeName() + \"-UbJoinMatchedSeqs\";\n\n  util::SendMassiveMsgpack<uint64_t>(lctx, tag, peer_rank, matched_seqs);\n\n  SPDLOG_LOGGER_INFO(logger, \"OPRF Join: finish sending matched seqs\");\n}\n\nstd::vector<uint64_t> Join::RecvMatchedSeqs(ExecContext* ctx,\n                                            int64_t peer_rank) {\n  auto lctx = ctx->GetSession()->GetLink();\n  auto tag = ctx->GetNodeName() + \"-UbJoinMatchedSeqs\";\n  return util::RecvMassiveMsgpack<uint64_t>(lctx, tag, peer_rank);\n}\n\nTensorPtr Join::BuildServerResult(\n    const std::vector<uint64_t>& matched_seqs,\n    const std::shared_ptr<util::UbPsiJoinCache>& ub_cache,\n    uint64_t client_unmatched_count, JoinRole join_role,\n    const std::shared_ptr<util::BatchProvider>& batch_provider) {\n  UInt64TensorBuilder result_builder;\n  result_builder.Reserve(\n      static_cast<int64_t>(matched_seqs.size() + client_unmatched_count));\n  std::unordered_set<uint64_t> matched_indices;\n  for (uint64_t matched_seq : matched_seqs) {\n    uint64_t matched_indice = ub_cache->GetIndice(matched_seq);\n    result_builder.UnsafeAppend(matched_indice);\n    matched_indices.insert(matched_indice);\n  }\n\n  if (join_role == JoinRole::kLeftOrRightJoinNullParty) {\n    for (uint64_t i = 0; i < client_unmatched_count; ++i) {\n      result_builder.UnsafeAppendNull();\n    }\n  } else if (join_role == JoinRole::kLeftOrRightJoinFullParty) {\n    for (int indice = 0; indice < batch_provider->TotalLength(); ++indice) {\n      if (matched_indices.count(indice) == 0) {\n        result_builder.Append(indice);\n      }\n    }\n  }\n\n  TensorPtr result_tensor;\n  result_builder.Finish(&result_tensor);\n  return result_tensor;\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/join.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <cstdint>\n#include <vector>\n\n#include \"engine/core/tensor.h\"\n#include \"engine/framework/exec.h\"\n#include \"engine/framework/operator.h\"\n#include \"engine/util/psi/batch_provider.h\"\n#include \"engine/util/psi/cipher_intersection.h\"\n#include \"engine/util/psi/common.h\"\n#include \"engine/util/psi/ub_helper.h\"\n\nnamespace scql::engine::op {\n\nclass Join : public Operator {\n public:\n  enum class JoinType : int64_t {\n    kInnerJoin = 0,\n    kLeftJoin = 1,\n    kRightJoin = 2,\n    kTypeNums,\n  };\n\n  enum class JoinRole {\n    kInnerJoinParty = 0,\n    kLeftOrRightJoinFullParty = 1,\n    kLeftOrRightJoinNullParty = 2,\n    kInValid\n  };\n\n  static const std::string kOpType;\n  // input/output names\n  static constexpr char kInLeft[] = \"Left\";\n  static constexpr char kInRight[] = \"Right\";\n  static constexpr char kOutLeftJoinIndex[] = \"LeftJoinIndex\";\n  static constexpr char kOutRightJoinIndex[] = \"RightJoinIndex\";\n  // attributes\n  static constexpr char kJoinTypeAttr[] = \"join_type\";\n  static constexpr char kInputPartyCodesAttr[] = \"input_party_codes\";\n\n  static constexpr char kAlgorithmAttr[] = \"psi_algorithm\";\n\n  static constexpr char kUbPsiServerHint[] = \"ub_psi_server_hint\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static void ValidatePsiTensors(ExecContext* ctx);\n  static void ValidateJoinTypeAndAlgo(ExecContext* ctx);\n\n  static void EcdhPsiJoin(ExecContext* ctx);\n  static void OprfPsiJoin(ExecContext* ctx, bool is_server,\n                          std::optional<util::PsiSizeInfo> psi_size_info = {});\n  static void Rr22PsiJoin(ExecContext* ctx);\n\n  static std::vector<TensorPtr> GetJoinKeys(ExecContext* ctx, bool is_left);\n  static void SetJoinResult(ExecContext* ctx, bool is_left,\n                            TensorPtr result_tensor);\n  static JoinRole GetJoinRole(int64_t join_type, bool is_left);\n\n  // oprf psi\n  static bool IsOprfServerAccordToHint(ExecContext* ctx, int64_t server_hint);\n  static TensorPtr OprfPsiServer(\n      ExecContext* ctx, JoinRole join_role, const std::string& tmp_dir,\n      const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n      const std::shared_ptr<util::BatchProvider>& batch_provider, bool is_left,\n      int64_t peer_rank, util::PsiExecutionInfoTable* psi_info_table,\n      std::shared_ptr<yacl::link::Context> psi_link);\n  static TensorPtr OprfPsiClient(\n      ExecContext* ctx, JoinRole join_role, const std::string& tmp_dir,\n      const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n      const std::shared_ptr<util::BatchProvider>& batch_provider, bool is_left,\n      int64_t peer_rank, util::PsiExecutionInfoTable* psi_info_table,\n      std::shared_ptr<yacl::link::Context> psi_link);\n\n  static uint64_t RecvNullCount(ExecContext* ctx, int64_t peer_rank);\n  static void SendNullCount(ExecContext* ctx, int64_t peer_rank,\n                            uint64_t null_count);\n  static std::vector<uint64_t> RecvMatchedSeqs(ExecContext* ctx,\n                                               int64_t peer_rank);\n  static void SendMatchedSeqs(ExecContext* ctx, int64_t peer_rank,\n                              const std::vector<uint64_t>& matched_seqs);\n  static TensorPtr BuildServerResult(\n      const std::vector<uint64_t>& matched_seqs,\n      const std::shared_ptr<util::UbPsiJoinCache>& ub_cache,\n      uint64_t client_unmatched_count, JoinRole join_role,\n      const std::shared_ptr<util::BatchProvider>& batch_provider);\n  static size_t GetTargetRank(ExecContext* ctx,\n                              const std::shared_ptr<yacl::link::Context>& lctx);\n};\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/join_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/join.h\"\n\n#include <cstddef>\n#include <cstdint>\n#include <vector>\n\n#include \"gmock/gmock.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n#include \"engine/util/psi/common.h\"\n\nnamespace scql::engine::op {\n\nstruct JoinTestCase {\n  std::vector<test::NamedTensor> left_inputs;\n  std::vector<test::NamedTensor> right_inputs;\n  Join::JoinType join_type = Join::JoinType::kInnerJoin;\n  util::PsiAlgo join_algo = util::PsiAlgo::kAutoPsi;\n  // join indices in following format:\n  // [\"left_idx1,right_idx1\", \"left_idx2,right_idx2\",...]\n  std::vector<std::string> join_indices;\n  int64_t ub_server;\n};\n\nclass JoinTest : public ::testing::TestWithParam<\n                     std::tuple<test::SpuRuntimeTestCase, JoinTestCase>> {\n protected:\n  static pb::ExecNode MakeJoinExecNode(const JoinTestCase& tc,\n                                       util::PsiAlgo join_algo);\n\n  static void FeedInputs(ExecContext* ctx,\n                         const std::vector<test::NamedTensor>& tensors);\n\n  static constexpr char kOutLeft[] = \"left_output\";\n  static constexpr char kOutRight[] = \"right_output\";\n};\n\nnamespace {\nstd::vector<std::string> AllMatchedJoinIndices(size_t left_count,\n                                               size_t right_count) {\n  std::vector<std::string> ret;\n  for (size_t left_idx = 0; left_idx < left_count; ++left_idx) {\n    for (size_t right_idx = 0; right_idx < right_count; ++right_idx) {\n      ret.emplace_back(absl::StrCat(left_idx, \",\", right_idx));\n    }\n  }\n  return ret;\n}\n}  // namespace\n\nINSTANTIATE_TEST_SUITE_P(\n    JoinBatchTest, JoinTest,\n    testing::Combine(\n        // any protocol is ok\n        testing::Values(test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2}),\n        // TODO: clean duplicated tests\n        testing::Values(\n            // ECDH PSI\n            // case 4\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_algo = util::PsiAlgo::kEcdhPsi,\n                .join_indices = {}},\n            // case 1\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", TensorFrom(arrow::int64(), \"[4,8,1,3,3,5]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", TensorFrom(arrow::int64(), \"[2,1,4,4,3,7,8]\"))},\n                .join_type = Join::JoinType::kInnerJoin,\n                .join_indices = {\"0,2\", \"0,3\", \"1,6\", \"2,1\", \"3,4\", \"4,4\"}},\n\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", TensorFrom(arrow::int64(), \"[4,8,1,3,3,5]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", TensorFrom(arrow::int64(), \"[2,1,4,4,3,7,8]\"))},\n                .join_type = Join::JoinType::kLeftJoin,\n                .join_indices = {\"0,2\", \"0,3\", \"1,6\", \"2,1\", \"3,4\", \"4,4\",\n                                 \"5,null\"}},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", TensorFrom(arrow::int64(), \"[4,8,1,3,3,5]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", TensorFrom(arrow::int64(), \"[2,1,4,4,3,7,8]\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_indices = {\"0,2\", \"0,3\", \"1,6\", \"2,1\", \"3,4\", \"4,4\",\n                                 \"null,0\", \"null,5\"}},\n            // clang-format off\n\n        //   ta inner join tb on x_1=y_1 and x_2 = y_2\n        //   join table is:\n        //         ta_index, x_1, x_2,    tb_index, y_1, y_2\n        //                0,   A,   1,           1,   A, 1\n        //                1,   A,   2,           2,   A, 2\n        //                2,   B,   1,           3,   B, 1\n        //                3,   B,   1,           3,   B, 1\n        //                4,   B,   2,           0,   B, 2\n        //                4,   B,   2,           5,   B, 2\n\n        //   ta left join tb on x_1=y_1 and x_2 = y_2\n        //   join table is:\n        //         ta_index, x_1,  x_2,    b_index,  y_1,   y_2\n        //                0,   A,   1,           1,    A,    1\n        //                1,   A,   2,           2,    A,    2\n        //                2,   B,   1,           3,    B,    1\n        //                3,   B,   1,           3,    B,    1\n        //                4,   B,   2,           0,    B,    2\n        //                4,   B,   2,           5,    B,    2\n        //                5,   C,   1,           null, null, null\n\n        //   ta right join tb on x_1=y_1 and x_2 = y_2\n        //   join table is:\n        //         ta_index,  x_1,   x_2,    b_index,  y_1,   y_2\n        //                0,    A,    1,           1,    A,    1\n        //                1,    A,    2,           2,    A,    2\n        //                2,    B,    1,           3,    B,    1\n        //                3,    B,    1,           3,    B,    1\n        //                4,    B,    2,           0,    B,    2\n        //                4,    B,    2,           5,    B,    2\n        //                null, null, null,        4,    B,    3\n            // clang-format on\n            // auto tensorX_1 = test::NamedTensor(\n            //     \"x_1\", TensorFrom(arrow::large_utf8(),\n            // R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\"));\n\n            // case 2\n            JoinTestCase{\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\")),\n                     test::NamedTensor(\"x_2\", TensorFrom(arrow::int64(),\n                                                         \"[1,2,1,1,2,1]\"))},\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"B\",\"A\",\"A\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\"y_2\", TensorFrom(arrow::int64(),\n                                                         \"[2,1,2,1,3,2]\"))},\n                .join_indices = {\"0,1\", \"1,2\", \"2,3\", \"3,3\", \"4,0\", \"4,5\"}},\n\n            JoinTestCase{\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\")),\n                     test::NamedTensor(\"x_2\", TensorFrom(arrow::int64(),\n                                                         \"[1,2,1,1,2,1]\"))},\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"B\",\"A\",\"A\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\"y_2\", TensorFrom(arrow::int64(),\n                                                         \"[2,1,2,1,3,2]\"))},\n                .join_type = Join::JoinType::kLeftJoin,\n                .join_indices = {\"0,1\", \"1,2\", \"2,3\", \"3,3\", \"4,0\", \"4,5\",\n                                 \"5,null\"}},\n            JoinTestCase{\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\")),\n                     test::NamedTensor(\"x_2\", TensorFrom(arrow::int64(),\n                                                         \"[1,2,1,1,2,1]\"))},\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"B\",\"A\",\"A\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\"y_2\", TensorFrom(arrow::int64(),\n                                                         \"[2,1,2,1,3,2]\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_indices = {\"0,1\", \"1,2\", \"2,3\", \"3,3\", \"4,0\", \"4,5\",\n                                 \"null,4\"}},\n\n            // case 3\n            // testcase: empty join output\n            JoinTestCase{.left_inputs = {test::NamedTensor(\n                             \"x\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"A\",\"B\",\"C\"])json\"))},\n                         .right_inputs = {test::NamedTensor(\n                             \"y\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                         .join_indices = {}},\n            JoinTestCase{.left_inputs = {test::NamedTensor(\n                             \"x\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"A\",\"B\",\"C\"])json\"))},\n                         .right_inputs = {test::NamedTensor(\n                             \"y\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                         .join_type = Join::JoinType::kLeftJoin,\n                         .join_indices = {\"0,null\", \"1,null\", \"2,null\"}},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"B\",\"C\"])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_indices = {\"null,0\", \"null,1\", \"null,2\", \"null,3\"}},\n\n            // case 4\n            // testcase: empty input\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_indices = {}},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_type = Join::JoinType::kLeftJoin,\n                .join_indices = {}},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_indices = {\"null,0\", \"null,1\", \"null,2\", \"null,3\"}},\n\n            // UbPsiJoin\n\n            // with hint\n\n            // case 1\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", TensorFrom(arrow::int64(), \"[4,8,1,3,3,5]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", TensorFrom(arrow::int64(), \"[2,1,4,4,3,7,8]\"))},\n                .join_type = Join::JoinType::kInnerJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,2\", \"0,3\", \"1,6\", \"2,1\", \"3,4\", \"4,4\"},\n                .ub_server = 0},\n\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", TensorFrom(arrow::int64(), \"[4,8,1,3,3,5]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", TensorFrom(arrow::int64(), \"[2,1,4,4,3,7,8]\"))},\n                .join_type = Join::JoinType::kLeftJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,2\", \"0,3\", \"1,6\", \"2,1\", \"3,4\", \"4,4\",\n                                 \"5,null\"},\n                .ub_server = 0},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", TensorFrom(arrow::int64(), \"[4,8,1,3,3,5]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", TensorFrom(arrow::int64(), \"[2,1,4,4,3,7,8]\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,2\", \"0,3\", \"1,6\", \"2,1\", \"3,4\", \"4,4\",\n                                 \"null,0\", \"null,5\"},\n                .ub_server = 0},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", TensorFrom(arrow::int64(), \"[4,8,1,3,3,5]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", TensorFrom(arrow::int64(), \"[2,1,4,4,3,7,8]\"))},\n                .join_type = Join::JoinType::kInnerJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,2\", \"0,3\", \"1,6\", \"2,1\", \"3,4\", \"4,4\"},\n                .ub_server = 1},\n\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", TensorFrom(arrow::int64(), \"[4,8,1,3,3,5]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", TensorFrom(arrow::int64(), \"[2,1,4,4,3,7,8]\"))},\n                .join_type = Join::JoinType::kLeftJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,2\", \"0,3\", \"1,6\", \"2,1\", \"3,4\", \"4,4\",\n                                 \"5,null\"},\n                .ub_server = 1},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", TensorFrom(arrow::int64(), \"[4,8,1,3,3,5]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", TensorFrom(arrow::int64(), \"[2,1,4,4,3,7,8]\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,2\", \"0,3\", \"1,6\", \"2,1\", \"3,4\", \"4,4\",\n                                 \"null,0\", \"null,5\"},\n                .ub_server = 1},\n\n            // case 2\n            JoinTestCase{\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\")),\n                     test::NamedTensor(\"x_2\", TensorFrom(arrow::int64(),\n                                                         \"[1,2,1,1,2,1]\"))},\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"B\",\"A\",\"A\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\"y_2\", TensorFrom(arrow::int64(),\n                                                         \"[2,1,2,1,3,2]\"))},\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,1\", \"1,2\", \"2,3\", \"3,3\", \"4,0\", \"4,5\"},\n                .ub_server = 0},\n\n            JoinTestCase{\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\")),\n                     test::NamedTensor(\"x_2\", TensorFrom(arrow::int64(),\n                                                         \"[1,2,1,1,2,1]\"))},\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"B\",\"A\",\"A\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\"y_2\", TensorFrom(arrow::int64(),\n                                                         \"[2,1,2,1,3,2]\"))},\n                .join_type = Join::JoinType::kLeftJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,1\", \"1,2\", \"2,3\", \"3,3\", \"4,0\", \"4,5\",\n                                 \"5,null\"},\n                .ub_server = 0},\n            JoinTestCase{\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\")),\n                     test::NamedTensor(\"x_2\", TensorFrom(arrow::int64(),\n                                                         \"[1,2,1,1,2,1]\"))},\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"B\",\"A\",\"A\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\"y_2\", TensorFrom(arrow::int64(),\n                                                         \"[2,1,2,1,3,2]\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,1\", \"1,2\", \"2,3\", \"3,3\", \"4,0\", \"4,5\",\n                                 \"null,4\"},\n                .ub_server = 0},\n\n            JoinTestCase{\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\")),\n                     test::NamedTensor(\"x_2\", TensorFrom(arrow::int64(),\n                                                         \"[1,2,1,1,2,1]\"))},\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"B\",\"A\",\"A\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\"y_2\", TensorFrom(arrow::int64(),\n                                                         \"[2,1,2,1,3,2]\"))},\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,1\", \"1,2\", \"2,3\", \"3,3\", \"4,0\", \"4,5\"},\n                .ub_server = 1},\n\n            JoinTestCase{\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\")),\n                     test::NamedTensor(\"x_2\", TensorFrom(arrow::int64(),\n                                                         \"[1,2,1,1,2,1]\"))},\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"B\",\"A\",\"A\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\"y_2\", TensorFrom(arrow::int64(),\n                                                         \"[2,1,2,1,3,2]\"))},\n                .join_type = Join::JoinType::kLeftJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,1\", \"1,2\", \"2,3\", \"3,3\", \"4,0\", \"4,5\",\n                                 \"5,null\"},\n                .ub_server = 1},\n            JoinTestCase{\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\")),\n                     test::NamedTensor(\"x_2\", TensorFrom(arrow::int64(),\n                                                         \"[1,2,1,1,2,1]\"))},\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"B\",\"A\",\"A\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\"y_2\", TensorFrom(arrow::int64(),\n                                                         \"[2,1,2,1,3,2]\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"0,1\", \"1,2\", \"2,3\", \"3,3\", \"4,0\", \"4,5\",\n                                 \"null,4\"},\n                .ub_server = 1},\n\n            // case 3\n            // testcase: empty join output\n            JoinTestCase{.left_inputs = {test::NamedTensor(\n                             \"x\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"A\",\"B\",\"C\"])json\"))},\n                         .right_inputs = {test::NamedTensor(\n                             \"y\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                         .join_algo = util::PsiAlgo::kOprfPsi,\n                         .join_indices = {},\n                         .ub_server = 0},\n            JoinTestCase{.left_inputs = {test::NamedTensor(\n                             \"x\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"A\",\"B\",\"C\"])json\"))},\n                         .right_inputs = {test::NamedTensor(\n                             \"y\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                         .join_type = Join::JoinType::kLeftJoin,\n                         .join_algo = util::PsiAlgo::kOprfPsi,\n                         .join_indices = {\"0,null\", \"1,null\", \"2,null\"},\n                         .ub_server = 0},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"B\",\"C\"])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"null,0\", \"null,1\", \"null,2\", \"null,3\"},\n                .ub_server = 0},\n            JoinTestCase{.left_inputs = {test::NamedTensor(\n                             \"x\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"A\",\"B\",\"C\"])json\"))},\n                         .right_inputs = {test::NamedTensor(\n                             \"y\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                         .join_algo = util::PsiAlgo::kOprfPsi,\n                         .join_indices = {},\n                         .ub_server = 1},\n            JoinTestCase{.left_inputs = {test::NamedTensor(\n                             \"x\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"A\",\"B\",\"C\"])json\"))},\n                         .right_inputs = {test::NamedTensor(\n                             \"y\", TensorFrom(arrow::large_utf8(),\n                                             R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                         .join_type = Join::JoinType::kLeftJoin,\n                         .join_algo = util::PsiAlgo::kOprfPsi,\n                         .join_indices = {\"0,null\", \"1,null\", \"2,null\"},\n                         .ub_server = 1},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"B\",\"C\"])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"null,0\", \"null,1\", \"null,2\", \"null,3\"},\n                .ub_server = 1},\n\n            // case 4\n            // testcase: empty input\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {},\n                .ub_server = 0},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_type = Join::JoinType::kLeftJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {},\n                .ub_server = 0},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"null,0\", \"null,1\", \"null,2\", \"null,3\"},\n                .ub_server = 0},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {},\n                .ub_server = 1},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_type = Join::JoinType::kLeftJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {},\n                .ub_server = 1},\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_type = Join::JoinType::kRightJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = {\"null,0\", \"null,1\", \"null,2\", \"null,3\"},\n                .ub_server = 1},\n\n            // case 5\n            // testcase: duplicated keys\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", FullNumericTensor<arrow::Int64Type>(5, 1))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", FullNumericTensor<arrow::Int64Type>(1000, 1))},\n                .join_type = Join::JoinType::kInnerJoin,\n                .join_algo = util::PsiAlgo::kOprfPsi,\n                .join_indices = AllMatchedJoinIndices(5, 1000),\n                .ub_server = 1},\n\n            // without hint\n\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"id_a\", TensorFrom(arrow::int64(), \"[4,8,1,3,3,5]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"id_b\", TensorFrom(arrow::int64(), \"[2,1,4,4,3,7,8]\"))},\n                .join_type = Join::JoinType::kInnerJoin,\n                .join_indices = {\"0,2\", \"0,3\", \"1,6\", \"2,1\", \"3,4\", \"4,4\"},\n                .ub_server = 1,\n            },\n\n            // case 2\n            JoinTestCase{\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"A\",\"B\",\"B\",\"B\",\"C\"])json\")),\n                     test::NamedTensor(\"x_2\", TensorFrom(arrow::int64(),\n                                                         \"[1,2,1,1,2,1]\"))},\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y_1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"B\",\"A\",\"A\",\"B\",\"B\",\"B\"])json\")),\n                     test::NamedTensor(\"y_2\", TensorFrom(arrow::int64(),\n                                                         \"[2,1,2,1,3,2]\"))},\n                .join_algo = util::PsiAlgo::kAutoPsi,\n                .join_indices = {\"0,1\", \"1,2\", \"2,3\", \"3,3\", \"4,0\", \"4,5\"},\n                .ub_server = 1,\n            },\n\n            // case 3\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"A\",\"B\",\"C\"])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_algo = util::PsiAlgo::kEcdhPsi,\n                .join_indices = {},\n                .ub_server = 1,\n            },\n\n            // case 4\n            JoinTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::large_utf8(), R\"json([])json\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"E\",\"F\",\"H\",\"G\"])json\"))},\n                .join_indices = {},\n                .ub_server = 1,\n            }\n\n            )),\n\n    TestParamNameGenerator(JoinTest));\n\nTEST_P(JoinTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto test_case = std::get<1>(parm);\n  std::vector<util::PsiAlgo> test_algo_types;\n  if (test_case.join_algo == util::PsiAlgo::kAutoPsi) {\n    // default test rr22/ecdh\n    test_algo_types = {util::PsiAlgo::kRr22Psi, util::PsiAlgo::kEcdhPsi};\n  } else {\n    test_algo_types = {test_case.join_algo};\n  }\n  for (auto algo : test_algo_types) {\n    pb::ExecNode node = MakeJoinExecNode(test_case, algo);\n    auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n    ExecContext alice_ctx(node, sessions[0].get());\n    ExecContext bob_ctx(node, sessions[1].get());\n\n    // feed inputs\n    FeedInputs(&alice_ctx, test_case.left_inputs);\n    FeedInputs(&bob_ctx, test_case.right_inputs);\n\n    // When\n    EXPECT_NO_THROW(test::RunAsync<Join>({&alice_ctx, &bob_ctx}));\n\n    // Then\n    // left output\n    auto left_output = alice_ctx.GetTensorTable()->GetTensor(kOutLeft);\n    EXPECT_TRUE(left_output != nullptr);\n    EXPECT_EQ(left_output->Type(), pb::PrimitiveDataType::INT64);\n\n    // right output\n    auto right_output = bob_ctx.GetTensorTable()->GetTensor(kOutRight);\n    EXPECT_TRUE(right_output != nullptr);\n    EXPECT_EQ(right_output->Type(), pb::PrimitiveDataType::INT64);\n\n    EXPECT_EQ(left_output->Length(), right_output->Length());\n    EXPECT_EQ(left_output->Length(), test_case.join_indices.size());\n\n    auto left_join_result = util::Stringify(left_output->ToArrowChunkedArray());\n    auto right_join_result =\n        util::Stringify(right_output->ToArrowChunkedArray());\n\n    auto indices_got = util::Combine(left_join_result, right_join_result);\n\n    EXPECT_THAT(indices_got,\n                ::testing::UnorderedElementsAreArray(test_case.join_indices));\n  }\n}\n\n/// ===========================\n/// JoinTest impl\n/// ===========================\n\npb::ExecNode JoinTest::MakeJoinExecNode(const JoinTestCase& tc,\n                                        util::PsiAlgo join_algo) {\n  test::ExecNodeBuilder builder(Join::kOpType);\n\n  builder.SetNodeName(\"join-test\");\n  builder.AddInt64Attr(Join::kJoinTypeAttr, static_cast<int64_t>(tc.join_type));\n  builder.AddInt64Attr(Join::kAlgorithmAttr, static_cast<int64_t>(join_algo));\n  builder.AddInt64Attr(Join::kUbPsiServerHint, tc.ub_server);\n  builder.AddStringsAttr(\n      Join::kInputPartyCodesAttr,\n      std::vector<std::string>{test::kPartyAlice, test::kPartyBob});\n\n  // Add inputs\n\n  std::vector<pb::Tensor> left_inputs;\n  for (const auto& named_tensor : tc.left_inputs) {\n    auto t = test::MakeTensorReference(named_tensor.name,\n                                       named_tensor.tensor->Type(),\n                                       pb::TensorStatus::TENSORSTATUS_PRIVATE);\n    left_inputs.push_back(std::move(t));\n  }\n  builder.AddInput(Join::kInLeft, left_inputs);\n\n  std::vector<pb::Tensor> right_inputs;\n  for (const auto& named_tensor : tc.right_inputs) {\n    auto t = test::MakeTensorReference(named_tensor.name,\n                                       named_tensor.tensor->Type(),\n                                       pb::TensorStatus::TENSORSTATUS_PRIVATE);\n    right_inputs.push_back(std::move(t));\n  }\n  builder.AddInput(Join::kInRight, right_inputs);\n\n  // Add outputs\n  auto left_join_output =\n      test::MakeTensorReference(kOutLeft, pb::PrimitiveDataType::INT64,\n                                pb::TensorStatus::TENSORSTATUS_PRIVATE);\n  auto right_join_output =\n      test::MakeTensorReference(kOutRight, pb::PrimitiveDataType::INT64,\n                                pb::TensorStatus::TENSORSTATUS_PRIVATE);\n  builder.AddOutput(Join::kOutLeftJoinIndex,\n                    std::vector<pb::Tensor>{left_join_output});\n  builder.AddOutput(Join::kOutRightJoinIndex,\n                    std::vector<pb::Tensor>{right_join_output});\n\n  return builder.Build();\n}\n\nvoid JoinTest::FeedInputs(ExecContext* ctx,\n                          const std::vector<test::NamedTensor>& tensors) {\n  auto* tensor_table = ctx->GetTensorTable();\n  for (const auto& named_tensor : tensors) {\n    tensor_table->AddTensor(named_tensor.name, named_tensor.tensor);\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/limit.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/limit.h\"\n\n#include \"libspu/kernel/hlo/geometrical.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Limit::kOpType(\"Limit\");\n\nconst std::string& Limit::Type() const { return kOpType; }\n\nvoid Limit::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() > 0, \"Limit input size must > 0\");\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"Limit input {} and output {} should have the same size\", kIn,\n               kOut);\n}\n\nvoid Limit::Execute(ExecContext* ctx) {\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  auto offset = ctx->GetInt64ValueFromAttribute(kOffset);\n  auto count = ctx->GetInt64ValueFromAttribute(kCount);\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    const auto& input_pb = input_pbs[i];\n    if (util::IsTensorStatusMatched(input_pb, pb::TENSORSTATUS_PRIVATE)) {\n      auto tensor = ctx->GetTensorTable()->GetTensor(input_pb.name());\n      YACL_ENFORCE(tensor, \"get private tensor failed, name={}\",\n                   input_pb.name());\n      std::shared_ptr<arrow::ChunkedArray> sliced_arr;\n      if (offset < tensor->Length()) {\n        sliced_arr = tensor->ToArrowChunkedArray()->Slice(offset, count);\n      } else {\n        sliced_arr = std::make_shared<arrow::ChunkedArray>(\n            std::vector<std::shared_ptr<arrow::Array>>{},\n            tensor->ToArrowChunkedArray()->type());\n      }\n\n      auto result = TensorFrom(std::move(sliced_arr));\n      ctx->GetTensorTable()->AddTensor(output_pbs[i].name(), std::move(result));\n    } else {\n      auto* symbols = ctx->GetSession()->GetDeviceSymbols();\n      auto* sctx = ctx->GetSession()->GetSpuContext();\n      auto value = symbols->getVar(\n          util::SpuVarNameEncoder::GetValueName(input_pb.name()));\n\n      auto value_result = spu::kernel::hlo::Slice(\n          sctx, value, {offset}, {std::min(offset + count, value.shape()[0])},\n          {1});\n      symbols->setVar(\n          util::SpuVarNameEncoder::GetValueName(output_pbs[i].name()),\n          value_result);\n\n#ifdef SCQL_WITH_NULL\n      auto validity = symbols->getVar(\n          util::SpuVarNameEncoder::GetValidityName(input_pb.name()));\n\n      auto validity_result = spu::kernel::hlo::Slice(\n          sctx, validity, {offset},\n          {std::min(offset + count, value.shape()[0])}, {1});\n      symbols->setVar(\n          util::SpuVarNameEncoder::GetValidityName(output_pbs[i].name()),\n          validity_result);\n#endif  // SCQL_WITH_NULL\n    }\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/limit.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/// @brief Shape return the shape of inputs\nclass Limit : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  static constexpr char kOffset[] = \"offset\";\n  static constexpr char kCount[] = \"count\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/limit_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/limit.h\"\n\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n#include \"engine/util/spu_io.h\"\n\nnamespace scql::engine::op {\n\nstruct LimitTestCase {\n  std::vector<test::NamedTensor> inputs;\n  pb::TensorStatus input_status;\n  int64_t offset;\n  int64_t count;\n  std::vector<test::NamedTensor> expect_outs;\n};\n\nclass LimitTest : public testing::TestWithParam<\n                      std::tuple<test::SpuRuntimeTestCase, LimitTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const LimitTestCase& tc);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const LimitTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    LimitBatchTest, LimitTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            LimitTestCase{\n                .inputs =\n                    {test::NamedTensor(\"a\", TensorFrom(arrow::boolean(),\n                                                       \"[true, false, true]\")),\n                     test::NamedTensor(\"b\", TensorFrom(arrow::int64(),\n                                                       \"[1,2,null,4,5,6,7,8]\")),\n                     test::NamedTensor(\n                         \"c\", TensorFrom(\n                                  arrow::float64(),\n                                  \"[1.1025, 100.245, -10.2, 0.34, 3.1415926]\")),\n                     test::NamedTensor(\"d\", TensorFrom(arrow::int64(), \"[1]\"))},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .offset = 1,\n                .count = 2,\n                .expect_outs =\n                    {test::NamedTensor(\"a_out\", TensorFrom(arrow::boolean(),\n                                                           \"[false,true]\")),\n                     test::NamedTensor(\"b_out\",\n                                       TensorFrom(arrow::int64(), \"[2,null]\")),\n                     test::NamedTensor(\"c_out\", TensorFrom(arrow::float64(),\n                                                           \"[100.245, -10.2]\")),\n                     test::NamedTensor(\"d_out\",\n                                       TensorFrom(arrow::int64(), \"[]\"))}},\n            LimitTestCase{\n                .inputs =\n                    {test::NamedTensor(\"a\", TensorFrom(arrow::boolean(),\n                                                       \"[true, false, true]\")),\n                     test::NamedTensor(\"b\", TensorFrom(arrow::int64(),\n                                                       \"[1,2,3,4,5,6,7,8]\")),\n                     test::NamedTensor(\n                         \"c\", TensorFrom(\n                                  arrow::float64(),\n                                  \"[1.1025, 100.245, -10.2, 0.34, 3.1415926]\")),\n                     test::NamedTensor(\"d\", TensorFrom(arrow::int64(), \"[1]\"))},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .offset = 1,\n                .count = 2,\n                .expect_outs =\n                    {test::NamedTensor(\"a_out\", TensorFrom(arrow::boolean(),\n                                                           \"[false,true]\")),\n                     test::NamedTensor(\"b_out\",\n                                       TensorFrom(arrow::int64(), \"[2,3]\")),\n                     test::NamedTensor(\"c_out\", TensorFrom(arrow::float64(),\n                                                           \"[100.245, -10.2]\")),\n                     test::NamedTensor(\"d_out\",\n                                       TensorFrom(arrow::int64(), \"[]\"))}},\n            LimitTestCase{\n                .inputs =\n                    {test::NamedTensor(\"a\", TensorFrom(arrow::boolean(),\n                                                       \"[true, false, true]\")),\n                     test::NamedTensor(\"b\", TensorFrom(arrow::int64(),\n                                                       \"[1,2,3,4,5,6,7,8]\")),\n                     test::NamedTensor(\n                         \"c\", TensorFrom(\n                                  arrow::float64(),\n                                  \"[1.1025, 100.245, -10.2, 0.34, 3.1415926]\")),\n                     test::NamedTensor(\"d\", TensorFrom(arrow::int64(), \"[1]\"))},\n                .input_status = pb::TENSORSTATUS_PUBLIC,\n                .offset = 1,\n                .count = 2,\n                .expect_outs =\n                    {test::NamedTensor(\"a_out\", TensorFrom(arrow::boolean(),\n                                                           \"[false,true]\")),\n                     test::NamedTensor(\"b_out\",\n                                       TensorFrom(arrow::int64(), \"[2,3]\")),\n                     test::NamedTensor(\"c_out\", TensorFrom(arrow::float64(),\n                                                           \"[100.245, -10.2]\")),\n                     test::NamedTensor(\"d_out\",\n                                       TensorFrom(arrow::int64(), \"[]\"))}})),\n    TestParamNameGenerator(LimitTest));\n\nTEST_P(LimitTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  EXPECT_NO_THROW(test::RunAsync<Limit>(ctx_ptrs));\n\n  // Then\n  // check alice output\n  for (const auto& expect_t : tc.expect_outs) {\n    auto expect_arr = expect_t.tensor->ToArrowChunkedArray();\n    TensorPtr out = nullptr;\n    if (tc.input_status == pb::TENSORSTATUS_PRIVATE) {\n      out = ctx_ptrs[0]->GetTensorTable()->GetTensor(expect_t.name);\n    } else if (tc.input_status == pb::TENSORSTATUS_PUBLIC) {\n      auto spu_io =\n          util::SpuOutfeedHelper(ctx_ptrs[0]->GetSession()->GetSpuContext(),\n                                 ctx_ptrs[0]->GetSession()->GetDeviceSymbols());\n      EXPECT_NO_THROW(out = spu_io.DumpPublic(expect_t.name));\n    } else {\n      EXPECT_NO_THROW(out = test::RevealSecret(ctx_ptrs, expect_t.name));\n    }\n    ASSERT_TRUE(out);\n    auto out_arr = out->ToArrowChunkedArray();\n    // compare tensor content\n    EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr))\n        << \"expect type = \" << expect_arr->type()->ToString()\n        << \", got type = \" << out_arr->type()->ToString()\n        << \"\\nexpect result = \" << expect_arr->ToString()\n        << \"\\nbut actual got result = \" << out_arr->ToString();\n  }\n}\n\n/// ===================\n/// LimitTest impl\n/// ===================\n\npb::ExecNode LimitTest::MakeExecNode(const LimitTestCase& tc) {\n  test::ExecNodeBuilder builder(Limit::kOpType);\n\n  builder.SetNodeName(\"Limit-test\");\n  builder.AddInt64Attr(Limit::kOffset, tc.offset);\n  builder.AddInt64Attr(Limit::kCount, tc.count);\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    auto t = test::MakeTensorReference(\n        named_tensor.name, named_tensor.tensor->Type(), tc.input_status);\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(Limit::kIn, inputs);\n\n  std::vector<pb::Tensor> outputs;\n  for (const auto& named_tensor : tc.expect_outs) {\n    auto t = test::MakeTensorReference(\n        named_tensor.name, named_tensor.tensor->Type(), tc.input_status);\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(Limit::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid LimitTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                           const LimitTestCase& tc) {\n  if (tc.input_status == pb::TENSORSTATUS_PRIVATE) {\n    for (auto* ctx : ctxs) {\n      test::FeedInputsAsPrivate(ctx, tc.inputs);\n    }\n  } else if (tc.input_status == pb::TensorStatus::TENSORSTATUS_SECRET) {\n    test::FeedInputsAsSecret(ctxs, tc.inputs);\n  } else {\n    test::FeedInputsAsPublic(ctxs, tc.inputs);\n  }\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/logical.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/logical.h\"\n\n#include \"arrow/compute/api.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/basic_unary.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Not::kOpType(\"Not\");\nconst std::string& Not::Type() const { return kOpType; }\n\nvoid Not::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(\n      inputs.size() == outputs.size(),\n      \"Not operator inputs {} and outputs {} should have the same size\", kIn,\n      kOut);\n\n  YACL_ENFORCE(\n      util::AreTensorsStatusEqualAndOneOf(\n          inputs, std::vector<pb::TensorStatus>{pb::TENSORSTATUS_PRIVATE,\n                                                pb::TENSORSTATUS_SECRET}),\n      \"Not operator inputs {} status should be same and in [private, secret]\",\n      kIn);\n  auto input_status = util::GetTensorStatus(inputs[0]);\n  YACL_ENFORCE(\n      util::AreTensorsStatusMatched(outputs, input_status),\n      \"Not operator inputs {} and outputs {} should have the same status\", kIn,\n      kOut);\n\n  // Check input & output data type\n  const auto input_type = inputs[0].elem_type();\n  const auto output_type = outputs[0].elem_type();\n  YACL_ENFORCE(input_type == pb::PrimitiveDataType::BOOL &&\n                   output_type == pb::PrimitiveDataType::BOOL,\n               \"Not operator both input and output data type should be BOOL, \"\n               \"but got input={}, output={}\",\n               pb::PrimitiveDataType_Name(input_type),\n               pb::PrimitiveDataType_Name(output_type));\n}\n\nvoid Not::Execute(ExecContext* ctx) {\n  if (ctx->GetInputStatus(kIn) == pb::TENSORSTATUS_PRIVATE) {\n    return ExecuteInPlain(ctx);\n  } else {\n    return ExecuteInSecret(ctx);\n  }\n}\n\nvoid Not::ExecuteInPlain(ExecContext* ctx) {\n  auto input_tensors = ctx->GetInputTensors(kIn);\n  std::vector<std::shared_ptr<Tensor>> results;\n  results.reserve(input_tensors.size());\n\n  for (const auto& input_tensor : input_tensors) {\n    auto result = arrow::compute::CallFunction(\n        \"invert\", {input_tensor->ToArrowChunkedArray()});\n    YACL_ENFORCE(result.ok(),\n                 \"caught error while invoking arrow invert function: {}\",\n                 result.status().ToString());\n    results.push_back(TensorFrom(result.ValueOrDie().chunked_array()));\n  }\n\n  ctx->SetOutputTensors(kOut, results);\n}\n\nvoid Not::ExecuteInSecret(ExecContext* ctx) {\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto input_values = ctx->GetInputValues(kIn);\n  std::vector<spu::Value> results;\n  results.reserve(input_values.size());\n\n  for (const auto& input_value : input_values) {\n    results.push_back(spu::kernel::hlo::Not(sctx, input_value));\n  }\n\n  ctx->SetOutputValues(kOut, results);\n\n#ifdef SCQL_WITH_NULL\n  auto input_validities = ctx->GetInputValidities(kIn);\n  ctx->SetOutputValidities(kOut, input_validities);\n#endif  // SCQL_WITH_NULL\n}\n\nvoid LogicalBase::ValidateIoDataTypes(ExecContext* ctx) {\n  const auto input_left_type = ctx->GetInput(kInLeft)[0].elem_type();\n  const auto input_right_type = ctx->GetInput(kInRight)[0].elem_type();\n  const auto output_type = ctx->GetOutput(kOut)[0].elem_type();\n  YACL_ENFORCE(\n      input_left_type == pb::PrimitiveDataType::BOOL &&\n          input_right_type == pb::PrimitiveDataType::BOOL,\n      \"Operator {} input data type should be BOOL, but got left={}, right={}\",\n      Type(), pb::PrimitiveDataType_Name(input_left_type),\n      pb::PrimitiveDataType_Name(input_right_type));\n  YACL_ENFORCE(output_type == pb::PrimitiveDataType::BOOL,\n               \"Operator {} output data type should be BOOL, but got={}\",\n               Type(), pb::PrimitiveDataType_Name(output_type));\n}\n\n// ===========================\n//   LogicalAnd impl\n// ===========================\n\nconst std::string LogicalAnd::kOpType(\"LogicalAnd\");\nconst std::string& LogicalAnd::Type() const { return kOpType; }\n\nspu::Value LogicalAnd::ComputeOnSpu(spu::SPUContext* sctx,\n                                    const spu::Value& lhs,\n                                    const spu::Value& rhs) {\n  return spu::kernel::hlo::And(sctx, lhs, rhs);\n}\n\nTensorPtr LogicalAnd::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  auto result = arrow::compute::CallFunction(\n      \"and_kleene\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow and function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n// ===========================\n//   LogicalOr impl\n// ===========================\n\nconst std::string LogicalOr::kOpType(\"LogicalOr\");\nconst std::string& LogicalOr::Type() const { return kOpType; }\n\nspu::Value LogicalOr::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                                   const spu::Value& rhs) {\n  return spu::kernel::hlo::Or(sctx, lhs, rhs);\n}\n\nTensorPtr LogicalOr::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  auto result = arrow::compute::CallFunction(\n      \"or_kleene\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n  YACL_ENFORCE(result.ok(), \"caught error while invoking arrow or function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/logical.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n#include \"engine/operator/binary_base.h\"\n\nnamespace scql::engine::op {\n\n/// @brief Out = Not In\nclass Not : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n  static void ExecuteInPlain(ExecContext* ctx);\n  static void ExecuteInSecret(ExecContext* ctx);\n};\n\nclass LogicalBase : public BinaryBase {\n protected:\n  void ValidateIoDataTypes(ExecContext* ctx) override;\n};\n\nclass LogicalAnd : public LogicalBase {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\nclass LogicalOr : public LogicalBase {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n protected:\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/logical_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/logical.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/binary_test.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct NotTestCase {\n  std::vector<test::NamedTensor> inputs;\n  pb::TensorStatus input_status;\n  std::vector<test::NamedTensor> outputs;\n};\n\nclass NotTest : public testing::TestWithParam<\n                    std::tuple<test::SpuRuntimeTestCase, NotTestCase>> {\n public:\n  static pb::ExecNode MakeExecNode(const NotTestCase& tc);\n\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const NotTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    NotBatchTest, NotTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            NotTestCase{\n                .inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::boolean(),\n                                    \"[true, false, null, false, false]\"))},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .outputs = {test::NamedTensor(\n                    \"x_hat\", TensorFrom(arrow::boolean(),\n                                        \"[false, true, null, true, true]\"))}},\n            NotTestCase{\n                .inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::boolean(),\n                                    \"[true, false, true, false, false]\"))},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\n                    \"x_hat\", TensorFrom(arrow::boolean(),\n                                        \"[false, true, false, true, true]\"))}}\n            // ,\n            // // testcase  with empty inputs\n            // NotTestCase{.inputs = {test::NamedTensor(\n            //                 \"x\", TensorFrom(arrow::boolean(), \"[]\"))},\n            //             .input_status = pb::TENSORSTATUS_SECRET,\n            //             .outputs = {test::NamedTensor(\n            //                 \"x_hat\", TensorFrom(arrow::boolean(),\n            //                 \"[]\"))}}\n            )));\n\nTEST_P(NotTest, Works) {\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  if (tc.input_status == pb::TENSORSTATUS_PRIVATE) {\n    Not alice_op;\n    EXPECT_NO_THROW({ alice_op.Run(ctx_ptrs[0]); });\n\n    auto* tensor_table = ctx_ptrs[0]->GetTensorTable();\n    for (const auto& named_tensor : tc.outputs) {\n      auto t = tensor_table->GetTensor(named_tensor.name);\n      ASSERT_TRUE(t != nullptr) << named_tensor.name << \" not found\";\n\n      auto expect_out_arr = named_tensor.tensor->ToArrowChunkedArray();\n      auto actual_out_arr = t->ToArrowChunkedArray();\n      EXPECT_TRUE(actual_out_arr->ApproxEquals(*expect_out_arr))\n          << \"\\nexpect result = \" << expect_out_arr->ToString()\n          << \"\\nbut actual got result = \" << actual_out_arr->ToString();\n    }\n  } else {\n    EXPECT_NO_THROW(test::RunAsync<Not>(ctx_ptrs));\n\n    for (const auto& named_tensor : tc.outputs) {\n      TensorPtr t = nullptr;\n      EXPECT_NO_THROW({ t = test::RevealSecret(ctx_ptrs, named_tensor.name); });\n      ASSERT_TRUE(t != nullptr);\n      auto expect_out_arr = named_tensor.tensor->ToArrowChunkedArray();\n      auto actual_out_arr = t->ToArrowChunkedArray();\n      EXPECT_TRUE(actual_out_arr->Equals(expect_out_arr))\n          << \"\\nexpect result = \" << expect_out_arr->ToString()\n          << \"\\nbut actual got result = \" << actual_out_arr->ToString();\n    }\n  }\n}\n\npb::ExecNode NotTest::MakeExecNode(const NotTestCase& tc) {\n  test::ExecNodeBuilder builder(Not::kOpType);\n\n  builder.SetNodeName(\"not-test\");\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    auto t = test::MakeTensorReference(\n        named_tensor.name, named_tensor.tensor->Type(), tc.input_status);\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(Not::kIn, inputs);\n\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.outputs.size(); ++i) {\n    auto t = test::MakeTensorAs(tc.outputs[i].name, inputs[i]);\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(Not::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid NotTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const NotTestCase& tc) {\n  if (tc.input_status == pb::TENSORSTATUS_PRIVATE) {\n    test::FeedInputsAsPrivate(ctxs[0], tc.inputs);\n  } else {\n    test::FeedInputsAsSecret(ctxs, tc.inputs);\n  }\n}\n\n// testcases for LogicalAnd & LogicalOr\n\nINSTANTIATE_TEST_SUITE_P(\n    LogicalBatchTest, BinaryComputeInSecretTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{\n                .op_type = LogicalAnd::kOpType,\n                .left_inputs =\n                    {test::NamedTensor(\n                         \"x1\", TensorFrom(arrow::boolean(),\n                                          \"[true, false, true, false]\")),\n                     test::NamedTensor(\n                         \"x2\", TensorFrom(arrow::boolean(),\n                                          \"[false, false, true, false]\"))},\n                .left_input_status = pb::TENSORSTATUS_SECRET,\n                .right_inputs =\n                    {test::NamedTensor(\n                         \"y1\", TensorFrom(arrow::boolean(),\n                                          \"[true, true, false, false]\")),\n                     test::NamedTensor(\"y2\",\n                                       TensorFrom(arrow::boolean(),\n                                                  \"[true, true, true, true]\"))},\n                .right_input_status = pb::TENSORSTATUS_SECRET,\n                .outputs = {test::NamedTensor(\n                                \"z1\",\n                                TensorFrom(arrow::boolean(),\n                                           \"[true, false, false, false]\")),\n                            test::NamedTensor(\n                                \"z2\",\n                                TensorFrom(arrow::boolean(),\n                                           \"[false, false, true, false]\"))},\n                .output_status = pb::TENSORSTATUS_SECRET},\n            BinaryTestCase{.op_type = LogicalOr::kOpType,\n                           .left_inputs = {test::NamedTensor(\n                               \"x1\", TensorFrom(arrow::boolean(),\n                                                \"[true, false, true, false]\"))},\n                           .left_input_status = pb::TENSORSTATUS_SECRET,\n                           .right_inputs = {test::NamedTensor(\n                               \"y1\", TensorFrom(arrow::boolean(),\n                                                \"[true, true, false, false]\"))},\n                           .right_input_status = pb::TENSORSTATUS_SECRET,\n                           .outputs = {test::NamedTensor(\n                               \"z1\", TensorFrom(arrow::boolean(),\n                                                \"[true, true, true, false]\"))},\n                           .output_status = pb::TENSORSTATUS_SECRET},\n            // testcase with empty inputs\n            BinaryTestCase{.op_type = LogicalAnd::kOpType,\n                           .left_inputs = {test::NamedTensor(\n                               \"x1\", TensorFrom(arrow::boolean(), \"[]\"))},\n                           .left_input_status = pb::TENSORSTATUS_SECRET,\n                           .right_inputs = {test::NamedTensor(\n                               \"y1\", TensorFrom(arrow::boolean(), \"[]\"))},\n                           .right_input_status = pb::TENSORSTATUS_SECRET,\n                           .outputs = {test::NamedTensor(\n                               \"z1\", TensorFrom(arrow::boolean(), \"[]\"))},\n                           .output_status = pb::TENSORSTATUS_SECRET},\n            BinaryTestCase{.op_type = LogicalOr::kOpType,\n                           .left_inputs = {test::NamedTensor(\n                               \"x1\", TensorFrom(arrow::boolean(), \"[]\"))},\n                           .left_input_status = pb::TENSORSTATUS_SECRET,\n                           .right_inputs = {test::NamedTensor(\n                               \"y1\", TensorFrom(arrow::boolean(), \"[]\"))},\n                           .right_input_status = pb::TENSORSTATUS_SECRET,\n                           .outputs = {test::NamedTensor(\n                               \"z1\", TensorFrom(arrow::boolean(), \"[]\"))},\n                           .output_status = pb::TENSORSTATUS_SECRET})),\n    TestParamNameGenerator(BinaryComputeInSecretTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    LogicalBatchTest, BinaryComputeInPlainTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            BinaryTestCase{.op_type = LogicalAnd::kOpType,\n                           .left_inputs = {test::NamedTensor(\n                               \"x1\", TensorFrom(arrow::boolean(),\n                                                \"[true, false, true, null]\"))},\n                           .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                           .right_inputs = {test::NamedTensor(\n                               \"y1\", TensorFrom(arrow::boolean(),\n                                                \"[true, true, null, false]\"))},\n                           .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                           .outputs = {test::NamedTensor(\n                               \"z1\", TensorFrom(arrow::boolean(),\n                                                \"[true, false, null, false]\"))},\n                           .output_status = pb::TENSORSTATUS_PRIVATE},\n            BinaryTestCase{.op_type = LogicalOr::kOpType,\n                           .left_inputs = {test::NamedTensor(\n                               \"x1\", TensorFrom(arrow::boolean(),\n                                                \"[true, false, true, null]\"))},\n                           .left_input_status = pb::TENSORSTATUS_PRIVATE,\n                           .right_inputs = {test::NamedTensor(\n                               \"y1\", TensorFrom(arrow::boolean(),\n                                                \"[true, true, null, false]\"))},\n                           .right_input_status = pb::TENSORSTATUS_PRIVATE,\n                           .outputs = {test::NamedTensor(\n                               \"z1\", TensorFrom(arrow::boolean(),\n                                                \"[true, true, true, null]\"))},\n                           .output_status = pb::TENSORSTATUS_PRIVATE})),\n    TestParamNameGenerator(BinaryComputeInPlainTest));\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/make_private.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/make_private.h\"\n\n#include \"engine/core/string_tensor_builder.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string MakePrivate::kOpType = \"MakePrivate\";\n\nconst std::string& MakePrivate::Type() const { return kOpType; }\n\nvoid MakePrivate::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"MakePrivate input {} and output {} should have the same size\",\n               kIn, kOut);\n  // TODO(shunde.csd): support TENSORSTATUS_CIPHER inputs\n  YACL_ENFORCE(\n      util::AreTensorsStatusEqualAndOneOf(\n          inputs, {pb::TENSORSTATUS_SECRET, pb::TENSORSTATUS_PUBLIC}),\n      \"MakePrivate input tensor's status should all be secret or public\");\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(outputs, pb::TENSORSTATUS_PRIVATE),\n               \"MakePrivate output tensor's status should all be private\");\n\n  std::vector<std::string> reveal_to_parties =\n      ctx->GetStringValuesFromAttribute(kRevealToAttr);\n  YACL_ENFORCE(reveal_to_parties.size() == 1,\n               \"MakePrivate operator attribute {} should have exactly 1 \"\n               \"element, but got {}\",\n               kRevealToAttr, reveal_to_parties.size());\n}\n\nvoid MakePrivate::Execute(ExecContext* ctx) {\n  auto reveal_to_party = ctx->GetStringValueFromAttribute(kRevealToAttr);\n  auto reveal_to_rank = ctx->GetSession()->GetPartyRank(reveal_to_party);\n  YACL_ENFORCE(reveal_to_rank != -1, \"unknown rank for party {}\",\n               reveal_to_party);\n\n  bool reveal_to_me = ctx->GetSession()->SelfPartyCode() == reveal_to_party;\n\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  util::SpuOutfeedHelper io(ctx->GetSession()->GetSpuContext(),\n                            ctx->GetSession()->GetDeviceSymbols());\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    TensorPtr t;\n    if (util::IsTensorStatusMatched(input_pbs[i], pb::TENSORSTATUS_SECRET)) {\n      t = io.RevealTo(input_pbs[i].name(), reveal_to_rank);\n      if (reveal_to_me &&\n          input_pbs[i].elem_type() == pb::PrimitiveDataType::STRING) {\n        YACL_ENFORCE(t);\n        t = ctx->GetSession()->HashToString(*t);\n      }\n    } else {\n      auto spu_io =\n          util::SpuOutfeedHelper(ctx->GetSession()->GetSpuContext(),\n                                 ctx->GetSession()->GetDeviceSymbols());\n      t = spu_io.DumpPublic(input_pbs[i].name());\n      YACL_ENFORCE(t);\n      if (input_pbs[i].elem_type() == pb::PrimitiveDataType::STRING) {\n        t = RevealPublicString(ctx, t, reveal_to_me, reveal_to_rank);\n      }\n    }\n\n    if (reveal_to_me) {\n      YACL_ENFORCE(t);\n      ctx->GetTensorTable()->AddTensor(output_pbs[i].name(), std::move(t));\n    }\n  }\n}\n\nTensorPtr MakePrivate::RevealPublicString(ExecContext* ctx, const TensorPtr& t,\n                                          bool reveal_to_me,\n                                          size_t reveal_to_rank) {\n  // TODO(jingshi): optimization: remove \"__null__\" in string_t to reduce\n  // network data interaction\n  auto string_t = ctx->GetSession()->HashToString(*t);\n  auto proto_t = std::make_shared<pb::Tensor>();\n  util::CopyValuesToProto(string_t, proto_t.get());\n  std::string content;\n  YACL_ENFORCE(proto_t->SerializeToString(&content));\n  auto contents = yacl::link::Gather(ctx->GetSession()->GetLink(),\n                                     yacl::ByteContainerView(content),\n                                     reveal_to_rank, \"string_make_private\");\n\n  if (!reveal_to_me) {\n    return nullptr;\n  }\n\n  std::vector<pb::Tensor> proto_ts;\n  for (const auto& content : contents) {\n    pb::Tensor proto_t;\n    YACL_ENFORCE(proto_t.ParseFromArray(content.data(), content.size()));\n    proto_ts.push_back(proto_t);\n  }\n  YACL_ENFORCE(proto_ts.size() > 0);\n  int row_num = proto_ts[0].string_data_size();\n  for (size_t rank = 1; rank < proto_ts.size(); ++rank) {\n    YACL_ENFORCE(proto_ts[rank].string_data_size() == row_num,\n                 \"rank#{} row_num={} not equal to rank#0 row_num={}\", rank,\n                 proto_ts[rank].string_data_size(), row_num);\n  }\n\n  StringTensorBuilder builder;\n  const std::string kStringPlaceHolder = \"__null__\";\n  for (int i = 0; i < row_num; ++i) {\n    std::string tmp = proto_ts[0].string_data(i);\n    for (size_t j = 1; j < proto_ts.size(); ++j) {\n      if (proto_ts[j].string_data(i) != kStringPlaceHolder) {\n        tmp = proto_ts[j].string_data(i);\n      }\n    }\n    builder.Append(tmp);\n  }\n  TensorPtr result;\n  builder.Finish(&result);\n\n  return result;\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/make_private.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n// Reveal the secret data\nclass MakePrivate : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n  // attrs\n  static constexpr char kRevealToAttr[] = \"reveal_to\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static TensorPtr RevealPublicString(ExecContext* ctx, const TensorPtr& t,\n                                      bool reveal_to_me, size_t reveal_to_rank);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/make_private_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/make_private.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct MakePrivateTestCase {\n  std::vector<test::NamedTensor> inputs;\n  pb::TensorStatus input_status;\n  std::string reveal_to;\n  std::vector<std::string> output_names;\n};\n\nclass MakePrivateTest\n    : public testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, MakePrivateTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const MakePrivateTestCase& tc);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const MakePrivateTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    MakePrivateBatchTest, MakePrivateTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            MakePrivateTestCase{\n                .inputs = {test::NamedTensor(\n                               \"x\", TensorFrom(arrow::large_utf8(),\n                                               R\"json([\"A\", \"B\", \"C\"])json\")),\n                           test::NamedTensor(\n                               \"y\", TensorFrom(arrow::int64(),\n                                               \"[42, -121, 9527, 1498672]\"))},\n                .input_status = pb::TENSORSTATUS_PUBLIC,\n                .reveal_to = \"bob\",\n                .output_names = {\"x_hat\", \"y_hat\"}},\n            MakePrivateTestCase{\n                .inputs =\n                    {test::NamedTensor(\"x\",\n                                       TensorFrom(arrow::int64(),\n                                                  \"[42, -121, 9527, 1498672]\")),\n                     test::NamedTensor(\"y\",\n                                       TensorFrom(arrow::float32(),\n                                                  \"[1.234, 0, -1.5, 2.75]\")),\n                     test::NamedTensor(\n                         \"z\", TensorFrom(arrow::large_utf8(),\n                                         R\"json([\"X\", \"Y\", \"ZZZ\"])json\")),\n                     test::NamedTensor(\n                         \"k\",\n                         TensorFrom(arrow::boolean(),\n                                    R\"json([true, false, false, false])json\"))},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .reveal_to = \"alice\",\n                .output_names = {\"x_hat\", \"y_hat\", \"z_hat\", \"k_hat\"}},\n            MakePrivateTestCase{\n                .inputs = {test::NamedTensor(\n                               \"x\", TensorFrom(arrow::int64(),\n                                               \"[42, -121, 9527, 1498672]\")),\n                           test::NamedTensor(\n                               \"y\", TensorFrom(arrow::float32(),\n                                               \"[1.234, 0, -1.5, 2.75]\"))},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .reveal_to = \"bob\",\n                .output_names = {\"x_hat\", \"y_hat\"}})),\n    TestParamNameGenerator(MakePrivateTest));\n\nTEST_P(MakePrivateTest, Works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  EXPECT_NO_THROW(test::RunAsync<MakePrivate>(ctx_ptrs));\n\n  // Then\n  auto* tensor_table = exec_ctxs[0].GetSession()->GetTensorTable();\n  for (size_t idx = 1; idx < exec_ctxs.size(); ++idx) {\n    if (tc.reveal_to == exec_ctxs[idx].GetSession()->SelfPartyCode()) {\n      tensor_table = exec_ctxs[idx].GetSession()->GetTensorTable();\n    }\n  }\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto tensor = tensor_table->GetTensor(tc.output_names[i]);\n    EXPECT_TRUE(tensor != nullptr);\n\n    EXPECT_TRUE(tensor->ToArrowChunkedArray()->ApproxEquals(\n        *tc.inputs[i].tensor->ToArrowChunkedArray()));\n  }\n}\n\n/// =====================\n/// MakePrivateTest impl\n/// =====================\n\npb::ExecNode MakePrivateTest::MakeExecNode(const MakePrivateTestCase& tc) {\n  test::ExecNodeBuilder builder(MakePrivate::kOpType);\n\n  builder.SetNodeName(\"make-private-test\");\n  builder.AddStringAttr(MakePrivate::kRevealToAttr, tc.reveal_to);\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    auto t = test::MakeTensorReference(\n        named_tensor.name, named_tensor.tensor->Type(), tc.input_status);\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(MakePrivate::kIn, inputs);\n\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto t = test::MakePrivateTensorReference(tc.output_names[i],\n                                              inputs[i].elem_type());\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(MakePrivate::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid MakePrivateTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                                 const MakePrivateTestCase& tc) {\n  if (tc.input_status == pb::TENSORSTATUS_SECRET) {\n    test::FeedInputsAsSecret(ctxs, tc.inputs);\n  } else {\n    test::FeedInputsAsPublic(ctxs, tc.inputs);\n  }\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/make_public.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/make_public.h\"\n\n#include \"libspu/device/symbol_table.h\"\n#include \"libspu/kernel/hal/type_cast.h\"\n\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string MakePublic::kOpType(\"MakePublic\");\nconst std::string& MakePublic::Type() const { return kOpType; }\n\nvoid MakePublic::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  YACL_ENFORCE(inputs.size() > 0, \"input size cannot be 0\");\n  const auto& outputs = ctx->GetOutput(kOut);\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"inputs' size={} and outputs' size={} not equal\", inputs.size(),\n               outputs.size());\n\n  YACL_ENFORCE(util::AreTensorsStatusEqualAndOneOf(\n                   inputs, {pb::TENSORSTATUS_PRIVATE, pb::TENSORSTATUS_SECRET}),\n               \"inputs' status are not equal and one of private/secret\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(outputs, pb::TENSORSTATUS_PUBLIC),\n               \"outputs' status are not all public\");\n}\n\nvoid MakePublic::Execute(ExecContext* ctx) {\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  const auto& input_status = util::GetTensorStatus(input_pbs[0]);\n  if (input_status == pb::TENSORSTATUS_PRIVATE) {\n    PrivateToPublic(ctx, input_pbs, output_pbs);\n  } else if (input_status == pb::TENSORSTATUS_SECRET) {\n    SecretToPublic(ctx, input_pbs, output_pbs);\n  } else {\n    YACL_THROW(\"input status={} not support in make_public\",\n               pb::TensorStatus_Name(input_status));\n  }\n}\n\nvoid MakePublic::PrivateToPublic(ExecContext* ctx,\n                                 const RepeatedPbTensor& inputs,\n                                 const RepeatedPbTensor& outputs) {\n  spu::device::ColocatedIo cio(ctx->GetSession()->GetSpuContext());\n  util::SpuInfeedHelper infeed_helper(&cio);\n\n  for (int i = 0; i < inputs.size(); ++i) {\n    const auto& in_name = inputs[i].name();\n    auto in_t = ctx->GetTensorTable()->GetTensor(in_name);\n\n    if (in_t != nullptr) {\n      // NOTE: if tensor' type is string, we should convert it to\n      // integer first, currently use hash value of string.\n      if (in_t->Type() == pb::PrimitiveDataType::STRING) {\n        in_t = ctx->GetSession()->StringToHash(*in_t);\n      }\n      const auto& out_name = outputs[i].name();\n      infeed_helper.InfeedTensorAsPublic(out_name, *in_t);\n    }\n  }\n  infeed_helper.Sync();\n\n  // merge symbols\n  auto& symbols = cio.deviceSymbols();\n  ctx->GetSession()->MergeDeviceSymbolsFrom(symbols);\n}\n\nvoid MakePublic::SecretToPublic(ExecContext* ctx,\n                                const RepeatedPbTensor& inputs,\n                                const RepeatedPbTensor& outputs) {\n  auto* symbols = ctx->GetSession()->GetDeviceSymbols();\n  for (int i = 0; i < inputs.size(); ++i) {\n    const auto& in_name = inputs[i].name();\n    auto secret_in_value =\n        symbols->getVar(util::SpuVarNameEncoder::GetValueName(in_name));\n\n    auto* sctx = ctx->GetSession()->GetSpuContext();\n    auto public_out_value = spu::kernel::hal::reveal(sctx, secret_in_value);\n\n    const auto& out_name = outputs[i].name();\n    symbols->setVar(util::SpuVarNameEncoder::GetValueName(out_name),\n                    public_out_value);\n\n#ifdef SCQL_WITH_NULL\n    auto secret_in_validity =\n        symbols->getVar(util::SpuVarNameEncoder::GetValidityName(in_name));\n\n    auto public_out_validity =\n        spu::kernel::hal::reveal(sctx, secret_in_validity);\n\n    symbols->setVar(util::SpuVarNameEncoder::GetValidityName(out_name),\n                    public_out_validity);\n#endif  // SCQL_WITH_NULL\n  }\n}\n\n};  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/make_public.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/// @brief MakePublic transfer private/secret data to public in spu\nclass MakePublic : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static void PrivateToPublic(ExecContext* ctx, const RepeatedPbTensor& inputs,\n                              const RepeatedPbTensor& outputs);\n\n  static void SecretToPublic(ExecContext* ctx, const RepeatedPbTensor& inputs,\n                             const RepeatedPbTensor& outputs);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/make_public_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/make_public.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n#include \"engine/util/spu_io.h\"\n\nnamespace scql::engine::op {\n\nstruct MakePublicTestCase {\n  std::vector<test::NamedTensor> inputs;\n  pb::TensorStatus input_status;\n  std::vector<std::string> output_names;\n};\n\nclass MakePublicTest\n    : public testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, MakePublicTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const MakePublicTestCase& tc);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const MakePublicTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    MakePublicBatchTest, MakePublicTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            MakePublicTestCase{\n                .inputs =\n                    {test::NamedTensor(\"x\", TensorFrom(arrow::int64(),\n                                                       \"[1,2,3,4,5,6,7,8]\")),\n                     test::NamedTensor(\n                         \"y\", TensorFrom(\n                                  arrow::float32(),\n                                  \"[1.1025, 100.245, -10.2, 0.34, 3.1415926]\")),\n                     test::NamedTensor(\n                         \"z\", TensorFrom(arrow::large_utf8(),\n                                         R\"json([\"A\", \"B\", \"C\"])json\"))},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_names = {\"x_hat\", \"y_hat\", \"z_hat\"}},\n            MakePublicTestCase{\n                .inputs =\n                    {test::NamedTensor(\n                         \"x\", TensorFrom(arrow::int64(), \"[1,2,3,4,5,6,7,8]\")),\n                     test::NamedTensor(\n                         \"y\",\n                         TensorFrom(\n                             arrow::float32(),\n                             \"[1.1025, 100.245, -10.2, 0.34, 3.1415926]\"))},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output_names = {\"x_hat\", \"y_hat\"}})),\n    TestParamNameGenerator(MakePublicTest));\n\nTEST_P(MakePublicTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  EXPECT_NO_THROW(test::RunAsync<MakePublic>(ctx_ptrs));\n\n  auto check_out = [&](ExecContext* ctx, const TensorPtr& in,\n                       const std::string& out_name) {\n    auto input_arr = in->ToArrowChunkedArray();\n    ASSERT_NE(nullptr, input_arr);\n\n    auto* sctx = ctx->GetSession()->GetSpuContext();\n    auto* device_symbols = ctx->GetSession()->GetDeviceSymbols();\n    util::SpuOutfeedHelper outfeed_helper(sctx, device_symbols);\n    auto output = outfeed_helper.DumpPublic(out_name);\n    ASSERT_NE(nullptr, output) << \"Output name: \" << out_name;\n    // convert hash to string for string tensor in spu\n    if (in->Type() == pb::PrimitiveDataType::STRING) {\n      output = ctx->GetSession()->HashToString(*output);\n    }\n    auto output_arr = output->ToArrowChunkedArray();\n    ASSERT_NE(nullptr, output_arr);\n\n    EXPECT_EQ(output_arr->type(), input_arr->type());\n    EXPECT_TRUE(output_arr->ApproxEquals(*input_arr))\n        << \"actual output = \" << output_arr->ToString()\n        << \", expect = \" << input_arr->ToString();\n  };\n\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    const auto& output_name = tc.output_names[i];\n    for (size_t idx = 0; idx < ctx_ptrs.size(); ++idx) {\n      if (tc.inputs[i].tensor->Type() == pb::PrimitiveDataType::STRING &&\n          idx > 0) {\n        continue;  // only alice know the origin string of hash\n      }\n      check_out(ctx_ptrs[idx], tc.inputs[i].tensor, output_name);\n    }\n  }\n}\n\n/// ===================\n/// MakePublicTest impl\n/// ===================\n\npb::ExecNode MakePublicTest::MakeExecNode(const MakePublicTestCase& tc) {\n  test::ExecNodeBuilder builder(MakePublic::kOpType);\n\n  builder.SetNodeName(\"make-public-test\");\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    pb::Tensor t;\n    if (tc.input_status == pb::TENSORSTATUS_PRIVATE) {\n      t = test::MakePrivateTensorReference(named_tensor.name,\n                                           named_tensor.tensor->Type());\n    } else {\n      t = test::MakeSecretTensorReference(named_tensor.name,\n                                          named_tensor.tensor->Type());\n    }\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(MakePublic::kIn, inputs);\n\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto t = test::MakeTensorReference(\n        tc.output_names[i], inputs[i].elem_type(), pb::TENSORSTATUS_PUBLIC);\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(MakePublic::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid MakePublicTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                                const MakePublicTestCase& tc) {\n  if (tc.input_status == pb::TENSORSTATUS_PRIVATE) {\n    test::FeedInputsAsPrivate(ctxs[0], tc.inputs);\n  } else {\n    test::FeedInputsAsSecret(ctxs, tc.inputs);\n  }\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/make_share.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/make_share.h\"\n\n#include \"libspu/device/io.h\"\n\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string MakeShare::kOpType(\"MakeShare\");\n\nconst std::string& MakeShare::Type() const { return kOpType; }\n\nvoid MakeShare::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"MakeShare input {} and output {} should have the same size\",\n               kIn, kOut);\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   inputs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"MakeShare input tensors' status should all be private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   outputs, pb::TensorStatus::TENSORSTATUS_SECRET),\n               \"MakeShare output tensors' status should all be secret\");\n}\n\nvoid MakeShare::Execute(ExecContext* ctx) {\n  spu::device::ColocatedIo cio(ctx->GetSession()->GetSpuContext());\n  util::SpuInfeedHelper infeed_helper(&cio);\n\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    const auto& input_pb = input_pbs[i];\n    const auto& output_pb = output_pbs[i];\n\n    auto in_t = ctx->GetTensorTable()->GetTensor(input_pb.name());\n    if (in_t == nullptr) {\n      // does not own the tensor, skip it\n      continue;\n    }\n    // NOTE: if tensor' type is string, we should convert it to\n    // integer first, currently use hash value of string.\n    if (in_t->Type() == pb::PrimitiveDataType::STRING) {\n      in_t = ctx->GetSession()->StringToHash(*in_t);\n    }\n    infeed_helper.InfeedTensorAsSecret(output_pb.name(), *in_t);\n  }\n\n  infeed_helper.Sync();\n\n  // merge symbols\n  auto& symbols = cio.deviceSymbols();\n\n  ctx->GetSession()->MergeDeviceSymbolsFrom(symbols);\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/make_share.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/// @brief MakeShare transfer private (plaintext) data from data owner to SPU\n/// (encrypted in secret-sharing)\nclass MakeShare : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/make_share_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/make_share.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct MakeShareTestCase {\n  std::vector<test::NamedTensor> inputs;\n  // private input inputs[i] owns by party who's rank = owners[i]\n  std::vector<size_t> owners;\n  std::vector<std::string> output_names;\n};\n\nclass MakeShareTest\n    : public testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, MakeShareTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const MakeShareTestCase& tc);\n  static void FeedInputs(ExecContext* ctx, const MakeShareTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    MakeShareBatchTest, MakeShareTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            MakeShareTestCase{\n                .inputs = {test::NamedTensor(\n                               \"x\", TensorFrom(arrow::large_utf8(),\n                                               R\"json([\"A\", \"B\", \"C\"])json\")),\n                           test::NamedTensor(\n                               \"y\", TensorFrom(arrow::large_utf8(),\n                                               R\"json([\"X\", \"Y\", \"Z\"])json\"))},\n                .owners = {0, 1},\n                .output_names = {\"x_hat\", \"y_hat\"}},\n            MakeShareTestCase{\n                .inputs =\n                    {test::NamedTensor(\"x\", TensorFrom(arrow::int64(),\n                                                       \"[1,2,3,4,5,6,7,8]\")),\n                     test::NamedTensor(\n                         \"y\",\n                         TensorFrom(\n                             arrow::float32(),\n                             \"[1.1025, 100.245, -10.2, 0.34, 3.1415926]\"))},\n                .owners = {0, 1},\n                .output_names = {\"x_hat\", \"y_hat\"}},\n            MakeShareTestCase{\n                .inputs = {test::NamedTensor(\n                               \"x\", TensorFrom(arrow::boolean(),\n                                               \"[true, false, true, true]\")),\n                           test::NamedTensor(\n                               \"y\", TensorFrom(arrow::boolean(),\n                                               \"[false, false, false, true]\"))},\n                .owners = {0, 1},\n                .output_names = {\"x_hat\", \"y_hat\"}},\n            MakeShareTestCase{\n                .inputs = {test::NamedTensor(\"x\",\n                                             TensorFrom(arrow::int64(), \"[]\")),\n                           test::NamedTensor(\"y\", TensorFrom(arrow::boolean(),\n                                                             \"[]\"))},\n                .owners = {0, 1},\n                .output_names = {\"x_hat\", \"y_hat\"}})),\n    TestParamNameGenerator(MakeShareTest));\n\nTEST_P(MakeShareTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs[0], tc);\n  FeedInputs(ctx_ptrs[1], tc);\n\n  // When\n  EXPECT_NO_THROW(test::RunAsync<MakeShare>(ctx_ptrs));\n\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    TensorPtr t = nullptr;\n    EXPECT_NO_THROW({ t = test::RevealSecret(ctx_ptrs, tc.output_names[i]); });\n    // convert hash to string for string tensor in spu\n    if (tc.inputs[i].tensor->Type() == pb::PrimitiveDataType::STRING) {\n      auto ctx = tc.owners[i] == 0 ? exec_ctxs[0] : exec_ctxs[1];\n      t = ctx.GetSession()->HashToString(*t);\n    }\n\n    auto actual_output = t->ToArrowChunkedArray();\n\n    auto expect_output = tc.inputs[i].tensor->ToArrowChunkedArray();\n\n    EXPECT_TRUE(actual_output->ApproxEquals(*expect_output))\n        << \"actual output = \" << actual_output->ToString()\n        << \", expect output = \" << expect_output->ToString();\n  }\n}\n\n/// ===================\n/// MakeShareTest impl\n/// ===================\n\npb::ExecNode MakeShareTest::MakeExecNode(const MakeShareTestCase& tc) {\n  test::ExecNodeBuilder builder(MakeShare::kOpType);\n\n  builder.SetNodeName(\"make-share-test\");\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    auto t = test::MakePrivateTensorReference(named_tensor.name,\n                                              named_tensor.tensor->Type());\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(MakeShare::kIn, inputs);\n\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto t = test::MakeSecretTensorReference(tc.output_names[i],\n                                             inputs[i].elem_type());\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(MakeShare::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid MakeShareTest::FeedInputs(ExecContext* ctx, const MakeShareTestCase& tc) {\n  auto* tensor_table = ctx->GetTensorTable();\n\n  auto lctx = ctx->GetSession()->GetLink();\n  for (size_t i = 0; i < tc.owners.size(); ++i) {\n    if (lctx->Rank() == tc.owners[i]) {\n      tensor_table->AddTensor(tc.inputs[i].name, tc.inputs[i].tensor);\n    }\n  }\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/oblivious_group_agg.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/oblivious_group_agg.h\"\n\n#include <cstdint>\n#include <utility>\n#include <vector>\n\n#include \"libspu/kernel/hlo/basic_unary.h\"\n\n#include \"engine/util/prefix_sum.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nvoid ObliviousGroupAggBase::Validate(ExecContext* ctx) {\n  const auto& group = ctx->GetInput(kGroup);\n  YACL_ENFORCE(group.size() == 1, \"group size must be 1\");\n  const auto& inputs = ctx->GetInput(kIn);\n  YACL_ENFORCE(inputs.size() > 0, \"input size cannot be 0\");\n  const auto& outputs = ctx->GetOutput(kOut);\n  YACL_ENFORCE(outputs.size() == inputs.size(),\n               \"outputs' size={} not equal to inputs' size={}\", outputs.size(),\n               inputs.size());\n\n  YACL_ENFORCE(util::IsTensorStatusMatched(group[0], pb::TENSORSTATUS_SECRET),\n               \"group's status is not secret\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(inputs, pb::TENSORSTATUS_SECRET),\n               \"inputs' status are not all secret\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(outputs, pb::TENSORSTATUS_SECRET),\n               \"outputs' status are not all secret\");\n}\n\nvoid ObliviousGroupAggBase::Execute(ExecContext* ctx) {\n  InitAttribute(ctx);\n\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto group_value = TransferGroupMask(sctx, ctx->GetInputValue(kGroup));\n\n  auto values = ctx->GetInputValues(kIn);\n  std::vector<spu::Value> results;\n  results.reserve(values.size());\n\n  for (const auto& value : values) {\n    spu::Value result;\n    if (RowCount(value) == 0) {\n      result = HandleEmptyInput(value);\n    } else {\n      result = CalculateResult(sctx, value, group_value);\n    }\n    results.push_back(std::move(result));\n  }\n\n  ctx->SetOutputValues(kOut, results);\n}\n\n// ===========================\n//   Sum impl\n// ===========================\n\nconst std::string ObliviousGroupSum::kOpType(\"ObliviousGroupSum\");\n\nconst std::string& ObliviousGroupSum::Type() const { return kOpType; }\n\nspu::Value ObliviousGroupSum::CalculateResult(spu::SPUContext* sctx,\n                                              const spu::Value& value,\n                                              const spu::Value& group) {\n  int64_t row_count = RowCount(value);\n  YACL_ENFORCE(row_count == RowCount(group));\n\n  spu::Value value_hat;\n\n  // NOTE: hack for boolean value.\n  if (value.dtype() == spu::DT_I1) {\n    value_hat = spu::kernel::hlo::Cast(sctx, value, value.vtype(), spu::DT_I64);\n  } else {\n    value_hat = value;\n  }\n\n  return util::Scan(\n      sctx, value_hat, group,\n      [&](const spu::Value& lhs_v, const spu::Value& lhs_gm,\n          const spu::Value& rhs_v, const spu::Value& rhs_gm) {\n        spu::Value new_v = spu::kernel::hlo::Add(\n            sctx, lhs_v, spu::kernel::hlo::Mul(sctx, lhs_gm, rhs_v));\n        spu::Value new_gm = spu::kernel::hlo::Mul(sctx, lhs_gm, rhs_gm);\n\n        return std::make_pair(new_v, new_gm);\n      });\n}\n\n// ===========================\n//   Count impl\n// ===========================\n\nconst std::string ObliviousGroupCount::kOpType(\"ObliviousGroupCount\");\n\nconst std::string& ObliviousGroupCount::Type() const { return kOpType; }\n\nspu::Value ObliviousGroupCount::CalculateResult(spu::SPUContext* sctx,\n                                                const spu::Value& value,\n                                                const spu::Value& group) {\n  int64_t row_count = RowCount(value);\n  YACL_ENFORCE(row_count == RowCount(group));\n\n  spu::Value ones = spu::kernel::hlo::Seal(\n      sctx,\n      spu::kernel::hlo::Constant(sctx, static_cast<int64_t>(1), value.shape()));\n\n  return util::Scan(\n      sctx, ones, group,\n      [&](const spu::Value& lhs_v, const spu::Value& lhs_gm,\n          const spu::Value& rhs_v, const spu::Value& rhs_gm) {\n        spu::Value new_v = spu::kernel::hlo::Add(\n            sctx, lhs_v, spu::kernel::hlo::Mul(sctx, lhs_gm, rhs_v));\n        spu::Value new_gm = spu::kernel::hlo::Mul(sctx, lhs_gm, rhs_gm);\n\n        return std::make_pair(new_v, new_gm);\n      });\n}\n\n// ===========================\n//   Avg impl\n// ===========================\n\nconst std::string ObliviousGroupAvg::kOpType(\"ObliviousGroupAvg\");\n\nconst std::string& ObliviousGroupAvg::Type() const { return kOpType; }\n\nspu::Value ObliviousGroupAvg::CalculateResult(spu::SPUContext* sctx,\n                                              const spu::Value& value,\n                                              const spu::Value& group) {\n  auto sum_result = ObliviousGroupSum().CalculateResult(sctx, value, group);\n  auto count_result = ObliviousGroupCount().CalculateResult(sctx, value, group);\n\n  if (sum_result.dtype() != spu::DT_F64) {\n    const auto sum_result_f64 = spu::kernel::hlo::Cast(\n        sctx, sum_result, sum_result.vtype(), spu::DT_F64);\n    return spu::kernel::hlo::Div(sctx, sum_result_f64, count_result);\n  } else {\n    return spu::kernel::hlo::Div(sctx, sum_result, count_result);\n  }\n}\n\n// ===========================\n//   Max impl\n// ===========================\n\nconst std::string ObliviousGroupMax::kOpType(\"ObliviousGroupMax\");\n\nconst std::string& ObliviousGroupMax::Type() const { return kOpType; }\n\nspu::Value ObliviousGroupMax::CalculateResult(spu::SPUContext* sctx,\n                                              const spu::Value& value,\n                                              const spu::Value& group) {\n  int64_t row_count = RowCount(value);\n  YACL_ENFORCE(row_count == RowCount(group));\n\n  return util::Scan(\n      sctx, value, group,\n      [&](const spu::Value& lhs_v, const spu::Value& lhs_gm,\n          const spu::Value& rhs_v, const spu::Value& rhs_gm) {\n        spu::Value new_v = spu::kernel::hlo::Select(\n            sctx, lhs_gm, spu::kernel::hlo::Max(sctx, lhs_v, rhs_v), lhs_v);\n        spu::Value new_gm = spu::kernel::hlo::Mul(sctx, lhs_gm, rhs_gm);\n\n        return std::make_pair(new_v, new_gm);\n      });\n}\n\n// ===========================\n//   Min impl\n// ===========================\n\nconst std::string ObliviousGroupMin::kOpType(\"ObliviousGroupMin\");\n\nconst std::string& ObliviousGroupMin::Type() const { return kOpType; }\n\nspu::Value ObliviousGroupMin::CalculateResult(spu::SPUContext* sctx,\n                                              const spu::Value& value,\n                                              const spu::Value& group) {\n  int64_t row_count = RowCount(value);\n  YACL_ENFORCE(row_count == RowCount(group));\n\n  return util::Scan(\n      sctx, value, group,\n      [&](const spu::Value& lhs_v, const spu::Value& lhs_gm,\n          const spu::Value& rhs_v, const spu::Value& rhs_gm) {\n        spu::Value new_v = spu::kernel::hlo::Select(\n            sctx, lhs_gm, spu::kernel::hlo::Min(sctx, lhs_v, rhs_v), lhs_v);\n        spu::Value new_gm = spu::kernel::hlo::Mul(sctx, lhs_gm, rhs_gm);\n\n        return std::make_pair(new_v, new_gm);\n      });\n}\n\n// ===========================\n//   PercentRank impl\n// ===========================\n\nconst std::string ObliviousPercentRank::kOpType(\"ObliviousPercentRank\");\nconst std::string& ObliviousPercentRank::Type() const { return kOpType; }\n\nspu::Value ObliviousPercentRank::CalculateResult(spu::SPUContext* sctx,\n                                                 const spu::Value& value,\n                                                 const spu::Value& partition) {\n  spu::Value count =\n      ObliviousGroupCount().CalculateResult(sctx, value, partition);\n\n  spu::Value inner_order_group_mark = TransferGroupMask(sctx, value);\n\n  spu::Value inner_count = ObliviousGroupCount().CalculateResult(\n      sctx, inner_order_group_mark, inner_order_group_mark);\n  spu::Value count_minus_inner_count =\n      spu::kernel::hlo::Sub(sctx, count, inner_count);\n  // rank = count - inner_count + 1\n  // rank_minus_1 = rank - 1\n  // rank_minus_1 = count - inner_count\n  spu::Value rank_minus_1 = count_minus_inner_count;\n  spu::Value reverted_partition = RevertGroupMaskTransfer(sctx, partition);\n  spu::Value reversed_mark = spu::kernel::hlo::Sub(\n      sctx, spu::kernel::hlo::Constant(sctx, 1, partition.shape()),\n      reverted_partition);\n\n  spu::Value total_count_minus_1 = spu::kernel::hlo::Sub(\n      sctx, count, spu::kernel::hlo::Constant(sctx, 1, count.shape()));\n  total_count_minus_1 = util::ExpandGroupValueReversely(\n      sctx, {total_count_minus_1}, reversed_mark)[0];\n  spu::Value ones = spu::kernel::hlo::Constant(sctx, static_cast<int64_t>(1),\n                                               rank_minus_1.shape());\n  total_count_minus_1 = spu::kernel::hlo::Max(sctx, ones, total_count_minus_1);\n  spu::Value float_rank = spu::kernel::hlo::Cast(\n      sctx, rank_minus_1, rank_minus_1.vtype(), spu::DataType::DT_F64);\n  return spu::kernel::hlo::Div(sctx, float_rank, total_count_minus_1);\n}\n\n// ===========================\n//   PercentileDisc impl\n// ===========================\n\nconst std::string ObliviousPercentileDisc::kOpType(\"ObliviousPercentileDisc\");\nconst std::string& ObliviousPercentileDisc::Type() const { return kOpType; }\n\nvoid ObliviousPercentileDisc::InitAttribute(ExecContext* ctx) {\n  percent_ = ctx->GetDoubleValueFromAttribute(kPercent);\n  YACL_ENFORCE(percent_ >= 0 && percent_ <= 1, \"percent must be in [0, 1]\");\n}\n\n// the group is in the format of [0, 1, 1, 0, 1, 1, 1]\nspu::Value ObliviousPercentileDisc::CalculateResult(spu::SPUContext* sctx,\n                                                    const spu::Value& value,\n                                                    const spu::Value& group) {\n  const double epsilon = 1e-9;\n  YACL_ENFORCE(percent_ >= 0 && percent_ <= 1, \"percent must be in [0, 1]\");\n  // percent = 1\n  if (1 - percent_ < epsilon) {\n    return ObliviousGroupMax().CalculateResult(sctx, value, group);\n  }\n\n  // percent = 0\n  if (percent_ < epsilon) {\n    return ObliviousGroupMin().CalculateResult(sctx, value, group);\n  }\n  spu::Value count = ObliviousGroupCount().CalculateResult(sctx, value, group);\n  spu::Value recovered_group = RevertGroupMaskTransfer(\n\n      sctx, group);  // reverse group from [0, 1, 1, 0, 1, 1, 1] to [0, 0, 1, 0,\n                     // 0, 0, 1]\n  spu::Value reversed_mark = spu::kernel::hlo::Sub(\n      sctx, spu::kernel::hlo::Constant(sctx, 1, group.shape()),\n      recovered_group);  // [0, 0, 1, 0, 0, 0, 1] to [1, 1, 0, 1, 1, 1, 0]\n  spu::Value percent_arr =\n      spu::kernel::hlo::Constant(sctx, percent_, group.shape());\n  // calculate the rank of the target percentile\n  spu::Value one = spu::kernel::hlo::Constant(sctx, 1, group.shape());\n  // target_pos = ceil(count * percent) - 1, but the count is start from 1, so\n  // the\n  // `-1` is no need here\n  spu::Value target_pos = spu::kernel::hlo::Ceil(\n      sctx, spu::kernel::hlo::Mul(sctx, count, percent_arr));\n  // index = rank * group, [0, 0, 0, index0, 0,..., 0, index1, 0, ...,0, indexn]\n  spu::Value index_values =\n      spu::kernel::hlo::Mul(sctx, target_pos, recovered_group);\n\n  auto expanded_index = util::ExpandGroupValueReversely(\n      sctx, {index_values},\n      reversed_mark);  // [index0, index0, index0, index1, index1, index1,\n                       // index1]\n  auto percentile_values = spu::kernel::hlo::Mul(\n      sctx, value,\n      spu::kernel::hlo::Equal(\n          sctx, expanded_index[0],\n          count));  // [0, arr[index0],...0, arr[index1], ..., 0]\n  return ObliviousGroupSum().CalculateResult(sctx, percentile_values, group);\n}\n\n// ===========================\n//   ObliviousRank impl\n// ===========================\nconst std::string ObliviousRank::kOpType(\"ObliviousRank\");\nconst std::string& ObliviousRank::Type() const { return kOpType; }\n\nspu::Value ObliviousRank::CalculateResult(\n    spu::SPUContext* sctx, const spu::Value& order_key_mark,\n    const spu::Value& partition_key_mark) {\n  spu::Value count = ObliviousGroupCount().CalculateResult(sctx, order_key_mark,\n                                                           partition_key_mark);\n\n  spu::Value inner_order_group_mark = TransferGroupMask(sctx, order_key_mark);\n\n  spu::Value inner_count = ObliviousGroupCount().CalculateResult(\n      sctx, inner_order_group_mark, inner_order_group_mark);\n  spu::Value count_minus_inner_count =\n      spu::kernel::hlo::Sub(sctx, count, inner_count);\n  // rank = count - inner_count + 1\n  spu::Value rank = spu::kernel::hlo::Add(\n      sctx, count_minus_inner_count,\n      spu::kernel::hlo::Constant(sctx, 1, count_minus_inner_count.shape()));\n\n  return rank;\n}\n};  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/oblivious_group_agg.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"libspu/kernel/hal/constants.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/basic_ternary.h\"\n#include \"libspu/kernel/hlo/casting.h\"\n#include \"libspu/kernel/hlo/const.h\"\n#include \"libspu/kernel/hlo/geometrical.h\"\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\nnamespace {\n\nint64_t RowCount(const spu::Value& value) {\n  return value.shape().size() > 0 ? value.shape()[0] : value.numel();\n}\n\n// IN  GroupMask: 1 means end of the group while 0 means other conditions.\n// OUT GroupMask: 0 means start of the group while 1 means other conditions.\n// e.g. IN: [0, 0, 1, 0, 0, 1, 0, 1, 0, 1]\n//      OUT:[0, 1, 1, 0, 1, 1, 0, 1, 0, 1]\nspu::Value TransferGroupMask(spu::SPUContext* ctx, const spu::Value& in) {\n  const int64_t row_cnt = in.shape()[0];\n  spu::Value in_not = spu::kernel::hlo::Sub(\n      ctx, spu::kernel::hlo::Constant(ctx, 1, in.shape()), in);\n\n  auto zero = spu::kernel::hal::zeros(ctx, in_not.dtype(), {1});\n  if (in_not.vtype() == spu::VIS_SECRET) {\n    zero = spu::kernel::hlo::Seal(ctx, zero);\n  }\n\n  return spu::kernel::hlo::Concatenate(\n      ctx, {zero, spu::kernel::hlo::Slice(ctx, in_not, {0}, {row_cnt - 1}, {})},\n      0);\n}\n\n// the inverse operation of the TransferGroupMask.\n// IN: [0, 1, 1, 0, 1, 1, 0, 1, 0, 1], must be in the format of\n// TransferGroupMask output. OUT:[0, 0, 1, 0, 0, 1, 0, 1, 0, 1]\nspu::Value RevertGroupMaskTransfer(spu::SPUContext* ctx, const spu::Value& in) {\n  const int64_t row_cnt = in.shape()[0];\n  auto zero = spu::kernel::hal::zeros(ctx, in.dtype(), {1});\n  if (in.vtype() == spu::VIS_SECRET) {\n    zero = spu::kernel::hlo::Seal(ctx, zero);\n  }\n\n  auto cut = spu::kernel::hlo::Slice(ctx, in, {1}, {row_cnt}, {});\n  auto in_not = spu::kernel::hlo::Concatenate(ctx, {cut, zero}, 0);\n  return spu::kernel::hlo::Sub(\n      ctx, spu::kernel::hlo::Constant(ctx, 1, in.shape()), in_not);\n}\n\n}  // namespace\n\nclass ObliviousGroupAggBase : public Operator {\n public:\n  static constexpr char kGroup[] = \"Group\";\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n public:\n  virtual spu::Value HandleEmptyInput(const spu::Value& in) { return in; }\n\n  virtual spu::Value CalculateResult(spu::SPUContext* sctx,\n                                     const spu::Value& value,\n                                     const spu::Value& group_value) = 0;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n\n  void Execute(ExecContext* ctx) override;\n  virtual void InitAttribute(ExecContext* ctx) {};\n};\n\nclass ObliviousGroupSum : public ObliviousGroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n public:\n  spu::Value HandleEmptyInput(const spu::Value& in) override {\n    // Sum(bool tensor) should return int64\n    if (in.dtype() == spu::DT_I1) {\n      return in.clone().setDtype(spu::DT_I64, true);\n    } else {\n      return in;\n    }\n  }\n\n  spu::Value CalculateResult(spu::SPUContext* sctx, const spu::Value& value,\n                             const spu::Value& group_value) override;\n};\n\nclass ObliviousGroupCount : public ObliviousGroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n public:\n  spu::Value HandleEmptyInput(const spu::Value& in) override {\n    return in.clone().setDtype(spu::DT_I64, true);\n  }\n\n  spu::Value CalculateResult(spu::SPUContext* sctx, const spu::Value& value,\n                             const spu::Value& group_value) override;\n};\n\nclass ObliviousGroupAvg : public ObliviousGroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n public:\n  spu::Value HandleEmptyInput(const spu::Value& in) override {\n    return in.clone().setDtype(spu::DT_F64, true);\n  }\n\n  spu::Value CalculateResult(spu::SPUContext* sctx, const spu::Value& value,\n                             const spu::Value& group_value) override;\n};\n\nclass ObliviousGroupMax : public ObliviousGroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n public:\n  spu::Value CalculateResult(spu::SPUContext* sctx, const spu::Value& value,\n                             const spu::Value& group_value) override;\n};\n\nclass ObliviousGroupMin : public ObliviousGroupAggBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n public:\n  spu::Value CalculateResult(spu::SPUContext* sctx, const spu::Value& value,\n                             const spu::Value& group_value) override;\n};\n// TODO(jingshi) : Add ObliviousGroupMedian.\n\nclass ObliviousPercentRank : public ObliviousGroupAggBase {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n public:\n  spu::Value HandleEmptyInput(const spu::Value& in) override {\n    return in.clone().setDtype(spu::DT_F64, true);\n  }\n\n  spu::Value CalculateResult(spu::SPUContext* sctx, const spu::Value& value,\n                             const spu::Value& partition_value) override;\n};\n\nclass ObliviousPercentileDisc : public ObliviousGroupAggBase {\n public:\n  static const std::string kOpType;\n  static constexpr char kPercent[] = \"percent\";\n  const std::string& Type() const override;\n\n public:\n  spu::Value CalculateResult(spu::SPUContext* sctx, const spu::Value& value,\n                             const spu::Value& group_value) override;\n\n protected:\n  void InitAttribute(ExecContext* ctx) override;\n\n private:\n  double percent_ = -1;\n};\n\nclass ObliviousRank : public ObliviousGroupAggBase {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n public:\n  spu::Value CalculateResult(spu::SPUContext* sctx, const spu::Value& value,\n                             const spu::Value& group_value) override;\n};\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/oblivious_group_agg_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/oblivious_group_agg.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/all_ops_register.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct ObliviousGroupAggTestCase {\n  std::string op_type;\n  std::vector<test::NamedTensor> inputs;\n  test::NamedTensor group;\n  std::vector<test::NamedTensor> outputs;\n  std::optional<std::pair<std::string, double>> double_attribute;\n};\n\nclass ObliviousGroupAggTest\n    : public testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, ObliviousGroupAggTestCase>> {\n protected:\n  void SetUp() override { RegisterAllOps(); }\n\n  static pb::ExecNode MakeExecNode(const ObliviousGroupAggTestCase& tc);\n};\n\nTEST_P(ObliviousGroupAggTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  test::FeedInputsAsSecret(ctx_ptrs, tc.inputs);\n  test::FeedInputsAsSecret(ctx_ptrs, {tc.group});\n\n  // When\n  EXPECT_NO_THROW(test::RunOpAsync(ctx_ptrs, [&]() {\n    return GetOpRegistry()->GetOperator(node.op_type());\n  }));\n\n  for (size_t i = 0; i < tc.inputs.size(); ++i) {\n    TensorPtr actual_output = nullptr;\n    EXPECT_NO_THROW(\n        { actual_output = test::RevealSecret(ctx_ptrs, tc.outputs[i].name); });\n    ASSERT_TRUE(actual_output != nullptr);\n    auto actual_arr = actual_output->ToArrowChunkedArray();\n    auto expect_arr = tc.outputs[i].tensor->ToArrowChunkedArray();\n    EXPECT_TRUE(actual_arr->ApproxEquals(\n        *expect_arr, arrow::EqualOptions::Defaults().atol(0.01)))\n        << \"\\nexpect result = \" << expect_arr->ToString()\n        << \"\\nbut actual got result = \" << actual_arr->ToString();\n  }\n}\n\n/// ===================\n/// ObliviousGroupAggTest impl\n/// ===================\n\npb::ExecNode ObliviousGroupAggTest::MakeExecNode(\n    const ObliviousGroupAggTestCase& tc) {\n  test::ExecNodeBuilder builder(tc.op_type);\n\n  if (tc.double_attribute.has_value()) {\n    builder.AddDoubleAttr(tc.double_attribute->first,\n                          tc.double_attribute->second);\n  }\n  builder.SetNodeName(\"oblivious-group-agg-test\");\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    pb::Tensor t = test::MakeSecretTensorReference(named_tensor.name,\n                                                   named_tensor.tensor->Type());\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(ObliviousGroupAggBase::kIn, inputs);\n\n  pb::Tensor t =\n      test::MakeSecretTensorReference(tc.group.name, tc.group.tensor->Type());\n  builder.AddInput(ObliviousGroupAggBase::kGroup, {t});\n\n  std::vector<pb::Tensor> outputs;\n  for (const auto& named_tensor : tc.outputs) {\n    pb::Tensor t = test::MakeSecretTensorReference(named_tensor.name,\n                                                   named_tensor.tensor->Type());\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(ObliviousGroupAggBase::kOut, outputs);\n\n  return builder.Build();\n}\n\n// =====================\n// TEST_SUITE: ObliviousGroupSum\n// =====================\n\nINSTANTIATE_TEST_SUITE_P(\n    ObliviousGroupSumTest, ObliviousGroupAggTest,\n    testing::Combine(\n        testing::Values(test::SpuRuntimeTestCase{spu::ProtocolKind::CHEETAH, 2},\n                        test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2},\n                        test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 3},\n                        test::SpuRuntimeTestCase{spu::ProtocolKind::ABY3, 3}),\n        testing::Values(\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupSum::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::boolean(), \"[true, false, true]\"))},\n                .group = test::NamedTensor(\"group\", TensorFrom(arrow::boolean(),\n                                                               \"[0, 0, 1]\")),\n                .outputs = {test::NamedTensor(\"out\", TensorFrom(arrow::int64(),\n                                                                \"[1, 1, 2]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupSum::kOpType,\n                .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::boolean(),\n                                                              \"[true]\"))},\n                .group = test::NamedTensor(\"group\",\n                                           TensorFrom(arrow::boolean(), \"[0]\")),\n                .outputs = {test::NamedTensor(\"out\", TensorFrom(arrow::int64(),\n                                                                \"[1]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupSum::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::int64(), \"[1, 1, 1, 1, 1]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1, 1, 2, 3, 1]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupSum::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::float32(),\n                                     \"[-3.14, 1.1, 10, 100, 31415.9]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float32(),\n                                      \"[-3.14, 1.1, 11.1, 111.1, 31415.9]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupSum::kOpType,\n                .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::float32(),\n                                                              \"[]\"))},\n                .group = test::NamedTensor(\"group\",\n                                           TensorFrom(arrow::boolean(), \"[]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float32(), \"[]\"))}})),\n    TestParamNameGenerator(ObliviousGroupAggTest));\n\n// =====================\n// TEST_SUITE: ObliviousGroupCount\n// =====================\n\nINSTANTIATE_TEST_SUITE_P(\n    ObliviousGroupCountTest, ObliviousGroupAggTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupCount::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1, 1, 2, 3, 1]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupCount::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::float32(),\n                                     \"[-3.14, 1.1, 10, 100, 31415.9]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1, 1, 2, 3, 1]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupCount::kOpType,\n                .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::float32(),\n                                                              \"[]\"))},\n                .group = test::NamedTensor(\"group\",\n                                           TensorFrom(arrow::boolean(), \"[]\")),\n                .outputs = {test::NamedTensor(\"out\", TensorFrom(arrow::int64(),\n                                                                \"[]\"))}})),\n    TestParamNameGenerator(ObliviousGroupAggTest));\n\n// =====================\n// TEST_SUITE: ObliviousGroupAvg\n// =====================\n\nINSTANTIATE_TEST_SUITE_P(\n    ObliviousGroupAvgTest, ObliviousGroupAggTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupAvg::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[1, 2, 2.5, 3, 5]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupAvg::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::float32(),\n                                     \"[-3.14, 1.3, 10, 100, 314.08]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(),\n                                      \"[-3.14, 1.3, 5.65, 37.1, 314.08]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupAvg::kOpType,\n                .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::float32(),\n                                                              \"[]\"))},\n                .group = test::NamedTensor(\"group\",\n                                           TensorFrom(arrow::boolean(), \"[]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[]\"))}})),\n    TestParamNameGenerator(ObliviousGroupAggTest));\n\n// =====================\n// TEST_SUITE: ObliviousGroupMax\n// =====================\n\nINSTANTIATE_TEST_SUITE_P(\n    ObliviousGroupMaxTest, ObliviousGroupAggTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupMax::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupMax::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::float32(),\n                                     \"[-3.14, 1.3, 10, 100, 314.08]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float32(),\n                                      \"[-3.14, 1.3, 10, 100, 314.08]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupMax::kOpType,\n                .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::float32(),\n                                                              \"[]\"))},\n                .group = test::NamedTensor(\"group\",\n                                           TensorFrom(arrow::boolean(), \"[]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float32(), \"[]\"))}})),\n    TestParamNameGenerator(ObliviousGroupAggTest));\n\n// =====================\n// TEST_SUITE: ObliviousGroupMin\n// =====================\n\nINSTANTIATE_TEST_SUITE_P(\n    ObliviousGroupMinTest, ObliviousGroupAggTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupMin::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1, 2, 2, 2, 5]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupMin::kOpType,\n                .inputs =\n                    {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                          \"[1, 2, 3, 4, 5]\")),\n                     test::NamedTensor(\n                         \"in_b\", TensorFrom(arrow::float32(),\n                                            \"[-3.14, 1.3, 10, 100, 314.08]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\")),\n                .outputs = {test::NamedTensor(\"out_a\",\n                                              TensorFrom(arrow::int64(),\n                                                         \"[1, 2, 2, 2, 5]\")),\n                            test::NamedTensor(\"out_b\",\n                                              TensorFrom(arrow::float32(),\n                                                         \"[-3.14, 1.3, 1.3, \"\n                                                         \"1.3, 314.08]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousGroupMin::kOpType,\n                .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::float32(),\n                                                              \"[]\"))},\n                .group = test::NamedTensor(\"group\",\n                                           TensorFrom(arrow::boolean(), \"[]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float32(), \"[]\"))}})),\n    TestParamNameGenerator(ObliviousGroupAggTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    ObliviousRankTest, ObliviousGroupAggTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(ObliviousGroupAggTestCase{\n            .op_type = ObliviousRank::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in\", TensorFrom(arrow::int64(), \"[1, 0, 1, 0, 1, 1, 1]\"))},\n            .group = test::NamedTensor(\n                \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 0, 1, 0, 1]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(), \"[1, 1, 1, 3, 3, 1, 2]\"))}})),\n    TestParamNameGenerator(ObliviousGroupAggTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    ObliviousPercentRankTest, ObliviousGroupAggTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousPercentRank::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::int64(), \"[1, 1, 1, 1, 1]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 0, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(),\n                                      \"[0.0, 0, 0.333, 0.666, 1.0]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousPercentRank::kOpType,\n                .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::int64(),\n                                                              \"[1]\"))},\n                .group = test::NamedTensor(\"group\",\n                                           TensorFrom(arrow::boolean(), \"[1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[0]\"))}},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousPercentRank::kOpType,\n                .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::int64(),\n                                                              \"[1,1]\"))},\n                .group = test::NamedTensor(\"group\", TensorFrom(arrow::boolean(),\n                                                               \"[1,1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[0.0,0.0]\"))}})),\n    TestParamNameGenerator(ObliviousGroupAggTest));\n\nstatic ObliviousGroupAggTestCase GenerateObliviousPercentileDiscTestCase(\n    double percentile, std::vector<int> groups) {\n  std::vector<int> in;\n  std::vector<int> out;\n  std::vector<int> group;\n  for (const auto group_size : groups) {\n    int count = 0;\n    std::vector<int> current_in;\n    while (count < group_size) {\n      if (count == group_size - 1) {\n        group.push_back(1);\n      } else {\n        group.push_back(0);\n      }\n      current_in.push_back(count);\n      count++;\n    }\n\n    int index = static_cast<int>(std::ceil(percentile * group_size)) - 1;\n    index = std::min(group_size - 1, index);\n    int value = current_in[index];\n    for (int i = 0; i < index; i++) {\n      out.push_back(0);\n    }\n\n    for (int i = index; i < group_size; i++) {\n      out.push_back(value);\n    }\n    in.insert(in.end(), current_in.begin(), current_in.end());\n  }\n\n  std::string in_str = \"[\";\n  std::string group_str = \"[\";\n  std::string out_str = \"[\";\n  for (size_t i = 0; i < in.size(); i++) {\n    in_str += std::to_string(in[i]);\n    group_str += std::to_string(group[i]);\n    out_str += std::to_string(out[i]);\n    if (i != in.size() - 1) {\n      in_str += \",\";\n      group_str += \",\";\n      out_str += \",\";\n    }\n  }\n\n  in_str += \"]\";\n  group_str += \"]\";\n  out_str += \"]\";\n\n  ObliviousGroupAggTestCase tc{\n      .op_type = ObliviousPercentileDisc::kOpType,\n      .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::int64(), in_str))},\n      .group =\n          test::NamedTensor(\"group\", TensorFrom(arrow::boolean(), group_str)),\n      .outputs = {test::NamedTensor(\"out\",\n                                    TensorFrom(arrow::int64(), out_str))},\n      .double_attribute =\n          std::make_pair(ObliviousPercentileDisc::kPercent, percentile)};\n  ;\n\n  return tc;\n}\n\nINSTANTIATE_TEST_SUITE_P(\n    ObliviousPercentileDiscTest, ObliviousGroupAggTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousPercentileDisc::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\",\n                    TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5, 6, 7, 8]\"))},\n                .group = test::NamedTensor(\n                    \"group\",\n                    TensorFrom(arrow::boolean(), \"[1, 0, 0, 0, 1, 0, 0, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\",\n                    TensorFrom(\n                        arrow::int64(),\n                        \"[1, 0, 3, 3, 3, 0, 7, 7]\"))},  // ceil(0.5*length)\n                                                        // - 1\n                .double_attribute =\n                    std::make_pair(ObliviousPercentileDisc::kPercent, 0.5)},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousPercentileDisc::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 0, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1, 2, 2, 2, 2]\"))},\n                .double_attribute =\n                    std::make_pair(ObliviousPercentileDisc::kPercent, 0)},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousPercentileDisc::kOpType,\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5]\"))},\n                .group = test::NamedTensor(\n                    \"group\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 0, 1]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5]\"))},\n                .double_attribute =\n                    std::make_pair(ObliviousPercentileDisc::kPercent, 1)},\n            ObliviousGroupAggTestCase{\n                .op_type = ObliviousPercentileDisc::kOpType,\n                .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::float32(),\n                                                              \"[]\"))},\n                .group = test::NamedTensor(\"group\",\n                                           TensorFrom(arrow::boolean(), \"[]\")),\n                .outputs = {test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float32(), \"[]\"))},\n                .double_attribute =\n                    std::make_pair(ObliviousPercentileDisc::kPercent, 0.5)},\n            GenerateObliviousPercentileDiscTestCase(0.343, {10, 100}),\n            GenerateObliviousPercentileDiscTestCase(0.43, {10, 100, 1234}),\n            GenerateObliviousPercentileDiscTestCase(0.3, {10, 100, 3215}))),\n    TestParamNameGenerator(ObliviousGroupAggTest));\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/oblivious_group_mark.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/oblivious_group_mark.h\"\n\n#include \"libspu/kernel/hal/shape_ops.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/casting.h\"\n#include \"libspu/kernel/hlo/const.h\"\n#include \"libspu/kernel/hlo/geometrical.h\"\n\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string ObliviousGroupMark::kOpType(\"ObliviousGroupMark\");\nconst std::string& ObliviousGroupMark::Type() const { return kOpType; }\n\nvoid ObliviousGroupMark::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  YACL_ENFORCE(inputs.size() > 0, \"input size cannot be 0\");\n  const auto& outputs = ctx->GetOutput(kOut);\n  YACL_ENFORCE(outputs.size() == 1, \"outputs' size={} not equal to 1\",\n               outputs.size());\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(inputs, pb::TENSORSTATUS_SECRET),\n               \"inputs' status are not all secret\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(outputs, pb::TENSORSTATUS_SECRET),\n               \"outputs' status are not all secret\");\n}\n\nvoid ObliviousGroupMark::Execute(ExecContext* ctx) {\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  // TODO(jingshi) : check and calculate validity\n  auto first_value = ctx->GetInputValue(kIn, 0);\n  int64_t row_count = first_value.shape().size() > 0 ? first_value.shape()[0]\n                                                     : first_value.numel();\n  spu::Value result;\n  if (row_count <= 1) {\n    result = spu::kernel::hlo::Seal(\n        sctx, spu::kernel::hlo::Constant(sctx, true, {row_count}));\n  } else {\n    result = GetFullGroupMark(ctx);\n  }\n\n  ctx->SetOutputValue(kOut, result);\n}\n\n// get group for row count >= 2\n// e.g: first_value = {0, 1, 1, 1, 2}\n// from_top = {0, 1, 1, 1}, to_bottom = {1, 1, 1, 2}\n// result = {1, 0, 0, 1}, full_result need to add tail = {1}\nspu::Value ObliviousGroupMark::GetFullGroupMark(ExecContext* ctx) {\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto values = ctx->GetInputValues(kIn);\n  auto first_value = values[0];\n  int64_t row_count = first_value.shape().size() > 0 ? first_value.shape()[0]\n                                                     : first_value.numel();\n  auto from_top =\n      spu::kernel::hal::slice(sctx, first_value, {0}, {row_count - 1}, {});\n  auto to_bottom =\n      spu::kernel::hal::slice(sctx, first_value, {1}, {row_count}, {});\n\n  auto result = spu::kernel::hlo::NotEqual(sctx, from_top, to_bottom);\n\n  for (size_t i = 1; i < values.size(); ++i) {\n    auto cur_value = values[i];\n    int64_t cur_row_count =\n        cur_value.shape().size() > 0 ? cur_value.shape()[0] : cur_value.numel();\n    YACL_ENFORCE(cur_row_count == row_count,\n                 \"intput tensor#{} row count not equal to the previous\");\n\n    auto from_top =\n        spu::kernel::hal::slice(sctx, cur_value, {0}, {row_count - 1}, {});\n    auto to_bottom =\n        spu::kernel::hal::slice(sctx, cur_value, {1}, {row_count}, {});\n\n    auto cur_result = spu::kernel::hlo::NotEqual(sctx, from_top, to_bottom);\n\n    result = spu::kernel::hlo::Or(sctx, result, cur_result);\n  }\n\n  auto tail =\n      spu::kernel::hlo::Seal(sctx, spu::kernel::hlo::Constant(sctx, true, {1}));\n\n  auto full_result = spu::kernel::hlo::Pad(sctx, result, tail, {0}, {1}, {0});\n  return full_result;\n}\n\n};  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/oblivious_group_mark.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass ObliviousGroupMark : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"Key\";\n  static constexpr char kOut[] = \"Group\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static spu::Value GetFullGroupMark(ExecContext* ctx);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/oblivious_group_mark_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/oblivious_group_mark.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct ObliviousGroupMarkTestCase {\n  std::vector<test::NamedTensor> inputs;\n  test::NamedTensor output;\n};\n\nclass ObliviousGroupMarkTest\n    : public testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, ObliviousGroupMarkTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const ObliviousGroupMarkTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    ObliviousGroupMarkBatchTest, ObliviousGroupMarkTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ObliviousGroupMarkTestCase{\n                .inputs = {test::NamedTensor(\n                    \"in\", TensorFrom(arrow::int64(), \"[0, 1, 1, 1, 2]\"))},\n                .output = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::boolean(), \"[1, 0, 0, 1, 1]\"))},\n            ObliviousGroupMarkTestCase{\n                .inputs = {test::NamedTensor(\"in_a\",\n                                             TensorFrom(arrow::int64(),\n                                                        \"[0, 0, 1, 1, 1, 1]\")),\n                           test::NamedTensor(\n                               \"in_b\",\n                               TensorFrom(arrow::float32(),\n                                          \"[-1, 0, 0, 3.14, 3.14, 3.14]\"))},\n                .output = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::boolean(), \"[1, 1, 1, 0, 0, 1]\"))},\n            ObliviousGroupMarkTestCase{\n                .inputs = {test::NamedTensor(\"in\", TensorFrom(arrow::int64(),\n                                                              \"[1]\"))},\n                .output = test::NamedTensor(\"out\", TensorFrom(arrow::boolean(),\n                                                              \"[1]\"))},\n            ObliviousGroupMarkTestCase{\n                .inputs = {test::NamedTensor(\"in\",\n                                             TensorFrom(arrow::int64(), \"[]\"))},\n                .output = test::NamedTensor(\"out\", TensorFrom(arrow::boolean(),\n                                                              \"[]\"))})),\n    TestParamNameGenerator(ObliviousGroupMarkTest));\n\nTEST_P(ObliviousGroupMarkTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  test::FeedInputsAsSecret(ctx_ptrs, tc.inputs);\n\n  // When\n  EXPECT_NO_THROW(test::RunAsync<ObliviousGroupMark>(ctx_ptrs));\n\n  // Then\n  TensorPtr actual_output = nullptr;\n  EXPECT_NO_THROW(\n      { actual_output = test::RevealSecret(ctx_ptrs, tc.output.name); });\n  ASSERT_TRUE(actual_output != nullptr);\n  auto actual_arr = actual_output->ToArrowChunkedArray();\n  auto expect_arr = tc.output.tensor->ToArrowChunkedArray();\n  EXPECT_TRUE(actual_arr->ApproxEquals(\n      *expect_arr, arrow::EqualOptions::Defaults().atol(0.001)))\n      << \"\\nexpect result = \" << expect_arr->ToString()\n      << \"\\nbut actual got result = \" << actual_arr->ToString();\n}\n\n/// ===================\n/// ObliviousGroupMarkTest impl\n/// ===================\n\npb::ExecNode ObliviousGroupMarkTest::MakeExecNode(\n    const ObliviousGroupMarkTestCase& tc) {\n  test::ExecNodeBuilder builder(ObliviousGroupMark::kOpType);\n\n  builder.SetNodeName(\"oblivious-group-mark-test\");\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    pb::Tensor t = test::MakeSecretTensorReference(named_tensor.name,\n                                                   named_tensor.tensor->Type());\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(ObliviousGroupMark::kIn, inputs);\n\n  pb::Tensor output =\n      test::MakeSecretTensorReference(tc.output.name, tc.output.tensor->Type());\n  builder.AddOutput(ObliviousGroupMark::kOut, {output});\n\n  return builder.Build();\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/publish.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/publish.h\"\n\n#include \"engine/util/tensor_util.h\"\n#include \"engine/util/time_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Publish::kOpType(\"Publish\");\n\nconst std::string& Publish::Type() const { return kOpType; }\n\nvoid Publish::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"input size={} and output size={} not equal\", inputs.size(),\n               outputs.size());\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   inputs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"input tensors status should be private\");\n}\n\nvoid Publish::Execute(ExecContext* ctx) {\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  int64_t num_rows = 0;\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    const auto& input_pb = input_pbs[i];\n    const auto& elem_type = input_pbs[i].elem_type();\n\n    const auto& output_name = util::GetStringValue(output_pbs[i]);\n\n    auto from_tensor = ctx->GetTensorTable()->GetTensor(input_pb.name());\n    YACL_ENFORCE(from_tensor, \"get private tensor={} failed\", input_pb.name());\n\n    auto proto_result = std::make_shared<pb::Tensor>();\n    SetProtoMeta(from_tensor.get(), output_name, proto_result, elem_type);\n\n    if (elem_type == pb::PrimitiveDataType::DATETIME) {\n      // DATETIME need format to publish\n      util::ConvertDateTimeAndCopyValuesToProto(from_tensor,\n                                                proto_result.get());\n    } else {\n      util::CopyValuesToProto(from_tensor, proto_result.get());\n    }\n    auto dim_value = proto_result->shape().dim(0).dim_value();\n    if (num_rows == 0 && dim_value != 0) {\n      num_rows = dim_value;\n    }\n    YACL_ENFORCE_EQ(num_rows, dim_value, \"num rows in result not matched {},{}\",\n                    num_rows, dim_value);\n\n    ctx->GetSession()->AddPublishResult(proto_result);\n  }\n}\n\nvoid Publish::SetProtoMeta(const Tensor* from_tensor, const std::string& name,\n                           const std::shared_ptr<pb::Tensor>& to_proto,\n                           pb::PrimitiveDataType elem_type) {\n  to_proto->set_name(name);\n  // set shape (rows, cols)\n  auto* shape = to_proto->mutable_shape();\n  auto* dim = shape->add_dim();\n  dim->set_dim_value(from_tensor->Length());  // rows\n  dim = shape->add_dim();\n  dim->set_dim_value(kColumnNumInProto);\n\n  if (elem_type == pb::PrimitiveDataType::DATETIME ||\n      elem_type == pb::PrimitiveDataType::TIMESTAMP) {\n    to_proto->set_elem_type(elem_type);\n  } else {\n    to_proto->set_elem_type(from_tensor->Type());\n  }\n  to_proto->set_option(pb::TensorOptions::VALUE);\n  to_proto->mutable_annotation()->set_status(\n      pb::TensorStatus::TENSORSTATUS_UNKNOWN);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/publish.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\n#include \"api/core.pb.h\"\n\nnamespace scql::engine::op {\n\n/// @brief Publish convert private data(owned) or public data(shared from SPU)\n/// to Proto and store results in session.\nclass Publish : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static void SetProtoMeta(const Tensor* from_tensor, const std::string& name,\n                           const std::shared_ptr<pb::Tensor>& to_proto,\n                           pb::PrimitiveDataType elem_type);\n\n private:\n  static constexpr int32_t kColumnNumInProto = 1;  // only contain one column.\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/publish_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/publish.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct PublishTestCase {\n  std::vector<test::NamedTensor> inputs;\n  std::vector<pb::PrimitiveDataType> input_types;\n  std::vector<std::string> out_strs;\n};\n\nclass PublishTest : public ::testing::TestWithParam<PublishTestCase> {\n protected:\n  static pb::ExecNode MakePublishExecNode(const PublishTestCase& tc);\n\n  static void FeedInputs(ExecContext* ctxs, const PublishTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    PublishPrivateTest, PublishTest,\n    testing::Values(\n        PublishTestCase{\n            // A simulation of User A in Los Angeles inserting records with\n            // TIMESTAMP and DATETIME columns\n            // (e.g., '2025-06-06 13:00:00', null, '2025-06-16 16:00:00',\n            // '2025-06-26 16:00:00') into MySQL\n            // followed by User B in Shanghai querying this data through the\n            // SCQL engine\n            .inputs =\n                {test::NamedTensor(\"in0\",\n                                   TensorFrom(arrow::int64(), \"[0,1,null,3]\")),\n                 test::NamedTensor(\n                     \"in1\",\n                     TensorFrom(arrow::int64(),\n                                \"[1749240000,1750114800,null,1750978800]\")),\n                 test::NamedTensor(\n                     \"in2\",\n                     TensorFrom(arrow::int64(),\n                                \"[1749214800,1750089600,null,1750953600]\"))},\n            .input_types =\n                {pb::PrimitiveDataType::INT64,\n                 // affected by timezone, we use Beijing time in test_util\n                 pb::PrimitiveDataType::TIMESTAMP,\n                 pb::PrimitiveDataType::DATETIME},\n            .out_strs = {R\"\"\"(name: \"col#0\"\nshape {\n  dim {\n    dim_value: 4\n  }\n  dim {\n    dim_value: 1\n  }\n}\nelem_type: INT64\nannotation {\n}\nint64_data: 0\nint64_data: 1\nint64_data: 0\nint64_data: 3\ndata_validity: true\ndata_validity: true\ndata_validity: false\ndata_validity: true\n)\"\"\",\n                         R\"\"\"(name: \"col#1\"\nshape {\n  dim {\n    dim_value: 4\n  }\n  dim {\n    dim_value: 1\n  }\n}\nelem_type: TIMESTAMP\nannotation {\n}\nint64_data: 1749240000\nint64_data: 1750114800\nint64_data: 0\nint64_data: 1750978800\ndata_validity: true\ndata_validity: true\ndata_validity: false\ndata_validity: true\n)\"\"\",\n                         R\"\"\"(name: \"col#2\"\nshape {\n  dim {\n    dim_value: 4\n  }\n  dim {\n    dim_value: 1\n  }\n}\nelem_type: DATETIME\nannotation {\n}\nstring_data: \"2025-06-06 13:00:00\"\nstring_data: \"2025-06-16 16:00:00\"\nstring_data: \"1970-01-01 00:00:00\"\nstring_data: \"2025-06-26 16:00:00\"\ndata_validity: true\ndata_validity: true\ndata_validity: false\ndata_validity: true\n)\"\"\"}},\n        PublishTestCase{\n            .inputs =\n                {test::NamedTensor(\n                     \"p0\", TensorFrom(arrow::large_utf8(),\n                                      R\"json([\"B\",\"A\",\"A\",\"CCC\",\"B\"])json\")),\n                 test::NamedTensor(\n                     \"p1\",\n                     TensorFrom(arrow::float32(),\n                                \"[1.1025, 100.245, -10.2, 0.34, 3.1415926]\"))},\n            .input_types = {pb::PrimitiveDataType::STRING,\n                            pb::PrimitiveDataType::FLOAT32},\n            .out_strs = {R\"\"\"(name: \"col#0\"\nshape {\n  dim {\n    dim_value: 5\n  }\n  dim {\n    dim_value: 1\n  }\n}\nelem_type: STRING\nannotation {\n}\nstring_data: \"B\"\nstring_data: \"A\"\nstring_data: \"A\"\nstring_data: \"CCC\"\nstring_data: \"B\"\n)\"\"\",\n                         R\"\"\"(name: \"col#1\"\nshape {\n  dim {\n    dim_value: 5\n  }\n  dim {\n    dim_value: 1\n  }\n}\nelem_type: FLOAT32\nannotation {\n}\nfloat_data: 1.1025\nfloat_data: 100.245\nfloat_data: -10.2\nfloat_data: 0.34\nfloat_data: 3.1415925\n)\"\"\"}}));\n\nTEST_P(PublishTest, Works) {\n  // Give\n  auto tc = GetParam();\n  auto node = MakePublishExecNode(tc);\n  auto session = test::Make1PCSession();\n  ExecContext ctx(node, session.get());\n  FeedInputs(&ctx, tc);\n\n  // When\n  Publish op;\n  ASSERT_NO_THROW(op.Run(&ctx););\n\n  // Then check output\n  auto result = session->GetPublishResults();\n  ASSERT_EQ(tc.inputs.size(), result.size());\n  for (size_t i = 0; i < result.size(); ++i) {\n    EXPECT_EQ(result[i]->DebugString(), tc.out_strs[i]);\n  }\n}\n\n/// ===========================\n/// PublishTest impl\n/// ===========================\n\npb::ExecNode PublishTest::MakePublishExecNode(const PublishTestCase& tc) {\n  test::ExecNodeBuilder builder(Publish::kOpType);\n\n  builder.SetNodeName(\"publish-test\");\n  // Add inputs\n  std::vector<pb::Tensor> input_datas;\n  for (size_t i = 0; i < tc.inputs.size(); ++i) {\n    const auto& named_tensor = tc.inputs[i];\n    auto data =\n        test::MakePrivateTensorReference(named_tensor.name, tc.input_types[i]);\n    input_datas.push_back(std::move(data));\n  }\n  builder.AddInput(Publish::kIn, input_datas);\n\n  // Add outputs\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.inputs.size(); ++i) {\n    pb::Tensor out;\n\n    auto name = fmt::format(\"col#{}\", i);\n    out.set_name(name);\n    out.set_option(pb::TensorOptions::VALUE);\n    out.add_string_data(name);\n    out.set_elem_type(pb::PrimitiveDataType::STRING);\n    outputs.push_back(std::move(out));\n  }\n  builder.AddOutput(Publish::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid PublishTest::FeedInputs(ExecContext* ctx, const PublishTestCase& tc) {\n  test::FeedInputsAsPrivate(ctx, tc.inputs);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/reduce.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/reduce.h\"\n\n#include <functional>\n#include <iterator>\n\n#include \"arrow/compute/api_aggregate.h\"\n#include \"arrow/compute/exec.h\"\n#include \"libspu/kernel/hal/constants.h\"\n#include \"libspu/kernel/hal/shape_ops.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/const.h\"\n#include \"libspu/kernel/hlo/indexing.h\"\n#include \"libspu/kernel/hlo/reduce.h\"\n#include \"libspu/kernel/hlo/sort.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nvoid ReduceBase::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() == 1,\n               \"operator {} input size should be 1, but got={}\", Type(),\n               inputs.size());\n  YACL_ENFORCE(outputs.size() == 1,\n               \"operator {} output size should be 1, but got={}\", Type(),\n               outputs.size());\n\n  const auto& input_status = util::GetTensorStatus(inputs[0]);\n  YACL_ENFORCE(input_status == pb::TENSORSTATUS_PRIVATE ||\n               input_status == pb::TENSORSTATUS_SECRET);\n  YACL_ENFORCE(util::IsTensorStatusMatched(outputs[0], input_status));\n}\n\nvoid ReduceBase::Execute(ExecContext* ctx) {\n  const auto& input_pb = ctx->GetInput(kIn)[0];\n  const auto& output_pb = ctx->GetOutput(kOut)[0];\n\n  InitAttribute(ctx);\n  if (util::GetTensorStatus(input_pb) == pb::TENSORSTATUS_PRIVATE) {\n    ExecuteInPlain(ctx, input_pb, output_pb);\n  } else {\n    auto* sctx = ctx->GetSession()->GetSpuContext();\n    auto* symbols = ctx->GetSession()->GetDeviceSymbols();\n    auto in_value =\n        symbols->getVar(util::SpuVarNameEncoder::GetValueName(input_pb.name()));\n    auto out_value = SecretReduceImpl(sctx, in_value);\n    symbols->setVar(util::SpuVarNameEncoder::GetValueName(output_pb.name()),\n                    out_value);\n#ifdef SCQL_WITH_NULL\n    // TODO: complete null propagation in aggregation\n#endif\n  }\n}\n\nvoid ReduceBase::ExecuteInPlain(ExecContext* ctx, const pb::Tensor& input_pb,\n                                const pb::Tensor& output_pb) {\n  const auto tensor = ctx->GetTensorTable()->GetTensor(input_pb.name());\n  YACL_ENFORCE(tensor, \"get private tensor failed, name={}\", input_pb.name());\n\n  const std::string& arrow_fun_name = GetArrowFunName();\n  auto result = arrow::compute::CallFunction(arrow_fun_name,\n                                             {tensor->ToArrowChunkedArray()});\n  YACL_ENFORCE(result.ok(), \"invoking arrow function '{}' failed: err_msg={}\",\n               arrow_fun_name, result.status().ToString());\n  auto scalar = result.ValueOrDie().scalar();\n  std::shared_ptr<arrow::Array> array;\n  ASSIGN_OR_THROW_ARROW_STATUS(array, arrow::MakeArrayFromScalar(*scalar, 1));\n  auto chunked_arr = std::make_shared<arrow::ChunkedArray>(array);\n\n  ctx->GetTensorTable()->AddTensor(output_pb.name(), TensorFrom(chunked_arr));\n}\n\nspu::Value ReduceBase::SecretReduceImpl(spu::SPUContext* sctx,\n                                        const spu::Value& in) {\n  if (in.numel() == 0) {\n    return HandleEmptyInput(in);\n  }\n\n  AggregateInit(sctx, in);\n\n  const auto& init_value = GetInitValue(sctx);\n  auto reduce_fn = GetReduceFn(sctx);\n\n  spu::kernel::hlo::BatchedValueBinaryFn reducer =\n      [reduce_fn](absl::Span<spu::Value const> lhs,\n                  absl::Span<spu::Value const> rhs) {\n        std::vector<spu::Value> out;\n        std::transform(lhs.begin(), lhs.end(), rhs.begin(),\n                       std::back_inserter(out), reduce_fn);\n        return out;\n      };\n\n  auto results = spu::kernel::hlo::Reduce(sctx, std::vector<spu::Value>{in},\n                                          std::vector<spu::Value>{init_value},\n                                          spu::Axes{0}, reducer);\n\n  return AggregateFinalize(sctx, results[0]);\n}\n\n// ================\n//  ReduceSum impl\n// ================\n\nconst std::string ReduceSum::kOpType(\"ReduceSum\");\n\nconst std::string& ReduceSum::Type() const { return kOpType; }\n\nspu::Value ReduceSum::GetInitValue(spu::SPUContext* sctx) {\n  return spu::kernel::hlo::Constant(sctx, static_cast<int64_t>(0), {1});\n}\n\nReduceBase::ReduceFn ReduceSum::GetReduceFn(spu::SPUContext* sctx) {\n  return [sctx](const spu::Value& lhs, const spu::Value& rhs) -> spu::Value {\n    return spu::kernel::hlo::Add(sctx, lhs, rhs);\n  };\n}\n\n// ================\n//  ReduceCount impl\n// ================\n\nconst std::string ReduceCount::kOpType(\"ReduceCount\");\n\nconst std::string& ReduceCount::Type() const { return kOpType; }\n\nspu::Value ReduceCount::GetInitValue(spu::SPUContext* sctx) {\n  YACL_THROW(\"unsupported reduce func: count\");\n}\n\nReduceBase::ReduceFn ReduceCount::GetReduceFn(spu::SPUContext* sctx) {\n  YACL_THROW(\"unsupported reduce func: count\");\n}\n\n// ===============\n// ReduceAvg impl\n// ===============\n\nconst std::string ReduceAvg::kOpType(\"ReduceAvg\");\nconst std::string& ReduceAvg::Type() const { return kOpType; }\n\nspu::Value ReduceAvg::HandleEmptyInput(const spu::Value& in) {\n  return in.clone().setDtype(spu::DT_F64, true);\n}\n\nvoid ReduceAvg::AggregateInit(spu::SPUContext* /*sctx*/, const spu::Value& in) {\n  if (in.numel() == 0 || in.shape().size() == 0) {\n    count_ = 0;\n  } else {\n    count_ = in.shape()[0];\n  }\n}\n\nspu::Value ReduceAvg::GetInitValue(spu::SPUContext* sctx) {\n  return spu::kernel::hlo::Constant(sctx, 0, {1});\n}\n\nReduceBase::ReduceFn ReduceAvg::GetReduceFn(spu::SPUContext* sctx) {\n  return [sctx](const spu::Value& lhs, const spu::Value& rhs) -> spu::Value {\n    return spu::kernel::hlo::Add(sctx, lhs, rhs);\n  };\n}\n\nspu::Value ReduceAvg::AggregateFinalize(spu::SPUContext* sctx,\n                                        const spu::Value& sum) {\n  auto count_f = spu::kernel::hlo::Constant(sctx, count_ * 1.0, {1});\n  return spu::kernel::hlo::Div(sctx, sum, count_f);\n}\n\n// =====================\n// ReduceMin impl\n// =====================\n\nconst std::string ReduceMin::kOpType(\"ReduceMin\");\nconst std::string& ReduceMin::Type() const { return kOpType; }\n\nvoid ReduceMin::AggregateInit(spu::SPUContext* sctx, const spu::Value& in) {\n  // set init_value_ to the first element of in\n  init_value_ = spu::kernel::hal::slice(sctx, in, {0}, {1}, {});\n}\n\nspu::Value ReduceMin::GetInitValue(spu::SPUContext* sctx) {\n  return init_value_;\n}\n\nReduceBase::ReduceFn ReduceMin::GetReduceFn(spu::SPUContext* sctx) {\n  return [sctx](const spu::Value& lhs, const spu::Value& rhs) -> spu::Value {\n    return spu::kernel::hlo::Min(sctx, lhs, rhs);\n  };\n}\n\n// =====================\n// ReduceMax impl\n// =====================\n\nconst std::string ReduceMax::kOpType(\"ReduceMax\");\nconst std::string& ReduceMax::Type() const { return kOpType; }\n\nvoid ReduceMax::AggregateInit(spu::SPUContext* sctx, const spu::Value& in) {\n  // set init_value_ to the first element of in\n  init_value_ = spu::kernel::hal::slice(sctx, in, {0}, {1}, {});\n}\n\nspu::Value ReduceMax::GetInitValue(spu::SPUContext* sctx) {\n  return init_value_;\n}\n\nReduceBase::ReduceFn ReduceMax::GetReduceFn(spu::SPUContext* sctx) {\n  return [sctx](const spu::Value& lhs, const spu::Value& rhs) -> spu::Value {\n    return spu::kernel::hlo::Max(sctx, lhs, rhs);\n  };\n}\n\n// =====================\n// ReducePercentileDisc impl\n// =====================\n\nconst std::string ReducePercentileDisc::kOpType(\"ReducePercentileDisc\");\nconst std::string& ReducePercentileDisc::Type() const { return kOpType; }\n\nvoid ReducePercentileDisc::InitAttribute(ExecContext* ctx) {\n  percent_ = ctx->GetDoubleValueFromAttribute(kPercent);\n  YACL_ENFORCE(percent_ >= 0 && percent_ <= 1,\n               \"percent should be in [0, 1], but got={}\", percent_);\n}\n\nvoid ReducePercentileDisc::AggregateInit(spu::SPUContext* sctx,\n                                         const spu::Value& in) {\n  // do nothing\n}\n\nspu::Value ReducePercentileDisc::GetInitValue(spu::SPUContext* sctx) {\n  YACL_THROW(\"should not reach here\");\n}\n\nReduceBase::ReduceFn ReducePercentileDisc::GetReduceFn(spu::SPUContext* sctx) {\n  YACL_THROW(\"should not reach here\");\n}\n\nvoid ReducePercentileDisc::ExecuteInPlain(ExecContext* ctx,\n                                          const pb::Tensor& in,\n                                          const pb::Tensor& out) {\n  auto tensor = ctx->GetTensorTable()->GetTensor(in.name());\n  YACL_ENFORCE(tensor, \"get private tensor failed, name={}\", in.name());\n  if (tensor->Length() == 0) {\n    ctx->GetTensorTable()->AddTensor(out.name(), tensor);\n    return;\n  }\n  int64_t pos = GetPointIndex(tensor->Length());\n  arrow::compute::PartitionNthOptions options(pos);\n\n  const arrow::compute::FunctionOptions* options_ptr = &options;\n  std::shared_ptr<arrow::Array> array;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      array, arrow::Concatenate(tensor->ToArrowChunkedArray()->chunks(),\n                                arrow::default_memory_pool()));\n  auto result = arrow::compute::CallFunction(\"partition_nth_indices\", {array},\n                                             options_ptr);\n\n  YACL_ENFORCE(result.ok(),\n               \"invoking arrow function 'partition_nth_indices' \"\n               \"failed: err_msg={}\",\n               result.status().ToString());\n  auto partitioned_indices = std::static_pointer_cast<arrow::UInt64Array>(\n      result.ValueOrDie().make_array());\n  std::shared_ptr<arrow::Scalar> scalar;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      scalar, array->GetScalar(partitioned_indices->Value(pos)));\n  ASSIGN_OR_THROW_ARROW_STATUS(array, arrow::MakeArrayFromScalar(*scalar, 1));\n  auto chunked_arr = std::make_shared<arrow::ChunkedArray>(array);\n\n  ctx->GetTensorTable()->AddTensor(out.name(), TensorFrom(chunked_arr));\n}\n\nspu::Value ReducePercentileDisc::SecretReduceImpl(spu::SPUContext* sctx,\n                                                  const spu::Value& in) {\n  auto length = in.shape()[0];\n  if (length == 0) {\n    return in;\n  }\n\n  auto pos =\n      static_cast<int>(std::ceil(percent_ * static_cast<double>(length)) - 1);\n  pos = std::max(pos, 0);\n  pos = std::min(pos, static_cast<int>(length - 1));\n\n  auto sorted = spu::kernel::hlo::SimpleSort(\n      sctx, {in}, 0, spu::kernel::hal::SortDirection::Ascending, 1);\n  spu::Value left_zeros = spu::kernel::hlo::Constant(sctx, 0, {pos});\n  spu::Value right_zeros =\n      spu::kernel::hlo::Constant(sctx, 0, {length - pos - 1});\n  spu::Value concat = spu::kernel::hlo::Concatenate(\n      sctx, {left_zeros, spu::kernel::hlo::Constant(sctx, 1, {1}), right_zeros},\n      0);\n  auto gathered = spu::kernel::hlo::Mul(sctx, sorted[0], concat);\n\n  spu::kernel::hlo::BatchedValueBinaryFn reducer =\n      [sctx](absl::Span<spu::Value const> lhs,\n             absl::Span<spu::Value const> rhs) {\n        std::vector<spu::Value> out;\n        std::transform(lhs.begin(), lhs.end(), rhs.begin(),\n                       std::back_inserter(out),\n                       [sctx](const spu::Value& lhs, const spu::Value& rhs) {\n                         return spu::kernel::hlo::Add(sctx, lhs, rhs);\n                       });\n        return out;\n      };\n  auto zero = spu::kernel::hlo::Constant(sctx, 0, {1});\n  auto result = spu::kernel::hlo::Reduce(\n      sctx, std::vector<spu::Value>{gathered}, std::vector<spu::Value>{zero},\n      spu::Axes{0}, reducer);\n  return result[0];\n}\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/reduce.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"arrow/compute/api.h\"\n#include \"arrow/compute/exec.h\"\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass ReduceBase : public Operator {\n public:\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n public:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n protected:\n  virtual std::string GetArrowFunName() = 0;\n\n  virtual spu::Value SecretReduceImpl(spu::SPUContext* sctx,\n                                      const spu::Value& in);\n  virtual void ExecuteInPlain(ExecContext* ctx, const pb::Tensor& in,\n                              const pb::Tensor& out);\n\n  virtual spu::Value HandleEmptyInput(const spu::Value& in) { return in; }\n\n  virtual void AggregateInit(spu::SPUContext* sctx, const spu::Value& in) {}\n  /// @returns reduce init value\n  virtual spu::Value GetInitValue(spu::SPUContext* sctx) = 0;\n\n  using ReduceFn =\n      std::function<spu::Value(const spu::Value& lhs, const spu::Value& rhs)>;\n\n  virtual ReduceFn GetReduceFn(spu::SPUContext* sctx) = 0;\n\n  virtual spu::Value AggregateFinalize(spu::SPUContext* sctx,\n                                       const spu::Value& value) {\n    return value;\n  }\n  virtual void InitAttribute(ExecContext* ctx) {}\n};\n\nclass ReduceSum : public ReduceBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  std::string GetArrowFunName() override { return \"sum\"; }\n\n  spu::Value GetInitValue(spu::SPUContext* sctx) override;\n  ReduceFn GetReduceFn(spu::SPUContext* sctx) override;\n};\n\nclass ReduceCount : public ReduceBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  std::string GetArrowFunName() override { return \"count\"; }\n\n  spu::Value GetInitValue(spu::SPUContext* sctx) override;\n  ReduceFn GetReduceFn(spu::SPUContext* sctx) override;\n};\n\nclass ReduceAvg : public ReduceBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  std::string GetArrowFunName() override { return \"mean\"; }\n\n  spu::Value HandleEmptyInput(const spu::Value& in) override;\n\n  void AggregateInit(spu::SPUContext* sctx, const spu::Value& in) override;\n\n  spu::Value GetInitValue(spu::SPUContext* sctx) override;\n  ReduceFn GetReduceFn(spu::SPUContext* sctx) override;\n\n  spu::Value AggregateFinalize(spu::SPUContext* sctx,\n                               const spu::Value& sum) override;\n\n private:\n  int64_t count_ = 0;\n};\n\nclass ReduceMin : public ReduceBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  std::string GetArrowFunName() override { return \"min\"; }\n\n  void AggregateInit(spu::SPUContext* sctx, const spu::Value& in) override;\n\n  spu::Value GetInitValue(spu::SPUContext* sctx) override;\n  ReduceFn GetReduceFn(spu::SPUContext* sctx) override;\n\n private:\n  spu::Value init_value_;\n};\n\nclass ReduceMax : public ReduceBase {\n public:\n  static const std::string kOpType;\n\n  const std::string& Type() const override;\n\n protected:\n  std::string GetArrowFunName() override { return \"max\"; }\n\n  void AggregateInit(spu::SPUContext* sctx, const spu::Value& in) override;\n\n  spu::Value GetInitValue(spu::SPUContext* sctx) override;\n  ReduceFn GetReduceFn(spu::SPUContext* sctx) override;\n\n private:\n  spu::Value init_value_;\n};\n\nclass ReducePercentileDisc : public ReduceBase {\n public:\n  static const std::string kOpType;\n  static constexpr char kPercent[] = \"percent\";\n  const std::string& Type() const override;\n\n protected:\n  std::string GetArrowFunName() override {\n    YACL_THROW(\"should not reach here\");\n  }\n  void AggregateInit(spu::SPUContext* sctx, const spu::Value& in) override;\n  spu::Value GetInitValue(spu::SPUContext* sctx) override;\n  ReduceFn GetReduceFn(spu::SPUContext* sctx) override;\n  void InitAttribute(ExecContext* ctx) override;\n  spu::Value SecretReduceImpl(spu::SPUContext* sctx,\n                              const spu::Value& in) override;\n  void ExecuteInPlain(ExecContext* ctx, const pb::Tensor& in,\n                      const pb::Tensor& out) override;\n\n private:\n  double percent_;\n\n  int64_t GetPointIndex(size_t length) const {\n    int64_t pos = static_cast<size_t>(\n        std::ceil(percent_ * static_cast<double>(length)) - 1);\n    pos = std::max(pos, static_cast<int64_t>(0));\n    pos = std::min(pos, static_cast<int64_t>(length) - 1);\n    return pos;\n  }\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/reduce_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/reduce.h\"\n\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/all_ops_register.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct ReduceTestCase {\n  std::string op_type;\n  pb::TensorStatus status;\n  test::NamedTensor input;\n  test::NamedTensor output;\n  std::optional<std::pair<std::string, double>> double_attr;\n};\n\nstatic ReduceTestCase GeneratePercentileDiscCase(pb::TensorStatus status,\n                                                 double percent,\n                                                 size_t input_size) {\n  std::string op_type = ReducePercentileDisc::kOpType;\n  std::string input_name = \"x\";\n  std::string output_name = \"y\";\n\n  int start_value = 0;\n  std::vector<int> input;\n  while (input.size() < input_size) {\n    input.push_back(start_value);\n    start_value += 1;\n  }\n  int expected_index = static_cast<int>(std::ceil(percent * input_size)) - 1;\n  expected_index = std::min((int)input_size - 1, expected_index);\n  expected_index = std::max(0, expected_index);\n  int expected_value = input[expected_index];\n  std::random_device rd;\n  std::mt19937 g(rd());\n  std::shuffle(input.begin(), input.end(), g);\n  std::string input_str = \"[\";\n  for (size_t i = 0; i < input.size(); ++i) {\n    input_str += std::to_string(input[i]);\n    if (i != input.size() - 1) {\n      input_str += \", \";\n    }\n  }\n  input_str += \"]\";\n  std::string output_str = \"[\" + std::to_string(expected_value) + \"]\";\n  SPDLOG_INFO(\"input_str: {}\", input_str);\n  SPDLOG_INFO(\"output_str: {}\", output_str);\n  auto input_tensor = TensorFrom(arrow::int32(), input_str);\n  auto output_tensor = TensorFrom(arrow::int32(), output_str);\n\n  return ReduceTestCase{\n      .op_type = op_type,\n      .status = status,\n      .input = test::NamedTensor(input_name, input_tensor),\n      .output = test::NamedTensor(output_name, output_tensor),\n      .double_attr = std::make_pair(ReducePercentileDisc::kPercent, percent),\n  };\n}\n\nclass ReduceTest : public ::testing::TestWithParam<\n                       std::tuple<test::SpuRuntimeTestCase, ReduceTestCase>> {\n protected:\n  void SetUp() override { RegisterAllOps(); }\n\n  static pb::ExecNode MakeExecNode(const ReduceTestCase& tc);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const ReduceTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    ReducePrivateTest, ReduceTest,\n    ::testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ReduceTestCase{.op_type = ReduceSum::kOpType,\n                           .status = pb::TENSORSTATUS_PRIVATE,\n                           .input = test::NamedTensor(\n                               \"x\", TensorFrom(arrow::boolean(),\n                                               \"[true, false, true, null]\")),\n                           .output = test::NamedTensor(\n                               \"y\", TensorFrom(arrow::uint64(), \"[2]\"))},\n            ReduceTestCase{.op_type = ReduceSum::kOpType,\n                           .status = pb::TENSORSTATUS_PRIVATE,\n                           .input = test::NamedTensor(\n                               \"x\", TensorFrom(arrow::int64(),\n                                               \"[1, 2, 3, 4, 5, 6, null]\")),\n                           .output = test::NamedTensor(\n                               \"y\", TensorFrom(arrow::int64(), \"[21]\"))},\n            ReduceTestCase{\n                .op_type = ReduceSum::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\n                    \"x\",\n                    TensorFrom(arrow::float64(),\n                               \"[0.1, 0.22, 0.33, 0.44, 0.55, 0.67, null]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[2.31]\"))},\n            ReduceTestCase{.op_type = ReduceAvg::kOpType,\n                           .status = pb::TENSORSTATUS_PRIVATE,\n                           .input = test::NamedTensor(\n                               \"x\", TensorFrom(arrow::int64(),\n                                               \"[1, 2, 3, 4, 5, 6, null]\")),\n                           .output = test::NamedTensor(\n                               \"y\", TensorFrom(arrow::float64(), \"[3.5]\"))},\n            ReduceTestCase{\n                .op_type = ReduceAvg::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[1.75, 2.34, 4.12, 1.99, null]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[2.55]\"))},\n            ReduceTestCase{\n                .op_type = ReduceMax::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(),\n                                    \"[1000, -2, 3345, 42, 5999, 60, null]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::int64(),\n                                                            \"[5999]\"))},\n            ReduceTestCase{\n                .op_type = ReduceMax::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[1.75, 2.34, 4.12, 1.99, null]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[4.12]\"))},\n            ReduceTestCase{\n                .op_type = ReduceMin::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(),\n                                    \"[1000, -2, 3345, 42, 5999, 60, null]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::int64(),\n                                                            \"[-2]\"))},\n            ReduceTestCase{\n                .op_type = ReduceMin::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[1.75, 2.34, 4.12, 1.99, null]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[1.75]\"))},\n            ReduceTestCase{\n                .op_type = ReduceCount::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[1.75, 2.34, 4.12, 1.99, null]\")),\n                .output = test::NamedTensor(\"y\",\n                                            TensorFrom(arrow::int64(), \"[4]\"))},\n            ReduceTestCase{\n                .op_type = ReduceCount::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[null, 2.34, null, 1.99, null]\")),\n                .output = test::NamedTensor(\"y\",\n                                            TensorFrom(arrow::int64(), \"[2]\"))},\n            ReduceTestCase{\n                .op_type = ReducePercentileDisc::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float32(),\n                                                           \"[3, 2, 1, 4, 5]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[3]\")),\n                .double_attr = std::make_pair(ReducePercentileDisc::kPercent,\n                                              0.5)},\n            ReduceTestCase{\n                .op_type = ReducePercentileDisc::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float32(),\n                                                           \"[3, 2, 1, 4]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[2]\")),\n                .double_attr = std::make_pair(ReducePercentileDisc::kPercent,\n                                              0.5)},\n            ReduceTestCase{\n                .op_type = ReducePercentileDisc::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float32(),\n                                                           \"[3, 2, 1, 4]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[1]\")),\n                .double_attr = std::make_pair(ReducePercentileDisc::kPercent,\n                                              0)},\n            ReduceTestCase{\n                .op_type = ReducePercentileDisc::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float32(),\n                                                           \"[3, 2, 1, 4]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[4]\")),\n                .double_attr = std::make_pair(ReducePercentileDisc::kPercent,\n                                              1)},\n            ReduceTestCase{\n                .op_type = ReducePercentileDisc::kOpType,\n                .status = pb::TENSORSTATUS_PRIVATE,\n                .input = test::NamedTensor(\"x\",\n                                           TensorFrom(arrow::float32(), \"[]\")),\n                .output = test::NamedTensor(\"y\",\n                                            TensorFrom(arrow::float32(), \"[]\")),\n                .double_attr = std::make_pair(ReducePercentileDisc::kPercent,\n                                              0.5)},\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_PRIVATE, 0.5, 2),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_PRIVATE, 0.6, 4),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_PRIVATE, 0, 10000),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_PRIVATE, 1, 10000),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_PRIVATE, 0.3112234, 10),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_PRIVATE, 0.314, 10001),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_PRIVATE, 0.442,\n                                       10001))),\n    TestParamNameGenerator(ReduceTest));\n\nINSTANTIATE_TEST_SUITE_P(\n    ReduceSecretTest, ReduceTest,\n    ::testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ReduceTestCase{\n                .op_type = ReduceSum::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::boolean(), \"[true, false, true]\")),\n                .output = test::NamedTensor(\"y\",\n                                            TensorFrom(arrow::int64(), \"[2]\"))},\n            ReduceTestCase{\n                .op_type = ReduceSum::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5, 6]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::int64(),\n                                                            \"[21]\"))},\n            ReduceTestCase{\n                .op_type = ReduceSum::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float32(),\n                                    \"[0.1, 0.22, 0.33, 0.44, 0.55, 0.67]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[2.31]\"))},\n            ReduceTestCase{\n                .op_type = ReduceAvg::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5, 6]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[3.5]\"))},\n            ReduceTestCase{.op_type = ReduceAvg::kOpType,\n                           .status = pb::TENSORSTATUS_SECRET,\n                           .input = test::NamedTensor(\n                               \"x\", TensorFrom(arrow::float32(),\n                                               \"[1.75, 2.34, 4.12, 1.99]\")),\n                           .output = test::NamedTensor(\n                               \"y\", TensorFrom(arrow::float64(), \"[2.55]\"))},\n            ReduceTestCase{\n                .op_type = ReduceMax::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(),\n                                    \"[1000, -2, 3345, 42, 5999, 60]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::int64(),\n                                                            \"[5999]\"))},\n            ReduceTestCase{.op_type = ReduceMax::kOpType,\n                           .status = pb::TENSORSTATUS_SECRET,\n                           .input = test::NamedTensor(\n                               \"x\", TensorFrom(arrow::float32(),\n                                               \"[1.75, 2.34, 4.12, 1.99]\")),\n                           .output = test::NamedTensor(\n                               \"y\", TensorFrom(arrow::float32(), \"[4.12]\"))},\n            ReduceTestCase{\n                .op_type = ReduceMin::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int64(),\n                                    \"[1000, -2, 3345, 42, 5999, 60]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::int64(),\n                                                            \"[-2]\"))},\n            ReduceTestCase{.op_type = ReduceMin::kOpType,\n                           .status = pb::TENSORSTATUS_SECRET,\n                           .input = test::NamedTensor(\n                               \"x\", TensorFrom(arrow::float32(),\n                                               \"[1.75, 2.34, 4.12, 1.99]\")),\n                           .output = test::NamedTensor(\n                               \"y\", TensorFrom(arrow::float32(), \"[1.75]\"))},\n            // testcase: empty inputs\n            ReduceTestCase{\n                .op_type = ReduceSum::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\"x\",\n                                           TensorFrom(arrow::float32(), \"[]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[]\"))},\n            ReduceTestCase{\n                .op_type = ReduceAvg::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\"x\",\n                                           TensorFrom(arrow::int64(), \"[]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[]\"))},\n            ReduceTestCase{\n                .op_type = ReduceMin::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\"x\",\n                                           TensorFrom(arrow::float32(), \"[]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[]\"))},\n            ReduceTestCase{\n                .op_type = ReduceMax::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\"x\",\n                                           TensorFrom(arrow::float32(), \"[]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[]\"))},\n            ReduceTestCase{\n                .op_type = ReducePercentileDisc::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float32(),\n                                                           \"[3, 2, 1, 4, 5]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[3]\")),\n                .double_attr = std::make_pair(ReducePercentileDisc::kPercent,\n                                              0.5)},\n            ReduceTestCase{\n                .op_type = ReducePercentileDisc::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float32(),\n                                                           \"[3, 2, 1, 4]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[2]\")),\n                .double_attr = std::make_pair(ReducePercentileDisc::kPercent,\n                                              0.5)},\n            ReduceTestCase{\n                .op_type = ReducePercentileDisc::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float32(),\n                                                           \"[3, 2, 1, 4]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[1]\")),\n                .double_attr = std::make_pair(ReducePercentileDisc::kPercent,\n                                              0)},\n            ReduceTestCase{\n                .op_type = ReducePercentileDisc::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float32(),\n                                                           \"[3, 2, 1, 4]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float32(),\n                                                            \"[4]\")),\n                .double_attr = std::make_pair(ReducePercentileDisc::kPercent,\n                                              1)},\n            ReduceTestCase{\n                .op_type = ReducePercentileDisc::kOpType,\n                .status = pb::TENSORSTATUS_SECRET,\n                .input = test::NamedTensor(\"x\",\n                                           TensorFrom(arrow::float32(), \"[]\")),\n                .output = test::NamedTensor(\"y\",\n                                            TensorFrom(arrow::float32(), \"[]\")),\n                .double_attr = std::make_pair(ReducePercentileDisc::kPercent,\n                                              0.5)},\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_SECRET, 0, 10000),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_SECRET, 1, 10000),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_SECRET, 0.314, 10000),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_SECRET, 0.442, 10000),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_SECRET, 0.314, 10001),\n            GeneratePercentileDiscCase(pb::TENSORSTATUS_SECRET, 0.442, 10001))),\n    TestParamNameGenerator(ReduceTest));\n\nTEST_P(ReduceTest, Works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  auto op_creator = [&]() {\n    return GetOpRegistry()->GetOperator(node.op_type());\n  };\n\n  if (tc.status == pb::TENSORSTATUS_PRIVATE) {\n    EXPECT_NO_THROW(test::RunOpAsync({ctx_ptrs[0]}, op_creator));\n  } else {\n    EXPECT_NO_THROW(test::RunOpAsync(ctx_ptrs, op_creator));\n  }\n\n  TensorPtr actual_output = nullptr;\n  if (tc.status == pb::TENSORSTATUS_PRIVATE) {\n    actual_output = ctx_ptrs[0]->GetTensorTable()->GetTensor(tc.output.name);\n  } else {\n    EXPECT_NO_THROW(\n        { actual_output = test::RevealSecret(ctx_ptrs, tc.output.name); });\n  }\n  ASSERT_TRUE(actual_output != nullptr);\n  auto actual_arr = actual_output->ToArrowChunkedArray();\n  auto expect_arr = tc.output.tensor->ToArrowChunkedArray();\n  EXPECT_TRUE(actual_arr->ApproxEquals(\n      *expect_arr, arrow::EqualOptions::Defaults().atol(0.001)))\n      << \"expect type = \" << expect_arr->type()->ToString()\n      << \", got type = \" << actual_arr->type()->ToString()\n      << \"\\nexpect result = \" << expect_arr->ToString()\n      << \"\\nbut actual got result = \" << actual_arr->ToString();\n}\n\npb::ExecNode ReduceTest::MakeExecNode(const ReduceTestCase& tc) {\n  test::ExecNodeBuilder builder(tc.op_type);\n\n  builder.SetNodeName(tc.op_type + \"-test\");\n  auto input = test::MakeTensorReference(tc.input.name, tc.input.tensor->Type(),\n                                         tc.status);\n  builder.AddInput(ReduceBase::kIn, {input});\n  auto output = test::MakeTensorReference(tc.output.name,\n                                          tc.output.tensor->Type(), tc.status);\n  builder.AddOutput(ReduceBase::kOut, {output});\n  if (tc.double_attr.has_value()) {\n    builder.AddDoubleAttr(tc.double_attr->first, tc.double_attr->second);\n  }\n\n  return builder.Build();\n}\n\nvoid ReduceTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                            const ReduceTestCase& tc) {\n  if (tc.status == pb::TENSORSTATUS_PRIVATE) {\n    test::FeedInputsAsPrivate(ctxs[0], {tc.input});\n  } else {\n    test::FeedInputsAsSecret(ctxs, {tc.input});\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/replicate.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/replicate.h\"\n\n#include \"arrow/array/builder_base.h\"\n#include \"arrow/scalar.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/context_util.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\nconst std::string Replicate::kOpType(\"Replicate\");\n\nconst std::string& Replicate::Type() const { return kOpType; }\n\nvoid Replicate::Validate(ExecContext* ctx) {\n  const auto& codes = ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  YACL_ENFORCE(codes.size() == 2, \"Replicate only support 2 parties\");\n  std::string my_party = ctx->GetSession()->SelfPartyCode();\n  if (my_party == codes[0]) {\n    const auto& left_input = ctx->GetInput(kLeft);\n    int64_t length = -1;\n    for (const auto& left : left_input) {\n      YACL_ENFORCE(util::IsTensorStatusMatched(left, pb::TENSORSTATUS_PRIVATE));\n      TensorPtr left_ptr = util::GetPrivateOrPublicTensor(ctx, left);\n      YACL_ENFORCE(left_ptr, \"tensor {} not found\", left.name());\n      if (length == -1) {\n        length = left_ptr->Length();\n      }\n\n      YACL_ENFORCE(left_ptr->Length() == length,\n                   \"different length in left input tensors\");\n    }\n  }\n\n  if (my_party == codes[1]) {\n    const auto& right_input = ctx->GetInput(kRight);\n    int64_t length = -1;\n    for (const auto& right : right_input) {\n      YACL_ENFORCE(\n          util::IsTensorStatusMatched(right, pb::TENSORSTATUS_PRIVATE));\n      TensorPtr right_ptr = util::GetPrivateOrPublicTensor(ctx, right);\n      YACL_ENFORCE(right_ptr, \"tensor {} not found\", right.name());\n      if (length == -1) {\n        length = right_ptr->Length();\n      }\n\n      YACL_ENFORCE(right_ptr->Length() == length,\n                   \"different length in right input tensors\");\n    }\n  }\n}\n\nstd::shared_ptr<arrow::ChunkedArray> Replicate::ExtendArray(\n    const std::shared_ptr<arrow::ChunkedArray>& array, int64_t extend_size,\n    bool interleaving) {\n  if (!array) {\n    return nullptr;\n  }\n  if (extend_size == 0 || array->num_chunks() == 0) {\n    std::shared_ptr<arrow::DataType> type = array->type();\n    auto result = arrow::ChunkedArray::Make({}, type);\n    YACL_ENFORCE(result.ok(), \"failed to make empty chunked array, error: {}\",\n                 result.status().ToString());\n\n    return result.ValueOrDie();\n  }\n  std::vector<std::shared_ptr<arrow::Array>> new_chunks;\n  if (interleaving) {\n    for (int64_t i = 0; i < extend_size; i++) {\n      for (const auto& chunk : array->chunks()) {\n        new_chunks.push_back(chunk);\n      }\n    }\n  } else {\n    std::unique_ptr<arrow::ArrayBuilder> builder;\n    THROW_IF_ARROW_NOT_OK(arrow::MakeBuilder(arrow::default_memory_pool(),\n                                             array->type(), &builder));\n    for (int i = 0; i < array->num_chunks(); i++) {\n      std::shared_ptr<arrow::Array> chunk = array->chunk(i);\n      for (int j = 0; j < chunk->length(); j++) {\n        for (int k = 0; k < extend_size; k++) {\n          auto value = chunk->GetScalar(j);\n          YACL_ENFORCE(value.ok(), \"failed to get scalar, error: {}\",\n                       value.status().ToString());\n          THROW_IF_ARROW_NOT_OK(builder->AppendScalar(*value.ValueOrDie()));\n        }\n      }\n    }\n    std::shared_ptr<arrow::Array> result;\n    THROW_IF_ARROW_NOT_OK(builder->Finish(&result));\n    new_chunks.push_back(result);\n  }\n\n  return std::make_shared<arrow::ChunkedArray>(new_chunks);\n}\n\nvoid Replicate::BuildReplicate(ExecContext* ctx, const RepeatedPbTensor& inputs,\n                               size_t dup_rows, const RepeatedPbTensor& outputs,\n                               bool interleaving) {\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"input size {} != output size {}\", inputs.size(),\n               outputs.size());\n  int64_t input_tensor_length = -1;\n  for (int i = 0; i < inputs.size(); i++) {\n    const auto& input_tensor = inputs[i];\n    YACL_ENFORCE(\n        util::IsTensorStatusMatched(input_tensor, pb::TENSORSTATUS_PRIVATE),\n        \"replicate tensors must be private\");\n    TensorPtr input_ptr = util::GetPrivateOrPublicTensor(ctx, input_tensor);\n    YACL_ENFORCE(input_ptr, \"tensor {} not found\", input_tensor.name());\n    if (input_tensor_length == -1) {\n      input_tensor_length = input_ptr->Length();\n    }\n\n    YACL_ENFORCE(input_ptr->Length() == input_tensor_length,\n                 \"input tensors length must be equal\");\n    auto chunked_arr = input_ptr->ToArrowChunkedArray();\n    YACL_ENFORCE(chunked_arr, \"input tensor {} is not valid\",\n                 input_tensor.name());\n    auto new_array = ExtendArray(chunked_arr, dup_rows, interleaving);\n    YACL_ENFORCE(new_array, \"failed to extend array {}\", input_tensor.name());\n    ctx->GetTensorTable()->AddTensor(outputs[i].name(), TensorFrom(new_array));\n  }\n}\n\nvoid Replicate::Execute(ExecContext* ctx) {\n  const auto& left = ctx->GetInput(kLeft);\n  const auto& right = ctx->GetInput(kRight);\n  const auto& left_out = ctx->GetOutput(kLeftOut);\n  const auto& right_out = ctx->GetOutput(kRightOut);\n\n  const auto& codes = ctx->GetStringValuesFromAttribute(kInputPartyCodesAttr);\n  std::string my_party = ctx->GetSession()->SelfPartyCode();\n  auto lctx = ctx->GetSession()->GetLink();\n  std::string tag = ctx->GetNodeName() + \"-Replicate\";\n  lctx = lctx->SubWorld(tag, codes);\n\n  if (my_party == codes[0]) {\n    if (my_party == codes[1]) {\n      TensorPtr right_input = util::GetPrivateOrPublicTensor(ctx, right[0]);\n      YACL_ENFORCE(right_input, \"tensor {} not found\", right[0].name());\n      BuildReplicate(ctx, left, right_input->Length(), left_out, true);\n    } else {\n      TensorPtr left_input = util::GetPrivateOrPublicTensor(ctx, left[0]);\n      YACL_ENFORCE(left_input, \"tensor {} not found\", left[0].name());\n      size_t left_length = left_input->Length();\n\n      auto length_bufs = yacl::link::AllGather(\n          lctx, yacl::ByteContainerView(&left_length, sizeof(left_length)),\n          tag);\n      YACL_ENFORCE(\n          lctx->NextRank() >= 0 && lctx->NextRank() < length_bufs.size(),\n          \"invalid rank({}) for buf size({})\", lctx->NextRank(),\n          length_bufs.size());\n      const size_t* right_length = length_bufs[lctx->NextRank()].data<size_t>();\n      YACL_ENFORCE(right_length);\n      BuildReplicate(ctx, left, *right_length, left_out, true);\n    }\n  }\n  if (my_party == codes[1]) {\n    if (my_party == codes[0]) {\n      TensorPtr left_input = util::GetPrivateOrPublicTensor(ctx, left[0]);\n      YACL_ENFORCE(left_input, \"tensor {} not found\", left[0].name());\n      BuildReplicate(ctx, right, left_input->Length(), right_out, false);\n    } else {\n      TensorPtr right_input = util::GetPrivateOrPublicTensor(ctx, right[0]);\n      YACL_ENFORCE(right_input, \"tensor {} not found\", right[0].name());\n      size_t right_length = right_input->Length();\n      auto length_bufs = yacl::link::AllGather(\n          lctx, yacl::ByteContainerView(&right_length, sizeof(right_length)),\n          tag);\n\n      const size_t* left_length;\n      YACL_ENFORCE(\n          lctx->NextRank() >= 0 && lctx->NextRank() < length_bufs.size(),\n          \"invalid rank({}) for buf size({})\", lctx->NextRank(),\n          length_bufs.size());\n      left_length = length_bufs[lctx->NextRank()].data<size_t>();\n      YACL_ENFORCE(left_length);\n\n      BuildReplicate(ctx, right, *left_length, right_out, false);\n    }\n  }\n}\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/replicate.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/*\nleft: [1, 2, 3], right: ['a', 'b']\nthe result after replicate is\nleft output:    [ 1,  2,  3,  1,  2,  3]\nright output:   ['a','a','a','b','b','b']\n*/\nclass Replicate : public Operator {\n public:\n  const std::string& Type() const override;\n  static constexpr char kLeft[] = \"Left\";\n  static constexpr char kRight[] = \"Right\";\n  static constexpr char kLeftOut[] = \"LeftOut\";\n  static constexpr char kRightOut[] = \"RightOut\";\n  static constexpr char kInputPartyCodesAttr[] = \"input_party_codes\";\n  static const std::string kOpType;\n\n protected:\n  void Execute(ExecContext* ctx) override;\n  void Validate(ExecContext* ctx) override;\n  void BuildReplicate(ExecContext* ctx, const RepeatedPbTensor& inputs,\n                      size_t dup_rows, const RepeatedPbTensor& outputs,\n                      bool interleaving);\n\n private:\n  static std::shared_ptr<arrow::ChunkedArray> ExtendArray(\n      const std::shared_ptr<arrow::ChunkedArray>& array, int64_t extend_size,\n      bool interleaving);\n};\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/replicate_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n#include \"engine/operator/replicate.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\nstruct ReplicateTestCase {\n  std::string op = Replicate::kOpType;\n  std::vector<test::NamedTensor> left_inputs;\n  std::vector<test::NamedTensor> right_inputs;\n  std::vector<test::NamedTensor> left_outputs;\n  std::vector<test::NamedTensor> right_outputs;\n  int world_size = 1;\n};\n\nclass ReplicateTest\n    : public ::testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, ReplicateTestCase>> {\n protected:\n  void SetUp() override {}\n  static pb::ExecNode MakeExecNode(const ReplicateTestCase& tc,\n                                   const std::string& name);\n  static void FeedInputs(const std::vector<ExecContext*>& ctx,\n                         const ReplicateTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    ReplicateTestSuite, ReplicateTest,\n    testing::Combine(\n        test::SpuTestValues2PC,\n        testing::Values(\n            ReplicateTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int32(), \"[1,2,3]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(), \"[100.0, 200.0]\"))},\n                .left_outputs = {test::NamedTensor(\n                    \"output_x\", TensorFrom(arrow::int32(), \"[1,2,3,1,2,3]\"))},\n                .right_outputs = {test::NamedTensor(\n                    \"output_y\",\n                    TensorFrom(arrow::float32(),\n                               \"[100.0, 100.0, 100.0, 200.0, 200.0, 200.0]\"))},\n                .world_size = 2},\n            ReplicateTestCase{\n                .left_inputs = {test::NamedTensor(\n                                    \"x\", TensorFrom(arrow::int32(), \"[1,2,3]\")),\n                                test::NamedTensor(\"x_1\",\n                                                  TensorFrom(arrow::int32(),\n                                                             \"[4,5,6]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(), \"[100.0, 200.0]\"))},\n                .left_outputs = {test::NamedTensor(\"output_x\",\n                                                   TensorFrom(arrow::int32(),\n                                                              \"[1,2,3,1,2,3]\")),\n                                 test::NamedTensor(\n                                     \"output_x_1\",\n                                     TensorFrom(arrow::int32(),\n                                                \"[4,5,6,4,5,6]\"))},\n                .right_outputs = {test::NamedTensor(\n                    \"output_y\",\n                    TensorFrom(arrow::float32(),\n                               \"[100.0, 100.0, 100.0, 200.0, 200.0, 200.0]\"))},\n                .world_size = 2},\n            ReplicateTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int32(), \"[1,2,3]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(), \"[]\"))},\n                .left_outputs = {test::NamedTensor(\n                    \"output_x\", TensorFrom(arrow::int32(), \"[]\"))},\n                .right_outputs = {test::NamedTensor(\n                    \"output_y\", TensorFrom(arrow::float32(), \"[]\"))},\n                .world_size = 2},\n            ReplicateTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int32(), \"[1,2,3]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(), \"[100.0, 200.0]\"))},\n                .left_outputs = {test::NamedTensor(\n                    \"output_x\", TensorFrom(arrow::int32(), \"[1,2,3,1,2,3]\"))},\n                .right_outputs = {test::NamedTensor(\n                    \"output_y\",\n                    TensorFrom(arrow::float32(),\n                               \"[100.0, 100.0, 100.0, 200.0, 200.0, 200.0]\"))}},\n            ReplicateTestCase{\n                .left_inputs = {test::NamedTensor(\n                                    \"x\", TensorFrom(arrow::int32(), \"[1,2,3]\")),\n                                test::NamedTensor(\"x_1\",\n                                                  TensorFrom(arrow::int32(),\n                                                             \"[4,5,6]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::large_utf8(), \"[\\\"a\\\", \\\"b\\\"]\"))},\n                .left_outputs = {test::NamedTensor(\"output_x\",\n                                                   TensorFrom(arrow::int32(),\n                                                              \"[1,2,3,1,2,3]\")),\n                                 test::NamedTensor(\n                                     \"output_x_1\",\n                                     TensorFrom(arrow::int32(),\n                                                \"[4,5,6,4,5,6]\"))},\n                .right_outputs = {test::NamedTensor(\n                    \"output_y\",\n                    TensorFrom(arrow::large_utf8(),\n                               \"[\\\"a\\\", \\\"a\\\", \\\"a\\\", \\\"b\\\", \\\"b\\\", \\\"b\\\"]\"))}},\n            ReplicateTestCase{\n                .left_inputs = {test::NamedTensor(\n                    \"x\", TensorFrom(arrow::int32(), \"[1,2,3]\"))},\n                .right_inputs = {test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float32(), \"[1]\"))},\n                .left_outputs = {test::NamedTensor(\n                    \"output_x\", TensorFrom(arrow::int32(), \"[1,2,3]\"))},\n                .right_outputs = {test::NamedTensor(\n                    \"output_y\", TensorFrom(arrow::float32(), \"[1,1,1]\"))}})));\n\nTEST_P(ReplicateTest, Works) {\n  auto param = GetParam();\n  auto tc = std::get<1>(param);\n  auto node = MakeExecNode(tc, tc.op);\n  std::vector<std::shared_ptr<scql::engine::Session>> sessions;\n  if (tc.world_size > 1) {\n    sessions = test::MakeMultiPCSession(std::get<0>(param));\n  } else {\n    sessions.push_back(test::Make1PCSession());\n  }\n\n  std::vector<ExecContext> exec_ctx;\n  exec_ctx.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctx.emplace_back(node, session.get());\n  }\n\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctx.size());\n  for (auto& i : exec_ctx) {\n    ctx_ptrs.emplace_back(&i);\n  }\n  FeedInputs(ctx_ptrs, tc);\n  EXPECT_NO_THROW(test::RunAsync<Replicate>(ctx_ptrs));\n\n  if (tc.world_size == 1) {\n    SPDLOG_INFO(\"world size = 1\");\n    ExecContext* alice_ctx = nullptr;\n    for (auto& c : ctx_ptrs) {\n      if (c->GetSession()->SelfPartyCode() == test::kPartyAlice) {\n        alice_ctx = c;\n        break;\n      }\n    }\n    EXPECT_NE(alice_ctx, nullptr);\n    for (auto& left : tc.left_outputs) {\n      TensorPtr left_output = alice_ctx->GetTensorTable()->GetTensor(left.name);\n      auto out_arr = left_output->ToArrowChunkedArray();\n      auto expect_arr = left.tensor->ToArrowChunkedArray();\n      arrow::EqualOptions eq;\n      EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr, eq.atol(0.001)))\n          << \"alice left output:\"\n          << \"\\nactual: \" << out_arr->ToString()\n          << \"\\nexpect: \" << expect_arr->ToString();\n    }\n\n    for (auto& right : tc.right_outputs) {\n      TensorPtr right_output =\n          alice_ctx->GetTensorTable()->GetTensor(right.name);\n      auto out_arr = right_output->ToArrowChunkedArray();\n      auto expect_arr = right.tensor->ToArrowChunkedArray();\n      arrow::EqualOptions eq;\n      EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr, eq.atol(0.001)))\n          << \"alice right output:\"\n          << \"\\nactual: \" << out_arr->ToString()\n          << \"\\nexpect: \" << expect_arr->ToString();\n    }\n  } else {\n    SPDLOG_INFO(\"world size = 2\");\n    ExecContext* alice_ctx;\n    ExecContext* bob_ctx;\n    for (auto& ctx : ctx_ptrs) {\n      if (ctx->GetSession()->SelfPartyCode() == test::kPartyAlice) {\n        alice_ctx = ctx;\n      } else if (ctx->GetSession()->SelfPartyCode() == test::kPartyBob) {\n        bob_ctx = ctx;\n      }\n    }\n\n    EXPECT_NE(alice_ctx, nullptr);\n    EXPECT_NE(bob_ctx, nullptr);\n    for (auto& left : tc.left_outputs) {\n      TensorPtr left_output = alice_ctx->GetTensorTable()->GetTensor(left.name);\n      auto out_arr = left_output->ToArrowChunkedArray();\n      auto expect_arr = left.tensor->ToArrowChunkedArray();\n      arrow::EqualOptions eq;\n      EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr, eq.atol(0.001)))\n          << \"alice left output:\"\n          << \"\\nactual: \" << out_arr->ToString()\n          << \"\\nexpect: \" << expect_arr->ToString();\n    }\n\n    for (auto& right : tc.right_outputs) {\n      TensorPtr right_output = bob_ctx->GetTensorTable()->GetTensor(right.name);\n      auto out_arr = right_output->ToArrowChunkedArray();\n      auto expect_arr = right.tensor->ToArrowChunkedArray();\n      arrow::EqualOptions eq;\n      EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr, eq.atol(0.001)))\n          << \"bob right output:\"\n          << \"\\nactual: \" << out_arr->ToString()\n          << \"\\nexpect: \" << expect_arr->ToString();\n    }\n  }\n}\n\npb::ExecNode ReplicateTest::MakeExecNode(const ReplicateTestCase& tc,\n                                         const std::string& name) {\n  test::ExecNodeBuilder builder(name);\n  builder.SetNodeName(name + \"-test\");\n\n  {\n    std::vector<pb::Tensor> left_tensors;\n    left_tensors.reserve(tc.left_inputs.size());\n    for (const auto& left : tc.left_inputs) {\n      left_tensors.push_back(test::MakeTensorReference(\n          left.name, left.tensor->Type(), pb::TENSORSTATUS_PRIVATE));\n    }\n\n    builder.AddInput(Replicate::kLeft, left_tensors);\n  }\n\n  {\n    std::vector<pb::Tensor> right_tensors;\n    right_tensors.reserve(tc.right_inputs.size());\n    for (const auto& right : tc.right_inputs) {\n      right_tensors.emplace_back(test::MakeTensorReference(\n          right.name, right.tensor->Type(), pb::TENSORSTATUS_PRIVATE));\n    }\n    builder.AddInput(Replicate::kRight, right_tensors);\n  }\n\n  {\n    std::vector<pb::Tensor> left_output_tensors;\n    left_output_tensors.reserve(tc.left_outputs.size());\n    for (const auto& left : tc.left_outputs) {\n      left_output_tensors.push_back(test::MakeTensorReference(\n          left.name, left.tensor->Type(), pb::TENSORSTATUS_PRIVATE));\n    }\n\n    builder.AddOutput(Replicate::kLeftOut, left_output_tensors);\n  }\n\n  {\n    std::vector<pb::Tensor> right_output_tensors;\n    right_output_tensors.reserve(tc.right_outputs.size());\n    for (const auto& right : tc.right_outputs) {\n      right_output_tensors.push_back(test::MakeTensorReference(\n          right.name, right.tensor->Type(), pb::TENSORSTATUS_PRIVATE));\n    }\n\n    builder.AddOutput(Replicate::kRightOut, right_output_tensors);\n  }\n\n  if (tc.world_size == 1) {\n    builder.AddStringsAttr(Replicate::kInputPartyCodesAttr,\n                           {test::kPartyAlice, test::kPartyAlice});\n  } else {\n    builder.AddStringsAttr(Replicate::kInputPartyCodesAttr,\n                           {test::kPartyAlice, test::kPartyBob});\n  }\n\n  return builder.Build();\n}\n\nvoid ReplicateTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                               const ReplicateTestCase& tc) {\n  if (ctxs.size() == 1) {\n    test::FeedInputsAsPrivate(ctxs[0], {tc.left_inputs});\n    test::FeedInputsAsPrivate(ctxs[0], {tc.right_inputs});\n  } else {\n    for (const auto& ctx : ctxs) {\n      if (ctx->GetSession()->SelfPartyCode() == test::kPartyAlice) {\n        test::FeedInputsAsPrivate(ctx, {tc.left_inputs});\n      } else if (ctx->GetSession()->SelfPartyCode() == test::kPartyBob) {\n        test::FeedInputsAsPrivate(ctx, {tc.right_inputs});\n      }\n    }\n  }\n}\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/run_sql.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/run_sql.h\"\n\n#include \"spdlog/spdlog.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/datasource/csvdb_adaptor.h\"\n\nnamespace scql::engine::op {\n\nconst std::string RunSQL::kOpType(\"RunSQL\");\n\nconst std::string& RunSQL::Type() const { return kOpType; }\n\nvoid RunSQL::Execute(ExecContext* ctx) {\n  auto logger = ctx->GetActiveLogger();\n  std::string select = ctx->GetStringValueFromAttribute(kSQLAttr);\n\n  std::vector<std::string> table_refs =\n      ctx->GetStringValuesFromAttribute(kTableRefsAttr);\n  YACL_ENFORCE(table_refs.size() > 0, \"attr: {} should not be empty\",\n               kTableRefsAttr);\n\n  std::vector<DataSource> datasource_specs =\n      ctx->GetDatasourceRouter()->Route(table_refs);\n\n  YACL_ENFORCE(datasource_specs.size() == table_refs.size(),\n               \"the size of route result mismatch with table_refs size\");\n  DataSource ds = datasource_specs[0];\n  if (datasource_specs.size() > 1) {\n    for (size_t i = 1; i < datasource_specs.size(); ++i) {\n      if (datasource_specs[i].id() != ds.id()) {\n        YACL_THROW(\n            \"RunSQL operator could not handle query across datasource, \"\n            \"table_refs=[{}]\",\n            fmt::join(table_refs, \",\"));\n      }\n    }\n\n    if (ds.kind() == DataSourceKind::CSVDB) {\n      // connection_strs are different for different table_ref, we need to merge\n      ds = MergeCsvdbDatasources(datasource_specs);\n    }\n  }\n  auto adaptor = ctx->GetDatasourceAdaptorMgr()->GetAdaptor(ds);\n  YACL_ENFORCE(adaptor, \"get adaptor failed\");\n\n  const auto& outputs_pb = ctx->GetOutput(kOut);\n  YACL_ENFORCE(outputs_pb.size() > 0, \"no output for RunSQL\");\n\n  std::vector<ColumnDesc> expected_outputs;\n  expected_outputs.reserve(outputs_pb.size());\n  for (const auto& i : outputs_pb) {\n    expected_outputs.emplace_back(i.name(), i.elem_type());\n  }\n\n  TensorBuildOptions options = {\n      .dump_to_disk = ctx->GetSession()->GetStreamingOptions().batched,\n      .dump_dir = ctx->GetSession()->GetStreamingOptions().dump_file_dir};\n  auto results = adaptor->ExecQuery(logger, select, expected_outputs, options);\n\n  YACL_ENFORCE(results.size() == expected_outputs.size(),\n               \"the size of ExecQuery results mismatch with expected_outputs\");\n  for (size_t i = 0; i < expected_outputs.size(); ++i) {\n    ctx->GetTensorTable()->AddTensor(expected_outputs[i].name, results[i]);\n  }\n  SPDLOG_LOGGER_INFO(logger, \"get result row={}, column={}\",\n                     results[0]->Length(), results.size());\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/run_sql.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass RunSQL : public Operator {\n public:\n  static const std::string kOpType;\n  // output\n  static constexpr char kOut[] = \"Out\";\n  // attributes\n  static constexpr char kSQLAttr[] = \"sql\";\n  static constexpr char kTableRefsAttr[] = \"table_refs\";\n\n  RunSQL() = default;\n\n  const std::string& Type() const override;\n\n protected:\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/run_sql_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/run_sql.h\"\n\n#include \"Poco/Data/SQLite/Connector.h\"\n#include \"Poco/Data/Session.h\"\n#include \"absl/debugging/failure_signal_handler.h\"\n#include \"absl/debugging/symbolize.h\"\n#include \"absl/flags/parse.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/datasource/datasource_adaptor_mgr.h\"\n#include \"engine/datasource/embed_router.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nclass RunSQLTest : public ::testing::Test {\n protected:\n  void SetUp() override {\n    Poco::Data::SQLite::Connector::registerConnector();\n\n    session_ =\n        std::make_unique<Poco::Data::Session>(\"SQLite\", db_connection_str_);\n\n    using Poco::Data::Keywords::now;\n    // create table\n    *session_ << \"CREATE TABLE person(name VARCHAR(30), age INTEGER(3))\", now;\n    // insert some rows\n    *session_ << \"INSERT INTO person VALUES(\\\"alice\\\", 18)\", now;\n    *session_ << \"INSERT INTO person VALUES(\\\"bob\\\", 20)\", now;\n    *session_ << \"INSERT INTO person VALUES(\\\"carol\\\", NULL)\", now;\n    *session_ << \"INSERT INTO person VALUES(NULL, NULL)\", now;\n  }\n\n protected:\n  std::unique_ptr<Poco::Data::Session> session_;\n  // https://www.sqlite.org/inmemorydb.html\n  std::string db_connection_str_ = \"file:runsql_test?mode=memory&cache=shared\";\n  std::string embed_router_conf_ = R\"json({\n      \"datasources\": [\n        {\n          \"id\": \"ds001\",\n          \"name\": \"sqlite3\",\n          \"kind\": \"SQLITE\",\n          \"connection_str\": \"file:runsql_test?mode=memory&cache=shared\"\n        }\n      ],\n      \"rules\":[\n        {\n          \"db\": \"*\",\n          \"table\": \"*\",\n          \"datasource_id\": \"ds001\"\n        }\n      ]\n    })json\";\n};\n\nTEST_F(RunSQLTest, normal) {\n  // Given\n  const std::string query = \"SELECT name, age FROM person\";\n  const std::string out_name = \"person.name\";\n  const std::string out_age = \"person.age\";\n  const std::vector<std::string> table_refs = {\"db.person\"};\n\n  test::ExecNodeBuilder node_builder(RunSQL::kOpType);\n  node_builder.AddStringAttr(RunSQL::kSQLAttr, query);\n  node_builder.AddStringsAttr(RunSQL::kTableRefsAttr, table_refs);\n  auto out0 = test::MakeTensorReference(out_name, pb::PrimitiveDataType::STRING,\n                                        pb::TensorStatus::TENSORSTATUS_PRIVATE);\n  // test type cast: INT64 -> INT32\n  auto out1 = test::MakeTensorReference(out_age, pb::PrimitiveDataType::INT32,\n                                        pb::TensorStatus::TENSORSTATUS_PRIVATE);\n  node_builder.AddOutput(RunSQL::kOut, {out0, out1});\n  auto node = node_builder.Build();\n\n  std::unique_ptr<Router> router = EmbedRouter::FromJsonStr(embed_router_conf_);\n  DatasourceAdaptorMgr ds_mgr;\n  auto session = test::Make1PCSession(router.get(), &ds_mgr);\n  ExecContext ctx(node, session.get());\n  // When\n  RunSQL op;\n  op.Run(&ctx);\n  // Then\n  auto out_tensor = ctx.GetTensorTable()->GetTensor(out_name);\n  ASSERT_NE(nullptr, out_tensor);\n  EXPECT_EQ(out_tensor->Type(), pb::PrimitiveDataType::STRING);\n  EXPECT_EQ(out_tensor->Length(), 4);\n  EXPECT_EQ(out_tensor->GetNullCount(), 1);\n\n  out_tensor = ctx.GetTensorTable()->GetTensor(out_age);\n  ASSERT_NE(nullptr, out_tensor);\n  EXPECT_EQ(out_tensor->Type(), pb::PrimitiveDataType::INT32);\n  EXPECT_EQ(out_tensor->Length(), 4);\n  EXPECT_EQ(out_tensor->GetNullCount(), 2);\n}\n\n}  // namespace scql::engine::op\n\nint main(int argc, char* argv[]) {\n  {\n    absl::InitializeSymbolizer(argv[0]);\n\n    absl::FailureSignalHandlerOptions options;\n    absl::InstallFailureSignalHandler(options);\n  }\n\n  ::testing::InitGoogleTest(&argc, argv);\n\n  absl::ParseCommandLine(argc, argv);\n  return RUN_ALL_TESTS();\n}"
  },
  {
    "path": "engine/operator/secret_join.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/secret_join.h\"\n\n#include \"arrow/compute/api.h\"\n#include \"libspu/kernel/hal/debug.h\"\n#include \"libspu/kernel/hal/public_helper.h\"\n#include \"libspu/kernel/hal/shape_ops.h\"\n#include \"libspu/kernel/hal/type_cast.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/basic_ternary.h\"\n#include \"libspu/kernel/hlo/basic_unary.h\"\n#include \"libspu/kernel/hlo/casting.h\"\n#include \"libspu/kernel/hlo/const.h\"\n#include \"libspu/kernel/hlo/geometrical.h\"\n#include \"libspu/kernel/hlo/indexing.h\"\n#include \"libspu/kernel/hlo/permute.h\"\n#include \"libspu/kernel/hlo/shuffle.h\"\n#include \"libspu/kernel/hlo/soprf.h\"\n#include \"libspu/kernel/hlo/sort.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/prefix_sum.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nusing namespace spu::kernel;\n\nnamespace {\n\nstd::vector<spu::Value> FillDummyValue(spu::SPUContext* sctx,\n                                       const std::vector<spu::Value>& inputs,\n                                       int64_t dummy_size) {\n  if (dummy_size <= 0) {\n    return inputs;\n  }\n  auto zeros = hlo::Seal(sctx, hlo::Constant(sctx, int64_t{0}, {dummy_size}));\n  std::vector<spu::Value> ret;\n  ret.reserve(inputs.size());\n  for (auto v : inputs) {\n    ret.push_back(hlo::Concatenate(\n        sctx, {v, hal::dtype_cast(sctx, zeros, v.dtype())}, 0));\n  }\n  return ret;\n}\n\n// return the join result position and the upper bound of join size\nstd::tuple<spu::Value, spu::Value> CountPosition(spu::SPUContext* sctx,\n                                                 const spu::Value& count,\n                                                 const spu::Value& mark) {\n  auto one = hlo::Seal(sctx, hlo::Constant(sctx, int64_t{1}, {1}));\n  auto c = hlo::Seal(sctx, hlo::Constant(sctx, int64_t{0}, {1}));\n  std::vector<spu::Value> tmp_a;\n  for (int64_t i = 0; i < count.numel(); ++i) {\n    c = hlo::Add(sctx, c, hlo::Slice(sctx, count, {i}, {i + 1}, {}));\n    tmp_a.push_back(c);\n  }\n\n  std::vector<spu::Value> tmp_b;\n  for (int64_t i = 0; i < mark.numel(); ++i) {\n    c = hlo::Sub(sctx, hlo::Add(sctx, c, one),\n                 hlo::Slice(sctx, mark, {i}, {i + 1}, {}));\n    tmp_b.push_back(c);\n  }\n\n  auto tmp_bc = hlo::Concatenate(sctx, tmp_b, 0);\n  auto p = hlo::Add(\n      sctx,\n      hlo::Mul(sctx, mark,\n               hlo::Sub(sctx, hlo::Concatenate(sctx, tmp_a, 0), tmp_bc)),\n      tmp_bc);\n  // index start from 0\n  auto index = hlo::Sub(sctx, p, hlo::Constant(sctx, int64_t{1}, {p.numel()}));\n  return {index, c};\n}\n\n// Build a permutation index consisting of two parts:\n// 1. the first part is the input parmeter 'p'\n// 2. the second part is the index which is not in 'p' but in 'pi'\n//\n// e.g: p = {2, 4, 5}, pi = {0, 1, 2, 3, 4, 5},\n//      output = {2, 4, 5, 0, 1, 3}\ntemplate <typename T>\nspu::Value BuildPerm(spu::SPUContext* sctx, const spu::Value& p,\n                     const spu::Value& pi) {\n  auto tmp = hlo::Concatenate(sctx, {pi, p}, 0);\n  auto soprf = hlo::SoPrf(sctx, tmp);\n  // reveal after soprf\n  auto soprf_revealed = hlo::Reveal(sctx, soprf);\n  auto view = spu::NdArrayView<T>(soprf_revealed.data());\n  std::set<T> p_set;\n  for (int64_t i = pi.numel(); i < view.numel(); ++i) {\n    auto [iter, ok] = p_set.insert(view[i]);\n    YACL_ENFORCE(ok, \"duplicate permutation\");\n  }\n  spu::Index index;\n  for (int64_t i = 0; i < pi.numel(); ++i) {\n    if (p_set.find(view[i]) == p_set.end()) {\n      index.push_back(i);\n    }\n  }\n  YACL_ENFORCE(index.size() == pi.numel() - p.numel(),\n               \"size mismatch, index size: {}, expected: {}, collisions may \"\n               \"happended in SoPrf\",\n               index.size(), pi.numel() - p.numel());\n\n  return hlo::Concatenate(sctx, {p, hlo::LinearGather(sctx, tmp, index)}, 0);\n};\n\n}  // namespace\n\nconst std::string SecretJoin::kOpType(\"SecretJoin\");\n\nconst std::string& SecretJoin::Type() const { return kOpType; }\n\nvoid SecretJoin::Validate(ExecContext* ctx) {\n  auto left_key = ctx->GetInput(kLeftKey);\n  YACL_ENFORCE(left_key.size() > 0, \"secret join cannot be empty\");\n  auto right_key = ctx->GetInput(kRightKey);\n  YACL_ENFORCE(left_key.size() == right_key.size(),\n               \"left key size{} != right key size{}\", left_key.size(),\n               right_key.size());\n\n  auto left_payload = ctx->GetInput(kLeftPayload);\n  YACL_ENFORCE(left_payload.size() > 0);\n  auto left_output = ctx->GetOutput(kOutLeft);\n  YACL_ENFORCE(left_output.size() == left_payload.size(),\n               \"left output size{} != left payload size{}\", left_output.size(),\n               left_payload.size());\n\n  auto right_payload = ctx->GetInput(kRightPayload);\n  YACL_ENFORCE(right_payload.size() > 0);\n  auto right_output = ctx->GetOutput(kOutRight);\n  YACL_ENFORCE(right_output.size() == right_payload.size(),\n               \"right output size{} != right payload size{}\",\n               right_output.size(), right_payload.size());\n\n  // check input output are all secret\n  YACL_ENFORCE(\n      util::AreTensorsStatusMatched(left_key, pb::TENSORSTATUS_SECRET));\n  YACL_ENFORCE(\n      util::AreTensorsStatusMatched(right_key, pb::TENSORSTATUS_SECRET));\n  YACL_ENFORCE(\n      util::AreTensorsStatusMatched(left_payload, pb::TENSORSTATUS_SECRET));\n  YACL_ENFORCE(\n      util::AreTensorsStatusMatched(right_payload, pb::TENSORSTATUS_SECRET));\n  YACL_ENFORCE(\n      util::AreTensorsStatusMatched(left_output, pb::TENSORSTATUS_SECRET));\n  YACL_ENFORCE(\n      util::AreTensorsStatusMatched(right_output, pb::TENSORSTATUS_SECRET));\n  // TODO: support ABY3/CHEETAH after spu supported\n  YACL_ENFORCE(ctx->GetSession()->GetSpuContext()->config().protocol ==\n                   spu::ProtocolKind::SEMI2K,\n               \"secret join only support SEMI2K protocol now\");\n}\n\nvoid SecretJoin::Execute(ExecContext* ctx) {\n  auto symbols = ctx->GetSession()->GetDeviceSymbols();\n  auto sctx = ctx->GetSession()->GetSpuContext();\n\n  auto left_key = symbols->getVar(\n      util::SpuVarNameEncoder::GetValueName(ctx->GetInput(kLeftKey)[0].name()));\n  auto right_key = symbols->getVar(util::SpuVarNameEncoder::GetValueName(\n      ctx->GetInput(kRightKey)[0].name()));\n  int64_t left_row_num = left_key.numel();\n  int64_t right_row_num = right_key.numel();\n  int64_t total_row = left_row_num + right_row_num;\n  SPDLOG_INFO(\"left row num: {}, right row num: {}\", left_row_num,\n              right_row_num);\n  if (left_row_num == 0 || right_row_num == 0) {\n    SetEmptyResult(ctx);\n    return;\n  }\n  //\n  // 1). Merge left and right table to count key group\n  //\n  spu::Value zeros = hlo::Constant(sctx, int64_t{0}, {left_row_num});\n  spu::Value ones = hlo::Constant(sctx, int64_t{1}, {right_row_num});\n  // [item_origin_mark] using '0' to mark the left rows and '1' to mark the\n  // right.\n  auto item_origin_mark = hlo::Concatenate(sctx, {zeros, ones}, 0);\n  const auto [merged_key, merged_payload] = MergeInputs(ctx);\n\n  std::vector<spu::Value> sort_inputs = merged_key;\n  sort_inputs.push_back(item_origin_mark);\n  sort_inputs.insert(sort_inputs.end(), merged_payload.begin(),\n                     merged_payload.end());\n  // sort_inputs: [keys, item_origin_mark, left_payloads, right_payloads]\n  auto results =\n      hlo::SimpleSort(sctx, sort_inputs, 0, hal::SortDirection::Ascending,\n                      merged_key.size() + 1 /* num_keys */, -1 /* valid_bits */,\n                      true /* stable */);\n  // accumulate count of left/right item in key group\n  const auto [left_item_count, right_item_count, tmp_right_count] =\n      CountKeyGroup(sctx,\n                    std::vector<spu::Value>(\n                        results.begin(), results.begin() + merged_key.size()),\n                    results[merged_key.size()]);\n  //\n  // 2). Separation: sort by item_origin_mark, then separate left and right to\n  // get table Ls and Rs\n  //\n  // sort inputs: [item_origin_mark, left_item_count, right_item_count,\n  // tmp_right_count, left_payloads, right_payloads]\n  std::vector<spu::Value> sep_inputs = {results[merged_key.size()],\n                                        left_item_count, right_item_count,\n                                        tmp_right_count};\n  sep_inputs.insert(sep_inputs.end(), results.begin() + merged_key.size() + 1,\n                    results.end());\n  // NOTE: set valid_bits to 2 to contain the sign bit, though the\n  // item_origin_mark only contains 0/1.\n  // TODO: using index to replace payloads to reduce communication\n  auto sep_sorted =\n      hlo::SimpleSort(sctx, sep_inputs, 0, hal::SortDirection::Ascending,\n                      1 /* num_keys */, 2 /* valid_bits */, true /* stable */);\n  // eb = (left_item_count * right_item_count) > 0, marks whether rows are in\n  // join result, add 0 to generate ashare\n  auto result_mark =\n      hlo::Add(sctx,\n               hlo::Greater(sctx, hlo::Mul(sctx, sep_sorted[1], sep_sorted[2]),\n                            hlo::Constant(sctx, int64_t{0}, {total_row})),\n               hlo::Constant(sctx, int64_t{0}, {total_row}));\n  // Ls results, left table after separation\n  // dL, payloads in Ls\n  std::vector<spu::Value> ls_payload;\n  for (int64_t i = 0; i < ctx->GetInput(kLeftPayload).size(); ++i) {\n    ls_payload.push_back(\n        hlo::Slice(sctx, sep_sorted[4 + i], {0}, {left_row_num}, {}));\n  }\n  // aR, right item count in Ls\n  auto ls_right_count =\n      hlo::Slice(sctx, sep_sorted[2], {0}, {left_row_num}, {});\n  // eb, result mark in Ls\n  auto ls_result_mark = hlo::Slice(sctx, result_mark, {0}, {left_row_num}, {});\n\n  // Rs results, right table after separation\n  // sR, tmp right count in Rs\n  auto rs_tmp_right_count =\n      hlo::Slice(sctx, sep_sorted[3], {left_row_num}, {total_row}, {});\n  // aL, left item count in Rs\n  auto rs_left_count =\n      hlo::Slice(sctx, sep_sorted[1], {left_row_num}, {total_row}, {});\n  // aR, right item count in Rs\n  auto rs_right_count =\n      hlo::Slice(sctx, sep_sorted[2], {left_row_num}, {total_row}, {});\n  // eb, result mark in Rs\n  auto rs_result_mark =\n      hlo::Slice(sctx, result_mark, {left_row_num}, {total_row}, {});\n  // dR, payloads in Rs\n  std::vector<spu::Value> rs_payload;\n  for (size_t i = 4 + ls_payload.size(); i < sep_sorted.size(); ++i) {\n    rs_payload.push_back(\n        hlo::Slice(sctx, sep_sorted[i], {left_row_num}, {total_row}, {}));\n  }\n  //\n  // 3). Position Calculation\n  //\n  // TODO: using join upper bound to slice after permutation rather than in\n  // result set\n  auto [pl, size_left] = CountPosition(sctx, ls_right_count, ls_result_mark);\n  auto [pr, size_right] = CountPosition(sctx, rs_left_count, rs_result_mark);\n\n  // reveal upper bound for join result size\n  auto upper_bound = hlo::Max(sctx, size_left, size_right);\n  spu::NdArrayRef upper_bound_arr =\n      spu::kernel::hal::dump_public(sctx, hlo::Reveal(sctx, upper_bound));\n  int64_t m = upper_bound_arr.at<int64_t>({0});\n\n  //\n  // 4). Distribution\n  //\n  // generate permutation\n  auto seq = hlo::Seal(sctx, hlo::Iota(sctx, spu::DataType::DT_I64, m));\n  auto seq_shuffled = hlo::Shuffle(sctx, {seq}, 0)[0];\n\n  spu::Value left_perm;\n  spu::Value right_perm;\n  if (sctx->config().field == spu::FM64) {\n    left_perm = BuildPerm<uint64_t>(sctx, pl, seq_shuffled);\n    right_perm = BuildPerm<uint64_t>(sctx, pr, seq_shuffled);\n  } else if (sctx->config().field == spu::FM128) {\n    left_perm = BuildPerm<uint128_t>(sctx, pl, seq_shuffled);\n    right_perm = BuildPerm<uint128_t>(sctx, pr, seq_shuffled);\n  } else {\n    YACL_THROW(\"unsupported field type: {}\", sctx->config().field);\n  }\n\n  // fill dummy to left: [ls_payload, dummy_mark]\n  auto ld_inputs_filled = FillDummyValue(sctx, ls_payload, m - left_row_num);\n  ld_inputs_filled.push_back(hlo::Seal(\n      sctx,\n      hlo::Concatenate(sctx,\n                       {hlo::Constant(sctx, int64_t{0}, {left_row_num}),\n                        hlo::Constant(sctx, int64_t{1}, {m - left_row_num})},\n                       0)));\n  // fill dummy to right: [rs_payload, rs_result_mark, rs_tmp_right_count,\n  // rs_left_count, rs_right_count, dummy_mark]\n  std::vector<spu::Value> rd_inputs = rs_payload;\n  rd_inputs.push_back(rs_result_mark);\n  rd_inputs.push_back(rs_tmp_right_count);\n  rd_inputs.push_back(rs_left_count);\n  rd_inputs.push_back(rs_right_count);\n  auto rd_inputs_filled = FillDummyValue(sctx, rd_inputs, m - right_row_num);\n  rd_inputs_filled.push_back(hlo::Seal(\n      sctx,\n      hlo::Concatenate(sctx,\n                       {hlo::Constant(sctx, int64_t{0}, {right_row_num}),\n                        hlo::Constant(sctx, int64_t{1}, {m - right_row_num})},\n                       0)));\n\n  // perm\n  // Ld, the left table after permutation\n  auto ld_permed = hlo::InvPermute(sctx, ld_inputs_filled, left_perm, 0);\n  // Rd, the right table after permutation\n  auto rd_permed = hlo::InvPermute(sctx, rd_inputs_filled, right_perm, 0);\n  //\n  // 5). Expansion\n  //\n  // Le, the left table after expansion\n  auto le_results = util::ExpandGroupValueReversely(\n      sctx, std::vector<spu::Value>(ld_permed.begin(), ld_permed.end() - 1),\n      *ld_permed.rbegin());\n  // Re, the right table after expansion\n  auto re_results = util::ExpandGroupValueReversely(\n      sctx, std::vector<spu::Value>(rd_permed.begin(), rd_permed.end() - 1),\n      *rd_permed.rbegin());\n  //\n  // 6) Alignment: only right payload need to be aligned\n  //\n  // aDL, left item count in Rd\n  auto re_left_count = rd_permed[rs_payload.size() + 2];\n  // eb, result mark in Re\n  auto re_results_mark = re_results[rs_payload.size()];\n\n  auto a_eb = hlo::Sub(sctx, re_left_count, re_results_mark);\n\n  // ai, the copy count before the item in the same group\n  auto tmp_a = hlo::Seal(sctx, hlo::Constant(sctx, int64_t{0}, {1}));\n  std::vector<spu::Value> a_slice;\n  for (int64_t i = re_left_count.numel() - 1; i >= 0; i--) {\n    tmp_a = hlo::Add(sctx, tmp_a, hlo::Slice(sctx, a_eb, {i}, {i + 1}, {}));\n    a_slice.push_back(tmp_a);\n  }\n  auto copy_count = hlo::Reverse(sctx, hlo::Concatenate(sctx, a_slice, 0), {0});\n\n  // (sR - 1) * (aL - 1)\n  auto re_ones = hlo::Constant(sctx, int64_t{1}, {re_left_count.numel()});\n  auto sr_1_al_1 =\n      hlo::Mul(sctx, hlo::Sub(sctx, re_results[rs_payload.size() + 1], re_ones),\n               hlo::Sub(sctx, re_results[rs_payload.size() + 2], re_ones));\n  // aR - 1\n  auto ar_1 = hlo::Sub(sctx, re_results[rs_payload.size() + 3], re_ones);\n\n  // bi = i - (sR - 1) * (aL - 1) + ai * (aR - 1), the position for right\n  // payload to replace\n  auto dr_pos = hlo::Add(sctx, hlo::Sub(sctx, seq, sr_1_al_1),\n                         hlo::Mul(sctx, copy_count, ar_1));\n\n  // pi = re * (bi - i) + i, the permutation for Rf (final table R)\n  auto rf_pi = hlo::Add(\n      sctx, hlo::Mul(sctx, re_results_mark, hlo::Sub(sctx, dr_pos, seq)), seq);\n\n  auto rf_results = hlo::InvPermute(\n      sctx,\n      std::vector<spu::Value>(re_results.begin(),\n                              re_results.begin() + rs_payload.size()),\n      rf_pi, 0);\n\n  // TODO: reveal join size in hlo::Reduce\n  auto join_size = hlo::Constant(sctx, int64_t{0}, {1});\n  for (int64_t i = 0; i < re_results_mark.numel(); ++i) {\n    join_size = hlo::Add(sctx, join_size,\n                         hlo::Slice(sctx, re_results_mark, {i}, {i + 1}, {}));\n  }\n  auto revealed_join_size =\n      hal::dump_public(sctx, hlo::Reveal(sctx, join_size)).at<int64_t>(0);\n  SPDLOG_INFO(\"join result size:{}\", revealed_join_size);\n\n  // set result\n  auto left_output = ctx->GetOutput(kOutLeft);\n  for (int64_t i = 0; i < left_output.size(); ++i) {\n    symbols->setVar(\n        util::SpuVarNameEncoder::GetValueName(left_output[i].name()),\n        hlo::Slice(sctx, le_results[i], {0}, {revealed_join_size}, {}));\n  }\n  auto right_output = ctx->GetOutput(kOutRight);\n  for (int64_t i = 0; i < right_output.size(); ++i) {\n    symbols->setVar(\n        util::SpuVarNameEncoder::GetValueName(right_output[i].name()),\n        hlo::Slice(sctx, rf_results[i], {0}, {revealed_join_size}, {}));\n  }\n}\n\n// vertically merge inputs from left and right, the keys are concatenated, while\n// the payload are filled with dummy items, e.g:\n// left table:\n//   key   left_data\n//    1       2\n//\n// right table:\n//   key   right_data\n//    3       4\n//\n// @returns:\n//   key | left_data right data\n//    1  |     2       NULL\n//    3  |   NULL      4\n//\nstd::tuple<std::vector<spu::Value>, std::vector<spu::Value>>\nSecretJoin::MergeInputs(ExecContext* ctx) {\n  auto* symbols = ctx->GetSession()->GetDeviceSymbols();\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  // concatenate key\n  int64_t left_row_num = 0;\n  int64_t right_row_num = 0;\n  std::vector<spu::Value> merged_keys;\n  for (int64_t i = 0; i < ctx->GetInput(kLeftKey).size(); ++i) {\n    auto left_key = symbols->getVar(util::SpuVarNameEncoder::GetValueName(\n        ctx->GetInput(kLeftKey)[i].name()));\n    left_row_num = left_key.numel();\n    auto right_key = symbols->getVar(util::SpuVarNameEncoder::GetValueName(\n        ctx->GetInput(kRightKey)[i].name()));\n    right_row_num = right_key.numel();\n\n    merged_keys.push_back(hlo::Concatenate(sctx, {left_key, right_key}, 0));\n  }\n\n  // fill payloads with dummy items\n  auto lz = hlo::Seal(sctx, hlo::Constant(sctx, int64_t{0}, {right_row_num}));\n  auto rz = hlo::Seal(sctx, hlo::Constant(sctx, int64_t{0}, {left_row_num}));\n  std::vector<spu::Value> payloads;\n  for (const auto& input : ctx->GetInput(kLeftPayload)) {\n    auto left_value =\n        symbols->getVar(util::SpuVarNameEncoder::GetValueName(input.name()));\n    // add dummy items to the end of left value\n    auto tmp = hlo::Concatenate(\n        sctx, {left_value, hal::dtype_cast(sctx, lz, left_value.dtype())}, 0);\n    payloads.push_back(tmp);\n  }\n  for (const auto& input : ctx->GetInput(kRightPayload)) {\n    auto right_value =\n        symbols->getVar(util::SpuVarNameEncoder::GetValueName(input.name()));\n    // add dummy items to the begin of right value\n    auto tmp = hlo::Concatenate(\n        sctx, {hal::dtype_cast(sctx, rz, right_value.dtype()), right_value}, 0);\n    payloads.push_back(tmp);\n  }\n\n  return std::make_pair(merged_keys, payloads);\n}\n\n// count the number of left and right items in each key group\n// @param[keys] are the sorted keys merged from left and right table.\n// @param[item_origin_mark] using '0' to mark the items in left table and '1' to\n// mark the right. e.g:\n// keys, item_origin_mark\n//   1,              0\n//   1,              1\n//   1,              1\n//   2,              1\n//\n// @returns\n// left_count, right_count, tmp_right_count\n//          1,           2,               0\n//          1,           2,               1\n//          1,           2,               2\n//          0,           1,               1\nstd::tuple<spu::Value, spu::Value, spu::Value> SecretJoin::CountKeyGroup(\n    spu::SPUContext* sctx, const std::vector<spu::Value>& keys,\n    const spu::Value& item_origin_mark) {\n  // 1. calculate key group mark, where '0' mark the begining of key group\n  auto total_row = keys[0].numel();\n  auto key_equal =\n      hlo::Equal(sctx, hlo::Slice(sctx, keys[0], {0}, {total_row - 1}, {}),\n                 hlo::Slice(sctx, keys[0], {1}, {total_row}, {}));\n  for (size_t i = 1; i < keys.size(); ++i) {\n    auto tmp_equal =\n        hlo::Equal(sctx, hlo::Slice(sctx, keys[i], {0}, {total_row - 1}, {}),\n                   hlo::Slice(sctx, keys[i], {1}, {total_row}, {}));\n    key_equal = hlo::And(sctx, key_equal, tmp_equal);\n  }\n  auto zero = hlo::Seal(sctx, hlo::Constant(sctx, false, {1}));\n  // TODO: cast to ashare first?\n  auto key_group_mark =\n      hlo::Concatenate(sctx, std::vector<spu::Value>{zero, key_equal}, 0);\n  auto shifted_mark =\n      hlo::Concatenate(sctx, std::vector<spu::Value>{key_equal, zero}, 0);\n\n  // 2. accumulate count of left/right item in key group\n  auto tmp_right_count = util::Scan(\n      sctx, item_origin_mark, key_group_mark,\n      [&](const spu::Value& lhs_v, const spu::Value& lhs_gm,\n          const spu::Value& rhs_v, const spu::Value& rhs_gm) {\n        spu::Value new_v = hlo::Add(sctx, lhs_v, hlo::Mul(sctx, lhs_gm, rhs_v));\n        spu::Value new_gm = hlo::Mul(sctx, lhs_gm, rhs_gm);\n\n        return std::make_pair(new_v, new_gm);\n      });\n  auto flip_mark =\n      hlo::Sub(sctx, hlo::Seal(sctx, hlo::Constant(sctx, 1, {total_row})),\n               item_origin_mark);\n  auto tmp_left_count = util::Scan(\n      sctx, flip_mark, key_group_mark,\n      [&](const spu::Value& lhs_v, const spu::Value& lhs_gm,\n          const spu::Value& rhs_v, const spu::Value& rhs_gm) {\n        spu::Value new_v = hlo::Add(sctx, lhs_v, hlo::Mul(sctx, lhs_gm, rhs_v));\n        spu::Value new_gm = hlo::Mul(sctx, lhs_gm, rhs_gm);\n\n        return std::make_pair(new_v, new_gm);\n      });\n\n  // 3. reverse propagation left/right count\n  auto left_count =\n      util::ExpandGroupValueReversely(sctx, {tmp_left_count}, shifted_mark);\n  auto right_count =\n      util::ExpandGroupValueReversely(sctx, {tmp_right_count}, shifted_mark);\n\n  return std::make_tuple(left_count[0], right_count[0], tmp_right_count);\n}\n\nvoid SecretJoin::SetEmptyResult(ExecContext* ctx) {\n  auto* symbols = ctx->GetSession()->GetDeviceSymbols();\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto left_output = ctx->GetOutput(kOutLeft);\n  for (int64_t i = 0; i < left_output.size(); ++i) {\n    auto v = symbols->getVar(util::SpuVarNameEncoder::GetValueName(\n        ctx->GetInput(kLeftPayload)[i].name()));\n    symbols->setVar(\n        util::SpuVarNameEncoder::GetValueName(left_output[i].name()),\n        hlo::Slice(sctx, v, {0}, {0}, {}));\n  }\n  auto right_output = ctx->GetOutput(kOutRight);\n  for (int64_t i = 0; i < right_output.size(); ++i) {\n    auto v = symbols->getVar(util::SpuVarNameEncoder::GetValueName(\n        ctx->GetInput(kRightPayload)[i].name()));\n    symbols->setVar(\n        util::SpuVarNameEncoder::GetValueName(right_output[i].name()),\n        hlo::Slice(sctx, v, {0}, {0}, {}));\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/secret_join.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/// @brief Idea from Scape: https://ieeexplore.ieee.org/document/9835540/\n/// Warn: for simplicity, the intersection of join are revealed\nclass SecretJoin : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kLeftKey[] = \"LeftKey\";\n  static constexpr char kRightKey[] = \"RightKey\";\n  static constexpr char kLeftPayload[] = \"Left\";\n  static constexpr char kRightPayload[] = \"Right\";\n  static constexpr char kOutLeft[] = \"LeftOutput\";\n  static constexpr char kOutRight[] = \"RightOutput\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n\n  void Execute(ExecContext* ctx) override;\n\n private:\n  void SetEmptyResult(ExecContext* ctx);\n\n  std::tuple<std::vector<spu::Value>, std::vector<spu::Value>> MergeInputs(\n      ExecContext* ctx);\n\n  std::tuple<spu::Value, spu::Value, spu::Value> CountKeyGroup(\n      spu::SPUContext* sctx, const std::vector<spu::Value>& keys,\n      const spu::Value& item_origin_mark);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/secret_join_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/secret_join.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct SecretJoinTestCase {\n  std::vector<test::NamedTensor> left_key;\n  std::vector<test::NamedTensor> right_key;\n  std::vector<test::NamedTensor> left_payload;\n  std::vector<test::NamedTensor> right_payload;\n  std::vector<test::NamedTensor> expect_left_output;\n  std::vector<test::NamedTensor> expect_right_output;\n};\n\nclass SecretJoinTest\n    : public ::testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, SecretJoinTestCase>> {\n protected:\n  static pb::ExecNode MakeSecretJoinExecNode(const SecretJoinTestCase& tc);\n\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const SecretJoinTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    SecretJoinSecretTest, SecretJoinTest,\n    testing::Combine(\n        testing::Values(test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2},\n                        test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 3}),\n        testing::Values(\n            SecretJoinTestCase{\n                .left_key = {test::NamedTensor(\n                    \"lk\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"a\", \"b\", \"a\", \"c\", \"b\"])json\"))},\n                .right_key = {test::NamedTensor(\n                    \"rk\", TensorFrom(arrow::large_utf8(),\n                                     R\"json([\"a\", \"a\", \"b\", \"d\", \"a\"])json\"))},\n                .left_payload =\n                    {test::NamedTensor(\n                         \"lp0\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"a\", \"b\", \"a\", \"c\", \"b\"])json\")),\n                     test::NamedTensor(\n                         \"lp1\",\n                         TensorFrom(\n                             arrow::large_utf8(),\n                             R\"json([\"x1\", \"y1\", \"x2\", \"z1\", \"y2\"])json\"))},\n                .right_payload =\n                    {test::NamedTensor(\n                         \"rp0\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"a\", \"a\", \"b\", \"d\", \"a\"])json\")),\n                     test::NamedTensor(\n                         \"rp1\",\n                         TensorFrom(\n                             arrow::large_utf8(),\n                             R\"json([\"r1\", \"r2\", \"s1\", \"t1\", \"r3\"])json\"))},\n                .expect_left_output =\n                    {test::NamedTensor(\n                         \"lp0\",\n                         TensorFrom(\n                             arrow::large_utf8(),\n                             R\"json([\"b\", \"b\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\"])json\")),\n                     test::NamedTensor(\n                         \"lp1\",\n                         TensorFrom(\n                             arrow::\n                                 large_utf8(),\n                             R\"json([\"y1\", \"y2\", \"x1\", \"x1\", \"x1\", \"x2\", \"x2\", \"x2\"])json\"))},\n                .expect_right_output =\n                    {test::NamedTensor(\n                         \"rp0\",\n                         TensorFrom(\n                             arrow::large_utf8(),\n                             R\"json([\"b\", \"b\", \"a\", \"a\", \"a\", \"a\", \"a\", \"a\"])json\")),\n                     test::NamedTensor(\n                         \"rp1\",\n                         TensorFrom(\n                             arrow::\n                                 large_utf8(),\n                             R\"json([\"s1\", \"s1\", \"r1\", \"r2\", \"r3\", \"r1\", \"r2\", \"r3\"])json\"))}},\n            SecretJoinTestCase{\n                .left_key = {test::NamedTensor(\n                    \"lk\", TensorFrom(arrow::int64(), \"[1, 2, 1, 2, 0]\"))},\n                .right_key = {test::NamedTensor(\n                    \"rk\", TensorFrom(arrow::int64(), \"[1, 2, 1, 2]\"))},\n                .left_payload =\n                    {test::NamedTensor(\"lp0\", TensorFrom(arrow::int64(),\n                                                         \"[1, 2, 1, 2, 0]\")),\n                     test::NamedTensor(\"lp1\", TensorFrom(arrow::int64(),\n                                                         \"[0, 1, 2, 3, 4]\"))},\n                .right_payload =\n                    {test::NamedTensor(\"rp0\", TensorFrom(arrow::int64(),\n                                                         \"[1, 2, 1, 2]\")),\n                     test::NamedTensor(\"rp1\", TensorFrom(arrow::int64(),\n                                                         \"[0, 1, 2, 3]\"))},\n                .expect_left_output =\n                    {test::NamedTensor(\"lp0\",\n                                       TensorFrom(arrow::int64(),\n                                                  \"[1, 1, 1, 1, 2, 2, 2, 2]\")),\n                     test::NamedTensor(\"lp1\",\n                                       TensorFrom(arrow::int64(),\n                                                  \"[0, 0, 2, 2, 1, 1, 3, 3]\"))},\n                .expect_right_output =\n                    {test::NamedTensor(\"rp0\",\n                                       TensorFrom(arrow::int64(),\n                                                  \"[1, 1, 1, 1, 2, 2, 2, 2]\")),\n                     test::NamedTensor(\n                         \"rp1\", TensorFrom(arrow::int64(),\n                                           \"[0, 2, 0, 2, 1, 3, 1, 3]\"))}},\n            SecretJoinTestCase{\n                .left_key =\n                    {test::NamedTensor(\n                         \"lk0\", TensorFrom(arrow::int64(), \"[1, 1, 2, 2, 5]\")),\n                     test::NamedTensor(\n                         \"lk1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"a\", \"a\", \"b\", \"d\", \"a\"])json\"))},\n                .right_key =\n                    {test::NamedTensor(\"rk0\", TensorFrom(arrow::int64(),\n                                                         \"[1, 1, 2, 2, 4, 6]\")),\n                     test::NamedTensor(\n                         \"rk1\",\n                         TensorFrom(\n                             arrow::large_utf8(),\n                             R\"json([\"a\", \"a\", \"b\", \"c\", \"e\", \"f\"])json\"))},\n                .left_payload = {test::NamedTensor(\n                    \"lp1\", TensorFrom(arrow::int64(), \"[0, 1, 2, 3, 4]\"))},\n                .right_payload = {test::NamedTensor(\n                    \"rp1\", TensorFrom(arrow::int64(), \"[0, 1, 2, 3, 4, 5]\"))},\n                .expect_left_output = {test::NamedTensor(\n                    \"lo1\", TensorFrom(arrow::int64(), \"[0, 0, 1, 1, 2]\"))},\n                .expect_right_output = {test::NamedTensor(\n                    \"ro1\", TensorFrom(arrow::int64(), \"[0, 1, 0, 1, 2]\"))}},\n            SecretJoinTestCase{\n                .left_key =\n                    {test::NamedTensor(\n                         \"lk\", TensorFrom(arrow::int64(), \"[1, 1, 2, 2, 5]\")),\n                     test::NamedTensor(\n                         \"lk0\", TensorFrom(arrow::float64(),\n                                           \"[1.0, 2.2, 3.3, 4.4, -5.5]\")),\n                     test::NamedTensor(\n                         \"lk1\",\n                         TensorFrom(arrow::large_utf8(),\n                                    R\"json([\"a\", \"a\", \"b\", \"d\", \"a\"])json\"))},\n                .right_key =\n                    {test::NamedTensor(\"rk\", TensorFrom(arrow::int64(),\n                                                        \"[1, 1, 2, 2, 4, 6]\")),\n                     test::NamedTensor(\n                         \"rk0\",\n                         TensorFrom(arrow::float64(),\n                                    \"[-1.0, -2.2, -3.3, -4.4, -5.5, 6.6]\")),\n                     test::NamedTensor(\n                         \"rk1\",\n                         TensorFrom(\n                             arrow::large_utf8(),\n                             R\"json([\"a\", \"a\", \"b\", \"c\", \"e\", \"f\"])json\"))},\n                .left_payload = {test::NamedTensor(\n                    \"lp1\", TensorFrom(arrow::int64(), \"[0, 1, 2, 3, 4]\"))},\n                .right_payload = {test::NamedTensor(\n                    \"rp1\", TensorFrom(arrow::int64(), \"[0, 1, 2, 3, 4, 5]\"))},\n                .expect_left_output = {test::NamedTensor(\n                    \"lo1\", TensorFrom(arrow::int64(), \"[]\"))},\n                .expect_right_output = {test::NamedTensor(\n                    \"ro1\", TensorFrom(arrow::int64(), \"[]\"))}},\n            SecretJoinTestCase{.left_key = {test::NamedTensor(\n                                   \"lk0\", TensorFrom(arrow::int64(), \"[]\"))},\n                               .right_key = {test::NamedTensor(\n                                   \"rk0\", TensorFrom(arrow::int64(), \"[]\"))},\n                               .left_payload = {test::NamedTensor(\n                                   \"lp1\", TensorFrom(arrow::int64(), \"[]\"))},\n                               .right_payload = {test::NamedTensor(\n                                   \"rp1\", TensorFrom(arrow::int64(), \"[]\"))},\n                               .expect_left_output = {test::NamedTensor(\n                                   \"lo1\", TensorFrom(arrow::int64(), \"[]\"))},\n                               .expect_right_output = {test::NamedTensor(\n                                   \"ro1\", TensorFrom(arrow::int64(), \"[]\"))}})),\n    TestParamNameGenerator(SecretJoinTest));\n\nTEST_P(SecretJoinTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeSecretJoinExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  EXPECT_NO_THROW(test::RunAsync<SecretJoin>(ctx_ptrs));\n\n  // Then check outputs in alice: reveal all secret output to\n  // alice\n\n  auto expect_output = tc.expect_left_output;\n  expect_output.insert(expect_output.end(), tc.expect_right_output.begin(),\n                       tc.expect_right_output.end());\n  for (const auto& expect_t : expect_output) {\n    TensorPtr out;\n    EXPECT_NO_THROW(out = test::RevealSecret(ctx_ptrs, expect_t.name));\n    // convert hash to string for string tensor in spu\n    if (expect_t.tensor->Type() == pb::PrimitiveDataType::STRING) {\n      out = ctx_ptrs[0]->GetSession()->HashToString(*out);\n    }\n    EXPECT_TRUE(out != nullptr);\n    // compare tensor content\n    EXPECT_TRUE(out->ToArrowChunkedArray()->Equals(\n        expect_t.tensor->ToArrowChunkedArray()))\n        << \"actual output = \" << out->ToArrowChunkedArray()->ToString()\n        << \", expect output = \"\n        << expect_t.tensor->ToArrowChunkedArray()->ToString();\n  }\n}\n\n/// ===========================\n/// SecretJoinTest impl\n/// ===========================\n\npb::ExecNode SecretJoinTest::MakeSecretJoinExecNode(\n    const SecretJoinTestCase& tc) {\n  test::ExecNodeBuilder builder(SecretJoin::kOpType);\n\n  builder.SetNodeName(\"secret-join-test\");\n  // Add inputs\n  {\n    std::vector<pb::Tensor> input_datas;\n    for (const auto& named_tensor : tc.left_key) {\n      auto data = test::MakeSecretTensorReference(named_tensor.name,\n                                                  named_tensor.tensor->Type());\n      input_datas.push_back(std::move(data));\n    }\n    builder.AddInput(SecretJoin::kLeftKey, input_datas);\n  }\n  {\n    std::vector<pb::Tensor> input_datas;\n    for (const auto& named_tensor : tc.right_key) {\n      auto data = test::MakeSecretTensorReference(named_tensor.name,\n                                                  named_tensor.tensor->Type());\n      input_datas.push_back(std::move(data));\n    }\n    builder.AddInput(SecretJoin::kRightKey, input_datas);\n  }\n  {\n    std::vector<pb::Tensor> input_datas;\n    for (const auto& named_tensor : tc.left_payload) {\n      auto data = test::MakeSecretTensorReference(named_tensor.name,\n                                                  named_tensor.tensor->Type());\n      input_datas.push_back(std::move(data));\n    }\n    builder.AddInput(SecretJoin::kLeftPayload, input_datas);\n  }\n  {\n    std::vector<pb::Tensor> input_datas;\n    for (const auto& named_tensor : tc.right_payload) {\n      auto data = test::MakeSecretTensorReference(named_tensor.name,\n                                                  named_tensor.tensor->Type());\n      input_datas.push_back(std::move(data));\n    }\n    builder.AddInput(SecretJoin::kRightPayload, input_datas);\n  }\n\n  // Add outputs\n  {\n    std::vector<pb::Tensor> outputs;\n    for (const auto& named_tensor : tc.expect_left_output) {\n      auto data = test::MakeSecretTensorReference(named_tensor.name,\n                                                  named_tensor.tensor->Type());\n      outputs.push_back(std::move(data));\n    }\n    builder.AddOutput(SecretJoin::kOutLeft, outputs);\n  }\n  {\n    std::vector<pb::Tensor> outputs;\n    for (const auto& named_tensor : tc.expect_right_output) {\n      auto data = test::MakeSecretTensorReference(named_tensor.name,\n                                                  named_tensor.tensor->Type());\n      outputs.push_back(std::move(data));\n    }\n    builder.AddOutput(SecretJoin::kOutRight, outputs);\n  }\n\n  return builder.Build();\n}\n\nvoid SecretJoinTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                                const SecretJoinTestCase& tc) {\n  test::FeedInputsAsSecret(ctxs, tc.left_key);\n  test::FeedInputsAsSecret(ctxs, tc.right_key);\n  test::FeedInputsAsSecret(ctxs, tc.left_payload);\n  test::FeedInputsAsSecret(ctxs, tc.right_payload);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/shape.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/shape.h\"\n\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Shape::kOpType(\"Shape\");\n\nconst std::string& Shape::Type() const { return kOpType; }\n\nvoid Shape::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() > 0, \"Shape input size must > 0\");\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"Shape input {} and output {} should have the same size\", kIn,\n               kOut);\n\n  YACL_ENFORCE(util::AreTensorsStatusMatched(\n                   outputs, pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"Shape output tensors' status should all be private\");\n}\n\nvoid Shape::Execute(ExecContext* ctx) {\n  const auto& input_pbs = ctx->GetInput(kIn);\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    const auto& input_pb = input_pbs[i];\n    std::pair<int64_t /* row count */, int64_t /* column count */> shapes;\n    shapes.second = 1;  // tensor only contains one column.\n    if (util::IsTensorStatusMatched(input_pb, pb::TENSORSTATUS_PRIVATE)) {\n      auto tensor = ctx->GetTensorTable()->GetTensor(input_pb.name());\n      YACL_ENFORCE(tensor, \"get private tensor failed, name={}\",\n                   input_pb.name());\n      shapes.first = tensor->Length();\n    } else if (util::IsTensorStatusMatched(input_pb, pb::TENSORSTATUS_SECRET)) {\n      auto* device_symbols = ctx->GetSession()->GetDeviceSymbols();\n      auto value = device_symbols->getVar(\n          util::SpuVarNameEncoder::GetValueName(input_pb.name()));\n      shapes.first =\n          value.shape().size() > 0 ? value.shape()[0] : value.numel();\n    } else {\n      YACL_THROW(\"not support input status={}\",\n                 pb::TensorStatus_Name(util::GetTensorStatus(input_pb)));\n    }\n\n    auto result = CreateShapeTensor(ctx, shapes);\n\n    ctx->GetTensorTable()->AddTensor(output_pbs[i].name(), std::move(result));\n  }\n}\n\nTensorPtr Shape::CreateShapeTensor(ExecContext* ctx,\n                                   const std::pair<int64_t, int64_t>& shapes) {\n  auto logger = ctx->GetActiveLogger();\n  int64_t axis = kAxisDefault;\n  try {\n    axis = ctx->GetInt64ValueFromAttribute(kAxis);\n  } catch (const ::yacl::EnforceNotMet& e) {\n    SPDLOG_LOGGER_WARN(\n        logger,\n        \"not set attribute axis, default get (row count, 1), exception={}\",\n        e.what());\n  }\n\n  Int64TensorBuilder builder;\n  if (axis == kAxisRow) {\n    builder.Append(shapes.first);\n  } else if (axis == kAxisColumn) {\n    builder.Append(shapes.second);\n  } else {\n    builder.Append(shapes.first);\n    builder.Append(shapes.second);\n  }\n\n  TensorPtr result;\n  builder.Finish(&result);\n\n  return result;\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/shape.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\n/// @brief Shape return the shape of inputs\nclass Shape : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n  static constexpr char kAxis[] = \"axis\";\n\n  static constexpr int64_t kAxisDefault = -1;\n  static constexpr int64_t kAxisRow = 0;\n  static constexpr int64_t kAxisColumn = 1;\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  TensorPtr static CreateShapeTensor(ExecContext* ctx,\n                                     const std::pair<int64_t, int64_t>& shapes);\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/shape_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/shape.h\"\n\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct ShapeTestCase {\n  std::vector<test::NamedTensor> inputs;\n  pb::TensorStatus input_status;\n  int64_t axis;\n  std::vector<test::NamedTensor> expect_outs;\n};\n\nclass ShapeTest : public testing::TestWithParam<\n                      std::tuple<test::SpuRuntimeTestCase, ShapeTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const ShapeTestCase& tc);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const ShapeTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    ShapeBatchTest, ShapeTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ShapeTestCase{\n                .inputs =\n                    {test::NamedTensor(\"a\", TensorFrom(arrow::boolean(),\n                                                       \"[true, false, true]\")),\n                     test::NamedTensor(\"b\", TensorFrom(arrow::int64(),\n                                                       \"[1,2,3,4,5,6,7,null]\")),\n                     test::NamedTensor(\n                         \"c\", TensorFrom(\n                                  arrow::float32(),\n                                  \"[1.1025, 100.245, -10.2, 0.34, 3.1415926]\")),\n                     test::NamedTensor(\n                         \"d\", TensorFrom(arrow::large_utf8(),\n                                         R\"json([\"A\",\"B\",\"C\",\"D\"])json\")),\n                     test::NamedTensor(\"e\", TensorFrom(arrow::int64(), \"[]\"))},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .axis = Shape::kAxisDefault,\n                .expect_outs =\n                    {test::NamedTensor(\"a_out\",\n                                       TensorFrom(arrow::int64(), \"[3,1]\")),\n                     test::NamedTensor(\"b_out\",\n                                       TensorFrom(arrow::int64(), \"[8,1]\")),\n                     test::NamedTensor(\"c_out\",\n                                       TensorFrom(arrow::int64(), \"[5,1]\")),\n                     test::NamedTensor(\"d_out\",\n                                       TensorFrom(arrow::int64(), \"[4,1]\")),\n                     test::NamedTensor(\"e_out\",\n                                       TensorFrom(arrow::int64(), \"[0,1]\"))}},\n            ShapeTestCase{\n                .inputs =\n                    {test::NamedTensor(\"a\", TensorFrom(arrow::boolean(),\n                                                       \"[true, false, true]\")),\n                     test::NamedTensor(\"b\", TensorFrom(arrow::int64(),\n                                                       \"[1,2,3,4,5,6,7,8]\")),\n                     test::NamedTensor(\n                         \"c\", TensorFrom(\n                                  arrow::float32(),\n                                  \"[1.1025, 100.245, -10.2, 0.34, 3.1415926]\")),\n                     test::NamedTensor(\"d\", TensorFrom(arrow::int64(), \"[]\"))},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .axis = Shape::kAxisRow,\n                .expect_outs =\n                    {test::NamedTensor(\"a_out\",\n                                       TensorFrom(arrow::int64(), \"[3]\")),\n                     test::NamedTensor(\"b_out\",\n                                       TensorFrom(arrow::int64(), \"[8]\")),\n                     test::NamedTensor(\"c_out\",\n                                       TensorFrom(arrow::int64(), \"[5]\")),\n                     test::NamedTensor(\"d_out\",\n                                       TensorFrom(arrow::int64(), \"[0]\"))}})),\n    TestParamNameGenerator(ShapeTest));\n\nTEST_P(ShapeTest, works) {\n  // Given\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  // When\n  Shape op;\n  EXPECT_NO_THROW(op.Run(ctx_ptrs[0]));\n\n  // Then\n  // check alice output\n  for (const auto& expect_t : tc.expect_outs) {\n    auto expect_arr = expect_t.tensor->ToArrowChunkedArray();\n    auto out = ctx_ptrs[0]->GetTensorTable()->GetTensor(expect_t.name);\n    ASSERT_TRUE(out);\n    auto out_arr = out->ToArrowChunkedArray();\n    // compare tensor content\n    EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr))\n        << \"expect type = \" << expect_arr->type()->ToString()\n        << \", got type = \" << out_arr->type()->ToString()\n        << \"\\nexpect result = \" << expect_arr->ToString()\n        << \"\\nbut actual got result = \" << out_arr->ToString();\n  }\n}\n\n/// ===================\n/// ShapeTest impl\n/// ===================\n\npb::ExecNode ShapeTest::MakeExecNode(const ShapeTestCase& tc) {\n  test::ExecNodeBuilder builder(Shape::kOpType);\n\n  builder.SetNodeName(\"shape-test\");\n  builder.AddInt64Attr(Shape::kAxis, tc.axis);\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    auto t = test::MakeTensorReference(\n        named_tensor.name, named_tensor.tensor->Type(), tc.input_status);\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(Shape::kIn, inputs);\n\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.expect_outs.size(); ++i) {\n    auto t = test::MakePrivateTensorReference(tc.expect_outs[i].name,\n                                              pb::PrimitiveDataType::INT64);\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(Shape::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid ShapeTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                           const ShapeTestCase& tc) {\n  if (tc.input_status == pb::TENSORSTATUS_PRIVATE) {\n    test::FeedInputsAsPrivate(ctxs[0], tc.inputs);\n  } else {\n    test::FeedInputsAsSecret(ctxs, tc.inputs);\n  }\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/shuffle.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/shuffle.h\"\n\n#include \"libspu/kernel/hlo/shuffle.h\"\n\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Shuffle::kOpType(\"Shuffle\");\nconst std::string& Shuffle::Type() const { return kOpType; }\n\nvoid Shuffle::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() > 0,\n               \"operator Shuffle input {} must have one element at least\", kIn);\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"operator Shuffle output and input should have the same size\");\n\n  YACL_ENFORCE(util::AreTensorsStatusMatchedOneOf(\n      inputs, {pb::TENSORSTATUS_SECRET, pb::TENSORSTATUS_PUBLIC}));\n  YACL_ENFORCE(util::AreTensorsStatusMatchedOneOf(\n      outputs, {pb::TENSORSTATUS_SECRET, pb::TENSORSTATUS_PUBLIC}));\n}\n\nvoid Shuffle::Execute(ExecContext* ctx) {\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto inputs = ctx->GetInputValues(kIn);\n  auto outputs = spu::kernel::hlo::Shuffle(sctx, inputs, 0);\n  ctx->SetOutputValues(kOut, outputs);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/shuffle.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass Shuffle : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/shuffle_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/shuffle.h\"\n\n#include \"gmock/gmock.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n#include \"engine/util/psi/batch_provider.h\"\n\nnamespace scql::engine::op {\n\nstruct ShuffleTestCase {\n  std::vector<test::NamedTensor> inputs;\n  std::vector<std::string> output_names;\n  std::vector<std::string> output_values;\n};\n\nclass ShuffleTest : public testing::TestWithParam<\n                        std::tuple<test::SpuRuntimeTestCase, ShuffleTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const ShuffleTestCase& tc);\n\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const ShuffleTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    ShuffleBatchTest, ShuffleTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            ShuffleTestCase{\n                .inputs = {test::NamedTensor(\"x1\", TensorFrom(arrow::int64(),\n                                                              \"[1,2,3,4,5]\")),\n                           test::NamedTensor(\"x2\",\n                                             TensorFrom(arrow::int64(),\n                                                        \"[10,11,12,13,14]\"))},\n                .output_names = {\"y1\", \"y2\"},\n                .output_values = {\"1,10\", \"2,11\", \"3,12\", \"4,13\", \"5,14\"}},\n            ShuffleTestCase{.inputs = {test::NamedTensor(\n                                \"x1\", TensorFrom(arrow::int64(), \"[1]\"))},\n                            .output_names = {\"y1\"},\n                            .output_values = {\"1\"}},\n            ShuffleTestCase{.inputs = {test::NamedTensor(\n                                \"x1\", TensorFrom(arrow::int64(), \"[]\"))},\n                            .output_names = {\"y1\"},\n                            .output_values = {}})),\n    TestParamNameGenerator(ShuffleTest));\n\nTEST_P(ShuffleTest, Works) {\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n\n  auto node = MakeExecNode(tc);\n\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  EXPECT_NO_THROW(test::RunAsync<Shuffle>(ctx_ptrs));\n\n  std::vector<TensorPtr> outs;\n  EXPECT_NO_THROW({\n    for (const auto& val_name : tc.output_names) {\n      auto t = test::RevealSecret(ctx_ptrs, val_name);\n      ASSERT_TRUE(t != nullptr);\n      EXPECT_EQ(t->Length(), tc.output_values.size());\n      outs.push_back(t);\n    }\n  });\n\n  util::BatchProvider provider(outs);\n  auto shuffle_result = provider.ReadNextBatch();\n  EXPECT_THAT(shuffle_result,\n              ::testing::UnorderedElementsAreArray(tc.output_values));\n}\n\npb::ExecNode ShuffleTest::MakeExecNode(const ShuffleTestCase& tc) {\n  test::ExecNodeBuilder builder(Shuffle::kOpType);\n\n  builder.SetNodeName(\"shuffle-test\");\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    auto t = test::MakeSecretTensorReference(named_tensor.name,\n                                             named_tensor.tensor->Type());\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(Shuffle::kIn, inputs);\n\n  std::vector<pb::Tensor> outputs;\n  for (size_t i = 0; i < tc.output_names.size(); ++i) {\n    auto t = test::MakeTensorAs(tc.output_names[i], inputs[i]);\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(Shuffle::kOut, outputs);\n\n  return builder.Build();\n}\n\nvoid ShuffleTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                             const ShuffleTestCase& tc) {\n  test::FeedInputsAsSecret(ctxs, tc.inputs);\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/sort.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/sort.h\"\n\n#include \"arrow/api.h\"\n#include \"arrow/compute/api.h\"\n#include \"arrow/table.h\"\n#include \"libspu/kernel/hlo/sort.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/table_util.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Sort::kOpType(\"Sort\");\nconst std::string& Sort::Type() const { return kOpType; }\n\nvoid Sort::Validate(ExecContext* ctx) {\n  const auto& sort_keys = ctx->GetInput(kInKey);\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n  YACL_ENFORCE(sort_keys.size() > 0);\n  YACL_ENFORCE(inputs.size() > 0);\n  YACL_ENFORCE(inputs.size() == outputs.size());\n\n  auto input_status = util::GetTensorStatus(inputs[0]);\n  YACL_ENFORCE(input_status == pb::TENSORSTATUS_PRIVATE ||\n                   input_status == pb::TENSORSTATUS_SECRET,\n               \"operator sort only supports private or secret inputs\");\n  // input and output should have the same status\n  YACL_ENFORCE(util::AreTensorsStatusMatched(sort_keys, input_status));\n  YACL_ENFORCE(util::AreTensorsStatusMatched(inputs, input_status));\n  YACL_ENFORCE(util::AreTensorsStatusMatched(outputs, input_status));\n}\n\nvoid Sort::Execute(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  auto input_status = util::GetTensorStatus(inputs[0]);\n  if (input_status == pb::TENSORSTATUS_PRIVATE) {\n    return SortInPlain(ctx);\n  } else {\n    return SortInSecret(ctx);\n  }\n}\n\nvoid Sort::SortInPlain(ExecContext* ctx) {\n  const auto& sort_key_pbs = ctx->GetInput(kInKey);\n  const auto& in_pbs = ctx->GetInput(kIn);\n\n  std::vector<arrow::compute::SortKey> sort_keys;\n\n  // Get sort directions - either a single bool or array of bools\n  std::vector<bool> reverses = ctx->GetBooleanValuesFromAttribute(kReverseAttr);\n  YACL_ENFORCE(reverses.size() == sort_key_pbs.size());\n  sort_keys.reserve(sort_key_pbs.size());\n  for (int64_t i = 0; i < sort_key_pbs.size(); i++) {\n    arrow::compute::SortOrder order =\n        reverses[i] ? arrow::compute::SortOrder::Descending\n                    : arrow::compute::SortOrder::Ascending;\n    sort_keys.emplace_back(sort_key_pbs[i].name(), order);\n  }\n  RepeatedPbTensor input_tensors;\n\n  std::vector<std::string> fields;\n  for (int i = 0; i < in_pbs.size(); i++) {\n    // TODO: if the duplicate columns are unavoidable in some scenarios consider\n    // to maitain the mapping relationship and reconstruct the table after\n    // sorting\n    YACL_ENFORCE(std::find(fields.begin(), fields.end(), in_pbs[i].name()) ==\n                     fields.end(),\n                 \"duplicate field '{}'\", in_pbs[i].name());\n    fields.push_back(in_pbs[i].name());\n\n    // From protobuf doc:\n    // Copying to the end of this RepeatedPtrField is slowest of all; it can't\n    // reliably copy-construct to the last element of this RepeatedPtrField, for\n    // example (unlike std::vector).\n    // We currently block this API.  The right way to add to the end is to call\n    // Add() and modify the element it points to.\n    // If you must add an existing value, call *Add() = value;\n    *(input_tensors.Add()) = in_pbs[i];\n  }\n\n  for (int i = 0; i < sort_key_pbs.size(); i++) {\n    // payload fields already contains sort key\n    if (std::find(fields.begin(), fields.end(), sort_key_pbs[i].name()) !=\n        fields.end()) {\n      continue;\n    }\n    *(input_tensors.Add()) = sort_key_pbs[i];\n  }\n\n  std::shared_ptr<arrow::Table> input_table =\n      util::ConstructTableFromTensors(ctx, input_tensors);\n\n  arrow::compute::SortOptions sort_options(sort_keys);\n\n  auto status = arrow::compute::SortIndices(input_table, sort_options);\n  YACL_ENFORCE(status.ok(), \"failed to sort indices\");\n  const std::shared_ptr<arrow::Array>& indices = status.ValueOrDie();\n\n  auto output_status = arrow::compute::Take(input_table, indices);\n  YACL_ENFORCE(output_status.ok(), \"failed to take indices after sorting\");\n  auto output_table = output_status.ValueOrDie().table();\n  YACL_ENFORCE(output_table, \"failed to convert datum to table\");\n\n  const auto& out_pbs = ctx->GetOutput(kOut);\n  YACL_ENFORCE(out_pbs.size() <= (int)output_table->fields().size(),\n               \"tensors' size after sorted({}) is less than expected({})\",\n               output_table->fields().size(), out_pbs.size());\n  for (int i = 0; i < out_pbs.size(); i++) {\n    ctx->GetTensorTable()->AddTensor(out_pbs[i].name(),\n                                     TensorFrom(output_table->column(i)));\n  }\n}\n\nvoid Sort::SortInSecret(ExecContext* ctx) {\n  const auto& sort_key_pbs = ctx->GetInput(kInKey);\n  const auto& in_pbs = ctx->GetInput(kIn);\n  const auto& out_pbs = ctx->GetOutput(kOut);\n\n  // Get sort directions - either a single bool or array of bools\n  std::vector<bool> reverses = ctx->GetBooleanValuesFromAttribute(kReverseAttr);\n  YACL_ENFORCE(reverses.size() == sort_key_pbs.size());\n  auto* symbols = ctx->GetSession()->GetDeviceSymbols();\n  std::vector<spu::Value> inputs;\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto reverse = reverses[0];\n  for (size_t i = 0; i < sort_key_pbs.size(); ++i) {\n    const auto& sort_key_pb = sort_key_pbs[i];\n    auto value = symbols->getVar(\n        util::SpuVarNameEncoder::GetValueName(sort_key_pb.name()));\n    if (reverses[i] != reverse) {\n      inputs.push_back(util::Invert(sctx, value));\n    } else {\n      inputs.push_back(value);\n    }\n  }\n  size_t sort_key_num = inputs.size();\n  for (const auto& in_pb : in_pbs) {\n    auto value =\n        symbols->getVar(util::SpuVarNameEncoder::GetValueName(in_pb.name()));\n    inputs.push_back(value);\n  }\n\n  auto sort_direction = spu::kernel::hal::SortDirection::Ascending;\n  if (reverse) {\n    sort_direction = spu::kernel::hal::SortDirection::Descending;\n  }\n  // NOTE: use default performance hint for SimpleSort\n  auto results = spu::kernel::hlo::SimpleSort(sctx, inputs, 0, sort_direction,\n                                              sort_key_num, -1, true);\n\n  for (int i = 0; i < out_pbs.size(); ++i) {\n    auto idx = sort_key_num + i;\n    symbols->setVar(util::SpuVarNameEncoder::GetValueName(out_pbs[i].name()),\n                    results[idx]);\n  }\n\n  // TODO: sort validity too\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/sort.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass Sort : public Operator {\n public:\n  static const std::string kOpType;\n  static constexpr char kInKey[] = \"Key\";\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n  static constexpr char kReverseAttr[] = \"reverse\";\n\n  const std::string& Type() const override;\n\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n private:\n  static void SortInPlain(ExecContext* ctx);\n  static void SortInSecret(ExecContext* ctx);\n};\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/sort_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/sort.h\"\n\n#include <vector>\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct SortTestCase {\n  std::vector<bool> reverse;\n  // input and output share the same status\n  pb::TensorStatus input_status;\n  std::vector<test::NamedTensor> sort_keys;\n  std::vector<test::NamedTensor> inputs;\n  std::vector<test::NamedTensor> outputs;\n};\n\nclass SortTest : public testing::TestWithParam<\n                     std::tuple<test::SpuRuntimeTestCase, SortTestCase>> {\n protected:\n  static pb::ExecNode MakeExecNode(const SortTestCase& tc);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const SortTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    SortBatchTest, SortTest,\n    testing::Combine(\n        test::SpuTestValuesMultiPC,\n        testing::Values(\n            SortTestCase{\n                .reverse = {true},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .sort_keys = {test::NamedTensor(\n                    \"k1\", TensorFrom(arrow::int64(), \"[5,1,2,4,3]\"))},\n                .inputs = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::int64(), \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::int64(), \"[10,13,14,12,11]\"))}},\n            SortTestCase{\n                .reverse = {false, false},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .sort_keys =\n                    {test::NamedTensor(\"k1\", TensorFrom(arrow::int64(),\n                                                        \"[2,1,2,4,3]\")),\n                     test::NamedTensor(\"k2\", TensorFrom(arrow::int64(),\n                                                        \"[2,1,1,3,4]\"))},\n                .inputs = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::int64(), \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::int64(), \"[11,12,10,14,13]\"))}},\n            // testcase: SimpleSort can sort by multiple keys\n            SortTestCase{\n                .reverse = {false, false},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .sort_keys =\n                    {test::NamedTensor(\"k1\", TensorFrom(arrow::int64(),\n                                                        \"[2,1,2,2,3]\")),\n                     test::NamedTensor(\"k2\", TensorFrom(arrow::int64(),\n                                                        \"[3,1,1,2,4]\"))},\n                .inputs = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::int64(), \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::int64(), \"[11,12,13,10,14]\"))}},\n            // testcase: empty inputs\n            SortTestCase{\n                .reverse = {false},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .sort_keys = {test::NamedTensor(\"k1\", TensorFrom(arrow::int64(),\n                                                                 \"[]\"))},\n                .inputs = {test::NamedTensor(\"x1\",\n                                             TensorFrom(arrow::int64(), \"[]\"))},\n                .outputs = {test::NamedTensor(\"y1\", TensorFrom(arrow::int64(),\n                                                               \"[]\"))}},\n            SortTestCase{\n                .reverse = {false},\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .sort_keys = {test::NamedTensor(\n                    \"k1\", TensorFrom(arrow::int64(), \"[5,1,2,4,3]\"))},\n                .inputs = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::int64(), \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::int64(), \"[11,12,14,13,10]\"))}},\n            SortTestCase{\n                .reverse = {false},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .sort_keys = {test::NamedTensor(\n                    \"k1\", TensorFrom(arrow::int64(), \"[5,1,2,4,3]\"))},\n                .inputs = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::int64(), \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::int64(), \"[11,12,14,13,10]\"))}},\n            SortTestCase{\n                .reverse = {true},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .sort_keys = {test::NamedTensor(\n                    \"k1\", TensorFrom(arrow::int64(), \"[5,1,2,4,3]\"))},\n                .inputs = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::int64(), \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::int64(), \"[10,13,14,12,11]\"))}},\n            SortTestCase{\n                .reverse = {false, false},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .sort_keys =\n                    {test::NamedTensor(\"k1\", TensorFrom(arrow::int64(),\n                                                        \"[2,1,2,4,3]\")),\n                     test::NamedTensor(\"k2\", TensorFrom(arrow::int64(),\n                                                        \"[2,1,1,3,4]\"))},\n                .inputs = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::int64(), \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::int64(), \"[11,12,10,14,13]\"))}},\n            // testcase: SimpleSort can sort by multiple keys\n            SortTestCase{\n                .reverse = {false, false},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .sort_keys =\n                    {test::NamedTensor(\"k1\", TensorFrom(arrow::int64(),\n                                                        \"[2,1,2,2,3]\")),\n                     test::NamedTensor(\"k2\", TensorFrom(arrow::int64(),\n                                                        \"[3,1,1,2,4]\"))},\n                .inputs = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::int64(), \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::int64(), \"[11,12,13,10,14]\"))}},\n            // testcase: empty inputs\n            SortTestCase{\n                .reverse = {false},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .sort_keys = {test::NamedTensor(\"k1\", TensorFrom(arrow::int64(),\n                                                                 \"[]\"))},\n                .inputs = {test::NamedTensor(\"x1\",\n                                             TensorFrom(arrow::int64(), \"[]\"))},\n                .outputs = {test::NamedTensor(\"y1\", TensorFrom(arrow::int64(),\n                                                               \"[]\"))}},\n            // testcase: empty inputs\n            SortTestCase{\n                .reverse = {false},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .sort_keys = {test::NamedTensor(\n                    \"k1\", TensorFrom(arrow::boolean(),\n                                     \"[true,false,false,true,true]\"))},\n                .inputs = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::boolean(),\n                                     \"[true,false,false,true,true]\"))},\n                .outputs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::boolean(),\n                                     \"[false,false,true,true,true]\"))}},\n            // testcase: sort by directions\n            SortTestCase{\n                .reverse = {false, true},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .sort_keys =\n                    {test::NamedTensor(\"k1\", TensorFrom(arrow::int64(),\n                                                        \"[2,1,2,2,3]\")),\n                     test::NamedTensor(\"k2\", TensorFrom(arrow::int64(),\n                                                        \"[3,1,1,2,4]\"))},\n                .inputs = {test::NamedTensor(\"x1\", TensorFrom(arrow::int64(),\n                                                              \"[2,1,2,2,3]\")),\n                           test::NamedTensor(\"x2\", TensorFrom(arrow::int64(),\n                                                              \"[3,1,1,2,4]\")),\n                           test::NamedTensor(\"x3\",\n                                             TensorFrom(arrow::int64(),\n                                                        \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\"y1\", TensorFrom(arrow::int64(),\n                                                               \"[1,2,2,2,3]\")),\n                            test::NamedTensor(\"y2\", TensorFrom(arrow::int64(),\n                                                               \"[1,3,2,1,4]\")),\n                            test::NamedTensor(\"y3\",\n                                              TensorFrom(arrow::int64(),\n                                                         \"[11,10,13,12,14]\"))}},\n            // testcase: sort by directions\n            SortTestCase{\n                .reverse = {false, false},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .sort_keys =\n                    {test::NamedTensor(\"k1\", TensorFrom(arrow::int64(),\n                                                        \"[2,1,2,2,3]\")),\n                     test::NamedTensor(\n                         \"k2\", TensorFrom(arrow::boolean(),\n                                          \"[true,false,true,false,true]\"))},\n                .inputs = {test::NamedTensor(\"x1\", TensorFrom(arrow::int64(),\n                                                              \"[2,1,2,2,3]\")),\n                           test::NamedTensor(\n                               \"x2\",\n                               TensorFrom(arrow::boolean(),\n                                          \"[true,false,true,false,true]\")),\n                           test::NamedTensor(\"x3\",\n                                             TensorFrom(arrow::int64(),\n                                                        \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\"y1\", TensorFrom(arrow::int64(),\n                                                               \"[1,2,2,2,3]\")),\n                            test::NamedTensor(\n                                \"y2\",\n                                TensorFrom(arrow::boolean(),\n                                           \"[false,false,true,true,true]\")),\n                            test::NamedTensor(\"y3\",\n                                              TensorFrom(arrow::int64(),\n                                                         \"[11,13,10,12,14]\"))}},\n            // testcase: sort by directions\n            SortTestCase{\n                .reverse = {false, false, true, true},\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .sort_keys =\n                    {test::NamedTensor(\"k1\", TensorFrom(arrow::int64(),\n                                                        \"[2,1,2,2,3]\")),\n                     test::NamedTensor(\"k2\", TensorFrom(arrow::int64(),\n                                                        \"[3,1,1,2,4]\")),\n                     test::NamedTensor(\"k3\", TensorFrom(arrow::int64(),\n                                                        \"[6,7,7,8,8]\")),\n                     test::NamedTensor(\"k4\", TensorFrom(arrow::int64(),\n                                                        \"[-3,-3,-4,-4,-5]\"))},\n                .inputs = {test::NamedTensor(\n                    \"x1\", TensorFrom(arrow::int64(), \"[10,11,12,13,14]\"))},\n                .outputs = {test::NamedTensor(\n                    \"y1\", TensorFrom(arrow::int64(), \"[11,12,13,10,14]\"))}})),\n    TestParamNameGenerator(SortTest));\n\nTEST_P(SortTest, Works) {\n  auto parm = GetParam();\n  auto tc = std::get<1>(parm);\n  auto node = MakeExecNode(tc);\n  auto sessions = test::MakeMultiPCSession(std::get<0>(parm));\n\n  std::vector<ExecContext> exec_ctxs;\n  exec_ctxs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctxs.emplace_back(node, session.get());\n  }\n\n  // feed inputs\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctxs.size());\n  for (auto& exec_ctx : exec_ctxs) {\n    ctx_ptrs.emplace_back(&exec_ctx);\n  }\n  FeedInputs(ctx_ptrs, tc);\n\n  if (tc.input_status == pb::TENSORSTATUS_SECRET) {\n    EXPECT_NO_THROW(test::RunAsync<Sort>(ctx_ptrs));\n  } else {\n    EXPECT_NO_THROW(test::RunAsync<Sort>({ctx_ptrs[0]}));\n  }\n\n  for (const auto& named_tensor : tc.outputs) {\n    TensorPtr actual_output = nullptr;\n    if (tc.input_status == pb::TENSORSTATUS_SECRET) {\n      EXPECT_NO_THROW(\n          { actual_output = test::RevealSecret(ctx_ptrs, named_tensor.name); });\n    } else {\n      actual_output =\n          ctx_ptrs[0]->GetTensorTable()->GetTensor(named_tensor.name);\n    }\n\n    ASSERT_TRUE(actual_output != nullptr);\n    auto actual_arr = actual_output->ToArrowChunkedArray();\n    auto expect_arr = named_tensor.tensor->ToArrowChunkedArray();\n    EXPECT_TRUE(actual_arr->ApproxEquals(\n        *expect_arr, arrow::EqualOptions::Defaults().atol(0.001)))\n        << \"\\nexpect result = \" << expect_arr->ToString()\n        << \"\\nbut actual got result = \" << actual_arr->ToString();\n  }\n}\n\npb::ExecNode SortTest::MakeExecNode(const SortTestCase& tc) {\n  test::ExecNodeBuilder builder(Sort::kOpType);\n\n  builder.SetNodeName(\"sort-test\");\n  std::vector<pb::Tensor> sort_keys;\n  for (const auto& named_tensor : tc.sort_keys) {\n    auto t = test::MakeTensorReference(\n        named_tensor.name, named_tensor.tensor->Type(), tc.input_status);\n    sort_keys.push_back(std::move(t));\n  }\n  builder.AddInput(Sort::kInKey, sort_keys);\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    auto t = test::MakeTensorReference(\n        named_tensor.name, named_tensor.tensor->Type(), tc.input_status);\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(Sort::kIn, inputs);\n\n  std::vector<pb::Tensor> outputs;\n  for (const auto& named_tensor : tc.outputs) {\n    auto t = test::MakeTensorReference(\n        named_tensor.name, named_tensor.tensor->Type(), tc.input_status);\n    outputs.push_back(std::move(t));\n  }\n  builder.AddOutput(Sort::kOut, outputs);\n\n  builder.AddBooleansAttr(Sort::kReverseAttr, tc.reverse);\n\n  return builder.Build();\n}\n\nvoid SortTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                          const SortTestCase& tc) {\n  if (tc.input_status == pb::TENSORSTATUS_SECRET) {\n    test::FeedInputsAsSecret(ctxs, tc.sort_keys);\n    test::FeedInputsAsSecret(ctxs, tc.inputs);\n  } else {\n    test::FeedInputsAsPrivate(ctxs[0], tc.sort_keys);\n    test::FeedInputsAsPrivate(ctxs[0], tc.inputs);\n  }\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/test_util.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/test_util.h\"\n\n#include <future>\n#include <memory>\n\n#include \"libspu/core/config.h\"\n\n#include \"engine/framework/session.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op::test {\n\nstatic yacl::link::FactoryMem g_mem_link_factory;\n\nnamespace {\n\npb::TensorList ToTensorList(const std::vector<pb::Tensor>& tensors) {\n  pb::TensorList list;\n  for (const auto& tensor : tensors) {\n    auto* new_tensor = list.add_tensors();\n    new_tensor->CopyFrom(tensor);\n  }\n  return list;\n}\n\n}  // namespace\n\npb::JobStartParams::Party BuildParty(const std::string& code, int32_t rank) {\n  pb::JobStartParams::Party party;\n  party.set_code(code);\n  party.set_name(\"party \" + code);\n  party.set_host(code + \".com\");\n  party.set_rank(rank);\n  return party;\n}\n\nspu::RuntimeConfig MakeSpuRuntimeConfigForTest(\n    spu::ProtocolKind protocol_kind, bool enable_colocated_optimization) {\n  spu::RuntimeConfig config;\n  config.protocol = protocol_kind;\n  config.field = spu::FieldType::FM64;\n  config.sigmoid_mode = spu::RuntimeConfig::SIGMOID_REAL;\n  config.experimental_enable_colocated_optimization =\n      enable_colocated_optimization;\n  spu::populateRuntimeConfig(config);\n  return config;\n}\n\nstd::shared_ptr<Session> Make1PCSession(Router* ds_router,\n                                        DatasourceAdaptorMgr* ds_mgr) {\n  pb::JobStartParams params;\n  params.set_party_code(kPartyAlice);\n  params.set_job_id(\"1PC-session\");\n  params.set_time_zone(\"+08:00\");\n  params.mutable_spu_runtime_cfg()->CopyFrom(\n      MakeSpuRuntimeConfigForTest(spu::ProtocolKind::REF2K).ToProto());\n  SessionOptions options;\n  auto* alice = params.add_parties();\n  alice->CopyFrom(BuildParty(kPartyAlice, 0));\n  pb::DebugOptions debug_opts;\n  // When there is only one party involved, the protocol will not be validated,\n  // so the related parameters are dummy.\n  std::vector<spu::ProtocolKind> allowed_protocols{spu::ProtocolKind::REF2K,\n                                                   spu::ProtocolKind::CHEETAH,\n                                                   spu::ProtocolKind::SEMI2K};\n  return std::make_shared<Session>(options, params, debug_opts,\n                                   &g_mem_link_factory, ds_router, ds_mgr,\n                                   allowed_protocols);\n}\n\nstd::vector<std::shared_ptr<Session>> MakeMultiPCSession(\n    const SpuRuntimeTestCase test_case) {\n  pb::JobStartParams common_params;\n  common_params.set_job_id(\"session_multi_pc\");\n  for (size_t i = 0; i < test_case.party_size; ++i) {\n    auto party = BuildParty(kPartyCodes[i], i);\n    auto* p = common_params.add_parties();\n    p->CopyFrom(party);\n  }\n  common_params.mutable_spu_runtime_cfg()->CopyFrom(\n      MakeSpuRuntimeConfigForTest(test_case.protocol,\n                                  test_case.enable_colocated_optimization)\n          .ToProto());\n\n  std::vector<std::future<std::shared_ptr<Session>>> futures;\n  SessionOptions options;\n  options.psi_config.psi_curve_type = psi::CURVE_FOURQ;\n  auto create_session = [&](const pb::JobStartParams& params) {\n    pb::DebugOptions debug_opts;\n    std::vector<spu::ProtocolKind> allowed_protocols{spu::ProtocolKind::CHEETAH,\n                                                     spu::ProtocolKind::SEMI2K,\n                                                     spu::ProtocolKind::ABY3};\n    return std::make_shared<Session>(options, params, debug_opts,\n                                     &g_mem_link_factory, nullptr, nullptr,\n                                     allowed_protocols);\n  };\n  for (size_t i = 0; i < test_case.party_size; ++i) {\n    pb::JobStartParams params;\n    params.CopyFrom(common_params);\n    params.set_party_code(kPartyCodes[i]);\n    futures.push_back(std::async(create_session, params));\n  }\n\n  std::vector<std::shared_ptr<Session>> results;\n  results.reserve(futures.size());\n  for (auto& future : futures) {\n    results.push_back(future.get());\n  }\n\n  return results;\n}\n\nExecNodeBuilder::ExecNodeBuilder(const std::string& op_type) {\n  node_.set_op_type(op_type);\n}\n\nExecNodeBuilder& ExecNodeBuilder::SetNodeName(const std::string& node_name) {\n  node_.set_node_name(node_name);\n  return *this;\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddInput(const std::string& name,\n                                           pb::TensorList tensors) {\n  auto& inputs = *node_.mutable_inputs();\n  inputs[name] = std::move(tensors);\n  return *this;\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddInput(\n    const std::string& name, const std::vector<pb::Tensor>& tensors) {\n  return AddInput(name, ToTensorList(tensors));\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddOutput(const std::string& name,\n                                            pb::TensorList tensors) {\n  auto& outputs = *node_.mutable_outputs();\n  outputs[name] = std::move(tensors);\n  return *this;\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddOutput(\n    const std::string& name, const std::vector<pb::Tensor>& tensors) {\n  return AddOutput(name, ToTensorList(tensors));\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddStringAttr(const std::string& name,\n                                                const std::string& value) {\n  return AddStringsAttr(name, std::vector<std::string>{value});\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddStringsAttr(\n    const std::string& name, const std::vector<std::string>& values) {\n  auto& attrs = *node_.mutable_attributes();\n  util::SetStringValues(attrs[name].mutable_t(), values);\n  return *this;\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddInt64Attr(const std::string& name,\n                                               int64_t value) {\n  return AddInt64sAttr(name, std::vector<int64_t>{value});\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddInt64sAttr(\n    const std::string& name, const std::vector<int64_t>& values) {\n  auto& attrs = *node_.mutable_attributes();\n  util::SetInt64Values(attrs[name].mutable_t(), values);\n  return *this;\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddBooleanAttr(const std::string& name,\n                                                 bool value) {\n  auto& attrs = *node_.mutable_attributes();\n  util::SetBooleanValues(attrs[name].mutable_t(), std::vector<bool>{value});\n  return *this;\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddBooleansAttr(\n    const std::string& name, const std::vector<bool>& values) {\n  auto& attrs = *node_.mutable_attributes();\n  util::SetBooleanValues(attrs[name].mutable_t(), values);\n  return *this;\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddDoubleAttr(const std::string& name,\n                                                double value) {\n  return AddDoubleAttrs(name, std::vector<double>{value});\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddDoubleAttrs(\n    const std::string& name, const std::vector<double>& value) {\n  auto& attrs = *node_.mutable_attributes();\n  util::SetDoubleValues(attrs[name].mutable_t(), value);\n  return *this;\n}\n\nExecNodeBuilder& ExecNodeBuilder::AddAttr(const std::string& name,\n                                          const pb::Tensor& tensor) {\n  auto& attrs = *node_.mutable_attributes();\n  attrs[name].mutable_t()->CopyFrom(tensor);\n  return *this;\n}\n\npb::ExecNode ExecNodeBuilder::Build() { return node_; }\n\npb::Tensor MakeTensorReference(const std::string& name,\n                               pb::PrimitiveDataType dtype,\n                               pb::TensorStatus visibility, int ref_count) {\n  pb::Tensor tensor;\n  tensor.set_name(name);\n  tensor.set_elem_type(dtype);\n  tensor.set_option(pb::TensorOptions::REFERENCE);\n  tensor.set_ref_num(ref_count);\n  {\n    auto& annotation = *tensor.mutable_annotation();\n    annotation.set_status(visibility);\n  }\n  return tensor;\n}\n\npb::Tensor MakeTensorAs(const std::string& name, const pb::Tensor& ref) {\n  pb::Tensor tensor;\n  tensor.CopyFrom(ref);\n  tensor.set_name(name);\n  return tensor;\n}\n\nvoid FeedInputsAsPrivate(ExecContext* ctx,\n                         const std::vector<test::NamedTensor>& ts) {\n  auto* tensor_table = ctx->GetTensorTable();\n  for (const auto& named_tensor : ts) {\n    tensor_table->AddTensor(named_tensor.name, named_tensor.tensor);\n  }\n}\n\nnamespace {\nvoid FeedInputAsShares(const std::vector<ExecContext*>& ctxs,\n                       const test::NamedTensor& input, spu::Visibility vtype) {\n  auto proc = [](ExecContext* ctx, const test::NamedTensor& input,\n                 spu::Visibility vtype) {\n    spu::device::ColocatedIo cio(ctx->GetSession()->GetSpuContext());\n\n    util::SpuInfeedHelper infeed_helper(&cio);\n    if (ctx->GetSession()->GetLink()->Rank() == 0) {\n      TensorPtr in_t = input.tensor;\n      if (in_t->Type() == pb::PrimitiveDataType::STRING) {\n        in_t = ctx->GetSession()->StringToHash(*in_t);\n      }\n      if (vtype == spu::VIS_SECRET) {\n        infeed_helper.InfeedTensorAsSecret(input.name, *in_t);\n      } else {\n        infeed_helper.InfeedTensorAsPublic(input.name, *in_t);\n      }\n    }\n\n    infeed_helper.Sync();\n\n    auto& symbols = cio.deviceSymbols();\n    ctx->GetSession()->MergeDeviceSymbolsFrom(symbols);\n  };\n\n  std::vector<std::future<void>> futures;\n  for (size_t i = 0; i < ctxs.size(); ++i) {\n    auto future = std::async(proc, ctxs[i], input, vtype);\n    futures.push_back(std::move(future));\n  }\n\n  for (auto& future : futures) {\n    future.get();\n  }\n}\n}  // namespace\n\nvoid FeedInputsAsSecret(const std::vector<ExecContext*>& ctxs,\n                        const std::vector<test::NamedTensor>& ts) {\n  for (size_t i = 0; i < ts.size(); ++i) {\n    FeedInputAsShares(ctxs, ts[i], spu::VIS_SECRET);\n  }\n}\n\nvoid FeedInputsAsPublic(const std::vector<ExecContext*>& ctxs,\n                        const std::vector<test::NamedTensor>& ts) {\n  for (size_t i = 0; i < ts.size(); ++i) {\n    FeedInputAsShares(ctxs, ts[i], spu::VIS_PUBLIC);\n  }\n}\n\nTensorPtr RevealSecret(const std::vector<ExecContext*>& ctxs,\n                       const std::string& name) {\n  auto reveal = [](ExecContext* ctx, const std::string& name) -> TensorPtr {\n    util::SpuOutfeedHelper io(ctx->GetSession()->GetSpuContext(),\n                              ctx->GetSession()->GetDeviceSymbols());\n    // reveal to rank 0: alice\n    return io.RevealTo(name, 0);\n  };\n  std::vector<std::future<TensorPtr>> futures;\n  for (auto* ctx : ctxs) {\n    auto future = std::async(reveal, ctx, name);\n    futures.push_back(std::move(future));\n  }\n\n  for (size_t i = 1; i < futures.size(); ++i) {\n    futures[i].get();\n  }\n  return futures[0].get();\n}\n\nvoid RunOpAsync(const std::vector<ExecContext*>& exec_ctxs,\n                OpCreator create_op_fn) {\n  std::vector<std::future<void>> futures(exec_ctxs.size());\n  for (size_t idx = 0; idx < exec_ctxs.size(); ++idx) {\n    futures[idx] = std::async(\n        std::launch::async,\n        [&](ExecContext* ectx) {\n          auto op = create_op_fn();\n          op->Run(ectx);\n        },\n        exec_ctxs[idx]);\n  }\n\n  bool is_throw = false;\n  for (size_t idx = 0; idx < futures.size(); ++idx) {\n    try {\n      futures[idx].get();\n    } catch (const std::exception& e) {\n      SPDLOG_ERROR(\"catch throw for idx={}, exception={}\", idx, e.what());\n      is_throw = true;\n    }\n  }\n  if (is_throw) {\n    YACL_THROW(\"op async err\");\n  }\n}\n\nvoid CheckTensorEqual(const TensorPtr& left, const TensorPtr& right) {\n  auto left_arr = left->ToArrowChunkedArray();\n  auto right_arr = right->ToArrowChunkedArray();\n\n  EXPECT_EQ(left_arr->type(), right_arr->type())\n      << \"left type = \" << left_arr->type()\n      << \",right type = \" << right_arr->type();\n\n  EXPECT_TRUE(left_arr->ApproxEquals(*right_arr))\n      << \"left = \" << left_arr->ToString()\n      << \"\\nright = \" << right_arr->ToString();\n}\n\n}  // namespace scql::engine::op::test\n"
  },
  {
    "path": "engine/operator/test_util.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <cmath>\n#include <functional>\n#include <vector>\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/datasource/datasource_adaptor_mgr.h\"\n#include \"engine/datasource/router.h\"\n#include \"engine/framework/exec.h\"\n#include \"engine/framework/operator.h\"\n#include \"engine/framework/session.h\"\n\n#ifndef TestParamNameGenerator\n#define TestParamNameGenerator(TestCaseClass)                                \\\n  [](const testing::TestParamInfo<TestCaseClass::ParamType>& info) {         \\\n    return fmt::format(                                                      \\\n        \"{}{}p{}{}\", info.index,                                             \\\n        spu::GetProtocolKindName(std::get<0>(info.param).protocol),          \\\n        std::get<0>(info.param).party_size,                                  \\\n        std::get<0>(info.param).enable_colocated_optimization ? \"opt\" : \"\"); \\\n  }\n#endif\n\nnamespace scql::engine::op::test {\n\n// predifined party codes for tests\nconstexpr char kPartyAlice[] = \"alice\";\nconstexpr char kPartyBob[] = \"bob\";\nconstexpr char kPartyCarol[] = \"carol\";\nconstexpr const char* kPartyCodes[] = {\"alice\", \"bob\", \"carol\"};\n\nspu::RuntimeConfig GetSpuRuntimeConfigForTest();\n\nstruct SpuRuntimeTestCase {\n  spu::ProtocolKind protocol;\n  size_t party_size;\n  bool enable_colocated_optimization;\n};\n\n#ifdef TEST_SEMI2K_ONLY\nstatic const auto SpuTestValues2PC = testing::Values(\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2, true});\n\nstatic const auto SpuTestValuesMultiPC = testing::Values(\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2, true},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 3, true});\n#else\nstatic const auto SpuTestValues2PC = testing::Values(\n    test::SpuRuntimeTestCase{spu::ProtocolKind::CHEETAH, 2, true},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2, true},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::CHEETAH, 2, false},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2, false});\n\nstatic const auto SpuTestValuesMultiPC = testing::Values(\n    test::SpuRuntimeTestCase{spu::ProtocolKind::CHEETAH, 2, true},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2, true},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 3, true},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::ABY3, 3, true},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::CHEETAH, 2, false},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2, false},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 3, false},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::ABY3, 3, false});\n#endif\n\nstatic const auto SpuTestValuesMultiPCDisableColocated = testing::Values(\n    test::SpuRuntimeTestCase{spu::ProtocolKind::CHEETAH, 2, false},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2, false},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 3, false},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::ABY3, 3, false});\n\nstatic const auto SpuTestValuesMultiPCEnableColocated = testing::Values(\n    test::SpuRuntimeTestCase{spu::ProtocolKind::CHEETAH, 2, true},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 2, true},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::SEMI2K, 3, true},\n    test::SpuRuntimeTestCase{spu::ProtocolKind::ABY3, 3, true});\n\npb::JobStartParams::Party BuildParty(const std::string& code, int32_t rank);\n\nspu::RuntimeConfig MakeSpuRuntimeConfigForTest(\n    spu::ProtocolKind protocol_kind,\n    bool enable_colocated_optimization = false);\n\n// make single party session\nstd::shared_ptr<Session> Make1PCSession(Router* ds_router = nullptr,\n                                        DatasourceAdaptorMgr* ds_mgr = nullptr);\n\n// Make Multi PC session\nstd::vector<std::shared_ptr<Session> > MakeMultiPCSession(\n    SpuRuntimeTestCase test_case);\n\nclass ExecNodeBuilder {\n public:\n  explicit ExecNodeBuilder(const std::string& op_type);\n\n  pb::ExecNode Build();\n\n  ExecNodeBuilder& SetNodeName(const std::string& node_name);\n\n  ExecNodeBuilder& AddInput(const std::string& name, pb::TensorList tensors);\n  ExecNodeBuilder& AddInput(const std::string& name,\n                            const std::vector<pb::Tensor>& tensors);\n\n  ExecNodeBuilder& AddOutput(const std::string& name, pb::TensorList tensors);\n  ExecNodeBuilder& AddOutput(const std::string& name,\n                             const std::vector<pb::Tensor>& tensors);\n\n  ExecNodeBuilder& AddStringAttr(const std::string& name,\n                                 const std::string& value);\n  ExecNodeBuilder& AddStringsAttr(const std::string& name,\n                                  const std::vector<std::string>& values);\n\n  ExecNodeBuilder& AddInt64Attr(const std::string& name, int64_t value);\n  ExecNodeBuilder& AddInt64sAttr(const std::string& name,\n                                 const std::vector<int64_t>& values);\n  ExecNodeBuilder& AddDoubleAttr(const std::string& name, double value);\n  ExecNodeBuilder& AddDoubleAttrs(const std::string& name,\n                                  const std::vector<double>& value);\n\n  ExecNodeBuilder& AddBooleanAttr(const std::string& name, bool value);\n  ExecNodeBuilder& AddBooleansAttr(const std::string& name,\n                                   const std::vector<bool>& values);\n\n  ExecNodeBuilder& AddAttr(const std::string& name, const pb::Tensor& tensor);\n\n private:\n  pb::ExecNode node_;\n};\n\npb::Tensor MakeTensorReference(const std::string& name,\n                               pb::PrimitiveDataType dtype,\n                               pb::TensorStatus visibility, int ref_count = 1);\n\ninline pb::Tensor MakePrivateTensorReference(const std::string& name,\n                                             pb::PrimitiveDataType dtype) {\n  return MakeTensorReference(name, dtype,\n                             pb::TensorStatus::TENSORSTATUS_PRIVATE);\n}\n\ninline pb::Tensor MakeSecretTensorReference(const std::string& name,\n                                            pb::PrimitiveDataType dtype) {\n  return MakeTensorReference(name, dtype,\n                             pb::TensorStatus::TENSORSTATUS_SECRET);\n}\n\npb::Tensor MakeTensorAs(const std::string& name, const pb::Tensor& ref);\n\nstruct NamedTensor {\n  std::string name;\n  TensorPtr tensor;\n\n  NamedTensor(std::string name, TensorPtr tensor)\n      : name(std::move(name)), tensor(std::move(tensor)) {}\n};\n\nvoid FeedInputsAsPrivate(ExecContext* ctx,\n                         const std::vector<test::NamedTensor>& ts);\n\nvoid FeedInputsAsPublic(const std::vector<ExecContext*>& ctxs,\n                        const std::vector<test::NamedTensor>& ts);\n\nvoid FeedInputsAsSecret(const std::vector<ExecContext*>& ctxs,\n                        const std::vector<test::NamedTensor>& ts);\n\n// assume ctxs[0] is ExecContext for rank 0\nTensorPtr RevealSecret(const std::vector<ExecContext*>& ctxs,\n                       const std::string& name);\n\nusing OpCreator = std::function<std::unique_ptr<Operator>()>;\n\nvoid RunOpAsync(const std::vector<ExecContext*>& exec_ctxs,\n                OpCreator create_op_fn);\n\ntemplate <class Op>\nvoid RunAsync(const std::vector<ExecContext*>& exec_ctxs) {\n  RunOpAsync(exec_ctxs, []() { return std::make_unique<Op>(); });\n}\n\nvoid CheckTensorEqual(const TensorPtr& left, const TensorPtr& right);\n\n}  // namespace scql::engine::op::test\n"
  },
  {
    "path": "engine/operator/trigonometric.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/trigonometric.h\"\n\n#include \"arrow/compute/exec.h\"\n#include \"arrow/datum.h\"\n#include \"arrow/result.h\"\n#include \"arrow/type.h\"\n#include \"arrow/type_fwd.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/basic_unary.h\"\n#include \"libspu/kernel/hlo/casting.h\"\n\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\nvoid TrigonometricFunction::Execute(ExecContext* ctx) {\n  if (ctx->GetOutputStatus(kOut) == pb::TENSORSTATUS_PRIVATE) {\n    ExecuteInPlain(ctx);\n  } else {\n    ExecuteInSecret(ctx);\n  }\n}\n\nvoid TrigonometricFunction::Validate(ExecContext* ctx) {\n  const auto& input = ctx->GetInput(kIn);\n  const auto& output = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(input.size() == 1, \"Sine function input size={} not equal to 1\",\n               input.size());\n  YACL_ENFORCE(output.size() == 1,\n               \"Sine function output size={} not equal to 1\", output.size());\n\n  YACL_ENFORCE(\n      util::IsTensorStatusMatched(output[0], util::GetTensorStatus(input[0])),\n      \"Sine function output tensor's status should be same with input\");\n  YACL_ENFORCE(output[0].elem_type() == pb::PrimitiveDataType::FLOAT64,\n               \"the output type of trigonometric must be float64\");\n}\n\nvoid TrigonometricFunction::ExecuteInSecret(ExecContext* ctx) {\n  auto* sctx = ctx->GetSession()->GetSpuContext();\n  auto input_values = ctx->GetInputValues(kIn);\n  std::vector<spu::Value> results;\n  results.reserve(input_values.size());\n\n  for (auto& spu_value : input_values) {\n    if (!spu_value.isFxp()) {\n      auto to_type = spu::DataType::DT_F64;\n      spu_value =\n          spu::kernel::hlo::Cast(sctx, spu_value, spu_value.vtype(), to_type);\n    }\n\n    results.push_back(ComputeOnSpu(sctx, spu_value));\n  }\n\n  ctx->SetOutputValues(kOut, results);\n}\n\nvoid TrigonometricFunction::ExecuteTrigonometricFunction(\n    ExecContext* ctx, const std::string& func) {\n  auto input_tensors = ctx->GetInputTensors(kIn);\n  std::vector<std::shared_ptr<Tensor>> results;\n  results.reserve(input_tensors.size());\n\n  for (const auto& input_tensor : input_tensors) {\n    auto result = arrow::compute::CallFunction(\n        func, {input_tensor->ToArrowChunkedArray()});\n    YACL_ENFORCE(result.ok(), \"failed to run '{}' function\", func);\n    results.push_back(TensorFrom(result.ValueOrDie().chunked_array()));\n  }\n\n  ctx->SetOutputTensors(kOut, results);\n}\n\n// ===========================\n//   Sin impl\n// ===========================\nconst std::string Sine::kOpType(\"Sin\");\n\nconst std::string& Sine::Type() const { return kOpType; }\n\nvoid Sine::ExecuteInPlain(ExecContext* ctx) {\n  ExecuteTrigonometricFunction(ctx, \"sin\");\n}\n\nspu::Value Sine::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& value) {\n  return spu::kernel::hlo::Sine(sctx, value);\n}\n\n// ===========================\n//   Cos impl\n// ===========================\nconst std::string Cosine::kOpType(\"Cos\");\n\nconst std::string& Cosine::Type() const { return kOpType; }\n\nvoid Cosine::ExecuteInPlain(ExecContext* ctx) {\n  ExecuteTrigonometricFunction(ctx, \"cos\");\n}\n\nspu::Value Cosine::ComputeOnSpu(spu::SPUContext* sctx,\n                                const spu::Value& value) {\n  return spu::kernel::hlo::Cosine(sctx, value);\n}\n\n// ===========================\n//   Arc Cos impl\n// ===========================\nconst std::string ACosine::kOpType(\"ACos\");\n\nconst std::string& ACosine::Type() const { return kOpType; }\n\nvoid ACosine::ExecuteInPlain(ExecContext* ctx) {\n  ExecuteTrigonometricFunction(ctx, \"acos\");\n}\n\nspu::Value ACosine::ComputeOnSpu(spu::SPUContext* sctx,\n                                 const spu::Value& value) {\n  return spu::kernel::hlo::Acos(sctx, value);\n}\n\n// ===========================\n//   Tan impl\n// ===========================\nconst std::string Tan::kOpType(\"Tan\");\n\nconst std::string& Tan::Type() const { return kOpType; }\n\nvoid Tan::ExecuteInPlain(ExecContext* ctx) {\n  ExecuteTrigonometricFunction(ctx, \"tan\");\n}\n\nspu::Value Tan::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& value) {\n  YACL_THROW(\"secret tangent function is not implemented\");\n}\n\n// ===========================\n//   Arc sine impl\n// ===========================\nconst std::string ASine::kOpType(\"ASin\");\nconst std::string& ASine::Type() const { return kOpType; }\nvoid ASine::ExecuteInPlain(ExecContext* ctx) {\n  ExecuteTrigonometricFunction(ctx, \"asin\");\n}\nspu::Value ASine::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& value) {\n  return spu::kernel::hlo::Asin(sctx, value);\n}\n\n// ===========================\n//   Arc tan impl\n// ===========================\nconst std::string ATan::kOpType(\"ATan\");\nconst std::string& ATan::Type() const { return kOpType; }\nvoid ATan::ExecuteInPlain(ExecContext* ctx) {\n  ExecuteTrigonometricFunction(ctx, \"atan\");\n}\nspu::Value ATan::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& value) {\n  YACL_THROW(\"secret atan function is not implemented\");\n}\n\n// ===========================\n//   ATan2 impl\n// ===========================\nconst std::string ATan2::kOpType(\"ATan2\");\nconst std::string& ATan2::Type() const { return kOpType; }\n\nvoid ATan2::ValidateIoDataTypes(ExecContext* ctx) {\n  const auto& output = ctx->GetOutput(kOut);\n  YACL_ENFORCE(output.size() == 1, \"output size of atan2 must be 1\");\n  YACL_ENFORCE(output[0].elem_type() == pb::PrimitiveDataType::FLOAT64 ||\n                   output[0].elem_type() == pb::PrimitiveDataType::FLOAT32,\n               \"output data type must be float\");\n}\n\nTensorPtr ATan2::ComputeInPlain(const Tensor& lhs, const Tensor& rhs) {\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"atan2\", {lhs.ToArrowChunkedArray(), rhs.ToArrowChunkedArray()});\n  YACL_ENFORCE(result.ok(), \"failed to run atan2 function\");\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value ATan2::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                               const spu::Value& rhs) {\n  return spu::kernel::hlo::Atan2(sctx, lhs, rhs);\n}\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/trigonometric.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n#include \"engine/operator/binary_base.h\"\n\nnamespace scql::engine::op {\nclass TrigonometricFunction : public Operator {\n public:\n  static constexpr char kIn[] = \"In\";\n  static constexpr char kOut[] = \"Out\";\n\n protected:\n  // It will throw exception if validation fails\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n\n  void ExecuteInSecret(ExecContext* ctx);\n\n  virtual void ExecuteInPlain(ExecContext* ctx) = 0;\n  static void ExecuteTrigonometricFunction(ExecContext* ctx,\n                                           const std::string& func);\n  virtual spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                                  const spu::Value& value) = 0;\n};\n\nclass Sine : public TrigonometricFunction {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n  void ExecuteInPlain(ExecContext* ctx) override;\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                          const spu::Value& value) override;\n};\n\nclass Cosine : public TrigonometricFunction {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n  void ExecuteInPlain(ExecContext* ctx) override;\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                          const spu::Value& value) override;\n};\n\nclass ACosine : public TrigonometricFunction {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n  void ExecuteInPlain(ExecContext* ctx) override;\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                          const spu::Value& value) override;\n};\n\nclass ASine : public TrigonometricFunction {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n  void ExecuteInPlain(ExecContext* ctx) override;\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                          const spu::Value& value) override;\n};\n\nclass Tan : public TrigonometricFunction {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n  void ExecuteInPlain(ExecContext* ctx) override;\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                          const spu::Value& value) override;\n};\n\nclass ATan : public TrigonometricFunction {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n  void ExecuteInPlain(ExecContext* ctx) override;\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                          const spu::Value& value) override;\n};\n\nclass ATan2 : public BinaryBase {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n protected:\n  void ValidateIoDataTypes(ExecContext* ctx) override;\n\n  spu::Value ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& lhs,\n                          const spu::Value& rhs) override;\n  TensorPtr ComputeInPlain(const Tensor& lhs, const Tensor& rhs) override;\n};\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/trigonometric_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/trigonometric.h\"\n\n#include \"arrow/type.h\"\n#include \"arrow/type_fwd.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\nstruct TrigonometricFunctionTestCase {\n  test::NamedTensor input;\n  pb::TensorStatus input_status;\n  test::NamedTensor output;\n  std::string op;\n  bool correct;\n  size_t world_size = 2;\n};\n\nstruct ATan2TestCase {\n  std::vector<test::NamedTensor> inputs;\n  test::NamedTensor output;\n  pb::TensorStatus output_status;\n};\n\nconst std::string SinOp = \"Sin\";\nconst std::string CosOp = \"Cos\";\nconst std::string ACosOp = \"ACos\";\nconst std::string ASinOp = \"ASin\";\nconst std::string TanOp = \"Tan\";\nconst std::string ATanOp = \"ATan\";\n\nclass TrigonometricFunctionTest\n    : public ::testing::TestWithParam<\n          std::tuple<test::SpuRuntimeTestCase, TrigonometricFunctionTestCase>> {\n protected:\n  static pb::ExecNode MakeTrigonometricFunctionExecNode(\n      const TrigonometricFunctionTestCase& tc, const std::string& name);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const TrigonometricFunctionTestCase& tc);\n};\n\nclass ATan2Test : public ::testing::TestWithParam<\n                      std::tuple<test::SpuRuntimeTestCase, ATan2TestCase>> {\n protected:\n  static pb::ExecNode MakeAtan2ExecNode(const ATan2TestCase& tc,\n                                        const std::string& name);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const ATan2TestCase& tc);\n};\n\npb::ExecNode ATan2Test::MakeAtan2ExecNode(const ATan2TestCase& tc,\n                                          const std::string& name) {\n  test::ExecNodeBuilder builder(name);\n  builder.SetNodeName(name + \"-test\");\n  {\n    auto left = test::MakeTensorReference(\n        tc.inputs[0].name, tc.inputs[0].tensor->Type(), tc.output_status);\n    builder.AddInput(ATan2::kInLeft, {left});\n\n    auto right = test::MakeTensorReference(\n        tc.inputs[1].name, tc.inputs[1].tensor->Type(), tc.output_status);\n    builder.AddInput(ATan2::kInRight, {right});\n  }\n\n  {\n    auto t = test::MakeTensorReference(tc.output.name, tc.output.tensor->Type(),\n                                       tc.output_status);\n    builder.AddOutput(ATan2::kOut, {t});\n  }\n\n  return builder.Build();\n}\n\npb::ExecNode TrigonometricFunctionTest::MakeTrigonometricFunctionExecNode(\n    const TrigonometricFunctionTestCase& tc, const std::string& name) {\n  test::ExecNodeBuilder builder(name);\n  builder.SetNodeName(name + \"-test\");\n  {\n    auto t = test::MakeTensorReference(tc.input.name, tc.input.tensor->Type(),\n                                       tc.input_status);\n    builder.AddInput(TrigonometricFunction::kIn, {t});\n  }\n\n  {\n    auto t = test::MakeTensorReference(tc.output.name, tc.output.tensor->Type(),\n                                       tc.input_status);\n    builder.AddOutput(TrigonometricFunction::kOut, {t});\n  }\n\n  return builder.Build();\n}\n\nvoid ATan2Test::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                           const ATan2TestCase& tc) {\n  if (tc.output_status == pb::TENSORSTATUS_PRIVATE) {\n    for (auto* ctx : ctxs) {\n      test::FeedInputsAsPrivate(ctx, tc.inputs);\n    }\n  } else if (tc.output_status == pb::TENSORSTATUS_SECRET) {\n    test::FeedInputsAsSecret(ctxs, tc.inputs);\n  } else {\n    test::FeedInputsAsPublic(ctxs, tc.inputs);\n  }\n}\n\nvoid TrigonometricFunctionTest::FeedInputs(\n    const std::vector<ExecContext*>& ctxs,\n    const TrigonometricFunctionTestCase& tc) {\n  if (tc.input_status == pb::TensorStatus::TENSORSTATUS_PRIVATE) {\n    for (auto* ctx : ctxs) {\n      test::FeedInputsAsPrivate(ctx, {tc.input});\n    }\n  } else if (tc.input_status == pb::TensorStatus::TENSORSTATUS_SECRET) {\n    SPDLOG_INFO(\"feeding as secret\");\n    test::FeedInputsAsSecret(ctxs, {tc.input});\n  } else {\n    test::FeedInputsAsPublic(ctxs, {tc.input});\n  }\n}\n\nINSTANTIATE_TEST_SUITE_P(\n    ATan2Test, ATan2Test,\n    testing::Combine(\n        test::SpuTestValues2PC,\n        testing::Values(\n            ATan2TestCase{\n                .inputs = {test::NamedTensor(\n                               \"left\",\n                               TensorFrom(arrow::float64(),\n                                          \"[1,1.73205080757]\")),  // 1, sqrt(3)\n                           test::NamedTensor(\n                               \"right\", TensorFrom(arrow::float64(), \"[1,1]\"))},\n                .output = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::float64(),\n                               \"[0.78539816,1.0471975512]\")),  // pi/4 , pi/3\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            ATan2TestCase{\n                .inputs = {test::NamedTensor(\n                               \"left\",\n                               TensorFrom(arrow::float64(),\n                                          \"[1,1.73205080757]\")),  // 1, sqrt(3)\n                           test::NamedTensor(\n                               \"right\", TensorFrom(arrow::float64(), \"[1,1]\"))},\n                .output = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::float64(),\n                               \"[0.78539816,1.0471975512]\")),  // pi/4 , pi/3\n                .output_status = pb::TENSORSTATUS_SECRET})));\n\nTEST_P(ATan2Test, atan2_works) {\n  auto param = GetParam();\n  auto tc = std::get<1>(param);\n  auto node = MakeAtan2ExecNode(tc, \"atan2\");\n  std::vector<std::shared_ptr<scql::engine::Session>> sessions;\n  sessions = test::MakeMultiPCSession(std::get<0>(param));\n  std::vector<ExecContext> exec_ctx;\n  exec_ctx.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctx.emplace_back(node, session.get());\n  }\n\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctx.size());\n  for (auto& i : exec_ctx) {\n    ctx_ptrs.emplace_back(&i);\n  }\n\n  FeedInputs(ctx_ptrs, tc);\n\n  EXPECT_NO_THROW(test::RunAsync<ATan2>(ctx_ptrs));\n\n  TensorPtr result;\n  if (tc.output_status == pb::TENSORSTATUS_PRIVATE) {\n    result = ctx_ptrs[0]->GetTensorTable()->GetTensor(tc.output.name);\n  } else {\n    EXPECT_NO_THROW(result = test::RevealSecret(ctx_ptrs, tc.output.name));\n  }\n\n  ASSERT_TRUE(result);\n  auto out_arr = result->ToArrowChunkedArray();\n  auto expect_arr = tc.output.tensor->ToArrowChunkedArray();\n\n  EXPECT_TRUE(out_arr->length() == expect_arr->length());\n  EXPECT_TRUE(out_arr->type()->ToString() == expect_arr->type()->ToString());\n\n  arrow::EqualOptions eqOption;\n  EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr, eqOption.atol(0.001)))\n      << \"actual: \" << out_arr << \"\\nexected: \" << expect_arr;\n}\n\nINSTANTIATE_TEST_SUITE_P(\n    TrigonometricPrivateTest, TrigonometricFunctionTest,\n    testing::Combine(\n        test::SpuTestValues2PC,\n        testing::Values(\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\n                    \"in\",\n                    TensorFrom(arrow::float64(),\n                               \"[0.0, 0.52359878, 0.78539816, 1.0472, 1.5708, \"\n                               \"2.0944, 2.35619, 2.61799, 3.14159]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(),\n                                      \"[0.0, 0.5, 0.70710678, 0.8660254, 1.0, \"\n                                      \"0.8660254, 0.70710678, 0.5, 0.0]\")),\n                .op = SinOp,\n                .correct = true},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\n                    \"in\",\n                    TensorFrom(arrow::float64(),\n                               \"[0.0, 0.52359878, 0.78539816, 1.0472, 1.5708, \"\n                               \"2.0944, 2.35619, 2.61799, 3.14159]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::float64(),\n                               \"[1.0, 0.8660254038, 0.7071067812, 0.5, 1e-16, \"\n                               \"-0.5, -0.7071067812, -0.8660254038, -1.0]\")),\n                .op = CosOp,\n                .correct = true},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\n                    \"in\", TensorFrom(arrow::float64(), \"[1.0, 0.0, -1.0]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(),\n                                      \"[0.0, 1.57079632679, 3.14159265359]\")),\n                .op = ACosOp,\n                .correct = true},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\n                    \"in\",\n                    TensorFrom(arrow::float64(),\n                               \"[0.0, 0.52359878, 0.78539816, 1.0472, 1.5708, \"\n                               \"2.0944, 2.35619, 2.61799, 3.14159]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(),\n                                      \"[0.0, 0.5, 0.70710678, 0.8660254, 1.0, \"\n                                      \"0.8660254, 0.70710678, 0.5, 0.0]\")),\n                .op = SinOp,\n                .correct = true},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\n                    \"in\",\n                    TensorFrom(arrow::float64(),\n                               \"[0.0, 0.52359878, 0.78539816, 1.0472, 1.5708, \"\n                               \"2.0944, 2.35619, 2.61799, 3.14159]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::float64(),\n                               \"[1.0, 0.8660254038, 0.7071067812, 0.5, 1e-16, \"\n                               \"-0.5, -0.7071067812, -0.8660254038, -1.0]\")),\n                .op = CosOp,\n                .correct = true},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\"in\", TensorFrom(arrow::int32(),\n                                                            \"[0, 1]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[1.0, 0.54030231]\")),\n                .op = CosOp,\n                .correct = true},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\n                    \"in\", TensorFrom(arrow::float64(), \"[1.0, 0.0, -1.0]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(),\n                                      \"[0.0, 1.57079632679, 3.14159265359]\")),\n                .op = ACosOp,\n                .correct = true},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\"in\", TensorFrom(arrow::float64(),\n                                                            \"[1,null]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output = test::NamedTensor(\"out\", TensorFrom(arrow::float64(),\n                                                              \"[0.0,null]\")),\n                .op = ACosOp,\n                .correct = true,\n                .world_size = 1},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\n                    \"in\",\n                    TensorFrom(arrow::float64(), \"[0.0, 0.52359878, null]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(), \"[0.0, 0.5, null]\")),\n                .op = SinOp,\n                .correct = true,\n                .world_size = 1},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\n                    \"in\",\n                    TensorFrom(arrow::float64(), \"[0.0, 0.52359878, null]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::float64(), \"[1.0, 0.8660254038, null]\")),\n                .op = CosOp,\n                .correct = true,\n                .world_size = 1},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\"in\", TensorFrom(arrow::float64(),\n                                                            \"[0.0, 0.5, 1]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(\n                        arrow::float64(),\n                        \"[0.0, 0.52359877559, 1.57079632679]\")),  // 0, pi/4,\n                                                                  // pi/2\n                .op = ASinOp,\n                .correct = true,\n                .world_size = 1},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\"in\", TensorFrom(arrow::float64(),\n                                                            \"[0.0, 0.5, 1]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output = test::NamedTensor(\n                    \"out\", TensorFrom(arrow::float64(),\n                                      \"[0.0, 0.52359877559, 1.57079632679]\")),\n                .op = ASinOp,\n                .correct = true},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\n                    \"in\",\n                    TensorFrom(\n                        arrow::float64(),\n                        \"[0.0, 0.78539816339, 0.52359877559]\")),  // 0, pi/4,\n                                                                  // pi/6\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(arrow::float64(), \"[0.0, 1, 0.57735026919]\")),\n                .op = TanOp,\n                .correct = true,\n                .world_size = 1},\n            TrigonometricFunctionTestCase{\n                .input = test::NamedTensor(\n                    \"in\",\n                    TensorFrom(arrow::float64(), \"[0.0, 1, 0.57735026919]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output = test::NamedTensor(\n                    \"out\",\n                    TensorFrom(\n                        arrow::float64(),\n                        \"[0.0, 0.78539816339, 0.52359877559]\")),  // 0, pi/4,\n                                                                  // pi/6\n                .op = ATanOp,\n                .correct = true,\n                .world_size = 1})),\n    TestParamNameGenerator(TrigonometricFunctionTest));\n\nTEST_P(TrigonometricFunctionTest, works) {\n  auto param = GetParam();\n  auto tc = std::get<1>(param);\n  auto node = MakeTrigonometricFunctionExecNode(tc, tc.op);\n  std::vector<std::shared_ptr<scql::engine::Session>> sessions;\n  if (tc.world_size > 1) {\n    sessions = test::MakeMultiPCSession(std::get<0>(param));\n  } else {\n    sessions.push_back(test::Make1PCSession());\n  }\n\n  std::vector<ExecContext> exec_ctx;\n  exec_ctx.reserve(sessions.size());\n  for (auto& session : sessions) {\n    exec_ctx.emplace_back(node, session.get());\n  }\n\n  std::vector<ExecContext*> ctx_ptrs;\n  ctx_ptrs.reserve(exec_ctx.size());\n  for (auto& i : exec_ctx) {\n    ctx_ptrs.emplace_back(&i);\n  }\n\n  FeedInputs(ctx_ptrs, tc);\n  std::unordered_map<std::string,\n                     std::function<void(std::vector<ExecContext*>)>>\n      func_handlers;\n  func_handlers[SinOp] = [](const std::vector<ExecContext*>& execs) {\n    test::RunAsync<Sine>(execs);\n  };\n  func_handlers[CosOp] = [](const std::vector<ExecContext*>& execs) {\n    test::RunAsync<Cosine>(execs);\n  };\n  func_handlers[ACosOp] = [](const std::vector<ExecContext*>& execs) {\n    test::RunAsync<ACosine>(execs);\n  };\n  func_handlers[ASinOp] = [](const std::vector<ExecContext*>& execs) {\n    test::RunAsync<ASine>(execs);\n  };\n  func_handlers[TanOp] = [](const std::vector<ExecContext*>& execs) {\n    test::RunAsync<Tan>(execs);\n  };\n  func_handlers[ATanOp] = [](const std::vector<ExecContext*>& execs) {\n    test::RunAsync<ATan>(execs);\n  };\n\n  if (tc.correct) {\n    SPDLOG_INFO(\"running {} test\\n\", tc.op);\n    EXPECT_NO_THROW(func_handlers[tc.op](ctx_ptrs));\n\n    TensorPtr result;\n    if (tc.input_status == pb::TENSORSTATUS_PRIVATE) {\n      result = ctx_ptrs[0]->GetTensorTable()->GetTensor(tc.output.name);\n    } else {\n      EXPECT_NO_THROW(result = test::RevealSecret(ctx_ptrs, tc.output.name));\n    }\n\n    ASSERT_TRUE(result);\n    auto out_arr = result->ToArrowChunkedArray();\n    auto expect_arr = tc.output.tensor->ToArrowChunkedArray();\n\n    EXPECT_TRUE(out_arr->length() == expect_arr->length());\n    EXPECT_TRUE(out_arr->type()->ToString() == expect_arr->type()->ToString());\n\n    arrow::EqualOptions eqOption;\n    EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr, eqOption.atol(0.001)))\n        << \"actual: \" << out_arr << \"\\nexected: \" << expect_arr;\n  } else {\n    SPDLOG_INFO(\"running {} test, expecting failure\", tc.op);\n    EXPECT_THROW(func_handlers[tc.op](ctx_ptrs), ::yacl::RuntimeError);\n  }\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/unary.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/unary.h\"\n\n#include \"arrow/api.h\"\n#include \"arrow/compute/api.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/basic_unary.h\"\n#include \"libspu/kernel/hlo/const.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Abs::kOpType(\"Abs\");\n// ===========================\n//   Abs impl\n// ===========================\nconst std::string& Abs::Type() const { return kOpType; }\nTensorPtr Abs::ComputeInPlain(const Tensor& in) {\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::AbsoluteValue(in.ToArrowChunkedArray());\n  YACL_ENFORCE(result.ok(), \"failed to compute abs\");\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Abs::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  return spu::kernel::hlo::Abs(sctx, in);\n}\n\n// ===========================\n//   Ceil impl\n// ===========================\nconst std::string Ceil::kOpType(\"Ceil\");\n\nconst std::string& Ceil::Type() const { return kOpType; }\n\nTensorPtr Ceil::ComputeInPlain(const Tensor& in) {\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::Ceil(in.ToArrowChunkedArray());\n  YACL_ENFORCE(result.ok(), \"failed to compute ceil\");\n  SPDLOG_INFO(\"after compute ceil\");\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Ceil::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  return spu::kernel::hlo::Ceil(sctx, in);\n}\n\n// ===========================\n//   Floor impl\n// ===========================\nconst std::string Floor::kOpType(\"Floor\");\n\nconst std::string& Floor::Type() const { return kOpType; }\n\nTensorPtr Floor::ComputeInPlain(const Tensor& in) {\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::Floor(in.ToArrowChunkedArray());\n  YACL_ENFORCE(result.ok(), \"failed to compute floor\");\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Floor::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  return spu::kernel::hlo::Floor(sctx, in);\n}\n\n// ===========================\n//   Round impl\n// ===========================\nconst std::string Round::kOpType(\"Round\");\nconst std::string& Round::Type() const { return kOpType; }\nTensorPtr Round::ComputeInPlain(const Tensor& in) {\n  arrow::Result<arrow::Datum> result = arrow::compute::Round(\n      in.ToArrowChunkedArray(), arrow::compute::RoundOptions(0));\n  YACL_ENFORCE(result.ok(), \"failed to compute round\");\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Round::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  YACL_THROW(\"spu not support round yet.\");\n}\n\n// ===========================\n//   Radians impl\n// ===========================\nconst std::string Radians::kOpType(\"Radians\");\nconst std::string& Radians::Type() const { return kOpType; }\n\nTensorPtr Radians::ComputeInPlain(const Tensor& in) {\n  const double radians_factor = M_PI / 180.0;\n\n  auto in_chunk = in.ToArrowChunkedArray();\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::Multiply(in_chunk, arrow::Datum(radians_factor));\n  YACL_ENFORCE(result.ok(), \"failed to compute radians, {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Radians::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  const double radians_factor = M_PI / 180.0;\n  spu::Value radians_factor_value =\n      spu::kernel::hlo::Constant(sctx, radians_factor, in.shape());\n\n  return spu::kernel::hlo::Mul(sctx, in, radians_factor_value);\n}\n// ===========================\n//   Degrees impl\n// ===========================\nconst std::string Degrees::kOpType(\"Degrees\");\nconst std::string& Degrees::Type() const { return kOpType; }\n\nTensorPtr Degrees::ComputeInPlain(const Tensor& in) {\n  const double degrees_factor = 180.0 / M_PI;\n\n  auto in_chunk = in.ToArrowChunkedArray();\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::Multiply(in_chunk, arrow::Datum(degrees_factor));\n  YACL_ENFORCE(result.ok(), \"failed to compute radians, {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Degrees::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  const double degrees_factor = 180.0 / M_PI;\n  spu::Value radians_factor_value =\n      spu::kernel::hlo::Constant(sctx, degrees_factor, in.shape());\n\n  return spu::kernel::hlo::Mul(sctx, in, radians_factor_value);\n}\n\n// ===========================\n//   Ln impl\n// ===========================\nconst std::string Ln::kOpType(\"Ln\");\nconst std::string& Ln::Type() const { return kOpType; }\n\nTensorPtr Ln::ComputeInPlain(const Tensor& in) {\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::Ln(in.ToArrowChunkedArray());\n  YACL_ENFORCE(result.ok(), \"failed to compute ln\");\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Ln::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  return spu::kernel::hlo::Log(sctx, in);\n}\n\n// ===========================\n//   Log10 impl\n// ===========================\nconst std::string Log10::kOpType(\"Log10\");\nconst std::string& Log10::Type() const { return kOpType; }\n\nTensorPtr Log10::ComputeInPlain(const Tensor& in) {\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::Log10(in.ToArrowChunkedArray());\n  YACL_ENFORCE(result.ok(), \"failed to compute log10\");\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Log10::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  YACL_THROW(\"spu not support log10 yet.\");\n}\n\n// ===========================\n//   Log2 impl\n// ===========================\nconst std::string Log2::kOpType(\"Log2\");\nconst std::string& Log2::Type() const { return kOpType; }\n\nTensorPtr Log2::ComputeInPlain(const Tensor& in) {\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::Log2(in.ToArrowChunkedArray());\n  YACL_ENFORCE(result.ok(), \"failed to compute log2\");\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Log2::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  YACL_THROW(\"spu not support log2 yet.\");\n}\n\n// ===========================\n//   Sqrt impl\n// ===========================\nconst std::string Sqrt::kOpType(\"Sqrt\");\nconst std::string& Sqrt::Type() const { return kOpType; }\n\nTensorPtr Sqrt::ComputeInPlain(const Tensor& in) {\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::Sqrt(in.ToArrowChunkedArray());\n  YACL_ENFORCE(result.ok(), \"failed to compute sqrt\");\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Sqrt::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  return spu::kernel::hlo::Sqrt(sctx, in);\n}\n\n// ===========================\n//   Exp impl\n// ===========================\nconst std::string Exp::kOpType(\"Exp\");\nconst std::string& Exp::Type() const { return kOpType; }\n\nTensorPtr Exp::ComputeInPlain(const Tensor& in) {\n  arrow::Result<arrow::Datum> result =\n      arrow::compute::Exp(in.ToArrowChunkedArray());\n  YACL_ENFORCE(result.ok(), \"failed to compute exp\");\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nspu::Value Exp::ComputeOnSpu(spu::SPUContext* sctx, const spu::Value& in) {\n  return spu::kernel::hlo::Exp(sctx, in);\n}\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/unary.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/operator/unary_base.h\"\n\nnamespace scql::engine::op {\n#define DEFINE_UNARY_CLASS(className)                       \\\n  class className : public UnaryBase {                      \\\n   public:                                                  \\\n    const std::string& Type() const override;               \\\n    static const std::string kOpType;                       \\\n                                                            \\\n   protected:                                               \\\n    TensorPtr ComputeInPlain(const Tensor& in) override;    \\\n    spu::Value ComputeOnSpu(spu::SPUContext* sctx,          \\\n                            const spu::Value& in) override; \\\n  };\n\nDEFINE_UNARY_CLASS(Abs);\nDEFINE_UNARY_CLASS(Ceil);\nDEFINE_UNARY_CLASS(Floor);\nDEFINE_UNARY_CLASS(Round);\nDEFINE_UNARY_CLASS(Radians);\nDEFINE_UNARY_CLASS(Degrees);\nDEFINE_UNARY_CLASS(Ln);\nDEFINE_UNARY_CLASS(Log10);\nDEFINE_UNARY_CLASS(Log2);\nDEFINE_UNARY_CLASS(Sqrt);\nDEFINE_UNARY_CLASS(Exp);\n\n#undef DEFINE_UNARY_CLASS\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/unary_base.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/unary_base.h\"\n\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\nvoid UnaryBase::Validate(ExecContext* ctx) {\n  const auto& in_pb = ctx->GetInput(kIn);\n  const auto& out_pb = ctx->GetOutput(kOut);\n  YACL_ENFORCE(in_pb.size() == 1, \"unary operators only support one input\");\n  YACL_ENFORCE(out_pb.size() == 1, \"unary operators only support one output\");\n  YACL_ENFORCE(\n      util::GetTensorStatus(in_pb[0]) == util::GetTensorStatus(out_pb[0]),\n      \"input and output should have same status\");\n}\n\nvoid UnaryBase::Execute(ExecContext* ctx) {\n  if (ctx->GetOutputStatus(kOut) == pb::TENSORSTATUS_PRIVATE) {\n    ExecuteInPlain(ctx);\n  } else {\n    ExecuteInSecret(ctx);\n  }\n}\n\nvoid UnaryBase::ExecuteInPlain(ExecContext* ctx) {\n  SPDLOG_INFO(\"inside ExecuteInPlain\");\n  auto in_ptr = ctx->GetInputTensor(kIn);\n  YACL_ENFORCE(in_ptr != nullptr);\n\n  auto result = ComputeInPlain(*in_ptr);\n  ctx->SetOutputTensor(kOut, std::move(result));\n}\n\nvoid UnaryBase::ExecuteInSecret(ExecContext* ctx) {\n  auto in_value = ctx->GetInputValue(kIn);\n  auto result_value =\n      ComputeOnSpu(ctx->GetSession()->GetSpuContext(), in_value);\n  ctx->SetOutputValue(kOut, result_value);\n}\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/unary_base.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\nclass UnaryBase : public Operator {\n public:\n  static constexpr const char kIn[] = \"In\";\n  static constexpr const char kOut[] = \"Out\";\n\n protected:\n  void Execute(ExecContext* ctx) override;\n  void Validate(ExecContext* ctx) override;\n  void ExecuteInPlain(ExecContext* ctx);\n  void ExecuteInSecret(ExecContext* ctx);\n  virtual TensorPtr ComputeInPlain(const Tensor& in) = 0;\n  virtual spu::Value ComputeOnSpu(spu::SPUContext* sctx,\n                                  const spu::Value& in) = 0;\n};\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/unary_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"unary.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/framework/registry.h\"\n#include \"engine/operator/all_ops_register.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\nstruct UnaryTestCase {\n  std::string op;\n  bool correct;\n  test::NamedTensor input;\n  test::NamedTensor output;\n  pb::TensorStatus input_status;\n  pb::TensorStatus output_status;\n  size_t world_size = 1;\n};\n\nclass UnaryTest : public ::testing::TestWithParam<\n                      std::tuple<test::SpuRuntimeTestCase, UnaryTestCase>> {\n protected:\n  void SetUp() override { RegisterAllOps(); };\n  static pb::ExecNode MakeExecNode(const UnaryTestCase& tc,\n                                   const std::string& name);\n  static void FeedInputs(const std::vector<ExecContext*>& ctxs,\n                         const UnaryTestCase& tc);\n};\n\npb::ExecNode UnaryTest::MakeExecNode(const UnaryTestCase& tc,\n                                     const std::string& name) {\n  test::ExecNodeBuilder builder(name);\n  builder.SetNodeName(name + \"-test\");\n\n  {\n    auto input = test::MakeTensorReference(\n        tc.input.name, tc.input.tensor->Type(), tc.input_status);\n    builder.AddInput(UnaryBase::kIn, {input});\n  }\n\n  {\n    auto output = test::MakeTensorReference(\n        tc.output.name, tc.output.tensor->Type(), tc.output_status);\n    builder.AddOutput(UnaryBase::kOut, {output});\n  }\n\n  return builder.Build();\n}\n\nvoid UnaryTest::FeedInputs(const std::vector<ExecContext*>& ctxs,\n                           const UnaryTestCase& tc) {\n  if (tc.input_status == pb::TensorStatus::TENSORSTATUS_PRIVATE) {\n    for (auto* ctx : ctxs) {\n      test::FeedInputsAsPrivate(ctx, {tc.input});\n    }\n  } else if (tc.input_status == pb::TensorStatus::TENSORSTATUS_SECRET) {\n    test::FeedInputsAsSecret(ctxs, {tc.input});\n  } else {\n    test::FeedInputsAsPublic(ctxs, {tc.input});\n  }\n}\n\nINSTANTIATE_TEST_SUITE_P(\n    UnaryTestSuite, UnaryTest,\n    testing::Combine(\n        test::SpuTestValues2PC,\n        testing::Values(\n            UnaryTestCase{\n                .op = Abs::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[-1, 0, 1]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[1, 0, 1]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Abs::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[-1.5, 0, 1]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[1.5, 0, 1]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output_status = pb::TENSORSTATUS_SECRET,\n                .world_size = 2},\n            UnaryTestCase{\n                .op = Ceil::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[-1.5, 0.6, 1.1]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[-1, 1, 2]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Ceil::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[-1.5, 0.6, 1.1]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[-1, 1, 2]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output_status = pb::TENSORSTATUS_SECRET,\n                .world_size = 2},\n            UnaryTestCase{\n                .op = Floor::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[-1.5, 0.1, 1.9]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[-2, 0, 1]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Floor::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[-1.5, 0.1, 1.9]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[-2, 0, 1]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output_status = pb::TENSORSTATUS_SECRET,\n                .world_size = 2},\n            UnaryTestCase{\n                .op = Round::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\n                    \"x\",\n                    TensorFrom(arrow::float64(), \"[-1.5, -1.1, 0.1, 1.9]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[-2, -1, 0, 2]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Radians::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[0, 180, 360]\")),\n                .output = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float64(),\n                                    \"[0, 3.1415926, 6.28318530718]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Radians::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[0, 180, 360]\")),\n                .output = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float64(),\n                                    \"[0, 3.1415926, 6.28318530718]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output_status = pb::TENSORSTATUS_SECRET,\n                .world_size = 2},\n            UnaryTestCase{\n                .op = Degrees::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float64(),\n                                    \"[0, 3.1415926, 6.28318530718]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[0, 180, 360]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Degrees::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float64(),\n                                    \"[0, 3.1415926, 6.28318530718]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[0, 180, 360]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output_status = pb::TENSORSTATUS_SECRET,\n                .world_size = 2},\n            UnaryTestCase{\n                .op = Ln::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float64(), \"[1, 2.71828182846]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[0, 1]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Ln::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\n                    \"x\", TensorFrom(arrow::float64(), \"[1, 2.71828182846]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[0, 1]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output_status = pb::TENSORSTATUS_SECRET,\n                .world_size = 2},\n            UnaryTestCase{\n                .op = Log10::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[1, 10, 100]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[0, 1, 2]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Log2::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[1, 2, 4, 8]\")),\n                .output = test::NamedTensor(\"y\", TensorFrom(arrow::float64(),\n                                                            \"[0, 1, 2, 3]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Sqrt::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[0, 1, 2, 4, 9]\")),\n                .output = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float64(),\n                                    \"[0, 1, 1.41421356237, 2, 3]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Sqrt::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[0, 1, 2, 4, 9]\")),\n                .output = test::NamedTensor(\n                    \"y\", TensorFrom(arrow::float64(),\n                                    \"[0, 1, 1.41421356237, 2, 3]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output_status = pb::TENSORSTATUS_SECRET,\n                .world_size = 2},\n            UnaryTestCase{\n                .op = Exp::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[0, 1, 2, 3]\")),\n                .output = test::NamedTensor(\n                    \"y\",\n                    TensorFrom(\n                        arrow::float64(),\n                        \"[1, 2.718281828, 7.389056098931, 20.085536923188]\")),\n                .input_status = pb::TENSORSTATUS_PRIVATE,\n                .output_status = pb::TENSORSTATUS_PRIVATE},\n            UnaryTestCase{\n                .op = Exp::kOpType,\n                .correct = true,\n                .input = test::NamedTensor(\"x\", TensorFrom(arrow::float64(),\n                                                           \"[0, 1, 2]\")),\n                .output = test::NamedTensor(\n                    \"y\",\n                    TensorFrom(arrow::float64(),\n                               \"[1, 2.7129974365234375, 7.332767486572266]\")),\n                .input_status = pb::TENSORSTATUS_SECRET,\n                .output_status = pb::TENSORSTATUS_SECRET,\n                .world_size = 2})),\n    TestParamNameGenerator(UnaryTest));\n\nTEST_P(UnaryTest, WorksCorrectly) {\n  auto param = GetParam();\n  auto tc = std::get<1>(param);\n  auto node = MakeExecNode(tc, tc.op);\n  std::vector<std::shared_ptr<scql::engine::Session>> sessions;\n  double tolerance = 0.001;\n  if (tc.world_size > 1) {\n    auto spu_tc = std::get<0>(param);\n    if (tc.op == Exp::kOpType) {\n      // The exp operation tends to be less accurate, particularly when using\n      // the CHEETAH protocol.\n      if (spu_tc.protocol == spu::ProtocolKind::CHEETAH) {\n        tolerance = 0.05;\n      } else {\n        tolerance = 0.005;\n      }\n    }\n\n    sessions = test::MakeMultiPCSession(spu_tc);\n  } else {\n    sessions.push_back(test::Make1PCSession());\n  }\n\n  std::vector<ExecContext*> ctxs;\n  std::vector<ExecContext> execs;\n\n  execs.reserve(sessions.size());\n  for (auto& session : sessions) {\n    execs.push_back(ExecContext(node, session.get()));\n  }\n\n  ctxs.reserve(execs.size());\n  for (auto& exec : execs) {\n    ctxs.push_back(&exec);\n  }\n  FeedInputs(ctxs, tc);\n\n  auto func = [&]() { return GetOpRegistry()->GetOperator(tc.op); };\n\n  if (tc.correct) {\n    test::RunOpAsync(ctxs, func);\n\n    // EXPECT_NO_THROW(op_handlers[tc.op](ctxs));\n    TensorPtr result;\n    if (tc.input_status == pb::TENSORSTATUS_PRIVATE) {\n      result = ctxs[0]->GetTensorTable()->GetTensor(tc.output.name);\n    } else {\n      EXPECT_NO_THROW(result = test::RevealSecret(ctxs, tc.output.name));\n    }\n\n    ASSERT_TRUE(result);\n    auto out_arr = result->ToArrowChunkedArray();\n    auto expect_arr = tc.output.tensor->ToArrowChunkedArray();\n\n    EXPECT_TRUE(out_arr->length() == expect_arr->length());\n    EXPECT_TRUE(out_arr->type()->ToString() == expect_arr->type()->ToString());\n\n    arrow::EqualOptions eqOption;\n    EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr, eqOption.atol(tolerance)))\n        << \"op: \" << tc.op << \", status: \" << tc.output_status\n        << \"\\nactual: \" << out_arr->ToString()\n        << \"\\nexected: \" << expect_arr->ToString();\n  } else {\n    EXPECT_THROW(test::RunOpAsync(ctxs, func), ::yacl::RuntimeError);\n  }\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/unique.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/unique.h\"\n\n#include \"arrow/compute/api_vector.h\"\n#include \"arrow/datum.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\n\nconst std::string Unique::kOpType(\"Unique\");\n\nconst std::string& Unique::Type() const { return kOpType; }\n\nvoid Unique::Validate(ExecContext* ctx) {\n  const auto& inputs = ctx->GetInput(kIn);\n  const auto& outputs = ctx->GetOutput(kOut);\n\n  YACL_ENFORCE(inputs.size() == 1, \"Unique input size must be 1\");\n  YACL_ENFORCE(inputs.size() == outputs.size(),\n               \"Unique input '{}' and output '{}' should have the same size\",\n               kIn, kOut);\n\n  YACL_ENFORCE(util::IsTensorStatusMatched(\n                   inputs[0], pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"Unique input tensor's status should be private\");\n  YACL_ENFORCE(util::IsTensorStatusMatched(\n                   outputs[0], pb::TensorStatus::TENSORSTATUS_PRIVATE),\n               \"Unique output tensor's status should be private\");\n}\n\nvoid Unique::Execute(ExecContext* ctx) {\n  auto tensor = ctx->GetInputTensor(kIn);\n\n  std::shared_ptr<arrow::Array> array;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      array, arrow::compute::Unique(tensor->ToArrowChunkedArray()));\n\n  auto chunked_arr = std::make_shared<arrow::ChunkedArray>(array);\n  ctx->SetOutputTensor(kOut, TensorFrom(chunked_arr));\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/unique.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\n\nclass Unique : public Operator {\n public:\n  static const std::string kOpType;\n\n  static constexpr char kIn[] = \"Key\";\n  static constexpr char kOut[] = \"UniqueKey\";\n\n  const std::string& Type() const override;\n\n protected:\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n};\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/unique_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/unique.h\"\n\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\n\nstruct UniqueTestCase {\n  test::NamedTensor input;\n  test::NamedTensor expect_out;\n};\n\nclass UniqueTest : public testing::TestWithParam<UniqueTestCase> {\n protected:\n  static pb::ExecNode MakeExecNode(const UniqueTestCase& tc);\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    UniqueBatchTest, UniqueTest,\n    testing::Values(\n        UniqueTestCase{\n            .input = test::NamedTensor(\n                \"a\", TensorFrom(arrow::boolean(),\n                                \"[true, false, true, null, false, null]\")),\n            .expect_out = test::NamedTensor(\n                \"a_out\", TensorFrom(arrow::boolean(), \"[true, false, null]\"))},\n        UniqueTestCase{\n            .input = test::NamedTensor(\n                \"a\", TensorFrom(arrow::int64(), \"[1,1,2,3,3,4,4,4,null,null]\")),\n            .expect_out = test::NamedTensor(\n                \"a_out\", TensorFrom(arrow::int64(), \"[1,2,3,4,null]\"))},\n        UniqueTestCase{\n            .input = test::NamedTensor(\n                \"a\", TensorFrom(arrow::float32(),\n                                \"[-10.2, 3.14, 0.34, 3.14,null,null]\")),\n            .expect_out = test::NamedTensor(\n                \"a_out\",\n                TensorFrom(arrow::float32(), \"[-10.2, 3.14, 0.34,null]\"))},\n        UniqueTestCase{.input = test::NamedTensor(\n                           \"a\", TensorFrom(arrow::large_utf8(),\n                                           R\"json([\"AB\",\"AB\",null,null])json\")),\n                       .expect_out = test::NamedTensor(\n                           \"a_out\", TensorFrom(arrow::large_utf8(),\n                                               R\"json([\"AB\",null])json\"))},\n        UniqueTestCase{\n            .input = test::NamedTensor(\"a\", TensorFrom(arrow::int64(), \"[]\")),\n            .expect_out = test::NamedTensor(\"a_out\", TensorFrom(arrow::int64(),\n                                                                \"[]\"))}));\n\nTEST_P(UniqueTest, works) {\n  // Given\n  auto tc = GetParam();\n  auto node = MakeExecNode(tc);\n  auto session = test::Make1PCSession();\n  ExecContext ctx(node, session.get());\n\n  test::FeedInputsAsPrivate(&ctx, {tc.input});\n\n  // When\n  Unique op;\n  EXPECT_NO_THROW(op.Run(&ctx));\n\n  // Then\n  auto expect_arr = tc.expect_out.tensor->ToArrowChunkedArray();\n  auto out = ctx.GetTensorTable()->GetTensor(tc.expect_out.name);\n  ASSERT_TRUE(out);\n  auto out_arr = out->ToArrowChunkedArray();\n  // compare tensor content\n  EXPECT_TRUE(out_arr->ApproxEquals(*expect_arr))\n      << \"expect type = \" << expect_arr->type()->ToString()\n      << \", got type = \" << out_arr->type()->ToString()\n      << \"\\nexpect result = \" << expect_arr->ToString()\n      << \"\\nbut actual got result = \" << out_arr->ToString();\n}\n\n/// ===================\n/// UniqueTest impl\n/// ===================\n\npb::ExecNode UniqueTest::MakeExecNode(const UniqueTestCase& tc) {\n  test::ExecNodeBuilder builder(Unique::kOpType);\n\n  builder.SetNodeName(\"unique-test\");\n\n  {\n    auto t = test::MakePrivateTensorReference(tc.input.name,\n                                              tc.input.tensor->Type());\n    builder.AddInput(Unique::kIn, {t});\n  }\n\n  {\n    auto t = test::MakePrivateTensorReference(tc.expect_out.name,\n                                              tc.expect_out.tensor->Type());\n    builder.AddOutput(Unique::kOut, {t});\n  }\n\n  return builder.Build();\n}\n\n}  // namespace scql::engine::op"
  },
  {
    "path": "engine/operator/window.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/operator/window.h\"\n\n#include \"arrow/api.h\"\n#include \"arrow/compute/api.h\"\n#include \"arrow/compute/row/grouper.h\"\n#include \"arrow/result.h\"\n#include \"arrow/table.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/table_util.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::op {\nbool AreRowsEqual(const std::shared_ptr<arrow::Table>& table, int64_t i,\n                  int64_t j) {\n  int num_cols = table->num_columns();\n  for (int col = 0; col < num_cols; col++) {\n    auto chunked_array = table->column(col);\n    arrow::Result<std::shared_ptr<arrow::Scalar>> scalar_i_result =\n        chunked_array->GetScalar(i);\n    YACL_ENFORCE(scalar_i_result.ok(), \"get scalar failed\");\n    arrow::Result<std::shared_ptr<arrow::Scalar>> scalar_j_result =\n        chunked_array->GetScalar(j);\n    YACL_ENFORCE(scalar_j_result.ok(), \"get scalar failed\");\n\n    auto scalar_i = scalar_i_result.ValueOrDie();\n    auto scalar_j = scalar_j_result.ValueOrDie();\n    if ((scalar_i == nullptr && scalar_j != nullptr) ||\n        (scalar_i != nullptr && scalar_j == nullptr)) {\n      return false;\n    }\n\n    if (scalar_i != nullptr && scalar_j != nullptr) {\n      if (!scalar_i->Equals(*scalar_j)) {\n        return false;\n      }\n    }\n  }\n\n  return true;\n}\n\nconst std::string RowNumber::kOpType(\"RowNumber\");\nconst std::string& RowNumber::Type() const { return RowNumber::kOpType; }\n\nvoid RankWindowBase::Validate(ExecContext* ctx) {\n  const auto& partition_id = ctx->GetInput(kPartitionId);\n  YACL_ENFORCE(partition_id.size() == 1, \"partition id size must be 1\");\n  const auto& partition_num = ctx->GetInput(kPartitionNum);\n  YACL_ENFORCE(partition_num.size() == 1, \"partition num size must be 1\");\n  const auto& inputs = ctx->GetInput(kIn);\n  YACL_ENFORCE(inputs.size() > 0, \"input size can't be 0\");\n  const auto& outputs = ctx->GetOutput(kOut);\n  YACL_ENFORCE(outputs.size() == 1, \"outputs' size = {} not equal 1\",\n               outputs.size());\n\n  YACL_ENFORCE(\n      util::IsTensorStatusMatched(partition_id[0], pb::TENSORSTATUS_PRIVATE),\n      \"partition id status is not private\");\n  YACL_ENFORCE(\n      util::IsTensorStatusMatched(partition_num[0], pb::TENSORSTATUS_PRIVATE),\n      \"partition num status is not private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(inputs, pb::TENSORSTATUS_PRIVATE),\n               \"inputs' status are not all private\");\n  YACL_ENFORCE(util::AreTensorsStatusMatched(outputs, pb::TENSORSTATUS_PRIVATE),\n               \"outputs' status are not all private\");\n}\nuint32_t RankWindowBase::GetPartitionNum(ExecContext* ctx) {\n  const auto& partition_num = ctx->GetInput(kPartitionNum)[0];\n  auto partition_num_t = ctx->GetTensorTable()->GetTensor(partition_num.name());\n  YACL_ENFORCE(partition_num_t, \"tensor({}) not found\", partition_num.name());\n  return util::GetScalarUint32(partition_num_t);\n}\n\nstd::shared_ptr<arrow::Array> RankWindowBase::GetPartitionId(ExecContext* ctx) {\n  const auto& partition = ctx->GetInput(kPartitionId)[0];\n  auto partition_t = ctx->GetTensorTable()->GetTensor(partition.name());\n  YACL_ENFORCE(partition_t, \"tensor({}) not found\", partition.name());\n\n  return util::ConcatenateChunkedArray(partition_t->ToArrowChunkedArray());\n}\n\nstd::vector<std::shared_ptr<arrow::ListArray>>\nRankWindowBase::GetPartitionedInputs(ExecContext* ctx,\n                                     const arrow::UInt32Array* partition_id,\n                                     uint32_t partition_num) {\n  // TODO: handle the special case of the partition key is empty\n  std::vector<std::shared_ptr<arrow::ListArray>> partitioned_inputs;\n  std::shared_ptr<arrow::ListArray> partitions;\n  ASSIGN_OR_THROW_ARROW_STATUS(\n      partitions,\n      arrow::compute::Grouper::MakeGroupings(*partition_id, partition_num));\n  const auto& input_pbs = ctx->GetInput(kIn);\n  for (int i = 0; i < input_pbs.size(); i++) {\n    const auto& input_pb = input_pbs[i];\n    auto in_t = ctx->GetTensorTable()->GetTensor(input_pb.name());\n\n    YACL_ENFORCE(in_t, \"tensor({}) not found\", input_pb.name());\n    auto in_array = util::ConcatenateChunkedArray(in_t->ToArrowChunkedArray());\n\n    std::shared_ptr<arrow::ListArray> partitioned_in;\n    ASSIGN_OR_THROW_ARROW_STATUS(\n        partitioned_in,\n        arrow::compute::Grouper::ApplyGroupings(*partitions, *in_array));\n    partitioned_inputs.push_back(partitioned_in);\n  }\n\n  return partitioned_inputs;\n}\n\nvoid RankWindowBase::ExecuteInPlain(ExecContext* ctx) {\n  auto partition_array = GetPartitionId(ctx);\n  const auto* partition_cast =\n      dynamic_cast<const arrow::UInt32Array*>(partition_array.get());\n  YACL_ENFORCE(partition_cast, \"cast partition id to uint32_t failed\");\n\n  int64_t tensor_length = partition_cast->length();\n  ReserveWindowResult(tensor_length);\n  std::unordered_map<uint, std::vector<int64_t>> positions_map;\n  for (int i = 0; i < tensor_length; i++) {\n    // partition_cast->Value(i) is the partition group\n    // positions_map stores the position info of each group\n    positions_map[partition_cast->Value(i)].push_back(i);\n  }\n\n  auto partition_num = GetPartitionNum(ctx);\n  const auto& input_pbs = ctx->GetInput(kIn);\n\n  std::vector<std::shared_ptr<arrow::ListArray>> partitioned_inputs =\n      GetPartitionedInputs(ctx, partition_cast, partition_num);\n  std::vector<std::shared_ptr<arrow::Field>> fields;\n  for (int i = 0; i < input_pbs.size(); i++) {\n    const auto& input_pb = input_pbs[i];\n    auto in_t = ctx->GetTensorTable()->GetTensor(input_pb.name());\n    YACL_ENFORCE(in_t, \"failed to find tensor '{}'\", input_pb.name());\n    fields.push_back(arrow::field(input_pb.name(), in_t->ArrowType()));\n  }\n  std::shared_ptr<arrow::Schema> schema = arrow::schema(fields);\n\n  std::vector<std::shared_ptr<arrow::Array>> window_results;\n\n  for (uint32_t partition_i = 0; partition_i < partition_num; partition_i++) {\n    std::vector<std::string> sort_keys;\n    std::vector<std::shared_ptr<arrow::Array>> slices;\n\n    for (const auto& tensor_slice : partitioned_inputs) {\n      std::shared_ptr<arrow::Array> partitioned_slice =\n          tensor_slice->value_slice(partition_i);\n      YACL_ENFORCE(partitioned_slice->length() > 0,\n                   \"partitioned slice(partition id: {}) is empty\", partition_i);\n      slices.push_back(partitioned_slice);\n    }\n\n    std::shared_ptr<arrow::Table> slice_table;\n\n    slice_table = arrow::Table::Make(schema, slices);\n    RunWindowFunc(ctx, std::move(slice_table), positions_map[partition_i]);\n  }\n\n  const auto& output_pbs = ctx->GetOutput(kOut);\n  ctx->GetTensorTable()->AddTensor(output_pbs[0].name(),\n                                   TensorFrom(GetWindowResult()));\n  SPDLOG_INFO(\"{} window function done\", Type());\n}\n\nvoid RankWindowBase::Execute(ExecContext* ctx) {\n  const auto output_status = util::GetTensorStatus(ctx->GetOutput(kOut)[0]);\n  if (output_status == pb::TENSORSTATUS_PRIVATE) {\n    ExecuteInPlain(ctx);\n  } else {\n    ExecuteInSecret(ctx);\n  }\n}\n\n// sort_indices is the position indices after sort, e.g. the result [3,0,2,1]\n// means the 4th row is ranked as first, first row ranked as\n// second, 3rd row is ranked 3rd, second row is ranked 4th\nstd::shared_ptr<arrow::Array> RankWindowBase::GetSortedIndices(\n    ExecContext* ctx, const std::shared_ptr<arrow::Table>& input) {\n  std::vector<arrow::compute::SortKey> sort_keys;\n\n  std::vector<std::string> reverse =\n      ctx->GetStringValuesFromAttribute(kReverseAttr);\n  YACL_ENFORCE(reverse.size() == input->fields().size(),\n               \"sort key numbers are not equal to that of reverse attribute\");\n\n  for (size_t i = 0; i < input->fields().size(); i++) {\n    arrow::compute::SortOrder order =\n        reverse[i] == \"1\" ? arrow::compute::SortOrder::Descending\n                          : arrow::compute::SortOrder::Ascending;\n    sort_keys.emplace_back(input->fields()[i]->name(), order);\n  }\n\n  // FIXME: currently arrow only provides the global null placement, here only\n  // take the first one to decide the null placement\n  //  Follow the progress of https://github.com/apache/arrow/pull/46926, and\n  //  if it gets merged into Arrow, please use it to fix the issue\n  arrow::compute::NullPlacement null_placement =\n      reverse[0] == \"0\" ? arrow::compute::NullPlacement::AtStart\n                        : arrow::compute::NullPlacement::AtEnd;\n  arrow::compute::SortOptions sort_options(sort_keys, null_placement);\n  auto status = arrow::compute::SortIndices(input, sort_options);\n  YACL_ENFORCE(status.ok(), \"failed to sort indices\");\n  return status.ValueOrDie();\n}\n\nvoid RowNumber::RunWindowFunc(ExecContext* ctx,\n                              std::shared_ptr<arrow::Table> input,\n                              const std::vector<int64_t>& positions) {\n  std::shared_ptr<arrow::Array> sort_indices = GetSortedIndices(ctx, input);\n\n  auto int_array = std::static_pointer_cast<arrow::Int64Array>(sort_indices);\n\n  // key: the indice, value: the rank number\n  std::vector<int64_t> row_number_count(int_array->length(), -1);\n  int64_t rank = 1;\n  const auto total = int_array->length();\n  for (int64_t i = 0; i < total; ++i) {\n    int64_t key = int_array->Value(i);\n    YACL_ENFORCE(key >= 0 && key < total && row_number_count[key] < 0,\n                 \"invalid row number\");\n    row_number_count[key] = rank;\n\n    rank++;\n  }\n\n  ProcessResults(int_array->length(), row_number_count, positions,\n                 window_results_);\n}\n\nconst std::string PercentRank::kOpType(\"PercentRank\");\nconst std::string& PercentRank::Type() const { return PercentRank::kOpType; }\nvoid PercentRank::RunWindowFunc(ExecContext* ctx,\n                                std::shared_ptr<arrow::Table> input,\n                                const std::vector<int64_t>& positions) {\n  std::shared_ptr<arrow::Array> sort_indices = GetSortedIndices(ctx, input);\n\n  auto int_array = std::static_pointer_cast<arrow::Int64Array>(sort_indices);\n\n  // key: the indice, value: the percent rank\n  std::vector<double> percent_rank(int_array->length(), -1);\n  int64_t rank = -1;\n  int64_t last_key = -1;\n  const auto total = int_array->length();\n  for (int64_t i = 0; i < int_array->length(); i++) {\n    int64_t key = int_array->Value(i);\n    YACL_ENFORCE(key >= 0 && key < total && percent_rank[key] < 0,\n                 \"invalid key in rank\");\n    if (rank == -1) {\n      rank = 1;\n    } else {\n      if (!AreRowsEqual(input, last_key, key)) {\n        rank = i + 1;\n      }\n    }\n    last_key = key;\n\n    percent_rank[key] = total == 1 ? 0 : 1.0 * (rank - 1) / (total - 1);\n  }\n\n  ProcessResults(int_array->length(), percent_rank, positions, window_results_);\n}\n\nconst std::string Rank::kOpType(\"Rank\");\nconst std::string& Rank::Type() const { return Rank::kOpType; }\n\nvoid Rank::RunWindowFunc(ExecContext* ctx, std::shared_ptr<arrow::Table> input,\n                         const std::vector<int64_t>& positions) {\n  std::shared_ptr<arrow::Array> sort_indices = GetSortedIndices(ctx, input);\n  auto int_array = std::static_pointer_cast<arrow::Int64Array>(sort_indices);\n\n  const auto total = int_array->length();\n  std::vector<int64_t> rank_map(total, -1);\n  int64_t rank = -1;\n  int64_t last_key = -1;\n  for (int64_t i = 0; i < int_array->length(); i++) {\n    int64_t key = int_array->Value(i);\n    YACL_ENFORCE(key >= 0 && key < total && rank_map[key] < 0,\n                 \"duplicated key in rank\");\n    if (rank == -1) {\n      rank = 1;\n    } else {\n      if (!AreRowsEqual(input, last_key, key)) {\n        rank = i + 1;\n      }\n    }\n    last_key = key;\n\n    rank_map[key] = rank;\n  }\n\n  ProcessResults(int_array->length(), rank_map, positions, window_results_);\n}\n\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/window.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"arrow/builder.h\"\n\n#include \"engine/framework/operator.h\"\n\nnamespace scql::engine::op {\nclass RankWindowBase : public Operator {\n public:\n  static constexpr char kIn[] = \"Key\";\n  static constexpr char kOut[] = \"Out\";\n  static constexpr char kPartitionId[] = \"PartitionId\";\n  static constexpr char kPartitionNum[] = \"PartitionNum\";\n  static constexpr char kReverseAttr[] = \"reverse\";\n\n protected:\n  static uint32_t GetPartitionNum(ExecContext* ctx);\n  static std::shared_ptr<arrow::Array> GetPartitionId(ExecContext* ctx);\n  TensorPtr BuildTensorFromScalarVector(\n      const arrow::ScalarVector& scalars,\n      std::shared_ptr<arrow::DataType> empty_type);\n\n  virtual void RunWindowFunc(ExecContext* ctx,\n                             std::shared_ptr<arrow::Table> input,\n                             const std::vector<int64_t>& positions) = 0;\n  void Validate(ExecContext* ctx) override;\n  void Execute(ExecContext* ctx) override;\n  static std::shared_ptr<arrow::Array> GetSortedIndices(\n      ExecContext* ctx, const std::shared_ptr<arrow::Table>& input);\n  static std::vector<std::shared_ptr<arrow::ListArray>> GetPartitionedInputs(\n      ExecContext* ctx, const arrow::UInt32Array* partition_id,\n      uint32_t partition_num);\n  virtual std::shared_ptr<arrow::ChunkedArray> GetWindowResult() = 0;\n  virtual void ExecuteInSecret(ExecContext* ctx) = 0;\n  void ExecuteInPlain(ExecContext* ctx);\n  virtual void ReserveWindowResult(size_t size) = 0;\n\n  template <typename T>\n  std::shared_ptr<arrow::ChunkedArray> VectorToChunkedArray(\n      std::vector<T>& vec) {\n    using BuilderType = typename arrow::CTypeTraits<T>::BuilderType;\n    BuilderType builder;\n\n    arrow::Status status;\n    status = builder.Reserve(vec.size());\n    YACL_ENFORCE(status.ok(), \"Reserve memory failed\");\n\n    for (const auto& value : vec) {\n      auto status = builder.Append(value);\n      YACL_ENFORCE(status.ok(), \"Append value failed\");\n    }\n\n    std::shared_ptr<arrow::Array> chunk;\n    status = builder.Finish(&chunk);\n    YACL_ENFORCE(status.ok(), \"Finish array failed\");\n\n    std::vector<std::shared_ptr<arrow::Array>> chunks;\n    chunks.push_back(chunk);\n    return std::make_shared<arrow::ChunkedArray>(chunks);\n  }\n\n  template <typename ValueType>\n  void ProcessResults(const int length, const std::vector<ValueType>& rank_map,\n                      const std::vector<int64_t>& positions,\n                      std::vector<ValueType>& window_results) {\n    YACL_ENFORCE(length == (int64_t)positions.size(),\n                 \"position vector size not equal to that of input value\");\n    for (int64_t i = 0; i < length; ++i) {\n      YACL_ENFORCE(i < rank_map.size(),\n                   \"failed to find the indice of position {}\", i);\n      YACL_ENFORCE(\n          positions[i] >= 0 && positions[i] < (int64_t)window_results.size(),\n          \"position {} is out of range [0, {}\", positions[i],\n          window_results.size());\n      window_results[positions[i]] = rank_map.at(i);\n    }\n  }\n};\n\nclass RowNumber : public RankWindowBase {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n protected:\n  void RunWindowFunc(ExecContext* ctx, std::shared_ptr<arrow::Table> input,\n                     const std::vector<int64_t>& positions) override;\n  void ExecuteInSecret(ExecContext* ctx) override {\n    YACL_THROW(\"not support in secret mode\");\n  }\n  std::shared_ptr<arrow::ChunkedArray> GetWindowResult() override {\n    return VectorToChunkedArray(window_results_);\n  }\n  void ReserveWindowResult(size_t size) override {\n    window_results_ = std::vector<int64_t>(size, 0);\n  };\n\n private:\n  std::vector<int64_t> window_results_;\n};\n\nclass PercentRank : public RankWindowBase {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n protected:\n  void RunWindowFunc(ExecContext* ctx, std::shared_ptr<arrow::Table> input,\n                     const std::vector<int64_t>& positions) override;\n  void ExecuteInSecret(ExecContext* ctx) override {\n    YACL_THROW(\"not support in secret mode\");\n  }\n  std::shared_ptr<arrow::ChunkedArray> GetWindowResult() override {\n    return VectorToChunkedArray(window_results_);\n  };\n  void ReserveWindowResult(size_t size) override {\n    window_results_ = std::vector<double>(size, 0.0);\n  };\n\n private:\n  std::vector<double> window_results_;\n};\n\nclass Rank : public RankWindowBase {\n public:\n  static const std::string kOpType;\n  const std::string& Type() const override;\n\n protected:\n  void RunWindowFunc(ExecContext* ctx, std::shared_ptr<arrow::Table> input,\n                     const std::vector<int64_t>& positions) override;\n  void ExecuteInSecret(ExecContext* ctx) override {\n    YACL_THROW(\"not support in secret mode\");\n  }\n  std::shared_ptr<arrow::ChunkedArray> GetWindowResult() override {\n    return VectorToChunkedArray(window_results_);\n  }\n  void ReserveWindowResult(size_t size) override {\n    window_results_ = std::vector<int64_t>(size, 0);\n  };\n\n private:\n  std::vector<int64_t> window_results_;\n};\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/operator/window_test.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n#include \"engine/operator/window.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/operator/all_ops_register.h\"\n#include \"engine/operator/test_util.h\"\n\nnamespace scql::engine::op {\nstruct WindowTestCase {\n  std::string op_type;\n  std::vector<test::NamedTensor> inputs;\n  test::NamedTensor partition_id;\n  test::NamedTensor partition_num;\n  std::vector<test::NamedTensor> outputs;\n  std::vector<std::string> reverse;\n  bool ok = true;\n};\n\nclass WindowTest : public testing::TestWithParam<WindowTestCase> {\n protected:\n  void SetUp() override {}\n\n  static pb::ExecNode MakeExecNode(const WindowTestCase& tc);\n};\n\nstd::string MakeLargeIncrementTensorInput(const size_t size) {\n  std::string tensor_str = \"[\";\n  for (size_t i = 0; i < size; i++) {\n    tensor_str += std::to_string(i + 1);\n    if (i != size - 1) {\n      tensor_str += \",\";\n    }\n  }\n\n  tensor_str += \"]\";\n  return tensor_str;\n}\n\nstd::string MakeAllZeroTensor(const size_t size) {\n  std::string tensor_str = \"[\";\n  for (size_t i = 0; i < size; i++) {\n    tensor_str += \"0\";\n    if (i != size - 1) {\n      tensor_str += \",\";\n    }\n  }\n\n  tensor_str += \"]\";\n  return tensor_str;\n}\n\nINSTANTIATE_TEST_SUITE_P(\n    WindowBatchTest, WindowTest,\n    testing::Values(\n        WindowTestCase{\n            .op_type = RowNumber::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in_a\",\n                TensorFrom(arrow::int64(), \"[1,null,3,4,5,6,7,null,9]\"))},\n            .partition_id = test::NamedTensor(\n                \"partition_id\",\n                TensorFrom(arrow::uint32(), \"[0,0,0,0,0,1,1,1,1]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[2]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(), \"[2,1,3,4,5,2,3,1,4]\"))},\n            .reverse = {\"0\"}},\n        WindowTestCase{\n            .op_type = RowNumber::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in_a\",\n                TensorFrom(arrow::int64(), \"[1,null,3,4,5,6,7,null,9]\"))},\n            .partition_id = test::NamedTensor(\n                \"partition_id\",\n                TensorFrom(arrow::uint32(), \"[0,0,0,0,0,1,1,1,1]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[2]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(), \"[4,5,3,2,1,3,2,4,1]\"))},\n            .reverse = {\"1\"}},\n        WindowTestCase{\n            .op_type = RowNumber::kOpType,\n            .inputs = {test::NamedTensor(\"in_a\",\n                                         TensorFrom(arrow::int64(), \"[]\"))},\n            .partition_id = test::NamedTensor(\n                \"partition_id\", TensorFrom(arrow::uint32(), \"[]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[0]\")),\n            .outputs = {test::NamedTensor(\"out\",\n                                          TensorFrom(arrow::int64(), \"[]\"))},\n            .reverse = {\"0\"}},\n        WindowTestCase{\n            .op_type = RowNumber::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in_a\", TensorFrom(arrow::int64(), \"[5,5,5,5,6,5,6,5]\"))},\n            .partition_id = test::NamedTensor(\"partition_id\",\n                                              TensorFrom(arrow::uint32(),\n                                                         \"[0,1,1,1,0,0,1,0]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[2]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(), \"[1,1,2,3,4,2,4,3]\"))},\n            .reverse = {\"0\"}},\n        WindowTestCase{\n            .op_type = RowNumber::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in_a\",\n                TensorFrom(arrow::int64(), \"[10,20,30,40,50,60,70,80]\"))},\n            .partition_id = test::NamedTensor(\"partition_id\",\n                                              TensorFrom(arrow::uint32(),\n                                                         \"[0,0,1,1,0,1,2,2]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(), \"[1,2,1,2,3,3,1,2]\"))},\n            .reverse = {\"0\"}},\n        WindowTestCase{\n            .op_type = RowNumber::kOpType,\n            .inputs = {test::NamedTensor(\n                           \"in_a\", TensorFrom(arrow::int64(),\n                                              \"[10,20,30,40,50,60,70,80]\")),\n                       test::NamedTensor(\"in_b\",\n                                         TensorFrom(arrow::int32(),\n                                                    \"[1,2,3,4,5,6,7,8]\"))},\n            .partition_id = test::NamedTensor(\"partition_id\",\n                                              TensorFrom(arrow::uint32(),\n                                                         \"[0,0,1,1,0,1,2,2]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(), \"[1,2,1,2,3,3,1,2]\"))},\n            .reverse = {\"0\", \"0\"}},\n        WindowTestCase{\n            .op_type = RowNumber::kOpType,\n            .inputs =\n                {test::NamedTensor(\"in_a\", TensorFrom(arrow::int64(),\n                                                      \"[1,2,3,4,5,6,7,8,9]\")),\n                 test::NamedTensor(\"in_b\", TensorFrom(arrow::int32(),\n                                                      \"[1,2,3,4,5,6,7,8,9]\"))},\n            .partition_id = test::NamedTensor(\n                \"partition_id\",\n                TensorFrom(arrow::uint32(), \"[0,0,0,0,0,1,1,1,1]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[2]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(), \"[5,4,3,2,1,4,3,2,1]\"))},\n            .reverse = {\"1\", \"0\"}},\n        WindowTestCase{\n            .op_type = RowNumber::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in_a\", TensorFrom(arrow::int64(),\n                                   MakeLargeIncrementTensorInput(10000)))},\n            .partition_id = test::NamedTensor(\n                \"partition_id\",\n                TensorFrom(arrow::uint32(), MakeAllZeroTensor(10000))),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[1]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(),\n                                  MakeLargeIncrementTensorInput(10000)))},\n            .reverse = {\"0\"}},\n        WindowTestCase{\n            .op_type = RowNumber::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in_a\",\n                TensorFrom(arrow::int64(),\n                           MakeLargeIncrementTensorInput(1024 * 1024)))},\n            .partition_id = test::NamedTensor(\n                \"partition_id\",\n                TensorFrom(arrow::uint32(), MakeAllZeroTensor(1024 * 1024))),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[1]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(),\n                                  MakeLargeIncrementTensorInput(1024 * 1024)))},\n            .reverse = {\"0\"}},\n        WindowTestCase{\n            .op_type = PercentRank::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in_a\",\n                TensorFrom(arrow::int64(), \"[1, 2, 3, 4, 5, 6, 6, 7, 8]\"))},\n            .partition_id = test::NamedTensor(\n                \"partition_id\",\n                TensorFrom(arrow::uint32(), \"[0, 0, 0, 0, 0, 1, 1, 1, 2]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[3]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::float64(),\n                                  \"[0, 0.25, 0.5, 0.75, 1, 0, 0, 1, 0]\"))},\n            .reverse = {\"0\"}},\n        WindowTestCase{.op_type = PercentRank::kOpType,\n                       .inputs = {test::NamedTensor(\n                           \"in_a\", TensorFrom(arrow::int64(),\n                                              \"[1,2,null,4,5,6,7,7,null]\"))},\n                       .partition_id = test::NamedTensor(\n                           \"partition_id\",\n                           TensorFrom(arrow::uint32(), \"[0,0,0,0,0,1,1,1,1]\")),\n                       .partition_num = test::NamedTensor(\n                           \"partition_num\", TensorFrom(arrow::uint32(), \"[2]\")),\n                       .outputs = {test::NamedTensor(\n                           \"out\", TensorFrom(arrow::float64(),\n                                             \"[0.25,0.5,0,0.75,1.0,0.33333,0.\"\n                                             \"66666,0.66666,0]\"))},\n                       .reverse = {\"0\"}},\n        WindowTestCase{\n            .op_type = Rank::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in_a\", TensorFrom(arrow::int64(), \"[1,2,4,4,5,6,7,7,9]\"))},\n            .partition_id = test::NamedTensor(\n                \"partition_id\",\n                TensorFrom(arrow::uint32(), \"[0,0,0,0,0,1,1,1,1]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[2]\")),\n            .outputs = {test::NamedTensor(\n                \"out\",\n                TensorFrom(arrow::int64(), \"[1, 2, 3, 3, 5, 1, 2, 2, 4]\"))},\n            .reverse = {\"0\"}},\n        WindowTestCase{\n            .op_type = Rank::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in_a\",\n                TensorFrom(arrow::int64(), \"[1,2,null,4,5,6,7,7,null]\"))},\n            .partition_id = test::NamedTensor(\n                \"partition_id\",\n                TensorFrom(arrow::uint32(), \"[0,0,0,0,0,1,1,1,1]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[2]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(), \"[2,3,1,4,5,2,3,3,1]\"))},\n            .reverse = {\"0\"}},\n        WindowTestCase{\n            .op_type = Rank::kOpType,\n            .inputs = {test::NamedTensor(\n                \"in_a\",\n                TensorFrom(arrow::int64(), \"[1,2,null,4,5,6,7,7,null]\"))},\n            .partition_id = test::NamedTensor(\n                \"partition_id\",\n                TensorFrom(arrow::uint32(), \"[0,0,0,0,0,1,1,1,1]\")),\n            .partition_num = test::NamedTensor(\n                \"partition_num\", TensorFrom(arrow::uint32(), \"[2]\")),\n            .outputs = {test::NamedTensor(\n                \"out\", TensorFrom(arrow::int64(), \"[4,3,5,2,1,3,1,1,4]\"))},\n            .reverse = {\"1\"}}));\n\nTEST_P(WindowTest, work) {\n  auto tc = GetParam();\n  auto node = MakeExecNode(tc);\n  auto session = test::Make1PCSession();\n\n  ExecContext ctx(node, session.get());\n\n  test::FeedInputsAsPrivate(&ctx, tc.inputs);\n  test::FeedInputsAsPrivate(&ctx, {tc.partition_id, tc.partition_num});\n\n  RegisterAllOps();\n  auto op = GetOpRegistry()->GetOperator(tc.op_type);\n\n  if (tc.ok) {\n    EXPECT_NO_THROW(op->Run(&ctx));\n  } else {\n    EXPECT_ANY_THROW(op->Run(&ctx));\n  }\n\n  SPDLOG_INFO(\"start to compare result\");\n  auto actual_output = ctx.GetTensorTable()->GetTensor(tc.outputs[0].name);\n\n  auto actual_arr = actual_output->ToArrowChunkedArray();\n  auto expect_arr = tc.outputs[0].tensor->ToArrowChunkedArray();\n\n  EXPECT_TRUE(actual_arr->ApproxEquals(*expect_arr))\n      << \"\\nexpect result = \" << expect_arr->ToString()\n      << \"\\nactual result = \" << actual_arr->ToString();\n}\n\npb::ExecNode WindowTest::MakeExecNode(const WindowTestCase& tc) {\n  test::ExecNodeBuilder builder(tc.op_type);\n  builder.AddStringsAttr(RowNumber::kReverseAttr, tc.reverse);\n  builder.SetNodeName(\"plaintext-window-test\");\n\n  std::vector<pb::Tensor> inputs;\n  for (const auto& named_tensor : tc.inputs) {\n    pb::Tensor t = test::MakePrivateTensorReference(\n        named_tensor.name, named_tensor.tensor->Type());\n    inputs.push_back(std::move(t));\n  }\n  builder.AddInput(RankWindowBase::kIn, inputs);\n\n  pb::Tensor partition_id = test::MakePrivateTensorReference(\n      tc.partition_id.name, tc.partition_id.tensor->Type());\n  builder.AddInput(RankWindowBase::kPartitionId, {partition_id});\n  pb::Tensor partition_num = test::MakePrivateTensorReference(\n      tc.partition_num.name, tc.partition_num.tensor->Type());\n  builder.AddInput(RankWindowBase::kPartitionNum, {partition_num});\n\n  std::vector<pb::Tensor> outputs;\n  for (const auto& named_tensor : tc.outputs) {\n    pb::Tensor t = test::MakePrivateTensorReference(\n        named_tensor.name, named_tensor.tensor->Type());\n    outputs.push_back(std::move(t));\n  }\n\n  builder.AddOutput(RankWindowBase::kOut, outputs);\n\n  return builder.Build();\n}\n}  // namespace scql::engine::op\n"
  },
  {
    "path": "engine/services/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\nproto_library(\n    name = \"mock_report_service_proto\",\n    srcs = [\"mock_report_service.proto\"],\n    deps = [\n        \"//api:engine_proto\",\n    ],\n)\n\nproto_library(\n    name = \"error_collector_service_proto\",\n    srcs = [\"error_collector_service.proto\"],\n    deps = [\n        \"//api:engine_proto\",\n        \"//api:status_proto\",\n    ],\n)\n\nproto_library(\n    name = \"prometheus_service_proto\",\n    srcs = [\"prometheus_service.proto\"],\n)\n\ncc_proto_library(\n    name = \"mock_report_service_cc_proto\",\n    deps = [\":mock_report_service_proto\"],\n)\n\ncc_proto_library(\n    name = \"error_collector_service_cc_proto\",\n    deps = [\":error_collector_service_proto\"],\n)\n\ncc_proto_library(\n    name = \"prometheus_service_cc_proto\",\n    deps = [\":prometheus_service_proto\"],\n)\n\ncc_library(\n    name = \"error_collector_service_impl\",\n    srcs = [\"error_collector_service_impl.cc\"],\n    hdrs = [\"error_collector_service_impl.h\"],\n    visibility = [\"//engine/exe:__pkg__\"],\n    deps = [\n        \":error_collector_service_cc_proto\",\n        \"//api:engine_cc_proto\",\n        \"//api:status_cc_proto\",\n        \"//engine/framework:session_manager\",\n        \"@brpc\",\n    ],\n)\n\ncc_library(\n    name = \"prometheus_service_impl\",\n    srcs = [\"prometheus_service_impl.cc\"],\n    hdrs = [\"prometheus_service_impl.h\"],\n    visibility = [\"//engine/exe:__pkg__\"],\n    deps = [\n        \":prometheus_service_cc_proto\",\n        \"//api:status_cc_proto\",\n        \"//engine/util:prometheus_monitor\",\n        \"@brpc\",\n        \"@brpc//:butil\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"engine_service_impl\",\n    srcs = [\"engine_service_impl.cc\"],\n    hdrs = [\"engine_service_impl.h\"],\n    visibility = [\"//engine/exe:__pkg__\"],\n    deps = [\n        \":error_collector_service_impl\",\n        \":pipeline\",\n        \":run_plan_core\",\n        \"//api:common_cc_proto\",\n        \"//api:engine_cc_proto\",\n        \"//api:scql_task_cc_proto\",\n        \"//api:status_cc_proto\",\n        \"//engine/auth:authenticator\",\n        \"//engine/datasource:datasource_adaptor_mgr\",\n        \"//engine/datasource:embed_router\",\n        \"//engine/framework:exec\",\n        \"//engine/framework:executor\",\n        \"//engine/framework:session_manager\",\n        \"//engine/link:channel_manager\",\n        \"//engine/link:mux_link_factory\",\n        \"//engine/link:mux_receiver_service\",\n        \"//engine/operator:all_ops_register\",\n        \"//engine/util:kpad_task_helper\",\n        \"//engine/util:trace_categories\",\n        \"@psi//psi/utils:sync\",\n    ],\n)\n\nscql_cc_test(\n    name = \"engine_service_impl_test\",\n    srcs = [\"engine_service_impl_test.cc\"],\n    env = {\n        \"ASAN_OPTIONS\": \"detect_leaks=0,detect_odr_violation=0\",  # 屏蔽leak,odr检测\n    },\n    deps = [\n        \":engine_service_impl\",\n        \":mock_report_service_cc_proto\",\n        \"//engine/operator:test_util\",\n        \"@org_pocoproject_poco//:poco\",\n    ],\n)\n\ncc_library(\n    name = \"run_plan_core\",\n    srcs = [\"run_plan_core.cc\"],\n    hdrs = [\"run_plan_core.h\"],\n    visibility = [\n        \"//engine/exe:__pkg__\",\n        \"//engine/services:__pkg__\",\n        \"//python/engine:__pkg__\",\n    ],\n    deps = [\n        \":pipeline\",\n        \"//api:engine_cc_proto\",\n        \"//api:status_cc_proto\",\n        \"//engine/framework:exec\",\n        \"//engine/framework:executor\",\n        \"//engine/framework:session\",\n        \"//engine/util:logging\",\n        \"//engine/util:trace_categories\",\n    ],\n)\n\ncc_library(\n    name = \"pipeline\",\n    srcs = [\"pipeline.cc\"],\n    hdrs = [\"pipeline.h\"],\n    visibility = [\n        \"//engine/exe:__pkg__\",\n        \"//python/engine:__pkg__\",\n    ],\n    deps = [\n        \"//api:engine_cc_proto\",\n        \"//engine/core:tensor\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/core:tensor_slice\",\n        \"//engine/framework:session\",\n        \"//engine/util:filepath_helper\",\n        \"@org_apache_arrow//:arrow\",\n    ],\n)\n"
  },
  {
    "path": "engine/services/engine_service_impl.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/services/engine_service_impl.h\"\n\n#include <chrono>\n#include <cstddef>\n#include <cstring>\n#include <exception>\n#include <memory>\n#include <stdexcept>\n#include <utility>\n\n#include \"brpc/closure_guard.h\"\n#include \"google/protobuf/util/json_util.h\"\n#include \"psi/utils/sync.h\"\n\n#include \"engine/exe/flags.h\"\n#include \"engine/framework/exec.h\"\n#include \"engine/framework/executor.h\"\n#include \"engine/framework/session.h\"\n#include \"engine/operator/all_ops_register.h\"\n#include \"engine/services/pipeline.h\"\n#include \"engine/util/kpad_task_helper.h\"\n#include \"engine/util/trace_categories.h\"\n\n#include \"engine/services/error_collector_service.pb.h\"\n\n#ifndef LOG_ERROR_AND_SET_STATUS_IMPL\n#define LOG_ERROR_AND_SET_STATUS_IMPL(logger, status, err_code, err_msg) \\\n  do {                                                                   \\\n    SPDLOG_LOGGER_ERROR(logger, err_msg);                                \\\n    status->set_code(err_code);                                          \\\n    status->set_message(err_msg);                                        \\\n  } while (false)\n#endif  // LOG_ERROR_AND_SET_STATUS_IMPL\n\n#ifndef LOG_ERROR_AND_SET_STATUS\n#define LOG_ERROR_AND_SET_STATUS(status, err_code, err_msg)                   \\\n  do {                                                                        \\\n    LOG_ERROR_AND_SET_STATUS_IMPL(spdlog::default_logger(), status, err_code, \\\n                                  err_msg);                                   \\\n  } while (false)\n#endif  // LOG_ERROR_AND_SET_STATUS\n\nnamespace {\n\nstd::string MessageToJsonString(const google::protobuf::Message& message) {\n  ::google::protobuf::util::JsonOptions opts;\n  opts.add_whitespace = false;\n  opts.preserve_proto_field_names = true;\n  opts.always_print_enums_as_ints = true;\n  std::string result;\n  ::google::protobuf::util::MessageToJsonString(message, &result, opts);\n  return result;\n}\n\nvoid MergePeerErrors(\n    const std::vector<std::pair<std::string, scql::pb::Status>>& peer_errors,\n    scql::pb::Status* status) {\n  std::string merged_error_msg{};\n  for (const auto& error : peer_errors) {\n    // NOTE: status->add_details() is not used here because the format used by\n    // brpc to convert messages containing Any into json is not compatible\n    // with the standard.\n    merged_error_msg.append(fmt::format(\"; (peer: {}, code: {}, msg: {})\",\n                                        error.first, error.second.code(),\n                                        error.second.message()));\n  }\n  status->set_message(fmt::format(\"{}{}\", status->message(), merged_error_msg));\n}\n\nclass CredentialExpception : std::runtime_error {\n public:\n  explicit CredentialExpception(const std::string& msg)\n      : std::runtime_error(\n            fmt::format(\"[Driver credential check failed] {}\", msg)) {}\n};\n\n}  // namespace\n\nnamespace scql::engine {\n\nEngineServiceImpl::EngineServiceImpl(\n    const EngineServiceOptions& options,\n    std::unique_ptr<SessionManager> session_mgr,\n    ChannelManager* channel_manager,\n    std::unique_ptr<auth::Authenticator> authenticator)\n    : service_options_(options),\n      session_mgr_(std::move(session_mgr)),\n      channel_manager_(channel_manager),\n      authenticator_(std::move(authenticator)) {\n  if (options.enable_authorization && options.credential.empty()) {\n    YACL_THROW(\n        \"credential is empty, you should provide credential for driver \"\n        \"authorization\");\n  }\n  op::RegisterAllOps();\n}\n\nvoid EngineServiceImpl::CheckDriverCredential(\n    const brpc::HttpHeader& http_header) {\n  if (!service_options_.enable_authorization) {\n    return;\n  }\n\n  const std::string* credential = http_header.GetHeader(\"Credential\");\n\n  if (credential == nullptr || credential->empty()) {\n    throw CredentialExpception(\"credential in http header is empty\");\n  }\n\n  if (*credential != service_options_.credential) {\n    throw CredentialExpception(\n        \"driver authorization failed, unknown driver credential\");\n  }\n}\n\nvoid EngineServiceImpl::StopJob(::google::protobuf::RpcController* cntl,\n                                const pb::StopJobRequest* request,\n                                pb::Status* status,\n                                ::google::protobuf::Closure* done) {\n  TRACE_EVENT_DEFAULT_TRACK(RPCCALL_CATEGORY, \"EngineServiceImpl::StopJob\");\n  brpc::ClosureGuard done_guard(done);\n  // check illegal request.\n  auto* controller = static_cast<brpc::Controller*>(cntl);\n  std::string source_ip =\n      butil::endpoint2str(controller->remote_side()).c_str();\n  auto session_id = request->job_id();\n  try {\n    CheckDriverCredential(controller->http_request());\n  } catch (const std::exception& e) {\n    LOG_ERROR_AND_SET_STATUS(status, pb::Code::UNAUTHENTICATED, e.what());\n    return;\n  }\n\n  if (session_id.empty()) {\n    std::string err_msg = \"session_id in request is empty\";\n    LOG_ERROR_AND_SET_STATUS(status, pb::Code::INVALID_ARGUMENT, err_msg);\n    return;\n  }\n\n  auto logger = GetActiveLogger(session_id);\n  SPDLOG_LOGGER_INFO(logger, \"EngineServiceImpl::StopJob({}), reason({})\",\n                     session_id, request->reason());\n\n  try {\n    session_mgr_->StopSession(session_id);\n\n    status->set_code(pb::Code::OK);\n    return;\n  } catch (const std::exception& e) {\n    std::string err_msg =\n        fmt::format(\"StopSession({}) failed, catch std::exception={}\",\n                    session_id, e.what());\n    LOG_ERROR_AND_SET_STATUS_IMPL(logger, status,\n                                  pb::Code::UNKNOWN_ENGINE_ERROR, err_msg);\n    return;\n  }\n}\n\nvoid CheckGraphChecksum(const pb::RunExecutionPlanRequest* request,\n                        Session* session) {\n  auto logger = (session != nullptr && session->GetLogger() != nullptr)\n                    ? session->GetLogger()\n                    : spdlog::default_logger();\n\n  if (session->GetLink()->WorldSize() < 2 ||\n      !request->graph_checksum().check_graph_checksum()) {\n    SPDLOG_LOGGER_INFO(logger, \"skip checking graph checksum\");\n    return;\n  }\n\n  SPDLOG_LOGGER_INFO(logger, \"check graph checksum\");\n  const auto& graph_checksum = request->graph_checksum();\n  auto iter = graph_checksum.sub_graph_checksums().find(\n      std::to_string(session->SelfRank()));\n  YACL_ENFORCE(iter != graph_checksum.sub_graph_checksums().end(),\n               \"get graph checksum failed for rank {}\", session->SelfRank());\n  const auto& whole_graph_checksum = graph_checksum.whole_graph_checksum();\n  // concat whole graph checksum and self sub graph checksum\n  auto checksum = whole_graph_checksum + iter->second;\n\n  // get checksum from other parties\n  auto checksum_bufs = yacl::link::AllGather(\n      session->GetLink(),\n      yacl::ByteContainerView(checksum.data(), checksum.length()),\n      \"graph checksum\");\n\n  for (size_t rank = 0; rank < session->GetLink()->WorldSize(); rank++) {\n    if (rank == session->SelfRank()) {\n      continue;\n    }\n    // split checksum\n    auto peer_checksum = std::string_view(checksum_bufs[rank]);\n    auto peer_whole_graph_checksum =\n        peer_checksum.substr(0, whole_graph_checksum.size());\n    YACL_ENFORCE(peer_whole_graph_checksum == whole_graph_checksum,\n                 \"peer_whole_graph_checksum: {} != whole_graph_checksum: {}\",\n                 peer_checksum, whole_graph_checksum);\n    auto iter = graph_checksum.sub_graph_checksums().find(std::to_string(rank));\n    YACL_ENFORCE(iter != graph_checksum.sub_graph_checksums().end(),\n                 \"get graph checksum failed for rank {}\", session->SelfRank());\n    auto local_sub_graph_checksum = std::string(iter->second);\n    auto peer_sub_graph_checksum = peer_checksum.substr(\n        whole_graph_checksum.size(), local_sub_graph_checksum.size());\n    if (peer_sub_graph_checksum != local_sub_graph_checksum) {\n      SPDLOG_LOGGER_WARN(logger,\n                         \"graph checksum mismatch for rank {}, self sub graph \"\n                         \"checksum: {}, peer sub graph checksum: {}\",\n                         rank, local_sub_graph_checksum,\n                         peer_sub_graph_checksum);\n    }\n  }\n}\n\nvoid EngineServiceImpl::RunExecutionPlan(\n    ::google::protobuf::RpcController* cntl,\n    const pb::RunExecutionPlanRequest* request,\n    pb::RunExecutionPlanResponse* response, ::google::protobuf::Closure* done) {\n  TRACE_EVENT_DEFAULT_TRACK(RPCCALL_CATEGORY,\n                            \"EngineServiceImpl::RunExecutionPlan\");\n  brpc::ClosureGuard done_guard(done);\n  auto* controller = static_cast<brpc::Controller*>(cntl);\n  std::string source_ip =\n      butil::endpoint2str(controller->remote_side()).c_str();\n\n  try {\n    CheckDriverCredential(controller->http_request());\n  } catch (const std::exception& e) {\n    LOG_ERROR_AND_SET_STATUS(response->mutable_status(),\n                             pb::Code::UNAUTHENTICATED, e.what());\n    return;\n  }\n\n  const std::string session_id = request->job_params().job_id();\n  response->set_job_id(session_id);\n  response->set_party_code(request->job_params().party_code());\n\n  if (request->async() && request->callback_url().empty()) {\n    std::string err_msg = fmt::format(\n        \"RunExecutionPlan run jobs({}) failed, in async mode but \"\n        \"callback_url is empty\",\n        session_id);\n    LOG_ERROR_AND_SET_STATUS(response->mutable_status(), pb::Code::BAD_REQUEST,\n                             err_msg);\n\n    ReportErrorToPeers(request->job_params(), pb::Code::BAD_REQUEST, err_msg);\n    return;\n  }\n\n  Session* session = nullptr;\n  // 1. create session first.\n  try {\n    VerifyPublicKeys(request->job_params());\n\n    session_mgr_->CreateSession(request->job_params(), request->debug_opts());\n    session = session_mgr_->GetSession(session_id);\n    YACL_ENFORCE(session, \"get session failed\");\n    // check graph checksum\n    CheckGraphChecksum(request, session);\n    ::scql::pb::Status status;\n    status.set_code(0);\n  } catch (const std::exception& e) {\n    std::string err_msg = fmt::format(\n        \"RunExecutionPlan create session({}) failed, catch \"\n        \"std::exception={} \",\n        session_id, e.what());\n    LOG_ERROR_AND_SET_STATUS(response->mutable_status(),\n                             pb::Code::UNKNOWN_ENGINE_ERROR, err_msg);\n    ReportErrorToPeers(request->job_params(), pb::Code::UNKNOWN_ENGINE_ERROR,\n                       err_msg);\n    return;\n  }\n  // report communication data during initialization\n  COMMUNICATION_COUNTER(session->GetLinkStats());\n  // 2. run plan in async or sync mode\n  auto logger = ActiveLogger(session);\n  SPDLOG_LOGGER_INFO(logger,\n                     \"[RunExecutionPlan] Session created successfully, start \"\n                     \"to run plan, client = {}\\nRunExecutionPlanRequest = {}\",\n                     source_ip, MessageToJsonString(*request));\n  if (request->async()) {\n    // Copy 'request' to avoid deconstruction before async call finished.\n    worker_pool_.Submit(&EngineServiceImpl::RunPlanAsync, this, *request,\n                        session, source_ip);\n    SPDLOG_LOGGER_INFO(logger,\n                       \"submit runplan for session({}), dag queue length={}\",\n                       session_id, worker_pool_.GetQueueLength());\n    response->mutable_status()->set_code(pb::Code::OK);\n    return;\n  } else {\n    // run in sync mode\n    RunPlanSync(request, session, response);\n    // Cannot directly set session status because the session may have already\n    // been removed\n    session_mgr_->CompareAndSetState(session_id, SessionState::COMP_FINISHED,\n                                     SessionState::SUCCEEDED);\n\n    try {\n      session_mgr_->RemoveSession(session_id);\n    } catch (const std::exception& e) {\n      SPDLOG_LOGGER_ERROR(logger,\n                          \"RunExecutionPlan remove session({}) failed, catch \"\n                          \"std::exception={}\",\n                          session_id, e.what());\n    }\n    return;\n  }\n}\n\nvoid EngineServiceImpl::QueryJobStatus(::google::protobuf::RpcController* cntl,\n                                       const pb::QueryJobStatusRequest* request,\n                                       pb::QueryJobStatusResponse* response,\n                                       ::google::protobuf::Closure* done) {\n  brpc::ClosureGuard done_guard(done);\n  auto* controller = static_cast<brpc::Controller*>(cntl);\n\n  try {\n    CheckDriverCredential(controller->http_request());\n  } catch (const std::exception& e) {\n    LOG_ERROR_AND_SET_STATUS(response->mutable_status(),\n                             pb::Code::UNAUTHENTICATED, e.what());\n    return;\n  }\n\n  const auto& job_id = request->job_id();\n  if (job_id.empty()) {\n    std::string err_msg = \"bad request: job_id is empty\";\n    LOG_ERROR_AND_SET_STATUS(response->mutable_status(),\n                             pb::Code::INVALID_ARGUMENT, err_msg);\n    return;\n  }\n  auto* session = session_mgr_->GetSession(job_id);\n\n  if (session == nullptr) {\n    std::string err_msg =\n        fmt::format(\"QueryJobStatus failed, job({}) not found\", job_id);\n    LOG_ERROR_AND_SET_STATUS(response->mutable_status(), pb::Code::NOT_FOUND,\n                             err_msg);\n    return;\n  }\n\n  auto logger = ActiveLogger(session);\n  logger->debug(\"Session is valid, handle QueryJobStatus request, request={}\",\n                MessageToJsonString(*request));\n\n  auto job_state = ConvertSessionStateToJobState(session->GetState());\n  if (job_state == pb::JOB_STATE_UNSPECIFIED) {\n    SPDLOG_LOGGER_WARN(logger, \"unknown job state, job_id={}\", job_id);\n  }\n\n  response->mutable_status()->set_code(pb::Code::OK);\n  response->set_job_state(job_state);\n\n  {\n    // set job progress\n    auto* progress = response->mutable_progress();\n\n    auto chronoTimePointToTimestamp =\n        [](const std::chrono::system_clock::time_point& tp)\n        -> google::protobuf::Timestamp {\n      google::protobuf::Timestamp timestamp;\n      auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(tp);\n      auto nanos =\n          std::chrono::time_point_cast<std::chrono::nanoseconds>(tp) -\n          std::chrono::time_point_cast<std::chrono::nanoseconds>(seconds);\n      timestamp.set_seconds(seconds.time_since_epoch().count());\n      timestamp.set_nanos(static_cast<int>(nanos.count()));\n      return timestamp;\n    };\n    progress->mutable_start_time()->CopyFrom(\n        chronoTimePointToTimestamp(session->GetStartTime()));\n\n    progress->set_stages_count(session->GetProgressStats()->GetNodesCnt());\n    progress->set_executed_stages(\n        session->GetProgressStats()->GetExecutedNodes());\n\n    auto link_stats = session->GetLinkStats();\n    progress->mutable_io_stats()->set_send_bytes(link_stats->sent_bytes);\n    progress->mutable_io_stats()->set_recv_bytes(link_stats->recv_bytes);\n    progress->mutable_io_stats()->set_send_actions(link_stats->sent_actions);\n    progress->mutable_io_stats()->set_recv_actions(link_stats->recv_actions);\n    auto* current_stage = progress->add_running_stages();\n    auto [node_start_time, current_node_name] =\n        session->GetProgressStats()->GetCurrentNodeInfo();\n    current_stage->mutable_start_time()->CopyFrom(\n        chronoTimePointToTimestamp(node_start_time));\n    current_stage->set_name(current_node_name);\n    current_stage->set_summary(session->GetProgressStats()->Summary());\n  }\n\n  SPDLOG_LOGGER_INFO(\n      logger, \"Finish to handle QueryJobStatus request, job_id={}\", job_id);\n}\n\nvoid EngineServiceImpl::ReportResult(Session* session,\n                                     const std::string& cb_url,\n                                     const std::string& report_info_str) {\n  auto session_id = session->Id();\n  auto logger = GetActiveLogger(session_id);\n  try {\n    auto rpc_channel =\n        channel_manager_->Create(logger, cb_url, RemoteRole::Driver);\n    if (!rpc_channel) {\n      session->SetState(SessionState::FAILED);\n      SPDLOG_LOGGER_WARN(logger,\n                         \"create rpc channel failed for driver: session_id={}, \"\n                         \"callback_url={}\",\n                         session_id, cb_url);\n      return;\n    }\n\n    // do http report\n    brpc::Controller cntl;\n    if (cntl.http_request().uri().SetHttpURL(cb_url) != 0) {\n      session->SetState(SessionState::FAILED);\n      const auto& st = cntl.http_request().uri().status();\n      SPDLOG_LOGGER_WARN(logger, \"failed to set request URL: {}\",\n                         st.error_str());\n      return;\n    }\n    cntl.http_request().set_method(brpc::HTTP_METHOD_POST);\n    cntl.http_request().set_content_type(\"application/json\");\n    cntl.request_attachment().append(report_info_str);\n\n    SPDLOG_LOGGER_WARN(\n        logger, \"session({}) send rpc request to driver, callback_url={}\",\n        session_id, cb_url);\n    // Because `done'(last parameter) is NULL, this function waits until\n    // the response comes back or error occurs(including timeout).\n    rpc_channel->CallMethod(nullptr, &cntl, nullptr, nullptr, nullptr);\n    if (cntl.Failed()) {\n      session->SetState(SessionState::FAILED);\n      SPDLOG_LOGGER_WARN(\n          logger, \"session({}) report callback URL({}) failed with error({})\",\n          session_id, cb_url, cntl.ErrorText());\n      return;\n    }\n\n    SPDLOG_LOGGER_INFO(\n        logger, \"session({}) report success, get response ({}), used({}ms)\",\n        session_id, cntl.response_attachment().to_string(),\n        cntl.latency_us() / 1000);\n\n  } catch (const std::exception& e) {\n    session->SetState(SessionState::FAILED);\n    SPDLOG_LOGGER_WARN(logger,\n                       \"ReportResult({}) failed, catch std::exception={}\",\n                       session_id, e.what());\n    return;\n  }\n}\n\nvoid EngineServiceImpl::VerifyPublicKeys(\n    const pb::JobStartParams& start_params) {\n  TRACE_EVENT_DEFAULT_TRACK(OTHER_CATEGORY,\n                            \"EngineServiceImpl::VerifyPublicKeys\");\n  if (!authenticator_) {\n    return;\n  }\n  std::vector<auth::PartyIdentity> parties;\n  for (const auto& party : start_params.parties()) {\n    parties.emplace_back(auth::PartyIdentity{party.code(), party.public_key()});\n  }\n  authenticator_->Verify(start_params.party_code(), parties);\n}\n\nvoid EngineServiceImpl::RunPlanSync(const pb::RunExecutionPlanRequest* request,\n                                    Session* session,\n                                    pb::RunExecutionPlanResponse* response) {\n  TRACE_EVENT_DEFAULT_TRACK(RPCCALL_CATEGORY, \"EngineServiceImpl::RunPlanSync\");\n  auto logger = ActiveLogger(session);\n  // 1. run jobs in plan and add result to response.\n  const std::string session_id = request->job_params().job_id();\n  try {\n    // wait until all peers finished, if any one of them broken, the\n    // ::yacl::IoError will be throw in other peers after Channel::Recv timeout\n    ::psi::SyncWait(session->GetLink(), [&] {\n      session->SetState(SessionState::RUNNING);\n      ::scql::engine::RunPlanCore(*request, session, response);\n    });\n    session->SetState(SessionState::COMP_FINISHED);\n\n    SPDLOG_LOGGER_INFO(logger, \"RunExecutionPlan completed, sessionID={}\",\n                       session_id);\n    auto lctx = session->GetLink();\n    lctx->WaitLinkTaskFinish();\n  } catch (const std::exception& e) {\n    session->SetState(SessionState::FAILED);\n\n    std::string err_msg = fmt::format(\n        \"RunExecutionPlan run jobs({}) failed, catch std::exception={}\",\n        session_id, e.what());\n    LOG_ERROR_AND_SET_STATUS_IMPL(logger, response->mutable_status(),\n                                  pb::Code::UNKNOWN_ENGINE_ERROR, err_msg);\n    response->mutable_out_columns()->Clear();\n    ReportErrorToPeers(request->job_params(), pb::Code::UNKNOWN_ENGINE_ERROR,\n                       err_msg);\n  }\n\n  MergePeerErrors(session->GetPeerErrors(), response->mutable_status());\n}\n\nvoid EngineServiceImpl::RunPlanAsync(const pb::RunExecutionPlanRequest& request,\n                                     Session* session,\n                                     const std::string& source_ip) {\n  TRACE_EVENT_DEFAULT_TRACK(RPCCALL_CATEGORY,\n                            \"EngineServiceImpl::RunPlanASync\");\n  pb::RunExecutionPlanResponse response;\n  response.set_job_id(request.job_params().job_id());\n  response.set_party_code(request.job_params().party_code());\n\n  auto session_id = session->Id();\n  RunPlanSync(&request, session, &response);\n\n  // prepare report info\n  pb::ReportRequest report;\n  report.mutable_status()->CopyFrom(response.status());\n  report.mutable_out_columns()->CopyFrom(response.out_columns());\n  report.set_job_id(response.job_id());\n  report.set_party_code(response.party_code());\n  report.set_num_rows_affected(response.num_rows_affected());\n\n  ReportResult(session, request.callback_url(), MessageToJsonString(report));\n  // Cannot directly set session status because the session may have already\n  // been removed\n  session_mgr_->CompareAndSetState(session_id, SessionState::COMP_FINISHED,\n                                   SessionState::SUCCEEDED);\n\n  // remove session.\n  // NOTE: removing the session should be performed after ReportResult to\n  // prevent the job watcher from receiving a \"session not found\" error when\n  // executing QueryJobStatus.\n  try {\n    session_mgr_->RemoveSession(request.job_params().job_id());\n  } catch (const std::exception& e) {\n    SPDLOG_ERROR(\n        \"RunExecutionPlan remove session({}) failed, catch \"\n        \"std::exception={}\",\n        request.job_params().job_id(), e.what());\n  }\n}\n\nvoid EngineServiceImpl::ReportErrorToPeers(const pb::JobStartParams& params,\n                                           const pb::Code err_code,\n                                           const std::string& err_msg) {\n  TRACE_EVENT_DEFAULT_TRACK(RPCCALL_CATEGORY,\n                            \"EngineServiceImpl::ReportErrorToPeers\");\n  auto logger = GetActiveLogger(params.job_id());\n  try {\n    PartyInfo parties(params);\n    for (const auto& party : parties.AllParties()) {\n      if (party.id == parties.SelfPartyCode()) {\n        continue;\n      }\n\n      auto rpc_channel =\n          channel_manager_->Create(logger, party.host, RemoteRole::PeerEngine);\n      YACL_ENFORCE(rpc_channel, \"create rpc channel failed for party=({},{})\",\n                   party.id, party.host);\n\n      services::pb::ReportErrorRequest request;\n      services::pb::ReportErrorResponse response;\n      brpc::Controller cntl;\n      services::pb::ErrorCollectorService_Stub stub(rpc_channel.get());\n\n      request.set_job_id(params.job_id());\n      request.set_party_code(parties.SelfPartyCode());\n      request.mutable_status()->set_code(err_code);\n      request.mutable_status()->set_message(err_msg);\n\n      stub.ReportError(&cntl, &request, &response, nullptr);\n      if (cntl.Failed()) {\n        SPDLOG_LOGGER_WARN(\n            logger,\n            \"sync error to peer=({},{}) rpc failed: error_code: {}, \"\n            \"error_text: {}\",\n            party.id, party.host, cntl.ErrorCode(), cntl.ErrorText());\n      } else {\n        if (response.status().code() != pb::Code::OK) {\n          SPDLOG_LOGGER_WARN(\n              logger, \"sync error to peer=({},{}) failed: status: {}\", party.id,\n              party.host, response.status().DebugString());\n        }\n      }\n    }\n  } catch (const std::exception& e) {\n    SPDLOG_LOGGER_WARN(logger, \"sync error to peers failed: throw: {}\",\n                       e.what());\n  }\n}\n\nstd::shared_ptr<spdlog::logger> EngineServiceImpl::GetActiveLogger(\n    const std::string& session_id) const {\n  auto* session = session_mgr_->GetSession(session_id);\n  return ActiveLogger(session);\n}\n\nvoid EngineServiceImpl::RunKpadTask(const util::ClusterDef& cluster_def) {\n  SPDLOG_INFO(\"Starting kpad task execution\");\n\n  auto scql_config =\n      scql::engine::util::ParseScqlConfig(FLAGS_kpad_scql_config);\n  YACL_ENFORCE(scql_config,\n               \"Failed to parse kpad_scql_config or kpad_scql_config is empty\");\n\n  auto self_party = cluster_def.self_party;\n  auto sub_graph_iter = scql_config->all_sub_graphs().find(self_party);\n  YACL_ENFORCE(sub_graph_iter != scql_config->all_sub_graphs().end(),\n               \"No subgraph found for self party: {}\", self_party);\n\n  auto job_params = scql::engine::util::BuildJobStartParams(\n      cluster_def, *scql_config, FLAGS_kpad_job_id);\n  YACL_ENFORCE(job_params, \"Failed to build job start parameters\");\n\n  // Create session\n  session_mgr_->CreateSession(*job_params, pb::DebugOptions{});\n  Session* session = session_mgr_->GetSession(FLAGS_kpad_job_id);\n  YACL_ENFORCE(session, \"Failed to get session\");\n\n  // Report communication data during initialization\n  COMMUNICATION_COUNTER(session->GetLinkStats());\n\n  auto logger = ActiveLogger(session);\n  SPDLOG_LOGGER_INFO(logger,\n                     \"[RunKpadTaskMode] Session created successfully, start \"\n                     \"to run kpad task, job_id={}\",\n                     FLAGS_kpad_job_id);\n\n  // Build execution plan request\n  pb::RunExecutionPlanRequest request;\n  *request.mutable_job_params() = *job_params;\n  *request.mutable_graph() = sub_graph_iter->second;\n\n  // Run plan in sync mode\n  pb::RunExecutionPlanResponse response;\n  RunPlanSync(&request, session, &response);\n  session_mgr_->CompareAndSetState(\n      FLAGS_kpad_job_id, SessionState::COMP_FINISHED, SessionState::SUCCEEDED);\n\n  session_mgr_->RemoveSession(FLAGS_kpad_job_id);\n\n  YACL_ENFORCE(response.status().code() == pb::Code::OK,\n               \"Kpad task execution failed with status: {} {}\",\n               response.status().code(), response.status().message());\n\n  SPDLOG_INFO(\"Kpad task execution completed successfully\");\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/services/engine_service_impl.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"yacl/utils/thread_pool.h\"\n\n#include \"engine/auth/authenticator.h\"\n#include \"engine/datasource/datasource_adaptor_mgr.h\"\n#include \"engine/framework/session_manager.h\"\n#include \"engine/link/channel_manager.h\"\n#include \"engine/services/run_plan_core.h\"\n#include \"engine/util/kpad_task_helper.h\"\n\n#include \"api/engine.pb.h\"\n#include \"api/scql_task.pb.h\"\n#include \"api/status.pb.h\"\n#include \"api/status_code.pb.h\"\n\nnamespace scql::engine {\n\nstruct EngineServiceOptions {\n  bool enable_authorization = false;\n  std::string credential;\n};\n\nclass EngineServiceImpl : public pb::SCQLEngineService {\n public:\n  EngineServiceImpl(const EngineServiceOptions& options,\n                    std::unique_ptr<SessionManager> session_mgr,\n                    ChannelManager* channel_manager,\n                    std::unique_ptr<auth::Authenticator> authenticator);\n\n  ~EngineServiceImpl() = default;\n\n  void RunExecutionPlan(::google::protobuf::RpcController* cntl,\n                        const pb::RunExecutionPlanRequest* request,\n                        pb::RunExecutionPlanResponse* response,\n                        ::google::protobuf::Closure* done) override;\n\n  void QueryJobStatus(::google::protobuf::RpcController* cntl,\n                      const pb::QueryJobStatusRequest* request,\n                      pb::QueryJobStatusResponse* response,\n                      ::google::protobuf::Closure* done) override;\n\n  void StopJob(::google::protobuf::RpcController* cntl,\n               const pb::StopJobRequest* request, pb::Status* status,\n               ::google::protobuf::Closure* done) override;\n\n  SessionManager* GetSessionManager() { return session_mgr_.get(); }\n\n  // Run kpad task execution, throws exception on failure\n  void RunKpadTask(const util::ClusterDef& cluster_def);\n\n private:\n  void ReportResult(Session* session, const std::string& cb_url,\n                    const std::string& report_info_str);\n\n  void RunPlanSync(const pb::RunExecutionPlanRequest* request, Session* session,\n                   pb::RunExecutionPlanResponse* response);\n\n  void RunPlanAsync(const pb::RunExecutionPlanRequest& request,\n                    Session* session, const std::string& source_ip);\n\n  void CheckDriverCredential(const brpc::HttpHeader& http_header);\n\n  void VerifyPublicKeys(const pb::JobStartParams& start_params);\n\n  void ReportErrorToPeers(const pb::JobStartParams& params, pb::Code err_code,\n                          const std::string& err_msg);\n\n  std::shared_ptr<spdlog::logger> GetActiveLogger(\n      const std::string& session_id) const;\n\n private:\n  const EngineServiceOptions service_options_;\n  std::unique_ptr<SessionManager> session_mgr_;\n  // thread pool to run async tasks.\n  yacl::ThreadPool worker_pool_;\n\n  ChannelManager* channel_manager_;\n\n  // used for datasource operator.\n  std::unique_ptr<Router> ds_router_;\n  std::unique_ptr<DatasourceAdaptorMgr> ds_mgr_;\n\n  std::unique_ptr<auth::Authenticator> authenticator_;\n};\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/services/engine_service_impl_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/services/engine_service_impl.h\"\n\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <vector>\n\n#include \"Poco/Data/SQLite/Connector.h\"\n#include \"Poco/Data/Session.h\"\n#include \"brpc/server.h\"\n#include \"gtest/gtest.h\"\n#include \"spdlog/spdlog.h\"\n\n#include \"engine/datasource/embed_router.h\"\n#include \"engine/exe/flags.h\"\n#include \"engine/framework/session.h\"\n#include \"engine/link/mux_link_factory.h\"\n#include \"engine/link/mux_receiver_service.h\"\n#include \"engine/operator/filter_by_index.h\"\n#include \"engine/operator/join.h\"\n#include \"engine/operator/publish.h\"\n#include \"engine/operator/run_sql.h\"\n#include \"engine/operator/test_util.h\"\n#include \"engine/util/trace_categories.h\"\n\n#include \"api/status_code.pb.h\"\n#include \"engine/services/mock_report_service.pb.h\"\n\nnamespace scql::engine {\n\nclass MockReportServiceImpl : public services::pb::MockReportService {\n public:\n  void Report(::google::protobuf::RpcController* controller,\n              const pb::ReportRequest* request,\n              services::pb::MockResponse* response,\n              ::google::protobuf::Closure* done) override {\n    brpc::ClosureGuard done_guard(done);\n    req_id = request->job_id();\n    status.CopyFrom(request->status());\n    if (request->out_columns_size() > 0) {\n      first_tensor = request->out_columns(0);\n    }\n    brpc::Controller* cntl = static_cast<brpc::Controller*>(controller);\n    cntl->response_attachment().append(\"receive report succ.\");\n  }\n\n public:\n  std::string req_id;\n  pb::Status status;\n  pb::Tensor first_tensor;\n};\n\nclass EngineServiceImplTest : public ::testing::Test {\n protected:\n  void SetUp() override {\n    // Construct EngineServiceImpl.\n    factory =\n        std::make_unique<MuxLinkFactory>(&channel_manager, &listener_manager);\n    EXPECT_NE(nullptr, factory.get());\n    engine_service_options.enable_authorization = true;\n    engine_service_options.credential = \"alice_credential\";\n    std::vector<spu::ProtocolKind> allowed_protocols = {\n        spu::ProtocolKind::SEMI2K};\n    impl = std::make_unique<EngineServiceImpl>(\n        engine_service_options,\n        std::make_unique<SessionManager>(session_options, &listener_manager,\n                                         std::move(factory), nullptr, nullptr,\n                                         1, allowed_protocols),\n        &channel_manager, nullptr);\n    EXPECT_NE(nullptr, impl.get());\n    {\n      global_session_id = \"test_session_id\";\n      // prepare pb::JobStartParams global_params.\n      global_params.set_job_id(global_session_id);\n\n      global_params.set_party_code(op::test::kPartyAlice);\n      auto* alice = global_params.add_parties();\n      alice->CopyFrom(op::test::BuildParty(op::test::kPartyAlice, 0));\n      global_cntl.http_request().SetHeader(\n          \"Credential\", fmt::format(\"{}_credential\", op::test::kPartyAlice));\n\n      global_params.mutable_spu_runtime_cfg()->CopyFrom(\n          op::test::MakeSpuRuntimeConfigForTest(spu::ProtocolKind::SEMI2K)\n              .ToProto());\n    }\n  }\n\n  void CheckJobStatus(pb::JobState pb_state) {\n    pb::QueryJobStatusRequest request;\n    request.set_job_id(global_session_id);\n    pb::QueryJobStatusResponse response;\n    EXPECT_NO_THROW(\n        impl->QueryJobStatus(&global_cntl, &request, &response, nullptr));\n    EXPECT_EQ(pb::Code::OK, response.status().code());\n    EXPECT_EQ(pb_state, response.job_state());\n  }\n\n  void SetAndCheckJobStatus(SessionState state) {\n    auto* session_manager = impl->GetSessionManager();\n    EXPECT_TRUE(session_manager->SetSessionState(global_session_id, state));\n\n    CheckJobStatus(ConvertSessionStateToJobState(state));\n  }\n\n  void CheckJobNodeCount(int32_t expected_nodes_count,\n                         int32_t expected_executed_nodes) {\n    pb::QueryJobStatusRequest request;\n    request.set_job_id(global_session_id);\n    pb::QueryJobStatusResponse response;\n    EXPECT_NO_THROW(\n        impl->QueryJobStatus(&global_cntl, &request, &response, nullptr));\n    EXPECT_EQ(pb::Code::OK, response.status().code());\n    EXPECT_EQ(expected_nodes_count, response.progress().stages_count());\n    EXPECT_EQ(expected_executed_nodes, response.progress().executed_stages());\n  }\n\n public:\n  ListenerManager listener_manager;\n  ChannelManager channel_manager;\n  std::unique_ptr<MuxLinkFactory> factory;\n  std::unique_ptr<EngineServiceImpl> impl;\n  std::string global_session_id;\n  brpc::Controller global_cntl;\n  pb::JobStartParams global_params;\n  SessionOptions session_options;\n  EngineServiceOptions engine_service_options;\n};\n\nvoid MockPipeline(pb::SchedulingPolicy* policy,\n                  const std::vector<size_t>& nodes_cnt_in_subdag) {\n  auto* pipeline = policy->add_pipelines();\n  for (size_t i : nodes_cnt_in_subdag) {\n    auto* subdag = pipeline->add_subdags();\n    for (size_t j = 0; j < i; ++j) {\n      auto* job = subdag->add_jobs();\n      job->add_node_ids(std::to_string(j));\n    }\n  }\n}\n\nTEST_F(EngineServiceImplTest, QueryJobStatus) {\n  // Given\n  //  bypass RunExecutionPlan, control the session's state manually.\n  pb::DebugOptions debug_opts;\n  pb::JobStartParams params;\n  {\n    params.set_job_id(global_session_id);\n\n    params.set_party_code(op::test::kPartyAlice);\n    auto* alice = params.add_parties();\n    alice->CopyFrom(op::test::BuildParty(op::test::kPartyAlice, 0));\n\n    params.mutable_spu_runtime_cfg()->CopyFrom(\n        op::test::MakeSpuRuntimeConfigForTest(spu::ProtocolKind::SEMI2K)\n            .ToProto());\n  }\n\n  // When\n  auto* session_manager = impl->GetSessionManager();\n  EXPECT_NO_THROW(session_manager->CreateSession(params, debug_opts));\n  // Then\n  CheckJobStatus(pb::JOB_INITIALIZED);\n  // When & Then\n  SetAndCheckJobStatus(SessionState::RUNNING);\n  SetAndCheckJobStatus(SessionState::ABORTING);\n  SetAndCheckJobStatus(SessionState::SUCCEEDED);\n  SetAndCheckJobStatus(SessionState::FAILED);\n\n  // Given\n  CheckJobNodeCount(0, 0);\n  auto* session = session_manager->GetSession(global_session_id);\n  // add first pipeline\n  pb::SchedulingPolicy policy;\n  MockPipeline(&policy, {5, 5});\n  session->InitProgressStats(policy);\n  CheckJobNodeCount(10, 0);\n  session->GetProgressStats()->IncExecutedNodes();\n  session->GetProgressStats()->IncExecutedNodes();\n  CheckJobNodeCount(10, 2);\n  EXPECT_EQ(2, session->GetProgressStats()->GetExecutedNodes());\n  EXPECT_EQ(\"stages executed 2/10\", session->GetProgressStats()->Summary());\n  // running to second subdag\n  for (int i = 0; i < 5; ++i) {\n    session->GetProgressStats()->IncExecutedNodes();\n  }\n  EXPECT_EQ(7, session->GetProgressStats()->GetExecutedNodes());\n  EXPECT_EQ(\"stages executed 7/10\", session->GetProgressStats()->Summary());\n  pb::SchedulingPolicy batched_policy;\n  // batched policy, 2 pipelines\n  MockPipeline(&batched_policy, {6, 4});\n  MockPipeline(&batched_policy, {4, 6});\n  session->InitProgressStats(batched_policy);\n  CheckJobNodeCount(20, 0);\n  session->GetProgressStats()->SetBatchCntInPipeline(10);\n  session->GetProgressStats()->IncExecutedBatch();\n  session->GetProgressStats()->IncExecutedBatch();\n  CheckJobNodeCount(20, 0);\n  EXPECT_EQ(0, session->GetProgressStats()->GetExecutedNodes());\n  session->GetProgressStats()->SetCurrentNodeInfo(\n      std::chrono::system_clock::now(), \"mock_node1\");\n  EXPECT_EQ(\n      \"executed pipeline:0/2 executed batch:2/10 node:mock_node1 in current \"\n      \"pipeline 1\",\n      session->GetProgressStats()->Summary());\n  // running to second pipeline\n  session->GetProgressStats()->IncExecutedPipeline();\n  session->GetProgressStats()->SetBatchCntInPipeline(5);\n  session->GetProgressStats()->IncExecutedBatch();\n  session->GetProgressStats()->IncExecutedBatch();\n  EXPECT_EQ(10, session->GetProgressStats()->GetExecutedNodes());\n  session->GetProgressStats()->SetCurrentNodeInfo(\n      std::chrono::system_clock::now(), \"mock_node2\");\n  EXPECT_EQ(\n      \"executed pipeline:1/2 executed batch:2/5 node:mock_node2 in current \"\n      \"pipeline 2\",\n      session->GetProgressStats()->Summary());\n}\n\nTEST_F(EngineServiceImplTest, RunExecutionPlan) {\n  // Given\n  pb::RunExecutionPlanRequest request;\n  request.mutable_job_params()->CopyFrom(global_params);\n  pb::RunExecutionPlanResponse response;\n  // When\n  EXPECT_NO_THROW(\n      impl->RunExecutionPlan(&global_cntl, &request, &response, nullptr));\n  // Then\n  EXPECT_EQ(pb::Code::OK, response.status().code());\n\n  // test with ExecNode\n  pb::ExecNode node;\n  node.set_node_name(\"Publish.0\");\n  node.set_op_type(\"Publish\");\n  std::string node_id = \"0\";\n  auto* graph = request.mutable_graph();\n  (*graph->mutable_nodes())[node_id] = node;\n  auto* pipeline = graph->mutable_policy()->add_pipelines();\n  auto* subdag = pipeline->add_subdags();\n  auto* job = subdag->add_jobs();\n  job->add_node_ids(node_id);\n\n  EXPECT_NO_THROW(\n      impl->RunExecutionPlan(&global_cntl, &request, &response, nullptr));\n  EXPECT_EQ(pb::Code::UNKNOWN_ENGINE_ERROR, response.status().code());\n}\n\nTEST_F(EngineServiceImplTest, RunExecutionPlanAsync) {\n  // Given\n  brpc::Server recv_server;\n  MockReportServiceImpl service;\n  {\n    ASSERT_EQ(\n        0, recv_server.AddService(&service, brpc::SERVER_DOESNT_OWN_SERVICE));\n    brpc::ServerOptions recv_options;\n    ASSERT_EQ(0, recv_server.Start(\"127.0.0.1:0\", &recv_options));\n  }\n  pb::RunExecutionPlanRequest request;\n  request.mutable_job_params()->CopyFrom(global_params);\n  request.set_async(true);\n  request.set_callback_url(\n      fmt::format(\"{}/MockReportService/Report\",\n                  butil::endpoint2str(recv_server.listen_address()).c_str()));\n\n  pb::RunExecutionPlanResponse response;\n  // When\n  EXPECT_NO_THROW(\n      impl->RunExecutionPlan(&global_cntl, &request, &response, nullptr));\n  // Then\n  EXPECT_EQ(pb::Code::OK, response.status().code());\n\n  usleep(1000 * 1000);  // wait async run finished.\n  EXPECT_EQ(global_session_id, service.req_id);\n  EXPECT_EQ(pb::Code::OK, service.status.code());\n\n  // test with error response\n  pb::ExecNode node;\n  node.set_node_name(\"Publish.0\");\n  node.set_op_type(\"Publish\");\n  std::string node_id = \"0\";\n  auto* graph = request.mutable_graph();\n  (*graph->mutable_nodes())[node_id] = node;\n  auto* pipeline = graph->mutable_policy()->add_pipelines();\n  auto* subdag = pipeline->add_subdags();\n  auto* job = subdag->add_jobs();\n  job->add_node_ids(node_id);\n\n  EXPECT_NO_THROW(\n      impl->RunExecutionPlan(&global_cntl, &request, &response, nullptr));\n  EXPECT_EQ(pb::Code::OK, response.status().code());\n\n  usleep(1000 * 1000);  // wait async run finished.\n  EXPECT_EQ(global_session_id, service.req_id);\n  EXPECT_EQ(pb::Code::UNKNOWN_ENGINE_ERROR, service.status.code());\n\n  recv_server.Stop(1000);\n  recv_server.Join();\n}\n\n// ===========================Test for 2 Parties =========================\n\nstruct InnerJoinTestCase {\n  std::vector<std::string> alice;\n  std::vector<std::string> bob;\n  std::vector<std::string> inner_join_result;\n};\nclass EngineServiceImpl2PartiesTest\n    : public ::testing::TestWithParam<InnerJoinTestCase> {\n protected:\n  void SetUp() override {\n    // Start Brpc Receive Services\n    servers = std::vector<brpc::Server>(kWorldSize);\n    for (size_t rank = 0; rank < kWorldSize; rank++) {\n      listener_managers.emplace_back(new ListenerManager());\n      services.emplace_back(\n          new MuxReceiverServiceImpl(listener_managers[rank].get()));\n      ASSERT_EQ(0, servers[rank].AddService(services[rank].get(),\n                                            brpc::SERVER_DOESNT_OWN_SERVICE));\n\n      brpc::ServerOptions options;\n      ASSERT_EQ(0, servers[rank].Start(\"127.0.0.1:0\", &options));\n    }\n\n    global_cntl.http_request().SetHeader(\"Credential\", \"alice_credential\");\n    // Construct EngineServiceImpl\n    for (size_t rank = 0; rank < kWorldSize; rank++) {\n      auto factory = std::make_unique<MuxLinkFactory>(\n          &channel_manager, listener_managers[rank].get());\n      ASSERT_NE(nullptr, factory.get());\n      EngineServiceOptions service_options;\n      service_options.enable_authorization = true;\n      service_options.credential = \"alice_credential\";\n      SessionOptions session_options;\n      std::vector<spu::ProtocolKind> allowed_protocols = {\n          spu::ProtocolKind::SEMI2K};\n      auto impl = std::make_unique<EngineServiceImpl>(\n          service_options,\n          std::make_unique<SessionManager>(\n              session_options, listener_managers[rank].get(),\n              std::move(factory), EmbedRouter::FromJsonStr(router_json_str),\n              std::make_unique<DatasourceAdaptorMgr>(), 10, allowed_protocols),\n          &channel_manager, nullptr);\n      ASSERT_NE(nullptr, impl.get());\n\n      factories.push_back(std::move(factory));\n      engine_svcs.emplace_back(std::move(impl));\n    }\n    ASSERT_EQ(kWorldSize, engine_svcs.size());\n  }\n\n  static std::unique_ptr<Poco::Data::Session> PrepareTableInMemory(\n      const InnerJoinTestCase& tc, const std::string& db_connection_str);\n\n  static pb::RunExecutionPlanRequest ConstructRequestForAlice(\n      const std::vector<brpc::Server>& servers);\n\n  static pb::RunExecutionPlanRequest ConstructRequestForBob(\n      const std::vector<brpc::Server>& servers);\n\n  static void AddSessionParameters(pb::RunExecutionPlanRequest* request,\n                                   const std::vector<brpc::Server>& servers,\n                                   const size_t& self_rank);\n\n  static void AddRunSQLNode(pb::RunExecutionPlanRequest* request,\n                            const std::string& table_name,\n                            const std::string& out_name, int ref_count);\n\n  static void AddJoinNode(pb::RunExecutionPlanRequest* request,\n                          const std::pair<std::string, std::string>& in_name,\n                          const std::pair<std::string, std::string>& out_name,\n                          int ref_count);\n\n  static void AddFilterByIndexNode(pb::RunExecutionPlanRequest* request,\n                                   const std::string& in_name,\n                                   const std::string& indice_name,\n                                   const std::string& out_name, int ref_count);\n\n  static void AddPublishNode(pb::RunExecutionPlanRequest* request,\n                             const std::string& in_name,\n                             const std::string& out_name, int ref_count);\n\n protected:\n  const size_t kWorldSize = 2U;\n  std::vector<std::unique_ptr<ListenerManager>> listener_managers;\n  std::vector<std::unique_ptr<MuxReceiverServiceImpl>> services;\n  std::vector<brpc::Server> servers;\n  ChannelManager channel_manager;\n  std::vector<std::unique_ptr<MuxLinkFactory>> factories;\n  std::vector<std::unique_ptr<EngineServiceImpl>> engine_svcs;\n  brpc::Controller global_cntl;\n  const std::string router_json_str = R\"json({\n      \"datasources\": [\n        {\n          \"id\": \"ds001\",\n          \"name\": \"sqlite3\",\n          \"kind\": \"SQLITE\",\n          \"connection_str\": \"file:runsql_test?mode=memory&cache=shared\"\n        }\n      ],\n      \"rules\":[\n        {\n          \"db\": \"*\",\n          \"table\": \"*\",\n          \"datasource_id\": \"ds001\"\n        }\n      ]\n    })json\";\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    InnerJoinTest, EngineServiceImpl2PartiesTest,\n    testing::Values(InnerJoinTestCase{.alice = {\"alice\", \"bob\", \"carol\"},\n                                      .bob = {\"alice\", \"carol\"},\n                                      .inner_join_result = {\"alice\", \"carol\"}},\n                    InnerJoinTestCase{\n                        .alice = {\"B\", \"B\", \"D\"},\n                        .bob = {\"B\", \"B\"},\n                        .inner_join_result = {\"B\", \"B\", \"B\", \"B\"}},\n                    InnerJoinTestCase{.alice = {\"B\", \"B\", \"D\"},\n                                      .bob = {\"A\", \"C\"},\n                                      .inner_join_result = {}}));\n\n// run the case: find persons who both exist in ta(Table A) and tb(Table B).\nTEST_P(EngineServiceImpl2PartiesTest, RunExecutionPlan) {\n  // Given\n  auto test_case = GetParam();\n  auto session = PrepareTableInMemory(\n      test_case, \"file:runsql_test?mode=memory&cache=shared\");\n\n  util::TracingSessionGuard guard(true, \"scql\", \"/tmp/trace.trace\");\n  // When\n  auto proc = [&](EngineServiceImpl* svc, pb::RunExecutionPlanRequest* request,\n                  pb::RunExecutionPlanResponse* response) {\n    EXPECT_NO_THROW(\n        svc->RunExecutionPlan(&global_cntl, request, response, nullptr));\n    EXPECT_EQ(pb::Code::OK, response->status().code());\n  };\n\n  pb::RunExecutionPlanResponse response_alice;\n  pb::RunExecutionPlanRequest request_alice = ConstructRequestForAlice(servers);\n  auto future_alice =\n      std::async(proc, engine_svcs[0].get(), &request_alice, &response_alice);\n\n  pb::RunExecutionPlanResponse response_bob;\n  pb::RunExecutionPlanRequest request_bob = ConstructRequestForBob(servers);\n  auto future_bob =\n      std::async(proc, engine_svcs[1].get(), &request_bob, &response_bob);\n  // Then\n  EXPECT_NO_THROW(future_alice.get());\n  SPDLOG_INFO(\"out: \\n{}\", response_alice.DebugString());\n\n  EXPECT_NO_THROW(future_bob.get());\n  SPDLOG_INFO(\"out: \\n{}\", response_bob.DebugString());\n\n  auto check_equal = [](const pb::Tensor& actual_result,\n                        std::vector<std::string>& expect_result) {\n    std::vector<std::string> tmp;\n    tmp.reserve(actual_result.string_data_size());\n    for (const auto& item : actual_result.string_data()) {\n      tmp.push_back(item);\n    }\n    std::sort(tmp.begin(), tmp.end());\n    std::sort(expect_result.begin(), expect_result.end());\n    EXPECT_EQ(tmp.size(), expect_result.size());\n\n    for (size_t i = 0; i < tmp.size(); ++i) {\n      EXPECT_EQ(tmp[i], expect_result[i]);\n    }\n  };\n  ASSERT_EQ(response_alice.out_columns_size(), 1);\n  check_equal(response_alice.out_columns(0), test_case.inner_join_result);\n  ASSERT_EQ(response_bob.out_columns_size(), 1);\n  check_equal(response_bob.out_columns(0), test_case.inner_join_result);\n\n  // -------test async run---------\n  {\n    // start mock report service.\n    brpc::Server recv_server;\n    MockReportServiceImpl service;\n    ASSERT_EQ(\n        0, recv_server.AddService(&service, brpc::SERVER_DOESNT_OWN_SERVICE));\n    brpc::ServerOptions recv_options;\n    ASSERT_EQ(0, recv_server.Start(\"127.0.0.1:0\", &recv_options));\n    // modify request\n    request_alice.set_async(true);\n    request_alice.set_callback_url(\n        fmt::format(\"{}/MockReportService/Report\",\n                    butil::endpoint2str(recv_server.listen_address()).c_str()));\n    request_bob.set_async(true);\n    // only check alice result\n    request_bob.set_callback_url(\n        fmt::format(\"{}/MockReportService/NotExistReport\",\n                    butil::endpoint2str(recv_server.listen_address()).c_str()));\n\n    pb::RunExecutionPlanResponse response_alice;\n    auto future_alice =\n        std::async(proc, engine_svcs[0].get(), &request_alice, &response_alice);\n\n    pb::RunExecutionPlanResponse response_bob;\n    auto future_bob =\n        std::async(proc, engine_svcs[1].get(), &request_bob, &response_bob);\n\n    EXPECT_NO_THROW(future_alice.get());\n    EXPECT_NO_THROW(future_bob.get());\n\n    ASSERT_EQ(response_alice.status().code(), 0);\n    ASSERT_EQ(response_bob.status().code(), 0);\n\n    usleep(100 * 1000);  // wait report\n    ASSERT_EQ(service.req_id, \"test_session_id\");\n    ASSERT_EQ(service.status.message(), \"\");\n    ASSERT_EQ(service.status.code(), 0);\n    check_equal(service.first_tensor, test_case.inner_join_result);\n\n    recv_server.Stop(1000);\n    recv_server.Join();\n  }\n}\n\n// control the time returned by the Report\nclass MockWaitReportServiceImpl : public services::pb::MockReportService {\n public:\n  void Report(::google::protobuf::RpcController* controller,\n              const pb::ReportRequest* request,\n              services::pb::MockResponse* response,\n              ::google::protobuf::Closure* done) override {\n    brpc::ClosureGuard done_guard(done);\n    // push to alice and bob\n    output_chan.Push(1);\n    // pull from alice and bob\n    input_chan.Pop();\n  }\n\n public:\n  util::SimpleChannel<size_t> input_chan{1};\n  util::SimpleChannel<size_t> output_chan{1};\n};\n\nTEST_P(EngineServiceImpl2PartiesTest, SessionNegotiationSameConf) {\n  // Given\n  auto test_case = GetParam();\n  auto session = PrepareTableInMemory(\n      test_case, \"file:runsql_test?mode=memory&cache=shared\");\n\n  // When\n  auto proc = [&](EngineServiceImpl* svc, pb::RunExecutionPlanRequest* request,\n                  pb::RunExecutionPlanResponse* response) {\n    EXPECT_NO_THROW(\n        svc->RunExecutionPlan(&global_cntl, request, response, nullptr));\n    EXPECT_EQ(pb::Code::OK, response->status().code());\n  };\n\n  // start mock report service.\n  brpc::Server recv_server;\n  MockWaitReportServiceImpl service;\n  ASSERT_EQ(0,\n            recv_server.AddService(&service, brpc::SERVER_DOESNT_OWN_SERVICE));\n  brpc::ServerOptions recv_options;\n  ASSERT_EQ(0, recv_server.Start(\"127.0.0.1:0\", &recv_options));\n\n  pb::RunExecutionPlanResponse response_alice;\n  pb::RunExecutionPlanRequest request_alice = ConstructRequestForAlice(servers);\n  // modify request\n  request_alice.set_async(true);\n  request_alice.set_callback_url(\n      fmt::format(\"{}/MockReportService/Report\",\n                  butil::endpoint2str(recv_server.listen_address()).c_str()));\n  auto* alice_job_params = request_alice.mutable_job_params();\n  auto* alice_psi_conf = alice_job_params->mutable_psi_cfg();\n  alice_psi_conf->set_psi_curve_type(\n      static_cast<int32_t>(psi::CurveType::CURVE_25519));\n  alice_psi_conf->set_rr22_mode(pb::LOW_MODE);\n  auto future_alice =\n      std::async(proc, engine_svcs[0].get(), &request_alice, &response_alice);\n\n  pb::RunExecutionPlanResponse response_bob;\n  pb::RunExecutionPlanRequest request_bob = ConstructRequestForBob(servers);\n  request_bob.set_async(true);\n  request_bob.set_callback_url(\n      fmt::format(\"{}/MockReportService/Report\",\n                  butil::endpoint2str(recv_server.listen_address()).c_str()));\n  auto* bob_job_params = request_bob.mutable_job_params();\n  auto* bob_psi_conf = bob_job_params->mutable_psi_cfg();\n  bob_psi_conf->set_psi_curve_type(\n      static_cast<int32_t>(psi::CurveType::CURVE_25519));\n  bob_psi_conf->set_rr22_mode(pb::LOW_MODE);\n  auto future_bob =\n      std::async(proc, engine_svcs[1].get(), &request_bob, &response_bob);\n  service.output_chan.Pop();  // alice wait async run finished.\n  service.output_chan.Pop();  // bob wait async run finished.\n  // Then\n  EXPECT_NO_THROW(future_alice.get());\n  SPDLOG_INFO(\"out: \\n{}\", response_alice.DebugString());\n\n  EXPECT_NO_THROW(future_bob.get());\n  SPDLOG_INFO(\"out: \\n{}\", response_bob.DebugString());\n  auto* session_alice = engine_svcs[0]->GetSessionManager()->GetSession(\n      request_alice.job_params().job_id());\n  EXPECT_EQ(session_alice->GetSessionOptions().psi_config.psi_curve_type,\n            psi::CurveType::CURVE_25519);\n  EXPECT_EQ(session_alice->GetSessionOptions().psi_config.rr22_mode,\n            pb::LOW_MODE);\n  auto* session_bob = engine_svcs[1]->GetSessionManager()->GetSession(\n      request_alice.job_params().job_id());\n  EXPECT_EQ(session_bob->GetSessionOptions().psi_config.psi_curve_type,\n            psi::CurveType::CURVE_25519);\n  EXPECT_EQ(session_bob->GetSessionOptions().psi_config.rr22_mode,\n            pb::LOW_MODE);\n  service.input_chan.Push(1);\n  service.input_chan.Push(1);\n  recv_server.Stop(1000);\n  recv_server.Join();\n}\n\nTEST_P(EngineServiceImpl2PartiesTest, SessionNegotiationDiffConf) {\n  // Given\n  auto test_case = GetParam();\n  auto session = PrepareTableInMemory(\n      test_case, \"file:runsql_test?mode=memory&cache=shared\");\n\n  // When\n  auto proc = [&](EngineServiceImpl* svc, pb::RunExecutionPlanRequest* request,\n                  pb::RunExecutionPlanResponse* response) {\n    EXPECT_NO_THROW(\n        svc->RunExecutionPlan(&global_cntl, request, response, nullptr));\n    EXPECT_EQ(pb::Code::OK, response->status().code());\n  };\n\n  // start mock report service.\n  brpc::Server recv_server;\n  MockWaitReportServiceImpl service;\n  ASSERT_EQ(0,\n            recv_server.AddService(&service, brpc::SERVER_DOESNT_OWN_SERVICE));\n  brpc::ServerOptions recv_options;\n  ASSERT_EQ(0, recv_server.Start(\"127.0.0.1:0\", &recv_options));\n\n  pb::RunExecutionPlanResponse response_alice;\n  pb::RunExecutionPlanRequest request_alice = ConstructRequestForAlice(servers);\n  // modify request\n  request_alice.set_async(true);\n  request_alice.set_callback_url(\n      fmt::format(\"{}/MockReportService/Report\",\n                  butil::endpoint2str(recv_server.listen_address()).c_str()));\n  auto* alice_job_params = request_alice.mutable_job_params();\n  auto* alice_psi_conf = alice_job_params->mutable_psi_cfg();\n  alice_psi_conf->set_psi_curve_type(\n      static_cast<int32_t>(psi::CurveType::CURVE_FOURQ));\n  alice_psi_conf->set_rr22_mode(pb::LOW_MODE);\n  std::vector<std::unique_ptr<EngineServiceImpl>> svcs;\n  std::vector<std::vector<spu::ProtocolKind>> allowed_protocols_v = {\n      {spu::ProtocolKind::SEMI2K, spu::ProtocolKind::ABY3},\n      {spu::ProtocolKind::SEMI2K, spu::ProtocolKind::CHEETAH}};\n  for (size_t rank = 0; rank < kWorldSize; rank++) {\n    auto factory = std::make_unique<MuxLinkFactory>(\n        &channel_manager, listener_managers[rank].get());\n    EngineServiceOptions service_options;\n    service_options.enable_authorization = true;\n    service_options.credential = \"alice_credential\";\n    SessionOptions session_options;\n    auto impl = std::make_unique<EngineServiceImpl>(\n        service_options,\n        std::make_unique<SessionManager>(\n            session_options, listener_managers[rank].get(), std::move(factory),\n            EmbedRouter::FromJsonStr(router_json_str),\n            std::make_unique<DatasourceAdaptorMgr>(), 10,\n            allowed_protocols_v[rank]),\n        &channel_manager, nullptr);\n    ASSERT_NE(nullptr, impl.get());\n    svcs.emplace_back(std::move(impl));\n  }\n  auto future_alice =\n      std::async(proc, svcs[0].get(), &request_alice, &response_alice);\n\n  pb::RunExecutionPlanResponse response_bob;\n  pb::RunExecutionPlanRequest request_bob = ConstructRequestForBob(servers);\n  request_bob.set_async(true);\n  request_bob.set_callback_url(\n      fmt::format(\"{}/MockReportService/Report\",\n                  butil::endpoint2str(recv_server.listen_address()).c_str()));\n  auto* bob_job_params = request_bob.mutable_job_params();\n  auto* bob_psi_conf = bob_job_params->mutable_psi_cfg();\n  bob_psi_conf->set_psi_curve_type(\n      static_cast<int32_t>(psi::CurveType::CURVE_FOURQ));\n  bob_psi_conf->set_rr22_mode(pb::FAST_MODE);\n\n  // Construct EngineServiceImpl\n  auto future_bob =\n      std::async(proc, svcs[1].get(), &request_bob, &response_bob);\n  service.output_chan.Pop();  // alice wait async run finished.\n  service.output_chan.Pop();  // bob wait async run finished.\n  // Then\n  EXPECT_NO_THROW(future_alice.get());\n  SPDLOG_INFO(\"out: \\n{}\", response_alice.DebugString());\n\n  EXPECT_NO_THROW(future_bob.get());\n  SPDLOG_INFO(\"out: \\n{}\", response_bob.DebugString());\n  auto* session_alice = svcs[0]->GetSessionManager()->GetSession(\n      request_alice.job_params().job_id());\n  EXPECT_EQ(session_alice->GetSessionOptions().psi_config.psi_curve_type,\n            psi::CurveType::CURVE_FOURQ);\n  EXPECT_EQ(session_alice->GetSessionOptions().psi_config.rr22_mode,\n            pb::LOW_MODE);\n  auto* session_bob = svcs[1]->GetSessionManager()->GetSession(\n      request_alice.job_params().job_id());\n  EXPECT_EQ(session_bob->GetSessionOptions().psi_config.psi_curve_type,\n            psi::CurveType::CURVE_FOURQ);\n  EXPECT_EQ(session_bob->GetSessionOptions().psi_config.rr22_mode,\n            pb::LOW_MODE);\n  service.input_chan.Push(1);\n  service.input_chan.Push(1);\n  recv_server.Stop(1000);\n  recv_server.Join();\n}\n\n/// ===========================\n/// Test for 2 Parties Implementation\n/// ===========================\n\nstd::unique_ptr<Poco::Data::Session>\nEngineServiceImpl2PartiesTest::PrepareTableInMemory(\n    const InnerJoinTestCase& tc, const std::string& db_connection_str) {\n  Poco::Data::SQLite::Connector::registerConnector();\n\n  auto result =\n      std::make_unique<Poco::Data::Session>(\"SQLite\", db_connection_str);\n\n  using Poco::Data::Keywords::now;\n  // create table: ta\n  *result << \"CREATE TABLE ta(name VARCHAR(30))\", now;\n  // insert some rows\n  for (size_t i = 0; i < tc.alice.size(); ++i) {\n    std::string row = fmt::format(\"INSERT INTO ta VALUES(\\\"{}\\\")\", tc.alice[i]);\n    *result << row, now;\n  }\n\n  // create table: tb\n  *result << \"CREATE TABLE tb(name VARCHAR(30))\", now;\n  // insert some rows\n  for (size_t i = 0; i < tc.bob.size(); ++i) {\n    std::string row = fmt::format(\"INSERT INTO tb VALUES(\\\"{}\\\")\", tc.bob[i]);\n    *result << row, now;\n  }\n\n  return result;\n}\n\npb::RunExecutionPlanRequest\nEngineServiceImpl2PartiesTest::ConstructRequestForAlice(\n    const std::vector<brpc::Server>& servers) {\n  pb::RunExecutionPlanRequest request;\n\n  // set graph checksum\n  auto* checker = request.mutable_graph_checksum();\n  checker->set_check_graph_checksum(true);\n  checker->mutable_sub_graph_checksums()->insert({\"0\", \"test\"});\n  checker->mutable_sub_graph_checksums()->insert({\"1\", \"test\"});\n  checker->mutable_whole_graph_checksum()->append(\"whole\");\n  AddSessionParameters(&request, servers, 0);\n\n  AddRunSQLNode(&request, \"ta\", \"ta.name\", 2);\n\n  AddJoinNode(&request, {\"ta.name\", \"tb.name\"}, {\"ta.index\", \"tb.index\"}, 1);\n\n  AddFilterByIndexNode(&request, \"ta.name\", \"ta.index\", \"ta.filtered\", 1);\n\n  AddPublishNode(&request, \"ta.filtered\", \"name\", 0);\n\n  return request;\n}\n\npb::RunExecutionPlanRequest\nEngineServiceImpl2PartiesTest::ConstructRequestForBob(\n    const std::vector<brpc::Server>& servers) {\n  pb::RunExecutionPlanRequest request;\n\n  // set graph checksum\n  auto* checker = request.mutable_graph_checksum();\n  checker->set_check_graph_checksum(true);\n  checker->mutable_sub_graph_checksums()->insert({\"0\", \"test\"});\n  checker->mutable_sub_graph_checksums()->insert({\"1\", \"test\"});\n  checker->mutable_whole_graph_checksum()->append(\"whole\");\n\n  AddSessionParameters(&request, servers, 1);\n\n  AddRunSQLNode(&request, \"tb\", \"tb.name\", 2);\n\n  AddJoinNode(&request, {\"ta.name\", \"tb.name\"}, {\"ta.index\", \"tb.index\"}, 1);\n\n  AddFilterByIndexNode(&request, \"tb.name\", \"tb.index\", \"tb.filtered\", 1);\n\n  AddPublishNode(&request, \"tb.filtered\", \"name\", 0);\n\n  return request;\n}\n\nvoid EngineServiceImpl2PartiesTest::AddSessionParameters(\n    pb::RunExecutionPlanRequest* request,\n    const std::vector<brpc::Server>& servers, const size_t& self_rank) {\n  auto* params = request->mutable_job_params();\n  params->set_job_id(\"test_session_id\");\n  params->set_party_code(\"party\" + std::to_string(self_rank));\n  for (size_t rank = 0; rank < servers.size(); rank++) {\n    auto* party = params->add_parties();\n    party->set_code(\"party\" + std::to_string(rank));\n    party->set_name(party->code());\n    party->set_host(\n        butil::endpoint2str(servers[rank].listen_address()).c_str());\n    party->set_rank(rank);\n  }\n\n  params->mutable_spu_runtime_cfg()->CopyFrom(\n      op::test::MakeSpuRuntimeConfigForTest(spu::ProtocolKind::SEMI2K)\n          .ToProto());\n}\n\nvoid EngineServiceImpl2PartiesTest::AddRunSQLNode(\n    pb::RunExecutionPlanRequest* request, const std::string& table_name,\n    const std::string& out_name, int ref_count) {\n  const std::string query = \"SELECT name FROM \" + table_name;\n  const std::vector<std::string> table_refs = {\"test.test\"};\n  op::test::ExecNodeBuilder node_builder(op::RunSQL::kOpType);\n  node_builder.SetNodeName(\"runsql-test\");\n  node_builder.AddStringAttr(op::RunSQL::kSQLAttr, query);\n  node_builder.AddStringsAttr(op::RunSQL::kTableRefsAttr, table_refs);\n  auto out = op::test::MakeTensorReference(\n      out_name, pb::PrimitiveDataType::STRING,\n      pb::TensorStatus::TENSORSTATUS_PRIVATE, ref_count);\n  node_builder.AddOutput(op::RunSQL::kOut, {out});\n  auto node = node_builder.Build();\n  auto* graph = request->mutable_graph();\n  (*(graph->mutable_nodes()))[op::RunSQL::kOpType] = node;\n  auto* pipeline = graph->mutable_policy()->add_pipelines();\n  auto* subdag = pipeline->add_subdags();\n  auto* job = subdag->add_jobs();\n  job->add_node_ids(op::RunSQL::kOpType);\n}\n\nvoid EngineServiceImpl2PartiesTest::AddJoinNode(\n    pb::RunExecutionPlanRequest* request,\n    const std::pair<std::string, std::string>& in_name,\n    const std::pair<std::string, std::string>& out_name, int ref_count) {\n  op::test::ExecNodeBuilder builder(op::Join::kOpType);\n  builder.SetNodeName(\"join-test\");\n  builder.AddInt64Attr(op::Join::kJoinTypeAttr, util::kInnerJoin);\n  builder.AddInt64Attr(op::Join::kAlgorithmAttr,\n                       static_cast<int64_t>(util::PsiAlgo::kEcdhPsi));\n  builder.AddStringsAttr(op::Join::kInputPartyCodesAttr,\n                         std::vector<std::string>{\"party0\", \"party1\"});\n  auto [in_name_left, in_name_right] = in_name;\n  auto in_left =\n      op::test::MakeTensorReference(in_name_left, pb::PrimitiveDataType::STRING,\n                                    pb::TensorStatus::TENSORSTATUS_PRIVATE);\n  auto in_right = op::test::MakeTensorReference(\n      in_name_right, pb::PrimitiveDataType::STRING,\n      pb::TensorStatus::TENSORSTATUS_PRIVATE);\n  builder.AddInput(op::Join::kInLeft, {in_left});\n  builder.AddInput(op::Join::kInRight, {in_right});\n  auto [out_name_left, out_name_right] = out_name;\n  auto join_output_left = op::test::MakeTensorReference(\n      out_name_left, pb::PrimitiveDataType::INT64,\n      pb::TensorStatus::TENSORSTATUS_PRIVATE, ref_count);\n  auto join_output_right = op::test::MakeTensorReference(\n      out_name_right, pb::PrimitiveDataType::INT64,\n      pb::TensorStatus::TENSORSTATUS_PRIVATE, ref_count);\n  builder.AddOutput(op::Join::kOutLeftJoinIndex, {join_output_left});\n  builder.AddOutput(op::Join::kOutRightJoinIndex, {join_output_right});\n\n  auto node = builder.Build();\n  auto* graph = request->mutable_graph();\n  (*(graph->mutable_nodes()))[op::Join::kOpType] = node;\n  auto* pipeline = graph->mutable_policy()->add_pipelines();\n  auto* subdag = pipeline->add_subdags();\n  auto* job = subdag->add_jobs();\n  job->add_node_ids(op::Join::kOpType);\n}\n\nvoid EngineServiceImpl2PartiesTest::AddFilterByIndexNode(\n    pb::RunExecutionPlanRequest* request, const std::string& in_name,\n    const std::string& indice_name, const std::string& out_name,\n    int ref_count) {\n  op::test::ExecNodeBuilder builder(op::FilterByIndex::kOpType);\n  builder.SetNodeName(\"filter-by-index-test\");\n  auto indice =\n      op::test::MakeTensorReference(indice_name, pb::PrimitiveDataType::INT64,\n                                    pb::TensorStatus::TENSORSTATUS_PRIVATE);\n  builder.AddInput(op::FilterByIndex::kInRowsIndexFilter, {indice});\n  auto in =\n      op::test::MakeTensorReference(in_name, pb::PrimitiveDataType::STRING,\n                                    pb::TensorStatus::TENSORSTATUS_PRIVATE);\n  builder.AddInput(op::FilterByIndex::kInData, {in});\n  auto out = op::test::MakeTensorReference(\n      out_name, pb::PrimitiveDataType::STRING,\n      pb::TensorStatus::TENSORSTATUS_PRIVATE, ref_count);\n  builder.AddOutput(op::FilterByIndex::kOut, {out});\n\n  auto node = builder.Build();\n  auto* graph = request->mutable_graph();\n  (*(graph->mutable_nodes()))[op::FilterByIndex::kOpType] = node;\n  auto* pipeline = graph->mutable_policy()->add_pipelines();\n  auto* subdag = pipeline->add_subdags();\n  auto* job = subdag->add_jobs();\n  job->add_node_ids(op::FilterByIndex::kOpType);\n}\n\nvoid EngineServiceImpl2PartiesTest::AddPublishNode(\n    pb::RunExecutionPlanRequest* request, const std::string& in_name,\n    const std::string& out_name, int ref_count) {\n  op::test::ExecNodeBuilder builder(op::Publish::kOpType);\n  builder.SetNodeName(\"publish-test\");\n  auto in =\n      op::test::MakeTensorReference(in_name, pb::PrimitiveDataType::STRING,\n                                    pb::TensorStatus::TENSORSTATUS_PRIVATE);\n  builder.AddInput(op::Publish::kIn, {in});\n\n  pb::Tensor out;\n  out.set_name(out_name);\n  out.set_elem_type(pb::PrimitiveDataType::STRING);\n  out.set_option(pb::TensorOptions::VALUE);\n  out.add_string_data(out_name);\n  builder.AddOutput(op::Publish::kOut, {out});\n\n  auto node = builder.Build();\n  auto* graph = request->mutable_graph();\n  (*(graph->mutable_nodes()))[op::Publish::kOpType] = node;\n  auto* pipeline = graph->mutable_policy()->add_pipelines();\n  auto* subdag = pipeline->add_subdags();\n  auto* job = subdag->add_jobs();\n  job->add_node_ids(op::Publish::kOpType);\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/services/error_collector_service.proto",
    "content": "//\n// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.engine.services.pb;\n\noption cc_generic_services = true;\n\nimport \"api/status.proto\";\n\nservice ErrorCollectorService {\n  // report error to peer engines\n  rpc ReportError(ReportErrorRequest) returns (ReportErrorResponse);\n}\n\nmessage ReportErrorRequest {\n  string job_id = 1;\n  string party_code = 2;\n  scql.pb.Status status = 3;\n}\n\nmessage ReportErrorResponse {\n  scql.pb.Status status = 1;\n}\n"
  },
  {
    "path": "engine/services/error_collector_service_impl.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/services/error_collector_service_impl.h\"\n\n#include \"brpc/closure_guard.h\"\n\n#include \"api/status_code.pb.h\"\n\nnamespace scql::engine {\n\nvoid ErrorCollectorServiceImpl::ReportError(\n    ::google::protobuf::RpcController* cntl,\n    const services::pb::ReportErrorRequest* request,\n    services::pb::ReportErrorResponse* response,\n    ::google::protobuf::Closure* done) {\n  brpc::ClosureGuard done_guard(done);\n  try {\n    const std::string& job_id = request->job_id();\n    Session* session = session_manager_->GetSession(job_id);\n    if (session == nullptr) {\n      response->mutable_status()->set_code(pb::Code::SESSION_NOT_FOUND);\n      response->mutable_status()->set_message(\n          fmt::format(\"no session for job_id={}\", job_id));\n      return;\n    }\n\n    session->StorePeerError(request->party_code(), request->status());\n\n    response->mutable_status()->set_code(pb::Code::OK);\n    return;\n  } catch (const std::exception& e) {\n    response->mutable_status()->set_code(pb::Code::UNKNOWN_ENGINE_ERROR);\n    response->mutable_status()->set_message(fmt::format(\n        \"internal error, job_id={}, error={}\", request->job_id(), e.what()));\n    return;\n  }\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/services/error_collector_service_impl.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/session_manager.h\"\n\n#include \"engine/services/error_collector_service.pb.h\"\n\nnamespace scql::engine {\n\nclass ErrorCollectorServiceImpl : public services::pb::ErrorCollectorService {\n public:\n  explicit ErrorCollectorServiceImpl(SessionManager* session_manager)\n      : session_manager_(session_manager) {}\n\n  void ReportError(::google::protobuf::RpcController* cntl,\n                   const services::pb::ReportErrorRequest* request,\n                   services::pb::ReportErrorResponse* response,\n                   ::google::protobuf::Closure* done) override;\n\n private:\n  SessionManager* session_manager_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/services/mock_report_service.proto",
    "content": "//\n// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.engine.services.pb;\n\noption cc_generic_services = true;\n\nimport \"api/engine.proto\";\n\n// Multiplexing Receiver Service\nservice MockReportService {\n  // push the data to receiver's local database.\n  rpc Report(scql.pb.ReportRequest) returns (MockResponse);\n}\n\nmessage MockResponse {\n  string response = 1;\n}"
  },
  {
    "path": "engine/services/pipeline.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/services/pipeline.h\"\n\n#include <algorithm>\n#include <memory>\n\n#include \"yacl/base/exception.h\"\n\n#include \"engine/core/tensor_batch_reader.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/core/tensor_slice.h\"\n#include \"engine/core/type.h\"\n#include \"engine/util/filepath_helper.h\"\n\nnamespace scql::engine {\n\nsize_t GetMaxSliceNum(const std::shared_ptr<yacl::link::Context>& link,\n                      size_t self_slice_num) {\n  const auto* tag = \"get_peer_slice_num\";\n  auto num_bufs = yacl::link::AllGather(\n      link, yacl::ByteContainerView(&self_slice_num, sizeof(size_t)), tag);\n  size_t max_slice_num = 0;\n  for (const auto& o : num_bufs) {\n    max_slice_num = std::max(o.data<size_t>()[0], max_slice_num);\n  }\n  return max_slice_num;\n}\n\nPipelineExecutor::PipelineExecutor(const pb::Pipeline& pipeline,\n                                   Session* session)\n    : session_(session),\n      first_batch_(true),\n      batched_(pipeline.batched()),\n      batch_num_(1) {\n  if (!batched_) {\n    return;\n  }\n  for (int i = 0; i < pipeline.inputs().size(); i++) {\n    const auto& pb_tensor = pipeline.inputs()[i];\n    auto tensor = session->GetTensorTable()->GetTensor(pb_tensor.name());\n    YACL_ENFORCE(tensor != nullptr, \"failed to get input tensor: {}\",\n                 pb_tensor.name());\n    input_tensors_.push_back(tensor);\n    auto slicer = CreateTensorSlice(tensor);\n    if (i != 0 && slicer->GetSliceNum() != batch_num_) {\n      YACL_THROW(\"input tensors has different batch num {}:{}\", batch_num_,\n                 slicer->GetSliceNum());\n    }\n    batch_num_ = slicer->GetSliceNum();\n    if (slicer->GetSliceNum() == 1) {\n      continue;\n    }\n    tensor_readers_.push_back(CreateTensorSlice(tensor));\n    input_tensor_names_.push_back(pb_tensor.name());\n  }\n  batch_num_ = GetMaxSliceNum(session_->GetLink(), batch_num_);\n  if (batch_num_ == 1) {\n    batched_ = false;\n    return;\n  }\n  for (const auto& pb_tensor : pipeline.outputs()) {\n    output_tensor_names_.push_back(pb_tensor.name());\n  }\n}\n\nvoid PipelineExecutor::UpdateTensorTable() {\n  if (!batched_) {\n    return;\n  }\n  // insert batched tensor into tensor table\n  for (size_t i = 0; i < input_tensors_.size(); i++) {\n    auto batched_tensor = tensor_readers_[i]->Next();\n    YACL_ENFORCE(batched_tensor != nullptr);\n    session_->GetTensorTable()->AddOrUpdateTensor(input_tensor_names_[i],\n                                                  batched_tensor);\n  }\n}\n\nvoid PipelineExecutor::FetchOutputTensors() {\n  if (!batched_) {\n    return;\n  }\n  for (size_t i = 0; i < output_tensor_names_.size(); i++) {\n    auto tensor =\n        session_->GetTensorTable()->GetTensor(output_tensor_names_[i]);\n    YACL_ENFORCE(tensor != nullptr,\n                 \"failed to get output tensor: {}\" + output_tensor_names_[i]);\n    // remove tensor to avoid error that tensor already exits\n    session_->GetTensorTable()->RemoveTensor(output_tensor_names_[i]);\n    if (first_batch_) {\n      output_writers_.push_back(std::make_shared<TensorWriter>(\n          output_tensor_names_[i], ToArrowDataType(tensor->Type()),\n          util::CreateDirWithRandSuffix(\n              session_->GetStreamingOptions().dump_file_dir,\n              output_tensor_names_[i])));\n    }\n    output_writers_[i]->WriteBatch(*tensor->ToArrowChunkedArray());\n  }\n  if (first_batch_) {\n    first_batch_ = false;\n  }\n}\n\nvoid PipelineExecutor::Finish() {\n  if (!batched_) {\n    return;\n  }\n  for (size_t i = 0; i < output_writers_.size(); i++) {\n    TensorPtr tensor;\n    output_writers_[i]->Finish(&tensor);\n    session_->GetTensorTable()->AddTensor(output_tensor_names_[i], tensor);\n  }\n  // put input tensors back to tensor table if need\n  for (size_t i = 0; i < input_tensor_names_.size(); i++) {\n    // if tensor removed by tensor table, don't put it back\n    if (session_->GetTensorTable()->GetTensor(input_tensor_names_[i]) !=\n        nullptr) {\n      session_->GetTensorTable()->AddOrUpdateTensor(input_tensor_names_[i],\n                                                    input_tensors_[i]);\n    }\n  }\n}\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/services/pipeline.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/framework/session.h\"\n\n#include \"api/subgraph.pb.h\"\n\nnamespace scql::engine {\n\nclass TensorSlice;\n\nclass PipelineExecutor {\n public:\n  PipelineExecutor(const pb::Pipeline& pipeline, Session* session);\n\n  void UpdateTensorTable();\n\n  void FetchOutputTensors();\n\n  size_t GetBatchNum() const { return batch_num_; }\n\n  void Finish();\n\n private:\n  std::vector<TensorPtr> input_tensors_;\n  std::vector<std::shared_ptr<TensorWriter>> output_writers_;\n  std::vector<std::string> input_tensor_names_;\n  std::vector<std::string> output_tensor_names_;\n  std::vector<std::shared_ptr<TensorSlice>> tensor_readers_;\n  Session* session_;\n  bool first_batch_;\n  bool batched_;\n  size_t batch_num_;\n};\n}  // namespace scql::engine"
  },
  {
    "path": "engine/services/prometheus_service.proto",
    "content": "//\n// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nsyntax = \"proto3\";\n\npackage scql.engine.services.pb;\n\noption cc_generic_services = true;\n\nmessage MetricsRequest {}\nmessage MetricsResponse {}\n\nservice metrics {\n  rpc default_method(MetricsRequest) returns (MetricsResponse);\n}\n"
  },
  {
    "path": "engine/services/prometheus_service_impl.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/services/prometheus_service_impl.h\"\n\n#include <brpc/closure_guard.h>\n#include <brpc/controller.h>\n#include <prometheus/serializer.h>\n#include <prometheus/text_serializer.h>\n\n#include \"brpc/builtin/prometheus_metrics_service.h\"\n#include \"butil/iobuf.h\"\n\nnamespace scql::engine {\n\nvoid MetricsService::default_method(\n    ::google::protobuf::RpcController* cntl_base,\n    const services::pb::MetricsRequest* request,\n    services::pb::MetricsResponse* response,\n    ::google::protobuf::Closure* done) {\n  brpc::ClosureGuard done_guard(done);\n  brpc::Controller* cntl = static_cast<brpc::Controller*>(cntl_base);\n\n  if (cntl->http_request().unresolved_path() != \"\") {\n    cntl->SetFailed(brpc::ENOMETHOD, \"404 page not found\");\n    return;\n  }\n\n  // collect metrics from all collectables\n  auto collected_metrics = std::vector<::prometheus::MetricFamily>{};\n  for (auto* collectable : collectables_) {\n    if (collectable == nullptr) {\n      continue;\n    }\n\n    auto&& metrics = collectable->Collect();\n    collected_metrics.insert(collected_metrics.end(),\n                             std::make_move_iterator(metrics.begin()),\n                             std::make_move_iterator(metrics.end()));\n  }\n\n  // write response\n  cntl->http_response().set_content_type(\"text/plain\");\n  {\n    butil::IOBufBuilder body;\n    auto serializer = std::unique_ptr<::prometheus::Serializer>{\n        new ::prometheus::TextSerializer()};\n    serializer->Serialize(body, collected_metrics);\n    body.move_to(cntl->response_attachment());\n  }\n  {\n    butil::IOBuf brpc_metrics_body;\n    // dump brpc metrics\n    if (brpc::DumpPrometheusMetricsToIOBuf(&brpc_metrics_body) < 0) {\n      cntl->SetFailed(\"Fail to dump brpc metrics\");\n      return;\n    }\n    cntl->response_attachment().append(brpc_metrics_body);\n  }\n}\n\nvoid MetricsService::RegisterCollectable(prometheus::Collectable* collectable) {\n  collectables_.push_back(collectable);\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/services/prometheus_service_impl.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <prometheus/registry.h>\n\n#include \"engine/services/prometheus_service.pb.h\"\n\nnamespace scql::engine {\n\nclass MetricsService : public services::pb::metrics {\n public:\n  MetricsService() = default;\n\n  virtual ~MetricsService() = default;\n\n  void default_method(::google::protobuf::RpcController* cntl_base,\n                      const services::pb::MetricsRequest* request,\n                      services::pb::MetricsResponse* response,\n                      ::google::protobuf::Closure* done) override;\n\n  void RegisterCollectable(prometheus::Collectable* collectable);\n\n private:\n  std::vector<prometheus::MetricFamily> CollectMetrics() const;\n\n private:\n  std::vector<prometheus::Collectable*> collectables_;\n};\n\n}  // namespace scql::engine"
  },
  {
    "path": "engine/services/run_plan_core.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/services/run_plan_core.h\"\n\n#include <chrono>\n\n#include \"engine/framework/exec.h\"\n#include \"engine/framework/executor.h\"\n#include \"engine/framework/session.h\"\n#include \"engine/services/pipeline.h\"\n#include \"engine/util/logging.h\"\n#include \"engine/util/trace_categories.h\"\n\n#include \"api/status_code.pb.h\"\n\nnamespace scql::engine {\n\nvoid RunPlanCore(const pb::RunExecutionPlanRequest& request, Session* session,\n                 pb::RunExecutionPlanResponse* response) {\n  TRACE_EVENT_DEFAULT_TRACK(RPCCALL_CATEGORY, \"RunPlanCore\");\n  auto logger = ActiveLogger(session);\n  const auto& graph = request.graph();\n  const auto& policy = graph.policy();\n  session->InitProgressStats(policy);\n  if (policy.pipelines().size() > 1) {\n    session->EnableStreamingBatched();\n  }\n  for (int pipe_index = 0; pipe_index < policy.pipelines().size();\n       pipe_index++) {\n    const auto& pipeline = policy.pipelines()[pipe_index];\n    PipelineExecutor pipe_executor(pipeline, session);\n    session->GetProgressStats()->SetBatchCntInPipeline(\n        pipe_executor.GetBatchNum());\n    TRACE_EVENT_DEFAULT_TRACK(\n        OPERATOR_CATEGORY,\n        ::perfetto::DynamicString(fmt::format(\"Run Pipeline: {}\", pipe_index)),\n        \"total batch num\", pipe_executor.GetBatchNum());\n    for (size_t i = 0; i < pipe_executor.GetBatchNum(); i++) {\n      TRACE_EVENT_DEFAULT_TRACK(\n          OPERATOR_CATEGORY,\n          ::perfetto::DynamicString(fmt::format(\"Run Batch: {}\", i)));\n      SPDLOG_LOGGER_INFO(logger,\n                         \"session({}) start to execute pipeline({}) batch({})\",\n                         session->Id(), pipe_index, i);\n      pipe_executor.UpdateTensorTable();\n      for (const auto& subdag : pipeline.subdags()) {\n        for (const auto& job : subdag.jobs()) {\n          const auto& node_ids = job.node_ids();\n          for (const auto& node_id : node_ids) {\n            const auto& iter = graph.nodes().find(node_id);\n            YACL_ENFORCE(iter != graph.nodes().cend(),\n                         \"no node for node_id={} in node_ids\", node_id);\n            const auto& node = iter->second;\n            TRACE_EVENT_DEFAULT_TRACK(OPERATOR_CATEGORY,\n                                      ::perfetto::DynamicString(fmt::format(\n                                          \"Run Node: node({}) op({})\",\n                                          node.node_name(), node.op_type())));\n            SPDLOG_LOGGER_INFO(logger,\n                               \"session({}) start to execute node({}) op({}) \"\n                               \"pipeline({}) batch({})\",\n                               session->Id(), node.node_name(), node.op_type(),\n                               pipe_index, i);\n            auto start = std::chrono::system_clock::now();\n            session->GetProgressStats()->SetCurrentNodeInfo(start,\n                                                            node.node_name());\n\n            YACL_ENFORCE(session->GetState() == SessionState::RUNNING,\n                         \"session status not equal to running\");\n            ExecContext context(node, session);\n            Executor executor;\n            executor.RunExecNode(&context);\n\n            auto end = std::chrono::system_clock::now();\n            SPDLOG_LOGGER_INFO(\n                logger,\n                \"session({}) finished executing node({}), op({}), cost({})ms\",\n                session->Id(), node.node_name(), node.op_type(),\n                std::chrono::duration_cast<std::chrono::milliseconds>(end -\n                                                                      start)\n                    .count());\n            // TODO(xiaoyuan): fix progress in streaming mode later\n            session->GetProgressStats()->IncExecutedNodes();\n            if (!session->GetStreamingOptions().batched) {\n              YACL_ENFORCE(session->GetProgressStats()->GetExecutedNodes() <=\n                               session->GetProgressStats()->GetNodesCnt(),\n                           \"executed nodes: {}, total nodes count: {}\",\n                           session->GetProgressStats()->GetExecutedNodes(),\n                           session->GetProgressStats()->GetNodesCnt());\n            }\n            if (node.op_type() == \"Publish\") {\n              auto results = session->GetPublishResults();\n              for (const auto& result : results) {\n                pb::Tensor* out_column = response->add_out_columns();\n                out_column->CopyFrom(*result);\n              }\n            } else if (node.op_type() == \"DumpFile\" ||\n                       node.op_type() == \"InsertTable\") {\n              auto affected_rows = session->GetAffectedRows();\n              response->set_num_rows_affected(affected_rows);\n            }\n            COMMUNICATION_COUNTER(session->GetLinkStats());\n          }\n        }\n        if (subdag.need_call_barrier_after_jobs()) {\n          yacl::link::Barrier(session->GetLink(), session->Id());\n        }\n      }\n      pipe_executor.FetchOutputTensors();\n      session->GetProgressStats()->IncExecutedBatch();\n      SPDLOG_LOGGER_INFO(\n          logger, \"session({}) finished executing pipeline({}) batch({})\",\n          session->Id(), pipe_index, i);\n    }\n    pipe_executor.Finish();\n    session->GetProgressStats()->IncExecutedPipeline();\n  }\n  SPDLOG_LOGGER_INFO(logger, \"session({}) run plan policy succ\", session->Id());\n  response->mutable_status()->set_code(::scql::pb::Code::OK);\n}\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/services/run_plan_core.h",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"engine/framework/session.h\"\n\n#include \"api/engine.pb.h\"\n\nnamespace scql::engine {\n\nvoid RunPlanCore(const pb::RunExecutionPlanRequest& request, Session* session,\n                 pb::RunExecutionPlanResponse* response);\n\n}  // namespace scql::engine\n"
  },
  {
    "path": "engine/util/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"@rules_cc//cc:defs.bzl\", \"cc_proto_library\")\nload(\"@rules_go//proto:def.bzl\", \"go_proto_library\")\nload(\"@rules_proto//proto:defs.bzl\", \"proto_library\")\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncc_library(\n    name = \"copy_to_proto_vistor\",\n    hdrs = [\"copy_to_proto_vistor.h\"],\n    deps = [\n        \"@org_apache_arrow//:arrow\",\n    ],\n)\n\ncc_library(\n    name = \"logging\",\n    srcs = [\"logging.cc\"],\n    hdrs = [\"logging.h\"],\n    deps = [\n        \"@brpc//:butil\",\n        \"@spdlog\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"prometheus_monitor\",\n    srcs = [\"prometheus_monitor.cc\"],\n    hdrs = [\"prometheus_monitor.h\"],\n    deps = [\n        \"@prometheus-cpp//core\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"tensor_util\",\n    srcs = [\"tensor_util.cc\"],\n    hdrs = [\"tensor_util.h\"],\n    deps = [\n        \":copy_to_proto_vistor\",\n        \"//engine/core:arrow_helper\",\n        \"//engine/core:tensor\",\n        \"//engine/util:spu_io\",\n        \"//engine/util:time_util\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"stringifier\",\n    srcs = [\"stringifier.cc\"],\n    hdrs = [\"stringifier.h\"],\n    deps = [\n        \"//engine/core:arrow_helper\",\n        \"//engine/core:tensor\",\n        \"//engine/core:tensor_constructor\",\n    ],\n)\n\nscql_cc_test(\n    name = \"stringifier_test\",\n    srcs = [\"stringifier_test.cc\"],\n    deps = [\n        \":stringifier\",\n    ],\n)\n\ncc_library(\n    name = \"spu_io\",\n    srcs = [\"spu_io.cc\"],\n    hdrs = [\"spu_io.h\"],\n    deps = [\n        \":ndarray_to_arrow\",\n        \":prefix_sum\",\n        \"//engine/core:arrow_helper\",\n        \"//engine/core:tensor\",\n        \"//engine/core:tensor_constructor\",\n        \"//engine/core:type\",\n        \"@org_apache_arrow//:arrow\",\n        \"@spulib//libspu/core:xt_helper\",\n        \"@spulib//libspu/device:io\",\n        \"@spulib//libspu/kernel/hal:constants\",\n        \"@spulib//libspu/kernel/hal:public_helper\",\n        \"@spulib//libspu/kernel/hlo:basic_binary\",\n        \"@spulib//libspu/kernel/hlo:casting\",\n        \"@spulib//libspu/kernel/hlo:geometrical\",\n    ],\n)\n\ncc_library(\n    name = \"ndarray_to_arrow\",\n    srcs = [\"ndarray_to_arrow.cc\"],\n    hdrs = [\"ndarray_to_arrow.h\"],\n    deps = [\n        \"//engine/core:arrow_helper\",\n        \"//engine/core:type\",\n        \"@org_apache_arrow//:arrow\",\n        \"@spulib//libspu/core:ndarray_ref\",\n        \"@spulib//libspu/core:xt_helper\",\n    ],\n)\n\ncc_library(\n    name = \"filepath_helper\",\n    srcs = [\"filepath_helper.cc\"],\n    hdrs = [\"filepath_helper.h\"],\n    deps = [\n        \"@abseil-cpp//absl/strings\",\n        \"@boost.uuid\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"time_util\",\n    srcs = [\"time_util.cc\"],\n    hdrs = [\"time_util.h\"],\n    deps = [\n        \"//engine/core:primitive_builder\",\n        \"//engine/core:tensor\",\n        \"//engine/core:tensor_constructor\",\n        \"@org_apache_arrow//:arrow\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\nscql_cc_test(\n    name = \"filepath_helper_test\",\n    srcs = [\"filepath_helper_test.cc\"],\n    linkopts = [\n        \"-lm\",\n    ],\n    deps = [\n        \":filepath_helper\",\n    ],\n)\n\ncc_library(\n    name = \"table_util\",\n    srcs = [\"table_util.cc\"],\n    hdrs = [\"table_util.h\"],\n    deps = [\n        \"//engine/framework:exec\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\ncc_library(\n    name = \"communicate_helper\",\n    hdrs = [\"communicate_helper.h\"],\n    deps = [\n        \"//engine/util:spu_io\",\n        \"@msgpack-c//:msgpack\",\n    ],\n)\n\ncc_library(\n    name = \"context_util\",\n    srcs = [\"context_util.cc\"],\n    hdrs = [\"context_util.h\"],\n    deps = [\n        \":tensor_util\",\n        \"//engine/framework:exec\",\n        \"//engine/util:spu_io\",\n    ],\n)\n\ncc_library(\n    name = \"prefix_sum\",\n    srcs = [\"prefix_sum.cc\"],\n    hdrs = [\"prefix_sum.h\"],\n    deps = [\n        \"@spulib//libspu/kernel/hlo:indexing\",\n    ],\n)\n\ncc_library(\n    name = \"progress_util\",\n    hdrs = [\"progress_util.h\"],\n    deps = [\n        \"@fmt\",\n    ],\n)\n\ncc_library(\n    name = \"concurrent_queue\",\n    hdrs = [\"concurrent_queue.h\"],\n)\n\ncc_library(\n    name = \"datamesh_helper\",\n    srcs = [\"datamesh_helper.cc\"],\n    hdrs = [\"datamesh_helper.h\"],\n    deps = [\n        \"@grpc//:grpc++\",\n        \"@kuscia//proto/api/v1alpha1/datamesh:domaindata_cpp_grpc\",\n        \"@kuscia//proto/api/v1alpha1/datamesh:domaindatasource_cpp_grpc\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\nscql_cc_test(\n    name = \"datamesh_helper_test\",\n    srcs = [\"datamesh_helper_test.cc\"],\n    linkopts = [\n        \"-lm\",\n    ],\n    deps = [\n        \":datamesh_helper\",\n        \"@grpc//:grpc++\",\n    ],\n)\n\ncc_library(\n    name = \"ssl_helper\",\n    srcs = [\"ssl_helper.cc\"],\n    hdrs = [\"ssl_helper.h\"],\n    deps = [\n        \"@brpc//:butil\",\n        \"@grpc//:grpc++\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\nscql_cc_test(\n    name = \"ssl_helper_test\",\n    srcs = [\"ssl_helper_test.cc\"],\n    linkopts = [\n        \"-lm\",\n    ],\n    deps = [\n        \":ssl_helper\",\n    ],\n)\n\ncc_library(\n    name = \"upload_info_helper\",\n    srcs = [\"upload_info_helper.cc\"],\n    hdrs = [\"upload_info_helper.h\"],\n    deps = [\n        \"@dataproxy_sdk_cc//dataproxy_sdk:data_proxy_stream\",\n        \"@dataproxy_sdk_cc//proto:data_proxy_cc_proto\",\n        \"@org_apache_arrow//:arrow\",\n    ],\n)\n\nscql_cc_test(\n    name = \"upload_info_helper_test\",\n    srcs = [\"upload_info_helper_test.cc\"],\n    linkopts = [\n        \"-lm\",\n    ],\n    deps = [\n        \":upload_info_helper\",\n    ],\n)\n\ncc_library(\n    name = \"trace_categories\",\n    srcs = [\"trace_categories.cc\"],\n    hdrs = [\"trace_categories.h\"],\n    deps = [\n        \"@perfetto\",\n        \"@spdlog\",\n    ],\n)\n\ncc_library(\n    name = \"kpad_task_helper\",\n    srcs = [\"kpad_task_helper.cc\"],\n    hdrs = [\"kpad_task_helper.h\"],\n    deps = [\n        \"//api:engine_cc_proto\",\n        \"//api:scql_task_cc_proto\",\n        \"@brpc//:butil\",\n        \"@com_google_protobuf//:json_util\",\n        \"@spdlog\",\n        \"@spulib//libspu/core:config\",\n        \"@yacl//yacl/base:exception\",\n    ],\n)\n\nscql_cc_test(\n    name = \"kpad_task_helper_test\",\n    srcs = [\"kpad_task_helper_test.cc\"],\n    linkopts = [\n        \"-lm\",\n    ],\n    deps = [\n        \":kpad_task_helper\",\n    ],\n)\n"
  },
  {
    "path": "engine/util/communicate_helper.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <cstddef>\n#include <cstdint>\n#include <utility>\n#include <vector>\n\n#include \"msgpack.hpp\"\n#include \"yacl/link/context.h\"\n\nnamespace scql::engine::util {\n\nstatic constexpr size_t kMsgpackBatchSize = 1000 * 1000;\nstatic constexpr char kCountSuffix[] = \"count info\";\nstatic constexpr char kBatchSuffix[] = \"batch\";\n\ntemplate <typename T>\nvoid SendMassiveMsgpack(const std::shared_ptr<yacl::link::Context>& lctx,\n                        const std::string& tag, int64_t peer_rank,\n                        const std::vector<T>& data) {\n  // send total count and batch count\n  size_t batch_count =\n      (data.size() + kMsgpackBatchSize - 1) / kMsgpackBatchSize;\n  msgpack::sbuffer count_buf;\n  msgpack::pack(count_buf, std::make_pair(data.size(), batch_count));\n  auto count_tag = fmt::format(\"{} {}\", tag, kCountSuffix);\n\n  lctx->Send(peer_rank,\n             yacl::ByteContainerView(count_buf.data(), count_buf.size()),\n             count_tag);\n\n  for (size_t batch_idx = 0; batch_idx < batch_count; ++batch_idx) {\n    auto start = batch_idx * kMsgpackBatchSize;\n    auto end = std::min((batch_idx + 1) * kMsgpackBatchSize, data.size());\n    auto sub_vec = std::vector<T>(data.begin() + start, data.begin() + end);\n    msgpack::sbuffer buf;\n    msgpack::pack(buf, sub_vec);\n    auto sub_tag = fmt::format(\"{} {} {}\", tag, kBatchSuffix, batch_idx);\n    lctx->Send(peer_rank, yacl::ByteContainerView(buf.data(), buf.size()),\n               sub_tag);\n  }\n}\n\ntemplate <typename T>\nstd::vector<T> RecvMassiveMsgpack(\n    const std::shared_ptr<yacl::link::Context>& lctx, const std::string& tag,\n    int64_t peer_rank) {\n  auto count_tag = fmt::format(\"{} {}\", tag, kCountSuffix);\n  auto count_buf = lctx->Recv(peer_rank, count_tag);\n  auto oh =\n      msgpack::unpack(static_cast<char*>(count_buf.data()), count_buf.size());\n  std::pair<size_t, size_t> count_info;\n  oh.get().convert(count_info);\n\n  const size_t& total_count = count_info.first;\n  const size_t& batch_count = count_info.second;\n  std::vector<T> ret;\n  ret.reserve(total_count);\n  for (size_t batch_idx = 0; batch_idx < batch_count; ++batch_idx) {\n    auto sub_tag = fmt::format(\"{} {} {}\", tag, kBatchSuffix, batch_idx);\n    auto sub_buf = lctx->Recv(peer_rank, sub_tag);\n    auto oh =\n        msgpack::unpack(static_cast<char*>(sub_buf.data()), sub_buf.size());\n    std::vector<T> sub_vec;\n    oh.get().convert(sub_vec);\n    ret.insert(ret.end(), sub_vec.begin(), sub_vec.end());\n  }\n  return ret;\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/concurrent_queue.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <atomic>\n#include <chrono>\n#include <condition_variable>\n#include <cstdint>\n#include <mutex>\n#include <optional>\n#include <queue>\n#include <utility>\n\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine::util {\ntemplate <typename T>\nclass SimpleChannel {\n public:\n  explicit SimpleChannel(size_t capacity) : capacity_(capacity) {}\n  SimpleChannel(size_t capacity, int32_t queue_max_block_seconds)\n      : capacity_(capacity),\n        queue_max_block_seconds_(queue_max_block_seconds) {}\n  ~SimpleChannel() {}\n\n  void Push(T& item) {\n    {\n      std::unique_lock<std::mutex> lock(mutex_);\n      if (closed_) {\n        cond_.notify_all();\n        YACL_THROW(\"send data to a closed queue\");\n      }\n      while (queue_.size() >= capacity_) {\n        auto ok =\n            cond_.wait_for(lock, std::chrono::seconds(queue_max_block_seconds_),\n                           [&] { return queue_.size() < capacity_; });\n        YACL_ENFORCE(ok, \"queue wait timeout\");\n      }\n      queue_.push(item);\n    }\n    cond_.notify_all();\n  }\n\n  void Push(T&& item) {\n    {\n      std::unique_lock<std::mutex> lock(mutex_);\n      if (closed_) {\n        cond_.notify_all();\n        YACL_THROW(\"send data to a closed queue\");\n      }\n      while (queue_.size() >= capacity_) {\n        auto ok =\n            cond_.wait_for(lock, std::chrono::seconds(queue_max_block_seconds_),\n                           [&] { return queue_.size() < capacity_; });\n        YACL_ENFORCE(ok, \"queue wait timeout\");\n      }\n      queue_.push(std::forward<T>(item));\n    }\n\n    cond_.notify_all();\n  }\n\n  std::optional<T> Pop() {\n    T item;\n    {\n      std::unique_lock<std::mutex> lock(mutex_);\n      while (queue_.empty() && !closed_) {\n        auto ok =\n            cond_.wait_for(lock, std::chrono::seconds(queue_max_block_seconds_),\n                           [&] { return !queue_.empty() || closed_; });\n        YACL_ENFORCE(ok, \"queue wait timeout\");\n      }\n      // return empty item if queue is closed and queue is empty\n      if (closed_ && queue_.empty()) {\n        return std::nullopt;\n      }\n      item = queue_.front();\n      queue_.pop();\n    }\n    cond_.notify_all();\n    return item;\n  }\n\n  // close queue, if a queue is empty, all Pop() will return empty item.\n  void Close() {\n    if (closed_) {\n      YACL_THROW(\"close a closed queue\");\n    }\n    std::unique_lock<std::mutex> lock(mutex_);\n    closed_ = true;\n    cond_.notify_all();\n  }\n  bool IsClosed() { return closed_; }\n\n private:\n  std::atomic_bool closed_{false};\n  std::mutex mutex_;\n  std::condition_variable cond_;\n  size_t capacity_;\n  std::queue<T> queue_;\n  // default wait 60 seconds\n  int32_t queue_max_block_seconds_{60};\n};\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/context_util.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/context_util.h\"\n\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/tensor_util.h\"\n\nnamespace scql::engine::util {\nTensorPtr GetPrivateOrPublicTensor(scql::engine::ExecContext* ctx,\n                                   const pb::Tensor& t) {\n  TensorPtr ret;\n  if (util::IsTensorStatusMatched(t, pb::TENSORSTATUS_PUBLIC)) {\n    // read public tensor from spu device symbol table\n    auto spu_io = util::SpuOutfeedHelper(ctx->GetSession()->GetSpuContext(),\n                                         ctx->GetSession()->GetDeviceSymbols());\n    ret = spu_io.DumpPublic(t.name());\n\n    if (t.elem_type() == pb::PrimitiveDataType::STRING) {\n      ret = ctx->GetSession()->HashToString(*ret);\n    }\n  } else {\n    ret = ctx->GetTensorTable()->GetTensor(t.name());\n  }\n  return ret;\n}\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/context_util.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n#include \"engine/core/tensor.h\"\n#include \"engine/framework/exec.h\"\n\nnamespace scql::engine::util {\nTensorPtr GetPrivateOrPublicTensor(ExecContext* ctx, const pb::Tensor& t);\n}\n"
  },
  {
    "path": "engine/util/copy_to_proto_vistor.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"arrow/array.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"api/core.pb.h\"\n\nnamespace scql::engine::util {\n\n/// @brief CopyToProtoVistor only copy array's value to pb::Tensor.\nclass CopyToProtoVistor {\n public:\n  CopyToProtoVistor() = delete;\n\n  explicit CopyToProtoVistor(pb::Tensor* to_tensor, bool contain_null)\n      : to_proto_(to_tensor), contain_null_(contain_null) {\n    YACL_ENFORCE(to_proto_, \"to_proto_ can not be null.\");\n  }\n\n  template <typename T>\n  arrow::Status Visit(const T& array) {\n    return arrow::Status::NotImplemented(\n        fmt::format(\"type {} is not implemented in CopyToProtoVistor\",\n                    array.type()->name()));\n  }\n\n  arrow::Status Visit(const arrow::LargeStringArray& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      to_proto_->add_string_data(array.GetString(i));\n      SetValidityIfNeeded(array.IsValid(i));\n    }\n    return arrow::Status::OK();\n  }\n\n  arrow::Status Visit(const arrow::BooleanArray& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      to_proto_->add_bool_data(array.GetView(i));\n      SetValidityIfNeeded(array.IsValid(i));\n    }\n    return arrow::Status::OK();\n  }\n\n  arrow::Status Visit(const arrow::NumericArray<arrow::FloatType>& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      to_proto_->add_float_data(array.GetView(i));\n      SetValidityIfNeeded(array.IsValid(i));\n    }\n    return arrow::Status::OK();\n  }\n\n  arrow::Status Visit(const arrow::NumericArray<arrow::DoubleType>& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      to_proto_->add_double_data(array.GetView(i));\n      SetValidityIfNeeded(array.IsValid(i));\n    }\n    return arrow::Status::OK();\n  }\n\n  arrow::Status Visit(const arrow::NumericArray<arrow::Int32Type>& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      to_proto_->add_int32_data(array.GetView(i));\n      SetValidityIfNeeded(array.IsValid(i));\n    }\n    return arrow::Status::OK();\n  }\n\n  // store uint32 to int64\n  arrow::Status Visit(const arrow::NumericArray<arrow::UInt32Type>& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      to_proto_->add_int64_data(array.GetView(i));\n      SetValidityIfNeeded(array.IsValid(i));\n    }\n    return arrow::Status::OK();\n  }\n\n  arrow::Status Visit(const arrow::NumericArray<arrow::Int64Type>& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      to_proto_->add_int64_data(array.GetView(i));\n      SetValidityIfNeeded(array.IsValid(i));\n    }\n    return arrow::Status::OK();\n  }\n\n  // NOTE: cast uint64 to int64\n  arrow::Status Visit(const arrow::NumericArray<arrow::UInt64Type>& array) {\n    for (int64_t i = 0; i < array.length(); i++) {\n      if (array.GetView(i) > INT64_MAX) {\n        return arrow::Status::Invalid(\n            fmt::format(\"overflow while casting uint64 to int64, number#{}={}\",\n                        i, array.GetView(i)));\n      }\n      to_proto_->add_int64_data(array.GetView(i));\n      SetValidityIfNeeded(array.IsValid(i));\n    }\n    return arrow::Status::OK();\n  }\n\n private:\n  void SetValidityIfNeeded(bool valid) {\n    if (contain_null_) {\n      to_proto_->add_data_validity(valid);\n    }\n  }\n\n private:\n  pb::Tensor* to_proto_;\n  bool contain_null_;\n};\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/datamesh_helper.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/datamesh_helper.h\"\n\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine::util {\n\ndm::DomainData QueryDomainData(std::shared_ptr<grpc::Channel> channel,\n                               const std::string& domain_data_id) {\n  dm::DomainDataService::Stub stub(channel);\n  grpc::ClientContext context;\n\n  dm::QueryDomainDataRequest request;\n  request.set_domaindata_id(domain_data_id);\n\n  dm::QueryDomainDataResponse resp;\n  auto status = stub.QueryDomainData(&context, request, &resp);\n  if (!status.ok()) {\n    YACL_THROW(\"issue grpc QueryDomainData failed, error_code={}, error_msg={}\",\n               fmt::underlying(status.error_code()), status.error_message());\n  }\n\n  if (resp.status().code() != 0) {\n    YACL_THROW(\"QueryDomainData returns error: code={}, msg={}\",\n               resp.status().code(), resp.status().message());\n  }\n\n  return resp.data();\n}\n\ndm::DomainDataSource QueryDomainDataSource(\n    std::shared_ptr<grpc::Channel> channel, const std::string& datasource_id) {\n  dm::DomainDataSourceService::Stub stub(channel);\n\n  grpc::ClientContext context;\n\n  dm::QueryDomainDataSourceRequest request;\n  request.set_datasource_id(datasource_id);\n\n  dm::QueryDomainDataSourceResponse resp;\n  auto status = stub.QueryDomainDataSource(&context, request, &resp);\n  if (!status.ok()) {\n    YACL_THROW(\n        \"issue grpc QueryDomainDataSource failed, error_code={}, error_msg={}\",\n        fmt::underlying(status.error_code()), status.error_message());\n  }\n  if (resp.status().code() != 0) {\n    YACL_THROW(\"QueryDomainDataSource returns error: code={}, msg={}\",\n               resp.status().code(), resp.status().message());\n  }\n\n  return resp.data();\n}\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/datamesh_helper.h",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"grpcpp/grpcpp.h\"\n\n#include \"kuscia/proto/api/v1alpha1/datamesh/domaindata.grpc.pb.h\"\n#include \"kuscia/proto/api/v1alpha1/datamesh/domaindatasource.grpc.pb.h\"\n\nnamespace scql::engine::util {\n\nnamespace dm = kuscia::proto::api::v1alpha1::datamesh;\n\ndm::DomainData QueryDomainData(std::shared_ptr<grpc::Channel> channel,\n                               const std::string& domain_data_id);\n\ndm::DomainDataSource QueryDomainDataSource(\n    std::shared_ptr<grpc::Channel> channel, const std::string& datasource_id);\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/datamesh_helper_test.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/datamesh_helper.h\"\n\n#include <gmock/gmock-matchers.h>\n#include <grpcpp/grpcpp.h>\n#include <gtest/gtest.h>\n\n#include \"yacl/base/exception.h\"\n\n#include \"kuscia/proto/api/v1alpha1/datamesh/domaindata.grpc.pb.h\"\n#include \"kuscia/proto/api/v1alpha1/datamesh/domaindatasource.grpc.pb.h\"\n\nnamespace scql::engine::util {\n\nclass FakeDomainDataService : public dm::DomainDataService::Service {\n public:\n  void SetNextResponse(const dm::QueryDomainDataResponse& response,\n                       const grpc::Status& status) {\n    std::lock_guard<std::mutex> lock(mu_);\n    next_response_ = response;\n    next_status_ = status;\n    called_ = false;\n  }\n\n  grpc::Status QueryDomainData(grpc::ServerContext* context,\n                               const dm::QueryDomainDataRequest* request,\n                               dm::QueryDomainDataResponse* response) override {\n    std::lock_guard<std::mutex> lock(mu_);\n    called_ = true;\n    if (request != nullptr) {\n      last_request_ = *request;\n    }\n    if (response != nullptr) {\n      *response = next_response_;\n    }\n    return next_status_;\n  }\n\n  bool WasCalled() {\n    std::lock_guard<std::mutex> lock(mu_);\n    return called_;\n  }\n  dm::QueryDomainDataRequest GetLastRequest() {\n    std::lock_guard<std::mutex> lock(mu_);\n    return last_request_;\n  }\n\n private:\n  std::mutex mu_;\n  dm::QueryDomainDataResponse next_response_;\n  grpc::Status next_status_ = grpc::Status::OK;\n  bool called_ = false;\n  dm::QueryDomainDataRequest last_request_;\n};\n\nclass FakeDomainDataSourceService\n    : public dm::DomainDataSourceService::Service {\n public:\n  void SetNextResponse(const dm::QueryDomainDataSourceResponse& response,\n                       const grpc::Status& status) {\n    std::lock_guard<std::mutex> lock(mu_);\n    next_response_ = response;\n    next_status_ = status;\n    called_ = false;\n  }\n\n  grpc::Status QueryDomainDataSource(\n      grpc::ServerContext* context,\n      const dm::QueryDomainDataSourceRequest* request,\n      dm::QueryDomainDataSourceResponse* response) override {\n    std::lock_guard<std::mutex> lock(mu_);\n    called_ = true;\n    if (request != nullptr) {\n      last_request_ = *request;\n    }\n    if (response != nullptr) {\n      *response = next_response_;\n    }\n    return next_status_;\n  }\n\n  bool WasCalled() {\n    std::lock_guard<std::mutex> lock(mu_);\n    return called_;\n  }\n  dm::QueryDomainDataSourceRequest GetLastRequest() {\n    std::lock_guard<std::mutex> lock(mu_);\n    return last_request_;\n  }\n\n private:\n  std::mutex mu_;\n  dm::QueryDomainDataSourceResponse next_response_;\n  grpc::Status next_status_ = grpc::Status::OK;\n  bool called_ = false;\n  dm::QueryDomainDataSourceRequest last_request_;\n};\n\nclass DataMeshHelperTest : public ::testing::Test {\n protected:\n  std::unique_ptr<grpc::Server> server_;\n  std::shared_ptr<grpc::Channel> channel_;\n\n  FakeDomainDataService fake_domain_data_service_;\n  FakeDomainDataSourceService fake_domain_data_source_service_;\n\n  std::string inproc_server_name_ = \"datamesh_helper_test_server\";\n\n  void SetUp() override {\n    grpc::ServerBuilder builder;\n\n    builder.RegisterService(&fake_domain_data_service_);\n    builder.RegisterService(&fake_domain_data_source_service_);\n\n    // Build and start the server (for in-process, no network ports are listened\n    // to here)\n    server_ = builder.BuildAndStart();\n    ASSERT_NE(server_, nullptr)\n        << \"Fake gRPC (in-process) server startup failure.\";\n\n    // Create a channel to the in-process server.\n    channel_ = server_->InProcessChannel(grpc::ChannelArguments());\n    ASSERT_NE(channel_, nullptr)\n        << \"Failed to create a channel to the in-process server.\";\n  }\n\n  void TearDown() override {\n    if (server_) {\n      server_->Shutdown();\n      server_->Wait();\n    }\n  }\n};\n\n// --- QueryDomainData Test Cases ---\n\nTEST_F(DataMeshHelperTest, QueryDomainData_Success) {\n  // Arrange\n  std::string domain_id = \"test_domain_success\";\n  dm::QueryDomainDataResponse expected_response_proto;\n  expected_response_proto.mutable_status()->set_code(0);\n  dm::DomainData* data_payload = expected_response_proto.mutable_data();\n  data_payload->set_domaindata_id(domain_id);\n\n  fake_domain_data_service_.SetNextResponse(expected_response_proto,\n                                            grpc::Status::OK);\n\n  // Act\n  dm::DomainData result = QueryDomainData(channel_, domain_id);\n\n  // Assert\n  ASSERT_TRUE(fake_domain_data_service_.WasCalled());\n  EXPECT_EQ(fake_domain_data_service_.GetLastRequest().domaindata_id(),\n            domain_id);\n  EXPECT_EQ(result.domaindata_id(), domain_id);\n}\n\nTEST_F(DataMeshHelperTest, QueryDomainData_GrpcError) {\n  // Arrange\n  std::string domain_id = \"domain_grpc_failure\";\n  fake_domain_data_service_.SetNextResponse(\n      {}, grpc::Status(grpc::StatusCode::UNAVAILABLE,\n                       \"Simulated gRPC network error\"));\n\n  // Act & Assert\n  EXPECT_THROW(\n      {\n        try {\n          QueryDomainData(channel_, domain_id);\n        } catch (const yacl::Exception& e) {\n          EXPECT_THAT(e.what(),\n                      ::testing::HasSubstr(\"Simulated gRPC network error\"));\n          EXPECT_THAT(e.what(),\n                      ::testing::HasSubstr(std::to_string(\n                          static_cast<int>(grpc::StatusCode::UNAVAILABLE))));\n          throw;\n        }\n      },\n      yacl::Exception);\n  ASSERT_TRUE(fake_domain_data_service_.WasCalled());\n}\n\nTEST_F(DataMeshHelperTest, QueryDomainData_ResponseStatusError) {\n  // Arrange\n  std::string domain_id = \"domain_logical_error\";\n  dm::QueryDomainDataResponse error_response_proto;\n  error_response_proto.mutable_status()->set_code(\n      5);  // randomly pick a number that is not zero\n  error_response_proto.mutable_status()->set_message(\n      \"Domain ID not found in system\");\n\n  fake_domain_data_service_.SetNextResponse(error_response_proto,\n                                            grpc::Status::OK);\n\n  // Act & Assert\n  EXPECT_THROW(\n      {\n        try {\n          QueryDomainData(channel_, domain_id);\n        } catch (const yacl::Exception& e) {\n          EXPECT_THAT(e.what(),\n                      ::testing::HasSubstr(\"Domain ID not found in system\"));\n          EXPECT_THAT(e.what(), ::testing::HasSubstr(\"code=5\"));\n          throw;\n        }\n      },\n      yacl::Exception);\n  ASSERT_TRUE(fake_domain_data_service_.WasCalled());\n}\n\n// --- QueryDomainDataSource Test Cases ---\n\nTEST_F(DataMeshHelperTest, QueryDomainDataSource_Success) {\n  // Arrange\n  std::string datasource_id = \"ds_test_success\";\n  dm::QueryDomainDataSourceResponse expected_response_proto;\n  expected_response_proto.mutable_status()->set_code(0);\n  dm::DomainDataSource* data_payload = expected_response_proto.mutable_data();\n  data_payload->set_datasource_id(datasource_id);\n  data_payload->set_name(\"MySQL DB\");\n  data_payload->set_type(\"localfs\");\n\n  fake_domain_data_source_service_.SetNextResponse(expected_response_proto,\n                                                   grpc::Status::OK);\n\n  // Act\n  dm::DomainDataSource result = QueryDomainDataSource(channel_, datasource_id);\n\n  // Assert\n  ASSERT_TRUE(fake_domain_data_source_service_.WasCalled());\n  EXPECT_EQ(fake_domain_data_source_service_.GetLastRequest().datasource_id(),\n            datasource_id);\n\n  EXPECT_EQ(result.datasource_id(), datasource_id);\n  EXPECT_EQ(result.name(), \"MySQL DB\");\n  EXPECT_EQ(result.type(), \"localfs\");\n}\n\nTEST_F(DataMeshHelperTest, QueryDomainDataSource_GrpcError) {\n  // Arrange\n  std::string datasource_id = \"ds_grpc_failure\";\n  fake_domain_data_source_service_.SetNextResponse(\n      {}, grpc::Status(grpc::StatusCode::INTERNAL, \"Unexpected server fault\"));\n\n  // Act & Assert\n  EXPECT_THROW(\n      {\n        try {\n          QueryDomainDataSource(channel_, datasource_id);\n        } catch (const yacl::Exception& e) {\n          EXPECT_THAT(e.what(),\n                      ::testing::HasSubstr(\"Unexpected server fault\"));\n          EXPECT_THAT(e.what(),\n                      ::testing::HasSubstr(std::to_string(\n                          static_cast<int>(grpc::StatusCode::INTERNAL))));\n          throw;\n        }\n      },\n      yacl::Exception);\n  ASSERT_TRUE(fake_domain_data_source_service_.WasCalled());\n}\n\nTEST_F(DataMeshHelperTest, QueryDomainDataSource_ResponseStatusError) {\n  // Arrange\n  std::string datasource_id = \"ds_logical_error\";\n  dm::QueryDomainDataSourceResponse error_response_proto;\n  error_response_proto.mutable_status()->set_code(12);\n  error_response_proto.mutable_status()->set_message(\n      \"Datasource credentials invalid\");\n\n  fake_domain_data_source_service_.SetNextResponse(error_response_proto,\n                                                   grpc::Status::OK);\n\n  // Act & Assert\n  EXPECT_THROW(\n      {\n        try {\n          QueryDomainDataSource(channel_, datasource_id);\n        } catch (const yacl::Exception& e) {\n          EXPECT_THAT(e.what(),\n                      ::testing::HasSubstr(\"Datasource credentials invalid\"));\n          EXPECT_THAT(e.what(), ::testing::HasSubstr(\"code=12\"));\n          throw;\n        }\n      },\n      yacl::Exception);\n  ASSERT_TRUE(fake_domain_data_source_service_.WasCalled());\n}\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/disk/BUILD.bazel",
    "content": "# Copyright 2024 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncc_library(\n    name = \"arrow_reader\",\n    srcs = [\"arrow_reader.cc\"],\n    hdrs = [\"arrow_reader.h\"],\n    deps = [\n        \"//engine/core:arrow_helper\",\n        \"@org_apache_arrow//:arrow\",\n    ],\n)\n\ncc_library(\n    name = \"arrow_writer\",\n    srcs = [\"arrow_writer.cc\"],\n    hdrs = [\"arrow_writer.h\"],\n    deps = [\n        \"//engine/core:arrow_helper\",\n        \"//engine/core:type\",\n        \"@org_apache_arrow//:arrow\",\n    ],\n)\n\nscql_cc_test(\n    name = \"reader_writer_test\",\n    srcs = [\"reader_writer_test.cc\"],\n    deps = [\n        \":arrow_reader\",\n        \":arrow_writer\",\n        \"//engine/util:filepath_helper\",\n    ],\n)\n\ncc_binary(\n    name = \"read_write_bench\",\n    srcs = [\"read_write_bench.cc\"],\n    deps = [\n        \"@google_benchmark//:benchmark_main\",\n    ] + [\n        \":arrow_reader\",\n        \":arrow_writer\",\n        \"//engine/util:filepath_helper\",\n        \"@yacl//yacl/utils:parallel\",\n    ],\n)\n"
  },
  {
    "path": "engine/util/disk/arrow_reader.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/disk/arrow_reader.h\"\n\n#include \"arrow/table.h\"\n#include \"spdlog/spdlog.h\"\n\nnamespace scql::engine::util::disk {\n\nstd::shared_ptr<arrow::RecordBatch> SimpleArrowReader::ReadNext() {\n  if (batch_index_ >= record_batch_num_) {\n    return nullptr;\n  }\n  std::shared_ptr<arrow::RecordBatch> rbatch;\n  ASSIGN_OR_THROW_ARROW_STATUS(rbatch,\n                               ipc_reader_->ReadRecordBatch(batch_index_));\n  batch_index_++;\n  return rbatch;\n}\n\nstd::shared_ptr<arrow::ChunkedArray> ReadFileArray(\n    const std::string& file_name) {\n  SPDLOG_INFO(\"ReadFileArray: {}\", file_name);\n  SimpleArrowReader reader(file_name);\n  std::vector<std::shared_ptr<arrow::RecordBatch>> result_batches;\n  result_batches.reserve(reader.GetBatchNum());\n  auto rbatch = reader.ReadNext();\n  while (rbatch != nullptr) {\n    result_batches.push_back(rbatch);\n    rbatch = reader.ReadNext();\n  }\n  std::shared_ptr<arrow::Table> table;\n  ASSIGN_OR_THROW_ARROW_STATUS(table, arrow::Table::FromRecordBatches(\n                                          reader.GetSchema(), result_batches));\n  THROW_IF_ARROW_NOT_OK(table->Validate());\n  return table->column(0);\n}\n\nstd::shared_ptr<arrow::ChunkedArray> FileBatchReader::ReadNext(\n    int64_t batch_size) {\n  if (cur_batch_ == nullptr) {\n    return nullptr;\n  }\n  int64_t num_to_read = batch_size;\n  std::vector<std::shared_ptr<arrow::RecordBatch>> result_batches;\n  while (cur_batch_ != nullptr && num_to_read > 0) {\n    if (cur_batch_->num_rows() <= num_to_read) {\n      result_batches.push_back(cur_batch_);\n      num_to_read -= cur_batch_->num_rows();\n      cur_batch_ = reader_.ReadNext();\n      continue;\n    }\n    auto batch = cur_batch_->Slice(0, num_to_read);\n    cur_batch_ = cur_batch_->Slice(num_to_read);\n    num_to_read -= batch->num_rows();\n    result_batches.push_back(batch);\n  }\n  std::shared_ptr<arrow::Table> table;\n  ASSIGN_OR_THROW_ARROW_STATUS(table, arrow::Table::FromRecordBatches(\n                                          reader_.GetSchema(), result_batches));\n  THROW_IF_ARROW_NOT_OK(table->Validate());\n  return table->column(0);\n}\n\n}  // namespace scql::engine::util::disk"
  },
  {
    "path": "engine/util/disk/arrow_reader.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"arrow/io/file.h\"\n#include \"arrow/ipc/reader.h\"\n\n#include \"engine/core/arrow_helper.h\"\n\nnamespace scql::engine::util::disk {\n\nclass SimpleArrowReader final {\n public:\n  explicit SimpleArrowReader(std::string file_name)\n      : file_name_(std::move(file_name)) {\n    std::shared_ptr<arrow::io::ReadableFile> infile;\n    ASSIGN_OR_THROW_ARROW_STATUS(\n        infile, arrow::io::ReadableFile::Open(file_name_,\n                                              arrow::default_memory_pool()));\n    ASSIGN_OR_THROW_ARROW_STATUS(\n        ipc_reader_, arrow::ipc::RecordBatchFileReader::Open(infile));\n    record_batch_num_ = ipc_reader_->num_record_batches();\n    schema_ = ipc_reader_->schema();\n    YACL_ENFORCE(schema_->num_fields() == 1,\n                 \"Simple file array must only keep one column\");\n  }\n  ~SimpleArrowReader() = default;\n  std::shared_ptr<arrow::RecordBatch> ReadNext();\n  size_t GetBatchNum() const { return record_batch_num_; }\n  std::shared_ptr<arrow::Schema> GetSchema() const { return schema_; }\n\n private:\n  std::shared_ptr<arrow::Schema> schema_;\n  std::string file_name_;\n  std::shared_ptr<arrow::ipc::RecordBatchFileReader> ipc_reader_;\n  size_t batch_index_ = 0;\n  size_t record_batch_num_;\n};\n\nclass FileBatchReader {\n public:\n  explicit FileBatchReader(std::string file_name)\n      : reader_(SimpleArrowReader(std::move(file_name))) {\n    // read first batch\n    cur_batch_ = reader_.ReadNext();\n  }\n\n  virtual ~FileBatchReader() = default;\n  std::shared_ptr<arrow::ChunkedArray> ReadNext(int64_t batch_size);\n  std::shared_ptr<arrow::Schema> GetSchema() const {\n    return reader_.GetSchema();\n  }\n\n private:\n  SimpleArrowReader reader_;\n  std::shared_ptr<arrow::RecordBatch> cur_batch_;\n};\n\nstd::shared_ptr<arrow::ChunkedArray> ReadFileArray(\n    const std::string& file_name);\n\n}  // namespace scql::engine::util::disk"
  },
  {
    "path": "engine/util/disk/arrow_writer.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/disk/arrow_writer.h\"\n\n#include \"arrow/array/array_base.h\"\n#include \"arrow/chunked_array.h\"\n#include \"arrow/io/file.h\"\n#include \"arrow/record_batch.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/core/arrow_helper.h\"\n\nnamespace scql::engine::util::disk {\n\nvoid ArrowWriter::Init() {\n  std::shared_ptr<arrow::io::FileOutputStream> outfile;\n  ASSIGN_OR_THROW_ARROW_STATUS(outfile,\n                               arrow::io::FileOutputStream::Open(file_path_));\n  ASSIGN_OR_THROW_ARROW_STATUS(ipc_writer_,\n                               arrow::ipc::MakeFileWriter(outfile, schema_));\n}\n\nsize_t ArrowWriter::WriteBatch(const arrow::RecordBatch& batch) {\n  YACL_ENFORCE(batch.num_columns() == 1, \"columns num in batch must be 1\");\n  if (batch.num_rows() == 0) {\n    return 0;\n  }\n  THROW_IF_ARROW_NOT_OK(ipc_writer_->WriteRecordBatch(batch));\n  num_rows_ += batch.num_rows();\n  null_count_ += batch.column(0)->null_count();\n  return batch.num_rows();\n}\n\nsize_t ArrowWriter::WriteBatch(const arrow::ChunkedArray& batch) {\n  size_t old_rows = num_rows_;\n  for (int i = 0; i < batch.num_chunks(); ++i) {\n    std::vector<std::shared_ptr<arrow::Array>> arrays = {batch.chunk(i)};\n    WriteBatch(\n        *arrow::RecordBatch::Make(schema_, batch.chunk(i)->length(), arrays));\n  }\n  return num_rows_ - old_rows;\n}\n\n}  // namespace scql::engine::util::disk"
  },
  {
    "path": "engine/util/disk/arrow_writer.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <utility>\n\n#include \"arrow/ipc/writer.h\"\n#include \"arrow/type.h\"\n\nnamespace scql::engine::util::disk {\n\nclass ArrowWriter final {\n public:\n  explicit ArrowWriter(std::shared_ptr<arrow::Schema> schema,\n                       std::string file_path)\n      : schema_(std::move(schema)), file_path_(std::move(file_path)) {\n    Init();\n  }\n\n  explicit ArrowWriter(const std::string& field_name,\n                       const std::shared_ptr<arrow::DataType>& data_type,\n                       std::string file_path)\n      : file_path_(std::move(file_path)) {\n    auto field = std::make_shared<arrow::Field>(field_name, data_type);\n    arrow::FieldVector fields = {field};\n    schema_ = std::make_shared<arrow::Schema>(fields);\n    Init();\n  }\n\n  ~ArrowWriter() {\n    if (ipc_writer_) {\n      static_cast<void>(ipc_writer_->Close());\n    }\n  };\n\n  size_t WriteBatch(const arrow::RecordBatch& batch);\n  size_t WriteBatch(const arrow::ChunkedArray& batch);\n\n  size_t GetRowNum() const { return num_rows_; }\n  size_t GetNullCount() const { return null_count_; }\n  std::shared_ptr<arrow::Schema> GetSchema() { return schema_; }\n  std::string GetFilePath() { return file_path_; }\n\n private:\n  // init before writing\n  void Init();\n  std::shared_ptr<arrow::ipc::RecordBatchWriter> ipc_writer_;\n  std::shared_ptr<arrow::Schema> schema_;\n  std::string file_path_;\n  size_t num_rows_ = 0;\n  size_t null_count_ = 0;\n};\n\n}  // namespace scql::engine::util::disk"
  },
  {
    "path": "engine/util/disk/read_write_bench.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <filesystem>\n\n#include \"arrow/chunked_array.h\"\n#include \"arrow/testing/random.h\"\n#include \"arrow/type.h\"\n#include \"benchmark/benchmark.h\"\n#include \"yacl/utils/parallel.h\"\n\n#include \"engine/util/disk/arrow_reader.h\"\n#include \"engine/util/disk/arrow_writer.h\"\n#include \"engine/util/filepath_helper.h\"\n\nstatic void BM_WriteTest(benchmark::State& state) {\n  for (auto _ : state) {\n    state.PauseTiming();\n    constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n    arrow::ArrayVector arrays;\n    constexpr size_t array_num = 3;\n    size_t array_num_rows = state.range(0);\n    auto field = std::make_shared<arrow::Field>(\"a\", arrow::int64());\n    for (size_t i = 0; i < array_num; ++i) {\n      arrays.push_back(\n          arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n    }\n    arrow::FieldVector fields = {field};\n    auto schema = std::make_shared<arrow::Schema>(fields);\n    auto expected_chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n    auto path = scql::engine::util::CreateDirWithRandSuffix(\n                    std::filesystem::temp_directory_path(), \"test\") /\n                \"test.arrow\";\n\n    state.ResumeTiming();\n    scql::engine::util::disk::ArrowWriter writer(schema, path.string());\n    writer.WriteBatch(*expected_chunked_array);\n    state.PauseTiming();\n    std::error_code ec;\n    std::filesystem::remove(path, ec);\n    state.ResumeTiming();\n  }\n}\n\nstatic void BM_ParallelWriteTest(benchmark::State& state) {\n  for (auto _ : state) {\n    state.PauseTiming();\n    constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n    arrow::ArrayVector arrays;\n    constexpr size_t array_num = 3;\n    size_t array_num_rows = state.range(0);\n    auto field = std::make_shared<arrow::Field>(\"a\", arrow::int64());\n    for (size_t i = 0; i < array_num; ++i) {\n      arrays.push_back(\n          arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n    }\n    arrow::FieldVector fields = {field};\n    auto schema = std::make_shared<arrow::Schema>(fields);\n    auto expected_chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n    auto path = scql::engine::util::CreateDirWithRandSuffix(\n        std::filesystem::temp_directory_path(), \"test\");\n\n    state.ResumeTiming();\n    yacl::parallel_for(0, state.range(1), [&](int64_t begin, int64_t end) {\n      for (int64_t i = begin; i < end; ++i) {\n        auto sub_path = scql::engine::util::CreateDir(path, std::to_string(i));\n        scql::engine::util::disk::ArrowWriter writer(\n            schema, (sub_path / \"test.arrow\").string());\n        writer.WriteBatch(*expected_chunked_array);\n      }\n    });\n    state.PauseTiming();\n    std::error_code ec;\n    std::filesystem::remove(path, ec);\n    state.ResumeTiming();\n  }\n}\n\nstatic void BM_WriteSmallFileTest(benchmark::State& state) {\n  for (auto _ : state) {\n    state.PauseTiming();\n    constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n    arrow::ArrayVector arrays;\n    size_t array_num = 300 * 1000 * 1000 / state.range(0);\n    size_t array_num_rows = state.range(0);\n    auto field = std::make_shared<arrow::Field>(\"a\", arrow::int64());\n    for (size_t i = 0; i < array_num; ++i) {\n      arrays.push_back(\n          arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n    }\n    arrow::FieldVector fields = {field};\n    auto schema = std::make_shared<arrow::Schema>(fields);\n    auto expected_chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n    auto path = scql::engine::util::CreateDirWithRandSuffix(\n                    std::filesystem::temp_directory_path(), \"test\") /\n                \"test.arrow\";\n\n    state.ResumeTiming();\n    scql::engine::util::disk::ArrowWriter writer(schema, path.string());\n    writer.WriteBatch(*expected_chunked_array);\n    state.PauseTiming();\n    std::error_code ec;\n    std::filesystem::remove(path, ec);\n    state.ResumeTiming();\n  }\n}\n\nstatic void BM_ReadTest(benchmark::State& state) {\n  for (auto _ : state) {\n    state.PauseTiming();\n    constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n    arrow::ArrayVector arrays;\n    size_t array_num = 300 * 1000 * 1000 / state.range(0);\n    size_t array_num_rows = state.range(0);\n    auto field = std::make_shared<arrow::Field>(\"a\", arrow::int64());\n    for (size_t i = 0; i < array_num; ++i) {\n      arrays.push_back(\n          arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n    }\n    arrow::FieldVector fields = {field};\n    auto schema = std::make_shared<arrow::Schema>(fields);\n    auto path = std::filesystem::temp_directory_path() / \"test.arrow\";\n    auto expected_chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n    {\n      scql::engine::util::disk::ArrowWriter writer(schema, path.string());\n      writer.WriteBatch(*expected_chunked_array);\n    }\n    state.ResumeTiming();\n    scql::engine::util::disk::FileBatchReader reader(path.string());\n    while (reader.ReadNext(state.range(0)));\n    state.PauseTiming();\n    std::error_code ec;\n    std::filesystem::remove(path, ec);\n    state.ResumeTiming();\n  }\n}\n\nstatic void BM_ParallelWriteSmallFileTest(benchmark::State& state) {\n  for (auto _ : state) {\n    state.PauseTiming();\n    constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n    arrow::ArrayVector arrays;\n    size_t array_num = 300 * 1000 * 1000 / state.range(0) / 20;\n    size_t array_num_rows = state.range(0);\n    auto field = std::make_shared<arrow::Field>(\"a\", arrow::int64());\n    for (size_t i = 0; i < array_num; ++i) {\n      arrays.push_back(\n          arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n    }\n    arrow::FieldVector fields = {field};\n    auto schema = std::make_shared<arrow::Schema>(fields);\n    auto expected_chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n    auto path = scql::engine::util::CreateDirWithRandSuffix(\n        std::filesystem::temp_directory_path(), \"test\");\n    yacl::parallel_for(0, 20, [&](int64_t begin, int64_t end) {\n      for (int64_t i = begin; i < end; ++i) {\n        auto sub_path = scql::engine::util::CreateDir(path, std::to_string(i));\n        scql::engine::util::disk::ArrowWriter writer(\n            schema, (sub_path / \"test.arrow\").string());\n        writer.WriteBatch(*expected_chunked_array);\n      }\n    });\n    state.PauseTiming();\n    std::error_code ec;\n    std::filesystem::remove(path, ec);\n    state.ResumeTiming();\n  }\n}\n\nBENCHMARK(BM_WriteTest)\n    ->Unit(benchmark::kMillisecond)\n    ->Arg(10000000)\n    ->Arg(100000000);\n\nBENCHMARK(BM_ParallelWriteTest)\n    ->Unit(benchmark::kMillisecond)\n    ->RangeMultiplier(2)\n    ->Args({2000000, 5})\n    ->Args({20000000, 5})\n    ->Args({2000000, 10})\n    ->Args({20000000, 10})\n    ->Args({2000000, 20})\n    ->Args({20000000, 20});\n\nBENCHMARK(BM_WriteSmallFileTest)\n    ->Unit(benchmark::kMillisecond)\n    ->Arg(5000)\n    ->Arg(50000)\n    ->Arg(500000);\n\nBENCHMARK(BM_ReadTest)\n    ->Unit(benchmark::kMillisecond)\n    ->Arg(5000)\n    ->Arg(50000)\n    ->Arg(500000);\n\nBENCHMARK(BM_ParallelWriteSmallFileTest)\n    ->Unit(benchmark::kMillisecond)\n    ->Arg(5000)\n    ->Arg(50000)\n    ->Arg(500000);\n"
  },
  {
    "path": "engine/util/disk/reader_writer_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <filesystem>\n\n#include \"arrow/chunked_array.h\"\n#include \"arrow/testing/random.h\"\n#include \"arrow/type.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/util/disk/arrow_reader.h\"\n#include \"engine/util/disk/arrow_writer.h\"\n#include \"engine/util/filepath_helper.h\"\n\nnamespace scql::engine::util::disk {\n\nclass ReaderWriterTest : public ::testing::Test {\n public:\n  ReaderWriterTest()\n      : tmp_dir_(util::ScopedDir(util::CreateDirWithRandSuffix(\n            std::filesystem::temp_directory_path(), \"test\"))) {}\n\n protected:\n  util::ScopedDir tmp_dir_;\n};\n\nTEST_F(ReaderWriterTest, ReadAndWrite) {\n  constexpr arrow::random::SeedType randomSeed = 0x0ff1ce;\n  arrow::ArrayVector arrays;\n  constexpr size_t array_num = 3;\n  constexpr size_t array_num_rows = 1000;\n  auto field = std::make_shared<arrow::Field>(\"a\", arrow::decimal128(30, 0));\n  for (size_t i = 0; i < array_num; ++i) {\n    arrays.push_back(\n        arrow::random::GenerateArray(*field, array_num_rows, randomSeed));\n  }\n  arrow::FieldVector fields = {field};\n  auto schema = std::make_shared<arrow::Schema>(fields);\n  auto path = tmp_dir_.path() / \"test.arrow\";\n  auto expected_chunked_array = std::make_shared<arrow::ChunkedArray>(arrays);\n  {\n    ArrowWriter writer(schema, path.string());\n    auto write_num = writer.WriteBatch(*expected_chunked_array);\n    ASSERT_EQ(array_num * array_num_rows, write_num);\n  }\n  {\n    auto chunked_array = ReadFileArray(path.string());\n    ASSERT_EQ(array_num * array_num_rows, chunked_array->length());\n    EXPECT_TRUE(chunked_array->Equals(expected_chunked_array))\n        << \"\\nexpect=\" << expected_chunked_array->ToString()\n        << \"\\n,but got=\" << chunked_array->ToString();\n  }\n}\n\n}  // namespace scql::engine::util::disk"
  },
  {
    "path": "engine/util/dp/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nproto_library(\n    name = \"flight_proto\",\n    srcs = [\"flight.proto\"],\n    deps = [\n        \"@kuscia//proto/api/v1alpha1/datamesh:domaindata_proto\",\n        \"@kuscia//proto/api/v1alpha1/datamesh:domaindatasource_proto\",\n        \"@kuscia//proto/api/v1alpha1/datamesh:flightdm_proto\",\n    ],\n)\n\ncc_proto_library(\n    name = \"flight_cc_proto\",\n    deps = [\n        \":flight_proto\",\n    ],\n)\n"
  },
  {
    "path": "engine/util/dp/flight.proto",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage kuscia.proto.api.v1alpha1.datamesh;\n\nimport \"kuscia/proto/api/v1alpha1/datamesh/flightdm.proto\";\nimport \"kuscia/proto/api/v1alpha1/datamesh/domaindatasource.proto\";\nimport \"kuscia/proto/api/v1alpha1/datamesh/domaindata.proto\";\n\n// TODO: export flightinner in kuscia\n\n// message CommandDataMeshQuery {\n//   CommandDomainDataQuery query = 1;\n//   DomainData domaindata = 2;\n//   DomainDataSource datasource = 3;\n// }\n\nmessage CommandDataMeshUpdate {\n  CommandDomainDataUpdate update = 1;\n  DomainData domaindata = 2;\n  DomainDataSource datasource = 3;\n}\n\nmessage CommandDataMeshSqlQuery {\n  CommandDataSourceSqlQuery query = 1;\n  DomainDataSource datasource = 2;\n}"
  },
  {
    "path": "engine/util/filepath_helper.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/filepath_helper.h\"\n\n#include <filesystem>\n\n#include \"absl/strings/match.h\"\n#include \"boost/uuid/random_generator.hpp\"\n#include \"boost/uuid/uuid_io.hpp\"\n#include \"yacl/base/exception.h\"\nnamespace scql::engine::util {\n\nstd::string GetS3LikeScheme(const std::string& url) {\n  const std::string schemes[] = {kSchemeS3, kSchemeMinIo, kSchemeOss};\n  for (const auto& scheme : schemes) {\n    if (absl::StartsWith(url, scheme)) {\n      return scheme;\n    }\n  }\n  return \"\";\n}\n\nvoid CheckS3LikeUrl(const std::string& path_without_prefix, bool is_restricted,\n                    const std::string& restricted_path) {\n  // 1. only allow absolute path for s3\n  YACL_ENFORCE(GetS3LikeScheme(restricted_path).empty(),\n               \"restricted_path should remove s3 prefix like 's3://'\");\n  YACL_ENFORCE(path_without_prefix.find(\"..\") == std::string::npos,\n               \"path={} cannot contain '..'\", path_without_prefix);\n  // 2. if restricted, the path_without_prefix must start with restricted_path\n  if (is_restricted) {\n    YACL_ENFORCE(absl::StartsWith(path_without_prefix, restricted_path),\n                 \"path={} not start with restricted_path={}\",\n                 path_without_prefix, restricted_path);\n  }\n}\n\nstd::string CheckAndGetAbsoluteLocalPath(\n    const std::string& in_filepath, bool is_restricted,\n    const std::string& restricted_filepath) {\n  YACL_ENFORCE(!in_filepath.empty());\n  auto final_path =\n      std::filesystem::weakly_canonical(std::filesystem::path(in_filepath));\n  if (is_restricted) {\n    YACL_ENFORCE(\n        !restricted_filepath.empty(),\n        \"when path is restricted, the restricted_filepath must not be empty\");\n    auto restricted_path = std::filesystem::weakly_canonical(\n        std::filesystem::path(restricted_filepath));\n    YACL_ENFORCE(\n        absl::StartsWith(final_path.string(), restricted_path.string()),\n        \"final_path={} not start with restricted_path={}\", final_path.string(),\n        restricted_path.string());\n  }\n\n  return final_path.string();\n}\n\nbool GetAndRemoveS3EndpointPrefix(std::string& endpoint) {\n  const std::string http_prefix = \"http://\";\n  const std::string https_prefix = \"https://\";\n  if (absl::StartsWith(endpoint, http_prefix)) {\n    endpoint.erase(0, http_prefix.length());\n    return false;\n  } else if (absl::StartsWith(endpoint, https_prefix)) {\n    endpoint.erase(0, https_prefix.length());\n  }\n  // https by default\n  return true;\n}\n\nstd::filesystem::path CreateDir(const std::filesystem::path& parent_dir,\n                                const std::string& dir_name) {\n  auto dir = parent_dir / dir_name;\n  if (std::filesystem::exists(dir)) {\n    YACL_THROW(\"failed to create dir {}, due to dir already exist\",\n               dir.string());\n  }\n  if (!std::filesystem::create_directories(dir)) {\n    YACL_THROW(\"failed to create dir {}\", dir.string());\n  }\n  return dir;\n}\n\nstd::filesystem::path CreateDirWithRandSuffix(\n    const std::filesystem::path& parent_dir, const std::string& dir_name) {\n  int tries = 0;\n\n  const int kMaxTries = 10;\n  boost::uuids::random_generator uuid_generator;\n\n  do {\n    auto uuid_str = boost::uuids::to_string(uuid_generator());\n    auto dir = parent_dir / fmt::format(\"{}-{}\", dir_name, uuid_str);\n    tries++;\n    if (std::filesystem::exists(dir)) {\n      continue;\n    }\n    if (!std::filesystem::create_directory(dir)) {\n      YACL_THROW(\"failed to create dir {}\", dir.string());\n    }\n    return dir;\n  } while (tries < kMaxTries);\n  YACL_THROW(\"failed to create dir {}\", dir_name);\n}\n\n// FIXME: Temporary solution for secretpad compatibility, which may miss oss\n// info in the path.\nstd::string BuildFullPathForPad(const std::string& path_without_prefix,\n                                const std::string& prefix,\n                                const std::string& bucket_name) {\n  size_t slash_pos = path_without_prefix.find('/');\n  YACL_ENFORCE(slash_pos != std::string::npos,\n               \"path={} must contain bucket name\", path_without_prefix);\n\n  std::string cur_bucket_name = path_without_prefix.substr(0, slash_pos);\n  std::string remaining_path = path_without_prefix.substr(slash_pos + 1);\n\n  // Replace \"BUCKET_NAME\" in the path with the bucket name in\n  // oss_datasource_info.\n  if (cur_bucket_name == \"BUCKET_NAME\") {\n    cur_bucket_name = bucket_name;\n  }\n\n  std::filesystem::path new_path = std::filesystem::path(cur_bucket_name) /\n                                   std::filesystem::path(prefix) /\n                                   std::filesystem::path(remaining_path);\n\n  return new_path.generic_string();\n}\n\n};  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/filepath_helper.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <filesystem>\n#include <string>\n#include <utility>\n\n#include \"spdlog/spdlog.h\"\n\nnamespace scql::engine::util {\n\nstatic constexpr char kSchemeS3[] = \"s3://\";\nstatic constexpr char kSchemeMinIo[] = \"minio://\";\nstatic constexpr char kSchemeOss[] = \"oss://\";\n\nstd::string GetS3LikeScheme(const std::string& url);\n\n// @param[path_without_prefix] should be the file path without prefix, e.g\n// \"bucket/path/to/file.txt\"\n// @param[restricted_path] should be a path without prefix, e.g: \"bucket\"\nvoid CheckS3LikeUrl(const std::string& path_without_prefix, bool is_restricted,\n                    const std::string& restricted_path);\n\nstd::string CheckAndGetAbsoluteLocalPath(\n    const std::string& in_filepath, bool is_restricted,\n    const std::string& restricted_filepath);\n\n// Returns true if the endpoint prefix is https, false if it is http, and true\n// by default.\nbool GetAndRemoveS3EndpointPrefix(std::string& endpoint);\n\nclass ScopedDir {\n public:\n  explicit ScopedDir(std::filesystem::path dir) : dir_(std::move(dir)) {}\n\n  const std::filesystem::path& path() const { return dir_; }\n\n  ~ScopedDir() {\n    if (!dir_.empty()) {\n      std::error_code ec;\n      std::filesystem::remove_all(dir_, ec);\n      if (ec.value() != 0) {\n        SPDLOG_WARN(\"can not remove tmp dir: {}, msg: {}\", dir_.string(),\n                    ec.message());\n      }\n    }\n  }\n\n private:\n  std::filesystem::path dir_;\n};\n\nstd::filesystem::path CreateDir(const std::filesystem::path& parent_dir,\n                                const std::string& dir_name);\n\nstd::filesystem::path CreateDirWithRandSuffix(\n    const std::filesystem::path& parent_dir, const std::string& dir_name);\n\nstd::string BuildFullPathForPad(const std::string& path_without_prefix,\n                                const std::string& prefix,\n                                const std::string& bucket_name);\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/filepath_helper_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/filepath_helper.h\"\n\n#include <filesystem>\n#include <string>\n\n#include \"gtest/gtest.h\"\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine::util {\n\nTEST(FilePathTest, CheckAndGetAbsoluteLocalPath) {\n  std::string path = \"/data/test.file\";\n  EXPECT_EQ(path, CheckAndGetAbsoluteLocalPath(path, false, \"null\"));\n\n  EXPECT_EQ(path, CheckAndGetAbsoluteLocalPath(path, true, \"/data\"));\n  EXPECT_THROW(CheckAndGetAbsoluteLocalPath(path, true, \"/another_dir\"),\n               yacl::EnforceNotMet);\n  EXPECT_THROW(CheckAndGetAbsoluteLocalPath(path, true, \"\"),\n               yacl::EnforceNotMet);\n\n  std::string current_path = std::filesystem::current_path().string();\n  EXPECT_EQ(current_path + \"/test.file\",\n            CheckAndGetAbsoluteLocalPath(\"./test.file\", false, \"\"));\n\n  EXPECT_EQ(current_path + \"/data/test.file\",\n            CheckAndGetAbsoluteLocalPath(\"./data/test.file\", true, \"./data\"));\n  EXPECT_THROW(CheckAndGetAbsoluteLocalPath(\"./data/../other_dir/test.file\",\n                                            true, \"./data\"),\n               yacl::EnforceNotMet);\n  EXPECT_THROW(\n      CheckAndGetAbsoluteLocalPath(\"../other_dir/test.file\", true, \"./data\"),\n      yacl::EnforceNotMet);\n}\n\nTEST(FilePathTest, CheckS3LikeUrl) {\n  EXPECT_NO_THROW(CheckS3LikeUrl(\"bucket/dir/test.file\", true, \"bucket\"));\n\n  EXPECT_THROW(CheckS3LikeUrl(\"bucket/dir/../dir2/test.file\", true, \"bucket\"),\n               yacl::EnforceNotMet);\n}\n\nTEST(FilePathTest, BuildFullPathForPad) {\n  std::string path = \"bucket_name/test.file\";\n  EXPECT_EQ(\"bucket_name/data/test.file\",\n            BuildFullPathForPad(path, \"data/\", \"bucket_name\"));\n\n  path = \"bucket_name/test.file\";\n  EXPECT_EQ(\"bucket_name/data/test.file\",\n            BuildFullPathForPad(path, \"data\", \"bucket_name\"));\n\n  path = \"bucket_name/test.file\";\n  EXPECT_EQ(\"bucket_name/test.file\",\n            BuildFullPathForPad(path, \"\", \"bucket_name\"));\n\n  path = \"BUCKET_NAME/test.file\";\n  EXPECT_EQ(\"bucket_name/test.file\",\n            BuildFullPathForPad(path, \"\", \"bucket_name\"));\n\n  path = \"test.file\";\n  EXPECT_THROW(BuildFullPathForPad(path, \"data/\", \"bucket_name\"),\n               yacl::EnforceNotMet);\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/kpad_task_helper.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/kpad_task_helper.h\"\n\n#include \"google/protobuf/util/json_util.h\"\n#include \"libspu/core/config.h\"\n#include \"spdlog/spdlog.h\"\n\n// Include rapidjson headers from brpc butil\n#include \"butil/third_party/rapidjson/document.h\"\n#include \"butil/third_party/rapidjson/error/en.h\"\n#include \"butil/third_party/rapidjson/rapidjson.h\"\n\nnamespace scql::engine::util {\n\nbool ValidateKpadTaskParams(const std::string& cluster_def,\n                            const std::string& job_id,\n                            const std::string& scql_config) {\n  bool has_cluster_def = !cluster_def.empty();\n  bool has_job_id = !job_id.empty();\n  bool has_scql_config = !scql_config.empty();\n\n  if (has_cluster_def != has_job_id || has_job_id != has_scql_config) {\n    SPDLOG_ERROR(\n        \"Invalid kpad task parameters: kpad_cluster_def, kpad_job_id, and \"\n        \"kpad_scql_config must all be provided or all be empty\");\n    return false;\n  }\n  return true;\n}\n\nstd::unique_ptr<ClusterDef> ParseClusterDef(const std::string& json_str) {\n  butil::rapidjson::Document doc;\n  doc.Parse(json_str.c_str());\n  if (doc.HasParseError()) {\n    SPDLOG_ERROR(\"Failed to parse cluster_def JSON: {} at offset {}\",\n                 butil::rapidjson::GetParseError_En(doc.GetParseError()),\n                 doc.GetErrorOffset());\n    return nullptr;\n  }\n  if (!doc.IsObject()) {\n    SPDLOG_ERROR(\"cluster_def JSON must be an object\");\n    return nullptr;\n  }\n  auto cluster_def = std::make_unique<ClusterDef>();\n  // Parse self_party\n  if (doc.HasMember(\"self_party\") && doc[\"self_party\"].IsString()) {\n    cluster_def->self_party = doc[\"self_party\"].GetString();\n  } else {\n    SPDLOG_ERROR(\"cluster_def missing or invalid 'self_party' field\");\n    return nullptr;\n  }\n  // Parse parties\n  if (doc.HasMember(\"parties\") && doc[\"parties\"].IsArray()) {\n    const auto& parties_array = doc[\"parties\"];\n    for (const auto* it = parties_array.Begin(); it != parties_array.End();\n         ++it) {\n      if (it->IsString()) {\n        std::string party_name = it->GetString();\n        cluster_def->parties.push_back(party_name);\n      } else {\n        SPDLOG_ERROR(\"cluster_def 'parties' array contains non-string element\");\n        return nullptr;\n      }\n    }\n  } else {\n    SPDLOG_ERROR(\"cluster_def missing or invalid 'parties' field\");\n    return nullptr;\n  }\n  // Parse services\n  if (doc.HasMember(\"services\") && doc[\"services\"].IsObject()) {\n    const auto& services_obj = doc[\"services\"];\n    for (auto it = services_obj.MemberBegin(); it != services_obj.MemberEnd();\n         ++it) {\n      if (!it->name.IsString() || !it->value.IsObject()) {\n        SPDLOG_ERROR(\"cluster_def 'services' has invalid party entry\");\n        return nullptr;\n      }\n      std::string party_name = it->name.GetString();\n      const auto& party_services = it->value;\n      std::map<std::string, Service> service_map;\n      for (auto service_it = party_services.MemberBegin();\n           service_it != party_services.MemberEnd(); ++service_it) {\n        if (!service_it->name.IsString() || !service_it->value.IsObject()) {\n          SPDLOG_ERROR(\"cluster_def party '{}' has invalid service entry\",\n                       party_name);\n          return nullptr;\n        }\n        std::string service_name = service_it->name.GetString();\n        const auto& service_obj = service_it->value;\n        Service service;\n        service.name = service_name;\n        // Parse service fields\n        if (service_obj.HasMember(\"name\") && service_obj[\"name\"].IsString()) {\n          service.name = service_obj[\"name\"].GetString();\n        }\n        if (service_obj.HasMember(\"host\") && service_obj[\"host\"].IsString()) {\n          service.host = service_obj[\"host\"].GetString();\n        } else {\n          SPDLOG_ERROR(\"service '{}' missing 'host' field\", service_name);\n          return nullptr;\n        }\n        if (service_obj.HasMember(\"port\") && service_obj[\"port\"].IsString()) {\n          service.port = service_obj[\"port\"].GetString();\n        } else {\n          SPDLOG_ERROR(\"service '{}' missing 'port' field\", service_name);\n          return nullptr;\n        }\n        if (service_obj.HasMember(\"scope\") && service_obj[\"scope\"].IsString()) {\n          service.scope = service_obj[\"scope\"].GetString();\n        }\n        if (service_obj.HasMember(\"protocol\") &&\n            service_obj[\"protocol\"].IsString()) {\n          service.protocol = service_obj[\"protocol\"].GetString();\n        }\n        service_map[service_name] = std::move(service);\n      }\n      cluster_def->services[party_name] = std::move(service_map);\n    }\n  } else {\n    SPDLOG_ERROR(\"cluster_def missing or invalid 'services' field\");\n    return nullptr;\n  }\n  return cluster_def;\n}\n\nstd::unique_ptr<scql::pb::ScqlConfig> ParseScqlConfig(\n    const std::string& scql_config_json) {\n  if (scql_config_json.empty()) {\n    return nullptr;\n  }\n\n  google::protobuf::util::JsonParseOptions options;\n  options.ignore_unknown_fields = true;\n\n  auto scql_config = std::make_unique<scql::pb::ScqlConfig>();\n  auto status = google::protobuf::util::JsonStringToMessage(\n      scql_config_json, scql_config.get(), options);\n  if (!status.ok()) {\n    SPDLOG_ERROR(\"Failed to parse scql_config: {}\", status.ToString());\n    return nullptr;\n  }\n\n  return scql_config;\n}\n\nstd::string GetPartyHost(const ClusterDef& cluster_def,\n                         const std::string& party_code,\n                         const std::string& job_id) {\n  auto services_iter = cluster_def.services.find(party_code);\n  if (services_iter == cluster_def.services.end()) {\n    SPDLOG_WARN(\"No services found for party: {}\", party_code);\n    return \"\";\n  }\n\n  const auto& service_map = services_iter->second;\n\n  // Assume there is only one service\n  if (!service_map.empty()) {\n    const auto& first_service = service_map.begin()->second;\n    if (first_service.host.empty()) {\n      SPDLOG_ERROR(\"No host found for party: {}\", party_code);\n      return \"\";\n    }\n    return first_service.host;\n  }\n\n  SPDLOG_ERROR(\"No services available for party: {}\", party_code);\n  return \"\";\n}\n\nstd::unique_ptr<scql::pb::JobStartParams> BuildJobStartParams(\n    const ClusterDef& cluster_def, const scql::pb::ScqlConfig& scql_config,\n    const std::string& job_id) {\n  auto job_params = std::make_unique<scql::pb::JobStartParams>();\n  job_params->set_job_id(job_id);\n  job_params->set_party_code(cluster_def.self_party);\n\n  for (int i = 0; i < scql_config.parties_size(); ++i) {\n    const auto& party_code = scql_config.parties()[i];\n    auto* party_info = job_params->add_parties();\n    party_info->set_code(party_code);\n    party_info->set_name(party_code);\n    party_info->set_rank(i);\n\n    std::string party_host = GetPartyHost(cluster_def, party_code, job_id);\n    if (!party_host.empty()) {\n      party_info->set_host(party_host);\n    } else {\n      SPDLOG_ERROR(\"Failed to get host for party: {}\", party_code);\n      // Return nullptr to indicate failure\n      return nullptr;\n    }\n  }\n\n  if (scql_config.has_spu_runtime_cfg()) {\n    *job_params->mutable_spu_runtime_cfg() = scql_config.spu_runtime_cfg();\n  } else {\n    // Set default SPU runtime config when none is provided\n    spu::RuntimeConfig default_config;\n    default_config.protocol = spu::ProtocolKind::SEMI2K;\n    default_config.field = spu::FieldType::FM64;\n    default_config.sigmoid_mode = spu::RuntimeConfig::SIGMOID_REAL;\n    default_config.experimental_enable_colocated_optimization = true;\n    spu::populateRuntimeConfig(default_config);\n    *job_params->mutable_spu_runtime_cfg() = default_config.ToProto();\n  }\n  if (!scql_config.time_zone().empty()) {\n    job_params->set_time_zone(scql_config.time_zone());\n  }\n  if (scql_config.has_link_cfg()) {\n    *job_params->mutable_link_cfg() = scql_config.link_cfg();\n  }\n  if (scql_config.has_psi_cfg()) {\n    *job_params->mutable_psi_cfg() = scql_config.psi_cfg();\n  }\n  if (scql_config.has_log_cfg()) {\n    *job_params->mutable_log_cfg() = scql_config.log_cfg();\n  }\n\n  return job_params;\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/kpad_task_helper.h",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <map>\n#include <memory>\n#include <string>\n#include <vector>\n\n#include \"api/engine.pb.h\"\n#include \"api/scql_task.pb.h\"\n\nnamespace scql::engine::util {\n\n// Service represents a service endpoint in the cluster\nstruct Service {\n  std::string name;      // service name\n  std::string host;      // service host address\n  std::string port;      // service port number\n  std::string scope;     // service scope\n  std::string protocol;  // service protocol\n};\n\n// ClusterDef defines the cluster configuration for task mode\nstruct ClusterDef {\n  std::string self_party;            // current node's party\n  std::vector<std::string> parties;  // all participating parties\n  std::map<std::string, std::map<std::string, Service>>\n      services;  // party -> service_name -> service\n};\n\n// ParseClusterDef parses JSON string into ClusterDef structure\n// Returns nullptr if parsing fails\nstd::unique_ptr<ClusterDef> ParseClusterDef(const std::string& json_str);\n\n// Validate kpad task parameters\n// Returns true if all parameters are valid (all empty or all non-empty)\n// Returns false and logs error if parameters are inconsistent\nbool ValidateKpadTaskParams(const std::string& cluster_def,\n                            const std::string& job_id,\n                            const std::string& scql_config);\n\n// Parse ScqlConfig from JSON string\n// Returns nullptr if parsing fails\nstd::unique_ptr<scql::pb::ScqlConfig> ParseScqlConfig(\n    const std::string& scql_config_json);\n\n// Get host from cluster def for a party\n// Returns \"host\" string, or empty string if not found\nstd::string GetPartyHost(const ClusterDef& cluster_def,\n                         const std::string& party_code,\n                         const std::string& job_id);\n\nstd::unique_ptr<scql::pb::JobStartParams> BuildJobStartParams(\n    const ClusterDef& cluster_def, const scql::pb::ScqlConfig& scql_config,\n    const std::string& job_id);\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/kpad_task_helper_test.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/kpad_task_helper.h\"\n\n#include \"gtest/gtest.h\"\n\nnamespace scql::engine::util {\nTEST(KpadTaskHelperTest, ParseClusterDefSuccess) {\n  const std::string cluster_def_json = R\"({\n    \"self_party\": \"alice\",\n    \"parties\": [\"alice\", \"bob\"],\n    \"services\": {\n      \"alice\": {\n        \"job123\": {\n          \"name\": \"job123\",\n          \"host\": \"localhost\",\n          \"port\": \"8080\",\n          \"scope\": \"cluster\",\n          \"protocol\": \"http\"\n        }\n      }\n    }\n  })\";\n\n  auto cluster_def = ParseClusterDef(cluster_def_json);\n  EXPECT_NE(cluster_def, nullptr);\n  EXPECT_EQ(cluster_def->self_party, \"alice\");\n  EXPECT_EQ(cluster_def->parties.size(), 2);\n  EXPECT_EQ(cluster_def->parties[0], \"alice\");\n  EXPECT_EQ(cluster_def->parties[1], \"bob\");\n}\n\nTEST(KpadTaskHelperTest, ParseClusterDefFailure) {\n  const std::string invalid_json = \"{ invalid json }\";\n\n  auto cluster_def = ParseClusterDef(invalid_json);\n  EXPECT_EQ(cluster_def, nullptr);\n}\n\nTEST(KpadTaskHelperTest, ParseScqlConfigSuccess) {\n  const std::string scql_config_json = R\"({\n    \"input_file_paths\": {\n      \"db.table1\": \"/path/to/table1.csv\",\n      \"db.table2\": \"/path/to/table2.csv\"\n    },\n    \"parties\": [\"alice\", \"bob\"],\n    \"time_zone\": \"+08:00\"\n  })\";\n\n  auto scql_config = ParseScqlConfig(scql_config_json);\n  EXPECT_NE(scql_config, nullptr);\n  EXPECT_EQ(scql_config->input_file_paths_size(), 2);\n  EXPECT_EQ(scql_config->input_file_paths().at(\"db.table1\"),\n            \"/path/to/table1.csv\");\n  EXPECT_EQ(scql_config->input_file_paths().at(\"db.table2\"),\n            \"/path/to/table2.csv\");\n  EXPECT_EQ(scql_config->parties_size(), 2);\n  EXPECT_EQ(scql_config->parties(0), \"alice\");\n  EXPECT_EQ(scql_config->parties(1), \"bob\");\n  EXPECT_EQ(scql_config->time_zone(), \"+08:00\");\n}\n\nTEST(KpadTaskHelperTest, ParseScqlConfigFailure) {\n  const std::string invalid_json = \"{ invalid json }\";\n\n  auto scql_config = ParseScqlConfig(invalid_json);\n  EXPECT_EQ(scql_config, nullptr);\n}\n\nTEST(KpadTaskHelperTest, GetPartyHostSuccess) {\n  ClusterDef cluster_def;\n  cluster_def.self_party = \"alice\";\n\n  Service service1;\n  service1.name = \"job1\";\n  service1.host = \"localhost\";\n  service1.port = \"8080\";\n  cluster_def.services[\"alice\"][\"job1\"] = service1;\n\n  // Test: Should return first service regardless of job_id\n  std::string result = GetPartyHost(cluster_def, \"alice\", \"nonexistent_job\");\n  EXPECT_EQ(result, \"localhost\");\n}\n\nTEST(KpadTaskHelperTest, GetPartyHostPartyFailure) {\n  ClusterDef cluster_def;\n  cluster_def.self_party = \"alice\";\n\n  Service service;\n  service.name = \"job1\";\n  service.host = \"localhost\";\n  service.port = \"8080\";\n  cluster_def.services[\"alice\"][\"job1\"] = service;\n\n  // Test: Non-existent party should return empty string\n  std::string result = GetPartyHost(cluster_def, \"bob\", \"job1\");\n  EXPECT_EQ(result, \"\");\n}\n\nTEST(KpadTaskHelperTest, BuildJobStartParamsSuccess) {\n  ClusterDef cluster_def;\n  cluster_def.self_party = \"alice\";\n\n  Service service;\n  service.name = \"job1\";\n  service.host = \"localhost\";\n  service.port = \"8080\";\n  cluster_def.services[\"alice\"][\"job1\"] = service;\n\n  Service bob_service;\n  bob_service.name = \"job1\";\n  bob_service.host = \"localhost\";\n  bob_service.port = \"8081\";\n  cluster_def.services[\"bob\"][\"job1\"] = bob_service;\n\n  scql::pb::ScqlConfig scql_config;\n  scql_config.add_parties(\"alice\");\n  scql_config.add_parties(\"bob\");\n\n  auto job_params = BuildJobStartParams(cluster_def, scql_config, \"job1\");\n  EXPECT_NE(job_params, nullptr);\n  EXPECT_EQ(job_params->job_id(), \"job1\");\n  EXPECT_EQ(job_params->party_code(), \"alice\");\n  EXPECT_EQ(job_params->parties_size(), 2);\n  EXPECT_EQ(job_params->parties(0).code(), \"alice\");\n  EXPECT_EQ(job_params->parties(0).host(), \"localhost\");\n  EXPECT_EQ(job_params->parties(1).code(), \"bob\");\n  EXPECT_EQ(job_params->parties(1).host(), \"localhost\");\n}\n\nTEST(KpadTaskHelperTest, BuildJobStartParamsFailure) {\n  ClusterDef cluster_def;\n  cluster_def.self_party = \"alice\";\n\n  // Only add alice service, not bob\n  Service service;\n  service.name = \"job1\";\n  service.host = \"localhost\";\n  service.port = \"8080\";\n  cluster_def.services[\"alice\"][\"job1\"] = service;\n\n  scql::pb::ScqlConfig scql_config;\n  scql_config.add_parties(\"alice\");\n  scql_config.add_parties(\"bob\");  // bob is missing from services\n\n  auto job_params = BuildJobStartParams(cluster_def, scql_config, \"job1\");\n  EXPECT_EQ(job_params, nullptr);\n}\n\nstruct ValidateParamsTestCase {\n  std::string cluster_def;\n  std::string job_id;\n  std::string scql_config;\n  bool expected;\n  std::string description;\n};\n\nclass ValidateKpadTaskParamsTest\n    : public testing::TestWithParam<ValidateParamsTestCase> {};\n\nTEST_P(ValidateKpadTaskParamsTest, Validate) {\n  const auto& tc = GetParam();\n  EXPECT_EQ(ValidateKpadTaskParams(tc.cluster_def, tc.job_id, tc.scql_config),\n            tc.expected)\n      << \"Failed for case: \" << tc.description;\n}\n\nINSTANTIATE_TEST_SUITE_P(\n    KpadTaskHelper, ValidateKpadTaskParamsTest,\n    testing::Values(\n        ValidateParamsTestCase{\"\", \"\", \"\", true, \"all empty (broker mode)\"},\n        ValidateParamsTestCase{\"cluster_def\", \"job_id\", \"scql_config\", true,\n                               \"all non-empty (kpad mode)\"},\n        ValidateParamsTestCase{\"\", \"job_id\", \"scql_config\", false,\n                               \"missing cluster_def\"},\n        ValidateParamsTestCase{\"cluster_def\", \"\", \"scql_config\", false,\n                               \"missing job_id\"},\n        ValidateParamsTestCase{\"cluster_def\", \"job_id\", \"\", false,\n                               \"missing scql_config\"},\n        ValidateParamsTestCase{\"cluster_def\", \"\", \"\", false,\n                               \"only cluster_def\"},\n        ValidateParamsTestCase{\"\", \"job_id\", \"\", false, \"only job_id\"},\n        ValidateParamsTestCase{\"\", \"\", \"scql_config\", false,\n                               \"only scql_config\"}));\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/logging.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/logging.h\"\n\n#include \"butil/file_util.h\"\n#include \"fmt/base.h\"\n#include \"spdlog/sinks/rotating_file_sink.h\"\n#include \"spdlog/sinks/stdout_color_sinks.h\"\n#include \"spdlog/spdlog.h\"\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine::util {\n\n// clang-format off\n/// custom formatting:\n/// https://github.com/gabime/spdlog/wiki/3.-Custom-formatting\n/// example: ```2019-11-29 06:58:54.633 [info] [log_test.cpp:TestBody:16] The answer is 42.```\n// clang-format on\nstatic const char* kFormatPattern =\n    \"%Y-%m-%d %H:%M:%S.%e [%l] [%s:%!:%#] [%n] %v\";\n\nstatic const char* kDetailLogFormatPattern = \"%v\";\n\nnamespace {\n\nconst char* kBrpcUnknownFuncname = \"BRPC\";\n\nspdlog::level::level_enum FromBrpcLogSeverity(int severity) {\n  spdlog::level::level_enum level = spdlog::level::off;\n  if (severity == ::logging::BLOG_INFO) {\n    level = spdlog::level::debug;\n  } else if (severity == ::logging::BLOG_NOTICE) {\n    level = spdlog::level::info;\n  } else if (severity == ::logging::BLOG_WARNING) {\n    level = spdlog::level::warn;\n  } else if (severity == ::logging::BLOG_ERROR) {\n    level = spdlog::level::err;\n  } else if (severity == ::logging::BLOG_FATAL) {\n    level = spdlog::level::critical;\n  } else {\n    level = spdlog::level::warn;\n  }\n  return level;\n}\n\nclass EnginelogSink : public ::logging::LogSink {\n public:\n  bool OnLogMessage(int severity, const char* file, int line,\n                    const butil::StringPiece& log_content) override {\n    spdlog::level::level_enum log_level = FromBrpcLogSeverity(severity);\n    spdlog::log(spdlog::source_loc{file, line, kBrpcUnknownFuncname}, log_level,\n                \"{}\", fmt::string_view(log_content.data(), log_content.size()));\n    return true;\n  }\n};\n\nvoid SinkBrpcLogWithDefaultLogger() {\n  static EnginelogSink nlog_sink;\n  ::logging::SetLogSink(&nlog_sink);\n  ::logging::SetMinLogLevel(::logging::BLOG_NOTICE);\n}\n\nauto GetConsoleSink() {\n  // sinks should be the same as the default logger\n  // If different loggers aim to write to the same output file, all of them\n  // must share the same sink. Otherwise there will be undefined behaviors.\n  static auto console_sink =\n      std::make_shared<spdlog::sinks::stdout_color_sink_mt>();\n  return console_sink;\n}\n\n}  // namespace\n\nstd::shared_ptr<spdlog::logger> CreateLogger(\n    const std::string& logger_name, const std::string& logger_file_name,\n    const LogOptions& opts, const std::string& formatter) {\n  // 1. mkdir logs/ if not exists\n  const butil::FilePath logs_dir{opts.log_dir};\n  {\n    butil::File::Error error;\n    YACL_ENFORCE(butil::CreateDirectoryAndGetError(logs_dir, &error),\n                 \"Failed to create directory={}: {}\", logs_dir.value(),\n                 butil::File::ErrorToString(error));\n  }\n\n  // 2. setup scqlengine logger, make it default\n  auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(\n      logs_dir.Append(logger_file_name).value(), opts.max_log_file_size,\n      opts.max_log_file_count);\n\n  std::vector<spdlog::sink_ptr> sinks{file_sink};\n  if (opts.enable_console_logger) {\n    sinks.push_back(GetConsoleSink());\n  }\n\n  auto logger =\n      std::make_shared<spdlog::logger>(logger_name, sinks.begin(), sinks.end());\n  auto level = spdlog::level::from_str(opts.log_level);\n  logger->set_level(level);\n  logger->set_pattern(formatter);\n  logger->flush_on(spdlog::level::info);\n  return logger;\n}\n\nstd::shared_ptr<spdlog::logger> CreateLogger(\n    const std::string& logger_name, const std::string& logger_file_name,\n    const LogOptions& opts) {\n  return CreateLogger(logger_name, logger_file_name, opts, kFormatPattern);\n}\n\nvoid SetupLogger(const LogOptions& opts) {\n  spdlog::set_default_logger(\n      CreateLogger(\"scqlengine\", \"scqlengine.log\", opts, kFormatPattern));\n\n  // sink brpc log.\n  SinkBrpcLogWithDefaultLogger();\n}\n\nstd::shared_ptr<spdlog::logger> CreateDetailLogger(\n    const std::string& logger_name, const std::string& logger_file_name,\n    const LogOptions& opts) {\n  return CreateLogger(logger_name, logger_file_name, opts,\n                      kDetailLogFormatPattern);\n}\n\nstd::shared_ptr<spdlog::logger> DupDefaultLogger(\n    const std::string& logger_name) {\n  auto default_logger = spdlog::default_logger();\n  auto default_sinks = default_logger->sinks();\n\n  auto new_logger = std::make_shared<spdlog::logger>(\n      logger_name, default_sinks.begin(), default_sinks.end());\n  new_logger->set_level(default_logger->level());\n  new_logger->set_pattern(kFormatPattern);\n  new_logger->flush_on(spdlog::level::info);\n\n  return new_logger;\n}\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/logging.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n#include <string>\n\n#include \"spdlog/logger.h\"\n\nnamespace scql::engine::util {\n\nstruct LogOptions {\n  bool enable_console_logger = false;\n  bool enable_psi_detail_logger = false;\n  bool enable_session_logger_separation = false;\n  std::string log_dir = \"logs\";\n  size_t max_log_file_size = 500 * 1024 * 1024;\n  size_t max_log_file_count = 10;\n  std::string log_level = \"info\";\n};\n\n// Setup default logger \"scqlengine\", and use it to sink brpc log.\nvoid SetupLogger(const LogOptions& opts = LogOptions());\n\nstd::shared_ptr<spdlog::logger> CreateDetailLogger(\n    const std::string& logger_name, const std::string& logger_file_name,\n    const LogOptions& opts = LogOptions());\n\nstd::shared_ptr<spdlog::logger> DupDefaultLogger(\n    const std::string& logger_name);\n\nstd::shared_ptr<spdlog::logger> CreateLogger(\n    const std::string& logger_name, const std::string& logger_file_name,\n    const LogOptions& opts);\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/ndarray_to_arrow.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/ndarray_to_arrow.h\"\n\n#include \"arrow/array/util.h\"\n#include \"arrow/type_traits.h\"\n#include \"arrow/util/bit_util.h\"\n#include \"arrow/util/bitmap_generate.h\"\n#include \"arrow/visit_type_inline.h\"\n#include \"libspu/core/xt_helper.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/type.h\"\n\nnamespace scql::engine::util {\n\nnamespace {\n\n/// @brief Conversion from spu NdArrayRef to Arrow format.\n// Inspired by arrow NumPyConverter:\n// https://github.com/apache/arrow/blob/6773da12bbc3c7c5ba96f10f76b31dda3c1c2bc8/cpp/src/arrow/python/numpy_to_arrow.cc#L181\nclass NdArrayConverter {\n public:\n  NdArrayConverter(const spu::NdArrayRef& arr, const spu::NdArrayRef* validity)\n      : pool_(arrow::default_memory_pool()),\n        arr_(arr),\n        validity_(validity),\n        pt_type_(spu::PT_INVALID),\n        type_(nullptr),\n        null_bitmap_(nullptr) {\n    length_ = arr_.numel();\n  }\n\n  arrow::Status Convert();\n  const arrow::ArrayVector& GetResult() const { return out_arrays_; }\n\n  template <typename T>\n  arrow::enable_if_primitive_ctype<T, arrow::Status> Visit(const T& type) {\n    return VisitNative<T>();\n  }\n  // default case\n  static arrow::Status Visit(const arrow::DataType& type) {\n    return arrow::Status::NotImplemented(fmt::format(\n        \"NdArrayConverter doesn't implement <{}> conversion\", type.ToString()));\n  }\n\n  bool IsStrided() const { return arr_.strides()[0] != 1; }\n\n protected:\n  /// @returns null count\n  /// returns -1 if @param[in] validity is invalid\n  static int64_t ValidityToBitmap(const spu::NdArrayRef* validity,\n                                  int64_t length, uint8_t* bitmap) {\n    int64_t null_count = 0;\n    try {\n      auto xt_validity = spu::xt_adapt<uint8_t>(*validity);\n      for (int64_t i = 0; i < length; ++i) {\n        if (xt_validity[i] > 0) {\n          arrow::bit_util::SetBit(bitmap, i);\n        } else {\n          ++null_count;\n          arrow::bit_util::ClearBit(bitmap, i);\n        }\n      }\n    } catch (...) {\n      // invalid validity\n      return -1;\n    }\n\n    return null_count;\n  }\n\n  arrow::Status InitNullBitmap() {\n    int64_t null_bytes = arrow::bit_util::BytesForBits(length_);\n    ARROW_ASSIGN_OR_RAISE(null_bitmap_,\n                          arrow::AllocateResizableBuffer(null_bytes, pool_));\n    std::memset(null_bitmap_->mutable_data(), 0,\n                static_cast<size_t>(null_bytes));\n    null_bitmap_data_ = null_bitmap_->mutable_data();\n    return arrow::Status::OK();\n  }\n\n  template <typename ArrowType>\n  arrow::Status ConvertData(std::shared_ptr<arrow::Buffer>* data) {\n    // strides only make sense when numel > 1\n    if (arr_.numel() > 1 && IsStrided()) {\n      return arrow::Status::NotImplemented(\n          \"NdArrayConverter doesn't support strided arrays\");\n    }\n\n    if (pt_type_ == spu::PT_I1) {\n      int64_t nbytes = arrow::bit_util::BytesForBits(length_);\n      ARROW_ASSIGN_OR_RAISE(auto buffer, arrow::AllocateBuffer(nbytes, pool_));\n\n      auto xt_values = spu::xt_adapt<bool>(arr_);\n      uint64_t i = 0;\n      const auto generator = [&xt_values, &i]() -> bool {\n        return xt_values[i++];\n      };\n      arrow::internal::GenerateBitsUnrolled(buffer->mutable_data(), 0, length_,\n                                            generator);\n\n      *data = std::move(buffer);\n      return arrow::Status::OK();\n    }\n\n    // zero-copy\n    *data = std::make_shared<NdArrayRefBuffer>(arr_.buf());\n    return arrow::Status::OK();\n  }\n\n  arrow::Status PushArray(const std::shared_ptr<arrow::ArrayData>& data) {\n    out_arrays_.emplace_back(arrow::MakeArray(data));\n    return arrow::Status::OK();\n  }\n\n  template <typename ArrowType>\n  arrow::Status VisitNative() {\n    if (validity_ != nullptr) {\n      ARROW_RETURN_NOT_OK(InitNullBitmap());\n      null_count_ = ValidityToBitmap(validity_, length_, null_bitmap_data_);\n      if (null_count_ == -1) {\n        return arrow::Status::Invalid(\"invalid validity type\");\n      }\n    } else {\n      null_count_ = 0;\n      null_bitmap_ = nullptr;\n      null_bitmap_data_ = nullptr;\n    }\n\n    std::shared_ptr<arrow::Buffer> data;\n    ARROW_RETURN_NOT_OK(ConvertData<ArrowType>(&data));\n\n    auto arr_data = arrow::ArrayData::Make(type_, length_, {null_bitmap_, data},\n                                           null_count_, 0);\n    return PushArray(arr_data);\n  }\n\n private:\n  arrow::MemoryPool* pool_;\n\n  const spu::NdArrayRef& arr_;\n  const spu::NdArrayRef* validity_;\n  spu::PtType pt_type_;\n\n  int64_t length_;\n  std::shared_ptr<arrow::DataType> type_;\n\n  // Used in visitor pattern\n  arrow::ArrayVector out_arrays_;\n\n  std::shared_ptr<arrow::ResizableBuffer> null_bitmap_;\n  uint8_t* null_bitmap_data_ = nullptr;\n  int64_t null_count_ = 0;\n};\n\narrow::Status NdArrayConverter::Convert() {\n  // Question: should we handle 0-dimension (scalar) case here?\n  if (arr_.ndim() != 1) {\n    return arrow::Status::Invalid(\n        \"only handle 1-dimensional NdArrayRef arrays\");\n  }\n\n  pt_type_ = arr_.eltype().as<spu::PtTy>()->pt_type();\n\n  type_ = SpuPtTypeToArrowDataType(pt_type_);\n\n  if (type_ == nullptr) {\n    return arrow::Status::Invalid(fmt::format(\"unsupported spu::PtType {}\",\n                                              spu::GetPtTypeName(pt_type_)));\n  }\n\n  // Visit the type to perform conversion\n  return arrow::VisitTypeInline(*type_, this);\n}\n\n}  // namespace\n\nNdArrayRefBuffer::NdArrayRefBuffer(std::shared_ptr<yacl::Buffer> buf)\n    : arrow::Buffer(nullptr, 0), buf_(std::move(buf)) {\n  is_mutable_ = false;\n  data_ = buf_->data<const uint8_t>();\n  size_ = buf_->size();\n  capacity_ = size_;\n  is_cpu_ = true;\n}\n\nstd::shared_ptr<arrow::ChunkedArray> NdArrayToArrow(\n    const spu::NdArrayRef& arr, const spu::NdArrayRef* validity) {\n  NdArrayConverter converter(arr, validity);\n  THROW_IF_ARROW_NOT_OK(converter.Convert());\n  return std::make_shared<arrow::ChunkedArray>(converter.GetResult());\n}\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/ndarray_to_arrow.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"arrow/buffer.h\"\n#include \"arrow/chunked_array.h\"\n#include \"libspu/core/ndarray_ref.h\"\n\nnamespace scql::engine::util {\n\nclass NdArrayRefBuffer : public arrow::Buffer {\n public:\n  explicit NdArrayRefBuffer(std::shared_ptr<yacl::Buffer> buf);\n\n  ~NdArrayRefBuffer() = default;\n\n private:\n  std::shared_ptr<yacl::Buffer> buf_;\n};\n\n/// @brief Convert spu NdArrayRef to arrow array\nstd::shared_ptr<arrow::ChunkedArray> NdArrayToArrow(\n    const spu::NdArrayRef& arr, const spu::NdArrayRef* validity = nullptr);\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/prefix_sum.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/prefix_sum.h\"\n\n#include \"absl/numeric/bits.h\"\n#include \"libspu/kernel/hlo/indexing.h\"\n\nnamespace scql::engine::util {\n\nnamespace {\n\nusing IndexTuple = std::pair<spu::Index, spu::Index>;\nusing ScanFnParallel = std::function<void(IndexTuple&)>;\n\n// Implements the most naive version of prefix sum tree structure.\n// Refer to\n// \"Circuit representation of a work-efficient 16-input parallel prefix sum\"\n// https://en.wikipedia.org/wiki/Prefix_sum#/media/File:Prefix_sum_16.svg\nvoid ScanParallel(std::size_t n, const ScanFnParallel& parallel_fn) {\n  size_t k = absl::bit_width(n - 1U);\n\n  if (n < 2) {\n    return;\n  }\n\n  for (size_t i = 1; i < (k + 1); i++) {\n    IndexTuple it;\n    for (size_t j = ((1 << i) - 1); j < n; j += (1 << i)) {\n      it.first.emplace_back(j);\n      it.second.emplace_back(j - (1 << (i - 1)));\n    }\n    if (!it.first.empty()) {\n      parallel_fn(it);\n    }\n  }\n\n  for (size_t i = (k - 1); i > 0; i--) {\n    IndexTuple it;\n    for (size_t j = (3 * (1 << (i - 1)) - 1); j < n; j += (1 << i)) {\n      it.first.emplace_back(j);\n      it.second.emplace_back(j - (1 << (i - 1)));\n    }\n\n    if (!it.first.empty()) {\n      parallel_fn(it);\n    }\n  }\n}\n\n}  // namespace\n\n// Reference: \"Scape: Scalable Collaborative Analytics System on Private\n// Database with Malicious Security\", Fig. 13\n//\n// @param[origin_group_mask] 0 means start of the group while 1 means other\n// conditions\nspu::Value Scan(spu::SPUContext* ctx, const spu::Value& origin_value,\n                const spu::Value& origin_group_mask, const ScanFn& scan_fn) {\n  spu::Value value = origin_value.clone();\n  spu::Value group_mask = origin_group_mask.clone();\n  auto parallel_scan_fn = [&](IndexTuple& index_tuple) {\n    auto lhs_v = spu::kernel::hlo::LinearGather(ctx, value, index_tuple.first);\n    auto lhs_gm =\n        spu::kernel::hlo::LinearGather(ctx, group_mask, index_tuple.first);\n\n    auto rhs_v = spu::kernel::hlo::LinearGather(ctx, value, index_tuple.second);\n    auto rhs_gm =\n        spu::kernel::hlo::LinearGather(ctx, group_mask, index_tuple.second);\n\n    const auto [new_v, new_gm] = scan_fn(lhs_v, lhs_gm, rhs_v, rhs_gm);\n\n    YACL_ENFORCE_EQ(value.dtype(), new_v.dtype());\n    YACL_ENFORCE_EQ(group_mask.dtype(), new_gm.dtype());\n\n    spu::kernel::hlo::LinearScatterInPlace(ctx, value, new_v,\n                                           index_tuple.first);\n    spu::kernel::hlo::LinearScatterInPlace(ctx, group_mask, new_gm,\n                                           index_tuple.first);\n  };\n  ScanParallel(origin_value.shape()[0], parallel_scan_fn);\n  return value;\n}\n\n};  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/prefix_sum.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <functional>\n\n#include \"libspu/core/context.h\"\n\nnamespace scql::engine::util {\n\nusing ScanFn = std::function<std::pair<spu::Value, spu::Value>(\n    const spu::Value&, const spu::Value&, const spu::Value&,\n    const spu::Value&)>;\n\n// Reference: \"Scape: Scalable Collaborative Analytics System on Private\n// Database with Malicious Security\", Fig. 13\nspu::Value Scan(spu::SPUContext* ctx, const spu::Value& origin_value,\n                const spu::Value& origin_group_mask, const ScanFn& scan_fn);\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/progress_util.h",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <cstddef>\n#include <mutex>\n#include <string>\n#include <vector>\n\n#include \"fmt/format.h\"\n\nnamespace scql::engine::util {\nclass ProgressStats {\n public:\n  ProgressStats() = default;\n\n  virtual void IncExecutedNodes() = 0;\n  virtual void IncExecutedBatch() = 0;\n  virtual void IncExecutedPipeline() = 0;\n  virtual void SetBatchCntInPipeline(size_t cnt) = 0;\n  virtual size_t GetExecutedNodes() = 0;\n  virtual size_t GetNodesCnt() = 0;\n  virtual std::string Summary() = 0;\n\n  virtual std::pair<std::chrono::time_point<std::chrono::system_clock>,\n                    std::string>\n  GetCurrentNodeInfo() = 0;\n\n  virtual void SetCurrentNodeInfo(\n      std::chrono::time_point<std::chrono::system_clock> start_time,\n      const std::string& name) = 0;\n};\n\nclass DefaultProgressStats : public ProgressStats {\n public:\n  DefaultProgressStats() = default;\n\n  void IncExecutedNodes() override {}\n  void IncExecutedBatch() override {}\n  void IncExecutedPipeline() override {}\n  void SetBatchCntInPipeline(size_t cnt) override {}\n  size_t GetNodesCnt() override { return 0; }\n  size_t GetExecutedNodes() override { return 0; }\n  std::pair<std::chrono::time_point<std::chrono::system_clock>, std::string>\n  GetCurrentNodeInfo() override {\n    return std::make_pair(std::chrono::system_clock::now(), \"\");\n  }\n  std::string Summary() override { return \"\"; }\n  void SetCurrentNodeInfo(\n      std::chrono::time_point<std::chrono::system_clock> start_time,\n      const std::string& name) override {}\n};\n\nclass NormalProgressStats : public ProgressStats {\n public:\n  explicit NormalProgressStats(size_t total_nodes_cnt)\n      : total_nodes_cnt_(total_nodes_cnt) {}\n\n  void IncExecutedNodes() override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    executed_nodes_cnt_++;\n  }\n  void IncExecutedBatch() override {}\n  void IncExecutedPipeline() override {}\n  void SetBatchCntInPipeline(size_t cnt) override {}\n  size_t GetNodesCnt() override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    return total_nodes_cnt_;\n  }\n  size_t GetExecutedNodes() override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    return executed_nodes_cnt_;\n  }\n  std::pair<std::chrono::time_point<std::chrono::system_clock>, std::string>\n  GetCurrentNodeInfo() override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    return std::make_pair(node_start_time_, current_node_name_);\n  }\n  std::string Summary() override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    return fmt::format(\"stages executed {}/{}\", executed_nodes_cnt_,\n                       total_nodes_cnt_);\n  }\n  void SetCurrentNodeInfo(\n      std::chrono::time_point<std::chrono::system_clock> start_time,\n      const std::string& name) override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    node_start_time_ = start_time;\n    current_node_name_ = name;\n  }\n\n private:\n  size_t total_nodes_cnt_ = 0;\n  size_t executed_nodes_cnt_ = 0;\n  mutable std::mutex progress_mutex_;\n  std::string current_node_name_;\n  std::chrono::time_point<std::chrono::system_clock> node_start_time_;\n};\n\nclass BatchedProgressStats : public ProgressStats {\n public:\n  explicit BatchedProgressStats(const std::vector<size_t>& node_cnt_in_pipeline)\n      : node_cnt_in_pipeline_(node_cnt_in_pipeline) {\n    for (auto cnt : node_cnt_in_pipeline_) {\n      total_nodes_cnt_ += cnt;\n    }\n  }\n\n  void IncExecutedNodes() override {}\n  void IncExecutedBatch() override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    executed_batch_cnt_in_pipeline_++;\n  }\n  void IncExecutedPipeline() override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    executed_nodes_cnt_ += node_cnt_in_pipeline_[executed_pipeline_cnt_];\n    executed_pipeline_cnt_++;\n    executed_batch_cnt_in_pipeline_ = 0;\n    batch_cnt_in_pipeline_ = 0;\n  }\n\n  void SetBatchCntInPipeline(size_t cnt) override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    batch_cnt_in_pipeline_ = cnt;\n  }\n\n  size_t GetNodesCnt() override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    return total_nodes_cnt_;\n  }\n  size_t GetExecutedNodes() override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    return executed_nodes_cnt_;\n  }\n  std::pair<std::chrono::time_point<std::chrono::system_clock>, std::string>\n  GetCurrentNodeInfo() override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    return std::make_pair(node_start_time_, current_node_name_);\n  }\n  std::string Summary() override {\n    return fmt::format(\n        \"executed pipeline:{}/{} executed batch:{}/{} \"\n        \"node:{} in current pipeline {}\",\n        executed_pipeline_cnt_, node_cnt_in_pipeline_.size(),\n        executed_batch_cnt_in_pipeline_, batch_cnt_in_pipeline_,\n        current_node_name_, executed_pipeline_cnt_ + 1);\n  }\n  void SetCurrentNodeInfo(\n      std::chrono::time_point<std::chrono::system_clock> start_time,\n      const std::string& name) override {\n    std::lock_guard<std::mutex> guard(progress_mutex_);\n    node_start_time_ = start_time;\n    current_node_name_ = name;\n  }\n\n private:\n  std::vector<size_t> node_cnt_in_pipeline_;\n  std::size_t executed_pipeline_cnt_ = 0;\n  std::size_t executed_batch_cnt_in_pipeline_ = 0;\n  size_t total_nodes_cnt_ = 0;\n  size_t executed_nodes_cnt_ = 0;\n  std::size_t batch_cnt_in_pipeline_ = 0;\n  mutable std::mutex progress_mutex_;\n  std::string current_node_name_;\n  std::chrono::time_point<std::chrono::system_clock> node_start_time_;\n};\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/prometheus_monitor.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/prometheus_monitor.h\"\n\n#include \"prometheus/detail/builder.h\"\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine::util {\n\nPrometheusMonitor::PrometheusMonitor() {\n  metrics_registry_ = std::make_unique<prometheus::Registry>();\n  // add default metric\n  stats_ = std::make_unique<Stats>(*metrics_registry_);\n}\n\nPrometheusMonitor::Stats::Stats(prometheus::Registry& registry)\n    : session_number_total(\n          ::prometheus::BuildGauge()\n              .Name(\"engine_concurrent_session_total\")\n              .Help(\"The concurrent session nums running in engine\")\n              .Register(registry)\n              .Add({})) {}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/prometheus_monitor.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <memory>\n\n#include \"prometheus/gauge.h\"\n#include \"prometheus/registry.h\"\n\nnamespace scql::engine::util {\n\nclass PrometheusMonitor {\n public:\n  static PrometheusMonitor* GetInstance() {\n    static PrometheusMonitor t;\n    return &t;\n  }\n\n  PrometheusMonitor(const PrometheusMonitor&) = delete;\n  PrometheusMonitor& operator=(const PrometheusMonitor&) = delete;\n\n  prometheus::Registry* GetRegistry() { return metrics_registry_.get(); }\n\n  // Metrics funcs\n  void IncSessionNumberTotal() { stats_->session_number_total.Increment(); }\n  void DecSessionNumberTotal() { stats_->session_number_total.Decrement(); }\n\n private:\n  PrometheusMonitor();\n\n  struct Stats {\n    prometheus::Gauge& session_number_total;\n\n    explicit Stats(prometheus::Registry& registry);\n  };\n  std::unique_ptr<Stats> stats_;\n\n  std::unique_ptr<prometheus::Registry> metrics_registry_;\n};\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/psi/BUILD.bazel",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nload(\"//engine/bazel:scql.bzl\", \"scql_cc_test\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncc_library(\n    name = \"common\",\n    srcs = [\"common.cc\"],\n    hdrs = [\"common.h\"],\n    deps = [\n        \"//engine/framework:exec\",\n        \"@psi//psi/utils:serialize\",\n        \"@spdlog\",\n    ],\n)\n\ncc_library(\n    name = \"batch_provider\",\n    srcs = [\"batch_provider.cc\"],\n    hdrs = [\"batch_provider.h\"],\n    deps = [\n        \":common\",\n        \"//engine/core:primitive_builder\",\n        \"//engine/core:tensor\",\n        \"//engine/core:tensor_slice\",\n        \"//engine/util:stringifier\",\n        \"//engine/util:tensor_util\",\n        \"@psi//psi/utils:arrow_csv_batch_provider\",\n        \"@psi//psi/utils:batch_provider\",\n        \"@psi//psi/utils:hash_bucket_cache\",\n        \"@yacl//yacl/link\",\n    ],\n)\n\nscql_cc_test(\n    name = \"batch_provider_test\",\n    srcs = [\"batch_provider_test.cc\"],\n    deps = [\n        \":batch_provider\",\n    ],\n)\n\ncc_library(\n    name = \"cipher_intersection\",\n    srcs = [\"cipher_intersection.cc\"],\n    hdrs = [\"cipher_intersection.h\"],\n    deps = [\n        \":batch_provider\",\n        \":common\",\n        \"//engine/core:primitive_builder\",\n        \"//engine/core:tensor\",\n        \"//engine/util:stringifier\",\n        \"@abseil-cpp//absl/container:flat_hash_map\",\n        \"@abseil-cpp//absl/container:flat_hash_set\",\n        \"@psi//psi/algorithm/ecdh/ub_psi:ub_psi_cache\",\n        \"@psi//psi/utils:batch_provider\",\n        \"@psi//psi/utils:batch_provider_impl\",\n        \"@psi//psi/utils:ec_point_store\",\n        \"@psi//psi/utils:hash_bucket_cache\",\n        \"@spdlog\",\n        \"@yacl//yacl/link\",\n    ],\n)\n\nscql_cc_test(\n    name = \"cipher_intersection_test\",\n    srcs = [\"cipher_intersection_test.cc\"],\n    deps = [\n        \":cipher_intersection\",\n    ],\n)\n\ncc_binary(\n    name = \"cipher_intersection_bench\",\n    srcs = [\"cipher_intersection_bench.cc\"],\n    deps = [\n        \"@google_benchmark//:benchmark_main\",\n    ] + [\n        \":cipher_intersection\",\n    ],\n)\n\ncc_library(\n    name = \"ub_helper\",\n    srcs = [\"ub_helper.cc\"],\n    hdrs = [\"ub_helper.h\"],\n    deps = [\n        \":batch_provider\",\n        \":cipher_intersection\",\n        \":common\",\n        \"@psi//psi/algorithm/ecdh/ub_psi:ecdh_oprf_psi\",\n        \"@psi//psi/utils:batch_provider_impl\",\n    ],\n)\n\ncc_library(\n    name = \"detail_logger\",\n    srcs = [\"detail_logger.cc\"],\n    hdrs = [\"detail_logger.h\"],\n    deps = [\n        \"//engine/core:tensor\",\n        \"//engine/util:logging\",\n        \"//engine/util:spu_io\",\n        \"@psi//psi/algorithm/ecdh:ecdh_logger\",\n        \"@psi//psi/cryptor:ecc_cryptor\",\n    ],\n)\n"
  },
  {
    "path": "engine/util/psi/batch_provider.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/psi/batch_provider.h\"\n\n#include <cstddef>\n\n#include \"absl/strings/escaping.h\"\n#include \"gflags/gflags.h\"\n#include \"yacl/crypto/rand/rand.h\"\n\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/tensor.h\"\n#include \"engine/util/psi/common.h\"\n#include \"engine/util/tensor_util.h\"\n\nDEFINE_int64(provider_batch_size, 8192, \"batch size used in PSI Provider\");\n\nnamespace scql::engine::util {\n\nstd::vector<std::string> Combine(const std::vector<std::string>& col1,\n                                 const std::vector<std::string>& col2) {\n  std::vector<std::string> result(col1.size());\n  for (size_t i = 0; i < col1.size(); ++i) {\n    result[i] = fmt::format(\"{},{}\", col1[i], col2[i]);\n  }\n  return result;\n}\n\nBatchProvider::BatchProvider(std::vector<TensorPtr> tensors, size_t batch_size)\n    : tensors_(std::move(tensors)), idx_(0), batch_size_(batch_size) {\n  for (size_t i = 0; i < tensors_.size(); ++i) {\n    YACL_ENFORCE(tensors_[i]->GetNullCount() == 0,\n                 \"NULL value is unsupported in PSI\");\n    if (i > 0 && tensors_[i]->Length() != tensors_[0]->Length()) {\n      YACL_THROW(\"inputs must have the same size\");\n    }\n\n    stringifiers_.push_back(\n        std::make_unique<Stringifier>(tensors_[i], batch_size_));\n  }\n}\n\nstd::vector<std::string> BatchProvider::ReadNextBatch() {\n  if (tensors_.empty()) {\n    return std::vector<std::string>{};\n  }\n\n  auto keys = stringifiers_[0]->StringifyBatch();\n  if (keys.empty()) {\n    return keys;\n  }\n\n  for (size_t i = 1; i < tensors_.size(); ++i) {\n    auto another_keys = stringifiers_[i]->StringifyBatch();\n    YACL_ENFORCE(keys.size() == another_keys.size(),\n                 \"tensor #{} batch size not equals with previous\", i);\n\n    keys = Combine(keys, another_keys);\n  }\n\n  return keys;\n}\n\npsi::IShuffledBatchProvider::ShuffledBatch\nBatchProvider::ReadNextShuffledBatch() {\n  std::vector<size_t> batch_indices;\n  std::vector<size_t> shuffle_indices;\n  if (tensors_.empty()) {\n    std::vector<std::string> keys;\n    return {keys, batch_indices, shuffle_indices, {}};\n  }\n\n  auto keys = ReadNextBatch();\n  batch_indices.resize(keys.size());\n  std::iota(batch_indices.begin(), batch_indices.end(), idx_);\n\n  shuffle_indices.resize(keys.size());\n  std::iota(shuffle_indices.begin(), shuffle_indices.end(), 0);\n  std::mt19937 rng(yacl::crypto::SecureRandU64());\n  std::shuffle(shuffle_indices.begin(), shuffle_indices.end(), rng);\n  std::vector<std::string> shuffled_keys(keys.size());\n  for (size_t i = 0; i < keys.size(); ++i) {\n    shuffled_keys[i].swap(keys[shuffle_indices[i]]);\n  }\n  keys.swap(shuffled_keys);\n  for (size_t i = 0; i < keys.size(); ++i) {\n    shuffle_indices[i] += idx_;\n  }\n\n  idx_ += keys.size();\n\n  return {keys, batch_indices, shuffle_indices,\n          std::vector<uint32_t>(keys.size(), 0)};\n}\n\nvoid BucketProvider::InitBucket(\n    const std::shared_ptr<yacl::link::Context>& lctx, size_t self_size,\n    size_t peer_size) {\n  is_bucket_tensor_ = AreAllBucketTensor(tensors_);\n  if (is_bucket_tensor_) {\n    for (auto& tensor : tensors_) {\n      tensor_slices_.push_back(CreateTensorSlice(tensor));\n    }\n    bucket_num_ = tensor_slices_[0]->GetSliceNum();\n    bucket_items_.resize(bucket_num_);\n    bucket_dup_idx_.resize(bucket_num_);\n    return;\n  }\n  auto bucket_size =\n      std::min(kBucketSize, util::ExchangeSetSize(lctx, kBucketSize));\n  size_t bucket_num =\n      (std::max(self_size, peer_size) + bucket_size - 1) / bucket_size;\n  bucket_num = std::max(bucket_num, static_cast<size_t>(1));\n  bucket_items_.resize(bucket_num);\n  bucket_dup_idx_.resize(bucket_num);\n  BatchProvider batch_provider(tensors_);\n  while (true) {\n    auto inputs = batch_provider.ReadNextBatch();\n    if (inputs.empty()) {\n      break;\n    }\n    for (auto& in_str : inputs) {\n      auto base64_data = absl::Base64Escape(in_str);\n      bucket_items_[std::hash<std::string>()(base64_data) % bucket_num]\n          .emplace_back(base64_data, item_index_);\n      item_index_++;\n    }\n  }\n  bucket_num_ = bucket_items_.size();\n}\n\nstd::vector<BucketProvider::DataPair> BucketProvider::GetBucketIdx(size_t idx) {\n  YACL_ENFORCE(idx < bucket_num_);\n  if (!is_bucket_tensor_) {\n    return bucket_items_[idx];\n  }\n  std::vector<TensorPtr> bucket_ts(tensor_slices_.size());\n  for (size_t i = 0; i < bucket_ts.size(); i++) {\n    auto t = tensor_slices_[i]->GetSlice(idx);\n    if (t == nullptr) {\n      break;\n    }\n    bucket_ts[i] = t;\n  }\n  std::vector<DataPair> bucket_items;\n  BatchProvider batch_provider(bucket_ts);\n  size_t item_index_ = 0;\n  while (true) {\n    auto inputs = batch_provider.ReadNextBatch();\n    if (inputs.empty()) {\n      break;\n    }\n    for (auto& in_str : inputs) {\n      auto base64_data = absl::Base64Escape(in_str);\n      bucket_items.emplace_back(base64_data, item_index_);\n      item_index_++;\n    }\n  }\n  return bucket_items;\n}\n\nstd::vector<psi::HashBucketCache::BucketItem>\nBucketProvider::GetDeDupItemsInBucket(size_t idx) {\n  auto items = GetBucketIdx(idx);\n  if (items.size() == 0) {\n    return {};\n  }\n  std::vector<psi::HashBucketCache::BucketItem> bucket_items;\n  std::unordered_map<std::string, std::vector<size_t>> cur_bucket_dup_idx;\n  for (auto& item : items) {\n    const auto& iter = cur_bucket_dup_idx.find(item.first);\n    if (iter != cur_bucket_dup_idx.end()) {\n      iter->second.push_back(item.second);\n    } else {\n      cur_bucket_dup_idx.insert({item.first, {item.second}});\n      psi::HashBucketCache::BucketItem bucket_item;\n      bucket_item.index = bucket_items.size();\n      bucket_item.extra_dup_cnt = 0;\n      bucket_item.base64_data = item.first;\n      bucket_items.push_back(bucket_item);\n    }\n  }\n  for (auto& bucket_item : bucket_items) {\n    bucket_item.extra_dup_cnt =\n        cur_bucket_dup_idx[bucket_item.base64_data].size() - 1;\n  }\n  bucket_dup_idx_[idx] = std::move(cur_bucket_dup_idx);\n  return bucket_items;\n}\n\nTensorPtr BucketProvider::CalIntersection(\n    const std::shared_ptr<yacl::link::Context>& lctx, size_t bucket_idx,\n    bool is_left, int64_t join_type,\n    const std::vector<psi::HashBucketCache::BucketItem>& bucket_items,\n    const std::vector<uint32_t>& indices,\n    const std::vector<uint32_t>& peer_cnt) {\n  YACL_ENFORCE(bucket_idx < bucket_num_);\n  UInt64TensorBuilder builder;\n  TensorPtr t;\n  auto bucket_dup_idx = bucket_dup_idx_[bucket_idx];\n  for (size_t i = 0; i < indices.size(); i++) {\n    const auto& bucket_item = bucket_items[indices[i]];\n    auto dup_idx = bucket_dup_idx[bucket_item.base64_data];\n    if (is_left) {\n      for (size_t k = 0; k < peer_cnt[i] + 1; k++) {\n        for (size_t j = 0; j < dup_idx.size(); j++) {\n          builder.Append(dup_idx[j]);\n        }\n      }\n    } else {\n      for (size_t j = 0; j < dup_idx.size(); j++) {\n        for (size_t k = 0; k < peer_cnt[i] + 1; k++) {\n          builder.Append(dup_idx[j]);\n        }\n      }\n    }\n  }\n  if ((join_type == kLeftJoin && is_left) ||\n      (join_type == kRightJoin && !is_left)) {\n    size_t null_cnt = 0;\n    std::unordered_set<uint32_t> indices_set(indices.size());\n    for (const auto indice : indices) {\n      indices_set.insert(indice);\n    }\n    for (size_t i = 0; i < bucket_items.size(); i++) {\n      if (indices_set.find(i) == indices_set.end()) {\n        for (const auto idx : bucket_dup_idx[bucket_items[i].base64_data]) {\n          builder.Append(idx);\n          null_cnt++;\n        }\n      }\n    }\n    lctx->Send(lctx->NextRank(),\n               yacl::ByteContainerView(&null_cnt, sizeof(null_cnt)),\n               \"null count\");\n  } else if (join_type == kLeftJoin || join_type == kRightJoin) {\n    auto data = lctx->Recv(lctx->NextRank(), \"null count\");\n    auto* null_cnt = data.data<size_t>();\n    for (size_t i = 0; i < *null_cnt; i++) {\n      builder.AppendNull();\n    }\n  }\n  builder.Finish(&t);\n  return t;\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/psi/batch_provider.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <cstddef>\n#include <cstdint>\n#include <limits>\n#include <memory>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\n#include \"psi/utils/batch_provider.h\"\n#include \"psi/utils/hash_bucket_cache.h\"\n#include \"yacl/link/link.h\"\n\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_slice.h\"\n#include \"engine/util/stringifier.h\"\n\nnamespace scql::engine::util {\n\nusing scql::engine::TensorPtr;\nusing scql::engine::util::Stringifier;\n\n/// @brief BatchProvider combines multiple join keys into one\nclass BatchProvider : public ::psi::IBasicBatchProvider,\n                      public ::psi::IShuffledBatchProvider {\n public:\n  explicit BatchProvider(std::vector<TensorPtr> tensors,\n                         size_t batch_size = 8192);\n\n  std::vector<std::string> ReadNextBatch() override;\n\n  psi::IShuffledBatchProvider::ShuffledBatch ReadNextShuffledBatch() override;\n\n  int64_t TotalLength() const {\n    return tensors_.empty() ? 0 : tensors_[0]->Length();\n  }\n\n  size_t batch_size() const override { return batch_size_; }\n\n private:\n  std::vector<TensorPtr> tensors_;\n  std::vector<std::unique_ptr<Stringifier>> stringifiers_;\n  size_t idx_;\n  size_t batch_size_;\n};\n\nclass BucketProvider {\n public:\n  using DataPair = std::pair<std::string, size_t>;\n  explicit BucketProvider(const std::vector<TensorPtr>& tensors)\n      : tensors_(tensors) {}\n  void InitBucket(const std::shared_ptr<yacl::link::Context>& lctx,\n                  size_t self_size, size_t peer_size);\n  std::vector<DataPair> GetBucketIdx(size_t idx);\n  std::vector<psi::HashBucketCache::BucketItem> GetDeDupItemsInBucket(\n      size_t idx);\n  size_t GetBucketNum() const { return bucket_num_; }\n  bool IsBucketTensor() const { return is_bucket_tensor_; }\n  TensorPtr CalIntersection(\n      const std::shared_ptr<yacl::link::Context>& lctx, size_t bucket_idx,\n      bool is_left, int64_t join_type,\n      const std::vector<psi::HashBucketCache::BucketItem>& bucket_items,\n      const std::vector<uint32_t>& indices,\n      const std::vector<uint32_t>& peer_cnt);\n\n  std::unordered_map<std::string, std::vector<size_t>> GetDupIndices(\n      size_t bucket_idx) {\n    return bucket_dup_idx_[bucket_idx];\n  }\n\n  void CleanBucket(size_t idx) {\n    // clear memory\n    std::vector<DataPair>().swap(bucket_items_[idx]);\n    std::unordered_map<std::string, std::vector<size_t>>().swap(\n        bucket_dup_idx_[idx]);\n  }\n\n private:\n  std::vector<TensorPtr> tensors_;\n  std::vector<std::vector<DataPair>> bucket_items_;\n  size_t item_index_ = 0;\n  // bucket_dup_idx_[i][j] means base64 data to indices of the i-th bucket\n  std::vector<std::unordered_map<std::string, std::vector<size_t>>>\n      bucket_dup_idx_;\n  std::vector<std::shared_ptr<TensorSlice>> tensor_slices_;\n  bool is_bucket_tensor_ = true;\n  size_t bucket_num_ = 0;\n  static constexpr size_t kBucketSize = 1000 * 1000;\n};\n\n/// @brief combine two columns into one, just concat them together.\n/// @note current implementation will fail if there exists separator(like\n/// \",\") in columns\n/// @param[in] col1 and @param[in] col2 should have the same length.\nstd::vector<std::string> Combine(const std::vector<std::string>& col1,\n                                 const std::vector<std::string>& col2);\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/psi/batch_provider_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/psi/batch_provider.h\"\n\n#include \"gmock/gmock.h\"\n#include \"gtest/gtest.h\"\n\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/string_tensor_builder.h\"\n\nnamespace scql::engine::util {\n\nclass BatchProviderTest : public ::testing::Test {\n protected:\n  /// @returns int64 tensor [0, 1, ..., len-1]\n  static std::shared_ptr<Tensor> MakeInt64SequenceTensor(int64_t len) {\n    Int64TensorBuilder builder;\n    for (int64_t i = 0; i < len; ++i) {\n      builder.Append(i);\n    }\n    std::shared_ptr<Tensor> result;\n    builder.Finish(&result);\n    return result;\n  }\n\n  /// @returns string tensor [\"a\", \"b\", ..., \"y\", \"z\", \"a\", \"b\", ...]\n  static std::shared_ptr<Tensor> MakeAlphabetStringTensor(int64_t len) {\n    StringTensorBuilder builder;\n    for (int64_t i = 0; i < len; ++i) {\n      std::string str(1, 'a' + (i % 26));\n      builder.Append(str);\n    }\n    std::shared_ptr<Tensor> result;\n    builder.Finish(&result);\n    return result;\n  }\n};\n\nTEST_F(BatchProviderTest, singleKey) {\n  const int64_t seq_len = 10;\n  auto tensor = MakeInt64SequenceTensor(seq_len);\n\n  BatchProvider provider(std::vector<TensorPtr>{tensor});\n\n  auto batch1 = provider.ReadNextBatch();\n  EXPECT_EQ(batch1.size(), 10);\n  EXPECT_THAT(batch1, ::testing::ElementsAre(\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\",\n                                             \"7\", \"8\", \"9\"));\n\n  auto empty_batch = provider.ReadNextBatch();\n  EXPECT_EQ(empty_batch.size(), 0);\n}\n\nTEST_F(BatchProviderTest, twoKeys) {\n  const int64_t seq_len = 10;\n  auto tensor1 = MakeInt64SequenceTensor(seq_len);\n  auto tensor2 = MakeAlphabetStringTensor(seq_len);\n\n  BatchProvider provider(std::vector<TensorPtr>{tensor1, tensor2});\n\n  auto batch1 = provider.ReadNextBatch();\n  EXPECT_EQ(batch1.size(), seq_len);\n  EXPECT_THAT(batch1,\n              ::testing::ElementsAre(\"0,a\", \"1,b\", \"2,c\", \"3,d\", \"4,e\", \"5,f\",\n                                     \"6,g\", \"7,h\", \"8,i\", \"9,j\"));\n\n  auto empty_batch = provider.ReadNextBatch();\n  EXPECT_EQ(empty_batch.size(), 0);\n}\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/psi/cipher_intersection.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/psi/cipher_intersection.h\"\n\n#include \"absl/container/flat_hash_map.h\"\n#include \"absl/container/flat_hash_set.h\"\n#include \"absl/strings/escaping.h\"\n#include \"psi/utils/arrow_csv_batch_provider.h\"\n#include \"psi/utils/batch_provider.h\"\n#include \"psi/utils/hash_bucket_cache.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/primitive_builder.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/util/psi/common.h\"\n\nDECLARE_int64(provider_batch_size);\n\nnamespace scql::engine::util {\n\nvoid InResultResolver::Set(uint64_t index, bool mask) { masks_[index] = mask; }\n\nTensorPtr InResultResolver::Finalize() {\n  arrow::BooleanBuilder mask_builder;\n  THROW_IF_ARROW_NOT_OK(mask_builder.AppendValues(masks_));\n  std::shared_ptr<arrow::BooleanArray> mask;\n  THROW_IF_ARROW_NOT_OK(mask_builder.Finish(&mask));\n  arrow::ArrayVector chunks_;\n  chunks_.push_back(mask);\n  auto result = arrow::ChunkedArray::Make(chunks_, mask->type());\n  std::shared_ptr<arrow::ChunkedArray> chunked_arr;\n  THROW_IF_ARROW_NOT_OK(std::move(result).Value(&chunked_arr));\n  return TensorFrom(chunked_arr);\n}\n\nvoid UbPsiJoinCache::SaveData(yacl::ByteContainerView item, size_t index,\n                              size_t shuffle_index) {\n  if (idx_ >= seq_to_indice_.size()) {\n    YACL_THROW(\"UbPsiJoin idx out-of-bounds, idx:{} >= vector size:{}\", idx_,\n               seq_to_indice_.size());\n  }\n  seq_to_indice_[idx_++] = shuffle_index;\n}\n\nUbPsiCipherStore::UbPsiCipherStore(std::string csv_path, bool enable_cache)\n    : csv_path_(std::move(csv_path)), enable_cache_(enable_cache) {\n  out_ = psi::io::BuildOutputStream(psi::io::FileIoOptions(csv_path_));\n  YACL_ENFORCE(out_, \"Fail to build outputstream for UbPsiCipherStore\");\n  out_->Write(kDummyField);\n  out_->Write(\"\\n\");\n}\n\nUbPsiCipherStore::~UbPsiCipherStore() { out_->Close(); }\n\nvoid UbPsiCipherStore::Save(const std::string& ciphertext,\n                            uint32_t duplicate_cnt) {\n  auto escaped_ciphertext = absl::Base64Escape(ciphertext);\n  for (size_t i = 0; i < duplicate_cnt + 1; ++i) {\n    out_->Write(fmt::format(\"{}\\n\", escaped_ciphertext));\n    if (enable_cache_) {\n      data_indices_[escaped_ciphertext].push_back(item_count_);\n    }\n    ++item_count_;\n  }\n}\n\nstd::vector<std::string> FinalizeAndComputeIntersection(\n    const std::shared_ptr<UbPsiCipherStore>& client_store,\n    const std::shared_ptr<UbPsiCipherStore>& server_store) {\n  client_store->Finalize();\n  server_store->Finalize();\n\n  std::vector<std::string> fields{UbPsiCipherStore::kDummyField};\n  psi::ArrowCsvBatchProvider server_provider(server_store->GetPath(), fields,\n                                             FLAGS_provider_batch_size);\n\n  // may have duplicate items\n  std::vector<std::string> results;\n\n  while (true) {\n    auto batch_server_data = server_provider.ReadNextBatch();\n\n    if (batch_server_data.empty()) {\n      break;\n    }\n\n    for (const std::string& server_item : batch_server_data) {\n      auto search_ret = client_store->SearchIndices(server_item);\n      if (search_ret.has_value()) {\n        results.push_back(server_item);\n      }\n    }\n  }\n\n  return results;\n}\n\nvoid InResultResolverWithBucket::FeedBucketData(\n    size_t bucket_idx,\n    const std::vector<psi::HashBucketCache::BucketItem>& bucket_items,\n    const std::vector<uint32_t>& indices,\n    const std::unordered_map<std::string, std::vector<size_t>>&\n        origin_indices) {\n  // build set\n  absl::flat_hash_set<size_t> intersection_set;\n  for (const auto& indice : indices) {\n    intersection_set.emplace(indice);\n  }\n  std::unique_lock lock(mtx_);\n  for (size_t i = 0; i < bucket_items.size(); i++) {\n    const auto& bucket_item = bucket_items[i];\n    auto it = origin_indices.find(bucket_item.base64_data);\n    YACL_ENFORCE(it != origin_indices.end());\n    if (intersection_set.contains(i)) {\n      for (const auto& idx : it->second) {\n        masks_[idx] = true;\n      }\n    }\n  }\n}\n\nTensorPtr InResultResolverWithBucket::ComputeInResult() {\n  arrow::BooleanBuilder mask_builder;\n  THROW_IF_ARROW_NOT_OK(mask_builder.AppendValues(masks_));\n  std::shared_ptr<arrow::BooleanArray> mask;\n  THROW_IF_ARROW_NOT_OK(mask_builder.Finish(&mask));\n  arrow::ArrayVector chunks_;\n  chunks_.push_back(mask);\n  auto result = arrow::ChunkedArray::Make(chunks_, mask->type());\n  std::shared_ptr<arrow::ChunkedArray> chunked_arr;\n  THROW_IF_ARROW_NOT_OK(std::move(result).Value(&chunked_arr));\n  return TensorFrom(chunked_arr);\n}\n\nTensorPtr FinalizeAndComputeOprfInResult(\n    const std::shared_ptr<UbPsiCipherStore>& client_store,\n    const std::shared_ptr<UbPsiCipherStore>& server_store) {\n  client_store->Finalize();\n  server_store->Finalize();\n\n  std::unordered_set<uint64_t> client_indices;\n  BooleanTensorBuilder result_builder;\n\n  std::vector<std::string> fields{UbPsiCipherStore::kDummyField};\n  psi::ArrowCsvBatchProvider server_provider(server_store->GetPath(), fields,\n                                             FLAGS_provider_batch_size);\n\n  while (true) {\n    auto batch_server_data = server_provider.ReadNextBatch();\n\n    if (batch_server_data.empty()) {\n      break;\n    }\n\n    for (const std::string& server_item : batch_server_data) {\n      auto search_ret = client_store->SearchIndices(server_item);\n      if (search_ret.has_value()) {\n        auto indices = search_ret.value();\n        client_indices.insert(indices.begin(), indices.end());\n      }\n    }\n  }\n\n  result_builder.Reserve(static_cast<int64_t>(client_store->ItemCount()));\n  for (uint64_t client_item_idx = 0;\n       client_item_idx < client_store->ItemCount(); ++client_item_idx) {\n    if (client_indices.count(client_item_idx) > 0) {\n      result_builder.UnsafeAppend(true);\n    } else {\n      result_builder.UnsafeAppend(false);\n    }\n  }\n\n  TensorPtr result_tensor;\n  result_builder.Finish(&result_tensor);\n  return result_tensor;\n}\n\nstd::pair<TensorPtr, std::vector<uint64_t>> FinalizeAndComputeOprfJoinResult(\n    const std::shared_ptr<UbPsiCipherStore>& server_store,\n    const std::shared_ptr<UbPsiCipherStore>& client_store,\n    uint64_t* server_unmatched_count, uint64_t* client_unmatched_count) {\n  YACL_ENFORCE(\n      server_unmatched_count == nullptr || client_unmatched_count == nullptr,\n      \"at least one of server_unmatched_count and client_unmatched_count \"\n      \"should \"\n      \"be nullptr\");\n\n  server_store->Finalize();\n  client_store->Finalize();\n\n  UInt64TensorBuilder result_builder;\n  uint64_t server_seq = 0;\n  std::vector<uint64_t> matched_seqs;\n  std::unordered_set<uint64_t> matched_indices;\n\n  auto add_matched_indice_lambda = [&result_builder, &server_seq, &matched_seqs,\n                                    &matched_indices,\n                                    client_unmatched_count](uint64_t indice) {\n    result_builder.Append(indice);\n    matched_seqs.push_back(server_seq);\n    if (client_unmatched_count != nullptr) {\n      matched_indices.insert(indice);\n    }\n  };\n\n  std::vector<std::string> fields{UbPsiCipherStore::kDummyField};\n  psi::ArrowCsvBatchProvider server_provider(server_store->GetPath(), fields,\n                                             FLAGS_provider_batch_size);\n  while (true) {\n    auto batch_server_data = server_provider.ReadNextBatch();\n\n    if (batch_server_data.empty()) {\n      break;\n    }\n\n    // TODO(jingshi): search in parallel\n    for (const std::string& server_item : batch_server_data) {\n      auto search_ret = client_store->SearchIndices(server_item);\n      if (search_ret.has_value()) {\n        auto indices = search_ret.value();\n        std::for_each(indices.begin(), indices.end(),\n                      add_matched_indice_lambda);\n      } else if (server_unmatched_count != nullptr) {\n        ++(*server_unmatched_count);\n      }\n      ++server_seq;\n    }\n  }\n\n  if (client_unmatched_count != nullptr) {\n    for (uint64_t indice = 0; indice < client_store->ItemCount(); ++indice) {\n      if (matched_indices.count(indice) == 0) {\n        ++(*client_unmatched_count);\n        result_builder.Append(indice);\n      }\n    }\n  }\n  if (server_unmatched_count != nullptr) {\n    result_builder.Reserve(static_cast<int64_t>(*server_unmatched_count));\n    for (uint64_t i = 0; i < *server_unmatched_count; ++i) {\n      result_builder.UnsafeAppendNull();\n    }\n  }\n\n  TensorPtr result_tensor;\n  result_builder.Finish(&result_tensor);\n  return {result_tensor, matched_seqs};\n}\n\nTensorPtr FinalizeAndComputeJoinIndices(\n    bool is_left,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& self_cache,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& peer_cache,\n    int64_t join_type) {\n  self_cache->Flush();\n  peer_cache->Flush();\n\n  if (is_left) {\n    return ComputeJoinIndices(self_cache, peer_cache, join_type, is_left);\n  } else {\n    return ComputeJoinIndices(peer_cache, self_cache, join_type, is_left);\n  }\n}\n\nTensorPtr ComputeJoinIndices(\n    const std::shared_ptr<psi::HashBucketEcPointStore>& left,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& right,\n    int64_t join_type, bool is_left) {\n  YACL_ENFORCE(left->num_bins() == right->num_bins(),\n               \"left store num_bins={} not equal to right store num_bins={}\",\n               left->num_bins(), right->num_bins());\n  Int64TensorBuilder builder;\n  uint64_t outer_join_key_size = 0;\n  if (join_type == kLeftJoin) {\n    outer_join_key_size = static_cast<uint64_t>(left->ItemCount());\n  } else if (join_type == kRightJoin) {\n    outer_join_key_size = static_cast<uint64_t>(right->ItemCount());\n  } else if (join_type == kInnerJoin) {\n    outer_join_key_size = 0;\n  }\n  absl::flat_hash_set<int64_t> left_matched;\n  absl::flat_hash_set<int64_t> right_matched;\n  left_matched.reserve(outer_join_key_size);\n  right_matched.reserve(outer_join_key_size);\n  for (size_t bin_idx = 0; bin_idx < left->num_bins(); ++bin_idx) {\n    auto left_bucket = left->LoadBucketItems(bin_idx);\n    auto right_bucket = right->LoadBucketItems(bin_idx);\n\n    // build hash map\n    absl::flat_hash_map<std::string, std::vector<int64_t>>\n        right_key_indices_map;\n    for (const auto& right_item : right_bucket) {\n      auto& indices = right_key_indices_map[right_item.base64_data];\n      indices.push_back(static_cast<int64_t>(right_item.index));\n    }\n    // probe the hash map\n    for (const auto& left_item : left_bucket) {\n      auto iter = right_key_indices_map.find(left_item.base64_data);\n      if (iter == right_key_indices_map.end()) {\n        continue;\n      }\n\n      const auto& right_indices = iter->second;\n      for (auto right_index : right_indices) {\n        left_matched.insert(static_cast<int64_t>(left_item.index));\n        right_matched.insert(right_index);\n        if (is_left) {\n          builder.Append(static_cast<int64_t>(left_item.index));\n        } else {\n          builder.Append(right_index);\n        }\n      }\n    }\n  }\n\n  for (uint64_t index = 0; index < outer_join_key_size; index++) {\n    if (join_type == kLeftJoin &&\n        left_matched.find(index) == left_matched.end()) {\n      if (is_left) {\n        builder.Append(index);\n      } else {\n        builder.AppendNull();\n      }\n    }\n    if (join_type == kRightJoin &&\n        right_matched.find(index) == right_matched.end()) {\n      if (is_left) {\n        builder.AppendNull();\n      } else {\n        builder.Append(index);\n      }\n    }\n  }\n  TensorPtr indices;\n  builder.Finish(&indices);\n  return indices;\n}\n\nTensorPtr FinalizeAndComputeInResult(\n    bool is_left,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& self_cache,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& peer_cache) {\n  self_cache->Flush();\n  peer_cache->Flush();\n\n  if (is_left) {\n    return ComputeInResult(self_cache, peer_cache);\n  } else {\n    return ComputeInResult(peer_cache, self_cache);\n  }\n}\n\nTensorPtr ComputeInResult(\n    const std::shared_ptr<psi::HashBucketEcPointStore>& left,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& right) {\n  YACL_ENFORCE(left->num_bins() == right->num_bins(),\n               \"left store num_bins={} not equal to right store num_bins={}\",\n               left->num_bins(), right->num_bins());\n  InResultResolver resolver(left->ItemCount());\n  std::mutex mtx;\n  yacl::parallel_for(0, left->num_bins(), [&](int64_t begin, int64_t end) {\n    for (int64_t bin_idx = begin; bin_idx < end; ++bin_idx) {\n      auto left_bucket = left->LoadBucketItems(bin_idx);\n      auto right_bucket = right->LoadBucketItems(bin_idx);\n\n      // build set\n      absl::flat_hash_set<std::string> right_keys;\n      for (const auto& right_item : right_bucket) {\n        right_keys.insert(right_item.base64_data);\n      }\n      std::unique_lock lock(mtx);\n      // probe the set\n      for (const auto& left_item : left_bucket) {\n        resolver.Set(left_item.index,\n                     right_keys.contains(left_item.base64_data));\n      }\n    }\n  });\n  return resolver.Finalize();\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/psi/cipher_intersection.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <vector>\n\n#include \"psi/algorithm/ecdh/ub_psi/ub_psi_cache.h\"\n#include \"psi/utils/batch_provider.h\"\n#include \"psi/utils/ec_point_store.h\"\n#include \"psi/utils/hash_bucket_cache.h\"\n#include \"yacl/link/link.h\"\n\n#include \"engine/core/tensor.h\"\n\nnamespace scql::engine::util {\n\nclass InResultResolver {\n public:\n  explicit InResultResolver(size_t result_size) { masks_.resize(result_size); }\n  void Set(uint64_t index, bool mask);\n\n  TensorPtr Finalize();\n\n private:\n  std::vector<bool> masks_;\n};\n\nclass InResultResolverWithBucket {\n public:\n  explicit InResultResolverWithBucket(size_t result_size) {\n    masks_.resize(result_size, false);\n  }\n\n  void FeedBucketData(\n      size_t bucket_idx,\n      const std::vector<psi::HashBucketCache::BucketItem>& bucket_items,\n      const std::vector<uint32_t>& indices,\n      const std::unordered_map<std::string, std::vector<size_t>>&\n          origin_indices);\n\n  TensorPtr ComputeInResult();\n\n private:\n  std::vector<bool> masks_;\n  std::mutex mtx_;\n};\n\nclass UbPsiJoinCache : public psi::IUbPsiCache {\n public:\n  explicit UbPsiJoinCache(size_t size) : seq_to_indice_(size) {}\n  void SaveData(yacl::ByteContainerView item, size_t index,\n                size_t shuffle_index) override;\n\n  size_t GetIndice(size_t seq) { return seq_to_indice_.at(seq); }\n\n private:\n  size_t idx_ = 0;\n  std::vector<size_t> seq_to_indice_;\n};\n\nclass UbPsiCipherStore : public psi::IEcPointStore {\n public:\n  explicit UbPsiCipherStore(std::string csv_path, bool enable_cache);\n\n  ~UbPsiCipherStore() override;\n\n  void Save(const std::string& ciphertext, uint32_t duplicate_cnt) override;\n\n  void Flush() override { out_->Flush(); }\n\n  uint64_t ItemCount() override { return item_count_; }\n\n  void Finalize() { return Flush(); }\n\n  std::string GetPath() const { return csv_path_; }\n\n  std::optional<std::vector<size_t>> SearchIndices(\n      const std::string& ciphertext) {\n    auto iter = data_indices_.find(ciphertext);\n    if (iter != data_indices_.end()) {\n      return iter->second;\n    } else {\n      return {};\n    }\n  }\n\n  static inline const char* kDummyField = \"evaluated_items\";\n\n protected:\n  std::string csv_path_;\n\n  std::unordered_map<std::string, std::vector<size_t>> data_indices_;\n  size_t item_count_ = 0;\n\n private:\n  bool enable_cache_;\n  std::unique_ptr<psi::io::OutputStream> out_;\n};\n\nTensorPtr FinalizeAndComputeOprfInResult(\n    const std::shared_ptr<UbPsiCipherStore>& client_store,\n    const std::shared_ptr<UbPsiCipherStore>& server_store);\n\nstd::pair<TensorPtr, std::vector<uint64_t>> FinalizeAndComputeOprfJoinResult(\n    const std::shared_ptr<UbPsiCipherStore>& server_store,\n    const std::shared_ptr<UbPsiCipherStore>& client_store,\n    uint64_t* server_unmatched_count, uint64_t* client_unmatched_count);\n\n// param is_left represents whether myself on the left side of join\nTensorPtr FinalizeAndComputeJoinIndices(\n    bool is_left,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& self_cache,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& peer_cache,\n    int64_t join_type);\n\n/// @param[in] is_left denotes whether to compute the left join indices.\n/// it returns right join indices if is_left == false\nTensorPtr ComputeJoinIndices(\n    const std::shared_ptr<psi::HashBucketEcPointStore>& left,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& right,\n    int64_t join_type, bool is_left);\n\n/// @param[in] is_left represents whether myself on the left side of in\nTensorPtr FinalizeAndComputeInResult(\n    bool is_left,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& self_cache,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& peer_cache);\n\nTensorPtr ComputeInResult(\n    const std::shared_ptr<psi::HashBucketEcPointStore>& left,\n    const std::shared_ptr<psi::HashBucketEcPointStore>& right);\n\nstd::vector<std::string> FinalizeAndComputeIntersection(\n    const std::shared_ptr<UbPsiCipherStore>& client_store,\n    const std::shared_ptr<UbPsiCipherStore>& server_store);\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/psi/cipher_intersection_bench.cc",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <algorithm>\n#include <cstddef>\n#include <filesystem>\n#include <random>\n#include <vector>\n\n#include \"arrow/builder.h\"\n#include \"benchmark/benchmark.h\"\n#include \"yacl/crypto/rand/rand.h\"\n\n#include \"engine/util/psi/cipher_intersection.h\"\n\nstatic void BM_InCalResult(benchmark::State& state) {\n  for (auto _ : state) {\n    state.PauseTiming();\n    size_t len = state.range(0);\n    std::vector<size_t> index_v(len);\n    for (size_t i = 0; i < len; ++i) {\n      index_v[i] = i;\n    }\n    std::mt19937 rng(yacl::crypto::SecureRandU64());\n    std::shuffle(index_v.begin(), index_v.end(), rng);\n    scql::engine::util::InResultResolver resolver(len);\n    state.ResumeTiming();\n    for (const auto& idx : index_v) {\n      resolver.Set(idx, true);\n    }\n    resolver.Finalize();\n  }\n}\n\nBENCHMARK(BM_InCalResult)->Unit(benchmark::kMillisecond)->Arg(1000 * 10000);\n"
  },
  {
    "path": "engine/util/psi/cipher_intersection_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/psi/cipher_intersection.h\"\n\n#include \"gmock/gmock.h\"\n#include \"gtest/gtest.h\"\n#include \"psi/utils/ec_point_store.h\"\n\n#include \"engine/util/psi/batch_provider.h\"\n#include \"engine/util/psi/common.h\"\n\nnamespace scql::engine::util {\n/// ======================================\n/// Test for JoinIndices\n/// ======================================\n\nstruct JoinTestCase {\n  std::vector<std::string> left;\n  std::vector<std::string> right;\n  // join indices in following format:\n  // [\"left_idx1,right_idx1\", \"left_idx2,right_idx2\",...]\n  std::vector<std::string> join_indices;\n};\n\nclass JoinIndicesTest : public ::testing::TestWithParam<JoinTestCase> {\n protected:\n  static std::shared_ptr<psi::HashBucketEcPointStore> MakeLeftStore(\n      const JoinTestCase& tc) {\n    auto store =\n        std::make_shared<psi::HashBucketEcPointStore>(\"/tmp\", kNumBins);\n\n    for (const auto& str : tc.left) {\n      store->Save(str, 0);\n    }\n\n    return store;\n  }\n\n  static std::shared_ptr<psi::HashBucketEcPointStore> MakeRightStore(\n      const JoinTestCase& tc) {\n    auto store =\n        std::make_shared<psi::HashBucketEcPointStore>(\"/tmp\", kNumBins);\n    for (const auto& str : tc.right) {\n      store->Save(str, 0);\n    }\n\n    return store;\n  }\n};\n\nINSTANTIATE_TEST_SUITE_P(\n    JoinIndicesBatchTest, JoinIndicesTest,\n    testing::Values(JoinTestCase{.left = {\"A\", \"B\", \"C\", \"D\", \"E\", \"F\"},\n                                 .right = {\"B\", \"C\", \"A\", \"E\", \"G\", \"H\"},\n                                 .join_indices = {\"0,2\", \"1,0\", \"2,1\", \"4,3\"}},\n                    JoinTestCase{.left = {\"A\", \"B\", \"C\", \"D\", \"E\", \"F\"},\n                                 .right = {\"H\", \"I\", \"G\", \"K\"},\n                                 .join_indices = {}},\n                    JoinTestCase{.left = {\"A\", \"B\", \"C\", \"D\", \"E\", \"A\"},\n                                 .right = {\"C\", \"A\", \"A\", \"K\", \"F\", \"B\"},\n                                 .join_indices = {\"0,1\", \"0,2\", \"1,5\", \"2,0\",\n                                                  \"5,1\", \"5,2\"}}));\n\nTEST_P(JoinIndicesTest, works) {\n  // Given\n  auto tc = GetParam();\n\n  auto left_store = MakeLeftStore(tc);\n  auto right_store = MakeRightStore(tc);\n\n  // When\n  auto left_indices =\n      FinalizeAndComputeJoinIndices(true, left_store, right_store, 0);\n  auto right_indices =\n      FinalizeAndComputeJoinIndices(false, right_store, left_store, 0);\n\n  // Then\n  EXPECT_EQ(left_indices->Length(), right_indices->Length());\n  EXPECT_EQ(left_indices->Length(), tc.join_indices.size());\n\n  BatchProvider provider(std::vector<TensorPtr>{left_indices, right_indices});\n\n  auto indices_got = provider.ReadNextBatch();\n  EXPECT_THAT(indices_got,\n              ::testing::UnorderedElementsAreArray(tc.join_indices));\n}\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/psi/common.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/psi/common.h\"\n\n#include <algorithm>\n#include <cstddef>\n#include <cstdint>\n#include <string>\n#include <vector>\n\n#include \"psi/utils/serialize.h\"\n\nnamespace scql::engine::util {\n\nPsiPlan GetOprfPsiPlan(int64_t self_length, int64_t peer_length) {\n  util::PsiPlan psi_plan;\n  psi_plan.unbalanced = true;\n  int64_t small_length = std::min(self_length, peer_length);\n  int64_t big_length = std::max(self_length, peer_length);\n\n  YACL_ENFORCE(\n      small_length != big_length,\n      \"When using an unbalanced algorithm, equal data volumes on both \"\n      \"sides indicate a PSI configuration issue. (It is suggested to \"\n      \"set the PSI algorithm to AUTO when the user isn't familiar with PSI)\");\n  psi_plan.is_server = small_length != self_length;\n  psi_plan.psi_size_info.self_size = self_length;\n  psi_plan.psi_size_info.peer_size = peer_length;\n\n  return psi_plan;\n}\n\nnamespace {\nconstexpr char kPsiInLeft[] = \"Left\";\nconstexpr char kPsiInRight[] = \"Right\";\nconstexpr char kPsiInputPartyCodesAttr[] = \"input_party_codes\";\n}  // namespace\n\nsize_t ExchangeSetSize(const std::shared_ptr<yacl::link::Context>& link_ctx,\n                       size_t items_size) {\n  YACL_ENFORCE(link_ctx->WorldSize() == 2, \"currently only support 2 parties\");\n  auto result =\n      yacl::link::AllGather(link_ctx, psi::utils::SerializeSize(items_size),\n                            fmt::format(\"EXCHANGE_SIZE\"));\n  return psi::utils::DeserializeSize(result[link_ctx->NextRank()]);\n}\n\nPsiPlan CoordinatePsiPlan(ExecContext* ctx) {\n  auto logger = ctx->GetActiveLogger();\n  SPDLOG_LOGGER_INFO(logger,\n                     \"coordinate between engines to determine OprfPsi plan\");\n  // get related party codes and ranks\n  const auto& my_party_code = ctx->GetSession()->SelfPartyCode();\n  std::vector<std::string> input_party_codes =\n      ctx->GetStringValuesFromAttribute(kPsiInputPartyCodesAttr);\n  bool is_left = my_party_code == input_party_codes.at(0);\n  const auto& peer_party_code = input_party_codes.at(is_left ? 1 : 0);\n  auto my_rank = ctx->GetSession()->GetPartyRank(my_party_code);\n  YACL_ENFORCE(my_rank != -1, \"unknown rank for party={}\", my_party_code);\n  auto peer_rank = ctx->GetSession()->GetPartyRank(peer_party_code);\n  YACL_ENFORCE(peer_rank != -1, \"unknown rank for party={}\", peer_party_code);\n\n  // get input length\n  const auto* input_name = is_left ? kPsiInLeft : kPsiInRight;\n  const auto& input_pbs = ctx->GetInput(input_name);\n  auto* table = ctx->GetTensorTable();\n  auto t = table->GetTensor(input_pbs[0].name());\n  YACL_ENFORCE(t != nullptr, \"tensor {} not found in tensor table\",\n               input_pbs[0].name());\n  int64_t tensor_length = t->Length();\n  if (ctx->GetOpType() == \"Join\") {\n    for (int pb_idx = 1; pb_idx < input_pbs.size(); ++pb_idx) {\n      auto t = table->GetTensor(input_pbs[pb_idx].name());\n      YACL_ENFORCE(t != nullptr, \"tensor {} not found in tensor table\",\n                   input_pbs[pb_idx].name());\n      YACL_ENFORCE(tensor_length == t->Length(),\n                   \"Tensor length in input_pbs should be the same\");\n    }\n  }\n\n  // communicate tensor length\n  auto psi_link = ctx->GetSession()->GetLink();\n  auto tag = ctx->GetNodeName() + \"-TensorLength\";\n  if (psi_link->WorldSize() > 2) {\n    psi_link = psi_link->SubWorld(tag, input_party_codes);\n  }\n  auto peer_length = ExchangeSetSize(psi_link, tensor_length);\n\n  return util::GetOprfPsiPlan(tensor_length, peer_length);\n}\n\nBatchFinishedCb::BatchFinishedCb(std::shared_ptr<spdlog::logger> logger,\n                                 std::string task_id, size_t batch_total)\n    : task_id_(std::move(task_id)),\n      batch_total_(batch_total),\n      logger_(std::move(logger)) {}\n\nvoid BatchFinishedCb::operator()(size_t batch_count) {\n  if (batch_count % 100 == 0) {\n    SPDLOG_LOGGER_INFO(\n        logger_,\n        \"PSI task {} progress report: #{}/{} batches have been completed\",\n        task_id_, batch_count, batch_total_);\n  }\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/psi/common.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <chrono>\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n#include <string>\n\n#include \"spdlog/logger.h\"\n\n#include \"engine/framework/exec.h\"\n\nnamespace scql::engine::util {\n\nstatic constexpr int64_t kInnerJoin = 0;\nstatic constexpr int64_t kLeftJoin = 1;\nstatic constexpr int64_t kRightJoin = 2;\nstatic constexpr size_t kNumBins = 64;\n\nenum class PsiAlgo : int64_t {\n  kAutoPsi = 0,\n  kEcdhPsi = 1,\n  kOprfPsi = 2,\n  kRr22Psi = 3,\n  kAlgoNums,  // Sentinel Value\n};\n\nstruct PsiSizeInfo {\n  size_t self_size = 0;\n  size_t peer_size = 0;\n};\n\nstruct PsiPlan {\n  bool unbalanced = false;\n  bool is_server = false;\n  PsiSizeInfo psi_size_info;\n};\n\nstruct PsiExecutionInfoTable {\n  decltype(std::chrono::system_clock::now()) start_time;\n  size_t self_size;\n  size_t peer_size;\n  int64_t result_size;\n};\n\nPsiPlan GetOprfPsiPlan(int64_t self_length, int64_t peer_length);\n\nPsiPlan CoordinatePsiPlan(ExecContext* ctx);\n\nclass BatchFinishedCb {\n public:\n  BatchFinishedCb(std::shared_ptr<spdlog::logger> logger, std::string task_id,\n                  size_t batch_total);\n\n  void operator()(size_t batch_count);\n\n private:\n  const std::string task_id_;\n  size_t batch_total_;\n  std::shared_ptr<spdlog::logger> logger_;\n};\n\nsize_t ExchangeSetSize(const std::shared_ptr<yacl::link::Context>& link_ctx,\n                       size_t items_size);\n\n/// @brief restore back the `in` output order via sorting output by index\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/psi/detail_logger.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/psi/detail_logger.h\"\n\n#include <algorithm>\n#include <cstdint>\n#include <memory>\n#include <sstream>\n#include <string>\n#include <vector>\n\n#include \"absl/strings/escaping.h\"\n#include \"arrow/compute/exec.h\"\n#include \"gflags/gflags.h\"\n\n#include \"engine/core/tensor.h\"\n\n// [PSI][MaskSelf][row id: num] XXXXXXXXXX\n#define LOG_FORMATTER \"[{}][{}][row id: {}] {}\"\n#define PSI_OP \"PSI\"\n\nDEFINE_uint64(detail_logger_sample_num, 0,\n              \"use to control sample number, 0 means print all, default 0.\");\n\nnamespace scql::engine::util {\n\nsize_t GetItemsNumToWrite(size_t start_idx, size_t items_count) {\n  size_t sample_num = FLAGS_detail_logger_sample_num;\n  if (sample_num == 0) {\n    return items_count;\n  }\n  if (sample_num <= start_idx) {\n    return 0;\n  }\n  return std::min(items_count, sample_num - start_idx);\n}\n\nstd::string InputStageToString(psi::ecdh::EcdhStage stage) {\n  static std::map<psi::ecdh::EcdhStage, std::string> stageMap = {\n      {psi::ecdh::EcdhStage::MaskSelf, \"HashSelf\"},\n      {psi::ecdh::EcdhStage::MaskPeer, \"RecvPeer\"},\n      {psi::ecdh::EcdhStage::RecvDualMaskedSelf, \"RecvSelfEncrypt\"}};\n\n  return stageMap[stage];\n}\n\nstd::string OutputStageToString(psi::ecdh::EcdhStage stage) {\n  static std::map<psi::ecdh::EcdhStage, std::string> stageMap = {\n      {psi::ecdh::EcdhStage::MaskSelf, \"MaskSelf\"},\n      {psi::ecdh::EcdhStage::MaskPeer, \"MaskPeer\"}};\n\n  return stageMap[stage];\n}\n\nvoid EcdhDetailLogger::Log(\n    psi::ecdh::EcdhStage stage,\n    const std::array<uint8_t, psi::kEccKeySize>& secret_key, size_t start_idx,\n    const std::vector<std::string>& input,\n    const std::vector<std::string>& output) {\n  auto to_write_items_count = GetItemsNumToWrite(start_idx, input.size());\n  if (to_write_items_count > 0) {\n    std::stringstream ss;\n    for (auto item : secret_key) {\n      ss << std::hex << std::setw(2) << std::setfill('0')\n         << static_cast<int>(item);\n    }\n    spd_logger_->info(LOG_FORMATTER, PSI_OP, \"PrivateKey\", 0, ss.str());\n    for (size_t i = 0; i < to_write_items_count; i++) {\n      spd_logger_->info(LOG_FORMATTER, PSI_OP, InputStageToString(stage),\n                        i + start_idx, absl::BytesToHexString(input[i]));\n    }\n    if (!output.empty() && stage != psi::ecdh::EcdhStage::RecvDualMaskedSelf) {\n      to_write_items_count = std::min(to_write_items_count, output.size());\n      for (size_t i = 0; i < to_write_items_count; i++) {\n        spd_logger_->info(LOG_FORMATTER, PSI_OP, OutputStageToString(stage),\n                          i + start_idx, absl::BytesToHexString(output[i]));\n      }\n    }\n  }\n}\n\nstd::string ScalarToString(std::shared_ptr<arrow::Scalar>& scalar,\n                           pb::PrimitiveDataType type) {\n  if (!scalar->is_valid) {\n    return \"null\";\n  }\n  // for string data, ToString returns [\n  //   \"string\"\n  // ]\n  // we need remove the suffix \"\\n]\" and prefix \"[\\n  \"\n  if (type == pb::PrimitiveDataType::STRING) {\n    auto str = scalar->ToString();\n    return str.substr(4, str.size() - 6);\n  }\n  return scalar->ToString();\n}\n\nvoid PsiDetailLogger::LogInput(const std::vector<TensorPtr>& inputs) {\n  spd_logger_->info(\"Start, Loading data...\");\n  auto to_write_items_count = GetItemsNumToWrite(0, inputs[0]->Length());\n  if (to_write_items_count > 0) {\n    for (size_t i = 0; i < to_write_items_count; i++) {\n      std::string to_write;\n      for (size_t j = 0; j < inputs.size(); ++j) {\n        auto scalar = inputs[j]->ToArrowChunkedArray()->GetScalar(i);\n        if (j == 0) {\n          to_write = ScalarToString(scalar.ValueOrDie(), inputs[j]->Type());\n        } else {\n          to_write = fmt::format(\n              \"{},{}\", to_write,\n              ScalarToString(scalar.ValueOrDie(), inputs[j]->Type()));\n        }\n      }\n      spd_logger_->info(LOG_FORMATTER, PSI_OP, \"Input\", i, to_write);\n    }\n  }\n}\n\nvoid PsiDetailLogger::LogOutput(const TensorPtr& result,\n                                const std::vector<TensorPtr>& inputs) {\n  auto to_write_items_count = GetItemsNumToWrite(0, result->Length());\n  if (to_write_items_count > 0) {\n    // for in\n    if (inputs.empty()) {\n      for (size_t i = 0; i < to_write_items_count; i++) {\n        auto scalar = result->ToArrowChunkedArray()->GetScalar(i);\n        std::string to_write =\n            ScalarToString(scalar.ValueOrDie(), result->Type());\n        spd_logger_->info(LOG_FORMATTER, PSI_OP, \"Output\", i, to_write);\n      }\n    } else {\n      // for join\n      std::vector<std::shared_ptr<arrow::ChunkedArray>> outputs;\n      for (const auto& input : inputs) {\n        auto take_result = arrow::compute::CallFunction(\n            \"take\",\n            {input->ToArrowChunkedArray(), result->ToArrowChunkedArray()});\n        outputs.emplace_back(take_result.ValueOrDie().chunked_array());\n      }\n      for (size_t i = 0; i < to_write_items_count; i++) {\n        std::string to_write;\n        for (size_t j = 0; j < inputs.size(); ++j) {\n          auto scalar = outputs[j]->GetScalar(i);\n          if (j == 0) {\n            to_write = ScalarToString(scalar.ValueOrDie(), inputs[j]->Type());\n          } else {\n            to_write = fmt::format(\n                \"{},{}\", to_write,\n                ScalarToString(scalar.ValueOrDie(), inputs[j]->Type()));\n          }\n        }\n        spd_logger_->info(LOG_FORMATTER, PSI_OP, \"Output\", i, to_write);\n      }\n    }\n  }\n  spd_logger_->info(\"End\");\n  spd_logger_->flush();\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/psi/detail_logger.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <vector>\n\n#include \"psi/algorithm/ecdh/ecdh_logger.h\"\n#include \"psi/cryptor/ecc_cryptor.h\"\n#include \"spdlog/logger.h\"\n\n#include \"engine/core/tensor.h\"\n\nnamespace scql::engine::util {\n\nclass EcdhDetailLogger : public psi::ecdh::EcdhLogger {\n public:\n  explicit EcdhDetailLogger(std::shared_ptr<spdlog::logger> spd_logger)\n      : spd_logger_(std::move(spd_logger)) {}\n\n  void Log(psi::ecdh::EcdhStage stage,\n           const std::array<uint8_t, psi::kEccKeySize>& secret_key,\n           size_t start_idx, const std::vector<std::string>& input,\n           const std::vector<std::string>& output = {}) override;\n\n private:\n  std::shared_ptr<spdlog::logger> spd_logger_;\n};\n\nclass PsiDetailLogger {\n public:\n  explicit PsiDetailLogger(std::shared_ptr<spdlog::logger> spd_logger)\n      : spd_logger_(std::move(spd_logger)) {\n    ecdh_logger_ = std::make_shared<EcdhDetailLogger>(spd_logger_);\n  }\n\n  void LogInput(const std::vector<TensorPtr>& inputs);\n  void LogOutput(const TensorPtr& result,\n                 const std::vector<TensorPtr>& inputs = {});\n  std::shared_ptr<EcdhDetailLogger> GetEcdhLogger() { return ecdh_logger_; }\n\n private:\n  std::shared_ptr<spdlog::logger> spd_logger_;\n  std::shared_ptr<EcdhDetailLogger> ecdh_logger_;\n};\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/psi/ub_helper.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/psi/ub_helper.h\"\n\n#include <future>\n\n#include \"psi/utils/batch_provider.h\"\n#include \"psi/utils/batch_provider_impl.h\"\n#include \"yacl/crypto/rand/rand.h\"\n\n#include \"engine/util/psi/batch_provider.h\"\n\nDECLARE_int64(provider_batch_size);\n\nnamespace scql::engine::util {\n\n// OPRF ECDH PSI phases\nvoid OprfPsiServerTransferServerItems(\n    ExecContext* ctx, std::shared_ptr<yacl::link::Context> psi_link,\n    const std::shared_ptr<util::BatchProvider>& batch_provider,\n    const std::shared_ptr<psi::ecdh::EcdhOprfPsiServer>& ec_oprf_psi_server,\n    std::shared_ptr<psi::IUbPsiCache> ub_cache) {\n  auto logger = ctx->GetActiveLogger();\n  SPDLOG_LOGGER_INFO(\n      logger,\n      \"Oprf server start to transfer evaluated server items, my rank: {}, my \"\n      \"party_code: {}\",\n      ctx->GetSession()->SelfRank(), ctx->GetSession()->SelfPartyCode());\n\n  yacl::link::Barrier(psi_link, \"Sync for UbPsi client and server\");\n\n  size_t self_item_count =\n      ub_cache\n          ? ec_oprf_psi_server->FullEvaluateAndSend(batch_provider, ub_cache)\n          : ec_oprf_psi_server->FullEvaluateAndSend(batch_provider);\n\n  SPDLOG_LOGGER_INFO(logger, \"Oprf server: evaluate and send {} items\",\n                     self_item_count);\n}\n\nvoid OprfPsiServerTransferClientItems(\n    ExecContext* ctx,\n    const std::shared_ptr<psi::ecdh::EcdhOprfPsiServer>& ec_oprf_psi_server) {\n  auto logger = ctx->GetActiveLogger();\n  SPDLOG_LOGGER_INFO(\n      logger,\n      \"Oprf server start to transfer client items, my rank: {}, my \"\n      \"party_code: {}\",\n      ctx->GetSession()->SelfRank(), ctx->GetSession()->SelfPartyCode());\n\n  ec_oprf_psi_server->RecvBlindAndSendEvaluate();\n  SPDLOG_LOGGER_INFO(logger, \"Oprf server finish transferring client items\");\n}\n\nvoid OprfPsiClientTransferServerItems(\n    ExecContext* ctx, std::shared_ptr<yacl::link::Context> psi_link,\n    const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n    const std::shared_ptr<UbPsiCipherStore>& cipher_store) {\n  auto logger = ctx->GetActiveLogger();\n  SPDLOG_LOGGER_INFO(\n      logger,\n      \"Oprf client start to receive evaluated server items, my rank: {}, my \"\n      \"party_code: {}\",\n      ctx->GetSession()->SelfRank(), ctx->GetSession()->SelfPartyCode());\n  auto ec_oprf_psi_client_offline =\n      std::make_shared<psi::ecdh::EcdhOprfPsiClient>(psi_options);\n\n  yacl::link::Barrier(psi_link, \"Sync for UbPsi client and server\");\n\n  ec_oprf_psi_client_offline->RecvFinalEvaluatedItems(cipher_store);\n  SPDLOG_LOGGER_INFO(\n      logger,\n      \"Oprf client finish receiving evaluated server items, items count: {}\",\n      cipher_store->ItemCount());\n}\n\nvoid OprfPsiClientTransferClientItems(\n    ExecContext* ctx,\n    const std::shared_ptr<util::BatchProvider>& batch_provider,\n    const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n    const std::shared_ptr<UbPsiCipherStore>& cipher_store) {\n  auto logger = ctx->GetActiveLogger();\n  SPDLOG_LOGGER_INFO(\n      logger,\n      \"Oprf client start to transfer client items, my rank: {}, my party_code: \"\n      \"{}\",\n      ctx->GetSession()->SelfRank(), ctx->GetSession()->SelfPartyCode());\n\n  auto ec_oprf_psi_client_online =\n      std::make_shared<psi::ecdh::EcdhOprfPsiClient>(psi_options);\n\n  std::future<size_t> f_client_send_blind = std::async([&] {\n    return ec_oprf_psi_client_online->SendBlindedItems(batch_provider);\n  });\n  ec_oprf_psi_client_online->RecvEvaluatedItems(cipher_store);\n  size_t self_items_count = f_client_send_blind.get();\n  SPDLOG_LOGGER_INFO(logger,\n                     \"Oprf client send {} blinded items in UbPsiClientOnline\",\n                     self_items_count);\n\n  SPDLOG_LOGGER_INFO(\n      logger, \"Oprf client finish transferring client items, client_count: {}\",\n      cipher_store->ItemCount());\n}\n\nvoid OprfServerTransferShuffledClientItems(\n    ExecContext* ctx,\n    const std::shared_ptr<psi::ecdh::EcdhOprfPsiServer>& dh_oprf_psi_server,\n    const std::string& server_cache_path,\n    std::vector<uint64_t>* matched_indices, size_t* self_item_count) {\n  auto logger = ctx->GetActiveLogger();\n  SPDLOG_LOGGER_INFO(\n      logger,\n      \"Oprf server start to transfer shuffled client items, my rank: {}, my \"\n      \"party_code: {}\",\n      ctx->GetSession()->SelfRank(), ctx->GetSession()->SelfPartyCode());\n  dh_oprf_psi_server->RecvBlindAndShuffleSendEvaluate();\n\n  std::shared_ptr<psi::IShuffledBatchProvider> cache_provider =\n      std::make_shared<psi::UbPsiCacheProvider>(server_cache_path,\n                                                FLAGS_provider_batch_size);\n\n  std::tie(*matched_indices, *self_item_count) =\n      dh_oprf_psi_server->RecvIntersectionMaskedItems(cache_provider);\n  SPDLOG_LOGGER_INFO(logger,\n                     \"Oprf server finish transfering shuffled client items\");\n}\n\nvoid OprfCLientTransferShuffledClientItems(\n    ExecContext* ctx,\n    const std::shared_ptr<util::BatchProvider>& batch_provider,\n    const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n    const std::shared_ptr<UbPsiCipherStore>& client_store,\n    const std::shared_ptr<UbPsiCipherStore>& server_store) {\n  auto logger = ctx->GetActiveLogger();\n  SPDLOG_LOGGER_INFO(\n      logger,\n      \"Oprf client start to transfer shuffled client items, my rank: {}, my \"\n      \"party_code: {}\",\n      ctx->GetSession()->SelfRank(), ctx->GetSession()->SelfPartyCode());\n\n  std::vector<uint8_t> private_key = yacl::crypto::RandBytes(psi::kEccKeySize);\n  auto ub_psi_client_shuffle_online =\n      std::make_shared<psi::ecdh::EcdhOprfPsiClient>(psi_options, private_key);\n\n  size_t self_items_count =\n      ub_psi_client_shuffle_online->SendBlindedItems(batch_provider);\n  SPDLOG_LOGGER_INFO(\n      logger, \"Oprf client send {} blinded items in UbPsiClientShuffleOnline\",\n      self_items_count);\n\n  ub_psi_client_shuffle_online->RecvEvaluatedItems(client_store);\n\n  auto matched_items =\n      FinalizeAndComputeIntersection(client_store, server_store);\n  std::shared_ptr<psi::IBasicBatchProvider> intersection_masked_provider =\n      std::make_shared<psi::MemoryBatchProvider>(matched_items,\n                                                 FLAGS_provider_batch_size);\n  ub_psi_client_shuffle_online->SendIntersectionMaskedItems(\n      intersection_masked_provider);\n  SPDLOG_LOGGER_INFO(logger,\n                     \"Oprf client finish transfering shuffled client items\");\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/psi/ub_helper.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <vector>\n\n#include \"psi/algorithm/ecdh/ub_psi/ecdh_oprf_psi.h\"\n#include \"psi/utils/batch_provider.h\"\n#include \"psi/utils/hash_bucket_cache.h\"\n#include \"yacl/link/link.h\"\n\n#include \"engine/core/tensor.h\"\n#include \"engine/framework/exec.h\"\n#include \"engine/util/psi/batch_provider.h\"\n#include \"engine/util/psi/cipher_intersection.h\"\n#include \"engine/util/stringifier.h\"\n\nnamespace scql::engine::util {\n\nvoid OprfPsiServerTransferServerItems(\n    ExecContext* ctx, std::shared_ptr<yacl::link::Context> psi_link,\n    const std::shared_ptr<BatchProvider>& batch_provider,\n    const std::shared_ptr<psi::ecdh::EcdhOprfPsiServer>& dh_oprf_psi_server,\n    std::shared_ptr<psi::IUbPsiCache> ub_cache = nullptr);\n\nvoid OprfPsiServerTransferClientItems(\n    ExecContext* ctx,\n    const std::shared_ptr<psi::ecdh::EcdhOprfPsiServer>& dh_oprf_psi_server);\n\nvoid OprfPsiClientTransferServerItems(\n    ExecContext* ctx, std::shared_ptr<yacl::link::Context> psi_link,\n    const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n    const std::shared_ptr<UbPsiCipherStore>& cipher_store);\n\nvoid OprfPsiClientTransferClientItems(\n    ExecContext* ctx,\n    const std::shared_ptr<util::BatchProvider>& batch_provider,\n    const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n    const std::shared_ptr<UbPsiCipherStore>& cipher_store);\n\nvoid OprfServerTransferShuffledClientItems(\n    ExecContext* ctx,\n    const std::shared_ptr<psi::ecdh::EcdhOprfPsiServer>& dh_oprf_psi_server,\n    const std::string& server_cache_path,\n    std::vector<uint64_t>* matched_indices, size_t* self_item_count);\n\nvoid OprfCLientTransferShuffledClientItems(\n    ExecContext* ctx,\n    const std::shared_ptr<util::BatchProvider>& batch_provider,\n    const psi::ecdh::EcdhOprfPsiOptions& psi_options,\n    const std::shared_ptr<UbPsiCipherStore>& client_store,\n    const std::shared_ptr<UbPsiCipherStore>& server_store);\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/spu_io.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/spu_io.h\"\n\n#include \"arrow/array/util.h\"\n#include \"gflags/gflags.h\"\n#include \"libspu/core/encoding.h\"\n#include \"libspu/device/io.h\"\n#include \"libspu/kernel/hal/public_helper.h\"\n#include \"libspu/kernel/hal/type_cast.h\"\n#include \"libspu/kernel/hlo/basic_unary.h\"\n#include \"libspu/kernel/hlo/const.h\"\n#include \"libspu/mpc/common/pv2k.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n#include \"engine/core/type.h\"\n#include \"engine/util/ndarray_to_arrow.h\"\nDEFINE_int64(max_chunk_size, 128UL * 1024 * 1024,\n             \"max chunk size of value proto\");\n\nnamespace scql::engine::util {\n\nnamespace {\n\nstruct SpuPtBufferViewConverter {\n  void const* data_ptr = nullptr;\n  bool is_bitset = false;\n\n  void Convert(const arrow::Array& array) {\n    THROW_IF_ARROW_NOT_OK(arrow::VisitArrayInline(array, this));\n  }\n\n  template <typename T>\n  arrow::Status Visit(const T& array) {\n    return arrow::Status::NotImplemented(\n        fmt::format(\"SpuPtBufferViewConverter for type {} is not implemented\",\n                    array.type()->name()));\n  }\n\n  template <typename TYPE>\n  arrow::Status Visit(const arrow::NumericArray<TYPE>& array) {\n    data_ptr = static_cast<void const*>(array.raw_values());\n    return arrow::Status::OK();\n  }\n\n  arrow::Status Visit(const arrow::BooleanArray& array) {\n    data_ptr = static_cast<void const*>(array.values()->data());\n    is_bitset = true;\n    return arrow::Status::OK();\n  }\n};\n\n}  // namespace\n\nspu::DataType GetWiderSpuType(const spu::DataType& t1,\n                              const spu::DataType& t2) {\n  std::unordered_map<spu::DataType, int> type_index{\n      // 1\n      {spu::DataType::DT_I1, 1},\n      // 8\n      {spu::DataType::DT_I8, 2},\n      {spu::DataType::DT_U8, 3},\n      // 16\n      {spu::DataType::DT_I16, 4},\n      {spu::DataType::DT_U16, 5},\n      {spu::DataType::DT_F16, 6},\n      // 32\n      {spu::DataType::DT_I32, 7},\n      {spu::DataType::DT_U32, 8},\n      {spu::DataType::DT_F32, 9},\n      // 64\n      {spu::DataType::DT_I64, 10},\n      {spu::DataType::DT_U64, 11},\n      {spu::DataType::DT_F64, 12}};\n\n  if (type_index.find(t1) == type_index.end()) {\n    return t2;\n  }\n\n  if (type_index.find(t2) == type_index.end()) {\n    return t1;\n  }\n\n  if (type_index[t1] > type_index[t2]) {\n    return t1;\n  } else {\n    return t2;\n  }\n}\n\nspu::Value Invert(spu::SPUContext* sctx, const spu::Value& val) {\n  if (val.dtype() == spu::DT_I1) {\n    return spu::kernel::hlo::Not(sctx, val);\n  }\n  // revert all bits\n  if (val.dtype() == spu::DT_U8 || val.dtype() == spu::DT_U16 ||\n      val.dtype() == spu::DT_U32 || val.dtype() == spu::DT_U64) {\n    return spu::kernel::hlo::Sub(\n        sctx, spu::kernel::hlo::Neg(sctx, val),\n        spu::kernel::hlo::Constant(sctx, 1, {val.shape()}));\n  }\n\n  return spu::kernel::hlo::Neg(sctx, val);\n}\n\nstd::vector<spu::Value> ExpandGroupValueReversely(\n    spu::SPUContext* sctx, const std::vector<spu::Value>& inputs,\n    const spu::Value& mark) {\n  // TODO: Scan api support vector inputs to speed up\n  std::vector<spu::Value> ret;\n  auto reversed_mark = spu::kernel::hlo::Reverse(sctx, mark, {0});\n  for (auto v : inputs) {\n    auto reversed_v = util::Scan(\n        sctx, spu::kernel::hlo::Reverse(sctx, v, {0}), reversed_mark,\n        [&](const spu::Value& lhs_v, const spu::Value& lhs_gm,\n            const spu::Value& rhs_v, const spu::Value& rhs_gm) {\n          spu::Value new_v = spu::kernel::hlo::Add(\n              sctx, lhs_v,\n              spu::kernel::hlo::Mul(sctx, lhs_gm,\n                                    spu::kernel::hlo::Sub(sctx, rhs_v, lhs_v)));\n          spu::Value new_gm = spu::kernel::hlo::Mul(sctx, lhs_gm, rhs_gm);\n\n          return std::make_pair(new_v, new_gm);\n        });\n\n    ret.push_back(spu::kernel::hlo::Reverse(sctx, reversed_v, {0}));\n  }\n  return ret;\n}\n\nstd::shared_ptr<arrow::Array> ConcatenateChunkedArray(\n    const std::shared_ptr<arrow::ChunkedArray>& chunked_arr) {\n  arrow::Result<std::shared_ptr<arrow::Array>> result;\n\n  if (chunked_arr->num_chunks() == 0) {\n    result = arrow::MakeEmptyArray(chunked_arr->type());\n  } else {\n    result = arrow::Concatenate(chunked_arr->chunks());\n  }\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error when try to ConcatenateChunkedArray: {}\",\n               result.status().ToString());\n\n  return result.ValueOrDie();\n}\n\nstd::string SpuVarNameEncoder::GetValueName(const std::string& name) {\n  return name + \".value\";\n}\n\nstd::string SpuVarNameEncoder::GetValidityName(const std::string& name) {\n  return name + \".validity\";\n}\n\nSpuInfeedHelper::PtView SpuInfeedHelper::ConvertArrowArrayToPtView(\n    const std::shared_ptr<arrow::Array>& array) {\n  spu::PtType pt = ArrowDataTypeToSpuPtType(array->type());\n  YACL_ENFORCE(pt != spu::PT_INVALID, \"unsupported arrow data type: {}\",\n               array->type()->ToString());\n\n  SpuPtBufferViewConverter converter;\n  converter.Convert(*array);\n\n  array_refs_.push_back(array);\n\n  auto value = spu::PtBufferView(converter.data_ptr, pt, {array->length()}, {1},\n                                 converter.is_bitset);\n\n#ifdef SCQL_WITH_NULL\n  // NOTE: null_bitmap may be nullptr if all values are valid in array\n  const uint8_t* null_bitmap = array->null_bitmap_data();\n\n  auto validity = spu::PtBufferView(static_cast<void const*>(null_bitmap),\n                                    spu::PT_I1, {array->length()}, {1}, true);\n  return PtView(value, validity);\n#endif  // SCQL_WITH_NULL\n\n  YACL_ENFORCE(array->null_count() == 0, \"not support null in spu yet\");\n  return PtView(value);\n}\n\nvoid SpuInfeedHelper::Sync() {\n  cio_->sync();\n  // release array refs\n  array_refs_.clear();\n}\n\nvoid SpuInfeedHelper::InfeedTensor(const std::string& name,\n                                   const Tensor& tensor,\n                                   spu::Visibility vtype) {\n  // FIXME(shunde.csd): rewrite if spu provides streaming io\n  // interface.\n  auto array = ConcatenateChunkedArray(tensor.ToArrowChunkedArray());\n\n  PtView pt_view = ConvertArrowArrayToPtView(array);\n\n  const auto val_name = SpuVarNameEncoder::GetValueName(name);\n  cio_->hostSetVar(val_name, pt_view.value, vtype);\n#ifdef SCQL_WITH_NULL\n  const auto validity_name = SpuVarNameEncoder::GetValidityName(name);\n  // FIXME(shunde.csd): if pt_view.validity.ptr == nullptr, we should allocate\n  // memory for null bitmap and set it with all valid.\n  cio_->hostSetVar(validity_name, pt_view.validity, vtype);\n#endif  // SCQL_WITH_NULL\n}\n\nTensorPtr SpuOutfeedHelper::DumpPublic(const std::string& name) {\n  const auto value_name = SpuVarNameEncoder::GetValueName(name);\n  if (!symbols_->hasVar(value_name)) {\n    return nullptr;\n  }\n  auto value = symbols_->getVar(value_name);\n  spu::NdArrayRef arr = spu::kernel::hal::dump_public(sctx_, value);\n#ifdef SCQL_WITH_NULL\n  auto validity_val =\n      symbols_->getVar(SpuVarNameEncoder::GetValidityName(name));\n  auto validity = spu::kernel::hal::dump_public(sctx_, validity_val);\n  return TensorFrom(NdArrayToArrow(arr, &validity));\n#else\n  return TensorFrom(NdArrayToArrow(arr, nullptr));\n#endif  // SCQL_WITH_NULL\n}\n\nspu::NdArrayRef RevealValueTo(spu::SPUContext* sctx, spu::device::IoClient& io,\n                              const spu::Value& value, size_t rank) {\n  auto private_value = spu::kernel::hal::reveal_to(sctx, value, rank);\n  if (sctx->lctx()->Rank() != rank) {\n    return spu::NdArrayRef();\n  }\n  auto dtype = private_value.dtype();\n  auto pt_type = io.getPtType({private_value});\n  auto fxp_bits = sctx->getFxpBits();\n\n  spu::NdArrayRef decoded(spu::makePtType(pt_type), private_value.shape());\n  spu::PtBufferView pv(decoded.data(), pt_type, decoded.shape(),\n                       decoded.strides());\n\n  spu::decodeFromRing(private_value.data(), dtype, fxp_bits, &pv);\n\n  return decoded;\n}\n\nTensorPtr SpuOutfeedHelper::RevealTo(const std::string& name, size_t rank) {\n  const auto& lctx = sctx_->lctx();\n\n  auto value = symbols_->getVar(SpuVarNameEncoder::GetValueName(name));\n  if (value.isPublic()) {\n    return DumpPublic(name);\n  }\n\n  spu::device::IoClient io(lctx->WorldSize(), sctx_->config());\n  auto revealed_value = RevealValueTo(sctx_, io, value, rank);\n\n#ifdef SCQL_WITH_NULL\n  auto validity = symbols_->getVar(SpuVarNameEncoder::GetValidityName(name));\n  auto revealed_validity = RevealValueTo(sctx_, io, validity, rank);\n#endif  // SCQL_WITH_NULL\n\n  if (lctx->Rank() != rank) {\n    return nullptr;\n  }\n#ifdef SCQL_WITH_NULL\n  return TensorFrom(NdArrayToArrow(revealed_value, &revealed_validity));\n#else\n  return TensorFrom(NdArrayToArrow(revealed_value, nullptr));\n#endif  // SCQL_WITH_NULL\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/spu_io.h",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <utility>\n\n#include \"arrow/api.h\"\n#include \"libspu/device/io.h\"\n#include \"libspu/kernel/hlo/basic_binary.h\"\n#include \"libspu/kernel/hlo/geometrical.h\"\n\n#include \"engine/core/tensor.h\"\n#include \"engine/util/prefix_sum.h\"\n\nnamespace scql::engine::util {\n\n// expand value from bottom to top for each group, mark using '0' to mark\n// the group end, e.g: inputs = {{0, 0, 1, 0, 2}}, mark = {1, 1, 0, 1, 0}\n//            output = {{1, 1, 1, 2, 2}}\nstd::vector<spu::Value> ExpandGroupValueReversely(\n    spu::SPUContext* sctx, const std::vector<spu::Value>& inputs,\n    const spu::Value& mark);\n\nspu::DataType GetWiderSpuType(const spu::DataType& t1, const spu::DataType& t2);\n\n// Invert the data values\nspu::Value Invert(spu::SPUContext* sctx, const spu::Value& val);\n\nstd::shared_ptr<arrow::Array> ConcatenateChunkedArray(\n    const std::shared_ptr<arrow::ChunkedArray>& chunked_arr);\n\nclass SpuVarNameEncoder {\n public:\n  static std::string GetValueName(const std::string& name);\n  static std::string GetValidityName(const std::string& name);\n};\n\n/// @brief helper class for infeeding tensor to SPU device\nclass SpuInfeedHelper {\n public:\n  explicit SpuInfeedHelper(spu::device::ColocatedIo* cio) : cio_(cio) {}\n\n  void InfeedTensorAsPublic(const std::string& name, const Tensor& tensor) {\n    InfeedTensor(name, tensor, spu::VIS_PUBLIC);\n  }\n\n  void InfeedTensorAsSecret(const std::string& name, const Tensor& tensor) {\n    InfeedTensor(name, tensor, spu::VIS_SECRET);\n  }\n\n  void Sync();\n\n private:\n  /// @brief spu plaintext view of arrow array\n  struct PtView {\n    spu::PtBufferView value;\n\n#ifdef SCQL_WITH_NULL\n    spu::PtBufferView validity;  // null bitmap\n\n    PtView(spu::PtBufferView val, spu::PtBufferView validity)\n        : value(val), validity(validity) {}\n#else\n    explicit PtView(spu::PtBufferView val) : value(std::move(val)) {}\n#endif  // SCQL_WITH_NULL\n\n    PtView() = delete;\n  };\n\n  /// @brief return PtView will be valid for as long as\n  /// @param[in] array is alive.\n  PtView ConvertArrowArrayToPtView(const std::shared_ptr<arrow::Array>& array);\n\n  void InfeedTensor(const std::string& name, const Tensor& tensor,\n                    spu::Visibility vtype);\n\n private:\n  spu::device::ColocatedIo* cio_;\n  // hold a copy of array's shared_ptr to make sure spu::PtBufferView valid\n  // until sync() is called.\n  std::vector<std::shared_ptr<arrow::Array>> array_refs_;\n};\n\n/// @brief helper class for outfeeding tensors from SPU device\nclass SpuOutfeedHelper {\n public:\n  SpuOutfeedHelper(spu::SPUContext* sctx,\n                   const spu::device::SymbolTable* symbols)\n      : sctx_(sctx), symbols_(symbols) {}\n\n  TensorPtr DumpPublic(const std::string& name);\n\n  /// Reveal a secret value from spu deivce to party `rank`.\n  /// @returns nullptr to other parties.\n  TensorPtr RevealTo(const std::string& name, size_t rank);\n\n private:\n  spu::SPUContext* sctx_;\n  const spu::device::SymbolTable* symbols_;\n};\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/ssl_helper.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/ssl_helper.h\"\n\n#include \"butil/file_util.h\"\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine::util {\n\ngrpc::SslCredentialsOptions LoadSslCredentialsOptions(\n    const std::string& key_file, const std::string& cert_file,\n    const std::string& cacert_file) {\n  grpc::SslCredentialsOptions opts;\n\n  std::string content;\n  YACL_ENFORCE(butil::ReadFileToString(butil::FilePath(cacert_file), &content));\n  opts.pem_root_certs = content;\n\n  YACL_ENFORCE(butil::ReadFileToString(butil::FilePath(key_file), &content));\n  opts.pem_private_key = content;\n\n  YACL_ENFORCE(butil::ReadFileToString(butil::FilePath(cert_file), &content));\n  opts.pem_cert_chain = content;\n  return opts;\n}\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/ssl_helper.h",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"grpcpp/grpcpp.h\"\n\nnamespace scql::engine::util {\n\ngrpc::SslCredentialsOptions LoadSslCredentialsOptions(\n    const std::string& key_file, const std::string& cert_file,\n    const std::string& cacert_file);\n\n}"
  },
  {
    "path": "engine/util/ssl_helper_test.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/ssl_helper.h\"\n\n#include \"butil/file_util.h\"\n#include \"gtest/gtest.h\"\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine::util {\n\nTEST(LoadSslCredentialsOptionsTest, Success) {\n  std::string key_file = \"key_file\";\n  std::string cert_file = \"cert_file\";\n  std::string cacert_file = \"cacert_file\";\n\n  butil::CreateDirectory(butil::FilePath(key_file).DirName(), true);\n  butil::WriteFile(butil::FilePath(key_file), \"dummy_key_content\",\n                   std::strlen(\"dummy_key_content\"));\n  butil::WriteFile(butil::FilePath(cert_file), \"dummy_cert_content\",\n                   std::strlen(\"dummy_cert_content\"));\n  butil::WriteFile(butil::FilePath(cacert_file), \"dummy_cacert_content\",\n                   std::strlen(\"dummy_cacert_content\"));\n\n  grpc::SslCredentialsOptions opts =\n      LoadSslCredentialsOptions(key_file, cert_file, cacert_file);\n\n  EXPECT_EQ(opts.pem_private_key, \"dummy_key_content\");\n  EXPECT_EQ(opts.pem_cert_chain, \"dummy_cert_content\");\n  EXPECT_EQ(opts.pem_root_certs, \"dummy_cacert_content\");\n}\n\nTEST(LoadSslCredentialsOptionsTest, ReadFileFailure) {\n  std::string invalid_path = \"invalid_path\";\n\n  EXPECT_THROW(\n      LoadSslCredentialsOptions(invalid_path, invalid_path, invalid_path),\n      yacl::EnforceNotMet);\n}\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/stringifier.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/stringifier.h\"\n\n#include <arrow/scalar.h>\n\n#include \"arrow/compute/cast.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor_constructor.h\"\n\nnamespace scql::engine::util {\n\nStringifier::Stringifier(const TensorPtr& tensor, size_t batch_size) {\n  reader_ = tensor->CreateBatchReader(batch_size);\n}\n\nstd::vector<std::string> Stringifier::StringifyBatch() {\n  auto chunked_array = reader_->Next();\n  if (chunked_array == nullptr) {\n    return {};\n  }\n  return Stringify(chunked_array);\n}\n\nstd::vector<std::string> Stringify(\n    const std::shared_ptr<arrow::ChunkedArray>& arrays) {\n  std::shared_ptr<arrow::ChunkedArray> chunked_array = arrays;\n  if (arrays->type()->id() != arrow::Type::LARGE_STRING) {\n    auto cast_result = arrow::compute::Cast(arrays, arrow::large_utf8());\n    YACL_ENFORCE(cast_result.ok(), \"cast to string failed: {}\",\n                 cast_result.status().ToString());\n    chunked_array = cast_result.ValueOrDie().chunked_array();\n  }\n  std::vector<std::string> result;\n  result.reserve(chunked_array->length());\n  for (int i = 0; i < chunked_array->num_chunks(); i++) {\n    auto array = chunked_array->chunk(i);\n    auto string_array =\n        arrow::internal::checked_pointer_cast<arrow::LargeStringArray>(array);\n    for (int j = 0; j < string_array->length(); j++) {\n      result.emplace_back(string_array->IsNull(j) ? \"null\"\n                                                  : string_array->GetView(j));\n    }\n  }\n\n  return result;\n}\n\nstd::vector<std::string> Stringify(const std::shared_ptr<arrow::Array>& array) {\n  auto arrays = arrow::ChunkedArray::Make({array}).ValueOrDie();\n  return Stringify(arrays);\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/stringifier.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"arrow/visit_array_inline.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor.h\"\n#include \"engine/core/tensor_batch_reader.h\"\n\nnamespace scql::engine::util {\n\n/// @brief Stringifier converts tensor to string representation\nclass Stringifier {\n public:\n  explicit Stringifier(const TensorPtr& tensor, size_t batch_size);\n\n  /// @brief Stringify next batch_size elements\n  /// @returns empty vector if reach end.\n  std::vector<std::string> StringifyBatch();\n\n private:\n  std::shared_ptr<TensorBatchReader> reader_;\n};\n\nstd::vector<std::string> Stringify(const std::shared_ptr<arrow::Array>& array);\n\nstd::vector<std::string> Stringify(\n    const std::shared_ptr<arrow::ChunkedArray>& arrays);\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/stringifier_test.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/stringifier.h\"\n\n#include <arrow/array.h>\n#include <arrow/builder.h>\n#include <gtest/gtest.h>\n\nnamespace scql::engine::util {\n\nclass StringifierTest : public ::testing::Test {\n protected:\n  void SetUp() override {}\n};\n\nTEST_F(StringifierTest, StringifyBooleanArray) {\n  // Create boolean array with true, false, null values\n  arrow::BooleanBuilder builder;\n  ASSERT_TRUE(builder.Append(true).ok());\n  ASSERT_TRUE(builder.Append(false).ok());\n  ASSERT_TRUE(builder.AppendNull().ok());\n  ASSERT_TRUE(builder.Append(true).ok());\n\n  std::shared_ptr<arrow::Array> array;\n  ASSERT_TRUE(builder.Finish(&array).ok());\n\n  auto result = Stringify(array);\n\n  ASSERT_EQ(4, result.size());\n  EXPECT_EQ(\"true\", result[0]);\n  EXPECT_EQ(\"false\", result[1]);\n  EXPECT_EQ(\"null\", result[2]);\n  EXPECT_EQ(\"true\", result[3]);\n}\n\nTEST_F(StringifierTest, StringifyInt32Array) {\n  // Create int32 array with positive, negative, and null values\n  arrow::Int32Builder builder;\n  ASSERT_TRUE(builder.Append(42).ok());\n  ASSERT_TRUE(builder.Append(-123).ok());\n  ASSERT_TRUE(builder.AppendNull().ok());\n  ASSERT_TRUE(builder.Append(0).ok());\n  ASSERT_TRUE(builder.Append(2147483647).ok());   // Max int32\n  ASSERT_TRUE(builder.Append(-2147483648).ok());  // Min int32\n\n  std::shared_ptr<arrow::Array> array;\n  ASSERT_TRUE(builder.Finish(&array).ok());\n\n  auto result = Stringify(array);\n\n  ASSERT_EQ(6, result.size());\n  EXPECT_EQ(\"42\", result[0]);\n  EXPECT_EQ(\"-123\", result[1]);\n  EXPECT_EQ(\"null\", result[2]);\n  EXPECT_EQ(\"0\", result[3]);\n  EXPECT_EQ(\"2147483647\", result[4]);\n  EXPECT_EQ(\"-2147483648\", result[5]);\n}\n\nTEST_F(StringifierTest, StringifyInt64Array) {\n  // Create int64 array with large values\n  arrow::Int64Builder builder;\n  ASSERT_TRUE(builder.Append(9223372036854775807LL).ok());       // Max int64\n  ASSERT_TRUE(builder.Append(-9223372036854775807LL - 1).ok());  // Min int64\n  ASSERT_TRUE(builder.Append(0).ok());\n  ASSERT_TRUE(builder.AppendNull().ok());\n\n  std::shared_ptr<arrow::Array> array;\n  ASSERT_TRUE(builder.Finish(&array).ok());\n\n  auto result = Stringify(array);\n\n  ASSERT_EQ(4, result.size());\n  EXPECT_EQ(\"9223372036854775807\", result[0]);\n  EXPECT_EQ(\"-9223372036854775808\", result[1]);\n  EXPECT_EQ(\"0\", result[2]);\n  EXPECT_EQ(\"null\", result[3]);\n}\n\nTEST_F(StringifierTest, StringifyFloatArray) {\n  // Create float array with various floating point values\n  arrow::FloatBuilder builder;\n  ASSERT_TRUE(builder.Append(3.14159f).ok());\n  ASSERT_TRUE(builder.Append(-2.71828f).ok());\n  ASSERT_TRUE(builder.Append(0.0f).ok());\n  ASSERT_TRUE(builder.AppendNull().ok());\n  ASSERT_TRUE(builder.Append(std::numeric_limits<float>::infinity()).ok());\n  ASSERT_TRUE(builder.Append(-std::numeric_limits<float>::infinity()).ok());\n\n  std::shared_ptr<arrow::Array> array;\n  ASSERT_TRUE(builder.Finish(&array).ok());\n\n  auto result = Stringify(array);\n\n  ASSERT_EQ(6, result.size());\n  EXPECT_EQ(\"3.14159\", result[0]);\n  EXPECT_EQ(\"-2.71828\", result[1]);\n  EXPECT_EQ(\"0\", result[2]);\n  EXPECT_EQ(\"null\", result[3]);\n  EXPECT_EQ(\"inf\", result[4]);\n  EXPECT_EQ(\"-inf\", result[5]);\n}\n\nTEST_F(StringifierTest, StringifyDoubleArray) {\n  // Create double array with high precision values\n  arrow::DoubleBuilder builder;\n  ASSERT_TRUE(builder.Append(3.141592653589793).ok());\n  ASSERT_TRUE(builder.Append(-2.718281828459045).ok());\n  ASSERT_TRUE(builder.Append(0.0).ok());\n  ASSERT_TRUE(builder.Append(1).ok());\n  ASSERT_TRUE(builder.AppendNull().ok());\n\n  std::shared_ptr<arrow::Array> array;\n  ASSERT_TRUE(builder.Finish(&array).ok());\n\n  auto result = Stringify(array);\n\n  ASSERT_EQ(5, result.size());\n  EXPECT_EQ(\"3.141592653589793\", result[0]);\n  EXPECT_EQ(\"-2.718281828459045\", result[1]);\n  EXPECT_EQ(\"0\", result[2]);\n  EXPECT_EQ(\"1\", result[3]);\n  EXPECT_EQ(\"null\", result[4]);\n}\n\nTEST_F(StringifierTest, StringifyStringArray) {\n  // Create string array with various string values\n  arrow::StringBuilder builder;\n  ASSERT_TRUE(builder.Append(\"hello\").ok());\n  ASSERT_TRUE(builder.Append(\"world\").ok());\n  ASSERT_TRUE(builder.Append(\"\").ok());  // empty string\n  ASSERT_TRUE(builder.AppendNull().ok());\n  ASSERT_TRUE(builder.Append(\"test string with spaces\").ok());\n  ASSERT_TRUE(builder.Append(\"special_chars: !@#$%^&*()\").ok());\n\n  std::shared_ptr<arrow::Array> array;\n  ASSERT_TRUE(builder.Finish(&array).ok());\n\n  auto result = Stringify(array);\n\n  ASSERT_EQ(6, result.size());\n  EXPECT_EQ(\"hello\", result[0]);\n  EXPECT_EQ(\"world\", result[1]);\n  EXPECT_EQ(\"\", result[2]);\n  EXPECT_EQ(\"null\", result[3]);\n  EXPECT_EQ(\"test string with spaces\", result[4]);\n  EXPECT_EQ(\"special_chars: !@#$%^&*()\", result[5]);\n}\n\nTEST_F(StringifierTest, StringifyLargeStringArray) {\n  // Create large string array\n  arrow::LargeStringBuilder builder;\n  ASSERT_TRUE(builder.Append(\"large string 1\").ok());\n  ASSERT_TRUE(builder.Append(\"large string 2\").ok());\n  ASSERT_TRUE(builder.AppendNull().ok());\n\n  std::shared_ptr<arrow::Array> array;\n  ASSERT_TRUE(builder.Finish(&array).ok());\n\n  auto result = Stringify(array);\n\n  ASSERT_EQ(3, result.size());\n  EXPECT_EQ(\"large string 1\", result[0]);\n  EXPECT_EQ(\"large string 2\", result[1]);\n  EXPECT_EQ(\"null\", result[2]);\n}\n\nTEST_F(StringifierTest, StringifyEmptyArray) {\n  // Test empty array\n  arrow::Int32Builder builder;\n  std::shared_ptr<arrow::Array> array;\n  ASSERT_TRUE(builder.Finish(&array).ok());\n\n  auto result = Stringify(array);\n\n  EXPECT_TRUE(result.empty());\n}\n\nTEST_F(StringifierTest, StringifyAllNullArray) {\n  // Test array with all null values\n  arrow::Int32Builder builder;\n  ASSERT_TRUE(builder.AppendNull().ok());\n  ASSERT_TRUE(builder.AppendNull().ok());\n  ASSERT_TRUE(builder.AppendNull().ok());\n\n  std::shared_ptr<arrow::Array> array;\n  ASSERT_TRUE(builder.Finish(&array).ok());\n\n  auto result = Stringify(array);\n\n  ASSERT_EQ(3, result.size());\n  EXPECT_EQ(\"null\", result[0]);\n  EXPECT_EQ(\"null\", result[1]);\n  EXPECT_EQ(\"null\", result[2]);\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/table_util.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/table_util.h\"\n\n#include \"arrow/array.h\"\n#include \"yacl/base/exception.h\"\n\nnamespace scql::engine::util {\n\nstd::shared_ptr<arrow::Table> ConstructTableFromTensors(\n    ExecContext* ctx, const RepeatedPbTensor& input_pbs) {\n  std::vector<std::shared_ptr<arrow::Field>> fields;\n  std::vector<std::shared_ptr<arrow::ChunkedArray>> chunked_arrs;\n  int64_t pre_length = 0;\n  for (int i = 0; i < input_pbs.size(); ++i) {\n    const auto& input_pb = input_pbs[i];\n    auto tensor = ctx->GetTensorTable()->GetTensor(input_pb.name());\n    YACL_ENFORCE(tensor != nullptr, \"get tensor={} from tensor table failed\",\n                 input_pb.name());\n    auto chunked_arr = tensor->ToArrowChunkedArray();\n    if (i > 0) {\n      YACL_ENFORCE(chunked_arr->length() == pre_length,\n                   \"input tensors must have the same length\");\n    }\n    pre_length = chunked_arr->length();\n\n    fields.emplace_back(arrow::field(input_pb.name(), chunked_arr->type()));\n    chunked_arrs.emplace_back(chunked_arr);\n  }\n\n  auto table = arrow::Table::Make(arrow::schema(fields), chunked_arrs);\n  return table;\n}\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/table_util.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include \"arrow/table.h\"\n\n#include \"engine/core/tensor.h\"\n#include \"engine/framework/exec.h\"\n\nnamespace scql::engine::util {\n\nstd::shared_ptr<arrow::Table> ConstructTableFromTensors(\n    ExecContext* ctx, const RepeatedPbTensor& input_pbs);\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/tensor_util.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/tensor_util.h\"\n\n#include \"arrow/visit_array_inline.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/core/arrow_helper.h\"\n#include \"engine/core/tensor.h\"\n#include \"engine/util/copy_to_proto_vistor.h\"\n#include \"engine/util/spu_io.h\"\n#include \"engine/util/time_util.h\"\n\nnamespace scql::engine::util {\n\nstd::string GetStringValue(const pb::Tensor& t) {\n  if (t.option() != pb::TensorOptions::VALUE ||\n      t.elem_type() != pb::PrimitiveDataType::STRING ||\n      t.string_data_size() < 1) {\n    YACL_THROW(\"tensor does not have string value\");\n  }\n  return t.string_data(0);\n}\n\nuint32_t GetScalarUint32(const std::shared_ptr<Tensor>& t) {\n  auto num_array = util::ConcatenateChunkedArray(t->ToArrowChunkedArray());\n  const auto* num_array_ptr =\n      dynamic_cast<const arrow::UInt32Array*>(num_array.get());\n  YACL_ENFORCE(num_array_ptr, \"cast tensor to uint32_t failed\");\n\n  YACL_ENFORCE(num_array_ptr->length() == 1,\n               \"input tensor should be a scalar, but got {}\",\n               num_array_ptr->length());\n  return num_array_ptr->Value(0);\n}\n\nstd::vector<std::string> GetStringValues(const pb::Tensor& t) {\n  if (t.option() != pb::TensorOptions::VALUE ||\n      t.elem_type() != pb::PrimitiveDataType::STRING) {\n    YACL_THROW(\"tensor does not have string values\");\n  }\n\n  std::vector<std::string> result(t.string_data_size());\n  for (int i = 0; i < t.string_data_size(); ++i) {\n    result[i] = t.string_data(i);\n  }\n  return result;\n}\n\nint64_t GetInt64Value(const pb::Tensor& t) {\n  if (t.option() != pb::TensorOptions::VALUE ||\n      t.elem_type() != pb::PrimitiveDataType::INT64 ||\n      t.int64_data_size() < 1) {\n    YACL_THROW(\"tensor does not have int64 value\");\n  }\n  return t.int64_data(0);\n}\n\nvoid SetStringValues(pb::Tensor* t, const std::vector<std::string>& values) {\n  t->set_option(pb::TensorOptions::VALUE);\n  t->set_elem_type(pb::PrimitiveDataType::STRING);\n  for (const auto& value : values) {\n    t->add_string_data(value);\n  }\n}\n\nvoid SetInt64Values(pb::Tensor* t, const std::vector<int64_t>& values) {\n  t->set_option(pb::TensorOptions::VALUE);\n  t->set_elem_type(pb::PrimitiveDataType::INT64);\n  for (const auto& value : values) {\n    t->add_int64_data(value);\n  }\n}\n\nvoid SetDoubleValues(pb::Tensor* t, const std::vector<double>& values) {\n  t->set_option(pb::TensorOptions::VALUE);\n  t->set_elem_type(pb::PrimitiveDataType::FLOAT64);\n  for (const auto& value : values) {\n    t->add_double_data(value);\n  }\n}\n\ndouble GetDoubleValue(const pb::Tensor& t) {\n  if (t.option() != pb::TensorOptions::VALUE ||\n      (t.elem_type() != pb::PrimitiveDataType::FLOAT32 &&\n       t.elem_type() != pb::PrimitiveDataType::FLOAT64) ||\n      t.double_data_size() < 1) {\n    YACL_THROW(\"tensor does not have double value\");\n  }\n  return t.double_data(0);\n}\n\nbool GetBooleanValue(const pb::Tensor& t) {\n  if (t.option() != pb::TensorOptions::VALUE ||\n      t.elem_type() != pb::PrimitiveDataType::BOOL || t.bool_data_size() < 1) {\n    YACL_THROW(\"tensor does not have boolean value\");\n  }\n  return t.bool_data(0);\n}\n\nvoid SetBooleanValues(pb::Tensor* t, const std::vector<bool>& values) {\n  t->set_option(pb::TensorOptions::VALUE);\n  t->set_elem_type(pb::PrimitiveDataType::BOOL);\n  for (const auto& value : values) {\n    t->add_bool_data(value);\n  }\n}\n\nstd::vector<bool> GetBooleanValues(const pb::Tensor& t) {\n  if (t.option() != pb::TensorOptions::VALUE ||\n      t.elem_type() != pb::PrimitiveDataType::BOOL) {\n    YACL_THROW(\"tensor does not have boolean value\");\n  }\n  std::vector<bool> result(t.bool_data_size());\n  for (int i = 0; i < t.bool_data_size(); i++) {\n    result[i] = t.bool_data(i);\n  }\n  return result;\n}\n\npb::TensorStatus GetTensorStatus(const pb::Tensor& t) {\n  return t.annotation().status();\n}\n\nbool AreTensorsStatusMatched(const RepeatedPbTensor& tensors,\n                             pb::TensorStatus expect_status) {\n  return std::all_of(tensors.begin(), tensors.end(),\n                     [&expect_status](const auto& t) {\n                       return IsTensorStatusMatched(t, expect_status);\n                     });\n}\n\nbool AreTensorsStatusMatchedOneOf(\n    const RepeatedPbTensor& tensors,\n    const std::vector<pb::TensorStatus>& status_set) {\n  for (int i = 1; i < tensors.size(); ++i) {\n    auto st = GetTensorStatus(tensors[i]);\n    bool matched = false;\n    for (const auto& elem : status_set) {\n      if (st == elem) {\n        matched = true;\n        continue;\n      }\n    }\n    if (!matched) {\n      return false;\n    }\n  }\n  return true;\n}\n\nbool OneOfTensorsStatusMatched(const RepeatedPbTensor& tensors,\n                               pb::TensorStatus expect_status) {\n  return std::any_of(tensors.begin(), tensors.end(), [&](const pb::Tensor& t) {\n    return IsTensorStatusMatched(t, expect_status);\n  });\n}\n\nbool IsTensorStatusMatched(const pb::Tensor& t,\n                           pb::TensorStatus expect_status) {\n  return GetTensorStatus(t) == expect_status;\n}\n\nbool AreTensorsStatusEqualAndOneOf(const RepeatedPbTensor& tensors,\n                                   std::vector<pb::TensorStatus> status_set) {\n  auto st = GetTensorStatus(tensors[0]);\n  for (int i = 1; i < tensors.size(); ++i) {\n    if (!IsTensorStatusMatched(tensors[i], st)) {\n      return false;\n    }\n  }\n  return std::any_of(\n      status_set.begin(), status_set.end(),\n      [&st](const pb::TensorStatus& elem) { return st == elem; });\n}\n\nvoid CopyValuesToProto(const std::shared_ptr<Tensor>& from_tensor,\n                       pb::Tensor* to_proto) {\n  CopyToProtoVistor copy_vistor(to_proto, from_tensor->GetNullCount() > 0);\n  const auto& chunked_arr = from_tensor->ToArrowChunkedArray();\n  for (int i = 0; i < chunked_arr->num_chunks(); ++i) {\n    THROW_IF_ARROW_NOT_OK(\n        arrow::VisitArrayInline(*(chunked_arr->chunk(i)), &copy_vistor));\n  }\n}\n\nstd::shared_ptr<Tensor> ConvertDateTimeToInt64(\n    const std::shared_ptr<arrow::ChunkedArray>& from_chunked_arr) {\n  ConvertDateTimeToInt64Visitor convert_visitor;\n  for (int i = 0; i < from_chunked_arr->num_chunks(); ++i) {\n    THROW_IF_ARROW_NOT_OK(arrow::VisitArrayInline(*(from_chunked_arr->chunk(i)),\n                                                  &convert_visitor));\n  }\n  return convert_visitor.GetResultTensor();\n}\n\nstd::shared_ptr<arrow::ChunkedArray> ConvertDateTimeToInt64(\n    const std::shared_ptr<arrow::Array>& from_arr) {\n  ConvertDateTimeToInt64Visitor convert_visitor;\n  THROW_IF_ARROW_NOT_OK(arrow::VisitArrayInline(*from_arr, &convert_visitor));\n  return convert_visitor.GetResultTensor()->ToArrowChunkedArray();\n}\n\nvoid ConvertDateTimeAndCopyValuesToProto(\n    const std::shared_ptr<Tensor>& from_tensor, pb::Tensor* to_proto) {\n  ConvertDatetimeProtoVistor convert_copy_vistor(\n      to_proto, from_tensor->GetNullCount() != 0);\n  const auto& chunked_arr = from_tensor->ToArrowChunkedArray();\n  for (int i = 0; i < chunked_arr->num_chunks(); ++i) {\n    THROW_IF_ARROW_NOT_OK(arrow::VisitArrayInline(*(chunked_arr->chunk(i)),\n                                                  &convert_copy_vistor));\n  }\n}\n\nbool AreAllBucketTensor(const std::vector<TensorPtr>& tensors) {\n  return std::all_of(tensors.begin(), tensors.end(),\n                     [](const TensorPtr& t) { return t->IsBucketTensor(); });\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/tensor_util.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <string>\n#include <vector>\n\n#include \"engine/core/tensor.h\"\n\nnamespace scql::engine::util {\n\n/// utils for scql tensor protobuf representation\n\nstd::string GetStringValue(const pb::Tensor& t);\n\nstd::vector<std::string> GetStringValues(const pb::Tensor& t);\n\nuint32_t GetScalarUint32(const std::shared_ptr<Tensor>& t);\n\nvoid SetStringValues(pb::Tensor* t, const std::vector<std::string>& values);\n\nint64_t GetInt64Value(const pb::Tensor& t);\n\nvoid SetInt64Values(pb::Tensor* t, const std::vector<int64_t>& values);\n\nbool GetBooleanValue(const pb::Tensor& t);\n\nstd::vector<bool> GetBooleanValues(const pb::Tensor& t);\n\nvoid SetDoubleValues(pb::Tensor* t, const std::vector<double>& values);\n\ndouble GetDoubleValue(const pb::Tensor& t);\n\nvoid SetBooleanValues(pb::Tensor* t, const std::vector<bool>& values);\n\npb::TensorStatus GetTensorStatus(const pb::Tensor& t);\n\n/// @returns true if all tensors' status are equal to @param[in] expect_status\nbool AreTensorsStatusMatched(const RepeatedPbTensor& tensors,\n                             pb::TensorStatus expect_status);\n\n/// @returns true if one of tensors' status is equal to @param[in] expect_status\nbool OneOfTensorsStatusMatched(const RepeatedPbTensor& tensors,\n                               pb::TensorStatus expect_status);\nbool AreTensorsStatusMatchedOneOf(\n    const RepeatedPbTensor& tensors,\n    const std::vector<pb::TensorStatus>& status_set);\nbool IsTensorStatusMatched(const pb::Tensor& t, pb::TensorStatus expect_status);\n\n/// @returns true if all tensor' status are the same and be one of\n/// @param[in] status_set.\n///\n/// Requirements:\n/// @param[in] tensors size should >= 1\nbool AreTensorsStatusEqualAndOneOf(const RepeatedPbTensor& tensors,\n                                   std::vector<pb::TensorStatus> status_set);\n\nvoid CopyValuesToProto(const std::shared_ptr<Tensor>& from_tensor,\n                       pb::Tensor* to_proto);\n\nstd::shared_ptr<Tensor> ConvertDateTimeToInt64(\n    const std::shared_ptr<arrow::ChunkedArray>& from_chunked_arr);\n\nstd::shared_ptr<arrow::ChunkedArray> ConvertDateTimeToInt64(\n    const std::shared_ptr<arrow::Array>& from_arr);\n\nvoid ConvertDateTimeAndCopyValuesToProto(\n    const std::shared_ptr<Tensor>& from_tensor, pb::Tensor* to_proto);\n\nbool AreAllBucketTensor(const std::vector<TensorPtr>& tensors);\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/time_util.cc",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/time_util.h\"\n\n#include <ctime>\n\n#include \"arrow/compute/exec.h\"\n#include \"yacl/base/exception.h\"\n\n#include \"engine/core/tensor_constructor.h\"\nnamespace scql::engine::util {\n\nstd::string ConvertEpochToStr(time_t epoch) {\n  struct tm date_time;\n  auto* date_ptr = gmtime_r(&epoch, &date_time);\n  YACL_ENFORCE(date_ptr != nullptr,\n               \"gmtime_r failed, errno: {}, error message: {}\", errno,\n               strerror(errno));\n  char buf[20];\n  strftime(buf, sizeof(buf), \"%Y-%m-%d %H:%M:%S\", &date_time);\n  std::string date_str(buf);\n  return date_str;\n}\n\nint64_t TimeZoneToSeconds(const std::string& time_zone) {\n  size_t length = time_zone.length();\n  YACL_ENFORCE(length == 6, \"unsupported time zone: {}\", time_zone);\n\n  int sign = time_zone[0] == '+' ? 1 : (time_zone[0] == '-' ? -1 : 0);\n  YACL_ENFORCE(sign != 0, \"unsupported time zone: {}\", time_zone);\n  YACL_ENFORCE(std::isdigit(time_zone[1]) && std::isdigit(time_zone[2]) &&\n                   time_zone[3] == ':' && std::isdigit(time_zone[4]) &&\n                   std::isdigit(time_zone[5]),\n               \"unsupported time zone: {}\", time_zone);\n\n  int hours = (time_zone[1] - '0') * 10 + time_zone[2] - '0';\n  int minutes = (time_zone[4] - '0') * 10 + time_zone[5] - '0';\n  YACL_ENFORCE(minutes <= kMinutePerHour, \"unsupported time zone: {}\",\n               time_zone);\n  int seconds = hours * kSecondPerHour + minutes * kSecondsPerMinute;\n  YACL_ENFORCE(seconds < kMaxTimeZoneHour * kSecondPerHour,\n               \"unsupported time zone: {}\", time_zone);\n\n  return seconds * sign;\n}\n\nstd::shared_ptr<Tensor> CompensateTimeZone(\n    const std::shared_ptr<Tensor>& from_tensor, const std::string& time_zone) {\n  int64_t time_zone_offset_s = TimeZoneToSeconds(time_zone);\n  auto chunked_array = from_tensor->ToArrowChunkedArray();\n  arrow::Result<arrow::Datum> result = arrow::compute::CallFunction(\n      \"add\", {from_tensor->ToArrowChunkedArray(),\n              arrow::MakeScalar(time_zone_offset_s)});\n\n  YACL_ENFORCE(result.ok(),\n               \"caught error while invoking arrow add function: {}\",\n               result.status().ToString());\n  return TensorFrom(result.ValueOrDie().chunked_array());\n}\n\nConvertDatetimeProtoVistor::ConvertDatetimeProtoVistor(pb::Tensor* to_tensor,\n                                                       bool contain_null)\n    : to_proto_(to_tensor), contain_null_(contain_null) {\n  YACL_ENFORCE(to_proto_, \"to_proto_ can not be null.\");\n}\n\narrow::Status ConvertDatetimeProtoVistor::Visit(\n    const arrow::NumericArray<arrow::Int64Type>& array) {\n  for (int64_t i = 0; i < array.length(); i++) {\n    to_proto_->add_string_data(\n        ConvertEpochToStr(static_cast<time_t>(array.GetView(i))));\n    if (contain_null_) {\n      to_proto_->add_data_validity(array.IsValid(i));\n    }\n  }\n  return arrow::Status::OK();\n}\n\nstd::shared_ptr<Tensor> ConvertDateTimeToInt64Visitor::GetResultTensor() {\n  std::shared_ptr<Tensor> result;\n  builder_.Finish(&result);\n  return result;\n}\n\nint64_t ConvertDateTimeToInt64Visitor::DateUnitCountPerSecond(\n    arrow::TimeUnit::type unit_type) {\n  int64_t unit;\n  switch (unit_type) {\n    case arrow::TimeUnit::type::SECOND:\n      unit = 1;\n      break;\n    case arrow::TimeUnit::type::MILLI:\n      unit = kMillisPerSecond;\n      break;\n    case arrow::TimeUnit::type::MICRO:\n      unit = kMicrosPerSecond;\n      break;\n    case arrow::TimeUnit::type::NANO:\n      unit = kNanosPerSecond;\n      break;\n    default:\n      YACL_THROW(\"unsupported TimeUnit type: {}\", fmt::underlying(unit_type));\n  }\n  return unit;\n}\n\narrow::Status ConvertDateTimeToInt64Visitor::Visit(\n    const arrow::NumericArray<arrow::Date32Type>& array) {\n  for (int64_t i = 0; i < array.length(); i++) {\n    if (array.IsValid(i)) {\n      int64_t value = static_cast<int32_t>(array.GetView(i)) * kSecondPerDay;\n      builder_.Append(value);\n    } else {\n      builder_.AppendNull();\n    }\n  }\n  return arrow::Status::OK();\n}\n\narrow::Status ConvertDateTimeToInt64Visitor::Visit(\n    const arrow::NumericArray<arrow::Date64Type>& array) {\n  for (int64_t i = 0; i < array.length(); i++) {\n    if (array.IsValid(i)) {\n      int64_t value = static_cast<int64_t>(array.GetView(i)) / kMillisPerSecond;\n      builder_.Append(value);\n    } else {\n      builder_.AppendNull();\n    }\n  }\n  return arrow::Status::OK();\n}\n\narrow::Status ConvertDateTimeToInt64Visitor::Visit(\n    const arrow::NumericArray<arrow::TimestampType>& array) {\n  int64_t unit = DateUnitCountPerSecond(\n      arrow::internal::checked_pointer_cast<arrow::TimestampType>(array.type())\n          ->unit());\n  for (int64_t i = 0; i < array.length(); i++) {\n    if (array.IsValid(i)) {\n      int64_t value = static_cast<int64_t>(array.GetView(i));\n      builder_.Append(value / unit);\n    } else {\n      builder_.AppendNull();\n    }\n  }\n  return arrow::Status::OK();\n}\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/time_util.h",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <string>\n\n#include \"engine/core/primitive_builder.h\"\n\n#include \"api/core.pb.h\"\n\nnamespace scql::engine::util {\n\nconstexpr int64_t kSecondPerDay = 86400;\nconstexpr int64_t kMillisPerSecond = 1000;\nconstexpr int64_t kMicrosPerSecond = 1000000;\nconstexpr int64_t kNanosPerSecond = 1000000000;\nconstexpr int64_t kMinutePerHour = 60;\nconstexpr int64_t kSecondsPerMinute = 60;\nconstexpr int64_t kSecondPerHour = 3600;\nconstexpr int64_t kMaxTimeZoneHour = 14;\n\nstd::string ConvertEpochToStr(time_t epoch);\n\nint64_t TimeZoneToSeconds(const std::string& time_zone);\n\nstd::shared_ptr<Tensor> CompensateTimeZone(\n    const std::shared_ptr<Tensor>& from_tensor, const std::string& time_zone);\n\n// arrow has no func to convert timestamp to str:\n// https://arrow.apache.org/docs/cpp/compute.html#\n/// @brief ConvertDatetimeProtoVistor convert timestamp to str and copy array's\n/// value to pb::Tensor.\nclass ConvertDatetimeProtoVistor {\n public:\n  ConvertDatetimeProtoVistor() = delete;\n\n  explicit ConvertDatetimeProtoVistor(pb::Tensor* to_tensor, bool contain_null);\n\n  template <typename T>\n  arrow::Status Visit(const T& array) {\n    return arrow::Status::NotImplemented(\n        fmt::format(\"type {} is not implemented in ConvertDatetimeProtoVistor\",\n                    array.type()->name()));\n  }\n\n  arrow::Status Visit(const arrow::NumericArray<arrow::Int64Type>& array);\n\n private:\n  pb::Tensor* to_proto_;\n  bool contain_null_;\n};\n\nclass ConvertDateTimeToInt64Visitor {\n public:\n  ConvertDateTimeToInt64Visitor() = default;\n\n  std::shared_ptr<Tensor> GetResultTensor();\n\n  static int64_t DateUnitCountPerSecond(arrow::TimeUnit::type unit_type);\n\n  template <typename T>\n  arrow::Status Visit(const T& array) {\n    return arrow::Status::NotImplemented(fmt::format(\n        \"type {} is not implemented in ConvertDateTimeToInt64Visitor\",\n        array.type()->name()));\n  }\n\n  // Date32Type for 32-bit date data (as number of days since UNIX epoch)\n  arrow::Status Visit(const arrow::NumericArray<arrow::Date32Type>& array);\n\n  // Date64Type for 64-bit date data (as number of milliseconds since UNIX\n  // epoch)\n  arrow::Status Visit(const arrow::NumericArray<arrow::Date64Type>& array);\n\n  // TimestampType for datetime data (as number of seconds, milliseconds,\n  // microseconds or nanoseconds since UNIX epoch)\n  arrow::Status Visit(const arrow::NumericArray<arrow::TimestampType>& array);\n\n private:\n  Int64TensorBuilder builder_;\n};\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/trace_categories.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/trace_categories.h\"\n\n#include <fstream>\n\n// Reserves internal static storage for our tracing categories.\nPERFETTO_TRACK_EVENT_STATIC_STORAGE();\n\nnamespace scql::engine::util {\n\nvoid InitializePerfetto() {\n  ::perfetto::TracingInitArgs args;\n  args.backends = ::perfetto::kInProcessBackend;\n  ::perfetto::Tracing::Initialize(args);\n  ::perfetto::TrackEvent::Register();\n}\n\nstd::unique_ptr<::perfetto::TracingSession> StartTracing(int fd) {\n  ::perfetto::TraceConfig cfg;\n  cfg.add_buffers()->set_size_kb(102400);\n  auto* ds_cfg = cfg.add_data_sources()->mutable_config();\n  ds_cfg->set_name(\"track_event\");\n  auto tracing_session = ::perfetto::Tracing::NewTrace();\n  tracing_session->Setup(cfg, fd);\n  tracing_session->StartBlocking();\n  return tracing_session;\n}\n\nvoid StopTracing(std::unique_ptr<::perfetto::TracingSession> tracing_session) {\n  ::perfetto::TrackEvent::Flush();\n  // Stop tracing and read the trace data.\n  tracing_session->StopBlocking();\n}\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/trace_categories.h",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n#include <fcntl.h>\n\n#include <cerrno>\n\n#include \"perfetto.h\"\n#include \"spdlog/spdlog.h\"\n\n#define OPERATOR_CATEGORY \"Operator\"\n#define RPCCALL_CATEGORY \"RpcCall\"\n#define OTHER_CATEGORY \"Other\"\n\n#define PERFETTO_INTERNAL_SCOPED_FINALIZER_WITH_TRACK(category)                \\\n  struct PERFETTO_UID(ScopedEvent) {                                           \\\n    struct EventFinalizer {                                                    \\\n      EventFinalizer(::perfetto::base::PlatformThreadId id) { id_ = id; }      \\\n      ~EventFinalizer() { TRACE_EVENT_END(category, ::perfetto::Track(id_)); } \\\n                                                                               \\\n      EventFinalizer(const EventFinalizer&) = delete;                          \\\n      inline EventFinalizer& operator=(const EventFinalizer&) = delete;        \\\n                                                                               \\\n      EventFinalizer(EventFinalizer&&) =                                       \\\n          PERFETTO_INTERNAL_EVENT_FINALIZER_KEYWORD;                           \\\n      EventFinalizer& operator=(EventFinalizer&&) = delete;                    \\\n      ::perfetto::base::PlatformThreadId id_;                                  \\\n    } finalizer;                                                               \\\n  }\n\n#define PERFETTO_INTERNAL_SCOPED_TRACK_EVENT_WITH_TRACK(category, name, tid, \\\n                                                        ...)                 \\\n  TRACE_EVENT_BEGIN(category, name, ::perfetto::Track(tid), ##__VA_ARGS__);  \\\n  PERFETTO_INTERNAL_SCOPED_FINALIZER_WITH_TRACK(category)                    \\\n  PERFETTO_UID(scoped_event) { tid }\n\n// Begin a slice which gets automatically closed when going out of scope.\n#define TRACE_EVENT_DEFAULT_TRACK(category, name, ...)                       \\\n  PERFETTO_INTERNAL_SCOPED_TRACK_EVENT_WITH_TRACK(                           \\\n      category, ::perfetto::internal::DecayEventNameType(name),              \\\n      ::perfetto::internal::TracingMuxer::Get() == nullptr                   \\\n          ? 0                                                                \\\n          : ::perfetto::internal::TracingMuxer::Get()->GetCurrentThreadId(), \\\n      ##__VA_ARGS__)\n\nPERFETTO_DEFINE_CATEGORIES(\n    ::perfetto::Category(OPERATOR_CATEGORY).SetDescription(\"operators.\"),\n    ::perfetto::Category(RPCCALL_CATEGORY).SetDescription(\"api call.\"),\n    ::perfetto::Category(OTHER_CATEGORY).SetDescription(\"other tasks.\"));\n\n#define COMMUNICATION_COUNTER(stats)                        \\\n  TRACE_COUNTER(OTHER_CATEGORY, \"yacl::link::sent_bytes\",   \\\n                stats->sent_bytes.load());                  \\\n  TRACE_COUNTER(OTHER_CATEGORY, \"yacl::link::recv_bytes\",   \\\n                stats->recv_bytes.load());                  \\\n  TRACE_COUNTER(OTHER_CATEGORY, \"yacl::link::sent_actions\", \\\n                stats->sent_actions.load());                \\\n  TRACE_COUNTER(OTHER_CATEGORY, \"yacl::link::recv_actions\", \\\n                stats->recv_actions.load());\n\nnamespace scql::engine::util {\n\nvoid InitializePerfetto();\n\nstd::unique_ptr<::perfetto::TracingSession> StartTracing(int fd);\n\nvoid StopTracing(std::unique_ptr<::perfetto::TracingSession> tracing_session);\n\nclass TracingSessionGuard {\n public:\n  explicit TracingSessionGuard(bool enable_trace,\n                               const std::string& process_name = \"\",\n                               const std::string& trace_log_path = \"\")\n      : enable_trace_(enable_trace), fd_(-1) {\n    if (!enable_trace_) {\n      return;\n    }\n    // setup perfetto tracing session\n    scql::engine::util::InitializePerfetto();\n    fd_ = open(trace_log_path.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0600);\n    if (fd_ == -1) {\n      // disable tracing when failed to write log\n      enable_trace_ = false;\n      SPDLOG_ERROR(\"failed to open: {}, errorno: {}\", trace_log_path, errno);\n      return;\n    }\n    tracing_session_ = scql::engine::util::StartTracing(fd_);\n    // Give a custom name for the traced process.\n    ::perfetto::ProcessTrack process_track =\n        ::perfetto::ProcessTrack::Current();\n    ::perfetto::protos::gen::TrackDescriptor desc = process_track.Serialize();\n    desc.mutable_process()->set_process_name(process_name);\n    ::perfetto::TrackEvent::SetTrackDescriptor(process_track, desc);\n  }\n\n  TracingSessionGuard(const TracingSessionGuard&) = delete;\n  TracingSessionGuard& operator=(const TracingSessionGuard&) = delete;\n\n  ~TracingSessionGuard() {\n    if (enable_trace_) {\n      scql::engine::util::StopTracing(std::move(tracing_session_));\n      if (fd_ != -1) {\n        close(fd_);\n      }\n    }\n  }\n\n private:\n  bool enable_trace_;\n  int fd_;\n  std::unique_ptr<::perfetto::TracingSession> tracing_session_;\n};\n\n}  // namespace scql::engine::util\n"
  },
  {
    "path": "engine/util/upload_info_helper.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/upload_info_helper.h\"\n\n#include <map>\n#include <string>\n#include <vector>\n\n#include \"arrow/api.h\"\n\n#include \"kuscia/proto/api/v1alpha1/common.pb.h\"\n\nnamespace scql::engine::util {\nstd::optional<dataproxy_sdk::pb::UploadInfo> ParseUploadInfoFromString(\n    const std::string& serialized_upload_info_str) {\n  dataproxy_sdk::pb::UploadInfo upload_info;\n  if (upload_info.ParseFromString(serialized_upload_info_str)) {\n    return upload_info;\n  } else {\n    return std::nullopt;\n  }\n}\n\ndataproxy_sdk::proto::UploadInfo ConvertProtoToClass(\n    const dataproxy_sdk::pb::UploadInfo& source_upload_info) {\n  dataproxy_sdk::proto::UploadInfo target_upload_info;\n\n  target_upload_info.set_domaindata_id(source_upload_info.domaindata_id());\n  target_upload_info.set_name(source_upload_info.name());\n  target_upload_info.set_type(source_upload_info.type());\n  target_upload_info.set_relative_uri(source_upload_info.relative_uri());\n  target_upload_info.set_datasource_id(source_upload_info.datasource_id());\n  target_upload_info.set_vendor(source_upload_info.vendor());\n\n  std::map<std::string, std::string> temp_attributes;\n  for (const auto& pair : source_upload_info.attributes()) {\n    temp_attributes[pair.first] = pair.second;\n  }\n  target_upload_info.set_attributes(temp_attributes);\n\n  std::vector<dataproxy_sdk::proto::DataColumn> temp_columns;\n\n  for (const kuscia::proto::api::v1alpha1::DataColumn& proto_column :\n       source_upload_info.columns()) {\n    dataproxy_sdk::proto::DataColumn custom_column;\n    custom_column.set_name(proto_column.name());\n    custom_column.set_type(proto_column.type());\n    custom_column.set_comment(proto_column.comment());\n    custom_column.set_not_nullable(proto_column.not_nullable());\n    temp_columns.push_back(custom_column);\n  }\n\n  target_upload_info.set_columns(temp_columns);\n\n  return target_upload_info;\n}\n\n// This function discards all existing columns in the UploadInfo object and\n// generates a completely new list of columns from the provided schema.\nvoid ResetColumnsFromSchema(const std::shared_ptr<arrow::Schema>& schema,\n                            dataproxy_sdk::proto::UploadInfo& upload_info) {\n  std::vector<dataproxy_sdk::proto::DataColumn> synced_columns;\n\n  for (const auto& field : schema->fields()) {\n    std::string name = field->name();\n    std::string type = ArrowToKusciaType(field->type());\n    bool not_nullable = !field->nullable();\n\n    dataproxy_sdk::proto::DataColumn new_column;\n    new_column.set_name(name);\n    new_column.set_type(type);\n    new_column.set_not_nullable(not_nullable);\n\n    synced_columns.push_back(new_column);\n  }\n\n  upload_info.set_columns(synced_columns);\n}\n\n// TODO: using arrow schema instaed of kuscia domaindata\n// kuscia supported types:\n// https://github.com/secretflow/dataproxy/blob/main/dataproxy-common/src/main/java/org/secretflow/dataproxy/common/utils/ArrowUtil.java#L32\n// arrow types:\n// https://github.com/apache/arrow/blob/main/cpp/src/arrow/type_fwd.h#L322\nstd::string ArrowToKusciaType(const std::shared_ptr<arrow::DataType>& dtype) {\n  switch (dtype->id()) {\n    case arrow::Type::FLOAT:\n      return \"float32\";\n    case arrow::Type::DOUBLE:\n      return \"float64\";\n    case arrow::Type::LARGE_STRING:\n      return \"string\";\n      // TODO: support timestamp[s]\n    default:\n      return dtype->ToString();\n  }\n  return \"\";\n}\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/upload_info_helper.h",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#pragma once\n\n#include <optional>\n#include <string>\n\n#include \"dataproxy_sdk/data_proxy_stream.h\"\n\n#include \"proto/data_proxy_pb.pb.h\"\n\nnamespace scql::engine::util {\n// Unmarshal string generated by proto.Marshal\nstd::optional<dataproxy_sdk::pb::UploadInfo> ParseUploadInfoFromString(\n    const std::string& serialized_upload_info_str);\n\ndataproxy_sdk::proto::UploadInfo ConvertProtoToClass(\n    const dataproxy_sdk::pb::UploadInfo& source_upload_info);\n\nvoid ResetColumnsFromSchema(const std::shared_ptr<arrow::Schema>& schema,\n                            dataproxy_sdk::proto::UploadInfo& upload_info);\n\nstd::string ArrowToKusciaType(const std::shared_ptr<arrow::DataType>& dtype);\n\n}  // namespace scql::engine::util"
  },
  {
    "path": "engine/util/upload_info_helper_test.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"engine/util/upload_info_helper.h\"\n\n#include \"gtest/gtest.h\"\n\nnamespace scql_proto = dataproxy_sdk::pb;\nnamespace dp_sdk = dataproxy_sdk::proto;\nnamespace scql_util = scql::engine::util;\n\nclass UploadInfoHelperTest : public ::testing::Test {\n protected:\n  scql_proto::UploadInfo CreateSampleProtoUploadInfo() {\n    scql_proto::UploadInfo proto_info;\n    proto_info.set_domaindata_id(\"proto_ddid_001\");\n    proto_info.set_name(\"Sample Proto Info\");\n    proto_info.set_type(\"table\");\n    proto_info.set_relative_uri(\"data/sample_table.csv\");\n    proto_info.set_datasource_id(\"ds_main\");\n    proto_info.set_vendor(\"SCQL_Engine\");\n\n    (*proto_info.mutable_attributes())[\"source_system\"] = \"SystemA\";\n    (*proto_info.mutable_attributes())[\"version\"] = \"1.0\";\n\n    auto* col1 = proto_info.add_columns();\n    col1->set_name(\"id\");\n    col1->set_type(\"int64\");\n    col1->set_comment(\"Primary key column\");\n    col1->set_not_nullable(true);\n\n    auto* col2 = proto_info.add_columns();\n    col2->set_name(\"description\");\n    col2->set_type(\"string\");\n    col2->set_comment(\"Text description, can be null\");\n    col2->set_not_nullable(false);\n\n    return proto_info;\n  }\n};\n\nTEST_F(UploadInfoHelperTest, ParseFromStringWithValidData) {\n  scql_proto::UploadInfo original_proto = CreateSampleProtoUploadInfo();\n  std::string serialized_data;\n  ASSERT_TRUE(original_proto.SerializeToString(&serialized_data));\n\n  std::optional<scql_proto::UploadInfo> parsed_opt =\n      scql_util::ParseUploadInfoFromString(serialized_data);\n\n  ASSERT_TRUE(parsed_opt.has_value());\n  const auto& parsed_proto = parsed_opt.value();\n\n  EXPECT_EQ(parsed_proto.domaindata_id(), original_proto.domaindata_id());\n  EXPECT_EQ(parsed_proto.name(), original_proto.name());\n  EXPECT_EQ(parsed_proto.type(), original_proto.type());\n  EXPECT_EQ(parsed_proto.relative_uri(), original_proto.relative_uri());\n  EXPECT_EQ(parsed_proto.datasource_id(), original_proto.datasource_id());\n  EXPECT_EQ(parsed_proto.vendor(), original_proto.vendor());\n\n  EXPECT_EQ(parsed_proto.attributes_size(), original_proto.attributes_size());\n  EXPECT_EQ(parsed_proto.attributes().at(\"source_system\"),\n            original_proto.attributes().at(\"source_system\"));\n\n  ASSERT_EQ(parsed_proto.columns_size(), original_proto.columns_size());\n  EXPECT_EQ(parsed_proto.columns(0).name(), original_proto.columns(0).name());\n  EXPECT_EQ(parsed_proto.columns(0).not_nullable(),\n            original_proto.columns(0).not_nullable());\n  EXPECT_EQ(parsed_proto.columns(1).name(), original_proto.columns(1).name());\n  EXPECT_EQ(parsed_proto.columns(1).not_nullable(),\n            original_proto.columns(1).not_nullable());\n}\n\nTEST_F(UploadInfoHelperTest, ConvertProtoToCustomClassFullData) {\n  scql_proto::UploadInfo source_proto = CreateSampleProtoUploadInfo();\n\n  dp_sdk::UploadInfo target_custom_info =\n      scql_util::ConvertProtoToClass(source_proto);\n\n  EXPECT_EQ(target_custom_info.domaindata_id(), source_proto.domaindata_id());\n  EXPECT_EQ(target_custom_info.name(), source_proto.name());\n  EXPECT_EQ(target_custom_info.type(), source_proto.type());\n  EXPECT_EQ(target_custom_info.relative_uri(), source_proto.relative_uri());\n  EXPECT_EQ(target_custom_info.datasource_id(), source_proto.datasource_id());\n  EXPECT_EQ(target_custom_info.vendor(), source_proto.vendor());\n\n  ASSERT_EQ(target_custom_info.attributes_size(),\n            source_proto.attributes_size());\n  EXPECT_EQ(target_custom_info.attributes().at(\"source_system\"),\n            source_proto.attributes().at(\"source_system\"));\n  EXPECT_EQ(target_custom_info.attributes().at(\"version\"),\n            source_proto.attributes().at(\"version\"));\n\n  ASSERT_EQ(target_custom_info.columns_size(), source_proto.columns_size());\n  ASSERT_EQ(target_custom_info.columns().size(),\n            static_cast<size_t>(source_proto.columns_size()));\n\n  const auto& custom_cols = target_custom_info.columns();\n\n  ASSERT_GE(custom_cols.size(), 1);\n  EXPECT_EQ(custom_cols[0].name(), source_proto.columns(0).name());\n  EXPECT_EQ(custom_cols[0].type(), source_proto.columns(0).type());\n  EXPECT_EQ(custom_cols[0].comment(), source_proto.columns(0).comment());\n  EXPECT_EQ(custom_cols[0].not_nullable(),\n            source_proto.columns(0).not_nullable());\n  EXPECT_TRUE(custom_cols[0].not_nullable());\n\n  ASSERT_GE(custom_cols.size(), 2);\n  EXPECT_EQ(custom_cols[1].name(), source_proto.columns(1).name());\n  EXPECT_EQ(custom_cols[1].type(), source_proto.columns(1).type());\n  EXPECT_EQ(custom_cols[1].comment(), source_proto.columns(1).comment());\n  EXPECT_EQ(custom_cols[1].not_nullable(),\n            source_proto.columns(1).not_nullable());\n  EXPECT_FALSE(custom_cols[1].not_nullable());\n}\n\nTEST_F(UploadInfoHelperTest, ResetColumnsFromSchemaTest) {\n  dp_sdk::UploadInfo upload_info;\n  auto* col1 = upload_info.add_columns();\n  col1->set_name(\"id\");\n  col1->set_type(\"int64\");\n  col1->set_not_nullable(true);\n\n  auto* col2 = upload_info.add_columns();\n  col2->set_name(\"obsolete_column\");\n  col2->set_type(\"string\");\n  col2->set_not_nullable(false);\n\n  auto field1 = arrow::field(\"id\", arrow::int64(), false);\n  auto field2 = arrow::field(\"float_val\", arrow::float32(), true);\n  auto field3 = arrow::field(\"double_val\", arrow::float64(), true);\n  auto field4 = arrow::field(\"string_val\", arrow::large_utf8(), true);\n  auto schema = arrow::schema({field1, field2, field3, field4});\n\n  scql_util::ResetColumnsFromSchema(schema, upload_info);\n\n  ASSERT_EQ(upload_info.columns_size(), 4);\n\n  const auto& synced_cols = upload_info.columns();\n  EXPECT_EQ(synced_cols[0].name(), \"id\");\n  EXPECT_EQ(synced_cols[0].type(), \"int64\");\n  EXPECT_TRUE(synced_cols[0].not_nullable());\n\n  EXPECT_EQ(synced_cols[1].name(), \"float_val\");\n  EXPECT_EQ(synced_cols[1].type(), \"float32\");\n  EXPECT_FALSE(synced_cols[1].not_nullable());\n\n  EXPECT_EQ(synced_cols[2].name(), \"double_val\");\n  EXPECT_EQ(synced_cols[2].type(), \"float64\");\n  EXPECT_FALSE(synced_cols[2].not_nullable());\n\n  EXPECT_EQ(synced_cols[3].name(), \"string_val\");\n  EXPECT_EQ(synced_cols[3].type(), \"string\");\n  EXPECT_FALSE(synced_cols[3].not_nullable());\n}"
  },
  {
    "path": "examples/opencore-demo/main.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/olekukonko/tablewriter\"\n\t\"github.com/sirupsen/logrus\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\t\"github.com/secretflow/scql/pkg/config\"\n\t\"github.com/secretflow/scql/pkg/executor\"\n\t\"github.com/secretflow/scql/pkg/interpreter/compiler\"\n\tpb \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n\t\"github.com/secretflow/scql/pkg/util/tableview\"\n)\n\ntype Config struct {\n\tSQL                 string                     `json:\"sql\"`\n\tCatalog             *pb.Catalog                `json:\"catalog\"`               // Catalog metadata\n\tSecurityConf        *v1.CompilerSecurityConfig `json:\"security_conf\"`         // Security configuration\n\tEngineEndpoints     map[string]string          `json:\"engine_endpoints\"`      // Map of party code to engine endpoint (for client connection)\n\tEngineLinkEndpoints map[string]string          `json:\"engine_link_endpoints\"` // Map of party code to link endpoint (for engine-to-engine communication)\n\tEngineClientType    string                     `json:\"engine_client_type\"`    // \"HTTP\" or \"GRPC\", defaults to \"HTTP\"\n\tEngineTimeout       int                        `json:\"engine_timeout\"`        // timeout in seconds\n\tTLSCACert           string                     `json:\"tls_ca_cert\"`           // Path to CA certificate (for GRPC)\n\tIssuer              string                     `json:\"issuer\"`                // party code\n\tCompileOpts         *v1.CompileOptions         `json:\"compile_opts\"`          // Compile options\n}\n\nfunc main() {\n\tvar configFile string\n\tvar showHelp bool\n\tvar sql string\n\tvar graphvizFile string\n\tflag.StringVar(&configFile, \"config\", \"\", \"Path to config JSON file\")\n\tflag.BoolVar(&showHelp, \"help\", false, \"Show help message\")\n\tflag.StringVar(&sql, \"sql\", \"\", \"SQL query to execute (overrides config file SQL if provided)\")\n\tflag.StringVar(&graphvizFile, \"graphviz\", \"\", \"Output execution graph to specified .dot file\")\n\tflag.Parse()\n\n\tif showHelp || configFile == \"\" {\n\t\tprintHelp()\n\t\tos.Exit(0)\n\t}\n\n\t// Load configuration\n\tconfig, err := loadConfig(configFile)\n\tif err != nil {\n\t\tlogrus.Fatalf(\"Failed to load config: %v\", err)\n\t}\n\n\tif sql != \"\" {\n\t\tconfig.SQL = sql\n\t}\n\n\t// Execute the workflow\n\tif err := execute(config, graphvizFile); err != nil {\n\t\tlogrus.Fatalf(\"Execution failed: %v\", err)\n\t}\n\n\tlogrus.Info(\"Execution completed successfully\")\n}\n\nfunc execute(config *Config, graphvizFile string) error {\n\tctx := context.Background()\n\n\t// Step 1: Compile SQL to execution plan\n\tlogrus.Info(\"Step 1: Compiling SQL to execution plan...\")\n\n\tcompiledPlan, err := compileSQL(ctx, config, graphvizFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"compilation failed: %w\", err)\n\t}\n\n\tlogrus.Infof(\"Compilation successful. SubGraphs: %d\", len(compiledPlan.SubGraphs))\n\n\t// Step 2: Execute the plan on engine\n\tlogrus.Info(\"Step 2: Executing plan on engine...\")\n\n\tresult, err := executePlan(ctx, config, compiledPlan)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"execution failed: %w\", err)\n\t}\n\n\t// Step 3: Display results\n\tlogrus.Info(\"Step 3: Query results:\")\n\tdisplayResults(result)\n\n\treturn nil\n}\n\nfunc compileSQL(ctx context.Context, config *Config, graphvizFile string) (*pb.CompiledPlan, error) {\n\t// Validate required fields\n\tif config.Catalog == nil {\n\t\treturn nil, fmt.Errorf(\"catalog is required\")\n\t}\n\tif config.SecurityConf == nil {\n\t\treturn nil, fmt.Errorf(\"security_conf is required\")\n\t}\n\n\t// Use default compile options if not provided\n\tcompileOpts := config.CompileOpts\n\tif compileOpts == nil {\n\t\tcompileOpts = &v1.CompileOptions{}\n\t}\n\n\t// Build compile request\n\treq := &v1.CompileSQLRequest{\n\t\tQuery:          config.SQL,\n\t\tIssuer:         &pb.PartyId{Code: config.Issuer},\n\t\tCatalog:        config.Catalog,\n\t\tCompileOpts:    compileOpts,\n\t\tIssueTime:      timestamppb.Now(),\n\t\tSecurityConfig: config.SecurityConf,\n\t\tAdditionalInfo: &v1.AdditionalInfoSpec{\n\t\t\tNeedOperatorGraph: false,\n\t\t},\n\t}\n\n\t// Use DetailedCompile to get both ExecutionPlan and ExecutionGraph in one pass\n\tdetails, err := compiler.DetailedCompile(ctx, req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif graphvizFile != \"\" && details.ExecutionGraph != nil {\n\t\tif err := os.WriteFile(graphvizFile, []byte(details.ExecutionGraph.DumpGraphviz()), 0644); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to write graphviz file: %w\", err)\n\t\t}\n\t\tlogrus.Infof(\"Execution graph written to %s\", graphvizFile)\n\t}\n\n\treturn details.ExecutionPlan, nil\n}\n\nfunc executePlan(ctx context.Context, conf *Config, compiledPlan *pb.CompiledPlan) (*pb.QueryResult, error) {\n\tif len(compiledPlan.SubGraphs) == 0 {\n\t\treturn nil, fmt.Errorf(\"no subgraphs in compiled plan\")\n\t}\n\n\t// Create a unique session ID for this execution\n\tsessionID := fmt.Sprintf(\"opencore-demo-%d\", time.Now().Unix())\n\n\t// Build JobStartParams with all parties\n\tjobParams := &pb.JobStartParams{\n\t\tJobId:         sessionID,\n\t\tPartyCode:     conf.Issuer,                 // The party initiating the query\n\t\tSpuRuntimeCfg: compiledPlan.SpuRuntimeConf, // SPU configuration from compiled plan\n\t}\n\n\t// Copy party info from compiled plan\n\tif compiledPlan.Parties != nil {\n\t\tfor i, party := range compiledPlan.Parties {\n\t\t\thost := \"\"\n\t\t\t// First try to get from engine_link_endpoints map (for engine-to-engine communication)\n\t\t\tif conf.EngineLinkEndpoints != nil {\n\t\t\t\tif endpoint, ok := conf.EngineLinkEndpoints[party.Code]; ok {\n\t\t\t\t\thost = endpoint\n\t\t\t\t}\n\t\t\t}\n\t\t\tif host == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"no engine link endpoint configured for party %s\", party.Code)\n\t\t\t}\n\t\t\tjobParams.Parties = append(jobParams.Parties, &pb.JobStartParams_Party{\n\t\t\t\tCode: party.Code,\n\t\t\t\tName: \"\", // Name is optional\n\t\t\t\tHost: host,\n\t\t\t\tRank: int32(i),\n\t\t\t})\n\t\t}\n\t}\n\n\t// Setup engine client\n\ttimeout := time.Duration(conf.EngineTimeout) * time.Second\n\tif timeout == 0 {\n\t\ttimeout = 300 * time.Second // default 5 minutes\n\t}\n\n\t// Determine client type\n\tclientType := conf.EngineClientType\n\tif clientType == \"\" {\n\t\tclientType = executor.EngineClientTypeHTTP // default to HTTP\n\t}\n\n\t// Setup TLS config only for GRPC client type\n\tvar tlsConfig *config.TLSConf\n\tif clientType == executor.EngineClientTypeGRPC && conf.TLSCACert != \"\" {\n\t\ttlsConfig = &config.TLSConf{\n\t\t\tMode:       \"tls\",\n\t\t\tCACertPath: conf.TLSCACert,\n\t\t}\n\t}\n\n\tengineClient := executor.NewEngineClient(\n\t\tclientType,\n\t\ttimeout,\n\t\ttlsConfig,\n\t\t\"application/json\",\n\t\t\"\", // protocol is not used anymore\n\t)\n\n\t// Send execution request to all parties\n\ttype executionResult struct {\n\t\tpartyCode string\n\t\tresponse  *pb.RunExecutionPlanResponse\n\t\terr       error\n\t}\n\n\tresults := make(chan executionResult, len(compiledPlan.SubGraphs))\n\n\tfor partyCode, subgraph := range compiledPlan.SubGraphs {\n\t\tgo func(party string, graph *pb.SubGraph) {\n\t\t\t// Determine the engine endpoint for this party\n\t\t\tengineEndpoint := \"\"\n\t\t\tif conf.EngineEndpoints != nil {\n\t\t\t\tif endpoint, ok := conf.EngineEndpoints[party]; ok {\n\t\t\t\t\tengineEndpoint = endpoint\n\t\t\t\t}\n\t\t\t}\n\t\t\tif engineEndpoint == \"\" {\n\t\t\t\tresults <- executionResult{\n\t\t\t\t\tpartyCode: party,\n\t\t\t\t\terr:       fmt.Errorf(\"no engine endpoint configured for party %s\", party),\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Create execution request for this party with its own party code\n\t\t\tpartyJobParams := &pb.JobStartParams{\n\t\t\t\tJobId:         jobParams.JobId,\n\t\t\t\tPartyCode:     party, // Set this engine's party code\n\t\t\t\tParties:       jobParams.Parties,\n\t\t\t\tSpuRuntimeCfg: jobParams.SpuRuntimeCfg, // Copy SPU config\n\t\t\t\tTimeZone:      jobParams.TimeZone,\n\t\t\t\tLinkCfg:       jobParams.LinkCfg,\n\t\t\t\tPsiCfg:        jobParams.PsiCfg,\n\t\t\t\tLogCfg:        jobParams.LogCfg,\n\t\t\t}\n\n\t\t\texecReq := &pb.RunExecutionPlanRequest{\n\t\t\t\tJobParams: partyJobParams,\n\t\t\t\tGraph:     graph,\n\t\t\t\tAsync:     false, // Synchronous execution\n\t\t\t}\n\n\t\t\t// Call engine\n\t\t\tlogrus.Infof(\"Calling engine for party %s at %s...\", party, engineEndpoint)\n\t\t\tresponse, err := engineClient.RunExecutionPlan(\n\t\t\t\tengineEndpoint,\n\t\t\t\t\"\", // no credential\n\t\t\t\texecReq,\n\t\t\t)\n\n\t\t\tresults <- executionResult{\n\t\t\t\tpartyCode: party,\n\t\t\t\tresponse:  response,\n\t\t\t\terr:       err,\n\t\t\t}\n\t\t}(partyCode, subgraph)\n\t}\n\n\t// Wait for all results\n\tvar issuerResult *pb.RunExecutionPlanResponse\n\tvar firstError error\n\n\tfor i := 0; i < len(compiledPlan.SubGraphs); i++ {\n\t\tresult := <-results\n\t\tif result.err != nil {\n\t\t\tlogrus.Errorf(\"Party %s execution failed: %v\", result.partyCode, result.err)\n\t\t\tif firstError == nil {\n\t\t\t\tfirstError = result.err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check response status\n\t\tif result.response.Status.Code != int32(pb.Code_OK) {\n\t\t\terr := fmt.Errorf(\"party %s engine returned error: %s\", result.partyCode, result.response.Status.Message)\n\t\t\tlogrus.Error(err)\n\t\t\tif firstError == nil {\n\t\t\t\tfirstError = err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tlogrus.Infof(\"Party %s execution succeeded\", result.partyCode)\n\n\t\t// Store the issuer's result (which contains the query output)\n\t\tif result.partyCode == conf.Issuer {\n\t\t\tissuerResult = result.response\n\t\t}\n\t}\n\n\tif firstError != nil {\n\t\treturn nil, fmt.Errorf(\"execution failed: %w\", firstError)\n\t}\n\n\tif issuerResult == nil {\n\t\treturn nil, fmt.Errorf(\"no result from issuer party %s\", conf.Issuer)\n\t}\n\n\t// Build query result from issuer's response\n\tqueryResult := &pb.QueryResult{\n\t\tAffectedRows: issuerResult.NumRowsAffected,\n\t\tOutColumns:   issuerResult.OutColumns,\n\t}\n\n\treturn queryResult, nil\n}\n\nfunc displayResults(result *pb.QueryResult) {\n\t// Print warnings if any\n\tfor _, warn := range result.GetWarnings() {\n\t\tfmt.Printf(\"Warning: %v\\n\", warn.Reason)\n\t}\n\n\t// Print table result if there are output columns\n\tif len(result.GetOutColumns()) > 0 {\n\t\tfmt.Fprintf(os.Stdout, \"[fetch]\\n\")\n\t\t// Create table writer\n\t\ttable := tablewriter.NewWriter(os.Stdout)\n\t\ttable.SetAutoWrapText(false)\n\t\ttable.SetAutoFormatHeaders(false)\n\n\t\t// Convert result to table\n\t\tif err := tableview.ConvertToTable(result.GetOutColumns(), table); err != nil {\n\t\t\tlogrus.Fatalf(\"[fetch] convertToTable with err: %v\\n\", err)\n\t\t}\n\n\t\t// Print summary and render table\n\t\tfmt.Printf(\"%v rows in set: (%vs)\\n\", table.NumLines(), result.GetCostTimeS())\n\t\ttable.Render()\n\t\treturn\n\t} else if result.GetAffectedRows() > 0 {\n\t\t// Print affected rows for non-SELECT queries\n\t\tfmt.Printf(\"[fetch] %v rows affected\\n\", result.GetAffectedRows())\n\t\treturn\n\t}\n}\n\nfunc loadConfig(filename string) (*Config, error) {\n\tdata, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read config file: %w\", err)\n\t}\n\n\tvar config Config\n\tunmarshaler := protojson.UnmarshalOptions{\n\t\tDiscardUnknown: true,\n\t\tAllowPartial:   true,\n\t}\n\n\t// Unmarshal into a temporary map to extract protobuf fields\n\tvar tmpMap map[string]json.RawMessage\n\tif err := json.Unmarshal(data, &tmpMap); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse config JSON: %w\", err)\n\t}\n\n\t// Parse simple fields\n\tif val, ok := tmpMap[\"sql\"]; ok {\n\t\tif err := json.Unmarshal(val, &config.SQL); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse sql: %w\", err)\n\t\t}\n\t}\n\tif val, ok := tmpMap[\"issuer\"]; ok {\n\t\tif err := json.Unmarshal(val, &config.Issuer); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse issuer: %w\", err)\n\t\t}\n\t}\n\tif val, ok := tmpMap[\"engine_client_type\"]; ok {\n\t\tif err := json.Unmarshal(val, &config.EngineClientType); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse engine_client_type: %w\", err)\n\t\t}\n\t}\n\tif val, ok := tmpMap[\"engine_timeout\"]; ok {\n\t\tif err := json.Unmarshal(val, &config.EngineTimeout); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse engine_timeout: %w\", err)\n\t\t}\n\t}\n\tif val, ok := tmpMap[\"tls_ca_cert\"]; ok {\n\t\tif err := json.Unmarshal(val, &config.TLSCACert); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse tls_ca_cert: %w\", err)\n\t\t}\n\t}\n\tif val, ok := tmpMap[\"engine_endpoints\"]; ok {\n\t\tif err := json.Unmarshal(val, &config.EngineEndpoints); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse engine_endpoints: %w\", err)\n\t\t}\n\t}\n\tif val, ok := tmpMap[\"engine_link_endpoints\"]; ok {\n\t\tif err := json.Unmarshal(val, &config.EngineLinkEndpoints); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse engine_link_endpoints: %w\", err)\n\t\t}\n\t}\n\n\t// Parse protobuf fields using protojson\n\tif val, ok := tmpMap[\"catalog\"]; ok {\n\t\tconfig.Catalog = &pb.Catalog{}\n\t\tif err := unmarshaler.Unmarshal(val, config.Catalog); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse catalog: %w\", err)\n\t\t}\n\t}\n\n\tif val, ok := tmpMap[\"security_conf\"]; ok {\n\t\tconfig.SecurityConf = &v1.CompilerSecurityConfig{}\n\t\tif err := unmarshaler.Unmarshal(val, config.SecurityConf); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse security_conf: %w\", err)\n\t\t}\n\t}\n\n\tif val, ok := tmpMap[\"compile_opts\"]; ok {\n\t\tconfig.CompileOpts = &v1.CompileOptions{}\n\t\tif err := unmarshaler.Unmarshal(val, config.CompileOpts); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse compile_opts: %w\", err)\n\t\t}\n\t}\n\n\treturn &config, nil\n}\n\n// printHelp prints usage information for the opencore-demo tool.\n// For complete configuration documentation, see the Config struct definition above.\nfunc printHelp() {\n\tfmt.Println(`Usage: opencore-demo --config <file> [options]\n\nDescription:\n  Compile and execute SCQL queries across multiple SCQL engines in a multi-party\n  computation setup. The tool compiles SQL into an execution graph, distributes\n  it to engines, and displays the results.\n\nOptions:\n  --config string    Path to config JSON file (required)\n  --sql string       SQL query to execute (overrides config file)\n  --graphviz string  Output execution graph to specified .dot file\n  --help             Show this help message\n\nConfig file fields:\n  sql                  Query string\n  catalog              Database metadata (api/interpreter.proto:Catalog)\n  security_conf        Security settings (api/v1alpha1/compiler.proto:CompilerSecurityConfig)\n  compile_opts         Compilation options (api/v1alpha1/compiler.proto:CompileOptions)\n  engine_endpoints     Map<party_code, endpoint> for client connections\n  engine_link_endpoints Map<party_code, endpoint> for engine-to-engine communication\n  engine_client_type   \"HTTP\" or \"GRPC\" (default: \"HTTP\")\n  engine_timeout       Timeout in seconds (default: 300)\n  tls_ca_cert          Path to CA certificate (required for GRPC)\n  issuer               Party code of the query issuer\n\nExamples:\n  opencore-demo --config example_config.json\n  opencore-demo --config example_config.json --sql \"SELECT * FROM table\"\n  opencore-demo --config example_config.json --graphviz graph.dot`)\n}\n"
  },
  {
    "path": "examples/tutorial/.gitignore",
    "content": "**/party_info.json\n*.pem\n**/authorized_profile.json\n**/gflags.conf\ndocker-compose.yml\n**/config.yml\ntls\n"
  },
  {
    "path": "examples/tutorial/README.md",
    "content": "# Guidelines\n\n## Startup\n\n```bash\nbash setup.sh # to initialize the environment\nbash project_bootstrap.sh # to start the project\n./compilerctl --config=\"example_config.json\" # to run the compilerctl\n```\n"
  },
  {
    "path": "examples/tutorial/docker/build.sh",
    "content": "#!/bin/bash\n#\n# Copyright 2026 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nset -eu\n\n# Global variables\nSCQL_IMAGE=secretflow/scql\nIMAGE_TAG=latest\nENABLE_CACHE=false\nTARGET_PLATFORM=\"\"\nPROTECT_DEV_ENV=false\nCONTAINER_ID=\"\"\nOVERLAY_VOLUME=\"\"\nWORKSPACE_MOUNT_ARGS=\"\"\nCACHE_MOUNT_ARGS=\"\"\nTMP_PATH=\"\"\n\n# Display usage information\nusage() {\n  echo \"Usage: $0 [-n Name] [-t Tag] [-p Platform] [-c] [-d]\"\n  echo \"\"\n  echo \"Options:\"\n  echo \"  -n name, image name, default is \\\"secretflow/scql\\\"\"\n  echo \"  -t tag, image tag, default is \\\"latest\\\"\"\n  echo \"  -p target platform, default is host architecture, support \\\"linux/arm64\\\" and \\\"linux/amd64\\\".\"\n  echo \"  -c, enable host disk bazel cache to speedup build process\"\n  echo \"  -d, protect development environment (use isolated build)\"\n}\n\n# Parse command line arguments\nparse_arguments() {\n  while getopts \"n:t:p:cd\" options; do\n    case \"${options}\" in\n    n)\n      SCQL_IMAGE=${OPTARG}\n      ;;\n    t)\n      IMAGE_TAG=${OPTARG}\n      ;;\n    c)\n      ENABLE_CACHE=true\n      ;;\n    d)\n      PROTECT_DEV_ENV=true\n      ;;\n    p)\n      TARGET_PLATFORM=${OPTARG}\n      ;;\n    *)\n      usage\n      exit 1\n      ;;\n    esac\n  done\n}\n\n# Setup environment variables and directories\nsetup_environment() {\n  set -x\n\n  # get work dir\n  SCRIPT_DIR=$(\n    cd \"$(dirname \"$0\")\"\n    pwd\n  )\n\n  WORK_DIR=$(\n    cd $SCRIPT_DIR/../../..\n    pwd\n  )\n\n  echo \"build image $SCQL_IMAGE:$IMAGE_TAG\"\n}\n\n# Configure Docker mount options and platform settings\nconfigure_docker_settings() {\n  # Configure cache mount options\n  CACHE_MOUNT_ARGS=\"\"\n  if ${ENABLE_CACHE}; then\n    local cache_vol_name=\"scql-ubuntu-buildcache\"\n    CACHE_MOUNT_ARGS=\"--mount type=volume,source=${cache_vol_name},target=/root/.cache\"\n  fi\n\n  # Configure workspace mount strategy based on protection mode\n  if [ \"$PROTECT_DEV_ENV\" = \"true\" ]; then\n    # Use overlay volume for complete isolation with direct mount\n    local overlay_volume=\"scql-build-overlay-$(date +%s)\"\n    local changes_dir=\"$WORK_DIR/.build_changes\"\n    echo \"Creating overlay volume with direct mount: $overlay_volume\"\n\n    # Create overlay directories in workspace\n    mkdir -p \"$changes_dir/upper\" \"$changes_dir/work\"\n\n    # Create overlay volume with workspace-relative paths\n    docker volume create \"${overlay_volume}\" \\\n      --driver local \\\n      --opt type=overlay \\\n      --opt device=overlay \\\n      --opt \"o=lowerdir=${WORK_DIR},upperdir=${changes_dir}/upper,workdir=${changes_dir}/work\" \\\n      >/dev/null\n\n    OVERLAY_VOLUME=\"$overlay_volume\"\n\n    WORKSPACE_MOUNT_ARGS=\"--mount type=volume,source=${overlay_volume},target=/home/admin/dev/\"\n  else\n    # Standard bind mount for non-protected builds\n    WORKSPACE_MOUNT_ARGS=\"--mount type=bind,source=${WORK_DIR},target=/home/admin/dev/\"\n  fi\n\n  # Configure platform settings\n  HOST_PLATFORM=\"\"\n  case \"$(arch)\" in\n    x86_64) HOST_PLATFORM=\"linux/amd64\" ;;\n    aarch64 | arm64) HOST_PLATFORM=\"linux/arm64\" ;;\n    *)\n      echo \"Unsupported host architecture: $(arch)\" >&2\n      exit 1\n      ;;\n  esac\n\n  # If TargetPlatform is not set, set to host platform\n  TARGET_PLATFORM=${TARGET_PLATFORM:-$HOST_PLATFORM}\n\n  BUILDER=secretflow/scql-ci:latest\n}\n\n# Create Docker container and build engine binary\ncreate_container_and_build() {\n  echo \"Creating Docker container and building engine binary...\"\n\n  # Create and start the container\n  CONTAINER_ID=$(docker run -d --rm \\\n    ${WORKSPACE_MOUNT_ARGS} \\\n    -w /home/admin/dev ${CACHE_MOUNT_ARGS} \\\n    --entrypoint \"\" \\\n    $BUILDER tail -f /dev/null)\n\n  # Setup cleanup trap for both container and build artifacts\n  trap 'cleanup_on_exit' EXIT\n\n  # Prepare git configuration\n  docker exec ${CONTAINER_ID} bash -c \"git config --global --add safe.directory /home/admin/dev\"\n\n  # Build engine binary only\n  docker exec ${CONTAINER_ID} bash -c \"cd /home/admin/dev && bazelisk --host_jvm_args=-Xmx8g build //engine/exe:scqlengine -c opt --jobs=32\"\n}\n\n# Prepare temporary directory and copy build files\nprepare_build_files() {\n  # prepare temporary path for file copies\n  TMP_PATH=$WORK_DIR/.buildtmp/$IMAGE_TAG\n  rm -rf $TMP_PATH\n  mkdir -p $TMP_PATH\n  mkdir -p $TMP_PATH/$TARGET_PLATFORM\n  echo \"copy files to dir: $TMP_PATH\"\n\n  # Copy scqlengine binary\n  docker cp ${CONTAINER_ID}:/home/admin/dev/bazel-bin/engine/exe/scqlengine $TMP_PATH/$TARGET_PLATFORM\n\n  # copy dockerfile\n  cp ${SCRIPT_DIR}/scql-ubuntu.Dockerfile $TMP_PATH/Dockerfile\n}\n\n# Build Docker image\nbuild_docker_image() {\n  cd $TMP_PATH\n  echo \"start to build scql image in $(pwd)\"\n\n  # If target == host, no need to use buildx\n  if [ \"$HOST_PLATFORM\" == \"$TARGET_PLATFORM\" ]; then\n    docker build --build-arg=\"TARGETPLATFORM=${TARGET_PLATFORM}\" -f Dockerfile -t $SCQL_IMAGE:$IMAGE_TAG .\n  else\n    docker buildx build --platform $TARGET_PLATFORM --load -f Dockerfile -t $SCQL_IMAGE:$IMAGE_TAG .\n  fi\n}\n\n# Cleanup function that runs on exit (success or failure)\ncleanup_on_exit() {\n  echo \"Starting cleanup process...\"\n\n  # Clean up root-owned directories\n  if [ \"$PROTECT_DEV_ENV\" = \"true\" ] && [ -n \"${OVERLAY_VOLUME:-}\" ]; then\n    local changes_dir=\"$WORK_DIR/.build_changes\"\n    if [ -d \"$changes_dir\" ]; then\n      # Use a separate container to clean up root-owned files by mounting the changes directory\n      docker run --rm --mount type=bind,source=\"$changes_dir\",target=/cleanup alpine sh -c \"rm -rf /cleanup/*\" 2>/dev/null || true\n    fi\n  fi\n\n  # Stop Docker container if it exists\n  if [ -n \"${CONTAINER_ID}\" ]; then\n    echo \"Stopping Docker container: ${CONTAINER_ID}\"\n    docker stop ${CONTAINER_ID} 2>/dev/null || true\n  fi\n\n  # Clean up overlay volume if it was created\n  if [ \"$PROTECT_DEV_ENV\" = \"true\" ] && [ -n \"${OVERLAY_VOLUME:-}\" ]; then\n    docker volume rm \"${OVERLAY_VOLUME}\" 2>/dev/null || true\n\n    local changes_dir=\"$WORK_DIR/.build_changes\"\n    if [ -d \"$changes_dir\" ]; then\n      rm -rf \"$changes_dir\" 2>/dev/null || true\n    fi\n  fi\n\n  # Clean up .buildtmp directory\n  local buildtmp_dir=\"$WORK_DIR/.buildtmp\"\n  if [ -d \"$buildtmp_dir\" ]; then\n    rm -rf \"$buildtmp_dir\"\n    echo \"Successfully cleaned up .buildtmp directory\"\n  fi\n}\n\nmain() {\n  parse_arguments \"$@\"\n  setup_environment\n  configure_docker_settings\n  create_container_and_build\n  prepare_build_files\n  build_docker_image\n  echo \"Build completed successfully!\"\n}\n\nmain \"$@\"\n"
  },
  {
    "path": "examples/tutorial/docker/scql-ubuntu.Dockerfile",
    "content": "FROM ubuntu:jammy\n\nARG TARGETPLATFORM\nRUN echo \"I'm building for $TARGETPLATFORM\"\n\nENV TZ=Asia/Shanghai\n\nRUN apt update \\\n    && apt install -y --no-install-recommends libgomp1 curl iputils-ping \\\n    && apt clean \\\n    && rm -rf /var/lib/apt/lists/*\n\n\nCOPY ./$TARGETPLATFORM/scqlengine /home/admin/bin/scqlengine\n"
  },
  {
    "path": "examples/tutorial/docker-compose.yml.template",
    "content": "services:\n  engine_alice:\n    cap_add:\n      - NET_ADMIN\n    command:\n      - /home/admin/bin/scqlengine\n      - --flagfile=/home/admin/engine/conf/gflags.conf\n    image: ${SCQL_IMAGE:-secretflow/scql:latest}\n    ports:\n      - \"8003:8003\"\n      - \"8004:8004\"\n    volumes:\n      - ./engine/alice/conf/gflags.conf:/home/admin/engine/conf/gflags.conf\n      - ./tls/engine_alice-ca.crt:/home/admin/engine/conf/cert.crt\n      - ./tls/engine_alice-ca.key:/home/admin/engine/conf/key.key\n  engine_bob:\n    cap_add:\n      - NET_ADMIN\n    command:\n      - /home/admin/bin/scqlengine\n      - --flagfile=/home/admin/engine/conf/gflags.conf\n    image: ${SCQL_IMAGE:-secretflow/scql:latest}\n    ports:\n      - \"8005:8003\"\n      - \"8006:8004\"\n    volumes:\n      - ./engine/bob/conf/gflags.conf:/home/admin/engine/conf/gflags.conf\n      - ./tls/engine_alice-ca.crt:/home/admin/engine/conf/cert.crt\n      - ./tls/engine_alice-ca.key:/home/admin/engine/conf/key.key\n  mysql:\n    image: mysql:8.0.39\n    environment:\n      - MYSQL_ROOT_PASSWORD=__MYSQL_ROOT_PASSWD__\n      - TZ=Asia/Shanghai\n    healthcheck:\n      retries: 10\n      test:\n        - CMD\n        - mysqladmin\n        - ping\n        - -h\n        - mysql\n      timeout: 20s\n    expose:\n      - \"3306\"\n    restart: always\n    volumes:\n      - ./mysql/initdb:/docker-entrypoint-initdb.d\n"
  },
  {
    "path": "examples/tutorial/engine/alice/conf/gflags.conf.template",
    "content": "--listen_port=8003\n--enable_separate_link_port=true\n--link_port=8004\n--datasource_router=embed\n--enable_driver_authorization=false\n--embed_router_conf={\"datasources\":[{\"id\":\"ds001\",\"name\":\"mysql db\",\"kind\":\"MYSQL\",\"connection_str\":\"db=alice;user=root;password=__MYSQL_ROOT_PASSWD__;host=mysql;auto-reconnect=true\"}],\"rules\":[{\"db\":\"*\",\"table\":\"*\",\"datasource_id\":\"ds001\"}]}\n# party authentication flags\n--enable_self_auth=false\n--enable_peer_auth=false\n# https flags\n--server_enable_ssl=true\n--server_ssl_certificate=/home/admin/engine/conf/cert.crt\n--server_ssl_private_key=/home/admin/engine/conf/key.key\n# set peer_engine_enable_ssl_as_client to true when peer SCQLEngine has https enabled\n--peer_engine_enable_ssl_as_client=true\n--driver_enable_ssl_as_client=false\n"
  },
  {
    "path": "examples/tutorial/engine/bob/conf/gflags.conf.template",
    "content": "--listen_port=8003\n--enable_separate_link_port=true\n--link_port=8004\n--datasource_router=embed\n--enable_driver_authorization=false\n--embed_router_conf={\"datasources\":[{\"id\":\"ds001\",\"name\":\"mysql db\",\"kind\":\"MYSQL\",\"connection_str\":\"db=bob;user=root;password=__MYSQL_ROOT_PASSWD__;host=mysql;auto-reconnect=true\"}],\"rules\":[{\"db\":\"*\",\"table\":\"*\",\"datasource_id\":\"ds001\"}]}\n# party authentication flags\n--enable_self_auth=false\n--enable_peer_auth=false\n# https flags\n--server_enable_ssl=true\n--server_ssl_certificate=/home/admin/engine/conf/cert.crt\n--server_ssl_private_key=/home/admin/engine/conf/key.key\n# set peer_engine_enable_ssl_as_client to true when peer SCQLEngine has https enabled\n--peer_engine_enable_ssl_as_client=true\n--driver_enable_ssl_as_client=false\n"
  },
  {
    "path": "examples/tutorial/example_config.json",
    "content": "{\n    \"sql\": \"SELECT a.credit_rank, COUNT(b.order_amount) FROM user_credit a JOIN user_stats b ON a.ID = b.ID GROUP BY a.credit_rank\",\n    \"catalog\": {\n        \"tables\": [\n            {\n                \"table_name\": \"user_credit\",\n                \"columns\": [\n                    {\n                        \"name\": \"ID\",\n                        \"type\": \"string\",\n                        \"ordinal_position\": 1\n                    },\n                    {\n                        \"name\": \"credit_rank\",\n                        \"type\": \"int\",\n                        \"ordinal_position\": 2\n                    },\n                    {\n                        \"name\": \"income\",\n                        \"type\": \"int\",\n                        \"ordinal_position\": 3\n                    },\n                    {\n                        \"name\": \"age\",\n                        \"type\": \"int\",\n                        \"ordinal_position\": 4\n                    }\n                ],\n                \"ref_table\": \"alice.user_credit\",\n                \"db_type\": \"mysql\",\n                \"owner\": {\n                    \"code\": \"alice\"\n                }\n            },\n            {\n                \"table_name\": \"user_stats\",\n                \"columns\": [\n                    {\n                        \"name\": \"ID\",\n                        \"type\": \"string\",\n                        \"ordinal_position\": 1\n                    },\n                    {\n                        \"name\": \"order_amount\",\n                        \"type\": \"float\",\n                        \"ordinal_position\": 2\n                    },\n                    {\n                        \"name\": \"is_active\",\n                        \"type\": \"int\",\n                        \"ordinal_position\": 3\n                    }\n                ],\n                \"ref_table\": \"bob.user_stats\",\n                \"db_type\": \"mysql\",\n                \"owner\": {\n                    \"code\": \"bob\"\n                }\n            }\n        ]\n    },\n    \"security_conf\": {\n        \"global_relaxation\": {\n            \"reveal_group_count\": true,\n            \"reveal_group_mark\": true,\n            \"reveal_key_after_join\": true,\n            \"reveal_filter_mask\": true\n        },\n        \"column_visibility_list\": [\n            {\n                \"table\": \"user_credit\",\n                \"column\": \"ID\",\n                \"visible_parties\": [\n                    {\n                        \"code\": \"bob\"\n                    }\n                ]\n            },\n            {\n                \"table\": \"user_credit\",\n                \"column\": \"credit_rank\",\n                \"visible_parties\": [\n                    {\n                        \"code\": \"bob\"\n                    }\n                ]\n            },\n            {\n                \"table\": \"user_credit\",\n                \"column\": \"income\",\n                \"visible_parties\": [\n                    {\n                        \"code\": \"bob\"\n                    }\n                ]\n            },\n            {\n                \"table\": \"user_credit\",\n                \"column\": \"age\",\n                \"visible_parties\": [\n                    {\n                        \"code\": \"bob\"\n                    }\n                ]\n            },\n            {\n                \"table\": \"user_stats\",\n                \"column\": \"ID\",\n                \"visible_parties\": [\n                    {\n                        \"code\": \"alice\"\n                    }\n                ]\n            },\n            {\n                \"table\": \"user_stats\",\n                \"column\": \"order_amount\",\n                \"visible_parties\": [\n                    {\n                        \"code\": \"alice\"\n                    }\n                ]\n            },\n            {\n                \"table\": \"user_stats\",\n                \"column\": \"is_active\",\n                \"visible_parties\": [\n                    {\n                        \"code\": \"alice\"\n                    }\n                ]\n            }\n        ],\n        \"reverse_inference_conf\": {\n            \"enable_reverse_inference\": true\n        }\n    },\n    \"engine_endpoints\": {\n        \"alice\": \"localhost:8003\",\n        \"bob\": \"localhost:8005\"\n    },\n    \"engine_link_endpoints\": {\n        \"alice\": \"tutorial-engine_alice-1:8004\",\n        \"bob\": \"tutorial-engine_bob-1:8004\"\n    },\n    \"engine_client_type\": \"GRPC\",\n    \"engine_timeout\": 300,\n    \"tls_ca_cert\": \"./tls/root-ca.crt\",\n    \"issuer\": \"alice\",\n    \"compile_opts\": {\n        \"spu_conf\": {\n            \"protocol\": \"SEMI2K\",\n            \"field\": \"FM64\",\n            \"experimental_enable_colocated_optimization\": true\n        },\n        \"batched\": false\n    }\n}\n"
  },
  {
    "path": "examples/tutorial/mysql/initdb/alice_init.sql",
    "content": "CREATE DATABASE IF NOT EXISTS `alice`;\nUSE `alice`;\n \nDROP TABLE IF EXISTS `user_credit`;\nCREATE TABLE `user_credit` (\n\t`ID` varchar(64) NOT NULL,\n\t`credit_rank` int NOT NULL,\n\t`income` int NOT NULL,\n\t`age` int NOT NULL,\n\tPRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\nLOCK TABLES `user_credit` WRITE;\nINSERT INTO `user_credit` VALUES (\"id0001\", 6, 100000, 20);\nINSERT INTO `user_credit` VALUES (\"id0002\", 5, 90000, 19);\nINSERT INTO `user_credit` VALUES (\"id0003\", 6, 89700, 32);\nINSERT INTO `user_credit` VALUES (\"id0005\", 6, 607000, 30);\nINSERT INTO `user_credit` VALUES (\"id0006\", 5, 30070, 25);\nINSERT INTO `user_credit` VALUES (\"id0007\", 6, 12070, 28);\nINSERT INTO `user_credit` VALUES (\"id0008\", 6, 200800, 50);\nINSERT INTO `user_credit` VALUES (\"id0009\", 6, 607000, 30);\nINSERT INTO `user_credit` VALUES (\"id0010\", 5, 30070, 25);\nINSERT INTO `user_credit` VALUES (\"id0011\", 5, 12070, 28);\nINSERT INTO `user_credit` VALUES (\"id0012\", 6, 200800, 50);\nINSERT INTO `user_credit` VALUES (\"id0013\", 5, 30070, 25);\nINSERT INTO `user_credit` VALUES (\"id0014\", 5, 12070, 28);\nINSERT INTO `user_credit` VALUES (\"id0015\", 6, 200800, 18);\nINSERT INTO `user_credit` VALUES (\"id0016\", 5, 30070, 26);\nINSERT INTO `user_credit` VALUES (\"id0017\", 5, 12070, 27);\nINSERT INTO `user_credit` VALUES (\"id0018\", 6, 200800, 16);\nINSERT INTO `user_credit` VALUES (\"id0019\", 6, 30070, 25);\nINSERT INTO `user_credit` VALUES (\"id0020\", 5, 12070, 28);\nUNLOCK TABLES;\n\n\n\n"
  },
  {
    "path": "examples/tutorial/mysql/initdb/bob_init.sql",
    "content": "CREATE DATABASE IF NOT EXISTS `bob`;\nUSE `bob`;\n\nDROP TABLE IF EXISTS `user_stats`;\nCREATE TABLE `user_stats` (\n\t`ID` varchar(64) not NULL,\n\t`order_amount` float not null,\n\t`is_active` tinyint(1) not null,\n\tPRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;\n\nLOCK TABLES `user_stats` WRITE;\nINSERT INTO `user_stats` VALUES (\"id0001\", 3598.0, 1);\nINSERT INTO `user_stats` VALUES (\"id0002\", 100.0, 0);\nINSERT INTO `user_stats` VALUES (\"id0003\", 2549.0, 1);\nINSERT INTO `user_stats` VALUES (\"id0004\", 21698.5, 1);\nINSERT INTO `user_stats` VALUES (\"id0005\", 4985.5, 1);\nINSERT INTO `user_stats` VALUES (\"id0006\", 3598.0, 1);\nINSERT INTO `user_stats` VALUES (\"id0007\", 322, 0);\nINSERT INTO `user_stats` VALUES (\"id0008\", 9816.2, 1);\nINSERT INTO `user_stats` VALUES (\"id0009\", 3598.0, 1);\nINSERT INTO `user_stats` VALUES (\"id0010\", 322, 0);\nINSERT INTO `user_stats` VALUES (\"id0011\", 9816.2, 1);\nINSERT INTO `user_stats` VALUES (\"id0012\", 3598.0, 1);\nINSERT INTO `user_stats` VALUES (\"id0013\", 322, 0);\nINSERT INTO `user_stats` VALUES (\"id0014\", 9816.2, 1);\nINSERT INTO `user_stats` VALUES (\"id0015\", 9816.2, 1);\nINSERT INTO `user_stats` VALUES (\"id0016\", 9816.2, 1);\nINSERT INTO `user_stats` VALUES (\"id0017\", 3598.0, 1);\nINSERT INTO `user_stats` VALUES (\"id0018\", 322, 0);\nINSERT INTO `user_stats` VALUES (\"id0019\", 9816.2, 1);\nINSERT INTO `user_stats` VALUES (\"id0020\", 9816.2, 1);\nUNLOCK TABLES;\n"
  },
  {
    "path": "examples/tutorial/project_bootstrap.sh",
    "content": "#!/bin/bash\nset -eu\n\nSCRIPT_DIR=$(cd \"$(dirname \"$0\")\" && pwd)\nPROJECT_ROOT=$(cd \"${SCRIPT_DIR}/..\" && pwd)\ncd \"${SCRIPT_DIR}\"\n\nif [ ! -f \"docker-compose.yml\" ]; then\n    if [ -f \"setup.sh\" ]; then\n        ./setup.sh\n    else\n        echo \"Error: Neither docker-compose.yml nor setup.sh found\"\n        exit 1\n    fi\nfi\n\nCOMPOSE_FILE=\"docker-compose.yml\"\n\ndocker compose -f \"${COMPOSE_FILE}\" -p tutorial down 2>/dev/null || true\ndocker compose -f \"${COMPOSE_FILE}\" -p tutorial up -d\n\nif [ ! -f \"example_config.json\" ]; then\n    echo \"Error: example_config.json not found\"\n    exit 1\nfi\n\nsleep 5\n\necho \"\"\necho \"Setup complete! Please take a try with the following command:\"\necho \"./opencore-demo --config=example_config.json\"\n"
  },
  {
    "path": "examples/tutorial/setup.sh",
    "content": "#!/bin/bash\nset -eu\n# get work dir\nSCRIPT_DIR=$(\n  cd \"$(dirname \"$0\")\"\n  pwd\n)\n\n# generate password for mysql root user\nMYSQL_PASSWD=$(cat /dev/urandom | base64 | tr -dc A-Za-z0-9 | head -c 13)\nfor file in $(grep -rl '__MYSQL_ROOT_PASSWD__' --exclude='*.sh' ${SCRIPT_DIR}/); do\n  # remove suffix .template\n  newfile=$(echo $file | sed 's/\\.[^.]*$//')\n  sed \"s/__MYSQL_ROOT_PASSWD__/${MYSQL_PASSWD}/g\" $file >$newfile\ndone\n\n# Check if the system is macOS and LibreSSL is installed\nif [[ \"$(uname)\" == \"Darwin\" ]] && openssl version | grep -q \"LibreSSL\"; then\n  echo \"You are using macOS with LibreSSL, which does not support ed25519.\"\n  echo \"Please install OpenSSL using the following command:\"\n  echo \"brew install openssl\"\n  exit 1\nfi\n\n# generate self-signed ca files for engine\n(cd $SCRIPT_DIR && bash ../../test-tools/ca_generator.sh)\n\necho \"successfully completed password generation and ca file generation\"\n\nSCRIPT_DIR=$(cd \"$(dirname \"$0\")\" && pwd)\nPROJECT_ROOT=$(cd \"${SCRIPT_DIR}/..\" && pwd)\n\ncd \"${PROJECT_ROOT}\"\n\n# load environment variables from .env if present (e.g., SCQL_IMAGE)\nif [ -f .env ]; then\n  set -a\n  . .env\n  set +a\nfi\n\ngo build -o \"${SCRIPT_DIR}/opencore-demo\" ./opencore-demo/main.go\n\n# determine SCQL image name (default to secretflow/scql:latest if not set)\nIMAGE_NAME=\"${SCQL_IMAGE:-secretflow/scql:latest}\"\n\n# check if the configured SCQL image exists\nif ! docker image inspect \"${IMAGE_NAME}\" >/dev/null 2>&1; then\n  echo \"WARNING: Docker image ${IMAGE_NAME} not found.\"\n  echo \"Please build the image first by running:\"\n  echo \"  bash ${SCRIPT_DIR}/docker/build.sh\"\nfi\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/secretflow/scql\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/apache/arrow/go/v17 v17.0.0\n\tgithub.com/cznic/mathutil v0.0.0-20181122101859-297441e03548\n\tgithub.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8\n\tgithub.com/cznic/strutil v0.0.0-20181122101858-275e90344537\n\tgithub.com/gin-gonic/gin v1.9.1\n\tgithub.com/go-co-op/gocron/v2 v2.7.1\n\tgithub.com/go-python/gopy v0.4.10\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/hashicorp/consul/api v1.29.1\n\tgithub.com/olekukonko/tablewriter v0.0.5\n\tgithub.com/pingcap/check v0.0.0-20211026125417-57bd13f7b5f0\n\tgithub.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63\n\tgithub.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7\n\tgithub.com/pkg/errors v0.9.1\n\tgithub.com/prometheus/client_golang v1.18.0\n\tgithub.com/secretflow/kuscia v0.0.0-20240911072119-68280d4f3fd9\n\tgithub.com/sirupsen/logrus v1.9.3\n\tgithub.com/spf13/cobra v1.7.0\n\tgithub.com/stretchr/testify v1.9.0\n\tgithub.com/tjfoc/gmsm v1.4.1\n\tgo.uber.org/mock v0.4.0\n\tgo.uber.org/zap v1.24.0\n\tgolang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8\n\tgolang.org/x/text v0.31.0\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094\n\tgoogle.golang.org/grpc v1.64.1\n\tgoogle.golang.org/protobuf v1.36.5\n\tgopkg.in/natefinch/lumberjack.v2 v2.0.0\n\tgopkg.in/yaml.v2 v2.4.0\n\tgopkg.in/yaml.v3 v3.0.1\n\tgorm.io/driver/mysql v1.4.4\n\tgorm.io/driver/postgres v1.5.9\n\tgorm.io/driver/sqlite v1.5.6\n\tgorm.io/gorm v1.25.11\n\tmodernc.org/parser v1.0.3\n\tmodernc.org/y v1.0.4\n)\n\nrequire (\n\tgithub.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect\n\tgithub.com/armon/go-metrics v0.4.1 // indirect\n\tgithub.com/benbjohnson/clock v1.1.0 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/bytedance/sonic v1.11.2 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.2.0 // indirect\n\tgithub.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect\n\tgithub.com/chenzhuoyu/iasm v0.9.1 // indirect\n\tgithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect\n\tgithub.com/fatih/color v1.16.0 // indirect\n\tgithub.com/gabriel-vasile/mimetype v1.4.3 // indirect\n\tgithub.com/gin-contrib/sse v0.1.0 // indirect\n\tgithub.com/go-logr/logr v1.4.2 // indirect\n\tgithub.com/go-playground/locales v0.14.1 // indirect\n\tgithub.com/go-playground/universal-translator v0.18.1 // indirect\n\tgithub.com/go-playground/validator/v10 v10.19.0 // indirect\n\tgithub.com/go-sql-driver/mysql v1.6.0 // indirect\n\tgithub.com/goccy/go-json v0.10.3 // indirect\n\tgithub.com/gogo/protobuf v1.3.2 // indirect\n\tgithub.com/google/flatbuffers v24.3.25+incompatible // indirect\n\tgithub.com/google/gofuzz v1.2.0 // indirect\n\tgithub.com/hashicorp/errwrap v1.1.0 // indirect\n\tgithub.com/hashicorp/go-cleanhttp v0.5.2 // indirect\n\tgithub.com/hashicorp/go-hclog v1.5.0 // indirect\n\tgithub.com/hashicorp/go-immutable-radix v1.3.1 // indirect\n\tgithub.com/hashicorp/go-multierror v1.1.1 // indirect\n\tgithub.com/hashicorp/go-rootcerts v1.0.2 // indirect\n\tgithub.com/hashicorp/golang-lru v0.5.4 // indirect\n\tgithub.com/hashicorp/serf v0.10.1 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/jackc/pgpassfile v1.0.0 // indirect\n\tgithub.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect\n\tgithub.com/jackc/pgx/v5 v5.5.5 // indirect\n\tgithub.com/jackc/puddle/v2 v2.2.1 // indirect\n\tgithub.com/jinzhu/inflection v1.0.0 // indirect\n\tgithub.com/jinzhu/now v1.1.5 // indirect\n\tgithub.com/jonboulle/clockwork v0.4.0 // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/klauspost/compress v1.17.9 // indirect\n\tgithub.com/klauspost/cpuid/v2 v2.2.8 // indirect\n\tgithub.com/leodido/go-urn v1.4.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.13 // indirect\n\tgithub.com/mattn/go-sqlite3 v1.14.22 // indirect\n\tgithub.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect\n\tgithub.com/mitchellh/go-homedir v1.1.0 // indirect\n\tgithub.com/mitchellh/mapstructure v1.5.0 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/pelletier/go-toml/v2 v2.1.1 // indirect\n\tgithub.com/pierrec/lz4/v4 v4.1.21 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect\n\tgithub.com/prometheus/client_model v0.5.0 // indirect\n\tgithub.com/prometheus/common v0.45.0 // indirect\n\tgithub.com/prometheus/procfs v0.12.0 // indirect\n\tgithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect\n\tgithub.com/rivo/uniseg v0.2.0 // indirect\n\tgithub.com/robfig/cron/v3 v3.0.1 // indirect\n\tgithub.com/spf13/pflag v1.0.5 // indirect\n\tgithub.com/stretchr/objx v0.5.2 // indirect\n\tgithub.com/twitchyliquid64/golang-asm v0.15.1 // indirect\n\tgithub.com/ugorji/go/codec v1.2.12 // indirect\n\tgithub.com/zeebo/xxh3 v1.0.2 // indirect\n\tgo.uber.org/atomic v1.9.0 // indirect\n\tgo.uber.org/multierr v1.8.0 // indirect\n\tgolang.org/x/arch v0.7.0 // indirect\n\tgolang.org/x/crypto v0.45.0 // indirect\n\tgolang.org/x/mod v0.29.0 // indirect\n\tgolang.org/x/net v0.47.0 // indirect\n\tgolang.org/x/sync v0.18.0 // indirect\n\tgolang.org/x/sys v0.38.0 // indirect\n\tgolang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect\n\tgolang.org/x/tools v0.38.0 // indirect\n\tgolang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect\n\tgopkg.in/inf.v0 v0.9.1 // indirect\n\tk8s.io/api v0.28.4 // indirect\n\tk8s.io/apimachinery v0.28.4 // indirect\n\tk8s.io/klog/v2 v2.100.1 // indirect\n\tk8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect\n\tmodernc.org/golex v1.0.1 // indirect\n\tmodernc.org/mathutil v1.6.0 // indirect\n\tmodernc.org/sortutil v1.1.1 // indirect\n\tmodernc.org/strutil v1.2.0 // indirect\n\tsigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect\n\tsigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=\ngithub.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU=\ngithub.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/apache/arrow/go/v17 v17.0.0 h1:RRR2bdqKcdbss9Gxy2NS/hK8i4LDMh23L6BbkN5+F54=\ngithub.com/apache/arrow/go/v17 v17.0.0/go.mod h1:jR7QHkODl15PfYyjM2nU+yTLScZ/qfj7OSUZmJ8putc=\ngithub.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=\ngithub.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=\ngithub.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=\ngithub.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=\ngithub.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=\ngithub.com/bytedance/sonic v1.11.2 h1:ywfwo0a/3j9HR8wsYGWsIWl2mvRsI950HyoxiBERw5A=\ngithub.com/bytedance/sonic v1.11.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=\ngithub.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=\ngithub.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=\ngithub.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=\ngithub.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=\ngithub.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=\ngithub.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=\ngithub.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=\ngithub.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=\ngithub.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=\ngithub.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=\ngithub.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=\ngithub.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8 h1:LpMLYGyy67BoAFGda1NeOBQwqlv7nUXpm+rIVHGxZZ4=\ngithub.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=\ngithub.com/cznic/strutil v0.0.0-20181122101858-275e90344537 h1:MZRmHqDBd0vxNwenEbKSQqRVT24d3C05ft8kduSwlqM=\ngithub.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=\ngithub.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=\ngithub.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=\ngithub.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=\ngithub.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=\ngithub.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=\ngithub.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=\ngithub.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=\ngithub.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=\ngithub.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=\ngithub.com/go-co-op/gocron/v2 v2.7.1 h1:HNHT5WERT4LVzMIqcaQIVrMpNpL6ROK8DiSnATLDxb4=\ngithub.com/go-co-op/gocron/v2 v2.7.1/go.mod h1:xY7bJxGazKam1cz04EebrlP4S9q4iWdiAylMGP3jY9w=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=\ngithub.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=\ngithub.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=\ngithub.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=\ngithub.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=\ngithub.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=\ngithub.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=\ngithub.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=\ngithub.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=\ngithub.com/go-python/gopy v0.4.10 h1:Ec3x+NTSzLsw9f6FTdDLwQCQlmlNmJIu4J6nSnyugqE=\ngithub.com/go-python/gopy v0.4.10/go.mod h1:zMV/gSSYa9u/8Zp0WYR+L/z+kOIqIUtMg/a1/GRy5uw=\ngithub.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=\ngithub.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=\ngithub.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=\ngithub.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=\ngithub.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=\ngithub.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=\ngithub.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/hashicorp/consul/api v1.29.1 h1:UEwOjYJrd3lG1x5w7HxDRMGiAUPrb3f103EoeKuuEcc=\ngithub.com/hashicorp/consul/api v1.29.1/go.mod h1:lumfRkY/coLuqMICkI7Fh3ylMG31mQSRZyef2c5YvJI=\ngithub.com/hashicorp/consul/proto-public v0.6.1 h1:+uzH3olCrksXYWAYHKqK782CtK9scfqH+Unlw3UHhCg=\ngithub.com/hashicorp/consul/proto-public v0.6.1/go.mod h1:cXXbOg74KBNGajC+o8RlA502Esf0R9prcoJgiOX/2Tg=\ngithub.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg=\ngithub.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=\ngithub.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=\ngithub.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=\ngithub.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=\ngithub.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=\ngithub.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=\ngithub.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=\ngithub.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=\ngithub.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=\ngithub.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=\ngithub.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=\ngithub.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=\ngithub.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=\ngithub.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=\ngithub.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=\ngithub.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=\ngithub.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=\ngithub.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=\ngithub.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=\ngithub.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=\ngithub.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=\ngithub.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=\ngithub.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=\ngithub.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=\ngithub.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=\ngithub.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=\ngithub.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=\ngithub.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=\ngithub.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=\ngithub.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=\ngithub.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=\ngithub.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=\ngithub.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=\ngithub.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=\ngithub.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=\ngithub.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=\ngithub.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=\ngithub.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=\ngithub.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=\ngithub.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=\ngithub.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=\ngithub.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=\ngithub.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=\ngithub.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=\ngithub.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=\ngithub.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=\ngithub.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=\ngithub.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=\ngithub.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=\ngithub.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=\ngithub.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=\ngithub.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=\ngithub.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=\ngithub.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=\ngithub.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=\ngithub.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=\ngithub.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ=\ngithub.com/pingcap/check v0.0.0-20211026125417-57bd13f7b5f0 h1:HVl5539r48eA+uDuX/ziBmQCxzT1pGrzWbKuXT46Bq0=\ngithub.com/pingcap/check v0.0.0-20211026125417-57bd13f7b5f0/go.mod h1:PYMCGwN0JHjoqGr3HrZoD+b8Tgx8bKnArhSq8YVzUMc=\ngithub.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=\ngithub.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 h1:+FZIDR/D97YOPik4N4lPDaUcLDF/EQPogxtlHB2ZZRM=\ngithub.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg=\ngithub.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=\ngithub.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 h1:k2BbABz9+TNpYRwsCCFS8pEEnFVOdbgEjL/kTlLuzZQ=\ngithub.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7/go.mod h1:8AanEdAHATuRurdGxZXBz0At+9avep+ub7U1AGYLIMM=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=\ngithub.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=\ngithub.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=\ngithub.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=\ngithub.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=\ngithub.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=\ngithub.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=\ngithub.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=\ngithub.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=\ngithub.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=\ngithub.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=\ngithub.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/secretflow/kuscia v0.0.0-20240911072119-68280d4f3fd9 h1:hf9FSkLBSGf5NTQ5LcCMivHhWVJZV4pJv0PhRoNDAco=\ngithub.com/secretflow/kuscia v0.0.0-20240911072119-68280d4f3fd9/go.mod h1:CApz27T/TGeMwGE7W79yQV65aCMyMBaDpb8G1hCeTpk=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=\ngithub.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=\ngithub.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=\ngithub.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=\ngithub.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=\ngithub.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=\ngithub.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=\ngithub.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=\ngithub.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=\ngithub.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=\ngithub.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=\ngithub.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=\ngithub.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=\ngithub.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=\ngo.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=\ngo.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=\ngo.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=\ngo.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=\ngo.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=\ngo.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=\ngo.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=\ngo.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=\ngo.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=\ngo.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=\ngo.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=\ngolang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=\ngolang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=\ngolang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=\ngolang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=\ngolang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=\ngolang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=\ngolang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=\ngolang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=\ngolang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=\ngolang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=\ngolang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=\ngolang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngolang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=\ngolang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=\ngolang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191107010934-f79515f33823/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=\ngolang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=\ngolang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=\ngonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ=\ngonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=\ngoogle.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=\ngoogle.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=\ngopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=\ngopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=\ngopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngorm.io/driver/mysql v1.4.4 h1:MX0K9Qvy0Na4o7qSC/YI7XxqUw5KDw01umqgID+svdQ=\ngorm.io/driver/mysql v1.4.4/go.mod h1:BCg8cKI+R0j/rZRQxeKis/forqRwRSYOR8OM3Wo6hOM=\ngorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=\ngorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=\ngorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE=\ngorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=\ngorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=\ngorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=\ngorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nk8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY=\nk8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0=\nk8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8=\nk8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg=\nk8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=\nk8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=\nk8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=\nk8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=\nmodernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=\nmodernc.org/golex v1.0.1 h1:EYKY1a3wStt0RzHaH8mdSRNg78Ub0OHxYfCRWw35YtM=\nmodernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254=\nmodernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk=\nmodernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk=\nmodernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=\nmodernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=\nmodernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=\nmodernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=\nmodernc.org/parser v1.0.2/go.mod h1:TXNq3HABP3HMaqLK7brD1fLA/LfN0KS6JxZn71QdDqs=\nmodernc.org/parser v1.0.3 h1:RQZAWGcfH7reyvq+zcJ9KE99zY2oVXmP2Rdl8cQVH/Y=\nmodernc.org/parser v1.0.3/go.mod h1:KH73bzDo4qREG480LRhmWZADl9vqx9IkthHtxUKRr0M=\nmodernc.org/scanner v1.0.1/go.mod h1:OIzD2ZtjYk6yTuyqZr57FmifbM9fIH74SumloSsajuE=\nmodernc.org/sortutil v1.1.1 h1:VQGxbQGcHaQeB/BX9TQjrHFmOA0bounO1X/jvOfRo6Q=\nmodernc.org/sortutil v1.1.1/go.mod h1:DTj/8BqjEBLZFVPYvEGDfFFg94SsfPxQ70R+SQJ98qA=\nmodernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=\nmodernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=\nmodernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=\nmodernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=\nmodernc.org/y v1.0.4 h1:e4bTlURSY/jhrS9z/NcwRcIwEBIBCO5fqzZmkJRQNOQ=\nmodernc.org/y v1.0.4/go.mod h1:GGHW6mKIBF7jlNo+lsc2/F+ZHq/YGJNOEL5Lnog/+j8=\nnullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=\nrsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=\nsigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=\nsigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=\nsigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=\nsigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=\nsigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=\nsigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=\n"
  },
  {
    "path": "pkg/config/tls_config.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//\thttp://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\npackage config\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n)\n\nconst (\n\tNoTLS     string = \"notls\"\n\tTLS       string = \"tls\"\n\tMutualTLS string = \"mtls\"\n)\n\ntype TLSConf struct {\n\tMode       string `yaml:\"mode\"`\n\tCertPath   string `yaml:\"cert\"`\n\tKeyPath    string `yaml:\"key\"`\n\tCACertPath string `yaml:\"cacert\"`\n}\n\nfunc LoadTLSConfig(mode, cacertPath, certPath, keyPath string) (*tls.Config, error) {\n\tvar tlsConfig *tls.Config\n\tcacert, err := os.ReadFile(cacertPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read cacert file\")\n\t}\n\tcacertPool := x509.NewCertPool()\n\tif !cacertPool.AppendCertsFromPEM(cacert) {\n\t\treturn nil, fmt.Errorf(\"failed to append CA certificates\")\n\t}\n\n\tlowerMode := strings.ToLower(mode)\n\tswitch lowerMode {\n\tcase TLS:\n\t\ttlsConfig = &tls.Config{\n\t\t\tRootCAs: cacertPool,\n\t\t}\n\tcase MutualTLS:\n\t\tcert, err := tls.LoadX509KeyPair(certPath, keyPath)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to load X509 key pair: %w\", err)\n\t\t}\n\n\t\ttlsConfig = &tls.Config{\n\t\t\tCertificates: []tls.Certificate{cert},\n\t\t\tRootCAs:      cacertPool,\n\t\t}\n\t}\n\treturn tlsConfig, nil\n}\n"
  },
  {
    "path": "pkg/constant/constant.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage constant\n\nconst (\n\tSecondsOneDay = 24 * 3600\n)\n\nconst (\n\tStringElementPlaceHolder = `__null__`\n)\n\nconst (\n\tDefaultGroupByThreshold uint64 = 4\n)\n\nconst (\n\tReasonCallbackFrontendFail = \"CallbackFrontendFail\"\n\tReasonSessionNotFound      = \"SessionNotFound\"\n\tReasonSessionAbnormalQuit  = \"SessionAbnormalQuit\"\n\tReasonSessionNormalQuit    = \"SessionNormalQuit\"\n\tReasonInvalidRequest       = \"InvalidRequest\"\n\tReasonInvalidRequestFormat = \"InvalidRequestFormat\"\n\tReasonInvalidResponse      = \"InvalidResponse\"\n\tReasonCallEngineFail       = \"CallEngineFail\"\n)\n\n// NOTE: the type values are defined by DataType Enum in \"api/v1/column.proto\"\nvar StringTypeAlias = map[string]bool{\"string\": true, \"str\": true}\n\nvar IntegerTypeAlias = map[string]bool{\"int32\": true, \"int64\": true, \"integer\": true, \"int\": true}\nvar FloatTypeAlias = map[string]bool{\"float32\": true}\nvar DoubleTypeAlias = map[string]bool{\"float\": true, \"double\": true, \"float64\": true}\nvar DateTimeTypeAlias = map[string]bool{\"datetime\": true}\nvar TimeStampTypeAlias = map[string]bool{\"timestamp\": true}\n\nfunc merge(ms ...map[string]bool) map[string]bool {\n\tres := map[string]bool{}\n\tfor _, m := range ms {\n\t\tfor k, v := range m {\n\t\t\tres[k] = v\n\t\t}\n\t}\n\treturn res\n}\n\nvar SupportTypes = merge(StringTypeAlias, IntegerTypeAlias, FloatTypeAlias, DoubleTypeAlias, DateTimeTypeAlias, TimeStampTypeAlias)\n\nconst (\n\tGMsm3Hash  = \"GMSM3\"\n\tSha256Hash = \"SHA256\"\n)\n\nfunc GetGroupByThreshold(val uint64) uint64 {\n\tif val == 0 {\n\t\treturn DefaultGroupByThreshold\n\t}\n\treturn val\n}\n"
  },
  {
    "path": "pkg/executor/engine_client.go",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage executor\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/secretflow/scql/pkg/config\"\n)\n\nconst (\n\tengineCredentialHeader = \"Credential\"\n)\n\nfunc NewEngineClientConn(endpoint, credential string, tlsCfg *config.TLSConf) (*grpc.ClientConn, error) {\n\tcreds := insecure.NewCredentials()\n\n\tif tlsCfg != nil && (tlsCfg.Mode == config.TLS || tlsCfg.Mode == config.MutualTLS) {\n\t\ttlsConfig, err := config.LoadTLSConfig(tlsCfg.Mode, tlsCfg.CACertPath, tlsCfg.CertPath, tlsCfg.KeyPath)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcreds = credentials.NewTLS(tlsConfig)\n\t}\n\n\tgrpcDialOpts := []grpc.DialOption{\n\t\tgrpc.WithUnaryInterceptor(grpcClientCredentialInterceptor(credential)),\n\t\tgrpc.WithTransportCredentials(creds),\n\t\t// FLOW_CONTROL_ERROR is encountered when the window size is small.\n\t\t// brpc issue: https://github.com/apache/brpc/issues/1087\n\t\tgrpc.WithInitialWindowSize(1 << 30),\n\t\tgrpc.WithInitialConnWindowSize(1 << 30),\n\t\tgrpc.WithDefaultCallOptions(\n\t\t\tgrpc.MaxCallRecvMsgSize(1<<30),\n\t\t\tgrpc.MaxCallSendMsgSize(1<<30),\n\t\t),\n\t}\n\treturn grpc.NewClient(endpoint, grpcDialOpts...)\n}\n\nfunc grpcClientCredentialInterceptor(credentialStr string) grpc.UnaryClientInterceptor {\n\treturn func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {\n\t\tctx = metadata.AppendToOutgoingContext(ctx, engineCredentialHeader, credentialStr)\n\t\treturn invoker(ctx, method, req, reply, cc, opts...)\n\t}\n}\n"
  },
  {
    "path": "pkg/executor/engine_client_test.go",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage executor\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNewEngineClientConn(t *testing.T) {\n\tr := require.New(t)\n\t// no network io performed\n\t_, err := NewEngineClientConn(\"xxx:1234\", \"\", nil)\n\tr.NoError(err)\n}\n"
  },
  {
    "path": "pkg/executor/engine_stub.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage executor\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\n\t\"github.com/secretflow/scql/pkg/config\"\n\tpb \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/util/message\"\n)\n\nconst (\n\trunExecutionPlanPath = \"/SCQLEngineService/RunExecutionPlan\"\n)\n\nconst (\n\tEngineClientTypeGRPC = \"GRPC\"\n\tEngineClientTypeHTTP = \"HTTP\"\n)\n\n//go:generate mockgen -source engine_stub.go -destination engine_stub_mock.go -package executor\ntype EngineClient interface {\n\tRunExecutionPlan(url, credential string, executionPlanReq *pb.RunExecutionPlanRequest) (*pb.RunExecutionPlanResponse, error)\n}\n\nfunc NewEngineClient(clientType string, timeout time.Duration, tlsCfg *config.TLSConf, contentType, protocol string) EngineClient {\n\tif clientType == EngineClientTypeGRPC {\n\t\treturn NewGRPCEngineClient(timeout, tlsCfg)\n\t} else {\n\t\tprotocol = strings.SplitN(protocol, \":\", 2)[0]\n\t\tif protocol == \"\" {\n\t\t\tprotocol = \"http\"\n\t\t}\n\t\treturn NewHttpEngineClient(timeout, contentType, protocol)\n\t}\n}\n\nfunc NewHttpEngineClient(timeout time.Duration, contentType, protocol string) EngineClient {\n\treturn &HttpEngineClient{\n\t\tprotocol:    protocol,\n\t\tcontentType: contentType,\n\t\tclient:      &http.Client{Timeout: timeout, Transport: &http.Transport{}},\n\t}\n}\n\nfunc NewGRPCEngineClient(timeout time.Duration, tlsCfg *config.TLSConf) EngineClient {\n\treturn &GrpcEngineClient{timeout: timeout, tlsCfg: tlsCfg}\n}\n\nfunc (h *HttpEngineClient) RunExecutionPlan(host, credential string, executionPlanReq *pb.RunExecutionPlanRequest) (*pb.RunExecutionPlanResponse, error) {\n\turl := url.URL{\n\t\tScheme: h.protocol,\n\t\tHost:   host,\n\t\tPath:   runExecutionPlanPath,\n\t}\n\turlStr := url.String()\n\n\tm := protojson.MarshalOptions{UseProtoNames: true}\n\tbody, err := m.Marshal(executionPlanReq)\n\tif err != nil {\n\t\treturn nil, errors.Errorf(\"Marshal error: %v\", err)\n\t}\n\tpostBody := string(body)\n\n\tctx := context.TODO()\n\tresponseBody, err := h.Post(ctx, urlStr, credential, h.contentType, postBody)\n\tif err != nil {\n\t\treturn nil, errors.Errorf(\"Post error: %v\", err)\n\t}\n\n\texecutionPlanRes := &pb.RunExecutionPlanResponse{}\n\t_, err = message.DeserializeFrom(io.NopCloser(strings.NewReader(responseBody)), executionPlanRes, h.contentType)\n\tif err != nil {\n\t\treturn nil, errors.Errorf(\"Deserialize error: %v\", err)\n\t}\n\n\treturn executionPlanRes, nil\n}\n\nfunc (g *GrpcEngineClient) RunExecutionPlan(url, credential string, executionPlanReq *pb.RunExecutionPlanRequest) (*pb.RunExecutionPlanResponse, error) {\n\tconn, err := NewEngineClientConn(url, credential, g.tlsCfg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer conn.Close()\n\n\tclient := pb.NewSCQLEngineServiceClient(conn)\n\tctx, cancel := context.WithTimeout(context.Background(), g.timeout)\n\tdefer cancel()\n\n\texecutionPlanRes, err := client.RunExecutionPlan(ctx, executionPlanReq)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn executionPlanRes, nil\n}\n\nfunc (h *HttpEngineClient) Post(ctx context.Context, url, credential, contentType, body string) (string, error) {\n\treq, err := http.NewRequest(http.MethodPost, url, strings.NewReader(body))\n\tif err != nil {\n\t\tlog.Errorf(\"HttpEngineClient.Post/NewRequest failed: url: %v, err: %v\", url, err)\n\t\treturn \"\", err\n\t}\n\treq.Header.Add(\"Content-Type\", contentType)\n\treq.Header.Add(\"Credential\", credential)\n\tresponse, err := h.client.Do(req)\n\tif err != nil {\n\t\tlog.Errorf(\"HttpEngineClient.Post/Do failed: url: %v, err: %v\", url, err)\n\t\treturn \"\", err\n\t}\n\tdefer response.Body.Close()\n\tresponseBody, err := io.ReadAll(response.Body)\n\tif err != nil {\n\t\tlog.Errorf(\"failed to read from response body with err:%v\", err)\n\t\treturn \"\", err\n\t}\n\tif response.StatusCode != http.StatusOK {\n\t\treturn \"\", errors.Errorf(\"httpCode:%v, responseBody:%v\", response.StatusCode, string(responseBody))\n\t}\n\treturn string(responseBody), nil\n}\n\ntype HttpEngineClient struct {\n\tprotocol    string\n\tcontentType string\n\tclient      *http.Client\n}\n\ntype GrpcEngineClient struct {\n\ttimeout time.Duration\n\ttlsCfg  *config.TLSConf\n}\n\n// EngineStub struct\ntype EngineStub struct {\n\texecutionPlanID string\n\t// callback URL\n\tcbURL     string\n\twebClient EngineClient\n}\n\n// NewEngineStub creates an engine stub instance\nfunc NewEngineStub(\n\tsessionID string,\n\tcallBackProtocol string,\n\tcallBackHost string,\n\tcallBackPath string,\n\tclient EngineClient) *EngineStub {\n\tcbURL := url.URL{\n\t\tScheme: callBackProtocol,\n\t\tHost:   callBackHost,\n\t\tPath:   callBackPath,\n\t}\n\n\treturn &EngineStub{\n\t\texecutionPlanID: sessionID,\n\t\tcbURL:           cbURL.String(),\n\t\twebClient:       client,\n\t}\n}\n"
  },
  {
    "path": "pkg/executor/engine_stub_mock.go",
    "content": "// Code generated by MockGen. DO NOT EDIT.\n// Source: engine_stub.go\n//\n// Generated by this command:\n//\n//\tmockgen -source engine_stub.go -destination engine_stub_mock.go -package executor\n//\n\n// Package executor is a generated GoMock package.\npackage executor\n\nimport (\n\treflect \"reflect\"\n\n\tscql \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tgomock \"go.uber.org/mock/gomock\"\n)\n\n// MockEngineClient is a mock of EngineClient interface.\ntype MockEngineClient struct {\n\tctrl     *gomock.Controller\n\trecorder *MockEngineClientMockRecorder\n\tisgomock struct{}\n}\n\n// MockEngineClientMockRecorder is the mock recorder for MockEngineClient.\ntype MockEngineClientMockRecorder struct {\n\tmock *MockEngineClient\n}\n\n// NewMockEngineClient creates a new mock instance.\nfunc NewMockEngineClient(ctrl *gomock.Controller) *MockEngineClient {\n\tmock := &MockEngineClient{ctrl: ctrl}\n\tmock.recorder = &MockEngineClientMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockEngineClient) EXPECT() *MockEngineClientMockRecorder {\n\treturn m.recorder\n}\n\n// RunExecutionPlan mocks base method.\nfunc (m *MockEngineClient) RunExecutionPlan(url, credential string, executionPlanReq *scql.RunExecutionPlanRequest) (*scql.RunExecutionPlanResponse, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"RunExecutionPlan\", url, credential, executionPlanReq)\n\tret0, _ := ret[0].(*scql.RunExecutionPlanResponse)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// RunExecutionPlan indicates an expected call of RunExecutionPlan.\nfunc (mr *MockEngineClientMockRecorder) RunExecutionPlan(url, credential, executionPlanReq any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"RunExecutionPlan\", reflect.TypeOf((*MockEngineClient)(nil).RunExecutionPlan), url, credential, executionPlanReq)\n}\n"
  },
  {
    "path": "pkg/executor/engine_stub_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage executor\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\n\t\"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\ntype TestBody struct {\n\tName     string `json:\"name\"`\n\tID       int    `json:\"id\"`\n\tFullName string `json:\"full_name\"`\n}\n\nfunc TestHttpClientPost(t *testing.T) {\n\tr := require.New(t)\n\tcli := NewEngineClient(\"HTTP\", time.Second, nil, \"application/json\", \"http\")\n\treq := &scql.RunExecutionPlanRequest{\n\t\tAsync:       false,\n\t\tCallbackUrl: \"http://example.com/callback\",\n\t}\n\tresp := &scql.RunExecutionPlanResponse{\n\t\tJobId:           \"job_id_example\",\n\t\tPartyCode:       \"party_code_example\",\n\t\tNumRowsAffected: 100,\n\t}\n\n\trespBody, err := protojson.Marshal(resp)\n\tr.NoError(err)\n\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.Method != \"POST\" {\n\t\t\tt.Errorf(\"Expected 'POST' request, got '%s'\", r.Method)\n\t\t}\n\t\tvar b scql.RunExecutionPlanRequest\n\t\terr := json.NewDecoder(r.Body).Decode(&b)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Error when unmarshaling json body: %v\", err)\n\t\t}\n\t\tif b.Async != req.Async {\n\t\t\tt.Errorf(\"Expect %t got %t\", req.Async, b.Async)\n\t\t}\n\t\tif b.CallbackUrl != req.CallbackUrl {\n\t\t\tt.Errorf(\"Expect %s got %s\", req.CallbackUrl, b.CallbackUrl)\n\t\t}\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tw.WriteHeader(http.StatusOK)\n\t\tw.Write(respBody)\n\t}))\n\tdefer ts.Close()\n\n\tu, err := url.Parse(ts.URL)\n\tif err != nil {\n\t\tt.Fatalf(\"Error parsing URL: %v\", err)\n\t}\n\n\t_, err = cli.RunExecutionPlan(u.Host, \"credential\", req)\n\tr.NoError(err)\n}\n"
  },
  {
    "path": "pkg/executor/executor.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/status\"\n\t\"github.com/secretflow/scql/pkg/util/logutil\"\n)\n\ntype Executor struct {\n\tExecutionPlans        map[string]*scql.RunExecutionPlanRequest\n\tOutputNames           []string\n\tEngineStub            *EngineStub\n\tSessionID             string\n\tPartyCodeToHost       map[string]string\n\tpartyCodeToCredential map[string]string\n\n\tmu sync.Mutex\n\t// the following variables are protected by mutex\n\t// intermediateResults valid only run in async mode\n\tintermediateResults map[string]*scql.ReportRequest\n}\n\ntype ResponseInfo struct {\n\tResponse *scql.RunExecutionPlanResponse\n\tErr      error\n}\n\nfunc NewExecutor(plans map[string]*scql.RunExecutionPlanRequest, outputNames []string,\n\tengineStub *EngineStub, id string, partyInfo *graph.PartyInfo) (*Executor, error) {\n\tpartyCodeToHost := make(map[string]string)\n\tpartyCodeToCredential := make(map[string]string)\n\tfor _, partyCode := range partyInfo.GetParties() {\n\t\tpartyURL, err := partyInfo.GetUrlByParty(partyCode)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpartyCodeToHost[partyCode] = partyURL\n\n\t\tpartyCredential, err := partyInfo.GetCredentialByParty(partyCode)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpartyCodeToCredential[partyCode] = partyCredential\n\t}\n\n\treturn &Executor{\n\t\tExecutionPlans:        plans,\n\t\tOutputNames:           outputNames,\n\t\tEngineStub:            engineStub,\n\t\tSessionID:             id,\n\t\tPartyCodeToHost:       partyCodeToHost,\n\t\tpartyCodeToCredential: partyCodeToCredential,\n\t\tintermediateResults:   make(map[string]*scql.ReportRequest),\n\t}, nil\n}\n\nfunc (exec *Executor) RunExecutionPlan(ctx context.Context, engineAsync bool) (*scql.QueryResponse, error) {\n\ttimeStart := time.Now()\n\tlogEntry := &logutil.MonitorLogEntry{\n\t\tSessionID:  exec.SessionID,\n\t\tActionName: fmt.Sprintf(\"%v@%v\", \"EngineStub\", \"RunExecutionPlan\"),\n\t}\n\tresult, err := exec.RunExecutionPlanCore(ctx, engineAsync)\n\tlogEntry.CostTime = time.Since(timeStart)\n\tif err != nil {\n\t\tlogEntry.ErrorMsg = err.Error()\n\t\tlogrus.Error(logEntry)\n\t} else {\n\t\tlogrus.Info(logEntry)\n\t}\n\n\treturn result, err\n}\n\nfunc (exec *Executor) RunExecutionPlanCore(ctx context.Context, engineAsync bool) (*scql.QueryResponse, error) {\n\t// Prepare requests for each party's engine\n\tvar urls []string\n\tvar bodies []string\n\tvar partyCodes []string\n\tvar partyCredentials []string\n\tvar executionPlanReqs []*scql.RunExecutionPlanRequest\n\t// Note: In P2P mode, ExecutionPlans contains only the current party's plan\n\t// (populated by CreateExecutor), so this loop runs exactly once.\n\tfor partyCode, pb := range exec.ExecutionPlans {\n\t\turl := exec.PartyCodeToHost[pb.GetJobParams().GetPartyCode()]\n\t\turls = append(urls, url)\n\n\t\tpb.Async = engineAsync\n\t\tpb.CallbackUrl = exec.EngineStub.cbURL\n\t\texecutionPlanReqs = append(executionPlanReqs, pb)\n\t\tm := protojson.MarshalOptions{UseProtoNames: true}\n\t\tbody, err := m.Marshal(pb)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tbodies = append(bodies, string(body))\n\n\t\tpartyCodes = append(partyCodes, partyCode)\n\n\t\tpartyCredentials = append(partyCredentials, exec.partyCodeToCredential[pb.GetJobParams().GetPartyCode()])\n\t}\n\n\t// Launch goroutines for each engine (1 goroutine in P2P mode)\n\tc := make(chan ResponseInfo, len(urls))\n\tfor i, url := range urls {\n\t\tgo func(partyCode, url, credential, rawRequest string, executionPlanReq *scql.RunExecutionPlanRequest) {\n\t\t\ttimeStart := time.Now()\n\t\t\tlogEntry := &logutil.MonitorLogEntry{\n\t\t\t\tSessionID:  exec.SessionID,\n\t\t\t\tActionName: fmt.Sprintf(\"%v@%v\", \"Executor\", \"RunExecutionPlan\"),\n\t\t\t\tRawRequest: rawRequest,\n\t\t\t}\n\t\t\tresponse, err := exec.EngineStub.webClient.RunExecutionPlan(url, credential, executionPlanReq)\n\t\t\tlogEntry.CostTime = time.Since(timeStart)\n\t\t\tif err != nil {\n\t\t\t\tlogEntry.ErrorMsg = err.Error()\n\t\t\t\tlogrus.Errorf(\"%v|PartyCode:%v|Url:%v\", logEntry, partyCode, url)\n\t\t\t} else {\n\t\t\t\tlogrus.Infof(\"%v|PartyCode:%v|Url:%v\", logEntry, partyCode, url)\n\t\t\t}\n\t\t\tc <- ResponseInfo{\n\t\t\t\tResponse: response,\n\t\t\t\tErr:      err,\n\t\t\t}\n\t\t}(partyCodes[i], url, partyCredentials[i], bodies[i], executionPlanReqs[i])\n\t}\n\n\t// Collect responses from all engines (1 response in P2P mode)\n\toutCols := []*scql.Tensor{}\n\tvar affectedRows int64 = 0\n\tvar dimValue int64 = 0\n\tisFirstCol := true\n\tfor i := 0; i < len(urls); i++ {\n\t\tresponseInfo := <-c\n\t\tif responseInfo.Err != nil {\n\t\t\treturn nil, responseInfo.Err\n\t\t}\n\t\tresponse := responseInfo.Response\n\t\tif response.GetStatus().GetCode() != int32(scql.Code_OK) {\n\t\t\treturn nil, status.NewStatusFromProto(response.GetStatus())\n\t\t}\n\n\t\tif response.GetNumRowsAffected() != 0 {\n\t\t\tif affectedRows == 0 {\n\t\t\t\taffectedRows = response.GetNumRowsAffected()\n\t\t\t} else if affectedRows != response.GetNumRowsAffected() {\n\t\t\t\terrMsg := fmt.Errorf(\"affected rows not matched, received affectedRows=%v, req.NumRowsAffected=%v\", affectedRows, response.GetNumRowsAffected())\n\t\t\t\treturn nil, status.Wrap(scql.Code_ENGINE_RUNSQL_ERROR, errMsg)\n\t\t\t}\n\t\t}\n\n\t\tfor _, col := range response.GetOutColumns() {\n\n\t\t\tcolShape := col.GetShape()\n\t\t\tif colShape == nil || len(colShape.GetDim()) == 0 {\n\t\t\t\treturn nil, status.Wrap(scql.Code_ENGINE_RUNSQL_ERROR, fmt.Errorf(\"unexpected nil TensorShape\"))\n\t\t\t}\n\t\t\tif isFirstCol {\n\t\t\t\tdimValue = colShape.GetDim()[0].GetDimValue()\n\t\t\t\tisFirstCol = false\n\t\t\t} else if dimValue != colShape.GetDim()[0].GetDimValue() {\n\t\t\t\terrMsg := fmt.Errorf(\"dim shape not matched, peer shape value=%v, self shape value=%v\", dimValue, colShape.GetDim()[0].GetDimValue())\n\t\t\t\treturn nil, status.Wrap(scql.Code_ENGINE_RUNSQL_ERROR, errMsg)\n\t\t\t}\n\t\t\tif _, err := find(exec.OutputNames, col.GetName()); err == nil {\n\t\t\t\toutCols = append(outCols, col)\n\t\t\t}\n\t\t}\n\t}\n\n\tif !engineAsync {\n\t\t// sync mode can get the query result\n\t\tif err := CheckResultSchemas(outCols, exec.OutputNames); err != nil {\n\t\t\treturn nil, status.Wrap(scql.Code_INTERNAL, err)\n\t\t}\n\t\treturn &scql.QueryResponse{\n\t\t\tStatus: &scql.Status{Code: int32(scql.Code_OK)},\n\t\t\tResult: &scql.QueryResult{\n\t\t\t\tOutColumns:   outCols,\n\t\t\t\tAffectedRows: affectedRows,\n\t\t\t},\n\t\t}, nil\n\t}\n\n\t// async mode returns response with OK status\n\treturn &scql.QueryResponse{\n\t\tStatus: &scql.Status{Code: int32(scql.Code_OK)},\n\t\tResult: &scql.QueryResult{\n\t\t\tAffectedRows: affectedRows,\n\t\t},\n\t}, nil\n}\n\n// call it only in async mode\n// return true if session finished (on error or succeed)\nfunc (exec *Executor) HandleResultCallback(req *scql.ReportRequest) (finished bool) {\n\n\texec.mu.Lock()\n\texec.intermediateResults[req.GetPartyCode()] = req\n\treportCnt := len(exec.intermediateResults)\n\texec.mu.Unlock()\n\n\t// finished on error\n\tif req.GetStatus().GetCode() != 0 {\n\t\treturn true\n\t}\n\n\t// finished on all report received\n\tif reportCnt == len(exec.ExecutionPlans) {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc CheckResultSchemas(outCols []*scql.Tensor, expectColNames []string) error {\n\tif len(outCols) != len(expectColNames) {\n\t\treturn fmt.Errorf(\"the size of output column expected to be %d, but got %d\", len(expectColNames), len(outCols))\n\t}\n\n\tfor i := 0; i < len(expectColNames); i++ {\n\t\tif outCols[i].GetName() != expectColNames[i] {\n\t\t\treturn fmt.Errorf(\"output column name not match, expect=%s, got=%s\", expectColNames[i], outCols[i].GetName())\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc find(ss []string, s string) (int, error) {\n\tfor i, e := range ss {\n\t\tif e == s {\n\t\t\treturn i, nil\n\t\t}\n\t}\n\treturn -1, fmt.Errorf(\"unable to find name %v in %v\", s, ss)\n}\n"
  },
  {
    "path": "pkg/executor/executor_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage executor\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\ntype mockGrpcEngineStub struct {\n\tsessionId string\n\t// url -> OutColumns\n\tresponses map[string][]*proto.Tensor\n}\n\nfunc (client *mockGrpcEngineStub) RunExecutionPlan(url, credential string, executionPlanReq *proto.RunExecutionPlanRequest) (*proto.RunExecutionPlanResponse, error) {\n\treturn &proto.RunExecutionPlanResponse{\n\t\tStatus:     &proto.Status{Code: int32(proto.Code_OK)},\n\t\tJobId:      client.sessionId,\n\t\tOutColumns: client.responses[url],\n\t}, nil\n}\n\nfunc (client *mockGrpcEngineStub) Post(ctx context.Context, url, credential, content_type, body string) (string, error) {\n\treturn \"\", errors.New(\"cannot use gRPC engine client to run HTTP method\")\n}\n\n// Helper to create mock party info for tests\nfunc createMockPartyInfo() *graph.PartyInfo {\n\treturn graph.NewPartyInfo([]*graph.Participant{\n\t\t{\n\t\t\tPartyCode: \"alice\",\n\t\t\tEndpoints: []string{\"alice.url\"},\n\t\t\tToken:     \"alice_credential\",\n\t\t},\n\t\t{\n\t\t\tPartyCode: \"bob\",\n\t\t\tEndpoints: []string{\"bob.url\"},\n\t\t\tToken:     \"bob_credential\",\n\t\t},\n\t})\n}\n\n// Helper to create a simple test execution graph\nfunc createTestExecutionGraph(partyInfo *graph.PartyInfo, outputName string) *graph.Graph {\n\tt1 := graph.NewTensor(0, \"alice.t1\")\n\tt1.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\tt1.OwnerPartyCode = \"alice\"\n\tt1.DType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING)\n\n\tt2 := graph.NewTensor(1, \"bob.t2\")\n\tt2.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\tt2.OwnerPartyCode = \"bob\"\n\tt2.DType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING)\n\n\t// Create execution nodes\n\trunSQLNode1 := &graph.ExecutionNode{\n\t\tID:         0,\n\t\tName:       \"RunSQLOp1\",\n\t\tOpType:     operator.OpNameRunSQL,\n\t\tInputs:     make(map[string][]*graph.Tensor),\n\t\tOutputs:    map[string][]*graph.Tensor{\"output\": {t1}},\n\t\tAttributes: make(map[string]*graph.Attribute),\n\t\tEdges:      make(map[*graph.Edge]bool),\n\t\tParties:    []string{\"alice\"},\n\t}\n\n\trunSQLNode2 := &graph.ExecutionNode{\n\t\tID:         1,\n\t\tName:       \"RunSQLOp2\",\n\t\tOpType:     operator.OpNameRunSQL,\n\t\tInputs:     make(map[string][]*graph.Tensor),\n\t\tOutputs:    map[string][]*graph.Tensor{\"output\": {t2}},\n\t\tAttributes: make(map[string]*graph.Attribute),\n\t\tEdges:      make(map[*graph.Edge]bool),\n\t\tParties:    []string{\"bob\"},\n\t}\n\n\t// Create pipeline with nodes\n\tpipeline := &graph.Pipeline{\n\t\tBatched:       false,\n\t\tInputTensors:  []*graph.Tensor{},\n\t\tOutputTensors: []*graph.Tensor{},\n\t\tNodes:         map[*graph.ExecutionNode]bool{runSQLNode1: true, runSQLNode2: true},\n\t}\n\n\t// Create graph\n\tg := &graph.Graph{\n\t\tPipelines:   []*graph.Pipeline{pipeline},\n\t\tNodeCnt:     2,\n\t\tOutputNames: []string{outputName},\n\t\tPartyInfo:   partyInfo,\n\t}\n\n\treturn g\n}\n\n// Helper to create mock engine stub for testing\nfunc createMockEngineStub(sessionID string, outputName string, mockValue []string) *EngineStub {\n\tstub := &EngineStub{}\n\tstub.webClient = &mockGrpcEngineStub{\n\t\tsessionId: sessionID,\n\t\tresponses: map[string][]*proto.Tensor{\n\t\t\t\"alice.url\": {\n\t\t\t\t{\n\t\t\t\t\tName:       outputName,\n\t\t\t\t\tElemType:   proto.PrimitiveDataType_STRING,\n\t\t\t\t\tStringData: mockValue,\n\t\t\t\t\tShape: &proto.TensorShape{\n\t\t\t\t\t\tDim: []*proto.TensorShape_Dimension{{\n\t\t\t\t\t\t\tValue: &proto.TensorShape_Dimension_DimValue{DimValue: int64(len(mockValue))},\n\t\t\t\t\t\t}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\treturn stub\n}\n\nfunc TestSyncExecutor(t *testing.T) {\n\ta := require.New(t)\n\n\t// Use helper functions to create test components\n\tpartyInfo := createMockPartyInfo()\n\toutputName := \"alice.t1\"\n\texecutionGraph := createTestExecutionGraph(partyInfo, outputName)\n\n\tp := graph.NewGraphPartitioner(executionGraph)\n\tp.NaivePartition()\n\n\tm := graph.NewGraphMapper(p.Graph, p.Pipelines)\n\tm.Map()\n\n\tsessionId := \"mock\"\n\tstartParams := &proto.JobStartParams{\n\t\tJobId: sessionId,\n\t}\n\n\tpbRequests := m.CodeGen(startParams)\n\n\t// only alice publish t1\n\t{\n\t\tmockValue := []string{\"test\"}\n\t\tstub := createMockEngineStub(sessionId, outputName, mockValue)\n\n\t\texecutor, err := NewExecutor(pbRequests, p.Graph.OutputNames, stub, sessionId, p.Graph.PartyInfo)\n\t\ta.NoError(err)\n\t\tresp, err := executor.RunExecutionPlan(context.Background(), false)\n\t\ta.NoError(err)\n\t\ta.Equal(len(p.Graph.OutputNames), len(resp.Result.OutColumns))\n\t\tfor i, name := range executor.OutputNames {\n\t\t\tout := resp.Result.OutColumns[i]\n\t\t\ta.Equal(name, out.Name)\n\t\t\ta.Equal(mockValue, out.GetStringData())\n\t\t}\n\t}\n}\n\nfunc TestFind(t *testing.T) {\n\ta := require.New(t)\n\n\tss := []string{\"0\", \"1\", \"2\", \"3\"}\n\n\t{\n\t\tidx, err := find(ss, \"1\")\n\t\ta.Equal(1, idx)\n\t\ta.Nil(err)\n\t}\n\n\t{\n\t\tidx, err := find(ss, \"4\")\n\t\ta.Equal(-1, idx)\n\t\ta.NotNil(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/expression/aggregation/aggregation.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage aggregation\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\n// IsAllFirstRow checks whether functions in `aggFuncs` are all FirstRow.\nfunc IsAllFirstRow(aggFuncs []*AggFuncDesc) bool {\n\tfor _, fun := range aggFuncs {\n\t\tif fun.Name != ast.AggFuncFirstRow {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// AggFunctionMode stands for the aggregation function's mode.\ntype AggFunctionMode int\n\n// |-----------------|--------------|--------------|\n// | AggFunctionMode | input        | output       |\n// |-----------------|--------------|--------------|\n// | CompleteMode    | origin data  | final result |\n// | FinalMode       | partial data | final result |\n// | Partial1Mode    | origin data  | partial data |\n// | Partial2Mode    | partial data | partial data |\n// | DedupMode       | origin data  | origin data  |\n// |-----------------|--------------|--------------|\nconst (\n\tCompleteMode AggFunctionMode = iota\n\tFinalMode\n\tPartial1Mode\n\tPartial2Mode\n\tDedupMode\n)\n"
  },
  {
    "path": "pkg/expression/aggregation/base_func.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage aggregation\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n\t\"github.com/secretflow/scql/pkg/util/mathutil\"\n)\n\n// baseFuncDesc describes an function signature, only used in planner.\ntype baseFuncDesc struct {\n\t// Name represents the function name.\n\tName string\n\t// Args represents the arguments of the function.\n\tArgs []expression.Expression\n\t// RetTp represents the return type of the function.\n\tRetTp *types.FieldType\n}\n\nfunc newBaseFuncDesc(ctx sessionctx.Context, name string, args []expression.Expression) (baseFuncDesc, error) {\n\tb := baseFuncDesc{Name: strings.ToLower(name), Args: args}\n\terr := b.typeInfer(ctx)\n\treturn b, err\n}\n\nfunc (a *baseFuncDesc) equal(ctx sessionctx.Context, other *baseFuncDesc) bool {\n\tif a.Name != other.Name || len(a.Args) != len(other.Args) {\n\t\treturn false\n\t}\n\tfor i := range a.Args {\n\t\tif !a.Args[i].Equal(ctx, other.Args[i]) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (a *baseFuncDesc) clone() *baseFuncDesc {\n\tclone := *a\n\tnewTp := *a.RetTp\n\tclone.RetTp = &newTp\n\tclone.Args = make([]expression.Expression, len(a.Args))\n\tfor i := range a.Args {\n\t\tclone.Args[i] = a.Args[i].Clone()\n\t}\n\treturn &clone\n}\n\n// String implements the fmt.Stringer interface.\nfunc (a *baseFuncDesc) String() string {\n\tbuffer := bytes.NewBufferString(a.Name)\n\tbuffer.WriteString(\"(\")\n\tfor i, arg := range a.Args {\n\t\tbuffer.WriteString(arg.String())\n\t\tif i+1 != len(a.Args) {\n\t\t\tbuffer.WriteString(\", \")\n\t\t}\n\t}\n\tbuffer.WriteString(\")\")\n\treturn buffer.String()\n}\n\n// typeInfer infers the arguments and return types of an function.\nfunc (a *baseFuncDesc) typeInfer(ctx sessionctx.Context) error {\n\tswitch a.Name {\n\tcase ast.AggFuncCount:\n\t\ta.typeInfer4Count(ctx)\n\tcase ast.AggFuncSum:\n\t\ta.typeInfer4Sum(ctx)\n\tcase ast.AggFuncAvg:\n\t\ta.typeInfer4Avg(ctx)\n\tcase ast.AggFuncGroupConcat:\n\t\ta.typeInfer4GroupConcat(ctx)\n\tcase ast.AggFuncMax, ast.AggFuncMin, ast.AggFuncFirstRow, ast.AggFuncMedian:\n\t\ta.typeInfer4MaxMin(ctx)\n\tcase ast.AggFuncStddevPop:\n\t\ta.typeInfer4PopOrSamp(ctx)\n\tcase ast.AggPercentileDisc:\n\t\ta.typeInfer4PercentileDisc(ctx)\n\tcase ast.WindowFuncRowNumber, ast.WindowFuncRank, ast.WindowFuncDenseRank:\n\t\ta.typeInfer4NumberFuncs()\n\tcase ast.WindowFuncCumeDist:\n\t\ta.typeInfer4CumeDist()\n\tcase ast.WindowFuncNtile:\n\t\ta.typeInfer4Ntile()\n\tcase ast.WindowFuncPercentRank:\n\t\ta.typeInfer4PercentRank()\n\tcase ast.WindowFuncLead, ast.WindowFuncLag:\n\t\ta.typeInfer4LeadLag(ctx)\n\tdefault:\n\t\treturn errors.Errorf(\"unsupported agg function: %s\", a.Name)\n\t}\n\treturn nil\n}\n\n// This function is copied from\n// https://github.com/pingcap/tidb/blob/80d6b5683c5c9e655d1eab432b198d7fea9b7d5f/pkg/expression/aggregation/base_func.go#L181,\n// and did some modifications, which is mainly on the percent parameter the range of which is changed to [0, 1] from [0, 100]\nfunc (a *baseFuncDesc) typeInfer4PercentileDisc(ctx sessionctx.Context) error {\n\tif len(a.Args) != 2 {\n\t\treturn errors.New(\"PERCENTILE_DISC should take 2 arguments\")\n\t}\n\n\tpercent, isNull, err := a.Args[1].EvalReal(ctx, chunk.Row{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"PERCENTILE_DISC: Invalid argument %s, error: %v\", a.Args[1].String(), err)\n\t}\n\tif percent < 0 || percent > 1 || isNull {\n\t\tif isNull {\n\t\t\treturn errors.New(\"PERCENTILE_DISC: Percentage value cannot be NULL\")\n\t\t}\n\t\treturn fmt.Errorf(\"Percentage value %f is out of range [0, 1]\", percent)\n\t}\n\ta.RetTp = a.Args[0].GetType().Clone()\n\t// a.RetTp.Flag &^= mysql.NotNullFlag, not sure why this line is needed in MaxMin\n\treturn nil\n}\n\nfunc (a *baseFuncDesc) typeInfer4Count(ctx sessionctx.Context) {\n\ta.RetTp = types.NewFieldType(mysql.TypeLonglong)\n\ta.RetTp.Flen = 21\n\ttypes.SetBinChsClnFlag(a.RetTp)\n}\n\n// typeInfer4Sum should returns a \"decimal\", otherwise it returns a \"double\".\n// Because child returns integer or decimal type.\nfunc (a *baseFuncDesc) typeInfer4Sum(ctx sessionctx.Context) {\n\tswitch a.Args[0].GetType().Tp {\n\tcase mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong:\n\t\t// Note(@yuyongqiang.yyq) int sum return int not float\n\t\ta.RetTp = types.NewFieldType(mysql.TypeLonglong)\n\t\ta.RetTp.Flen = 21\n\tdefault:\n\t\ta.RetTp = types.NewFieldType(mysql.TypeDouble)\n\t\ta.RetTp.Flen, a.RetTp.Decimal = mysql.MaxRealWidth, types.UnspecifiedLength\n\t}\n\ttypes.SetBinChsClnFlag(a.RetTp)\n}\n\n// typeInfer4Avg should returns a \"decimal\", otherwise it returns a \"double\".\n// Because child returns integer or decimal type.\nfunc (a *baseFuncDesc) typeInfer4Avg(ctx sessionctx.Context) {\n\tswitch a.Args[0].GetType().Tp {\n\tcase mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeNewDecimal:\n\t\ta.RetTp = types.NewFieldType(mysql.TypeNewDecimal)\n\t\tif a.Args[0].GetType().Decimal < 0 {\n\t\t\ta.RetTp.Decimal = mysql.MaxDecimalScale\n\t\t} else {\n\t\t\ta.RetTp.Decimal = mathutil.Min(a.Args[0].GetType().Decimal+types.DivFracIncr, mysql.MaxDecimalScale)\n\t\t}\n\t\ta.RetTp.Flen = mysql.MaxDecimalWidth\n\tcase mysql.TypeDouble, mysql.TypeFloat:\n\t\ta.RetTp = types.NewFieldType(mysql.TypeDouble)\n\t\ta.RetTp.Flen, a.RetTp.Decimal = mysql.MaxRealWidth, a.Args[0].GetType().Decimal\n\tdefault:\n\t\ta.RetTp = types.NewFieldType(mysql.TypeDouble)\n\t\ta.RetTp.Flen, a.RetTp.Decimal = mysql.MaxRealWidth, types.UnspecifiedLength\n\t}\n\ttypes.SetBinChsClnFlag(a.RetTp)\n}\n\nfunc (a *baseFuncDesc) typeInfer4GroupConcat(ctx sessionctx.Context) {\n\ta.RetTp = types.NewFieldType(mysql.TypeVarString)\n\ta.RetTp.Charset, a.RetTp.Collate = charset.GetDefaultCharsetAndCollate()\n\n\ta.RetTp.Flen, a.RetTp.Decimal = mysql.MaxBlobWidth, 0\n\t// TODO: a.Args[i] = expression.WrapWithCastAsString(ctx, a.Args[i])\n}\n\nfunc (a *baseFuncDesc) typeInfer4MaxMin(ctx sessionctx.Context) {\n\t// _, argIsScalaFunc := a.Args[0].(*expression.ScalarFunction)\n\t// if argIsScalaFunc && a.Args[0].GetType().Tp == mysql.TypeFloat {\n\t// \t// For scalar function, the result of \"float32\" is set to the \"float64\"\n\t// \t// field in the \"Datum\". If we do not wrap a cast-as-double function on a.Args[0],\n\t// \t// error would happen when extracting the evaluation of a.Args[0] to a ProjectionExec.\n\t// \ttp := types.NewFieldType(mysql.TypeDouble)\n\t// \ttp.Flen, tp.Decimal = mysql.MaxRealWidth, types.UnspecifiedLength\n\t// \ttypes.SetBinChsClnFlag(tp)\n\t// \ta.Args[0] = expression.BuildCastFunction(ctx, a.Args[0], tp)\n\t// }\n\ta.RetTp = a.Args[0].GetType()\n\tif (a.Name == ast.AggFuncMax || a.Name == ast.AggFuncMin) && a.RetTp.Tp != mysql.TypeBit {\n\t\ta.RetTp = a.Args[0].GetType().Clone()\n\t\ta.RetTp.Flag &^= mysql.NotNullFlag\n\t}\n\t// TODO: fix other aggFuncs for TypeEnum & TypeSet\n\tif (a.RetTp.Tp == mysql.TypeEnum || a.RetTp.Tp == mysql.TypeSet) && a.Name != ast.AggFuncFirstRow {\n\t\ta.RetTp = &types.FieldType{Tp: mysql.TypeString, Flen: mysql.MaxFieldCharLength}\n\t}\n}\n\nfunc (a *baseFuncDesc) typeInfer4NumberFuncs() {\n\ta.RetTp = types.NewFieldType(mysql.TypeLonglong)\n\ta.RetTp.Flen = 21\n\ttypes.SetBinChsClnFlag(a.RetTp)\n}\n\nfunc (a *baseFuncDesc) typeInfer4CumeDist() {\n\ta.RetTp = types.NewFieldType(mysql.TypeDouble)\n\ta.RetTp.Flen, a.RetTp.Decimal = mysql.MaxRealWidth, mysql.NotFixedDec\n}\n\nfunc (a *baseFuncDesc) typeInfer4Ntile() {\n\ta.RetTp = types.NewFieldType(mysql.TypeLonglong)\n\ta.RetTp.Flen = 21\n\ttypes.SetBinChsClnFlag(a.RetTp)\n\ta.RetTp.Flag |= mysql.UnsignedFlag\n}\n\nfunc (a *baseFuncDesc) typeInfer4PercentRank() {\n\ta.RetTp = types.NewFieldType(mysql.TypeDouble)\n\ta.RetTp.Flag, a.RetTp.Decimal = mysql.MaxRealWidth, mysql.NotFixedDec\n}\n\nfunc (a *baseFuncDesc) typeInfer4LeadLag(ctx sessionctx.Context) {\n\tif len(a.Args) <= 2 {\n\t\ta.typeInfer4MaxMin(ctx)\n\t} else {\n\t\t// Merge the type of first and third argument.\n\t\ta.RetTp = expression.InferType4ControlFuncs(a.Args[0].GetType(), a.Args[2].GetType())\n\t}\n}\n\nfunc (a *baseFuncDesc) typeInfer4PopOrSamp(ctx sessionctx.Context) {\n\t// var_pop/std/var_samp/stddev_samp's return value type is double\n\ta.RetTp = types.NewFieldType(mysql.TypeDouble)\n\ta.RetTp.Flen, a.RetTp.Decimal = mysql.MaxRealWidth, types.UnspecifiedLength\n}\n\n// GetDefaultValue gets the default value when the function's input is null.\n// According to MySQL, default values of the function are listed as follows:\n// e.g.\n// Table t which is empty:\n// +-------+---------+---------+\n// | Table | Field   | Type    |\n// +-------+---------+---------+\n// | t     | a       | int(11) |\n// +-------+---------+---------+\n//\n// Query: `select a, avg(a), sum(a), count(a), bit_xor(a), bit_or(a), bit_and(a), max(a), min(a), group_concat(a) from t;`\n// +------+--------+--------+----------+------------+-----------+----------------------+--------+--------+-----------------+\n// | a    | avg(a) | sum(a) | count(a) | bit_xor(a) | bit_or(a) | bit_and(a)           | max(a) | min(a) | group_concat(a) |\n// +------+--------+--------+----------+------------+-----------+----------------------+--------+--------+-----------------+\n// | NULL |   NULL |   NULL |        0 |          0 |         0 | 18446744073709551615 |   NULL |   NULL | NULL            |\n// +------+--------+--------+----------+------------+-----------+----------------------+--------+--------+-----------------+\nfunc (a *baseFuncDesc) GetDefaultValue() (v types.Datum) {\n\tswitch a.Name {\n\tcase ast.AggFuncCount:\n\t\tv = types.NewIntDatum(0)\n\tcase ast.AggFuncFirstRow, ast.AggFuncGroupConcat, ast.AggFuncSum:\n\t\tv = types.Datum{}\n\t}\n\treturn\n}\n\n// We do not need to wrap cast upon these functions,\n// since the EvalXXX method called by the arg is determined by the corresponding arg type.\nvar noNeedCastAggFuncs = map[string]struct{}{\n\tast.AggFuncCount:    {},\n\tast.AggFuncMax:      {},\n\tast.AggFuncMin:      {},\n\tast.AggFuncFirstRow: {},\n\tast.WindowFuncNtile: {},\n}\n\n// WrapCastForAggArgs wraps the args of an aggregate function with a cast function.\nfunc (a *baseFuncDesc) WrapCastForAggArgs(ctx sessionctx.Context) {\n\tif len(a.Args) == 0 {\n\t\treturn\n\t}\n\tif _, ok := noNeedCastAggFuncs[a.Name]; ok {\n\t\treturn\n\t}\n\tvar castFunc func(ctx sessionctx.Context, expr expression.Expression) expression.Expression\n\tswitch retTp := a.RetTp; retTp.EvalType() {\n\tcase types.ETInt:\n\t\tcastFunc = expression.WrapWithCastAsInt\n\tcase types.ETReal:\n\t\tcastFunc = expression.WrapWithCastAsReal\n\tcase types.ETString:\n\t\tcastFunc = expression.WrapWithCastAsString\n\tcase types.ETDecimal:\n\t\tcastFunc = expression.WrapWithCastAsDecimal\n\tcase types.ETDatetime, types.ETTimestamp:\n\t\tcastFunc = func(ctx sessionctx.Context, expr expression.Expression) expression.Expression {\n\t\t\treturn expression.WrapWithCastAsTime(ctx, expr, retTp)\n\t\t}\n\tcase types.ETDuration:\n\t\tcastFunc = expression.WrapWithCastAsDuration\n\tcase types.ETJson:\n\t\tcastFunc = expression.WrapWithCastAsJSON\n\tdefault:\n\t\tpanic(\"should never happen in baseFuncDesc.WrapCastForAggArgs\")\n\t}\n\tfor i := range a.Args {\n\t\t// Do not cast the second args of these functions, as they are simply non-negative numbers.\n\t\tif i == 1 && (a.Name == ast.WindowFuncLead || a.Name == ast.WindowFuncLag || a.Name == ast.WindowFuncNthValue) {\n\t\t\tcontinue\n\t\t}\n\t\ta.Args[i] = castFunc(ctx, a.Args[i])\n\t\tif a.Name != ast.AggFuncAvg && a.Name != ast.AggFuncSum {\n\t\t\tcontinue\n\t\t}\n\t\t// After wrapping cast on the argument, flen etc. may not the same\n\t\t// as the type of the aggregation function. The following part set\n\t\t// the type of the argument exactly as the type of the aggregation\n\t\t// function.\n\t\t// Note: If the `Tp` of argument is the same as the `Tp` of the\n\t\t// aggregation function, it will not wrap cast function on it\n\t\t// internally. The reason of the special handling for `Column` is\n\t\t// that the `RetType` of `Column` refers to the `infoschema`, so we\n\t\t// need to set a new variable for it to avoid modifying the\n\t\t// definition in `infoschema`.\n\t\tif col, ok := a.Args[i].(*expression.Column); ok {\n\t\t\tcol.RetType = types.NewFieldType(col.RetType.Tp)\n\t\t}\n\t\t// originTp is used when the the `Tp` of column is TypeFloat32 while\n\t\t// the type of the aggregation function is TypeFloat64.\n\t\toriginTp := a.Args[i].GetType().Tp\n\t\t*(a.Args[i].GetType()) = *(a.RetTp)\n\t\ta.Args[i].GetType().Tp = originTp\n\t}\n}\n"
  },
  {
    "path": "pkg/expression/aggregation/descriptor.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage aggregation\n\nimport (\n\t\"math\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// AggFuncDesc describes an aggregation function signature, only used in planner.\ntype AggFuncDesc struct {\n\tbaseFuncDesc\n\t// Mode represents the execution mode of the aggregation function.\n\tMode AggFunctionMode\n\t// HasDistinct represents whether the aggregation function contains distinct attribute.\n\tHasDistinct bool\n\t// UseAsThreshold represents whether the aggregation function(count) uses as a threshold\n\tUseAsThreshold bool\n}\n\n// NewAggFuncDesc creates an aggregation function signature descriptor.\nfunc NewAggFuncDesc(ctx sessionctx.Context, name string, args []expression.Expression, hasDistinct bool) (*AggFuncDesc, error) {\n\tb, err := newBaseFuncDesc(ctx, name, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &AggFuncDesc{baseFuncDesc: b, HasDistinct: hasDistinct}, nil\n}\n\n// Equal checks whether two aggregation function signatures are equal.\nfunc (a *AggFuncDesc) Equal(ctx sessionctx.Context, other *AggFuncDesc) bool {\n\tif a.HasDistinct != other.HasDistinct {\n\t\treturn false\n\t}\n\treturn a.baseFuncDesc.equal(ctx, &other.baseFuncDesc)\n}\n\n// Clone copies an aggregation function signature totally.\nfunc (a *AggFuncDesc) Clone() *AggFuncDesc {\n\tclone := *a\n\tclone.baseFuncDesc = *a.baseFuncDesc.clone()\n\tclone.UseAsThreshold = false\n\treturn &clone\n}\n\n// EvalNullValueInOuterJoin gets the null value when the aggregation is upon an outer join,\n// and the aggregation function's input is null.\n// If there is no matching row for the inner table of an outer join,\n// an aggregation function only involves constant and/or columns belongs to the inner table\n// will be set to the null value.\n// The input stands for the schema of Aggregation's child. If the function can't produce a null value, the second\n// return value will be false.\n// e.g.\n// Table t with only one row:\n// +-------+---------+---------+\n// | Table | Field   | Type    |\n// +-------+---------+---------+\n// | t     | a       | int(11) |\n// +-------+---------+---------+\n// +------+\n// | a    |\n// +------+\n// |    1 |\n// +------+\n//\n// Table s which is empty:\n// +-------+---------+---------+\n// | Table | Field   | Type    |\n// +-------+---------+---------+\n// | s     | a       | int(11) |\n// +-------+---------+---------+\n//\n// Query: `select t.a as `t.a`,  count(95), sum(95), avg(95), bit_or(95), bit_and(95), bit_or(95), max(95), min(95), s.a as `s.a`, avg(95) from t left join s on t.a = s.a;`\n// +------+-----------+---------+---------+------------+-------------+------------+---------+---------+------+----------+\n// | t.a  | count(95) | sum(95) | avg(95) | bit_or(95) | bit_and(95) | bit_or(95) | max(95) | min(95) | s.a  | avg(s.a) |\n// +------+-----------+---------+---------+------------+-------------+------------+---------+---------+------+----------+\n// |    1 |         1 |      95 | 95.0000 |         95 |          95 |         95 |      95 |      95 | NULL |     NULL |\n// +------+-----------+---------+---------+------------+-------------+------------+---------+---------+------+----------+\nfunc (a *AggFuncDesc) EvalNullValueInOuterJoin(ctx sessionctx.Context, schema *expression.Schema) (types.Datum, bool) {\n\tswitch a.Name {\n\tcase ast.AggFuncCount:\n\t\treturn a.evalNullValueInOuterJoin4Count(ctx, schema)\n\tcase ast.AggFuncSum, ast.AggFuncMax, ast.AggFuncMin,\n\t\tast.AggFuncFirstRow:\n\t\treturn a.evalNullValueInOuterJoin4Sum(ctx, schema)\n\tcase ast.AggFuncAvg, ast.AggFuncGroupConcat:\n\t\treturn types.Datum{}, false\n\tcase ast.AggFuncBitAnd:\n\t\treturn a.evalNullValueInOuterJoin4BitAnd(ctx, schema)\n\tcase ast.AggFuncBitOr, ast.AggFuncBitXor:\n\t\treturn a.evalNullValueInOuterJoin4BitOr(ctx, schema)\n\tdefault:\n\t\tpanic(\"unsupported agg function\")\n\t}\n}\n\nfunc (a *AggFuncDesc) evalNullValueInOuterJoin4Count(ctx sessionctx.Context, schema *expression.Schema) (types.Datum, bool) {\n\tfor _, arg := range a.Args {\n\t\tresult := expression.EvaluateExprWithNull(ctx, schema, arg)\n\t\tcon, ok := result.(*expression.Constant)\n\t\tif !ok || con.Value.IsNull() {\n\t\t\treturn types.Datum{}, ok\n\t\t}\n\t}\n\treturn types.NewDatum(1), true\n}\n\nfunc (a *AggFuncDesc) evalNullValueInOuterJoin4Sum(ctx sessionctx.Context, schema *expression.Schema) (types.Datum, bool) {\n\tresult := expression.EvaluateExprWithNull(ctx, schema, a.Args[0])\n\tcon, ok := result.(*expression.Constant)\n\tif !ok || con.Value.IsNull() {\n\t\treturn types.Datum{}, ok\n\t}\n\treturn con.Value, true\n}\n\nfunc (a *AggFuncDesc) evalNullValueInOuterJoin4BitAnd(ctx sessionctx.Context, schema *expression.Schema) (types.Datum, bool) {\n\tresult := expression.EvaluateExprWithNull(ctx, schema, a.Args[0])\n\tcon, ok := result.(*expression.Constant)\n\tif !ok || con.Value.IsNull() {\n\t\treturn types.NewDatum(uint64(math.MaxUint64)), true\n\t}\n\treturn con.Value, true\n}\n\nfunc (a *AggFuncDesc) evalNullValueInOuterJoin4BitOr(ctx sessionctx.Context, schema *expression.Schema) (types.Datum, bool) {\n\tresult := expression.EvaluateExprWithNull(ctx, schema, a.Args[0])\n\tcon, ok := result.(*expression.Constant)\n\tif !ok || con.Value.IsNull() {\n\t\treturn types.NewDatum(0), true\n\t}\n\treturn con.Value, true\n}\n"
  },
  {
    "path": "pkg/expression/aggregation/util.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage aggregation\n\nimport (\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/codec\"\n\t\"github.com/secretflow/scql/pkg/util/mvmap\"\n)\n\n// distinctChecker stores existing keys and checks if given data is distinct.\ntype distinctChecker struct {\n\texistingKeys *mvmap.MVMap\n\tkey          []byte\n\tvals         [][]byte\n\tsc           *stmtctx.StatementContext\n}\n\n// createDistinctChecker creates a new distinct checker.\nfunc createDistinctChecker(sc *stmtctx.StatementContext) *distinctChecker {\n\treturn &distinctChecker{\n\t\texistingKeys: mvmap.NewMVMap(),\n\t\tsc:           sc,\n\t}\n}\n\n// Check checks if values is distinct.\nfunc (d *distinctChecker) Check(values []types.Datum) (bool, error) {\n\td.key = d.key[:0]\n\tvar err error\n\td.key, err = codec.EncodeValue(d.sc, d.key, values...)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\td.vals = d.existingKeys.Get(d.key, d.vals[:0])\n\tif len(d.vals) > 0 {\n\t\treturn false, nil\n\t}\n\td.existingKeys.Put(d.key, []byte{})\n\treturn true, nil\n}\n"
  },
  {
    "path": "pkg/expression/aggregation/window_func.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage aggregation\n\nimport (\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n)\n\n// WindowFuncDesc describes a window function signature, only used in planner.\ntype WindowFuncDesc struct {\n\tbaseFuncDesc\n}\n\n// NewWindowFuncDesc creates a window function signature descriptor.\nfunc NewWindowFuncDesc(ctx sessionctx.Context, name string, args []expression.Expression) (*WindowFuncDesc, error) {\n\tswitch strings.ToLower(name) {\n\tcase ast.WindowFuncNthValue:\n\t\tval, isNull, ok := expression.GetUint64FromConstant(args[1])\n\t\t// nth_value does not allow `0`, but allows `null`.\n\t\tif !ok || (val == 0 && !isNull) {\n\t\t\treturn nil, nil\n\t\t}\n\tcase ast.WindowFuncNtile:\n\t\tval, isNull, ok := expression.GetUint64FromConstant(args[0])\n\t\t// ntile does not allow `0`, but allows `null`.\n\t\tif !ok || (val == 0 && !isNull) {\n\t\t\treturn nil, nil\n\t\t}\n\tcase ast.WindowFuncLead, ast.WindowFuncLag:\n\t\tif len(args) < 2 {\n\t\t\tbreak\n\t\t}\n\t\t_, isNull, ok := expression.GetUint64FromConstant(args[1])\n\t\tif !ok || isNull {\n\t\t\treturn nil, nil\n\t\t}\n\t}\n\tbase, err := newBaseFuncDesc(ctx, name, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &WindowFuncDesc{base}, nil\n}\n\n// noFrameWindowFuncs is the functions that operate on the entire partition,\n// they should not have frame specifications.\nvar noFrameWindowFuncs = map[string]struct{}{\n\tast.WindowFuncCumeDist:    {},\n\tast.WindowFuncDenseRank:   {},\n\tast.WindowFuncLag:         {},\n\tast.WindowFuncLead:        {},\n\tast.WindowFuncNtile:       {},\n\tast.WindowFuncPercentRank: {},\n\tast.WindowFuncRank:        {},\n\tast.WindowFuncRowNumber:   {},\n}\n\n// NeedFrame checks if the function need frame specification.\nfunc NeedFrame(name string) bool {\n\t_, ok := noFrameWindowFuncs[strings.ToLower(name)]\n\treturn !ok\n}\n"
  },
  {
    "path": "pkg/expression/builtin.go",
    "content": "// Copyright 2013 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n)\n\n// baseBuiltinFunc will be contained in every struct that implement builtinFunc interface.\ntype baseBuiltinFunc struct {\n\targs []Expression\n\tctx  sessionctx.Context\n\ttp   *types.FieldType\n\t//pbCode tipb.ScalarFuncSig\n}\n\n//func (b *baseBuiltinFunc) setPbCode(c tipb.ScalarFuncSig) {\n//\tb.pbCode = c\n//}\n\nfunc newBaseBuiltinFunc(ctx sessionctx.Context, args []Expression) baseBuiltinFunc {\n\tif ctx == nil {\n\t\tpanic(\"ctx should not be nil\")\n\t}\n\treturn baseBuiltinFunc{\n\t\targs: args,\n\t\tctx:  ctx,\n\t\ttp:   types.NewFieldType(mysql.TypeUnspecified),\n\t}\n}\n\nfunc (b *baseBuiltinFunc) getArgs() []Expression {\n\treturn b.args\n}\n\nfunc (b *baseBuiltinFunc) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error {\n\treturn errors.Errorf(\"baseBuiltinFunc.vecEvalInt() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error {\n\treturn errors.Errorf(\"baseBuiltinFunc.vecEvalReal() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) vecEvalString(input *chunk.Chunk, result *chunk.Column) error {\n\treturn errors.Errorf(\"baseBuiltinFunc.vecEvalString() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error {\n\treturn errors.Errorf(\"baseBuiltinFunc.vecEvalDecimal() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) vecEvalTime(input *chunk.Chunk, result *chunk.Column) error {\n\treturn errors.Errorf(\"baseBuiltinFunc.vecEvalTime() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) vecEvalDuration(input *chunk.Chunk, result *chunk.Column) error {\n\treturn errors.Errorf(\"baseBuiltinFunc.vecEvalDuration() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) vecEvalJSON(input *chunk.Chunk, result *chunk.Column) error {\n\treturn errors.Errorf(\"baseBuiltinFunc.vecEvalJSON() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) evalInt(row chunk.Row) (int64, bool, error) {\n\treturn 0, false, errors.Errorf(\"baseBuiltinFunc.evalInt() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) evalReal(row chunk.Row) (float64, bool, error) {\n\treturn 0, false, errors.Errorf(\"baseBuiltinFunc.evalReal() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) evalString(row chunk.Row) (string, bool, error) {\n\treturn \"\", false, errors.Errorf(\"baseBuiltinFunc.evalString() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\treturn nil, false, errors.Errorf(\"baseBuiltinFunc.evalDecimal() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) evalTime(row chunk.Row) (types.Time, bool, error) {\n\treturn types.ZeroTime, false, errors.Errorf(\"baseBuiltinFunc.evalTime() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) evalDuration(row chunk.Row) (types.Duration, bool, error) {\n\treturn types.Duration{}, false, errors.Errorf(\"baseBuiltinFunc.evalDuration() should never be called, please contact the TiDB team for help\")\n}\n\nfunc (b *baseBuiltinFunc) getRetTp() *types.FieldType {\n\treturn b.tp\n}\n\nfunc (b *baseBuiltinFunc) equal(fun builtinFunc) bool {\n\tfunArgs := fun.getArgs()\n\tif len(funArgs) != len(b.args) {\n\t\treturn false\n\t}\n\tfor i := range b.args {\n\t\tif !b.args[i].Equal(b.ctx, funArgs[i]) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (b *baseBuiltinFunc) getCtx() sessionctx.Context {\n\treturn b.ctx\n}\n\nfunc (b *baseBuiltinFunc) cloneFrom(from *baseBuiltinFunc) {\n\tb.args = make([]Expression, 0, len(b.args))\n\tfor _, arg := range from.args {\n\t\tb.args = append(b.args, arg.Clone())\n\t}\n\tb.ctx = from.ctx\n\tb.tp = from.tp\n}\n\nfunc (b *baseBuiltinFunc) setDecimalAndFlenForDatetime(fsp int) {\n\tb.tp.Decimal = fsp\n\tb.tp.Flen = mysql.MaxDatetimeWidthNoFsp + fsp\n\tif fsp > 0 {\n\t\t// Add the length for `.`.\n\t\tb.tp.Flen++\n\t}\n}\n\nfunc (b *baseBuiltinFunc) setDecimalAndFlenForDate() {\n\tb.tp.Decimal = 0\n\tb.tp.Flen = mysql.MaxDateWidth\n\tb.tp.Tp = mysql.TypeDate\n}\n\nfunc (b *baseBuiltinFunc) setDecimalAndFlenForTime(fsp int) {\n\tb.tp.Decimal = fsp\n\tb.tp.Flen = mysql.MaxDurationWidthNoFsp + fsp\n\tif fsp > 0 {\n\t\t// Add the length for `.`.\n\t\tb.tp.Flen++\n\t}\n}\n\ntype builtinFunc interface {\n\t// evalInt evaluates int result of builtinFunc by given row.\n\tevalInt(row chunk.Row) (val int64, isNull bool, err error)\n\t// evalReal evaluates real representation of builtinFunc by given row.\n\tevalReal(row chunk.Row) (val float64, isNull bool, err error)\n\t// evalString evaluates string representation of builtinFunc by given row.\n\tevalString(row chunk.Row) (val string, isNull bool, err error)\n\t// evalDecimal evaluates decimal representation of builtinFunc by given row.\n\tevalDecimal(row chunk.Row) (val *types.MyDecimal, isNull bool, err error)\n\t// evalTime evaluates DATE/DATETIME/TIMESTAMP representation of builtinFunc by given row.\n\tevalTime(row chunk.Row) (val types.Time, isNull bool, err error)\n\t// evalDuration evaluates duration representation of builtinFunc by given row.\n\tevalDuration(row chunk.Row) (val types.Duration, isNull bool, err error)\n\t// getArgs returns the arguments expressions.\n\tgetArgs() []Expression\n\t// equal check if this function equals to another function.\n\tequal(builtinFunc) bool\n\t// getCtx returns this function's context.\n\tgetCtx() sessionctx.Context\n\t// getRetTp returns the return type of the built-in function.\n\tgetRetTp() *types.FieldType\n\t//// setPbCode sets pbCode for signature.\n\t//setPbCode(tipb.ScalarFuncSig)\n\n\t// Clone returns a copy of itself.\n\tClone() builtinFunc\n}\n\ntype builtinFuncNew interface {\n\tevalIntWithCtx(ctx sessionctx.Context, row chunk.Row) (val int64, isNull bool, err error)\n}\n\n// functionClass is the interface for a function which may contains multiple functions.\ntype functionClass interface {\n\t// getFunction gets a function signature by the types and the counts of given arguments.\n\tgetFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error)\n}\n\n// baseFunctionClass will be contained in every struct that implement functionClass interface.\ntype baseFunctionClass struct {\n\tfuncName string\n\tminArgs  int\n\tmaxArgs  int\n}\n\nfunc (b *baseFunctionClass) verifyArgs(args []Expression) error {\n\tl := len(args)\n\tif l < b.minArgs || (b.maxArgs != -1 && l > b.maxArgs) {\n\t\treturn ErrIncorrectParameterCount.GenWithStackByArgs(b.funcName)\n\t}\n\treturn nil\n}\n\n// newBaseBuiltinFuncWithTp creates a built-in function signature with specified types of arguments and the return type of the function.\n// argTps indicates the types of the args, retType indicates the return type of the built-in function.\n// Every built-in function needs determined argTps and retType when we create it.\nfunc newBaseBuiltinFuncWithTp(ctx sessionctx.Context, args []Expression, retType types.EvalType, argTps ...types.EvalType) (bf baseBuiltinFunc) {\n\tif len(args) != len(argTps) {\n\t\tpanic(\"unexpected length of args and argTps\")\n\t}\n\tif ctx == nil {\n\t\tpanic(\"ctx should not be nil\")\n\t}\n\n\t/* NOTE(yang.y): disable type casting\n\tfor i := range args {\n\t\tswitch argTps[i] {\n\t\tcase types.ETInt:\n\t\t\targs[i] = WrapWithCastAsInt(ctx, args[i])\n\t\tcase types.ETReal:\n\t\t\targs[i] = WrapWithCastAsReal(ctx, args[i])\n\t\tcase types.ETDecimal:\n\t\t\targs[i] = WrapWithCastAsDecimal(ctx, args[i])\n\t\tcase types.ETString:\n\t\t\targs[i] = WrapWithCastAsString(ctx, args[i])\n\t\tcase types.ETDatetime:\n\t\t\targs[i] = WrapWithCastAsTime(ctx, args[i], types.NewFieldType(mysql.TypeDatetime))\n\t\tcase types.ETTimestamp:\n\t\t\targs[i] = WrapWithCastAsTime(ctx, args[i], types.NewFieldType(mysql.TypeTimestamp))\n\t\tcase types.ETDuration:\n\t\t\targs[i] = WrapWithCastAsDuration(ctx, args[i])\n\t\tcase types.ETJson:\n\t\t\targs[i] = WrapWithCastAsJSON(ctx, args[i])\n\t\t}\n\t}\n\t*/\n\n\tvar fieldType *types.FieldType\n\tswitch retType {\n\tcase types.ETInt:\n\t\tfieldType = &types.FieldType{\n\t\t\tTp:      mysql.TypeLonglong,\n\t\t\tFlen:    mysql.MaxIntWidth,\n\t\t\tDecimal: 0,\n\t\t\tFlag:    mysql.BinaryFlag,\n\t\t}\n\tcase types.ETString:\n\t\tfieldType = &types.FieldType{\n\t\t\tTp:      mysql.TypeVarString,\n\t\t\tFlen:    0,\n\t\t\tDecimal: types.UnspecifiedLength,\n\t\t}\n\tcase types.ETDecimal:\n\t\tfieldType = &types.FieldType{\n\t\t\tTp:      mysql.TypeNewDecimal,\n\t\t\tFlen:    11,\n\t\t\tDecimal: 0,\n\t\t\tFlag:    mysql.BinaryFlag,\n\t\t}\n\tcase types.ETReal:\n\t\tfieldType = &types.FieldType{\n\t\t\tTp:      mysql.TypeDouble,\n\t\t\tFlen:    mysql.MaxRealWidth,\n\t\t\tDecimal: types.UnspecifiedLength,\n\t\t\tFlag:    mysql.BinaryFlag,\n\t\t}\n\tcase types.ETDatetime:\n\t\tfieldType = &types.FieldType{\n\t\t\tTp:      mysql.TypeDatetime,\n\t\t\tFlen:    mysql.MaxDatetimeWidthWithFsp,\n\t\t\tDecimal: int(types.MaxFsp),\n\t\t\tFlag:    mysql.BinaryFlag,\n\t\t}\n\tcase types.ETTimestamp:\n\t\tfieldType = &types.FieldType{\n\t\t\tTp:      mysql.TypeTimestamp,\n\t\t\tFlen:    mysql.MaxDatetimeWidthWithFsp,\n\t\t\tDecimal: int(types.MaxFsp),\n\t\t\tFlag:    mysql.BinaryFlag,\n\t\t}\n\tcase types.ETDuration:\n\t\tfieldType = &types.FieldType{\n\t\t\tTp:      mysql.TypeDuration,\n\t\t\tFlen:    mysql.MaxDurationWidthWithFsp,\n\t\t\tDecimal: int(types.MaxFsp),\n\t\t\tFlag:    mysql.BinaryFlag,\n\t\t}\n\t// TODO(yang.y): add more cases\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"generateCmpSigs: unsupported op type %v. Please contact yang.y for details\", retType))\n\t}\n\tbf = baseBuiltinFunc{\n\t\targs: args,\n\t\tctx:  ctx,\n\t\ttp:   fieldType,\n\t}\n\treturn bf\n}\n\n// funcs holds all registered builtin functions. When new function is added,\n// check expression/function_traits.go to see if it should be appended to\n// any set there.\nvar funcs = map[string]functionClass{\n\t// common functions\n\tast.IsNull: &isNullFunctionClass{baseFunctionClass{ast.IsNull, 1, 1}},\n\n\t// string functions\n\tast.Concat: &concatFunctionClass{baseFunctionClass{ast.Concat, 1, -1}},\n\n\t// control functions\n\tast.If:       &ifFunctionClass{baseFunctionClass{ast.If, 3, 3}},\n\tast.Ifnull:   &ifNullFunctionClass{baseFunctionClass{ast.Ifnull, 2, 2}},\n\tast.Greatest: &greatestFunctionClass{baseFunctionClass{ast.Greatest, 2, -1}},\n\tast.Least:    &leastFunctionClass{baseFunctionClass{ast.Least, 2, -1}},\n\n\tast.LogicAnd:   &logicAndFunctionClass{baseFunctionClass{ast.LogicAnd, 2, 2}},\n\tast.LogicOr:    &logicOrFunctionClass{baseFunctionClass{ast.LogicOr, 2, 2}},\n\tast.LogicXor:   &logicXorFunctionClass{baseFunctionClass{ast.LogicXor, 2, 2}},\n\tast.GE:         &compareFunctionClass{baseFunctionClass{ast.GE, 2, 2}, opcode.GE},\n\tast.LE:         &compareFunctionClass{baseFunctionClass{ast.LE, 2, 2}, opcode.LE},\n\tast.NE:         &compareFunctionClass{baseFunctionClass{ast.NE, 2, 2}, opcode.NE},\n\tast.EQ:         &compareFunctionClass{baseFunctionClass{ast.EQ, 2, 2}, opcode.EQ},\n\tast.LT:         &compareFunctionClass{baseFunctionClass{ast.LT, 2, 2}, opcode.LT},\n\tast.GT:         &compareFunctionClass{baseFunctionClass{ast.GT, 2, 2}, opcode.GT},\n\tast.UnaryNot:   &unaryNotFunctionClass{baseFunctionClass{ast.UnaryNot, 1, 1}},\n\tast.UnaryMinus: &unaryMinusFunctionClass{baseFunctionClass{ast.UnaryMinus, 1, 1}},\n\tast.Case:       &caseWhenFunctionClass{baseFunctionClass{ast.Case, 1, -1}},\n\tast.RowFunc:    &rowFunctionClass{baseFunctionClass{ast.RowFunc, 2, -1}},\n\tast.Like:       &likeFunctionClass{baseFunctionClass{ast.Like, 3, 3}},\n\tast.Regexp:     &regexpFunctionClass{baseFunctionClass{ast.Regexp, 2, 2}},\n\tast.Plus:       &arithmeticPlusFunctionClass{baseFunctionClass{ast.Plus, 2, 2}},\n\tast.Minus:      &arithmeticMinusFunctionClass{baseFunctionClass{ast.Minus, 2, 2}},\n\tast.Div:        &arithmeticDivideFunctionClass{baseFunctionClass{ast.Div, 2, 2}},\n\tast.Mul:        &arithmeticMultiplyFunctionClass{baseFunctionClass{ast.Mul, 2, 2}},\n\tast.IntDiv:     &arithmeticIntDivideFunctionClass{baseFunctionClass{ast.IntDiv, 2, 2}},\n\tast.Mod:        &arithmeticModFunctionClass{baseFunctionClass{ast.Mod, 2, 2}},\n\n\tast.In:        &inFunctionClass{baseFunctionClass{ast.In, 2, -1}},\n\tast.Substring: &substringFunctionClass{baseFunctionClass{ast.Substring, 2, 3}},\n\tast.Lower:     &lowerFunctionClass{baseFunctionClass{ast.Lower, 1, 1}},\n\tast.Upper:     &upperFunctionClass{baseFunctionClass{ast.Upper, 1, 1}},\n\tast.Coalesce:  &coalesceFunctionClass{baseFunctionClass{ast.Coalesce, 1, -1}},\n\tast.Length:    &lengthFunctionClass{baseFunctionClass{ast.Length, 1, 1}},\n\tast.Replace:   &replaceFunctionClass{baseFunctionClass{ast.Replace, 3, 3}},\n\tast.Trim:      &trimFunctionClass{baseFunctionClass{ast.Trim, 1, 1}},\n\n\t// math functions\n\tast.Abs:      &absFunctionClass{baseFunctionClass{ast.Abs, 1, 1}},\n\tast.Acos:     &acosFunctionClass{baseFunctionClass{ast.Acos, 1, 1}},\n\tast.Asin:     &asinFunctionClass{baseFunctionClass{ast.Asin, 1, 1}},\n\tast.Atan:     &atanFunctionClass{baseFunctionClass{ast.Atan, 1, 2}},\n\tast.Atan2:    &atanFunctionClass{baseFunctionClass{ast.Atan2, 2, 2}},\n\tast.Ceil:     &ceilFunctionClass{baseFunctionClass{ast.Ceil, 1, 1}},\n\tast.Ceiling:  &ceilFunctionClass{baseFunctionClass{ast.Ceiling, 1, 1}},\n\tast.Conv:     &convFunctionClass{baseFunctionClass{ast.Conv, 3, 3}},\n\tast.Cos:      &cosFunctionClass{baseFunctionClass{ast.Cos, 1, 1}},\n\tast.Cot:      &cotFunctionClass{baseFunctionClass{ast.Cot, 1, 1}},\n\tast.CRC32:    &crc32FunctionClass{baseFunctionClass{ast.CRC32, 1, 1}},\n\tast.Degrees:  &degreesFunctionClass{baseFunctionClass{ast.Degrees, 1, 1}},\n\tast.Exp:      &expFunctionClass{baseFunctionClass{ast.Exp, 1, 1}},\n\tast.Floor:    &floorFunctionClass{baseFunctionClass{ast.Floor, 1, 1}},\n\tast.Ln:       &logFunctionClass{baseFunctionClass{ast.Ln, 1, 1}},\n\tast.Log:      &logFunctionClass{baseFunctionClass{ast.Log, 1, 2}},\n\tast.Log2:     &log2FunctionClass{baseFunctionClass{ast.Log2, 1, 1}},\n\tast.Log10:    &log10FunctionClass{baseFunctionClass{ast.Log10, 1, 1}},\n\tast.PI:       &piFunctionClass{baseFunctionClass{ast.PI, 0, 0}},\n\tast.Pow:      &powFunctionClass{baseFunctionClass{ast.Pow, 2, 2}},\n\tast.Power:    &powFunctionClass{baseFunctionClass{ast.Power, 2, 2}},\n\tast.Radians:  &radiansFunctionClass{baseFunctionClass{ast.Radians, 1, 1}},\n\tast.Rand:     &randFunctionClass{baseFunctionClass{ast.Rand, 0, 1}},\n\tast.Round:    &roundFunctionClass{baseFunctionClass{ast.Round, 1, 2}},\n\tast.Sign:     &signFunctionClass{baseFunctionClass{ast.Sign, 1, 1}},\n\tast.Sin:      &sinFunctionClass{baseFunctionClass{ast.Sin, 1, 1}},\n\tast.Sqrt:     &sqrtFunctionClass{baseFunctionClass{ast.Sqrt, 1, 1}},\n\tast.Tan:      &tanFunctionClass{baseFunctionClass{ast.Tan, 1, 1}},\n\tast.Truncate: &truncateFunctionClass{baseFunctionClass{ast.Truncate, 2, 2}},\n\tast.Instr:    &instrFunctionClass{baseFunctionClass{ast.Instr, 2, 2}},\n\n\t// time\n\tast.DateDiff:    &dateDiffFunctionClass{baseFunctionClass{ast.DateDiff, 2, 2}},\n\tast.AddDate:     &addDateFunctionClass{baseFunctionClass{ast.AddDate, 3, 3}},\n\tast.DateAdd:     &addDateFunctionClass{baseFunctionClass{ast.DateAdd, 3, 3}},\n\tast.SubDate:     &subDateFunctionClass{baseFunctionClass{ast.SubDate, 3, 3}},\n\tast.DateSub:     &subDateFunctionClass{baseFunctionClass{ast.DateSub, 3, 3}},\n\tast.AddTime:     &addTimeFunctionClass{baseFunctionClass{ast.AddTime, 2, 2}},\n\tast.SubTime:     &subTimeFunctionClass{baseFunctionClass{ast.SubTime, 2, 2}},\n\tast.TimeDiff:    &timeDiffFunctionClass{baseFunctionClass{ast.TimeDiff, 2, 2}},\n\tast.DateFormat:  &dateFormatFunctionClass{baseFunctionClass{ast.DateFormat, 2, 2}},\n\tast.StrToDate:   &strToDateFunctionClass{baseFunctionClass{ast.StrToDate, 2, 2}},\n\tast.Curdate:     &currentDateFunctionClass{baseFunctionClass{ast.Curdate, 0, 0}},\n\tast.CurrentDate: &currentDateFunctionClass{baseFunctionClass{ast.CurrentDate, 0, 0}},\n\tast.Curtime:     &currentTimeFunctionClass{baseFunctionClass{ast.Curtime, 0, 1}},\n\tast.Now:         &nowFunctionClass{baseFunctionClass{ast.Now, 0, 1}},\n\tast.LastDay:     &lastDayFunctionClass{baseFunctionClass{ast.LastDay, 1, 1}},\n\n\t//built-in\n\tast.GeoDist: &builtinGeoDistFunctionClass{baseFunctionClass{ast.GeoDist, 4, 5}},\n}\n\n// baseBuiltinCastFunc will be contained in every struct that implement cast builtinFunc.\ntype baseBuiltinCastFunc struct {\n\tbaseBuiltinFunc\n\n\t// inUnion indicates whether cast is in union context.\n\tinUnion bool\n}\n\nfunc (b *baseBuiltinCastFunc) cloneFrom(from *baseBuiltinCastFunc) {\n\tb.baseBuiltinFunc.cloneFrom(&from.baseBuiltinFunc)\n\tb.inUnion = from.inUnion\n}\n\nfunc newBaseBuiltinCastFunc(builtinFunc baseBuiltinFunc, inUnion bool) baseBuiltinCastFunc {\n\treturn baseBuiltinCastFunc{\n\t\tbaseBuiltinFunc: builtinFunc,\n\t\tinUnion:         inUnion,\n\t}\n}\n\ntype builtinSubstring2ArgsSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinSubstring2ArgsSig) Clone() builtinFunc {\n\tnewSig := &builtinSubstring2ArgsSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals SUBSTR(str,pos), SUBSTR(str FROM pos), SUBSTR() is a synonym for SUBSTRING().\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_substr\nfunc (b *builtinSubstring2ArgsSig) evalString(row chunk.Row) (string, bool, error) {\n\tstr, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\tpos, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\tlength := int64(len(str))\n\tif pos < 0 {\n\t\tpos += length\n\t} else {\n\t\tpos--\n\t}\n\tif pos > length || pos < 0 {\n\t\tpos = length\n\t}\n\treturn str[pos:], false, nil\n}\n\ntype builtinSubstring2ArgsUTF8Sig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinSubstring2ArgsUTF8Sig) Clone() builtinFunc {\n\tnewSig := &builtinSubstring2ArgsUTF8Sig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals SUBSTR(str,pos), SUBSTR(str FROM pos), SUBSTR() is a synonym for SUBSTRING().\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_substr\nfunc (b *builtinSubstring2ArgsUTF8Sig) evalString(row chunk.Row) (string, bool, error) {\n\tstr, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\tpos, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\trunes := []rune(str)\n\tlength := int64(len(runes))\n\tif pos < 0 {\n\t\tpos += length\n\t} else {\n\t\tpos--\n\t}\n\tif pos > length || pos < 0 {\n\t\tpos = length\n\t}\n\treturn string(runes[pos:]), false, nil\n}\n\ntype builtinSubstring3ArgsSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinSubstring3ArgsSig) Clone() builtinFunc {\n\tnewSig := &builtinSubstring3ArgsSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals SUBSTR(str,pos,len), SUBSTR(str FROM pos FOR len), SUBSTR() is a synonym for SUBSTRING().\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_substr\nfunc (b *builtinSubstring3ArgsSig) evalString(row chunk.Row) (string, bool, error) {\n\tstr, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\tpos, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\tlength, isNull, err := b.args[2].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\tbyteLen := int64(len(str))\n\tif pos < 0 {\n\t\tpos += byteLen\n\t} else {\n\t\tpos--\n\t}\n\tif pos > byteLen || pos < 0 {\n\t\tpos = byteLen\n\t}\n\tend := pos + length\n\tif end < pos {\n\t\treturn \"\", false, nil\n\t} else if end < byteLen {\n\t\treturn str[pos:end], false, nil\n\t}\n\treturn str[pos:], false, nil\n}\n\ntype builtinSubstring3ArgsUTF8Sig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinSubstring3ArgsUTF8Sig) Clone() builtinFunc {\n\tnewSig := &builtinSubstring3ArgsUTF8Sig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals SUBSTR(str,pos,len), SUBSTR(str FROM pos FOR len), SUBSTR() is a synonym for SUBSTRING().\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_substr\nfunc (b *builtinSubstring3ArgsUTF8Sig) evalString(row chunk.Row) (string, bool, error) {\n\tstr, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\tpos, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\tlength, isNull, err := b.args[2].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\trunes := []rune(str)\n\tnumRunes := int64(len(runes))\n\tif pos < 0 {\n\t\tpos += numRunes\n\t} else {\n\t\tpos--\n\t}\n\tif pos > numRunes || pos < 0 {\n\t\tpos = numRunes\n\t}\n\tend := pos + length\n\tif end < pos {\n\t\treturn \"\", false, nil\n\t} else if end < numRunes {\n\t\treturn string(runes[pos:end]), false, nil\n\t}\n\treturn string(runes[pos:]), false, nil\n}\n"
  },
  {
    "path": "pkg/expression/builtin_arithmetic.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\n\t\"slices\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n\t\"github.com/secretflow/scql/pkg/util/mathutil\"\n)\n\nvar (\n\t_ functionClass = &arithmeticPlusFunctionClass{}\n\t_ functionClass = &arithmeticMinusFunctionClass{}\n\t_ functionClass = &arithmeticDivideFunctionClass{}\n\t_ functionClass = &arithmeticMultiplyFunctionClass{}\n\t_ functionClass = &arithmeticIntDivideFunctionClass{}\n\t_ functionClass = &arithmeticModFunctionClass{}\n)\n\nvar (\n\t_ builtinFunc = &builtinArithmeticPlusRealSig{}\n\t_ builtinFunc = &builtinArithmeticPlusDecimalSig{}\n\t_ builtinFunc = &builtinArithmeticPlusIntSig{}\n\t_ builtinFunc = &builtinArithmeticMinusRealSig{}\n\t_ builtinFunc = &builtinArithmeticMinusDecimalSig{}\n\t_ builtinFunc = &builtinArithmeticMinusIntSig{}\n\t_ builtinFunc = &builtinArithmeticDivideRealSig{}\n\t_ builtinFunc = &builtinArithmeticDivideDecimalSig{}\n\t_ builtinFunc = &builtinArithmeticMultiplyRealSig{}\n\t_ builtinFunc = &builtinArithmeticMultiplyDecimalSig{}\n\t_ builtinFunc = &builtinArithmeticMultiplyIntUnsignedSig{}\n\t_ builtinFunc = &builtinArithmeticMultiplyIntSig{}\n\t_ builtinFunc = &builtinArithmeticIntDivideIntSig{}\n\t_ builtinFunc = &builtinArithmeticModIntSig{}\n)\n\n// precIncrement indicates the number of digits by which to increase the scale of the result of division operations\n// performed with the / operator.\nconst precIncrement = 4\n\n// numericContextResultType returns types.EvalType for numeric function's parameters.\n// the returned types.EvalType should be one of: types.ETInt, types.ETDecimal, types.ETReal\nfunc numericContextResultType(ft *types.FieldType) types.EvalType {\n\tif types.IsTypeTemporal(ft.Tp) {\n\t\tif ft.Decimal > 0 {\n\t\t\treturn types.ETDecimal\n\t\t}\n\t\treturn types.ETInt\n\t}\n\tif types.IsBinaryStr(ft) {\n\t\treturn types.ETInt\n\t}\n\tevalTp4Ft := types.ETReal\n\tif !ft.Hybrid() {\n\t\tevalTp4Ft = ft.EvalType()\n\t\tif evalTp4Ft != types.ETDecimal && evalTp4Ft != types.ETInt {\n\t\t\tevalTp4Ft = types.ETReal\n\t\t}\n\t}\n\treturn evalTp4Ft\n}\n\n// setFlenDecimal4Int is called to set proper `Flen` and `Decimal` of return\n// type according to the two input parameter's types.\nfunc setFlenDecimal4Int(retTp, a, b *types.FieldType) {\n\tretTp.Decimal = 0\n\tretTp.Flen = mysql.MaxIntWidth\n}\n\n// setFlenDecimal4RealOrDecimal is called to set proper `Flen` and `Decimal` of return\n// type according to the two input parameter's types.\nfunc setFlenDecimal4RealOrDecimal(retTp, a, b *types.FieldType, isReal bool, isMultiply bool) {\n\tif a.Decimal != types.UnspecifiedLength && b.Decimal != types.UnspecifiedLength {\n\t\tretTp.Decimal = a.Decimal + b.Decimal\n\t\tif !isMultiply {\n\t\t\tretTp.Decimal = mathutil.Max(a.Decimal, b.Decimal)\n\t\t}\n\t\tif !isReal && retTp.Decimal > mysql.MaxDecimalScale {\n\t\t\tretTp.Decimal = mysql.MaxDecimalScale\n\t\t}\n\t\tif a.Flen == types.UnspecifiedLength || b.Flen == types.UnspecifiedLength {\n\t\t\tretTp.Flen = types.UnspecifiedLength\n\t\t\treturn\n\t\t}\n\t\tdigitsInt := mathutil.Max(a.Flen-a.Decimal, b.Flen-b.Decimal)\n\t\tif isMultiply {\n\t\t\tdigitsInt = a.Flen - a.Decimal + b.Flen - b.Decimal\n\t\t}\n\t\tretTp.Flen = digitsInt + retTp.Decimal + 3\n\t\tif isReal {\n\t\t\tretTp.Flen = mathutil.Min(retTp.Flen, mysql.MaxRealWidth)\n\t\t\treturn\n\t\t}\n\t\tretTp.Flen = mathutil.Min(retTp.Flen, mysql.MaxDecimalWidth)\n\t\treturn\n\t}\n\tif isReal {\n\t\tretTp.Flen, retTp.Decimal = types.UnspecifiedLength, types.UnspecifiedLength\n\t} else {\n\t\tretTp.Flen, retTp.Decimal = mysql.MaxDecimalWidth, mysql.MaxDecimalScale\n\t}\n}\n\nfunc (c *arithmeticDivideFunctionClass) setType4DivDecimal(retTp, a, b *types.FieldType) {\n\tvar deca, decb = a.Decimal, b.Decimal\n\tif deca == int(types.UnspecifiedFsp) {\n\t\tdeca = 0\n\t}\n\tif decb == int(types.UnspecifiedFsp) {\n\t\tdecb = 0\n\t}\n\tretTp.Decimal = deca + precIncrement\n\tif retTp.Decimal > mysql.MaxDecimalScale {\n\t\tretTp.Decimal = mysql.MaxDecimalScale\n\t}\n\tif a.Flen == types.UnspecifiedLength {\n\t\tretTp.Flen = mysql.MaxDecimalWidth\n\t\treturn\n\t}\n\tretTp.Flen = a.Flen + decb + precIncrement\n\tif retTp.Flen > mysql.MaxDecimalWidth {\n\t\tretTp.Flen = mysql.MaxDecimalWidth\n\t}\n}\n\nfunc (c *arithmeticDivideFunctionClass) setType4DivReal(retTp *types.FieldType) {\n\tretTp.Decimal = types.UnspecifiedLength\n\tretTp.Flen = mysql.MaxRealWidth\n}\n\ntype arithmeticPlusFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *arithmeticPlusFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tlhsTp, rhsTp := args[0].GetType(), args[1].GetType()\n\tlhsEvalTp, rhsEvalTp := numericContextResultType(lhsTp), numericContextResultType(rhsTp)\n\tif lhsEvalTp == types.ETReal || rhsEvalTp == types.ETReal {\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal, types.ETReal)\n\t\tsetFlenDecimal4RealOrDecimal(bf.tp, args[0].GetType(), args[1].GetType(), true, false)\n\t\tsig := &builtinArithmeticPlusRealSig{bf}\n\t\treturn sig, nil\n\t} else if lhsEvalTp == types.ETDecimal || rhsEvalTp == types.ETDecimal {\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDecimal, types.ETDecimal, types.ETDecimal)\n\t\tsetFlenDecimal4RealOrDecimal(bf.tp, args[0].GetType(), args[1].GetType(), false, false)\n\t\tsig := &builtinArithmeticPlusDecimalSig{bf}\n\t\treturn sig, nil\n\t} else {\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, types.ETInt)\n\t\tif mysql.HasUnsignedFlag(args[0].GetType().Flag) || mysql.HasUnsignedFlag(args[1].GetType().Flag) {\n\t\t\tbf.tp.Flag |= mysql.UnsignedFlag\n\t\t}\n\t\tsetFlenDecimal4Int(bf.tp, args[0].GetType(), args[1].GetType())\n\t\tsig := &builtinArithmeticPlusIntSig{bf}\n\t\treturn sig, nil\n\t}\n}\n\ntype builtinArithmeticPlusIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (s *builtinArithmeticPlusIntSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticPlusIntSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinArithmeticPlusDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (s *builtinArithmeticPlusDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticPlusDecimalSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinArithmeticPlusRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (s *builtinArithmeticPlusRealSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticPlusRealSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype arithmeticMinusFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *arithmeticMinusFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tlhsTp, rhsTp := args[0].GetType(), args[1].GetType()\n\tlhsEvalTp, rhsEvalTp := numericContextResultType(lhsTp), numericContextResultType(rhsTp)\n\tif lhsEvalTp == types.ETReal || rhsEvalTp == types.ETReal {\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal, types.ETReal)\n\t\tsetFlenDecimal4RealOrDecimal(bf.tp, args[0].GetType(), args[1].GetType(), true, false)\n\t\tsig := &builtinArithmeticMinusRealSig{bf}\n\t\treturn sig, nil\n\t} else if lhsEvalTp == types.ETDecimal || rhsEvalTp == types.ETDecimal {\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDecimal, types.ETDecimal, types.ETDecimal)\n\t\tsetFlenDecimal4RealOrDecimal(bf.tp, args[0].GetType(), args[1].GetType(), false, false)\n\t\tsig := &builtinArithmeticMinusDecimalSig{bf}\n\t\treturn sig, nil\n\t} else {\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, types.ETInt)\n\t\tsetFlenDecimal4Int(bf.tp, args[0].GetType(), args[1].GetType())\n\t\tif mysql.HasUnsignedFlag(args[0].GetType().Flag) || mysql.HasUnsignedFlag(args[1].GetType().Flag) {\n\t\t\tbf.tp.Flag |= mysql.UnsignedFlag\n\t\t}\n\t\tsig := &builtinArithmeticMinusIntSig{baseBuiltinFunc: bf}\n\t\treturn sig, nil\n\t}\n}\n\ntype builtinArithmeticMinusIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (s *builtinArithmeticMinusIntSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticMinusIntSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinArithmeticMinusDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (s *builtinArithmeticMinusDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticMinusDecimalSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinArithmeticMinusRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (s *builtinArithmeticMinusRealSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticMinusRealSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype arithmeticIntDivideFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *arithmeticIntDivideFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlhsTp, rhsTp := args[0].GetType(), args[1].GetType()\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, types.ETInt)\n\tif mysql.HasUnsignedFlag(lhsTp.Flag) || mysql.HasUnsignedFlag(rhsTp.Flag) {\n\t\tbf.tp.Flag |= mysql.UnsignedFlag\n\t}\n\tsig := &builtinArithmeticIntDivideIntSig{bf}\n\treturn sig, nil\n}\n\ntype builtinArithmeticIntDivideIntSig struct{ baseBuiltinFunc }\n\nfunc (s *builtinArithmeticIntDivideIntSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticIntDivideIntSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype arithmeticModFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *arithmeticModFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tlhsTp, rhsTp := args[0].GetType(), args[1].GetType()\n\tblockTypes := []byte{mysql.TypeFloat, mysql.TypeDouble, mysql.TypeNewDecimal}\n\tif slices.Contains(blockTypes, rhsTp.Tp) || slices.Contains(blockTypes, lhsTp.Tp) {\n\t\treturn nil, fmt.Errorf(\"getFunction: not support mod float\")\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, types.ETInt)\n\tif mysql.HasUnsignedFlag(lhsTp.Flag) {\n\t\tbf.tp.Flag |= mysql.UnsignedFlag\n\t}\n\tsig := &builtinArithmeticModIntSig{bf}\n\treturn sig, nil\n}\n\ntype builtinArithmeticModIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (s *builtinArithmeticModIntSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticModIntSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype arithmeticMultiplyFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *arithmeticMultiplyFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tlhsTp, rhsTp := args[0].GetType(), args[1].GetType()\n\tlhsEvalTp, rhsEvalTp := numericContextResultType(lhsTp), numericContextResultType(rhsTp)\n\tif lhsEvalTp == types.ETReal || rhsEvalTp == types.ETReal {\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal, types.ETReal)\n\t\tsetFlenDecimal4RealOrDecimal(bf.tp, args[0].GetType(), args[1].GetType(), true, true)\n\t\tsig := &builtinArithmeticMultiplyRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_MultiplyReal)\n\t\treturn sig, nil\n\t} else if lhsEvalTp == types.ETDecimal || rhsEvalTp == types.ETDecimal {\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDecimal, types.ETDecimal, types.ETDecimal)\n\t\tsetFlenDecimal4RealOrDecimal(bf.tp, args[0].GetType(), args[1].GetType(), false, true)\n\t\tsig := &builtinArithmeticMultiplyDecimalSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_MultiplyDecimal)\n\t\treturn sig, nil\n\t} else {\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, types.ETInt)\n\t\tif mysql.HasUnsignedFlag(lhsTp.Flag) || mysql.HasUnsignedFlag(rhsTp.Flag) {\n\t\t\tbf.tp.Flag |= mysql.UnsignedFlag\n\t\t\tsetFlenDecimal4Int(bf.tp, args[0].GetType(), args[1].GetType())\n\t\t\tsig := &builtinArithmeticMultiplyIntUnsignedSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_MultiplyIntUnsigned)\n\t\t\treturn sig, nil\n\t\t}\n\t\tsetFlenDecimal4Int(bf.tp, args[0].GetType(), args[1].GetType())\n\t\tsig := &builtinArithmeticMultiplyIntSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_MultiplyInt)\n\t\treturn sig, nil\n\t}\n}\n\ntype builtinArithmeticMultiplyRealSig struct{ baseBuiltinFunc }\n\nfunc (s *builtinArithmeticMultiplyRealSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticMultiplyRealSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinArithmeticMultiplyDecimalSig struct{ baseBuiltinFunc }\n\nfunc (s *builtinArithmeticMultiplyDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticMultiplyDecimalSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinArithmeticMultiplyIntUnsignedSig struct{ baseBuiltinFunc }\n\nfunc (s *builtinArithmeticMultiplyIntUnsignedSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticMultiplyIntUnsignedSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinArithmeticMultiplyIntSig struct{ baseBuiltinFunc }\n\nfunc (s *builtinArithmeticMultiplyIntSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticMultiplyIntSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (s *builtinArithmeticMultiplyRealSig) evalReal(row chunk.Row) (float64, bool, error) {\n\ta, isNull, err := s.args[0].EvalReal(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tb, isNull, err := s.args[1].EvalReal(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tresult := a * b\n\tif math.IsInf(result, 0) {\n\t\treturn 0, true, types.ErrOverflow.GenWithStackByArgs(\"DOUBLE\", fmt.Sprintf(\"(%s * %s)\", s.args[0].String(), s.args[1].String()))\n\t}\n\treturn result, false, nil\n}\n\nfunc (s *builtinArithmeticMultiplyDecimalSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\ta, isNull, err := s.args[0].EvalDecimal(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\tb, isNull, err := s.args[1].EvalDecimal(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\tc := &types.MyDecimal{}\n\terr = types.DecimalMul(a, b, c)\n\tif err != nil && !terror.ErrorEqual(err, types.ErrTruncated) {\n\t\treturn nil, true, err\n\t}\n\treturn c, false, nil\n}\n\nfunc (s *builtinArithmeticMultiplyIntUnsignedSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\ta, isNull, err := s.args[0].EvalInt(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tunsignedA := uint64(a)\n\tb, isNull, err := s.args[1].EvalInt(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tunsignedB := uint64(b)\n\tresult := unsignedA * unsignedB\n\tif unsignedA != 0 && result/unsignedA != unsignedB {\n\t\treturn 0, true, types.ErrOverflow.GenWithStackByArgs(\"BIGINT UNSIGNED\", fmt.Sprintf(\"(%s * %s)\", s.args[0].String(), s.args[1].String()))\n\t}\n\treturn int64(result), false, nil\n}\n\nfunc (s *builtinArithmeticMultiplyIntSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\ta, isNull, err := s.args[0].EvalInt(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tb, isNull, err := s.args[1].EvalInt(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tresult := a * b\n\tif a != 0 && result/a != b {\n\t\treturn 0, true, types.ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"(%s * %s)\", s.args[0].String(), s.args[1].String()))\n\t}\n\treturn result, false, nil\n}\n\ntype arithmeticDivideFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *arithmeticDivideFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tlhsTp, rhsTp := args[0].GetType(), args[1].GetType()\n\tlhsEvalTp, rhsEvalTp := numericContextResultType(lhsTp), numericContextResultType(rhsTp)\n\tif lhsEvalTp == types.ETReal || rhsEvalTp == types.ETReal {\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal, types.ETReal)\n\t\tc.setType4DivReal(bf.tp)\n\t\tsig := &builtinArithmeticDivideRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_DivideReal)\n\t\treturn sig, nil\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDecimal, types.ETDecimal, types.ETDecimal)\n\tc.setType4DivDecimal(bf.tp, lhsTp, rhsTp)\n\tsig := &builtinArithmeticDivideDecimalSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_DivideDecimal)\n\treturn sig, nil\n}\n\ntype builtinArithmeticDivideRealSig struct{ baseBuiltinFunc }\n\nfunc (s *builtinArithmeticDivideRealSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticDivideRealSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinArithmeticDivideDecimalSig struct{ baseBuiltinFunc }\n\nfunc (s *builtinArithmeticDivideDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinArithmeticDivideDecimalSig{}\n\tnewSig.cloneFrom(&s.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (s *builtinArithmeticDivideRealSig) evalReal(row chunk.Row) (float64, bool, error) {\n\ta, isNull, err := s.args[0].EvalReal(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tb, isNull, err := s.args[1].EvalReal(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif b == 0 {\n\t\treturn 0, true, handleDivisionByZeroError(s.ctx)\n\t}\n\tresult := a / b\n\tif math.IsInf(result, 0) {\n\t\treturn 0, true, types.ErrOverflow.GenWithStackByArgs(\"DOUBLE\", fmt.Sprintf(\"(%s / %s)\", s.args[0].String(), s.args[1].String()))\n\t}\n\treturn result, false, nil\n}\n\nfunc (s *builtinArithmeticDivideDecimalSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\ta, isNull, err := s.args[0].EvalDecimal(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\n\tb, isNull, err := s.args[1].EvalDecimal(s.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\n\tc := &types.MyDecimal{}\n\terr = types.DecimalDiv(a, b, c, types.DivFracIncr)\n\tif err == types.ErrDivByZero {\n\t\treturn c, true, handleDivisionByZeroError(s.ctx)\n\t} else if err == nil {\n\t\t_, frac := c.PrecisionAndFrac()\n\t\tif frac < s.baseBuiltinFunc.tp.Decimal {\n\t\t\terr = c.Round(c, s.baseBuiltinFunc.tp.Decimal, types.ModeHalfEven)\n\t\t}\n\t}\n\treturn c, false, err\n}\n"
  },
  {
    "path": "pkg/expression/builtin_cast.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// We implement 6 CastAsXXFunctionClass for `cast` built-in functions.\n// XX means the return type of the `cast` built-in functions.\n// XX contains the following 6 types:\n// Int, Decimal, Real, String.\n\n// We implement 6 CastYYAsXXSig built-in function signatures for every CastAsXXFunctionClass.\n// builtinCastXXAsYYSig takes a argument of type XX and returns a value of type YY.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n)\n\nvar (\n\t_ functionClass = &castAsIntFunctionClass{}\n\t_ functionClass = &castAsRealFunctionClass{}\n\t_ functionClass = &castAsStringFunctionClass{}\n\t_ functionClass = &castAsDecimalFunctionClass{}\n\t_ functionClass = &castAsTimeFunctionClass{}\n)\n\nvar (\n\t_ builtinFunc = &builtinCastIntAsIntSig{}\n\t_ builtinFunc = &builtinCastIntAsRealSig{}\n\t_ builtinFunc = &builtinCastIntAsStringSig{}\n\t_ builtinFunc = &builtinCastIntAsDecimalSig{}\n\t_ builtinFunc = &builtinCastIntAsTimeSig{}\n\n\t_ builtinFunc = &builtinCastRealAsIntSig{}\n\t_ builtinFunc = &builtinCastRealAsRealSig{}\n\t_ builtinFunc = &builtinCastRealAsStringSig{}\n\t_ builtinFunc = &builtinCastRealAsDecimalSig{}\n\t_ builtinFunc = &builtinCastRealAsTimeSig{}\n\n\t_ builtinFunc = &builtinCastDecimalAsIntSig{}\n\t_ builtinFunc = &builtinCastDecimalAsRealSig{}\n\t_ builtinFunc = &builtinCastDecimalAsStringSig{}\n\t_ builtinFunc = &builtinCastDecimalAsDecimalSig{}\n\t_ builtinFunc = &builtinCastDecimalAsTimeSig{}\n\n\t_ builtinFunc = &builtinCastStringAsIntSig{}\n\t_ builtinFunc = &builtinCastStringAsRealSig{}\n\t_ builtinFunc = &builtinCastStringAsStringSig{}\n\t_ builtinFunc = &builtinCastStringAsDecimalSig{}\n\t_ builtinFunc = &builtinCastStringAsTimeSig{}\n\n\t_ builtinFunc = &builtinCastTimeAsIntSig{}\n\t_ builtinFunc = &builtinCastTimeAsRealSig{}\n\t_ builtinFunc = &builtinCastTimeAsStringSig{}\n\t_ builtinFunc = &builtinCastTimeAsDecimalSig{}\n\t_ builtinFunc = &builtinCastTimeAsTimeSig{}\n)\n\ntype castAsIntFunctionClass struct {\n\tbaseFunctionClass\n\n\ttp *types.FieldType\n}\n\nfunc (c *castAsIntFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinCastFunc(newBaseBuiltinFunc(ctx, args), ctx.Value(inUnionCastContext) != nil)\n\tbf.tp = c.tp\n\tif args[0].GetType().Hybrid() || IsBinaryLiteral(args[0]) {\n\t\tsig = &builtinCastIntAsIntSig{bf}\n\t\treturn sig, nil\n\t}\n\targTp := args[0].GetType().EvalType()\n\tswitch argTp {\n\tcase types.ETInt:\n\t\tsig = &builtinCastIntAsIntSig{bf}\n\tcase types.ETReal:\n\t\tsig = &builtinCastRealAsIntSig{bf}\n\tcase types.ETDecimal:\n\t\tsig = &builtinCastDecimalAsIntSig{bf}\n\tcase types.ETString:\n\t\tsig = &builtinCastStringAsIntSig{bf}\n\tdefault:\n\t\tpanic(\"unsupported types.EvalType in castAsIntFunctionClass\")\n\t}\n\treturn sig, nil\n}\n\ntype castAsRealFunctionClass struct {\n\tbaseFunctionClass\n\n\ttp *types.FieldType\n}\n\nfunc (c *castAsRealFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinCastFunc(newBaseBuiltinFunc(ctx, args), ctx.Value(inUnionCastContext) != nil)\n\tbf.tp = c.tp\n\tif IsBinaryLiteral(args[0]) {\n\t\tsig = &builtinCastRealAsRealSig{bf}\n\t\treturn sig, nil\n\t}\n\tvar argTp types.EvalType\n\tif args[0].GetType().Hybrid() {\n\t\targTp = types.ETInt\n\t} else {\n\t\targTp = args[0].GetType().EvalType()\n\t}\n\tswitch argTp {\n\tcase types.ETInt:\n\t\tsig = &builtinCastIntAsRealSig{bf}\n\tcase types.ETReal:\n\t\tsig = &builtinCastRealAsRealSig{bf}\n\tcase types.ETDecimal:\n\t\tsig = &builtinCastDecimalAsRealSig{bf}\n\tcase types.ETString:\n\t\tsig = &builtinCastStringAsRealSig{bf}\n\tdefault:\n\t\tpanic(\"unsupported types.EvalType in castAsRealFunctionClass\")\n\t}\n\treturn sig, nil\n}\n\ntype castAsDecimalFunctionClass struct {\n\tbaseFunctionClass\n\n\ttp *types.FieldType\n}\n\nfunc (c *castAsDecimalFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinCastFunc(newBaseBuiltinFunc(ctx, args), ctx.Value(inUnionCastContext) != nil)\n\tbf.tp = c.tp\n\tif IsBinaryLiteral(args[0]) {\n\t\tsig = &builtinCastDecimalAsDecimalSig{bf}\n\t\treturn sig, nil\n\t}\n\tvar argTp types.EvalType\n\tif args[0].GetType().Hybrid() {\n\t\targTp = types.ETInt\n\t} else {\n\t\targTp = args[0].GetType().EvalType()\n\t}\n\tswitch argTp {\n\tcase types.ETInt:\n\t\tsig = &builtinCastIntAsDecimalSig{bf}\n\tcase types.ETReal:\n\t\tsig = &builtinCastRealAsDecimalSig{bf}\n\tcase types.ETDecimal:\n\t\tsig = &builtinCastDecimalAsDecimalSig{bf}\n\tcase types.ETString:\n\t\tsig = &builtinCastStringAsDecimalSig{bf}\n\tdefault:\n\t\tpanic(\"unsupported types.EvalType in castAsDecimalFunctionClass\")\n\t}\n\treturn sig, nil\n}\n\ntype castAsStringFunctionClass struct {\n\tbaseFunctionClass\n\n\ttp *types.FieldType\n}\n\nfunc (c *castAsStringFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFunc(ctx, args)\n\tbf.tp = c.tp\n\tif args[0].GetType().Hybrid() || IsBinaryLiteral(args[0]) {\n\t\tsig = &builtinCastStringAsStringSig{bf}\n\t\treturn sig, nil\n\t}\n\targTp := args[0].GetType().EvalType()\n\tswitch argTp {\n\tcase types.ETInt:\n\t\tsig = &builtinCastIntAsStringSig{bf}\n\tcase types.ETReal:\n\t\tsig = &builtinCastRealAsStringSig{bf}\n\tcase types.ETDecimal:\n\t\tsig = &builtinCastDecimalAsStringSig{bf}\n\tcase types.ETString:\n\t\tsig = &builtinCastStringAsStringSig{bf}\n\tdefault:\n\t\tpanic(\"unsupported types.EvalType in castAsStringFunctionClass\")\n\t}\n\treturn sig, nil\n}\n\ntype builtinCastIntAsIntSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastIntAsIntSig) Clone() builtinFunc {\n\tnewSig := &builtinCastIntAsIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastIntAsRealSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastIntAsRealSig) Clone() builtinFunc {\n\tnewSig := &builtinCastIntAsRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastIntAsDecimalSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastIntAsDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinCastIntAsDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastIntAsStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCastIntAsStringSig) Clone() builtinFunc {\n\tnewSig := &builtinCastIntAsStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinCastRealAsRealSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastRealAsRealSig) Clone() builtinFunc {\n\tnewSig := &builtinCastRealAsRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastRealAsIntSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastRealAsIntSig) Clone() builtinFunc {\n\tnewSig := &builtinCastRealAsIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastRealAsDecimalSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastRealAsDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinCastRealAsDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastRealAsStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCastRealAsStringSig) Clone() builtinFunc {\n\tnewSig := &builtinCastRealAsStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinCastDecimalAsDecimalSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastDecimalAsDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinCastDecimalAsDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastDecimalAsIntSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastDecimalAsIntSig) Clone() builtinFunc {\n\tnewSig := &builtinCastDecimalAsIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastDecimalAsStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCastDecimalAsStringSig) Clone() builtinFunc {\n\tnewSig := &builtinCastDecimalAsStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinCastDecimalAsRealSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastDecimalAsRealSig) Clone() builtinFunc {\n\tnewSig := &builtinCastDecimalAsRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastStringAsStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCastStringAsStringSig) Clone() builtinFunc {\n\tnewSig := &builtinCastStringAsStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinCastStringAsIntSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastStringAsIntSig) Clone() builtinFunc {\n\tnewSig := &builtinCastStringAsIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastStringAsRealSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastStringAsRealSig) Clone() builtinFunc {\n\tnewSig := &builtinCastStringAsRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\ntype builtinCastStringAsDecimalSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastStringAsDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinCastStringAsDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\n// inCastContext is session key type that indicates whether executing\n// in special cast context that negative unsigned num will be zero.\ntype inCastContext int\n\nfunc (i inCastContext) String() string {\n\treturn \"__cast_ctx\"\n}\n\n// inUnionCastContext is session key value that indicates whether executing in\n// union cast context.\n// @see BuildCastFunction4Union\nconst inUnionCastContext inCastContext = 0\n\n// hasSpecialCast checks if this expr has its own special cast function.\n// for example(#9713): when doing arithmetic using results of function DayName,\n// \"Monday\" should be regarded as 0, \"Tuesday\" should be regarded as 1 and so on.\nfunc hasSpecialCast(ctx sessionctx.Context, expr Expression, tp *types.FieldType) bool {\n\tswitch f := expr.(type) {\n\tcase *ScalarFunction:\n\t\tswitch f.FuncName.L {\n\t\tcase ast.DayName:\n\t\t\tswitch tp.EvalType() {\n\t\t\tcase types.ETInt, types.ETReal:\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// BuildCastFunction4Union build a implicitly CAST ScalarFunction from the Union\n// Expression.\nfunc BuildCastFunction4Union(ctx sessionctx.Context, expr Expression, tp *types.FieldType) (res Expression) {\n\tctx.SetValue(inUnionCastContext, struct{}{})\n\tdefer func() {\n\t\tctx.SetValue(inUnionCastContext, nil)\n\t}()\n\treturn BuildCastFunction(ctx, expr, tp)\n}\n\n// BuildCastFunction builds a CAST ScalarFunction from the Expression.\nfunc BuildCastFunction(ctx sessionctx.Context, expr Expression, tp *types.FieldType) (res Expression) {\n\tif hasSpecialCast(ctx, expr, tp) {\n\t\treturn expr\n\t}\n\n\tvar fc functionClass\n\tswitch tp.EvalType() {\n\tcase types.ETInt:\n\t\tfc = &castAsIntFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp}\n\tcase types.ETDecimal:\n\t\tfc = &castAsDecimalFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp}\n\tcase types.ETReal:\n\t\tfc = &castAsRealFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp}\n\tcase types.ETString:\n\t\tfc = &castAsStringFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp}\n\tcase types.ETDatetime, types.ETTimestamp:\n\t\tfc = &castAsTimeFunctionClass{baseFunctionClass{ast.Cast, 1, 1}, tp}\n\tdefault:\n\t\tterror.Log(fmt.Errorf(\"unsupported data type in cast: %+v\", tp.EvalType()))\n\t\treturn\n\t}\n\tf, err := fc.getFunction(ctx, []Expression{expr})\n\tterror.Log(err)\n\tres = &ScalarFunction{\n\t\tFuncName: model.NewCIStr(ast.Cast),\n\t\tRetType:  tp,\n\t\tFunction: f,\n\t}\n\treturn res\n}\n\n// WrapWithCastAsInt wraps `expr` with `cast` if the return type of expr is not\n// type int, otherwise, returns `expr` directly.\nfunc WrapWithCastAsInt(ctx sessionctx.Context, expr Expression) Expression {\n\tif expr.GetType().EvalType() == types.ETInt {\n\t\treturn expr\n\t}\n\ttp := types.NewFieldType(mysql.TypeLonglong)\n\ttp.Flen, tp.Decimal = expr.GetType().Flen, 0\n\ttypes.SetBinChsClnFlag(tp)\n\ttp.Flag |= expr.GetType().Flag & mysql.UnsignedFlag\n\treturn BuildCastFunction(ctx, expr, tp)\n}\n\n// WrapWithCastAsReal wraps `expr` with `cast` if the return type of expr is not\n// type real, otherwise, returns `expr` directly.\nfunc WrapWithCastAsReal(ctx sessionctx.Context, expr Expression) Expression {\n\tif expr.GetType().EvalType() == types.ETReal {\n\t\treturn expr\n\t}\n\ttp := types.NewFieldType(mysql.TypeDouble)\n\ttp.Flen, tp.Decimal = mysql.MaxRealWidth, types.UnspecifiedLength\n\ttypes.SetBinChsClnFlag(tp)\n\ttp.Flag |= expr.GetType().Flag & mysql.UnsignedFlag\n\treturn BuildCastFunction(ctx, expr, tp)\n}\n\n// WrapWithCastAsDecimal wraps `expr` with `cast` if the return type of expr is\n// not type decimal, otherwise, returns `expr` directly.\nfunc WrapWithCastAsDecimal(ctx sessionctx.Context, expr Expression) Expression {\n\tif expr.GetType().EvalType() == types.ETDecimal {\n\t\treturn expr\n\t}\n\ttp := types.NewFieldType(mysql.TypeNewDecimal)\n\ttp.Flen, tp.Decimal = expr.GetType().Flen, expr.GetType().Decimal\n\tif expr.GetType().EvalType() == types.ETInt {\n\t\ttp.Flen = mysql.MaxIntWidth\n\t}\n\ttypes.SetBinChsClnFlag(tp)\n\ttp.Flag |= expr.GetType().Flag & mysql.UnsignedFlag\n\treturn BuildCastFunction(ctx, expr, tp)\n}\n\n// WrapWithCastAsTime wraps `expr` with `cast` if the return type of expr is not\n// same as type of the specified `tp` , otherwise, returns `expr` directly.\nfunc WrapWithCastAsTime(ctx sessionctx.Context, expr Expression, tp *types.FieldType) Expression {\n\texprTp := expr.GetType().Tp\n\tif tp.Tp == exprTp {\n\t\treturn expr\n\t} else if (exprTp == mysql.TypeDate || exprTp == mysql.TypeTimestamp) && tp.Tp == mysql.TypeDatetime {\n\t\treturn expr\n\t}\n\tswitch x := expr.GetType(); x.Tp {\n\tcase mysql.TypeDatetime, mysql.TypeTimestamp, mysql.TypeDate, mysql.TypeDuration:\n\t\ttp.Decimal = x.Decimal\n\tdefault:\n\t\ttp.Decimal = int(types.MaxFsp)\n\t}\n\tswitch tp.Tp {\n\tcase mysql.TypeDate:\n\t\ttp.Flen = mysql.MaxDateWidth\n\tcase mysql.TypeDatetime, mysql.TypeTimestamp:\n\t\ttp.Flen = mysql.MaxDatetimeWidthNoFsp\n\t\tif tp.Decimal > 0 {\n\t\t\ttp.Flen = tp.Flen + 1 + tp.Decimal\n\t\t}\n\t}\n\ttypes.SetBinChsClnFlag(tp)\n\treturn BuildCastFunction(ctx, expr, tp)\n}\n\n// WrapWithCastAsString wraps `expr` with `cast` if the return type of expr is\n// not type string, otherwise, returns `expr` directly.\nfunc WrapWithCastAsString(ctx sessionctx.Context, expr Expression) Expression {\n\texprTp := expr.GetType()\n\tif exprTp.EvalType() == types.ETString {\n\t\treturn expr\n\t}\n\targLen := exprTp.Flen\n\t// If expr is decimal, we should take the decimal point and negative sign\n\t// into consideration, so we set `expr.GetType().Flen + 2` as the `argLen`.\n\t// Since the length of float and double is not accurate, we do not handle\n\t// them.\n\tif exprTp.Tp == mysql.TypeNewDecimal && argLen != int(types.UnspecifiedFsp) {\n\t\targLen += 2\n\t}\n\tif exprTp.EvalType() == types.ETInt {\n\t\targLen = mysql.MaxIntWidth\n\t}\n\ttp := types.NewFieldType(mysql.TypeVarString)\n\ttp.Charset, tp.Collate = charset.GetDefaultCharsetAndCollate()\n\ttp.Flen, tp.Decimal = argLen, types.UnspecifiedLength\n\treturn BuildCastFunction(ctx, expr, tp)\n}\n\n// WrapWithCastAsDuration wraps `expr` with `cast` if the return type of expr is\n// not type duration, otherwise, returns `expr` directly.\nfunc WrapWithCastAsDuration(ctx sessionctx.Context, expr Expression) Expression {\n\tif expr.GetType().Tp == mysql.TypeDuration {\n\t\treturn expr\n\t}\n\ttp := types.NewFieldType(mysql.TypeDuration)\n\tswitch x := expr.GetType(); x.Tp {\n\tcase mysql.TypeDatetime, mysql.TypeTimestamp, mysql.TypeDate:\n\t\ttp.Decimal = x.Decimal\n\tdefault:\n\t\ttp.Decimal = int(types.MaxFsp)\n\t}\n\ttp.Flen = mysql.MaxDurationWidthNoFsp\n\tif tp.Decimal > 0 {\n\t\ttp.Flen = tp.Flen + 1 + tp.Decimal\n\t}\n\treturn BuildCastFunction(ctx, expr, tp)\n}\n\n// WrapWithCastAsJSON wraps `expr` with `cast` if the return type of expr is not\n// type json, otherwise, returns `expr` directly.\nfunc WrapWithCastAsJSON(ctx sessionctx.Context, expr Expression) Expression {\n\tif expr.GetType().Tp == mysql.TypeJSON && !mysql.HasParseToJSONFlag(expr.GetType().Flag) {\n\t\treturn expr\n\t}\n\ttp := &types.FieldType{\n\t\tTp:      mysql.TypeJSON,\n\t\tFlen:    12582912, // FIXME: Here the Flen is not trusted.\n\t\tDecimal: 0,\n\t\tCharset: mysql.DefaultCharset,\n\t\tCollate: mysql.DefaultCollationName,\n\t\tFlag:    mysql.BinaryFlag,\n\t}\n\treturn BuildCastFunction(ctx, expr, tp)\n}\n\ntype castAsTimeFunctionClass struct {\n\tbaseFunctionClass\n\n\ttp *types.FieldType\n}\n\nfunc (c *castAsTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFunc(ctx, args)\n\tbf.tp = c.tp\n\targTp := args[0].GetType().EvalType()\n\tswitch argTp {\n\tcase types.ETInt:\n\t\tsig = &builtinCastIntAsTimeSig{bf}\n\tcase types.ETReal:\n\t\tsig = &builtinCastRealAsTimeSig{bf}\n\tcase types.ETDecimal:\n\t\tsig = &builtinCastDecimalAsTimeSig{bf}\n\tcase types.ETDatetime, types.ETTimestamp:\n\t\tsig = &builtinCastTimeAsTimeSig{bf}\n\tcase types.ETString:\n\t\tsig = &builtinCastStringAsTimeSig{bf}\n\tdefault:\n\t\tpanic(\"unsupported types.EvalType in castAsTimeFunctionClass\")\n\t}\n\treturn sig, nil\n}\n\ntype builtinCastIntAsTimeSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCastIntAsTimeSig) Clone() builtinFunc {\n\tnewSig := &builtinCastIntAsTimeSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCastIntAsTimeSig) evalTime(row chunk.Row) (res types.Time, isNull bool, err error) {\n\treturn res, false, nil\n}\n\ntype builtinCastRealAsTimeSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCastRealAsTimeSig) Clone() builtinFunc {\n\tnewSig := &builtinCastRealAsTimeSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCastRealAsTimeSig) evalTime(row chunk.Row) (types.Time, bool, error) {\n\treturn types.Time{}, false, nil\n}\n\ntype builtinCastDecimalAsTimeSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCastDecimalAsTimeSig) Clone() builtinFunc {\n\tnewSig := &builtinCastDecimalAsTimeSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCastDecimalAsTimeSig) evalTime(row chunk.Row) (res types.Time, isNull bool, err error) {\n\treturn types.Time{}, false, nil\n}\n\ntype builtinCastTimeAsTimeSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCastTimeAsTimeSig) Clone() builtinFunc {\n\tnewSig := &builtinCastTimeAsTimeSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCastTimeAsTimeSig) evalTime(row chunk.Row) (res types.Time, isNull bool, err error) {\n\tres, isNull, err = b.args[0].EvalTime(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn res, isNull, err\n\t}\n\n\tsc := b.ctx.GetSessionVars().StmtCtx\n\tif res, err = res.Convert(sc, b.tp.Tp); err != nil {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(b.ctx, err)\n\t}\n\tres, err = res.RoundFrac(sc, int8(b.tp.Decimal))\n\tif b.tp.Tp == mysql.TypeDate {\n\t\t// Truncate hh:mm:ss part if the type is Date.\n\t\tres.SetCoreTime(types.FromDate(res.Year(), res.Month(), res.Day(), 0, 0, 0, 0))\n\t\tres.SetType(b.tp.Tp)\n\t}\n\treturn res, false, err\n}\n\ntype builtinCastStringAsTimeSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCastStringAsTimeSig) Clone() builtinFunc {\n\tnewSig := &builtinCastStringAsTimeSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCastStringAsTimeSig) evalTime(row chunk.Row) (res types.Time, isNull bool, err error) {\n\tval, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn res, isNull, err\n\t}\n\tsc := b.ctx.GetSessionVars().StmtCtx\n\tres, err = types.ParseTime(sc, val, b.tp.Tp, int8(b.tp.Decimal))\n\tif err != nil {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(b.ctx, err)\n\t}\n\tif b.tp.Tp == mysql.TypeDate {\n\t\t// Truncate hh:mm:ss part if the type is Date.\n\t\tres.SetCoreTime(types.FromDate(res.Year(), res.Month(), res.Day(), 0, 0, 0, 0))\n\t}\n\treturn res, false, nil\n}\n\ntype builtinCastTimeAsIntSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastTimeAsIntSig) Clone() builtinFunc {\n\tnewSig := &builtinCastTimeAsIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCastTimeAsIntSig) evalInt(row chunk.Row) (res int64, isNull bool, err error) {\n\treturn 0, false, nil\n}\n\ntype builtinCastTimeAsRealSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastTimeAsRealSig) Clone() builtinFunc {\n\tnewSig := &builtinCastTimeAsRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCastTimeAsRealSig) evalReal(row chunk.Row) (res float64, isNull bool, err error) {\n\treturn 0.0, false, nil\n}\n\ntype builtinCastTimeAsDecimalSig struct {\n\tbaseBuiltinCastFunc\n}\n\nfunc (b *builtinCastTimeAsDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinCastTimeAsDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinCastFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCastTimeAsDecimalSig) evalDecimal(row chunk.Row) (res *types.MyDecimal, isNull bool, err error) {\n\treturn nil, false, nil\n}\n\ntype builtinCastTimeAsStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCastTimeAsStringSig) Clone() builtinFunc {\n\tnewSig := &builtinCastTimeAsStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCastTimeAsStringSig) evalString(row chunk.Row) (res string, isNull bool, err error) {\n\treturn \"\", false, nil\n}\n"
  },
  {
    "path": "pkg/expression/builtin_compare.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n)\n\nvar (\n\t_ builtinFunc = &builtinLTIntSig{}\n\t_ builtinFunc = &builtinLTStringSig{}\n\t_ builtinFunc = &builtinLEIntSig{}\n\t_ builtinFunc = &builtinLEStringSig{}\n\t_ builtinFunc = &builtinGTIntSig{}\n\t_ builtinFunc = &builtinGTStringSig{}\n\t_ builtinFunc = &builtinGEIntSig{}\n\t_ builtinFunc = &builtinGEStringSig{}\n\t_ builtinFunc = &builtinNEIntSig{}\n\t_ builtinFunc = &builtinNEStringSig{}\n)\n\ntype compareFunctionClass struct {\n\tbaseFunctionClass\n\n\top opcode.Op\n}\n\n// getFunction sets compare built-in function signatures for various types.\nfunc (c *compareFunctionClass) getFunction(ctx sessionctx.Context, rawArgs []Expression) (sig builtinFunc, err error) {\n\t//if err = c.verifyArgs(rawArgs); err != nil {\n\t//\treturn nil, err\n\t//}\n\targs := c.refineArgs(ctx, rawArgs)\n\tcmpType := GetAccurateCmpType(args[0], args[1])\n\tsig, err = c.generateCmpSigs(ctx, args, cmpType)\n\treturn sig, err\n}\n\n// generateCmpSigs generates compare function signatures.\nfunc (c *compareFunctionClass) generateCmpSigs(ctx sessionctx.Context, args []Expression, tp types.EvalType) (sig builtinFunc, err error) {\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, tp, tp)\n\tbf.tp.Flen = 1\n\tbf.tp.Flag |= mysql.IsBooleanFlag\n\tswitch tp {\n\tcase types.ETInt:\n\t\tswitch c.op {\n\t\tcase opcode.LT:\n\t\t\tsig = &builtinLTIntSig{bf}\n\t\tcase opcode.LE:\n\t\t\tsig = &builtinLEIntSig{bf}\n\t\tcase opcode.GT:\n\t\t\tsig = &builtinGTIntSig{bf}\n\t\tcase opcode.EQ:\n\t\t\tsig = &builtinEQIntSig{bf}\n\t\tcase opcode.GE:\n\t\t\tsig = &builtinGEIntSig{bf}\n\t\tcase opcode.NE:\n\t\t\tsig = &builtinNEIntSig{bf}\n\t\t// TODO(yang.y): add more cases\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"generateCmpSigs: unsupported op type %v. Please contact yang.y for details\", c.op)\n\t\t}\n\tcase types.ETReal:\n\t\tswitch c.op {\n\t\tcase opcode.LT:\n\t\t\tsig = &builtinLTRealSig{bf}\n\t\tcase opcode.LE:\n\t\t\tsig = &builtinLERealSig{bf}\n\t\tcase opcode.GT:\n\t\t\tsig = &builtinGTRealSig{bf}\n\t\tcase opcode.GE:\n\t\t\tsig = &builtinGERealSig{bf}\n\t\tcase opcode.EQ:\n\t\t\tsig = &builtinEQRealSig{bf}\n\t\tcase opcode.NE:\n\t\t\tsig = &builtinNERealSig{bf}\n\t\t// TODO(yang.y): add more cases\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"generateCmpSigs: unsupported op type %v. Please contact yang.y for details\", c.op)\n\t\t}\n\tcase types.ETDecimal:\n\t\tswitch c.op {\n\t\tcase opcode.LT:\n\t\t\tsig = &builtinLTDecimalSig{bf}\n\t\tcase opcode.LE:\n\t\t\tsig = &builtinLEDecimalSig{bf}\n\t\tcase opcode.GT:\n\t\t\tsig = &builtinGTDecimalSig{bf}\n\t\tcase opcode.GE:\n\t\t\tsig = &builtinGEDecimalSig{bf}\n\t\tcase opcode.EQ:\n\t\t\tsig = &builtinEQDecimalSig{bf}\n\t\tcase opcode.NE:\n\t\t\tsig = &builtinNEDecimalSig{bf}\n\t\t\t// TODO(qunshan.huangqs): add more cases\n\t\t\t// case opcode.NullEQ:\n\t\t\t// \tsig = &builtinNullEQDecimalSig{bf}\n\t\t}\n\tcase types.ETString:\n\t\tswitch c.op {\n\t\tcase opcode.LT:\n\t\t\tsig = &builtinLTStringSig{bf}\n\t\tcase opcode.LE:\n\t\t\tsig = &builtinLEStringSig{bf}\n\t\tcase opcode.GT:\n\t\t\tsig = &builtinGTStringSig{bf}\n\t\tcase opcode.GE:\n\t\t\tsig = &builtinGEStringSig{bf}\n\t\tcase opcode.EQ:\n\t\t\tsig = &builtinEQStringSig{bf}\n\t\tcase opcode.NE:\n\t\t\tsig = &builtinNEStringSig{bf}\n\t\t// TODO(yang.y): add more cases\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"generateCmpSigs: unsupported op type %v. Please contact yang.y for details\", c.op)\n\t\t}\n\t// TODO(yang.y): add more cases\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"generateCmpSigs: unsupported type %v. Please contact yang.y for details\", tp)\n\t}\n\treturn\n}\n\n// getBaseCmpType gets the EvalType that the two args will be treated as when comparing.\nfunc getBaseCmpType(lhs, rhs types.EvalType, lft, rft *types.FieldType) types.EvalType {\n\tif lft.Tp == mysql.TypeUnspecified || rft.Tp == mysql.TypeUnspecified {\n\t\tif lft.Tp == rft.Tp {\n\t\t\treturn types.ETString\n\t\t}\n\t\tif lft.Tp == mysql.TypeUnspecified {\n\t\t\tlhs = rhs\n\t\t} else {\n\t\t\trhs = lhs\n\t\t}\n\t}\n\tif lhs.IsStringKind() && rhs.IsStringKind() {\n\t\treturn types.ETString\n\t} else if (lhs == types.ETInt || lft.Hybrid()) && (rhs == types.ETInt || rft.Hybrid()) {\n\t\treturn types.ETInt\n\t} else if ((lhs == types.ETInt || lft.Hybrid()) || lhs == types.ETDecimal) &&\n\t\t((rhs == types.ETInt || rft.Hybrid()) || rhs == types.ETDecimal) {\n\t\treturn types.ETDecimal\n\t}\n\treturn types.ETReal\n}\n\n// GetAccurateCmpType uses a more complex logic to decide the EvalType of the two args when compare with each other than\n// getBaseCmpType does.\nfunc GetAccurateCmpType(lhs, rhs Expression) types.EvalType {\n\tlhsFieldType, rhsFieldType := lhs.GetType(), rhs.GetType()\n\tlhsEvalType, rhsEvalType := lhsFieldType.EvalType(), rhsFieldType.EvalType()\n\tcmpType := getBaseCmpType(lhsEvalType, rhsEvalType, lhsFieldType, rhsFieldType)\n\treturn cmpType\n\t// TODO(yang.y): revisit the original logic\n}\n\ntype builtinLTIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLTIntSig) Clone() builtinFunc {\n\tnewSig := &builtinLTIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinLTStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLTStringSig) Clone() builtinFunc {\n\tnewSig := &builtinLTStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinEQIntSig struct {\n\tbaseBuiltinFunc\n}\n\ntype builtinEQStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinEQStringSig) Clone() builtinFunc {\n\tnewSig := &builtinEQStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinEQIntSig) Clone() builtinFunc {\n\tnewSig := &builtinEQIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinLEIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLEIntSig) Clone() builtinFunc {\n\tnewSig := &builtinLEIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinLEStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLEStringSig) Clone() builtinFunc {\n\tnewSig := &builtinLEStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinGTIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGTIntSig) Clone() builtinFunc {\n\tnewSig := &builtinGTIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinGTStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGTStringSig) Clone() builtinFunc {\n\tnewSig := &builtinGTStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinGEIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGEIntSig) Clone() builtinFunc {\n\tnewSig := &builtinGEIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinGEStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGEStringSig) Clone() builtinFunc {\n\tnewSig := &builtinGEStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinNEIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinNEIntSig) Clone() builtinFunc {\n\tnewSig := &builtinNEIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinNEStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinNEStringSig) Clone() builtinFunc {\n\tnewSig := &builtinNEStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinLTRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLTRealSig) Clone() builtinFunc {\n\tnewSig := &builtinLTRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinLTRealSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfLT(CompareReal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinLTDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLTDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinLTDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinLTDecimalSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfLT(CompareDecimal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinLERealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLERealSig) Clone() builtinFunc {\n\tnewSig := &builtinLERealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinLERealSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfLE(CompareReal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinLEDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLEDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinLEDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinLEDecimalSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfLE(CompareDecimal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinGTRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGTRealSig) Clone() builtinFunc {\n\tnewSig := &builtinGTRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinGTRealSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfGT(CompareReal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinGTDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGTDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinGTDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinGTDecimalSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfGT(CompareDecimal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinGERealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGERealSig) Clone() builtinFunc {\n\tnewSig := &builtinGERealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinGERealSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfGE(CompareReal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinGEDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGEDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinGEDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinGEDecimalSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfGE(CompareDecimal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinEQRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinEQRealSig) Clone() builtinFunc {\n\tnewSig := &builtinEQRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinEQRealSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfEQ(CompareReal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinEQDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinEQDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinEQDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinEQDecimalSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfEQ(CompareDecimal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinNERealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinNERealSig) Clone() builtinFunc {\n\tnewSig := &builtinNERealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinNERealSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfNE(CompareReal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\ntype builtinNEDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinNEDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinNEDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinNEDecimalSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {\n\treturn resOfNE(CompareDecimal(b.ctx, b.args[0], b.args[1], row, row))\n}\n\n// CompareReal compares two float-point values.\nfunc CompareReal(sctx sessionctx.Context, lhsArg, rhsArg Expression, lhsRow, rhsRow chunk.Row) (int64, bool, error) {\n\targ0, isNull0, err := lhsArg.EvalReal(sctx, lhsRow)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\n\targ1, isNull1, err := rhsArg.EvalReal(sctx, rhsRow)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\n\tif isNull0 || isNull1 {\n\t\treturn compareNull(isNull0, isNull1), true, nil\n\t}\n\treturn int64(types.CompareFloat64(arg0, arg1)), false, nil\n}\n\n// CompareDecimal compares two decimals.\nfunc CompareDecimal(sctx sessionctx.Context, lhsArg, rhsArg Expression, lhsRow, rhsRow chunk.Row) (int64, bool, error) {\n\targ0, isNull0, err := lhsArg.EvalDecimal(sctx, lhsRow)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\n\targ1, isNull1, err := rhsArg.EvalDecimal(sctx, rhsRow)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\n\tif isNull0 || isNull1 {\n\t\treturn compareNull(isNull0, isNull1), true, nil\n\t}\n\treturn int64(arg0.Compare(arg1)), false, nil\n}\n\n// CompareInt compares two integers.\nfunc CompareInt(sctx sessionctx.Context, lhsArg, rhsArg Expression, lhsRow, rhsRow chunk.Row) (int64, bool, error) {\n\targ0, isNull0, err := lhsArg.EvalInt(sctx, lhsRow)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\n\targ1, isNull1, err := rhsArg.EvalInt(sctx, rhsRow)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\n\t// compare null values.\n\tif isNull0 || isNull1 {\n\t\treturn compareNull(isNull0, isNull1), true, nil\n\t}\n\n\tisUnsigned0, isUnsigned1 := mysql.HasUnsignedFlag(lhsArg.GetType().Flag), mysql.HasUnsignedFlag(rhsArg.GetType().Flag)\n\tvar res int\n\tswitch {\n\tcase isUnsigned0 && isUnsigned1:\n\t\tres = types.CompareUint64(uint64(arg0), uint64(arg1))\n\tcase isUnsigned0 && !isUnsigned1:\n\t\tif arg1 < 0 || uint64(arg0) > math.MaxInt64 {\n\t\t\tres = 1\n\t\t} else {\n\t\t\tres = types.CompareInt64(arg0, arg1)\n\t\t}\n\tcase !isUnsigned0 && isUnsigned1:\n\t\tif arg0 < 0 || uint64(arg1) > math.MaxInt64 {\n\t\t\tres = -1\n\t\t} else {\n\t\t\tres = types.CompareInt64(arg0, arg1)\n\t\t}\n\tcase !isUnsigned0 && !isUnsigned1:\n\t\tres = types.CompareInt64(arg0, arg1)\n\t}\n\treturn int64(res), false, nil\n}\n\n// CompareString compares two strings.\nfunc CompareString(sctx sessionctx.Context, lhsArg, rhsArg Expression, lhsRow, rhsRow chunk.Row) (int64, bool, error) {\n\targ0, isNull0, err := lhsArg.EvalString(sctx, lhsRow)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\n\targ1, isNull1, err := rhsArg.EvalString(sctx, rhsRow)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\n\tif isNull0 || isNull1 {\n\t\treturn compareNull(isNull0, isNull1), true, nil\n\t}\n\treturn int64(types.CompareString(arg0, arg1)), false, nil\n}\n\nfunc resOfLT(val int64, isNull bool, err error) (int64, bool, error) {\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val < 0 {\n\t\tval = 1\n\t} else {\n\t\tval = 0\n\t}\n\treturn val, false, nil\n}\n\nfunc resOfLE(val int64, isNull bool, err error) (int64, bool, error) {\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val <= 0 {\n\t\tval = 1\n\t} else {\n\t\tval = 0\n\t}\n\treturn val, false, nil\n}\n\nfunc resOfGT(val int64, isNull bool, err error) (int64, bool, error) {\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val > 0 {\n\t\tval = 1\n\t} else {\n\t\tval = 0\n\t}\n\treturn val, false, nil\n}\n\nfunc resOfGE(val int64, isNull bool, err error) (int64, bool, error) {\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val >= 0 {\n\t\tval = 1\n\t} else {\n\t\tval = 0\n\t}\n\treturn val, false, nil\n}\n\nfunc resOfEQ(val int64, isNull bool, err error) (int64, bool, error) {\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val == 0 {\n\t\tval = 1\n\t} else {\n\t\tval = 0\n\t}\n\treturn val, false, nil\n}\n\nfunc resOfNE(val int64, isNull bool, err error) (int64, bool, error) {\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val != 0 {\n\t\tval = 1\n\t} else {\n\t\tval = 0\n\t}\n\treturn val, false, nil\n}\n\n// compareNull compares null values based on the following rules.\n// 1. NULL is considered to be equal to NULL\n// 2. NULL is considered to be smaller than a non-NULL value.\n// NOTE: (lhsIsNull == true) or (rhsIsNull == true) is required.\nfunc compareNull(lhsIsNull, rhsIsNull bool) int64 {\n\tif lhsIsNull && rhsIsNull {\n\t\treturn 0\n\t}\n\tif lhsIsNull {\n\t\treturn -1\n\t}\n\treturn 1\n}\n\n// TODO(teng.t, yang.y): Add more operators like builtin[GT|EQ|LT|...][Real|Int|...]Sig\n\n// tryToConvertConstantInt tries to convert a constant with other type to a int constant.\n// isExceptional indicates whether the 'int column [cmp] const' might be true/false.\n// If isExceptional is true, ExecptionalVal is returned. Or, CorrectVal is returned.\n// CorrectVal: The computed result. If the constant can be converted to int without exception, return the val. Else return 'con'(the input).\n// ExceptionalVal : It is used to get more information to check whether 'int column [cmp] const' is true/false\n//\n//\tIf the op == LT,LE,GT,GE and it gets an Overflow when converting, return inf/-inf.\n//\tIf the op == EQ,NullEQ and the constant can never be equal to the int column, return ‘con’(the input, a non-int c     onstant).\nfunc tryToConvertConstantInt(ctx sessionctx.Context, targetFieldType *types.FieldType, con *Constant) (_ *Constant, isExceptional bool) {\n\tif con.GetType().EvalType() == types.ETInt {\n\t\treturn con, false\n\t}\n\tdt, err := con.Eval(chunk.Row{})\n\tif err != nil {\n\t\treturn con, false\n\t}\n\tsc := ctx.GetSessionVars().StmtCtx\n\n\tdt, err = dt.ConvertTo(sc, targetFieldType)\n\tif err != nil {\n\t\tif terror.ErrorEqual(err, types.ErrOverflow) {\n\t\t\treturn &Constant{\n\t\t\t\tValue:   dt,\n\t\t\t\tRetType: targetFieldType,\n\t\t\t}, true\n\t\t}\n\t\treturn con, false\n\t}\n\treturn &Constant{\n\t\tValue:   dt,\n\t\tRetType: targetFieldType,\n\t}, false\n}\n\n// RefineComparedConstant changes a non-integer constant argument to its ceiling or floor result by the given op.\n// isExceptional indicates whether the 'int column [cmp] const' might be true/false.\n// If isExceptional is true, ExecptionalVal is returned. Or, CorrectVal is returned.\n// CorrectVal: The computed result. If the constant can be converted to int without exception, return the val. Else return 'con'(the input).\n// ExceptionalVal : It is used to get more information to check whether 'int column [cmp] const' is true/false\n//\n//\tIf the op == LT,LE,GT,GE and it gets an Overflow when converting, return inf/-inf.\n//\tIf the op == EQ,NullEQ and the constant can never be equal to the int column, return ‘con’(the input, a non-int c     onstant).\nfunc RefineComparedConstant(ctx sessionctx.Context, targetFieldType types.FieldType, con *Constant, op opcode.Op) (_ *Constant, isExceptional bool) {\n\tdt, err := con.Eval(chunk.Row{})\n\tif err != nil {\n\t\treturn con, false\n\t}\n\tsc := ctx.GetSessionVars().StmtCtx\n\n\tif targetFieldType.Tp == mysql.TypeBit {\n\t\ttargetFieldType = *types.NewFieldType(mysql.TypeLonglong)\n\t}\n\tvar intDatum types.Datum\n\tintDatum, err = dt.ConvertTo(sc, &targetFieldType)\n\tif err != nil {\n\t\tif terror.ErrorEqual(err, types.ErrOverflow) {\n\t\t\treturn &Constant{\n\t\t\t\tValue:   intDatum,\n\t\t\t\tRetType: &targetFieldType,\n\t\t\t}, true\n\t\t}\n\t\treturn con, false\n\t}\n\tc, err := intDatum.CompareDatum(sc, &con.Value)\n\tif err != nil {\n\t\treturn con, false\n\t}\n\tif c == 0 {\n\t\treturn &Constant{\n\t\t\tValue:   intDatum,\n\t\t\tRetType: &targetFieldType,\n\t\t}, false\n\t}\n\tswitch op {\n\tcase opcode.LT, opcode.GE:\n\t\tresultExpr := NewFunctionInternal(ctx, ast.Ceil, types.NewFieldType(mysql.TypeUnspecified), con)\n\t\tif resultCon, ok := resultExpr.(*Constant); ok {\n\t\t\treturn tryToConvertConstantInt(ctx, &targetFieldType, resultCon)\n\t\t}\n\tcase opcode.LE, opcode.GT:\n\t\tresultExpr := NewFunctionInternal(ctx, ast.Floor, types.NewFieldType(mysql.TypeUnspecified), con)\n\t\tif resultCon, ok := resultExpr.(*Constant); ok {\n\t\t\treturn tryToConvertConstantInt(ctx, &targetFieldType, resultCon)\n\t\t}\n\tcase opcode.NullEQ, opcode.EQ:\n\t\tswitch con.GetType().EvalType() {\n\t\t// An integer value equal or NULL-safe equal to a float value which contains\n\t\t// non-zero decimal digits is definitely false.\n\t\t// e.g.,\n\t\t//   1. \"integer  =  1.1\" is definitely false.\n\t\t//   2. \"integer <=> 1.1\" is definitely false.\n\t\tcase types.ETReal, types.ETDecimal:\n\t\t\treturn con, true\n\t\tcase types.ETString:\n\t\t\t// We try to convert the string constant to double.\n\t\t\t// If the double result equals the int result, we can return the int result;\n\t\t\t// otherwise, the compare function will be false.\n\t\t\tvar doubleDatum types.Datum\n\t\t\tdoubleDatum, err = dt.ConvertTo(sc, types.NewFieldType(mysql.TypeDouble))\n\t\t\tif err != nil {\n\t\t\t\treturn con, false\n\t\t\t}\n\t\t\tif c, err = doubleDatum.CompareDatum(sc, &intDatum); err != nil {\n\t\t\t\treturn con, false\n\t\t\t}\n\t\t\tif c != 0 {\n\t\t\t\treturn con, true\n\t\t\t}\n\t\t\treturn &Constant{\n\t\t\t\tValue:   intDatum,\n\t\t\t\tRetType: &targetFieldType,\n\t\t\t}, false\n\t\t}\n\t}\n\treturn con, false\n}\n\n// refineArgs will rewrite the arguments if the compare expression is `int column <cmp> non-int constant` or\n// `non-int constant <cmp> int column`. E.g., `a < 1.1` will be rewritten to `a < 2`.\nfunc (c *compareFunctionClass) refineArgs(ctx sessionctx.Context, args []Expression) []Expression {\n\treturn args\n\t// TODO(yang.y): revisit the original logic\n}\n\nfunc aggregateType(args []Expression) *types.FieldType {\n\tfieldTypes := make([]*types.FieldType, len(args))\n\tfor i := range fieldTypes {\n\t\tfieldTypes[i] = args[i].GetType()\n\t}\n\treturn types.AggFieldType(fieldTypes)\n}\n\n// resolveType4Extremum gets compare type for GREATEST and LEAST and BETWEEN (mainly for datetime).\nfunc resolveType4Extremum(args []Expression) types.EvalType {\n\taggType := aggregateType(args)\n\n\tvar temporalItem *types.FieldType\n\tif aggType.EvalType().IsStringKind() {\n\t\tfor i := range args {\n\t\t\titem := args[i].GetType()\n\t\t\t// Find the temporal value in the arguments but prefer DateTime value.\n\t\t\tif types.IsTypeTemporal(item.Tp) {\n\t\t\t\tif temporalItem == nil || item.Tp == mysql.TypeDatetime {\n\t\t\t\t\ttemporalItem = item\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif !types.IsTypeTemporal(aggType.Tp) && temporalItem != nil {\n\t\t\taggType.Tp = temporalItem.Tp\n\t\t}\n\t\t// TODO: String charset, collation checking are needed.\n\t}\n\treturn aggType.EvalType()\n}\n\n// unsupportedJSONComparison reports warnings while there is a JSON type in least/greatest function's arguments\nfunc unsupportedJSONComparison(ctx sessionctx.Context, args []Expression) {\n\tfor _, arg := range args {\n\t\ttp := arg.GetType().Tp\n\t\tif tp == mysql.TypeJSON {\n\t\t\tctx.GetSessionVars().StmtCtx.AppendWarning(errUnsupportedJSONComparison)\n\t\t\tbreak\n\t\t}\n\t}\n}\n\ntype greatestFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *greatestFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\ttp := resolveType4Extremum(args)\n\tcmpAsDatetime := false\n\tif tp == types.ETDatetime || tp == types.ETTimestamp {\n\t\tcmpAsDatetime = true\n\t\ttp = types.ETString\n\t} else if tp == types.ETDuration {\n\t\ttp = types.ETString\n\t} else if tp == types.ETJson {\n\t\tunsupportedJSONComparison(ctx, args)\n\t\ttp = types.ETString\n\t}\n\targTps := make([]types.EvalType, len(args))\n\tfor i := range args {\n\t\targTps[i] = tp\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, tp, argTps...)\n\tif cmpAsDatetime {\n\t\ttp = types.ETDatetime\n\t}\n\tswitch tp {\n\tcase types.ETInt:\n\t\tsig = &builtinGreatestIntSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_GreatestInt)\n\tcase types.ETReal:\n\t\tsig = &builtinGreatestRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_GreatestReal)\n\tcase types.ETDecimal:\n\t\tsig = &builtinGreatestDecimalSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_GreatestDecimal)\n\tcase types.ETString:\n\t\tsig = &builtinGreatestStringSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_GreatestString)\n\tcase types.ETDatetime, types.ETTimestamp:\n\t\tsig = &builtinGreatestTimeSig{bf}\n\tdefault:\n\t\t//sig = &builtinGreatestTimeSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_GreatestTime)\n\t\treturn nil, fmt.Errorf(\"unsupported data type %d\", tp)\n\t}\n\tsig.getRetTp().Flen, sig.getRetTp().Decimal = fixFlenAndDecimalForGreatestAndLeast(args)\n\treturn sig, nil\n}\n\nfunc fixFlenAndDecimalForGreatestAndLeast(args []Expression) (flen, decimal int) {\n\tfor _, arg := range args {\n\t\targFlen, argDecimal := arg.GetType().Flen, arg.GetType().Decimal\n\t\tif argFlen > flen {\n\t\t\tflen = argFlen\n\t\t}\n\t\tif argDecimal > decimal {\n\t\t\tdecimal = argDecimal\n\t\t}\n\t}\n\treturn flen, decimal\n}\n\ntype builtinGreatestIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGreatestIntSig) Clone() builtinFunc {\n\tnewSig := &builtinGreatestIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals a builtinGreatestIntSig.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_greatest\nfunc (b *builtinGreatestIntSig) evalInt(row chunk.Row) (max int64, isNull bool, err error) {\n\tmax, isNull, err = b.args[0].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn max, isNull, err\n\t}\n\tfor i := 1; i < len(b.args); i++ {\n\t\tvar v int64\n\t\tv, isNull, err = b.args[i].EvalInt(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn max, isNull, err\n\t\t}\n\t\tif v > max {\n\t\t\tmax = v\n\t\t}\n\t}\n\treturn\n}\n\ntype builtinGreatestRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGreatestRealSig) Clone() builtinFunc {\n\tnewSig := &builtinGreatestRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinGreatestRealSig.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_greatest\nfunc (b *builtinGreatestRealSig) evalReal(row chunk.Row) (max float64, isNull bool, err error) {\n\tmax, isNull, err = b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn max, isNull, err\n\t}\n\tfor i := 1; i < len(b.args); i++ {\n\t\tvar v float64\n\t\tv, isNull, err = b.args[i].EvalReal(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn max, isNull, err\n\t\t}\n\t\tif v > max {\n\t\t\tmax = v\n\t\t}\n\t}\n\treturn\n}\n\ntype builtinGreatestDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGreatestDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinGreatestDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals a builtinGreatestDecimalSig.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_greatest\nfunc (b *builtinGreatestDecimalSig) evalDecimal(row chunk.Row) (max *types.MyDecimal, isNull bool, err error) {\n\tmax, isNull, err = b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn max, isNull, err\n\t}\n\tfor i := 1; i < len(b.args); i++ {\n\t\tvar v *types.MyDecimal\n\t\tv, isNull, err = b.args[i].EvalDecimal(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn max, isNull, err\n\t\t}\n\t\tif v.Compare(max) > 0 {\n\t\t\tmax = v\n\t\t}\n\t}\n\treturn\n}\n\ntype builtinGreatestStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGreatestStringSig) Clone() builtinFunc {\n\tnewSig := &builtinGreatestStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals a builtinGreatestStringSig.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_greatest\nfunc (b *builtinGreatestStringSig) evalString(row chunk.Row) (max string, isNull bool, err error) {\n\tmax, isNull, err = b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn max, isNull, err\n\t}\n\tfor i := 1; i < len(b.args); i++ {\n\t\tvar v string\n\t\tv, isNull, err = b.args[i].EvalString(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn max, isNull, err\n\t\t}\n\t\tif types.CompareString(v, max) > 0 {\n\t\t\tmax = v\n\t\t}\n\t}\n\treturn\n}\n\ntype builtinGreatestTimeSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGreatestTimeSig) Clone() builtinFunc {\n\tnewSig := &builtinGreatestTimeSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals a builtinGreatestTimeSig.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_greatest\nfunc (b *builtinGreatestTimeSig) evalString(row chunk.Row) (res string, isNull bool, err error) {\n\tvar (\n\t\tstrRes  string\n\t\ttimeRes types.Time\n\t)\n\tsc := b.ctx.GetSessionVars().StmtCtx\n\tfor i := 0; i < len(b.args); i++ {\n\t\tv, isNull, err := b.args[i].EvalString(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn \"\", true, err\n\t\t}\n\t\tt, err := types.ParseDatetime(sc, v)\n\t\tif err != nil {\n\t\t\tif err = handleInvalidTimeError(b.ctx, err); err != nil {\n\t\t\t\treturn v, true, err\n\t\t\t}\n\t\t} else {\n\t\t\tv = t.String()\n\t\t}\n\t\t// In MySQL, if the compare result is zero, than we will try to use the string comparison result\n\t\tif i == 0 || strings.Compare(v, strRes) > 0 {\n\t\t\tstrRes = v\n\t\t}\n\t\tif i == 0 || t.Compare(timeRes) > 0 {\n\t\t\ttimeRes = t\n\t\t}\n\t}\n\tif timeRes.IsZero() {\n\t\tres = strRes\n\t} else {\n\t\tres = timeRes.String()\n\t}\n\treturn res, false, nil\n}\n\ntype leastFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *leastFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\ttp := resolveType4Extremum(args)\n\tcmpAsDatetime := false\n\tif tp == types.ETDatetime || tp == types.ETTimestamp {\n\t\tcmpAsDatetime = true\n\t\ttp = types.ETString\n\t} else if tp == types.ETDuration {\n\t\ttp = types.ETString\n\t} else if tp == types.ETJson {\n\t\tunsupportedJSONComparison(ctx, args)\n\t\ttp = types.ETString\n\t}\n\targTps := make([]types.EvalType, len(args))\n\tfor i := range args {\n\t\targTps[i] = tp\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, tp, argTps...)\n\tif cmpAsDatetime {\n\t\ttp = types.ETDatetime\n\t}\n\tswitch tp {\n\tcase types.ETInt:\n\t\tsig = &builtinLeastIntSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_LeastInt)\n\tcase types.ETReal:\n\t\tsig = &builtinLeastRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_LeastReal)\n\tcase types.ETDecimal:\n\t\tsig = &builtinLeastDecimalSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_LeastDecimal)\n\tcase types.ETString:\n\t\tsig = &builtinLeastStringSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_LeastString)\n\tcase types.ETDatetime, types.ETTimestamp:\n\t\tsig = &builtinLeastTimeSig{bf}\n\tdefault:\n\t\t//sig = &builtinLeastTimeSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_LeastTime)\n\t\treturn nil, fmt.Errorf(\"unsupported data type %d\", tp)\n\t}\n\tsig.getRetTp().Flen, sig.getRetTp().Decimal = fixFlenAndDecimalForGreatestAndLeast(args)\n\treturn sig, nil\n}\n\ntype builtinLeastIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLeastIntSig) Clone() builtinFunc {\n\tnewSig := &builtinLeastIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals a builtinLeastIntSig.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_least\nfunc (b *builtinLeastIntSig) evalInt(row chunk.Row) (min int64, isNull bool, err error) {\n\tmin, isNull, err = b.args[0].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn min, isNull, err\n\t}\n\tfor i := 1; i < len(b.args); i++ {\n\t\tvar v int64\n\t\tv, isNull, err = b.args[i].EvalInt(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn min, isNull, err\n\t\t}\n\t\tif v < min {\n\t\t\tmin = v\n\t\t}\n\t}\n\treturn\n}\n\ntype builtinLeastRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLeastRealSig) Clone() builtinFunc {\n\tnewSig := &builtinLeastRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinLeastRealSig.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#functionleast\nfunc (b *builtinLeastRealSig) evalReal(row chunk.Row) (min float64, isNull bool, err error) {\n\tmin, isNull, err = b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn min, isNull, err\n\t}\n\tfor i := 1; i < len(b.args); i++ {\n\t\tvar v float64\n\t\tv, isNull, err = b.args[i].EvalReal(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn min, isNull, err\n\t\t}\n\t\tif v < min {\n\t\t\tmin = v\n\t\t}\n\t}\n\treturn\n}\n\ntype builtinLeastDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLeastDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinLeastDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals a builtinLeastDecimalSig.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#functionleast\nfunc (b *builtinLeastDecimalSig) evalDecimal(row chunk.Row) (min *types.MyDecimal, isNull bool, err error) {\n\tmin, isNull, err = b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn min, isNull, err\n\t}\n\tfor i := 1; i < len(b.args); i++ {\n\t\tvar v *types.MyDecimal\n\t\tv, isNull, err = b.args[i].EvalDecimal(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn min, isNull, err\n\t\t}\n\t\tif v.Compare(min) < 0 {\n\t\t\tmin = v\n\t\t}\n\t}\n\treturn\n}\n\ntype builtinLeastStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLeastStringSig) Clone() builtinFunc {\n\tnewSig := &builtinLeastStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals a builtinLeastStringSig.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#functionleast\nfunc (b *builtinLeastStringSig) evalString(row chunk.Row) (min string, isNull bool, err error) {\n\tmin, isNull, err = b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn min, isNull, err\n\t}\n\tfor i := 1; i < len(b.args); i++ {\n\t\tvar v string\n\t\tv, isNull, err = b.args[i].EvalString(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn min, isNull, err\n\t\t}\n\t\tif types.CompareString(v, min) < 0 {\n\t\t\tmin = v\n\t\t}\n\t}\n\treturn\n}\n\ntype builtinLeastTimeSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLeastTimeSig) Clone() builtinFunc {\n\tnewSig := &builtinLeastTimeSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals a builtinLeastTimeSig.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#functionleast\nfunc (b *builtinLeastTimeSig) evalString(row chunk.Row) (res string, isNull bool, err error) {\n\tvar (\n\t\t// timeRes will be converted to a strRes only when the arguments is a valid datetime value.\n\t\tstrRes  string     // Record the strRes of each arguments.\n\t\ttimeRes types.Time // Record the time representation of a valid arguments.\n\t)\n\tsc := b.ctx.GetSessionVars().StmtCtx\n\tfor i := 0; i < len(b.args); i++ {\n\t\tv, isNull, err := b.args[i].EvalString(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn \"\", true, err\n\t\t}\n\t\tt, err := types.ParseDatetime(sc, v)\n\t\tif err != nil {\n\t\t\tif err = handleInvalidTimeError(b.ctx, err); err != nil {\n\t\t\t\treturn v, true, err\n\t\t\t}\n\t\t} else {\n\t\t\tv = t.String()\n\t\t}\n\t\tif i == 0 || strings.Compare(v, strRes) < 0 {\n\t\t\tstrRes = v\n\t\t}\n\t\tif i == 0 || t.Compare(timeRes) < 0 {\n\t\t\ttimeRes = t\n\t\t}\n\t}\n\n\tif timeRes.IsZero() {\n\t\tres = strRes\n\t} else {\n\t\tres = timeRes.String()\n\t}\n\treturn res, false, nil\n}\n\n// coalesceFunctionClass returns the first non-NULL value in the list,\n// or NULL if there are no non-NULL values.\ntype coalesceFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *coalesceFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfieldTps := make([]*types.FieldType, 0, len(args))\n\tfor _, arg := range args {\n\t\tfieldTps = append(fieldTps, arg.GetType())\n\t}\n\n\t// Use the aggregated field type as retType.\n\tresultFieldType := types.AggFieldType(fieldTps)\n\tresultEvalType := types.AggregateEvalType(fieldTps, &resultFieldType.Flag)\n\tretEvalTp := resultFieldType.EvalType()\n\n\tfieldEvalTps := make([]types.EvalType, 0, len(args))\n\tfor range args {\n\t\tfieldEvalTps = append(fieldEvalTps, retEvalTp)\n\t}\n\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, retEvalTp, fieldEvalTps...)\n\tbf.tp.Flag |= resultFieldType.Flag\n\tresultFieldType.Flen, resultFieldType.Decimal = 0, types.UnspecifiedLength\n\n\t// Set retType to BINARY(0) if all arguments are of type NULL.\n\tif resultFieldType.Tp == mysql.TypeNull {\n\t\ttypes.SetBinChsClnFlag(bf.tp)\n\t} else {\n\t\tmaxIntLen := 0\n\t\tmaxFlen := 0\n\n\t\t// Find the max length of field in `maxFlen`,\n\t\t// and max integer-part length in `maxIntLen`.\n\t\tfor _, argTp := range fieldTps {\n\t\t\tif argTp.Decimal > resultFieldType.Decimal {\n\t\t\t\tresultFieldType.Decimal = argTp.Decimal\n\t\t\t}\n\t\t\targIntLen := argTp.Flen\n\t\t\tif argTp.Decimal > 0 {\n\t\t\t\targIntLen -= argTp.Decimal + 1\n\t\t\t}\n\n\t\t\t// Reduce the sign bit if it is a signed integer/decimal\n\t\t\tif !mysql.HasUnsignedFlag(argTp.Flag) {\n\t\t\t\targIntLen--\n\t\t\t}\n\t\t\tif argIntLen > maxIntLen {\n\t\t\t\tmaxIntLen = argIntLen\n\t\t\t}\n\t\t\tif argTp.Flen > maxFlen || argTp.Flen == types.UnspecifiedLength {\n\t\t\t\tmaxFlen = argTp.Flen\n\t\t\t}\n\t\t}\n\t\t// For integer, field length = maxIntLen + (1/0 for sign bit)\n\t\t// For decimal, field length = maxIntLen + maxDecimal + (1/0 for sign bit)\n\t\tif resultEvalType == types.ETInt || resultEvalType == types.ETDecimal {\n\t\t\tresultFieldType.Flen = maxIntLen + resultFieldType.Decimal\n\t\t\tif resultFieldType.Decimal > 0 {\n\t\t\t\tresultFieldType.Flen++\n\t\t\t}\n\t\t\tif !mysql.HasUnsignedFlag(resultFieldType.Flag) {\n\t\t\t\tresultFieldType.Flen++\n\t\t\t}\n\t\t\tbf.tp = resultFieldType\n\t\t} else {\n\t\t\tbf.tp.Flen = maxFlen\n\t\t}\n\t\t// Set the field length to maxFlen for other types.\n\t\tif bf.tp.Flen > mysql.MaxDecimalWidth {\n\t\t\tbf.tp.Flen = mysql.MaxDecimalWidth\n\t\t}\n\t}\n\n\tswitch retEvalTp {\n\tcase types.ETInt:\n\t\tsig = &builtinCoalesceIntSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_CoalesceInt)\n\tcase types.ETReal:\n\t\tsig = &builtinCoalesceRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_CoalesceReal)\n\tcase types.ETDecimal:\n\t\tsig = &builtinCoalesceDecimalSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_CoalesceDecimal)\n\tcase types.ETString:\n\t\tsig = &builtinCoalesceStringSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_CoalesceString)\n\t\t// case types.ETDatetime, types.ETTimestamp:\n\t\t// \tsig = &builtinCoalesceTimeSig{bf}\n\t\t// \t//sig.setPbCode(tipb.ScalarFuncSig_CoalesceTime)\n\t\t// case types.ETDuration:\n\t\t// \tbf.tp.Decimal, err = getExpressionFsp(ctx, args[0])\n\t\t// \tif err != nil {\n\t\t// \t\treturn nil, err\n\t\t// \t}\n\t\t// \tsig = &builtinCoalesceDurationSig{bf}\n\t\t// \t//sig.setPbCode(tipb.ScalarFuncSig_CoalesceDuration)\n\t\t// case types.ETJson:\n\t\t// \tsig = &builtinCoalesceJSONSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_CoalesceJson)\n\t}\n\n\treturn sig, nil\n}\n\n// builtinCoalesceIntSig is builtin function coalesce signature which return type int\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_coalesce\ntype builtinCoalesceIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCoalesceIntSig) Clone() builtinFunc {\n\tnewSig := &builtinCoalesceIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCoalesceIntSig) evalInt(row chunk.Row) (res int64, isNull bool, err error) {\n\tfor _, a := range b.getArgs() {\n\t\tres, isNull, err = a.EvalInt(b.ctx, row)\n\t\tif err != nil || !isNull {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn res, isNull, err\n}\n\n// builtinCoalesceRealSig is builtin function coalesce signature which return type real\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_coalesce\ntype builtinCoalesceRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCoalesceRealSig) Clone() builtinFunc {\n\tnewSig := &builtinCoalesceRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCoalesceRealSig) evalReal(row chunk.Row) (res float64, isNull bool, err error) {\n\tfor _, a := range b.getArgs() {\n\t\tres, isNull, err = a.EvalReal(b.ctx, row)\n\t\tif err != nil || !isNull {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn res, isNull, err\n}\n\n// builtinCoalesceDecimalSig is builtin function coalesce signature which return type Decimal\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_coalesce\ntype builtinCoalesceDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCoalesceDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinCoalesceDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCoalesceDecimalSig) evalDecimal(row chunk.Row) (res *types.MyDecimal, isNull bool, err error) {\n\tfor _, a := range b.getArgs() {\n\t\tres, isNull, err = a.EvalDecimal(b.ctx, row)\n\t\tif err != nil || !isNull {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn res, isNull, err\n}\n\n// builtinCoalesceStringSig is builtin function coalesce signature which return type string\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_coalesce\ntype builtinCoalesceStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCoalesceStringSig) Clone() builtinFunc {\n\tnewSig := &builtinCoalesceStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinCoalesceStringSig) evalString(row chunk.Row) (res string, isNull bool, err error) {\n\tfor _, a := range b.getArgs() {\n\t\tres, isNull, err = a.EvalString(b.ctx, row)\n\t\tif err != nil || !isNull {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn res, isNull, err\n}\n\n// builtinCoalesceTimeSig is builtin function coalesce signature which return type time\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_coalesce\n// type builtinCoalesceTimeSig struct {\n// \tbaseBuiltinFunc\n// }\n\n// func (b *builtinCoalesceTimeSig) Clone() builtinFunc {\n// \tnewSig := &builtinCoalesceTimeSig{}\n// \tnewSig.cloneFrom(&b.baseBuiltinFunc)\n// \treturn newSig\n// }\n\n// func (b *builtinCoalesceTimeSig) evalTime(row chunk.Row) (res types.Time, isNull bool, err error) {\n// \tfor _, a := range b.getArgs() {\n// \t\tres, isNull, err = a.EvalTime(b.ctx, row)\n// \t\tif err != nil || !isNull {\n// \t\t\tbreak\n// \t\t}\n// \t}\n// \treturn res, isNull, err\n// }\n\n// builtinCoalesceDurationSig is builtin function coalesce signature which return type duration\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_coalesce\n// type builtinCoalesceDurationSig struct {\n// \tbaseBuiltinFunc\n// }\n\n// func (b *builtinCoalesceDurationSig) Clone() builtinFunc {\n// \tnewSig := &builtinCoalesceDurationSig{}\n// \tnewSig.cloneFrom(&b.baseBuiltinFunc)\n// \treturn newSig\n// }\n\n// func (b *builtinCoalesceDurationSig) evalDuration(row chunk.Row) (res types.Duration, isNull bool, err error) {\n// \tfor _, a := range b.getArgs() {\n// \t\tres, isNull, err = a.EvalDuration(b.ctx, row)\n// \t\tif err != nil || !isNull {\n// \t\t\tbreak\n// \t\t}\n// \t}\n// \treturn res, isNull, err\n// }\n\n// builtinCoalesceJSONSig is builtin function coalesce signature which return type json.\n// See http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_coalesce\n// type builtinCoalesceJSONSig struct {\n// \tbaseBuiltinFunc\n// }\n\n// func (b *builtinCoalesceJSONSig) Clone() builtinFunc {\n// \tnewSig := &builtinCoalesceJSONSig{}\n// \tnewSig.cloneFrom(&b.baseBuiltinFunc)\n// \treturn newSig\n// }\n\n// func (b *builtinCoalesceJSONSig) evalJSON(row chunk.Row) (res json.BinaryJSON, isNull bool, err error) {\n// \tfor _, a := range b.getArgs() {\n// \t\tres, isNull, err = a.EvalJSON(b.ctx, row)\n// \t\tif err != nil || !isNull {\n// \t\t\tbreak\n// \t\t}\n// \t}\n// \treturn res, isNull, err\n// }\n\n// CompareFunc defines the compare function prototype.\ntype CompareFunc = func(sctx sessionctx.Context, lhsArg, rhsArg Expression, lhsRow, rhsRow chunk.Row) (int64, bool, error)\n\n// GetCmpFunction get the compare function according to two arguments.\nfunc GetCmpFunction(lhs, rhs Expression) CompareFunc {\n\tswitch GetAccurateCmpType(lhs, rhs) {\n\tcase types.ETInt:\n\t\treturn CompareInt\n\tcase types.ETReal:\n\t\treturn CompareReal\n\tcase types.ETDecimal:\n\t\treturn CompareDecimal\n\tcase types.ETString:\n\t\treturn CompareString\n\t\t// case types.ETDuration:\n\t\t// \treturn CompareDuration\n\t\t// case types.ETDatetime, types.ETTimestamp:\n\t\t// \treturn CompareTime\n\t\t// case types.ETJson:\n\t\t// \treturn CompareJSON\n\t}\n\treturn nil\n}\n\n// isTemporalColumn checks if a expression is a temporal column,\n// temporal column indicates time column or duration column.\nfunc isTemporalColumn(expr Expression) bool {\n\tft := expr.GetType()\n\tif _, isCol := expr.(*Column); !isCol {\n\t\treturn false\n\t}\n\tif !types.IsTypeTime(ft.Tp) && ft.Tp != mysql.TypeDuration {\n\t\treturn false\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "pkg/expression/builtin_control.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//\thttp://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\npackage expression\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n\t\"github.com/secretflow/scql/pkg/util/mathutil\"\n)\n\nvar (\n\t_ functionClass = &caseWhenFunctionClass{}\n\t_ functionClass = &ifFunctionClass{}\n\t_ functionClass = &ifNullFunctionClass{}\n)\n\nvar (\n\t_ builtinFunc = &builtinCaseWhenIntSig{}\n\t_ builtinFunc = &builtinCaseWhenRealSig{}\n\t_ builtinFunc = &builtinCaseWhenDecimalSig{}\n\t_ builtinFunc = &builtinCaseWhenStringSig{}\n\t_ builtinFunc = &builtinIfNullIntSig{}\n\t_ builtinFunc = &builtinIfNullRealSig{}\n\t_ builtinFunc = &builtinIfNullDecimalSig{}\n\t_ builtinFunc = &builtinIfNullStringSig{}\n\t_ builtinFunc = &builtinIfIntSig{}\n\t_ builtinFunc = &builtinIfRealSig{}\n\t_ builtinFunc = &builtinIfDecimalSig{}\n\t_ builtinFunc = &builtinIfStringSig{}\n)\n\n// InferType4ControlFuncs infer result type for builtin IF, IFNULL, NULLIF, LEAD and LAG.\nfunc InferType4ControlFuncs(lhs, rhs *types.FieldType) *types.FieldType {\n\tresultFieldType := &types.FieldType{}\n\tif lhs.Tp == mysql.TypeNull {\n\t\t*resultFieldType = *rhs\n\t\t// If both arguments are NULL, make resulting type BINARY(0).\n\t\tif rhs.Tp == mysql.TypeNull {\n\t\t\tresultFieldType.Tp = mysql.TypeString\n\t\t\tresultFieldType.Flen, resultFieldType.Decimal = 0, 0\n\t\t\ttypes.SetBinChsClnFlag(resultFieldType)\n\t\t}\n\t} else if rhs.Tp == mysql.TypeNull {\n\t\t*resultFieldType = *lhs\n\t} else {\n\t\tresultFieldType = types.AggFieldType([]*types.FieldType{lhs, rhs})\n\t\tevalType := types.AggregateEvalType([]*types.FieldType{lhs, rhs}, &resultFieldType.Flag)\n\t\tif evalType == types.ETInt {\n\t\t\tresultFieldType.Decimal = 0\n\t\t} else {\n\t\t\tif lhs.Decimal == types.UnspecifiedLength || rhs.Decimal == types.UnspecifiedLength {\n\t\t\t\tresultFieldType.Decimal = types.UnspecifiedLength\n\t\t\t} else {\n\t\t\t\tresultFieldType.Decimal = mathutil.Max(lhs.Decimal, rhs.Decimal)\n\t\t\t}\n\t\t}\n\t\tif types.IsNonBinaryStr(lhs) && !types.IsBinaryStr(rhs) {\n\t\t\tresultFieldType.Charset, resultFieldType.Collate, resultFieldType.Flag = charset.CharsetUTF8MB4, charset.CollationUTF8MB4, 0\n\t\t\tif mysql.HasBinaryFlag(lhs.Flag) || !types.IsNonBinaryStr(rhs) {\n\t\t\t\tresultFieldType.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t} else if types.IsNonBinaryStr(rhs) && !types.IsBinaryStr(lhs) {\n\t\t\tresultFieldType.Charset, resultFieldType.Collate, resultFieldType.Flag = charset.CharsetUTF8MB4, charset.CollationUTF8MB4, 0\n\t\t\tif mysql.HasBinaryFlag(rhs.Flag) || !types.IsNonBinaryStr(lhs) {\n\t\t\t\tresultFieldType.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t} else if types.IsBinaryStr(lhs) || types.IsBinaryStr(rhs) || !evalType.IsStringKind() {\n\t\t\ttypes.SetBinChsClnFlag(resultFieldType)\n\t\t} else {\n\t\t\tresultFieldType.Charset, resultFieldType.Collate, resultFieldType.Flag = mysql.DefaultCharset, mysql.DefaultCollationName, 0\n\t\t}\n\t\tif evalType == types.ETDecimal || evalType == types.ETInt {\n\t\t\tlhsUnsignedFlag, rhsUnsignedFlag := mysql.HasUnsignedFlag(lhs.Flag), mysql.HasUnsignedFlag(rhs.Flag)\n\t\t\tlhsFlagLen, rhsFlagLen := 0, 0\n\t\t\tif !lhsUnsignedFlag {\n\t\t\t\tlhsFlagLen = 1\n\t\t\t}\n\t\t\tif !rhsUnsignedFlag {\n\t\t\t\trhsFlagLen = 1\n\t\t\t}\n\t\t\tlhsFlen := lhs.Flen - lhsFlagLen\n\t\t\trhsFlen := rhs.Flen - rhsFlagLen\n\t\t\tif lhs.Decimal != types.UnspecifiedLength {\n\t\t\t\tlhsFlen -= lhs.Decimal\n\t\t\t}\n\t\t\tif lhs.Decimal != types.UnspecifiedLength {\n\t\t\t\trhsFlen -= rhs.Decimal\n\t\t\t}\n\t\t\tresultFieldType.Flen = mathutil.Max(lhsFlen, rhsFlen) + resultFieldType.Decimal + 1\n\t\t} else {\n\t\t\tresultFieldType.Flen = mathutil.Max(lhs.Flen, rhs.Flen)\n\t\t}\n\t}\n\t// Fix decimal for int and string.\n\tresultEvalType := resultFieldType.EvalType()\n\tif resultEvalType == types.ETInt {\n\t\tresultFieldType.Decimal = 0\n\t} else if resultEvalType == types.ETString {\n\t\tif lhs.Tp != mysql.TypeNull || rhs.Tp != mysql.TypeNull {\n\t\t\tresultFieldType.Decimal = types.UnspecifiedLength\n\t\t}\n\t}\n\treturn resultFieldType\n}\n\ntype caseWhenFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *caseWhenFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tl := len(args)\n\t// Fill in each 'THEN' clause parameter type.\n\tfieldTps := make([]*types.FieldType, 0, (l+1)/2)\n\tdecimal, flen, isBinaryStr, isBinaryFlag := args[1].GetType().Decimal, 0, false, false\n\tfor i := 1; i < l; i += 2 {\n\t\tfieldTps = append(fieldTps, args[i].GetType())\n\t\tdecimal = mathutil.Max(decimal, args[i].GetType().Decimal)\n\t\tflen = mathutil.Max(flen, args[i].GetType().Flen)\n\t\tisBinaryStr = isBinaryStr || types.IsBinaryStr(args[i].GetType())\n\t\tisBinaryFlag = isBinaryFlag || !types.IsNonBinaryStr(args[i].GetType())\n\t}\n\tif l%2 == 1 {\n\t\tfieldTps = append(fieldTps, args[l-1].GetType())\n\t\tdecimal = mathutil.Max(decimal, args[l-1].GetType().Decimal)\n\t\tflen = mathutil.Max(flen, args[l-1].GetType().Flen)\n\t\tisBinaryStr = isBinaryStr || types.IsBinaryStr(args[l-1].GetType())\n\t\tisBinaryFlag = isBinaryFlag || !types.IsNonBinaryStr(args[l-1].GetType())\n\t}\n\n\tfieldTp := types.AggFieldType(fieldTps)\n\ttp := fieldTp.EvalType()\n\n\tif tp == types.ETInt {\n\t\tdecimal = 0\n\t}\n\tfieldTp.Decimal, fieldTp.Flen = decimal, flen\n\tif fieldTp.EvalType().IsStringKind() && !isBinaryStr {\n\t\tfieldTp.Charset, fieldTp.Collate = charset.CharsetUTF8MB4, charset.CollationUTF8MB4\n\t}\n\tif isBinaryFlag {\n\t\tfieldTp.Flag |= mysql.BinaryFlag\n\t}\n\t// Set retType to BINARY(0) if all arguments are of type NULL.\n\tif fieldTp.Tp == mysql.TypeNull {\n\t\tfieldTp.Flen, fieldTp.Decimal = 0, -1\n\t\ttypes.SetBinChsClnFlag(fieldTp)\n\t}\n\targTps := make([]types.EvalType, 0, l)\n\tfor i := 0; i < l-1; i += 2 {\n\t\targTps = append(argTps, types.ETInt, tp)\n\t}\n\tif l%2 == 1 {\n\t\targTps = append(argTps, tp)\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, tp, argTps...)\n\tbf.tp = fieldTp\n\n\tswitch tp {\n\tcase types.ETInt:\n\t\tbf.tp.Decimal = 0\n\t\tsig = &builtinCaseWhenIntSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_CaseWhenInt)\n\tcase types.ETReal:\n\t\tsig = &builtinCaseWhenRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_CaseWhenReal)\n\tcase types.ETDecimal:\n\t\tsig = &builtinCaseWhenDecimalSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_CaseWhenDecimal)\n\tcase types.ETString:\n\t\tbf.tp.Decimal = types.UnspecifiedLength\n\t\tsig = &builtinCaseWhenStringSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_CaseWhenString)\n\t//case types.ETDatetime, types.ETTimestamp:\n\t//\tsig = &builtinCaseWhenTimeSig{bf}\n\t//\tsig.setPbCode(tipb.ScalarFuncSig_CaseWhenTime)\n\t//case types.ETDuration:\n\t//\tsig = &builtinCaseWhenDurationSig{bf}\n\t//\tsig.setPbCode(tipb.ScalarFuncSig_CaseWhenDuration)\n\t//case types.ETJson:\n\t//\tsig = &builtinCaseWhenJSONSig{bf}\n\t//\tsig.setPbCode(tipb.ScalarFuncSig_CaseWhenJson)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"caseWhenFunctionClass.getFunction: unsupported type %v\", tp)\n\n\t}\n\treturn sig, nil\n}\n\ntype builtinCaseWhenIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCaseWhenIntSig) Clone() builtinFunc {\n\tnewSig := &builtinCaseWhenIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals a builtinCaseWhenIntSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/case.html\nfunc (b *builtinCaseWhenIntSig) evalInt(row chunk.Row) (ret int64, isNull bool, err error) {\n\tvar condition int64\n\targs, l := b.getArgs(), len(b.getArgs())\n\tfor i := 0; i < l-1; i += 2 {\n\t\tcondition, isNull, err = args[i].EvalInt(b.ctx, row)\n\t\tif err != nil {\n\t\t\treturn 0, isNull, err\n\t\t}\n\t\tif isNull || condition == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tret, isNull, err = args[i+1].EvalInt(b.ctx, row)\n\t\treturn ret, isNull, err\n\t}\n\t// when clause(condition, result) -> args[i], args[i+1]; (i >= 0 && i+1 < l-1)\n\t// else clause -> args[l-1]\n\t// If case clause has else clause, l%2 == 1.\n\tif l%2 == 1 {\n\t\tret, isNull, err = args[l-1].EvalInt(b.ctx, row)\n\t\treturn ret, isNull, err\n\t}\n\treturn ret, true, nil\n}\n\ntype builtinCaseWhenRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCaseWhenRealSig) Clone() builtinFunc {\n\tnewSig := &builtinCaseWhenRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinCaseWhenRealSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/case.html\nfunc (b *builtinCaseWhenRealSig) evalReal(row chunk.Row) (ret float64, isNull bool, err error) {\n\tvar condition int64\n\targs, l := b.getArgs(), len(b.getArgs())\n\tfor i := 0; i < l-1; i += 2 {\n\t\tcondition, isNull, err = args[i].EvalInt(b.ctx, row)\n\t\tif err != nil {\n\t\t\treturn 0, isNull, err\n\t\t}\n\t\tif isNull || condition == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tret, isNull, err = args[i+1].EvalReal(b.ctx, row)\n\t\treturn ret, isNull, err\n\t}\n\t// when clause(condition, result) -> args[i], args[i+1]; (i >= 0 && i+1 < l-1)\n\t// else clause -> args[l-1]\n\t// If case clause has else clause, l%2 == 1.\n\tif l%2 == 1 {\n\t\tret, isNull, err = args[l-1].EvalReal(b.ctx, row)\n\t\treturn ret, isNull, err\n\t}\n\treturn ret, true, nil\n}\n\ntype builtinCaseWhenDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCaseWhenDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinCaseWhenDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals a builtinCaseWhenDecimalSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/case.html\nfunc (b *builtinCaseWhenDecimalSig) evalDecimal(row chunk.Row) (ret *types.MyDecimal, isNull bool, err error) {\n\tvar condition int64\n\targs, l := b.getArgs(), len(b.getArgs())\n\tfor i := 0; i < l-1; i += 2 {\n\t\tcondition, isNull, err = args[i].EvalInt(b.ctx, row)\n\t\tif err != nil {\n\t\t\treturn nil, isNull, err\n\t\t}\n\t\tif isNull || condition == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tret, isNull, err = args[i+1].EvalDecimal(b.ctx, row)\n\t\treturn ret, isNull, err\n\t}\n\t// when clause(condition, result) -> args[i], args[i+1]; (i >= 0 && i+1 < l-1)\n\t// else clause -> args[l-1]\n\t// If case clause has else clause, l%2 == 1.\n\tif l%2 == 1 {\n\t\tret, isNull, err = args[l-1].EvalDecimal(b.ctx, row)\n\t\treturn ret, isNull, err\n\t}\n\treturn ret, true, nil\n}\n\ntype builtinCaseWhenStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCaseWhenStringSig) Clone() builtinFunc {\n\tnewSig := &builtinCaseWhenStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals a builtinCaseWhenStringSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/case.html\nfunc (b *builtinCaseWhenStringSig) evalString(row chunk.Row) (ret string, isNull bool, err error) {\n\tvar condition int64\n\targs, l := b.getArgs(), len(b.getArgs())\n\tfor i := 0; i < l-1; i += 2 {\n\t\tcondition, isNull, err = args[i].EvalInt(b.ctx, row)\n\t\tif err != nil {\n\t\t\treturn \"\", isNull, err\n\t\t}\n\t\tif isNull || condition == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tret, isNull, err = args[i+1].EvalString(b.ctx, row)\n\t\treturn ret, isNull, err\n\t}\n\t// when clause(condition, result) -> args[i], args[i+1]; (i >= 0 && i+1 < l-1)\n\t// else clause -> args[l-1]\n\t// If case clause has else clause, l%2 == 1.\n\tif l%2 == 1 {\n\t\tret, isNull, err = args[l-1].EvalString(b.ctx, row)\n\t\treturn ret, isNull, err\n\t}\n\treturn ret, true, nil\n}\n\ntype ifFunctionClass struct {\n\tbaseFunctionClass\n}\n\n// getFunction see https://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html#function_if\nfunc (c *ifFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tretTp := InferType4ControlFuncs(args[1].GetType(), args[2].GetType())\n\tevalTps := retTp.EvalType()\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, evalTps, types.ETInt, evalTps, evalTps)\n\tretTp.Flag |= bf.tp.Flag\n\tbf.tp = retTp\n\tswitch evalTps {\n\tcase types.ETInt:\n\t\tsig = &builtinIfIntSig{bf}\n\t\t// sig.setPbCode(tipb.ScalarFuncSig_IfInt)\n\tcase types.ETReal:\n\t\tsig = &builtinIfRealSig{bf}\n\t\t// sig.setPbCode(tipb.ScalarFuncSig_IfReal)\n\tcase types.ETDecimal:\n\t\tsig = &builtinIfDecimalSig{bf}\n\t\t// sig.setPbCode(tipb.ScalarFuncSig_IfDecimal)\n\tcase types.ETString:\n\t\tsig = &builtinIfStringSig{bf}\n\t\t// sig.setPbCode(tipb.ScalarFuncSig_IfString)\n\tcase types.ETDatetime, types.ETTimestamp, types.ETDuration, types.ETJson:\n\t\treturn nil, fmt.Errorf(\"unsupported type %v of if function\", evalTps)\n\t}\n\treturn sig, nil\n}\n\ntype builtinIfIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinIfIntSig) Clone() builtinFunc {\n\tnewSig := &builtinIfIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinIfIntSig) evalInt(row chunk.Row) (ret int64, isNull bool, err error) {\n\targ0, isNull0, err := b.args[0].EvalInt(b.ctx, row)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\targ1, isNull1, err := b.args[1].EvalInt(b.ctx, row)\n\tif (!isNull0 && arg0 != 0) || err != nil {\n\t\treturn arg1, isNull1, err\n\t}\n\targ2, isNull2, err := b.args[2].EvalInt(b.ctx, row)\n\treturn arg2, isNull2, err\n}\n\ntype builtinIfRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinIfRealSig) Clone() builtinFunc {\n\tnewSig := &builtinIfRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinIfRealSig) evalReal(row chunk.Row) (ret float64, isNull bool, err error) {\n\targ0, isNull0, err := b.args[0].EvalInt(b.ctx, row)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\targ1, isNull1, err := b.args[1].EvalReal(b.ctx, row)\n\tif (!isNull0 && arg0 != 0) || err != nil {\n\t\treturn arg1, isNull1, err\n\t}\n\targ2, isNull2, err := b.args[2].EvalReal(b.ctx, row)\n\treturn arg2, isNull2, err\n}\n\ntype builtinIfDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinIfDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinIfDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinIfDecimalSig) evalDecimal(row chunk.Row) (ret *types.MyDecimal, isNull bool, err error) {\n\targ0, isNull0, err := b.args[0].EvalInt(b.ctx, row)\n\tif err != nil {\n\t\treturn nil, true, err\n\t}\n\targ1, isNull1, err := b.args[1].EvalDecimal(b.ctx, row)\n\tif (!isNull0 && arg0 != 0) || err != nil {\n\t\treturn arg1, isNull1, err\n\t}\n\targ2, isNull2, err := b.args[2].EvalDecimal(b.ctx, row)\n\treturn arg2, isNull2, err\n}\n\ntype builtinIfStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinIfStringSig) Clone() builtinFunc {\n\tnewSig := &builtinIfStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinIfStringSig) evalString(row chunk.Row) (ret string, isNull bool, err error) {\n\targ0, isNull0, err := b.args[0].EvalInt(b.ctx, row)\n\tif err != nil {\n\t\treturn \"\", true, err\n\t}\n\targ1, isNull1, err := b.args[1].EvalString(b.ctx, row)\n\tif (!isNull0 && arg0 != 0) || err != nil {\n\t\treturn arg1, isNull1, err\n\t}\n\targ2, isNull2, err := b.args[2].EvalString(b.ctx, row)\n\treturn arg2, isNull2, err\n}\n\ntype ifNullFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *ifNullFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tlhs, rhs := args[0].GetType(), args[1].GetType()\n\tretTp := InferType4ControlFuncs(lhs, rhs)\n\tretTp.Flag |= (lhs.Flag & mysql.NotNullFlag) | (rhs.Flag & mysql.NotNullFlag)\n\tif lhs.Tp == mysql.TypeNull && rhs.Tp == mysql.TypeNull {\n\t\tretTp.Tp = mysql.TypeNull\n\t\tretTp.Flen, retTp.Decimal = 0, -1\n\t\ttypes.SetBinChsClnFlag(retTp)\n\t}\n\tevalTps := retTp.EvalType()\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, evalTps, evalTps, evalTps)\n\tbf.tp = retTp\n\tswitch evalTps {\n\tcase types.ETInt:\n\t\tsig = &builtinIfNullIntSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_IfNullInt)\n\tcase types.ETReal:\n\t\tsig = &builtinIfNullRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_IfNullReal)\n\tcase types.ETDecimal:\n\t\tsig = &builtinIfNullDecimalSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_IfNullDecimal)\n\tcase types.ETString:\n\t\tsig = &builtinIfNullStringSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_IfNullString)\n\tcase types.ETDatetime, types.ETTimestamp, types.ETDuration, types.ETJson:\n\t\treturn nil, fmt.Errorf(\"unsupported type %v of ifnull function\", evalTps)\n\t}\n\treturn sig, nil\n}\n\ntype builtinIfNullIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinIfNullIntSig) Clone() builtinFunc {\n\tnewSig := &builtinIfNullIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinIfNullIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\targ0, isNull, err := b.args[0].EvalInt(b.ctx, row)\n\tif !isNull || err != nil {\n\t\treturn arg0, err != nil, err\n\t}\n\targ1, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\treturn arg1, isNull || err != nil, err\n}\n\ntype builtinIfNullRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinIfNullRealSig) Clone() builtinFunc {\n\tnewSig := &builtinIfNullRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinIfNullRealSig) evalReal(row chunk.Row) (float64, bool, error) {\n\targ0, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif !isNull || err != nil {\n\t\treturn arg0, err != nil, err\n\t}\n\targ1, isNull, err := b.args[1].EvalReal(b.ctx, row)\n\treturn arg1, isNull || err != nil, err\n}\n\ntype builtinIfNullDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinIfNullDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinIfNullDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinIfNullDecimalSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\targ0, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif !isNull || err != nil {\n\t\treturn arg0, err != nil, err\n\t}\n\targ1, isNull, err := b.args[1].EvalDecimal(b.ctx, row)\n\treturn arg1, isNull || err != nil, err\n}\n\ntype builtinIfNullStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinIfNullStringSig) Clone() builtinFunc {\n\tnewSig := &builtinIfNullStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinIfNullStringSig) evalString(row chunk.Row) (string, bool, error) {\n\targ0, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif !isNull || err != nil {\n\t\treturn arg0, err != nil, err\n\t}\n\targ1, isNull, err := b.args[1].EvalString(b.ctx, row)\n\treturn arg1, isNull || err != nil, err\n}\n"
  },
  {
    "path": "pkg/expression/builtin_like.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"regexp\"\n\t\"sync\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n\t\"github.com/secretflow/scql/pkg/util/stringutil\"\n)\n\nvar (\n\t_ functionClass = &likeFunctionClass{}\n\t_ functionClass = &regexpFunctionClass{}\n)\n\nvar (\n\t_ builtinFunc = &builtinLikeSig{}\n\t_ builtinFunc = &builtinRegexpSig{}\n\t_ builtinFunc = &builtinRegexpUTF8Sig{}\n)\n\ntype likeFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *likeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\targTp := []types.EvalType{types.ETString, types.ETString, types.ETInt}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, argTp...)\n\tbf.tp.Flen = 1\n\tbf.tp.Flag |= mysql.IsBooleanFlag\n\tsig := &builtinLikeSig{bf, nil, false, sync.Once{}}\n\t//sig.setPbCode(tipb.ScalarFuncSig_LikeSig)\n\treturn sig, nil\n}\n\ntype builtinLikeSig struct {\n\tbaseBuiltinFunc\n\t// pattern and isMemorizedPattern is not serialized with builtinLikeSig, treat them as a cache to accelerate\n\t// the evaluation of builtinLikeSig.\n\tpattern            WildcardPattern\n\tisMemorizedPattern bool\n\tonce               sync.Once\n}\n\nfunc (b *builtinLikeSig) Clone() builtinFunc {\n\tnewSig := &builtinLikeSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\tnewSig.pattern = b.pattern\n\tnewSig.isMemorizedPattern = b.isMemorizedPattern\n\treturn newSig\n}\n\n// evalInt evals a builtinLikeSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/string-comparison-functions.html#operator_like\nfunc (b *builtinLikeSig) evalInt(row chunk.Row) (int64, bool, error) {\n\tvalStr, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\tpatternStr, isNull, err := b.args[1].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tescape, isNull, err := b.args[2].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tmemorization := func() {\n\t\tif b.pattern == nil {\n\t\t\tif b.args[1].ConstItem(b.ctx.GetSessionVars().StmtCtx) && b.args[2].ConstItem(b.ctx.GetSessionVars().StmtCtx) {\n\t\t\t\tb.pattern.Compile(patternStr, byte(escape))\n\t\t\t\tb.isMemorizedPattern = true\n\t\t\t}\n\t\t}\n\t}\n\t// Only be executed once to achieve thread-safe\n\tb.once.Do(memorization)\n\tif !b.isMemorizedPattern {\n\t\t// Must not use b.pattern to avoid data race\n\t\tpattern := b.pattern\n\t\tpattern.Compile(patternStr, byte(escape))\n\t\treturn boolToInt64(pattern.DoMatch(valStr)), false, nil\n\t}\n\treturn boolToInt64(b.pattern.DoMatch(valStr)), false, nil\n}\n\ntype regexpFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *regexpFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETString, types.ETString)\n\tbf.tp.Flen = 1\n\tbf.tp.Flag |= mysql.IsBooleanFlag\n\tvar sig builtinFunc\n\tsig = newBuiltinRegexpSig(bf)\n\t//sig.setPbCode(tipb.ScalarFuncSig_RegexpSig)\n\treturn sig, nil\n}\n\ntype builtinRegexpSharedSig struct {\n\tbaseBuiltinFunc\n\tcompile         func(string) (*regexp.Regexp, error)\n\tmemorizedRegexp *regexp.Regexp\n\tmemorizedErr    error\n}\n\nfunc (b *builtinRegexpSharedSig) clone(from *builtinRegexpSharedSig) {\n\tb.cloneFrom(&from.baseBuiltinFunc)\n\tb.compile = from.compile\n\tif from.memorizedRegexp != nil {\n\t\tb.memorizedRegexp = from.memorizedRegexp.Copy()\n\t}\n\tb.memorizedErr = from.memorizedErr\n}\n\n// evalInt evals `expr REGEXP pat`, or `expr RLIKE pat`.\n// See https://dev.mysql.com/doc/refman/5.7/en/regexp.html#operator_regexp\nfunc (b *builtinRegexpSharedSig) evalInt(row chunk.Row) (int64, bool, error) {\n\texpr, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, true, err\n\t}\n\n\tpat, isNull, err := b.args[1].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, true, err\n\t}\n\n\tre, err := b.compile(pat)\n\tif err != nil {\n\t\treturn 0, true, ErrRegexp.GenWithStackByArgs(err.Error())\n\t}\n\treturn boolToInt64(re.MatchString(expr)), false, nil\n}\n\ntype builtinRegexpSig struct {\n\tbuiltinRegexpSharedSig\n}\n\nfunc newBuiltinRegexpSig(bf baseBuiltinFunc) *builtinRegexpSig {\n\tshared := builtinRegexpSharedSig{baseBuiltinFunc: bf}\n\tshared.compile = regexp.Compile\n\treturn &builtinRegexpSig{builtinRegexpSharedSig: shared}\n}\n\nfunc (b *builtinRegexpSig) Clone() builtinFunc {\n\tnewSig := &builtinRegexpSig{}\n\tnewSig.clone(&b.builtinRegexpSharedSig)\n\treturn newSig\n}\n\ntype builtinRegexpUTF8Sig struct {\n\tbuiltinRegexpSharedSig\n}\n\nfunc newBuiltinRegexpUTF8Sig(bf baseBuiltinFunc) *builtinRegexpUTF8Sig {\n\tshared := builtinRegexpSharedSig{baseBuiltinFunc: bf}\n\tshared.compile = regexp.Compile\n\treturn &builtinRegexpUTF8Sig{builtinRegexpSharedSig: shared}\n}\n\nfunc (b *builtinRegexpUTF8Sig) Clone() builtinFunc {\n\tnewSig := &builtinRegexpUTF8Sig{}\n\tnewSig.clone(&b.builtinRegexpSharedSig)\n\treturn newSig\n}\n\n// WildcardPattern is the interface used for wildcard pattern match.\ntype WildcardPattern interface {\n\t// Compile compiles the patternStr with specified escape character.\n\tCompile(patternStr string, escape byte)\n\t// DoMatch tries to match the str with compiled pattern, `Compile()` must be called before calling it.\n\tDoMatch(str string) bool\n}\n\ntype binPattern struct {\n\tpatChars []byte\n\tpatTypes []byte\n}\n\n// Compile implements WildcardPattern interface.\nfunc (p *binPattern) Compile(patternStr string, escape byte) {\n\tp.patChars, p.patTypes = stringutil.CompilePattern(patternStr, escape)\n}\n\n// Compile implements WildcardPattern interface.\nfunc (p *binPattern) DoMatch(str string) bool {\n\treturn stringutil.DoMatch(str, p.patChars, p.patTypes)\n}\n"
  },
  {
    "path": "pkg/expression/builtin_math.go",
    "content": "// Copyright 2013 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\t\"hash/crc32\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/cznic/mathutil\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n)\n\nvar (\n\t_ functionClass = &absFunctionClass{}\n\t_ functionClass = &roundFunctionClass{}\n\t_ functionClass = &ceilFunctionClass{}\n\t_ functionClass = &floorFunctionClass{}\n\t_ functionClass = &logFunctionClass{}\n\t_ functionClass = &log2FunctionClass{}\n\t_ functionClass = &log10FunctionClass{}\n\t_ functionClass = &randFunctionClass{}\n\t_ functionClass = &powFunctionClass{}\n\t_ functionClass = &convFunctionClass{}\n\t_ functionClass = &crc32FunctionClass{}\n\t_ functionClass = &signFunctionClass{}\n\t_ functionClass = &sqrtFunctionClass{}\n\t_ functionClass = &acosFunctionClass{}\n\t_ functionClass = &asinFunctionClass{}\n\t_ functionClass = &atanFunctionClass{}\n\t_ functionClass = &cosFunctionClass{}\n\t_ functionClass = &cotFunctionClass{}\n\t_ functionClass = &degreesFunctionClass{}\n\t_ functionClass = &expFunctionClass{}\n\t_ functionClass = &piFunctionClass{}\n\t_ functionClass = &radiansFunctionClass{}\n\t_ functionClass = &sinFunctionClass{}\n\t_ functionClass = &tanFunctionClass{}\n\t_ functionClass = &truncateFunctionClass{}\n)\n\nvar (\n\t_ builtinFunc = &builtinAbsRealSig{}\n\t_ builtinFunc = &builtinAbsIntSig{}\n\t_ builtinFunc = &builtinAbsUIntSig{}\n\t_ builtinFunc = &builtinAbsDecSig{}\n\t_ builtinFunc = &builtinRoundRealSig{}\n\t_ builtinFunc = &builtinRoundIntSig{}\n\t_ builtinFunc = &builtinRoundDecSig{}\n\t_ builtinFunc = &builtinRoundWithFracRealSig{}\n\t_ builtinFunc = &builtinRoundWithFracIntSig{}\n\t_ builtinFunc = &builtinRoundWithFracDecSig{}\n\t_ builtinFunc = &builtinCeilRealSig{}\n\t_ builtinFunc = &builtinCeilIntToDecSig{}\n\t_ builtinFunc = &builtinCeilIntToIntSig{}\n\t_ builtinFunc = &builtinCeilDecToIntSig{}\n\t_ builtinFunc = &builtinCeilDecToDecSig{}\n\t_ builtinFunc = &builtinFloorRealSig{}\n\t_ builtinFunc = &builtinFloorIntToDecSig{}\n\t_ builtinFunc = &builtinFloorIntToIntSig{}\n\t_ builtinFunc = &builtinFloorDecToIntSig{}\n\t_ builtinFunc = &builtinFloorDecToDecSig{}\n\t_ builtinFunc = &builtinLog1ArgSig{}\n\t_ builtinFunc = &builtinLog2ArgsSig{}\n\t_ builtinFunc = &builtinLog2Sig{}\n\t_ builtinFunc = &builtinLog10Sig{}\n\t_ builtinFunc = &builtinRandSig{}\n\t_ builtinFunc = &builtinRandWithSeedFirstGenSig{}\n\t_ builtinFunc = &builtinPowSig{}\n\t_ builtinFunc = &builtinConvSig{}\n\t_ builtinFunc = &builtinCRC32Sig{}\n\t_ builtinFunc = &builtinSignSig{}\n\t_ builtinFunc = &builtinSqrtSig{}\n\t_ builtinFunc = &builtinAcosSig{}\n\t_ builtinFunc = &builtinAsinSig{}\n\t_ builtinFunc = &builtinAtan1ArgSig{}\n\t_ builtinFunc = &builtinAtan2ArgsSig{}\n\t_ builtinFunc = &builtinCosSig{}\n\t_ builtinFunc = &builtinCotSig{}\n\t_ builtinFunc = &builtinDegreesSig{}\n\t_ builtinFunc = &builtinExpSig{}\n\t_ builtinFunc = &builtinPISig{}\n\t_ builtinFunc = &builtinRadiansSig{}\n\t_ builtinFunc = &builtinSinSig{}\n\t_ builtinFunc = &builtinTanSig{}\n\t_ builtinFunc = &builtinTruncateIntSig{}\n\t_ builtinFunc = &builtinTruncateRealSig{}\n\t_ builtinFunc = &builtinTruncateDecimalSig{}\n\t_ builtinFunc = &builtinTruncateUintSig{}\n)\n\ntype absFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *absFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, c.verifyArgs(args)\n\t}\n\n\targFieldTp := args[0].GetType()\n\targTp := argFieldTp.EvalType()\n\tif argTp != types.ETInt && argTp != types.ETDecimal {\n\t\targTp = types.ETReal\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, argTp, argTp)\n\tif mysql.HasUnsignedFlag(argFieldTp.Flag) {\n\t\tbf.tp.Flag |= mysql.UnsignedFlag\n\t}\n\tif argTp == types.ETReal {\n\t\tbf.tp.Flen, bf.tp.Decimal = mysql.GetDefaultFieldLengthAndDecimal(mysql.TypeDouble)\n\t} else {\n\t\tbf.tp.Flen = argFieldTp.Flen\n\t\tbf.tp.Decimal = argFieldTp.Decimal\n\t}\n\tvar sig builtinFunc\n\tswitch argTp {\n\tcase types.ETInt:\n\t\tif mysql.HasUnsignedFlag(argFieldTp.Flag) {\n\t\t\tsig = &builtinAbsUIntSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_AbsUInt)\n\t\t} else {\n\t\t\tsig = &builtinAbsIntSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_AbsInt)\n\t\t}\n\tcase types.ETDecimal:\n\t\tsig = &builtinAbsDecSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_AbsDecimal)\n\tcase types.ETReal:\n\t\tsig = &builtinAbsRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_AbsReal)\n\tdefault:\n\t\tpanic(\"unexpected argTp\")\n\t}\n\treturn sig, nil\n}\n\ntype builtinAbsRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinAbsRealSig) Clone() builtinFunc {\n\tnewSig := &builtinAbsRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals ABS(value).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_abs\nfunc (b *builtinAbsRealSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn math.Abs(val), false, nil\n}\n\ntype builtinAbsIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinAbsIntSig) Clone() builtinFunc {\n\tnewSig := &builtinAbsIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals ABS(value).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_abs\nfunc (b *builtinAbsIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\tval, isNull, err := b.args[0].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val >= 0 {\n\t\treturn val, false, nil\n\t}\n\tif val == math.MinInt64 {\n\t\treturn 0, false, types.ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"abs(%d)\", val))\n\t}\n\treturn -val, false, nil\n}\n\ntype builtinAbsUIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinAbsUIntSig) Clone() builtinFunc {\n\tnewSig := &builtinAbsUIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals ABS(value).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_abs\nfunc (b *builtinAbsUIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\treturn b.args[0].EvalInt(b.ctx, row)\n}\n\ntype builtinAbsDecSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinAbsDecSig) Clone() builtinFunc {\n\tnewSig := &builtinAbsDecSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals ABS(value).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_abs\nfunc (b *builtinAbsDecSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\tval, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\tto := new(types.MyDecimal)\n\tif !val.IsNegative() {\n\t\t*to = *val\n\t} else {\n\t\tif err = types.DecimalSub(new(types.MyDecimal), val, to); err != nil {\n\t\t\treturn nil, true, err\n\t\t}\n\t}\n\treturn to, false, nil\n}\n\nfunc (c *roundFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, c.verifyArgs(args)\n\t}\n\t// NOTE(shunde.csd): In SCQL, ROUND return type is always INTEGER, which differs from TiDB/MySQL\n\targTp := types.ETInt\n\tif argTp != types.ETInt && argTp != types.ETDecimal {\n\t\targTp = types.ETReal\n\t}\n\targTps := []types.EvalType{argTp}\n\tif len(args) > 1 {\n\t\targTps = append(argTps, types.ETInt)\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, argTp, argTps...)\n\targFieldTp := args[0].GetType()\n\tif mysql.HasUnsignedFlag(argFieldTp.Flag) {\n\t\tbf.tp.Flag |= mysql.UnsignedFlag\n\t}\n\n\tbf.tp.Flen = argFieldTp.Flen\n\tbf.tp.Decimal = calculateDecimal4RoundAndTruncate(ctx, args, argTp)\n\tif bf.tp.Decimal != types.UnspecifiedLength {\n\t\tif argFieldTp.Decimal != types.UnspecifiedLength {\n\t\t\tdecimalDelta := bf.tp.Decimal - argFieldTp.Decimal\n\t\t\tbf.tp.Flen += mathutil.Max(decimalDelta, 0)\n\t\t} else {\n\t\t\tbf.tp.Flen = argFieldTp.Flen + bf.tp.Decimal\n\t\t}\n\t}\n\n\tvar sig builtinFunc\n\tif len(args) > 1 {\n\t\tswitch argTp {\n\t\tcase types.ETInt:\n\t\t\tsig = &builtinRoundWithFracIntSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_RoundWithFracInt)\n\t\tcase types.ETDecimal:\n\t\t\tsig = &builtinRoundWithFracDecSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_RoundWithFracDec)\n\t\tcase types.ETReal:\n\t\t\tsig = &builtinRoundWithFracRealSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_RoundWithFracReal)\n\t\tdefault:\n\t\t\tpanic(\"unexpected argTp\")\n\t\t}\n\t} else {\n\t\tswitch argTp {\n\t\tcase types.ETInt:\n\t\t\tsig = &builtinRoundIntSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_RoundInt)\n\t\tcase types.ETDecimal:\n\t\t\tsig = &builtinRoundDecSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_RoundDec)\n\t\tcase types.ETReal:\n\t\t\tsig = &builtinRoundRealSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_RoundReal)\n\t\tdefault:\n\t\t\tpanic(\"unexpected argTp\")\n\t\t}\n\t}\n\treturn sig, nil\n}\n\n// calculateDecimal4RoundAndTruncate calculates tp.decimals of round/truncate func.\nfunc calculateDecimal4RoundAndTruncate(ctx sessionctx.Context, args []Expression, retType types.EvalType) int {\n\tif retType == types.ETInt || len(args) <= 1 {\n\t\treturn 0\n\t}\n\tsecondConst, secondIsConst := args[1].(*Constant)\n\tif !secondIsConst {\n\t\treturn args[0].GetType().Decimal\n\t}\n\targDec, isNull, err := secondConst.EvalInt(ctx, chunk.Row{})\n\tif err != nil || isNull || argDec < 0 {\n\t\treturn 0\n\t}\n\tif argDec > mysql.MaxDecimalScale {\n\t\treturn mysql.MaxDecimalScale\n\t}\n\treturn int(argDec)\n}\n\ntype builtinRoundRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinRoundRealSig) Clone() builtinFunc {\n\tnewSig := &builtinRoundRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals ROUND(value).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_round\nfunc (b *builtinRoundRealSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn types.Round(val, 0), false, nil\n}\n\ntype builtinRoundIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinRoundIntSig) Clone() builtinFunc {\n\tnewSig := &builtinRoundIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals ROUND(value).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_round\nfunc (b *builtinRoundIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\treturn b.args[0].EvalInt(b.ctx, row)\n}\n\ntype builtinRoundDecSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinRoundDecSig) Clone() builtinFunc {\n\tnewSig := &builtinRoundDecSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals ROUND(value).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_round\nfunc (b *builtinRoundDecSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\tval, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\tto := new(types.MyDecimal)\n\tif err = val.Round(to, 0, types.ModeHalfEven); err != nil {\n\t\treturn nil, true, err\n\t}\n\treturn to, false, nil\n}\n\ntype builtinRoundWithFracRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinRoundWithFracRealSig) Clone() builtinFunc {\n\tnewSig := &builtinRoundWithFracRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals ROUND(value, frac).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_round\nfunc (b *builtinRoundWithFracRealSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tfrac, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn types.Round(val, int(frac)), false, nil\n}\n\ntype builtinRoundWithFracIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinRoundWithFracIntSig) Clone() builtinFunc {\n\tnewSig := &builtinRoundWithFracIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals ROUND(value, frac).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_round\nfunc (b *builtinRoundWithFracIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\tval, isNull, err := b.args[0].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tfrac, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn int64(types.Round(float64(val), int(frac))), false, nil\n}\n\ntype builtinRoundWithFracDecSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinRoundWithFracDecSig) Clone() builtinFunc {\n\tnewSig := &builtinRoundWithFracDecSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals ROUND(value, frac).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_round\nfunc (b *builtinRoundWithFracDecSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\tval, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\tfrac, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\tto := new(types.MyDecimal)\n\tif err = val.Round(to, mathutil.Min(int(frac), b.tp.Decimal), types.ModeHalfEven); err != nil {\n\t\treturn nil, true, err\n\t}\n\treturn to, false, nil\n}\n\ntype ceilFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *ceilFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\tretTp, argTp := getEvalTp4FloorAndCeil(args[0])\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, retTp, argTp)\n\tsetFlag4FloorAndCeil(bf.tp, args[0])\n\targFieldTp := args[0].GetType()\n\tbf.tp.Flen, bf.tp.Decimal = argFieldTp.Flen, 0\n\n\tswitch argTp {\n\tcase types.ETInt:\n\t\tif retTp == types.ETInt {\n\t\t\tsig = &builtinCeilIntToIntSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_CeilIntToInt)\n\t\t} else {\n\t\t\tsig = &builtinCeilIntToDecSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_CeilIntToDec)\n\t\t}\n\tcase types.ETDecimal:\n\t\tif retTp == types.ETInt {\n\t\t\tsig = &builtinCeilDecToIntSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_CeilDecToInt)\n\t\t} else {\n\t\t\tsig = &builtinCeilDecToDecSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_CeilDecToDec)\n\t\t}\n\tdefault:\n\t\tsig = &builtinCeilRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_CeilReal)\n\t}\n\treturn sig, nil\n}\n\ntype builtinCeilRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCeilRealSig) Clone() builtinFunc {\n\tnewSig := &builtinCeilRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinCeilRealSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_ceil\nfunc (b *builtinCeilRealSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn math.Ceil(val), false, nil\n}\n\ntype builtinCeilIntToIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCeilIntToIntSig) Clone() builtinFunc {\n\tnewSig := &builtinCeilIntToIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals a builtinCeilIntToIntSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_ceil\nfunc (b *builtinCeilIntToIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\treturn b.args[0].EvalInt(b.ctx, row)\n}\n\ntype builtinCeilIntToDecSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCeilIntToDecSig) Clone() builtinFunc {\n\tnewSig := &builtinCeilIntToDecSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals a builtinCeilIntToDecSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_Ceil\nfunc (b *builtinCeilIntToDecSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\tval, isNull, err := b.args[0].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, true, err\n\t}\n\n\tif mysql.HasUnsignedFlag(b.args[0].GetType().Flag) || val >= 0 {\n\t\treturn types.NewDecFromUint(uint64(val)), false, nil\n\t}\n\treturn types.NewDecFromInt(val), false, nil\n}\n\ntype builtinCeilDecToIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCeilDecToIntSig) Clone() builtinFunc {\n\tnewSig := &builtinCeilDecToIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals a builtinCeilDecToIntSig.\n// Ceil receives\nfunc (b *builtinCeilDecToIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\tval, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\t// err here will only be ErrOverFlow(will never happen) or ErrTruncate(can be ignored).\n\tres, err := val.ToInt()\n\tif err == types.ErrTruncated {\n\t\terr = nil\n\t\tif !val.IsNegative() {\n\t\t\tres = res + 1\n\t\t}\n\t}\n\treturn res, false, err\n}\n\ntype builtinCeilDecToDecSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCeilDecToDecSig) Clone() builtinFunc {\n\tnewSig := &builtinCeilDecToDecSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals a builtinCeilDecToDecSig.\nfunc (b *builtinCeilDecToDecSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\tval, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\n\tres := new(types.MyDecimal)\n\tif val.IsNegative() {\n\t\terr = val.Round(res, 0, types.ModeTruncate)\n\t\treturn res, err != nil, err\n\t}\n\n\terr = val.Round(res, 0, types.ModeTruncate)\n\tif err != nil || res.Compare(val) == 0 {\n\t\treturn res, err != nil, err\n\t}\n\n\terr = types.DecimalAdd(res, types.NewDecFromInt(1), res)\n\treturn res, err != nil, err\n}\n\ntype floorFunctionClass struct {\n\tbaseFunctionClass\n}\n\n// getEvalTp4FloorAndCeil gets the types.EvalType of FLOOR and CEIL.\nfunc getEvalTp4FloorAndCeil(arg Expression) (retTp, argTp types.EvalType) {\n\tfieldTp := arg.GetType()\n\tretTp, argTp = types.ETInt, fieldTp.EvalType()\n\t// NOTE(shunde.csd): In SCQL, FLOOR/CEIL return type is always INTEGER, which differs from TiDB/MySQL\n\tswitch argTp {\n\tcase types.ETInt, types.ETDecimal:\n\t\tretTp = types.ETInt\n\tdefault:\n\t\tretTp, argTp = types.ETInt, types.ETReal\n\t}\n\treturn retTp, argTp\n}\n\n// setFlag4FloorAndCeil sets return flag of FLOOR and CEIL.\nfunc setFlag4FloorAndCeil(tp *types.FieldType, arg Expression) {\n\tfieldTp := arg.GetType()\n\tif (fieldTp.Tp == mysql.TypeLong || fieldTp.Tp == mysql.TypeLonglong || fieldTp.Tp == mysql.TypeNewDecimal) && mysql.HasUnsignedFlag(fieldTp.Flag) {\n\t\ttp.Flag |= mysql.UnsignedFlag\n\t}\n\t// TODO: when argument type is timestamp, add not null flag.\n}\n\nfunc (c *floorFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\tretTp, argTp := getEvalTp4FloorAndCeil(args[0])\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, retTp, argTp)\n\tsetFlag4FloorAndCeil(bf.tp, args[0])\n\tbf.tp.Flen, bf.tp.Decimal = args[0].GetType().Flen, 0\n\tswitch argTp {\n\tcase types.ETInt:\n\t\tif retTp == types.ETInt {\n\t\t\tsig = &builtinFloorIntToIntSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_FloorIntToInt)\n\t\t} else {\n\t\t\tsig = &builtinFloorIntToDecSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_FloorIntToDec)\n\t\t}\n\tcase types.ETDecimal:\n\t\tif retTp == types.ETInt {\n\t\t\tsig = &builtinFloorDecToIntSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_FloorDecToInt)\n\t\t} else {\n\t\t\tsig = &builtinFloorDecToDecSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_FloorDecToDec)\n\t\t}\n\tdefault:\n\t\tsig = &builtinFloorRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_FloorReal)\n\t}\n\treturn sig, nil\n}\n\ntype builtinFloorRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinFloorRealSig) Clone() builtinFunc {\n\tnewSig := &builtinFloorRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinFloorRealSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_floor\nfunc (b *builtinFloorRealSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn math.Floor(val), false, nil\n}\n\ntype builtinFloorIntToIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinFloorIntToIntSig) Clone() builtinFunc {\n\tnewSig := &builtinFloorIntToIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals a builtinFloorIntToIntSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_floor\nfunc (b *builtinFloorIntToIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\treturn b.args[0].EvalInt(b.ctx, row)\n}\n\ntype builtinFloorIntToDecSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinFloorIntToDecSig) Clone() builtinFunc {\n\tnewSig := &builtinFloorIntToDecSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals a builtinFloorIntToDecSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_floor\nfunc (b *builtinFloorIntToDecSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\tval, isNull, err := b.args[0].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, true, err\n\t}\n\n\tif mysql.HasUnsignedFlag(b.args[0].GetType().Flag) || val >= 0 {\n\t\treturn types.NewDecFromUint(uint64(val)), false, nil\n\t}\n\treturn types.NewDecFromInt(val), false, nil\n}\n\ntype builtinFloorDecToIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinFloorDecToIntSig) Clone() builtinFunc {\n\tnewSig := &builtinFloorDecToIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals a builtinFloorDecToIntSig.\n// floor receives\nfunc (b *builtinFloorDecToIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\tval, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\t// err here will only be ErrOverFlow(will never happen) or ErrTruncate(can be ignored).\n\tres, err := val.ToInt()\n\tif err == types.ErrTruncated {\n\t\terr = nil\n\t\tif val.IsNegative() {\n\t\t\tres--\n\t\t}\n\t}\n\treturn res, false, err\n}\n\ntype builtinFloorDecToDecSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinFloorDecToDecSig) Clone() builtinFunc {\n\tnewSig := &builtinFloorDecToDecSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals a builtinFloorDecToDecSig.\nfunc (b *builtinFloorDecToDecSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\tval, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, true, err\n\t}\n\n\tres := new(types.MyDecimal)\n\tif !val.IsNegative() {\n\t\terr = val.Round(res, 0, types.ModeTruncate)\n\t\treturn res, err != nil, err\n\t}\n\n\terr = val.Round(res, 0, types.ModeTruncate)\n\tif err != nil || res.Compare(val) == 0 {\n\t\treturn res, err != nil, err\n\t}\n\n\terr = types.DecimalSub(res, types.NewDecFromInt(1), res)\n\treturn res, err != nil, err\n}\n\ntype logFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *logFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tvar (\n\t\tsig     builtinFunc\n\t\tbf      baseBuiltinFunc\n\t\targsLen = len(args)\n\t)\n\n\tif argsLen == 1 {\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\t} else {\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal, types.ETReal)\n\t}\n\n\tif argsLen == 1 {\n\t\tsig = &builtinLog1ArgSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_Log1Arg)\n\t} else {\n\t\tsig = &builtinLog2ArgsSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_Log2Args)\n\t}\n\n\treturn sig, nil\n}\n\ntype builtinLog1ArgSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLog1ArgSig) Clone() builtinFunc {\n\tnewSig := &builtinLog1ArgSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinLog1ArgSig, corresponding to log(x).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_log\nfunc (b *builtinLog1ArgSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val <= 0 {\n\t\tb.ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInvalidArgumentForLogarithm)\n\t\treturn 0, true, nil\n\t}\n\treturn math.Log(val), false, nil\n}\n\ntype builtinLog2ArgsSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLog2ArgsSig) Clone() builtinFunc {\n\tnewSig := &builtinLog2ArgsSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinLog2ArgsSig, corresponding to log(b, x).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_log\nfunc (b *builtinLog2ArgsSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval1, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\tval2, isNull, err := b.args[1].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\tif val1 <= 0 || val1 == 1 || val2 <= 0 {\n\t\tb.ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInvalidArgumentForLogarithm)\n\t\treturn 0, true, nil\n\t}\n\n\treturn math.Log(val2) / math.Log(val1), false, nil\n}\n\ntype log2FunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *log2FunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinLog2Sig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Log2)\n\treturn sig, nil\n}\n\ntype builtinLog2Sig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLog2Sig) Clone() builtinFunc {\n\tnewSig := &builtinLog2Sig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinLog2Sig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_log2\nfunc (b *builtinLog2Sig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val <= 0 {\n\t\tb.ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInvalidArgumentForLogarithm)\n\t\treturn 0, true, nil\n\t}\n\treturn math.Log2(val), false, nil\n}\n\ntype log10FunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *log10FunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinLog10Sig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Log10)\n\treturn sig, nil\n}\n\ntype builtinLog10Sig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLog10Sig) Clone() builtinFunc {\n\tnewSig := &builtinLog10Sig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinLog10Sig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_log10\nfunc (b *builtinLog10Sig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val <= 0 {\n\t\tb.ctx.GetSessionVars().StmtCtx.AppendWarning(ErrInvalidArgumentForLogarithm)\n\t\treturn 0, true, nil\n\t}\n\treturn math.Log10(val), false, nil\n}\n\ntype randFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *randFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tvar sig builtinFunc\n\tvar argTps []types.EvalType\n\tif len(args) > 0 {\n\t\targTps = []types.EvalType{types.ETInt}\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, argTps...)\n\tbt := bf\n\tif len(args) == 0 {\n\t\tsig = &builtinRandSig{bt, &sync.Mutex{}, NewWithTime()}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_Rand)\n\t} else if _, isConstant := args[0].(*Constant); isConstant {\n\t\t// According to MySQL manual:\n\t\t// If an integer argument N is specified, it is used as the seed value:\n\t\t// With a constant initializer argument, the seed is initialized once\n\t\t// when the statement is prepared, prior to execution.\n\t\tseed, isNull, err := args[0].EvalInt(ctx, chunk.Row{})\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif isNull {\n\t\t\t// When the seed is null we need to use 0 as the seed.\n\t\t\t// The behavior same as MySQL.\n\t\t\tseed = 0\n\t\t}\n\t\tsig = &builtinRandSig{bt, &sync.Mutex{}, NewWithSeed(seed)}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_Rand)\n\t} else {\n\t\tsig = &builtinRandWithSeedFirstGenSig{bt}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_RandWithSeedFirstGen)\n\t}\n\treturn sig, nil\n}\n\ntype builtinRandSig struct {\n\tbaseBuiltinFunc\n\tmu       *sync.Mutex\n\tmysqlRng *MysqlRng\n}\n\nfunc (b *builtinRandSig) Clone() builtinFunc {\n\tnewSig := &builtinRandSig{mysqlRng: b.mysqlRng, mu: b.mu}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals RAND().\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_rand\nfunc (b *builtinRandSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tb.mu.Lock()\n\tres := b.mysqlRng.Gen()\n\tb.mu.Unlock()\n\treturn res, false, nil\n}\n\ntype builtinRandWithSeedFirstGenSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinRandWithSeedFirstGenSig) Clone() builtinFunc {\n\tnewSig := &builtinRandWithSeedFirstGenSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals RAND(N).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_rand\nfunc (b *builtinRandWithSeedFirstGenSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tseed, isNull, err := b.args[0].EvalInt(b.ctx, row)\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\t// b.args[0] is promised to be a non-constant(such as a column name) in\n\t// builtinRandWithSeedFirstGenSig, the seed is initialized with the value for each\n\t// invocation of RAND().\n\tvar rng *MysqlRng\n\tif !isNull {\n\t\trng = NewWithSeed(seed)\n\t} else {\n\t\trng = NewWithSeed(0)\n\t}\n\treturn rng.Gen(), false, nil\n}\n\ntype powFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *powFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal, types.ETReal)\n\tsig := &builtinPowSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Pow)\n\treturn sig, nil\n}\n\ntype builtinPowSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinPowSig) Clone() builtinFunc {\n\tnewSig := &builtinPowSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals POW(x, y).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_pow\nfunc (b *builtinPowSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tx, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\ty, isNull, err := b.args[1].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tpower := math.Pow(x, y)\n\tif math.IsInf(power, -1) || math.IsInf(power, 1) || math.IsNaN(power) {\n\t\treturn 0, false, types.ErrOverflow.GenWithStackByArgs(\"DOUBLE\", fmt.Sprintf(\"pow(%s, %s)\", strconv.FormatFloat(x, 'f', -1, 64), strconv.FormatFloat(y, 'f', -1, 64)))\n\t}\n\treturn power, false, nil\n}\n\ntype roundFunctionClass struct {\n\tbaseFunctionClass\n}\n\ntype convFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *convFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString, types.ETInt, types.ETInt)\n\t//bf.tp.Charset, bf.tp.Collate = ctx.GetSessionVars().GetCharsetInfo()\n\tbf.tp.Flen = 64\n\tsig := &builtinConvSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Conv)\n\treturn sig, nil\n}\n\ntype builtinConvSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinConvSig) Clone() builtinFunc {\n\tnewSig := &builtinConvSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals CONV(N,from_base,to_base).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_conv.\nfunc (b *builtinConvSig) evalString(row chunk.Row) (res string, isNull bool, err error) {\n\tvar str string\n\tswitch x := b.args[0].(type) {\n\tcase *Constant:\n\t\tif x.Value.Kind() == types.KindBinaryLiteral {\n\t\t\tstr = x.Value.GetBinaryLiteral().ToBitLiteralString(true)\n\t\t}\n\tcase *ScalarFunction:\n\t\tif x.FuncName.L == ast.Cast {\n\t\t\targ0 := x.GetArgs()[0]\n\t\t\tif arg0.GetType().Hybrid() || IsBinaryLiteral(arg0) {\n\t\t\t\tstr, isNull, err = arg0.EvalString(b.ctx, row)\n\t\t\t\tif isNull || err != nil {\n\t\t\t\t\treturn str, isNull, err\n\t\t\t\t}\n\t\t\t\td := types.NewStringDatum(str)\n\t\t\t\tstr = d.GetBinaryLiteral().ToBitLiteralString(true)\n\t\t\t}\n\t\t}\n\t}\n\tfromBase, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn res, isNull, err\n\t}\n\n\ttoBase, isNull, err := b.args[2].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn res, isNull, err\n\t}\n\tif len(str) == 0 {\n\t\tstr, isNull, err = b.args[0].EvalString(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn res, isNull, err\n\t\t}\n\t} else {\n\t\tstr, isNull, err = b.conv(str[2:], 2, fromBase)\n\t\tif err != nil {\n\t\t\treturn str, isNull, err\n\t\t}\n\t}\n\treturn b.conv(str, fromBase, toBase)\n}\nfunc (b *builtinConvSig) conv(str string, fromBase, toBase int64) (res string, isNull bool, err error) {\n\tvar (\n\t\tsigned     bool\n\t\tnegative   bool\n\t\tignoreSign bool\n\t)\n\tif fromBase < 0 {\n\t\tfromBase = -fromBase\n\t\tsigned = true\n\t}\n\n\tif toBase < 0 {\n\t\ttoBase = -toBase\n\t\tignoreSign = true\n\t}\n\n\tif fromBase > 36 || fromBase < 2 || toBase > 36 || toBase < 2 {\n\t\treturn res, true, nil\n\t}\n\n\tstr = getValidPrefix(strings.TrimSpace(str), fromBase)\n\tif len(str) == 0 {\n\t\treturn \"0\", false, nil\n\t}\n\n\tif str[0] == '-' {\n\t\tnegative = true\n\t\tstr = str[1:]\n\t}\n\n\tval, err := strconv.ParseUint(str, int(fromBase), 64)\n\tif err != nil {\n\t\treturn res, false, types.ErrOverflow.GenWithStackByArgs(\"BIGINT UNSINGED\", str)\n\t}\n\tif signed {\n\t\tif negative && val > -math.MinInt64 {\n\t\t\tval = -math.MinInt64\n\t\t}\n\t\tif !negative && val > math.MaxInt64 {\n\t\t\tval = math.MaxInt64\n\t\t}\n\t}\n\tif negative {\n\t\tval = -val\n\t}\n\n\tif int64(val) < 0 {\n\t\tnegative = true\n\t} else {\n\t\tnegative = false\n\t}\n\tif ignoreSign && negative {\n\t\tval = 0 - val\n\t}\n\n\ts := strconv.FormatUint(val, int(toBase))\n\tif negative && ignoreSign {\n\t\ts = \"-\" + s\n\t}\n\tres = strings.ToUpper(s)\n\treturn res, false, nil\n}\n\ntype crc32FunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *crc32FunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETString)\n\tbf.tp.Flen = 10\n\tbf.tp.Flag |= mysql.UnsignedFlag\n\tsig := &builtinCRC32Sig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_CRC32)\n\treturn sig, nil\n}\n\ntype builtinCRC32Sig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCRC32Sig) Clone() builtinFunc {\n\tnewSig := &builtinCRC32Sig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals a CRC32(expr).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_crc32\nfunc (b *builtinCRC32Sig) evalInt(row chunk.Row) (int64, bool, error) {\n\tx, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tr := crc32.ChecksumIEEE([]byte(x))\n\treturn int64(r), false, nil\n}\n\ntype signFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *signFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETReal)\n\tsig := &builtinSignSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Sign)\n\treturn sig, nil\n}\n\ntype builtinSignSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinSignSig) Clone() builtinFunc {\n\tnewSig := &builtinSignSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals SIGN(v).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_sign\nfunc (b *builtinSignSig) evalInt(row chunk.Row) (int64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val > 0 {\n\t\treturn 1, false, nil\n\t} else if val == 0 {\n\t\treturn 0, false, nil\n\t} else {\n\t\treturn -1, false, nil\n\t}\n}\n\ntype sqrtFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *sqrtFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinSqrtSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Sqrt)\n\treturn sig, nil\n}\n\ntype builtinSqrtSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinSqrtSig) Clone() builtinFunc {\n\tnewSig := &builtinSqrtSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a SQRT(x).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_sqrt\nfunc (b *builtinSqrtSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val < 0 {\n\t\treturn 0, true, nil\n\t}\n\treturn math.Sqrt(val), false, nil\n}\n\ntype acosFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *acosFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinAcosSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Acos)\n\treturn sig, nil\n}\n\ntype builtinAcosSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinAcosSig) Clone() builtinFunc {\n\tnewSig := &builtinAcosSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinAcosSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_acos\nfunc (b *builtinAcosSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif val < -1 || val > 1 {\n\t\treturn 0, true, nil\n\t}\n\n\treturn math.Acos(val), false, nil\n}\n\ntype asinFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *asinFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinAsinSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Asin)\n\treturn sig, nil\n}\n\ntype builtinAsinSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinAsinSig) Clone() builtinFunc {\n\tnewSig := &builtinAsinSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinAsinSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_asin\nfunc (b *builtinAsinSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\tif val < -1 || val > 1 {\n\t\treturn 0, true, nil\n\t}\n\n\treturn math.Asin(val), false, nil\n}\n\ntype atanFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *atanFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tvar (\n\t\tsig     builtinFunc\n\t\tbf      baseBuiltinFunc\n\t\targsLen = len(args)\n\t)\n\n\tif argsLen == 1 {\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\t} else {\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal, types.ETReal)\n\t}\n\n\tif argsLen == 1 {\n\t\tsig = &builtinAtan1ArgSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_Atan1Arg)\n\t} else {\n\t\tsig = &builtinAtan2ArgsSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_Atan2Args)\n\t}\n\n\treturn sig, nil\n}\n\ntype builtinAtan1ArgSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinAtan1ArgSig) Clone() builtinFunc {\n\tnewSig := &builtinAtan1ArgSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinAtan1ArgSig, corresponding to atan(x).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_atan\nfunc (b *builtinAtan1ArgSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\treturn math.Atan(val), false, nil\n}\n\ntype builtinAtan2ArgsSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinAtan2ArgsSig) Clone() builtinFunc {\n\tnewSig := &builtinAtan2ArgsSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinAtan1ArgSig, corresponding to atan(y, x).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_atan\nfunc (b *builtinAtan2ArgsSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval1, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\tval2, isNull, err := b.args[1].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\treturn math.Atan2(val1, val2), false, nil\n}\n\ntype cosFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *cosFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinCosSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Cos)\n\treturn sig, nil\n}\n\ntype builtinCosSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCosSig) Clone() builtinFunc {\n\tnewSig := &builtinCosSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinCosSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_cos\nfunc (b *builtinCosSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn math.Cos(val), false, nil\n}\n\ntype cotFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *cotFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinCotSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Cot)\n\treturn sig, nil\n}\n\ntype builtinCotSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCotSig) Clone() builtinFunc {\n\tnewSig := &builtinCotSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinCotSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_cot\nfunc (b *builtinCotSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\ttan := math.Tan(val)\n\tif tan != 0 {\n\t\tcot := 1 / tan\n\t\tif !math.IsInf(cot, 0) && !math.IsNaN(cot) {\n\t\t\treturn cot, false, nil\n\t\t}\n\t}\n\treturn 0, false, types.ErrOverflow.GenWithStackByArgs(\"DOUBLE\", fmt.Sprintf(\"cot(%s)\", strconv.FormatFloat(val, 'f', -1, 64)))\n}\n\ntype degreesFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *degreesFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinDegreesSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Degrees)\n\treturn sig, nil\n}\n\ntype builtinDegreesSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinDegreesSig) Clone() builtinFunc {\n\tnewSig := &builtinDegreesSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinDegreesSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_degrees\nfunc (b *builtinDegreesSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tres := val * 180 / math.Pi\n\treturn res, false, nil\n}\n\ntype expFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *expFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinExpSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Exp)\n\treturn sig, nil\n}\n\ntype builtinExpSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinExpSig) Clone() builtinFunc {\n\tnewSig := &builtinExpSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinExpSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_exp\nfunc (b *builtinExpSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\texp := math.Exp(val)\n\tif math.IsInf(exp, 0) || math.IsNaN(exp) {\n\t\ts := fmt.Sprintf(\"exp(%s)\", b.args[0].String())\n\t\treturn 0, false, types.ErrOverflow.GenWithStackByArgs(\"DOUBLE\", s)\n\t}\n\treturn exp, false, nil\n}\n\ntype piFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *piFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tvar (\n\t\tbf  baseBuiltinFunc\n\t\tsig builtinFunc\n\t)\n\n\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETReal)\n\tbf.tp.Decimal = 6\n\tbf.tp.Flen = 8\n\tsig = &builtinPISig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_PI)\n\treturn sig, nil\n}\n\ntype builtinPISig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinPISig) Clone() builtinFunc {\n\tnewSig := &builtinPISig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinPISig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_pi\nfunc (b *builtinPISig) evalReal(_ chunk.Row) (float64, bool, error) {\n\treturn float64(math.Pi), false, nil\n}\n\ntype radiansFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *radiansFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinRadiansSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Radians)\n\treturn sig, nil\n}\n\ntype builtinRadiansSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinRadiansSig) Clone() builtinFunc {\n\tnewSig := &builtinRadiansSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals RADIANS(X).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_radians\nfunc (b *builtinRadiansSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tx, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn x * math.Pi / 180, false, nil\n}\n\ntype sinFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *sinFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinSinSig{bf}\n\t///sig.setPbCode(tipb.ScalarFuncSig_Sin)\n\treturn sig, nil\n}\n\ntype builtinSinSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinSinSig) Clone() builtinFunc {\n\tnewSig := &builtinSinSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinSinSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_sin\nfunc (b *builtinSinSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn math.Sin(val), false, nil\n}\n\ntype tanFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *tanFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\tsig := &builtinTanSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Tan)\n\treturn sig, nil\n}\n\ntype builtinTanSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinTanSig) Clone() builtinFunc {\n\tnewSig := &builtinTanSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a builtinTanSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_tan\nfunc (b *builtinTanSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn math.Tan(val), false, nil\n}\n\ntype truncateFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *truncateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\targTp := args[0].GetType().EvalType()\n\tif argTp.IsStringKind() {\n\t\targTp = types.ETReal\n\t}\n\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, argTp, argTp, types.ETInt)\n\n\tbf.tp.Decimal = calculateDecimal4RoundAndTruncate(ctx, args, argTp)\n\tbf.tp.Flen = args[0].GetType().Flen - args[0].GetType().Decimal + bf.tp.Decimal\n\tbf.tp.Flag |= args[0].GetType().Flag\n\n\tvar sig builtinFunc\n\tswitch argTp {\n\tcase types.ETInt:\n\t\tif mysql.HasUnsignedFlag(args[0].GetType().Flag) {\n\t\t\tsig = &builtinTruncateUintSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_TruncateUint)\n\t\t} else {\n\t\t\tsig = &builtinTruncateIntSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_TruncateInt)\n\t\t}\n\tcase types.ETReal:\n\t\tsig = &builtinTruncateRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_TruncateReal)\n\tcase types.ETDecimal:\n\t\tsig = &builtinTruncateDecimalSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_TruncateDecimal)\n\tdefault:\n\t\treturn nil, errIncorrectArgs.GenWithStackByArgs(\"truncate\")\n\t}\n\n\treturn sig, nil\n}\n\ntype builtinTruncateDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinTruncateDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinTruncateDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDecimal evals a TRUNCATE(X,D).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_truncate\nfunc (b *builtinTruncateDecimalSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\tx, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\n\td, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn nil, isNull, err\n\t}\n\n\tresult := new(types.MyDecimal)\n\tif err := x.Round(result, mathutil.Min(int(d), b.getRetTp().Decimal), types.ModeTruncate); err != nil {\n\t\treturn nil, true, err\n\t}\n\treturn result, false, nil\n}\n\ntype builtinTruncateRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinTruncateRealSig) Clone() builtinFunc {\n\tnewSig := &builtinTruncateRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalReal evals a TRUNCATE(X,D).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_truncate\nfunc (b *builtinTruncateRealSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tx, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\td, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\treturn types.Truncate(x, int(d)), false, nil\n}\n\ntype builtinTruncateIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinTruncateIntSig) Clone() builtinFunc {\n\tnewSig := &builtinTruncateIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals a TRUNCATE(X,D).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_truncate\nfunc (b *builtinTruncateIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\tx, isNull, err := b.args[0].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif mysql.HasUnsignedFlag(b.args[1].GetType().Flag) {\n\t\treturn x, false, nil\n\t}\n\n\td, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\n\tif d >= 0 {\n\t\treturn x, false, nil\n\t}\n\t// -MinInt = MinInt, special case\n\tif d == mathutil.MinInt {\n\t\treturn 0, false, nil\n\t}\n\tshift := int64(math.Pow10(int(-d)))\n\treturn x / shift * shift, false, nil\n}\n\nfunc (b *builtinTruncateUintSig) Clone() builtinFunc {\n\tnewSig := &builtinTruncateUintSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinTruncateUintSig struct {\n\tbaseBuiltinFunc\n}\n\n// evalInt evals a TRUNCATE(X,D).\n// See https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_truncate\nfunc (b *builtinTruncateUintSig) evalInt(row chunk.Row) (int64, bool, error) {\n\tx, isNull, err := b.args[0].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif mysql.HasUnsignedFlag(b.args[1].GetType().Flag) {\n\t\treturn x, false, nil\n\t}\n\tuintx := uint64(x)\n\n\td, isNull, err := b.args[1].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\tif d >= 0 {\n\t\treturn x, false, nil\n\t}\n\t// -MinInt = MinInt, special case\n\tif d == mathutil.MinInt {\n\t\treturn 0, false, nil\n\t}\n\tshift := uint64(math.Pow10(int(-d)))\n\treturn int64(uintx / shift * shift), false, nil\n}\n"
  },
  {
    "path": "pkg/expression/builtin_op.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n)\n\nvar (\n\t_ functionClass = &logicAndFunctionClass{}\n\t_ functionClass = &logicOrFunctionClass{}\n\t_ functionClass = &logicXorFunctionClass{}\n\t_ functionClass = &unaryMinusFunctionClass{}\n\t_ functionClass = &isNullFunctionClass{}\n\t_ functionClass = &unaryNotFunctionClass{}\n)\n\nvar (\n\t_ builtinFunc = &builtinLogicAndSig{}\n\t_ builtinFunc = &builtinLogicOrSig{}\n\t_ builtinFunc = &builtinLogicXorSig{}\n\t_ builtinFunc = &builtinUnaryMinusIntSig{}\n\t_ builtinFunc = &builtinUnaryMinusDecimalSig{}\n\t_ builtinFunc = &builtinUnaryMinusRealSig{}\n\t_ builtinFunc = &builtinDecimalIsNullSig{}\n\t_ builtinFunc = &builtinIntIsNullSig{}\n\t_ builtinFunc = &builtinRealIsNullSig{}\n\t_ builtinFunc = &builtinStringIsNullSig{}\n\t_ builtinFunc = &builtinUnaryNotRealSig{}\n\t_ builtinFunc = &builtinUnaryNotDecimalSig{}\n\t_ builtinFunc = &builtinUnaryNotIntSig{}\n)\n\ntype logicAndFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *logicAndFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\terr := c.verifyArgs(args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\targs[0], err = wrapWithIsTrue(ctx, true, args[0])\n\tif err != nil {\n\t\treturn nil, errors.Trace(err)\n\t}\n\targs[1], err = wrapWithIsTrue(ctx, true, args[1])\n\tif err != nil {\n\t\treturn nil, errors.Trace(err)\n\t}\n\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, types.ETInt)\n\tsig := &builtinLogicAndSig{bf}\n\tsig.tp.Flen = 1\n\tbf.tp.Flag |= mysql.IsBooleanFlag\n\treturn sig, nil\n}\n\ntype builtinLogicAndSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLogicAndSig) Clone() builtinFunc {\n\tnewSig := &builtinLogicAndSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype isTrueOrFalseFunctionClass struct {\n\tbaseFunctionClass\n\top opcode.Op\n\n\t// keepNull indicates how this function treats a null input parameter.\n\t// If keepNull is true and the input parameter is null, the function will return null.\n\t// If keepNull is false, the null input parameter will be cast to 0.\n\tkeepNull bool\n}\n\nfunc (c *isTrueOrFalseFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\targTp := args[0].GetType().EvalType()\n\tif argTp == types.ETTimestamp || argTp == types.ETDatetime || argTp == types.ETDuration {\n\t\targTp = types.ETInt\n\t} else if argTp == types.ETJson || argTp == types.ETString {\n\t\targTp = types.ETReal\n\t}\n\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, argTp)\n\tbf.tp.Flen = 1\n\tbf.tp.Flag |= mysql.IsBooleanFlag\n\tvar sig builtinFunc\n\tswitch c.op {\n\tcase opcode.IsTruth:\n\t\tswitch argTp {\n\t\tcase types.ETInt:\n\t\t\tsig = &builtinIntIsTrueSig{bf, c.keepNull}\n\t\tdefault:\n\t\t\treturn nil, errors.Errorf(\"unexpected types.EvalType %v\", argTp)\n\t\t}\n\tcase opcode.IsFalsity:\n\t\tswitch argTp {\n\t\tcase types.ETInt:\n\t\t\tsig = &builtinIntIsFalseSig{bf, c.keepNull}\n\t\tdefault:\n\t\t\treturn nil, errors.Errorf(\"unexpected types.EvalType %v\", argTp)\n\t\t}\n\t}\n\treturn sig, nil\n}\n\ntype builtinIntIsFalseSig struct {\n\tbaseBuiltinFunc\n\tkeepNull bool\n}\n\nfunc (b *builtinIntIsFalseSig) Clone() builtinFunc {\n\tnewSig := &builtinIntIsFalseSig{keepNull: b.keepNull}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinIntIsTrueSig struct {\n\tbaseBuiltinFunc\n\tkeepNull bool\n}\n\nfunc (b *builtinIntIsTrueSig) Clone() builtinFunc {\n\tnewSig := &builtinIntIsTrueSig{keepNull: b.keepNull}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype logicOrFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *logicOrFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\terr := c.verifyArgs(args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\targs[0], err = wrapWithIsTrue(ctx, true, args[0])\n\tif err != nil {\n\t\treturn nil, errors.Trace(err)\n\t}\n\targs[1], err = wrapWithIsTrue(ctx, true, args[1])\n\tif err != nil {\n\t\treturn nil, errors.Trace(err)\n\t}\n\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, types.ETInt)\n\tbf.tp.Flen = 1\n\tbf.tp.Flag |= mysql.IsBooleanFlag\n\tsig := &builtinLogicOrSig{bf}\n\treturn sig, nil\n}\n\ntype builtinLogicOrSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLogicOrSig) Clone() builtinFunc {\n\tnewSig := &builtinLogicOrSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype logicXorFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *logicXorFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\terr := c.verifyArgs(args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, types.ETInt)\n\tsig := &builtinLogicXorSig{bf}\n\tsig.tp.Flen = 1\n\tbf.tp.Flag |= mysql.IsBooleanFlag\n\treturn sig, nil\n}\n\ntype builtinLogicXorSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLogicXorSig) Clone() builtinFunc {\n\tnewSig := &builtinLogicXorSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype unaryMinusFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *unaryMinusFunctionClass) handleIntOverflow(arg *Constant) (overflow bool) {\n\tif mysql.HasUnsignedFlag(arg.GetType().Flag) {\n\t\tuval := arg.Value.GetUint64()\n\t\t// -math.MinInt64 is 9223372036854775808, so if uval is more than 9223372036854775808, like\n\t\t// 9223372036854775809, -9223372036854775809 is less than math.MinInt64, overflow occurs.\n\t\tif uval > uint64(-math.MinInt64) {\n\t\t\treturn true\n\t\t}\n\t} else {\n\t\tval := arg.Value.GetInt64()\n\t\t// The math.MinInt64 is -9223372036854775808, the math.MaxInt64 is 9223372036854775807,\n\t\t// which is less than abs(-9223372036854775808). When val == math.MinInt64, overflow occurs.\n\t\tif val == math.MinInt64 {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// typeInfer infers unaryMinus function return type. when the arg is an int constant and overflow,\n// typerInfer will infers the return type as types.ETDecimal, not types.ETInt.\nfunc (c *unaryMinusFunctionClass) typeInfer(argExpr Expression) (types.EvalType, bool) {\n\ttp := argExpr.GetType().EvalType()\n\tif tp != types.ETInt && tp != types.ETDecimal {\n\t\ttp = types.ETReal\n\t}\n\n\toverflow := false\n\t// TODO: Handle float overflow.\n\tif arg, ok := argExpr.(*Constant); ok && tp == types.ETInt {\n\t\toverflow = c.handleIntOverflow(arg)\n\t\tif overflow {\n\t\t\ttp = types.ETDecimal\n\t\t}\n\t}\n\treturn tp, overflow\n}\n\nfunc (c *unaryMinusFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\targExpr, argExprTp := args[0], args[0].GetType()\n\t_, intOverflow := c.typeInfer(argExpr)\n\n\tvar bf baseBuiltinFunc\n\tswitch argExprTp.EvalType() {\n\tcase types.ETInt:\n\t\tif intOverflow {\n\t\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETDecimal, types.ETDecimal)\n\t\t\tsig = &builtinUnaryMinusDecimalSig{bf, true}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_UnaryMinusDecimal)\n\t\t} else {\n\t\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt)\n\t\t\tsig = &builtinUnaryMinusIntSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_UnaryMinusInt)\n\t\t}\n\t\tbf.tp.Decimal = 0\n\tcase types.ETDecimal:\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETDecimal, types.ETDecimal)\n\t\tbf.tp.Decimal = argExprTp.Decimal\n\t\tsig = &builtinUnaryMinusDecimalSig{bf, false}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_UnaryMinusDecimal)\n\tcase types.ETReal:\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\t\tsig = &builtinUnaryMinusRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_UnaryMinusReal)\n\tdefault:\n\t\ttp := argExpr.GetType().Tp\n\t\tif types.IsTypeTime(tp) || tp == mysql.TypeDuration {\n\t\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETDecimal, types.ETDecimal)\n\t\t\tsig = &builtinUnaryMinusDecimalSig{bf, false}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_UnaryMinusDecimal)\n\t\t} else {\n\t\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal)\n\t\t\tsig = &builtinUnaryMinusRealSig{bf}\n\t\t\t//sig.setPbCode(tipb.ScalarFuncSig_UnaryMinusReal)\n\t\t}\n\t}\n\tbf.tp.Flen = argExprTp.Flen + 1\n\treturn sig, err\n}\n\ntype builtinUnaryMinusIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinUnaryMinusIntSig) Clone() builtinFunc {\n\tnewSig := &builtinUnaryMinusIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinUnaryMinusIntSig) evalInt(row chunk.Row) (res int64, isNull bool, err error) {\n\tvar val int64\n\tval, isNull, err = b.args[0].EvalInt(b.ctx, row)\n\tif err != nil || isNull {\n\t\treturn val, isNull, err\n\t}\n\n\tif mysql.HasUnsignedFlag(b.args[0].GetType().Flag) {\n\t\tuval := uint64(val)\n\t\tif uval > uint64(-math.MinInt64) {\n\t\t\treturn 0, false, types.ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"-%v\", uval))\n\t\t} else if uval == uint64(-math.MinInt64) {\n\t\t\treturn math.MinInt64, false, nil\n\t\t}\n\t} else if val == math.MinInt64 {\n\t\treturn 0, false, types.ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"-%v\", val))\n\t}\n\treturn -val, false, nil\n}\n\ntype builtinUnaryMinusDecimalSig struct {\n\tbaseBuiltinFunc\n\n\tconstantArgOverflow bool\n}\n\nfunc (b *builtinUnaryMinusDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinUnaryMinusDecimalSig{constantArgOverflow: b.constantArgOverflow}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinUnaryMinusDecimalSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {\n\tdec, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif err != nil || isNull {\n\t\treturn dec, isNull, err\n\t}\n\treturn types.DecimalNeg(dec), false, nil\n}\n\ntype builtinUnaryMinusRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinUnaryMinusRealSig) Clone() builtinFunc {\n\tnewSig := &builtinUnaryMinusRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinUnaryMinusRealSig) evalReal(row chunk.Row) (float64, bool, error) {\n\tval, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\treturn -val, isNull, err\n}\n\ntype isNullFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *isNullFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\targTp := args[0].GetType().EvalType()\n\tif argTp == types.ETTimestamp {\n\t\targTp = types.ETDatetime\n\t} else if argTp == types.ETJson {\n\t\targTp = types.ETString\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, argTp)\n\tbf.tp.Flen = 1\n\tbf.tp.Flag |= mysql.IsBooleanFlag\n\tvar sig builtinFunc\n\tswitch argTp {\n\tcase types.ETInt:\n\t\tsig = &builtinIntIsNullSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_IntIsNull)\n\tcase types.ETDecimal:\n\t\tsig = &builtinDecimalIsNullSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_DecimalIsNull)\n\tcase types.ETReal:\n\t\tsig = &builtinRealIsNullSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_RealIsNull)\n\tcase types.ETString:\n\t\tsig = &builtinStringIsNullSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_StringIsNull)\n\tdefault:\n\t\tpanic(\"unexpected types.EvalType\")\n\t}\n\treturn sig, nil\n}\n\ntype builtinDecimalIsNullSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinDecimalIsNullSig) Clone() builtinFunc {\n\tnewSig := &builtinDecimalIsNullSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc evalIsNull(isNull bool, err error) (int64, bool, error) {\n\tif err != nil {\n\t\treturn 0, true, err\n\t}\n\tif isNull {\n\t\treturn 1, false, nil\n\t}\n\treturn 0, false, nil\n}\n\nfunc (b *builtinDecimalIsNullSig) evalInt(row chunk.Row) (int64, bool, error) {\n\t_, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\treturn evalIsNull(isNull, err)\n}\n\ntype builtinIntIsNullSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinIntIsNullSig) Clone() builtinFunc {\n\tnewSig := &builtinIntIsNullSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinIntIsNullSig) evalInt(row chunk.Row) (int64, bool, error) {\n\t_, isNull, err := b.args[0].EvalInt(b.ctx, row)\n\treturn evalIsNull(isNull, err)\n}\n\ntype builtinRealIsNullSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinRealIsNullSig) Clone() builtinFunc {\n\tnewSig := &builtinRealIsNullSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinRealIsNullSig) evalInt(row chunk.Row) (int64, bool, error) {\n\t_, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\treturn evalIsNull(isNull, err)\n}\n\ntype builtinStringIsNullSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinStringIsNullSig) Clone() builtinFunc {\n\tnewSig := &builtinStringIsNullSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinStringIsNullSig) evalInt(row chunk.Row) (int64, bool, error) {\n\t_, isNull, err := b.args[0].EvalString(b.ctx, row)\n\treturn evalIsNull(isNull, err)\n}\n\ntype unaryNotFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *unaryNotFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\targTp := args[0].GetType().EvalType()\n\tif argTp == types.ETTimestamp || argTp == types.ETDatetime || argTp == types.ETDuration {\n\t\targTp = types.ETInt\n\t} else if argTp == types.ETJson || argTp == types.ETString {\n\t\targTp = types.ETReal\n\t}\n\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, argTp)\n\tbf.tp.Flen = 1\n\tbf.tp.Flag |= mysql.IsBooleanFlag\n\n\tvar sig builtinFunc\n\tswitch argTp {\n\tcase types.ETReal:\n\t\tsig = &builtinUnaryNotRealSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_UnaryNotReal)\n\tcase types.ETDecimal:\n\t\tsig = &builtinUnaryNotDecimalSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_UnaryNotDecimal)\n\tcase types.ETInt:\n\t\tsig = &builtinUnaryNotIntSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_UnaryNotInt)\n\tdefault:\n\t\treturn nil, errors.Errorf(\"unexpected types.EvalType %v\", argTp)\n\t}\n\treturn sig, nil\n}\n\ntype builtinUnaryNotRealSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinUnaryNotRealSig) Clone() builtinFunc {\n\tnewSig := &builtinUnaryNotRealSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinUnaryNotRealSig) evalInt(row chunk.Row) (int64, bool, error) {\n\targ, isNull, err := b.args[0].EvalReal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, true, err\n\t}\n\tif arg == 0 {\n\t\treturn 1, false, nil\n\t}\n\treturn 0, false, nil\n}\n\ntype builtinUnaryNotDecimalSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinUnaryNotDecimalSig) Clone() builtinFunc {\n\tnewSig := &builtinUnaryNotDecimalSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinUnaryNotDecimalSig) evalInt(row chunk.Row) (int64, bool, error) {\n\targ, isNull, err := b.args[0].EvalDecimal(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, true, err\n\t}\n\tif arg.IsZero() {\n\t\treturn 1, false, nil\n\t}\n\treturn 0, false, nil\n}\n\ntype builtinUnaryNotIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinUnaryNotIntSig) Clone() builtinFunc {\n\tnewSig := &builtinUnaryNotIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinUnaryNotIntSig) evalInt(row chunk.Row) (int64, bool, error) {\n\targ, isNull, err := b.args[0].EvalInt(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, true, err\n\t}\n\tif arg == 0 {\n\t\treturn 1, false, nil\n\t}\n\treturn 0, false, nil\n}\n"
  },
  {
    "path": "pkg/expression/builtin_other.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n)\n\nvar (\n\t_ functionClass = &inFunctionClass{}\n\t_ functionClass = &rowFunctionClass{}\n)\n\nvar (\n\t_ builtinFunc = &builtinInIntSig{}\n\t_ builtinFunc = &builtinInStringSig{}\n\t_ builtinFunc = &builtinRowSig{}\n)\n\ntype inFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *inFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\targTps := make([]types.EvalType, len(args))\n\tfor i := range args {\n\t\targTps[i] = args[0].GetType().EvalType()\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, argTps...)\n\tbf.tp.Flen = 1\n\tbf.tp.Flag |= mysql.IsBooleanFlag\n\tswitch args[0].GetType().EvalType() {\n\tcase types.ETInt:\n\t\tsig = &builtinInIntSig{baseBuiltinFunc: bf}\n\tcase types.ETString:\n\t\tsig = &builtinInStringSig{baseBuiltinFunc: bf}\n\t}\n\treturn sig, nil\n}\n\n// builtinInIntSig see https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in\ntype builtinInIntSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinInIntSig) Clone() builtinFunc {\n\tnewSig := &builtinInIntSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// builtinInStringSig see https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in\ntype builtinInStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinInStringSig) Clone() builtinFunc {\n\tnewSig := &builtinInStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinGeoDist struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinGeoDist) Clone() builtinFunc {\n\tnewFunction := &builtinGeoDist{}\n\tnewFunction.cloneFrom(&b.baseBuiltinFunc)\n\treturn newFunction\n}\n\ntype builtinGeoDistFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *builtinGeoDistFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tvar bf baseBuiltinFunc\n\tif len(args) == 4 {\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal, types.ETReal, types.ETReal, types.ETReal)\n\t} else {\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETReal, types.ETReal, types.ETReal, types.ETReal, types.ETReal, types.ETReal)\n\t}\n\n\tsig := &builtinGeoDist{bf}\n\treturn sig, nil\n}\n\ntype rowFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *rowFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\targTps := make([]types.EvalType, len(args))\n\tfor i := range argTps {\n\t\targTps[i] = args[i].GetType().EvalType()\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, argTps...)\n\tsig = &builtinRowSig{bf}\n\treturn sig, nil\n}\n\ntype builtinRowSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinRowSig) Clone() builtinFunc {\n\tnewSig := &builtinRowSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString rowFunc should always be flattened in expression rewrite phrase.\nfunc (b *builtinRowSig) evalString(row chunk.Row) (string, bool, error) {\n\tpanic(\"builtinRowSig.evalString() should never be called.\")\n}\n"
  },
  {
    "path": "pkg/expression/builtin_string.go",
    "content": "// Copyright 2013 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"strings\"\n\n\t\"unicode/utf8\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/variable\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n)\n\nvar (\n\t_ functionClass = &lengthFunctionClass{}\n\t_ functionClass = &concatFunctionClass{}\n\t_ functionClass = &lowerFunctionClass{}\n\t_ functionClass = &upperFunctionClass{}\n\t_ functionClass = &replaceFunctionClass{}\n\t_ functionClass = &substringFunctionClass{}\n\t_ functionClass = &instrFunctionClass{}\n)\n\nvar (\n\t_ builtinFunc = &builtinLengthSig{}\n\t_ builtinFunc = &builtinConcatSig{}\n\t_ builtinFunc = &builtinLowerSig{}\n\t_ builtinFunc = &builtinUpperSig{}\n\t_ builtinFunc = &builtinReplaceSig{}\n\t_ builtinFunc = &builtinSubstring2ArgsSig{}\n\t_ builtinFunc = &builtinSubstring3ArgsSig{}\n\t_ builtinFunc = &builtinSubstring2ArgsUTF8Sig{}\n\t_ builtinFunc = &builtinSubstring3ArgsUTF8Sig{}\n\t_ builtinFunc = &builtinInstrUTF8Sig{}\n\t_ builtinFunc = &builtinInstrSig{}\n)\n\n// SetBinFlagOrBinStr sets resTp to binary string if argTp is a binary string,\n// if not, sets the binary flag of resTp to true if argTp has binary flag.\nfunc SetBinFlagOrBinStr(argTp *types.FieldType, resTp *types.FieldType) {\n\tif types.IsBinaryStr(argTp) {\n\t\ttypes.SetBinChsClnFlag(resTp)\n\t} else if mysql.HasBinaryFlag(argTp.Flag) || !types.IsNonBinaryStr(argTp) {\n\t\tresTp.Flag |= mysql.BinaryFlag\n\t}\n}\n\ntype concatFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *concatFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\targTps := make([]types.EvalType, 0, len(args))\n\tfor i := 0; i < len(args); i++ {\n\t\targTps = append(argTps, types.ETString)\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, argTps...)\n\tfor i := range args {\n\t\targType := args[i].GetType()\n\t\tSetBinFlagOrBinStr(argType, bf.tp)\n\n\t\tif argType.Flen < 0 {\n\t\t\tbf.tp.Flen = mysql.MaxBlobWidth\n\t\t\t// log.Errorf(\"unexpected `Flen` value(-1) in CONCAT's args: arg's index %d\", i)\n\t\t}\n\t\tbf.tp.Flen += argType.Flen\n\t}\n\tif bf.tp.Flen >= mysql.MaxBlobWidth {\n\t\tbf.tp.Flen = mysql.MaxBlobWidth\n\t}\n\n\tmaxAllowedPacket := variable.DefMaxAllowedPacket\n\n\tsig := &builtinConcatSig{bf, maxAllowedPacket}\n\t// sig.setPbCode(tipb.ScalarFuncSig_Concat)\n\treturn sig, nil\n}\n\ntype builtinConcatSig struct {\n\tbaseBuiltinFunc\n\tmaxAllowedPacket uint64\n}\n\nfunc (b *builtinConcatSig) Clone() builtinFunc {\n\tnewSig := &builtinConcatSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\tnewSig.maxAllowedPacket = b.maxAllowedPacket\n\treturn newSig\n}\n\n// evalString evals a builtinConcatSig\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_concat\nfunc (b *builtinConcatSig) evalString(row chunk.Row) (d string, isNull bool, err error) {\n\tvar s []byte\n\tfor _, a := range b.getArgs() {\n\t\td, isNull, err = a.EvalString(b.ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn d, isNull, err\n\t\t}\n\t\tif uint64(len(s)+len(d)) > b.maxAllowedPacket {\n\t\t\tb.ctx.GetSessionVars().StmtCtx.AppendWarning(errWarnAllowedPacketOverflowed.GenWithStackByArgs(\"concat\", b.maxAllowedPacket))\n\t\t\treturn \"\", true, nil\n\t\t}\n\t\ts = append(s, []byte(d)...)\n\t}\n\treturn string(s), false, nil\n}\n\ntype substringFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *substringFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\targTps := []types.EvalType{types.ETString, types.ETInt}\n\tif len(args) == 3 {\n\t\targTps = append(argTps, types.ETInt)\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, argTps...)\n\targType := args[0].GetType()\n\tbf.tp.Flen = argType.Flen\n\tSetBinFlagOrBinStr(argType, bf.tp)\n\n\tvar sig builtinFunc\n\tswitch {\n\tcase len(args) == 3 && types.IsBinaryStr(argType):\n\t\tsig = &builtinSubstring3ArgsSig{bf}\n\tcase len(args) == 2 && types.IsBinaryStr(argType):\n\t\tsig = &builtinSubstring2ArgsSig{bf}\n\tcase len(args) == 3:\n\t\tsig = &builtinSubstring3ArgsUTF8Sig{bf}\n\tcase len(args) == 2:\n\t\tsig = &builtinSubstring2ArgsUTF8Sig{bf}\n\tdefault:\n\t\t// Should never happens.\n\t\treturn nil, errors.Errorf(\"SUBSTR invalid arg length, expect 2 or 3 but got: %v\", len(args))\n\t}\n\treturn sig, nil\n}\n\ntype upperFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *upperFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString)\n\targTp := args[0].GetType()\n\tbf.tp.Flen = argTp.Flen\n\tSetBinFlagOrBinStr(argTp, bf.tp)\n\tvar sig builtinFunc\n\tif types.IsBinaryStr(argTp) {\n\t\tsig = &builtinUpperSig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_Upper)\n\t} else {\n\t\tsig = &builtinUpperUTF8Sig{bf}\n\t\t//sig.setPbCode(tipb.ScalarFuncSig_UpperUTF8)\n\t}\n\treturn sig, nil\n}\n\ntype builtinUpperUTF8Sig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinUpperUTF8Sig) Clone() builtinFunc {\n\tnewSig := &builtinUpperUTF8Sig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals a builtinUpperUTF8Sig.\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_upper\nfunc (b *builtinUpperUTF8Sig) evalString(row chunk.Row) (d string, isNull bool, err error) {\n\td, isNull, err = b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn d, isNull, err\n\t}\n\n\treturn strings.ToUpper(d), false, nil\n}\n\ntype builtinUpperSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinUpperSig) Clone() builtinFunc {\n\tnewSig := &builtinUpperSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals a builtinUpperSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_upper\nfunc (b *builtinUpperSig) evalString(row chunk.Row) (d string, isNull bool, err error) {\n\td, isNull, err = b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn d, isNull, err\n\t}\n\n\treturn d, false, nil\n}\n\ntype lowerFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *lowerFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString)\n\targTp := args[0].GetType()\n\tbf.tp.Flen = argTp.Flen\n\tSetBinFlagOrBinStr(argTp, bf.tp)\n\tsig := &builtinLowerSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Lower)\n\treturn sig, nil\n}\n\ntype builtinLowerSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLowerSig) Clone() builtinFunc {\n\tnewSig := &builtinLowerSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals a builtinLowerSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_lower\nfunc (b *builtinLowerSig) evalString(row chunk.Row) (d string, isNull bool, err error) {\n\td, isNull, err = b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn d, isNull, err\n\t}\n\n\tif types.IsBinaryStr(b.args[0].GetType()) {\n\t\treturn d, false, nil\n\t}\n\n\treturn strings.ToLower(d), false, nil\n}\n\ntype replaceFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *replaceFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString, types.ETString, types.ETString)\n\tbf.tp.Flen = c.fixLength(args)\n\tfor _, a := range args {\n\t\tSetBinFlagOrBinStr(a.GetType(), bf.tp)\n\t}\n\tsig := &builtinReplaceSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Replace)\n\treturn sig, nil\n}\n\n// fixLength calculate the Flen of the return type.\nfunc (c *replaceFunctionClass) fixLength(args []Expression) int {\n\tcharLen := args[0].GetType().Flen\n\toldStrLen := args[1].GetType().Flen\n\tdiff := args[2].GetType().Flen - oldStrLen\n\tif diff > 0 && oldStrLen > 0 {\n\t\tcharLen += (charLen / oldStrLen) * diff\n\t}\n\treturn charLen\n}\n\ntype builtinReplaceSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinReplaceSig) Clone() builtinFunc {\n\tnewSig := &builtinReplaceSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals a builtinReplaceSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_replace\nfunc (b *builtinReplaceSig) evalString(row chunk.Row) (d string, isNull bool, err error) {\n\tvar str, oldStr, newStr string\n\n\tstr, isNull, err = b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn d, isNull, err\n\t}\n\toldStr, isNull, err = b.args[1].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn d, isNull, err\n\t}\n\tnewStr, isNull, err = b.args[2].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn d, isNull, err\n\t}\n\tif oldStr == \"\" {\n\t\treturn str, false, nil\n\t}\n\treturn strings.Replace(str, oldStr, newStr, -1), false, nil\n}\n\ntype lengthFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *lengthFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETString)\n\tbf.tp.Flen = 10\n\tsig := &builtinLengthSig{bf}\n\t//sig.setPbCode(tipb.ScalarFuncSig_Length)\n\treturn sig, nil\n}\n\ntype builtinLengthSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLengthSig) Clone() builtinFunc {\n\tnewSig := &builtinLengthSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evaluates a builtinLengthSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html\nfunc (b *builtinLengthSig) evalInt(row chunk.Row) (int64, bool, error) {\n\tval, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn 0, isNull, err\n\t}\n\treturn int64(len([]byte(val))), false, nil\n}\n\ntype instrFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *instrFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETString, types.ETString)\n\tbf.tp.Flen = 11\n\tif types.IsBinaryStr(bf.args[0].GetType()) || types.IsBinaryStr(bf.args[1].GetType()) {\n\t\tsig := &builtinInstrSig{bf}\n\t\treturn sig, nil\n\t}\n\tsig := &builtinInstrUTF8Sig{bf}\n\treturn sig, nil\n}\n\ntype builtinInstrUTF8Sig struct{ baseBuiltinFunc }\n\nfunc (b *builtinInstrUTF8Sig) Clone() builtinFunc {\n\tnewSig := &builtinInstrUTF8Sig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinInstrSig struct{ baseBuiltinFunc }\n\nfunc (b *builtinInstrSig) Clone() builtinFunc {\n\tnewSig := &builtinInstrSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalInt evals INSTR(str,substr), case insensitive\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_instr\nfunc (b *builtinInstrUTF8Sig) evalInt(row chunk.Row) (int64, bool, error) {\n\tstr, IsNull, err := b.args[0].EvalString(b.ctx, row)\n\tif IsNull || err != nil {\n\t\treturn 0, true, err\n\t}\n\tstr = strings.ToLower(str)\n\n\tsubstr, IsNull, err := b.args[1].EvalString(b.ctx, row)\n\tif IsNull || err != nil {\n\t\treturn 0, true, err\n\t}\n\tsubstr = strings.ToLower(substr)\n\n\tidx := strings.Index(str, substr)\n\tif idx == -1 {\n\t\treturn 0, false, nil\n\t}\n\treturn int64(utf8.RuneCountInString(str[:idx]) + 1), false, nil\n}\n\n// evalInt evals INSTR(str,substr), case sensitive\n// See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_instr\nfunc (b *builtinInstrSig) evalInt(row chunk.Row) (int64, bool, error) {\n\tstr, IsNull, err := b.args[0].EvalString(b.ctx, row)\n\tif IsNull || err != nil {\n\t\treturn 0, true, err\n\t}\n\n\tsubstr, IsNull, err := b.args[1].EvalString(b.ctx, row)\n\tif IsNull || err != nil {\n\t\treturn 0, true, err\n\t}\n\n\tidx := strings.Index(str, substr)\n\tif idx == -1 {\n\t\treturn 0, false, nil\n\t}\n\treturn int64(idx + 1), false, nil\n}\n\ntype builtinTrimSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinTrimSig) Clone() builtinFunc {\n\tnewFunction := &builtinTrimSig{}\n\tnewFunction.cloneFrom(&b.baseBuiltinFunc)\n\treturn newFunction\n}\n\ntype trimFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *trimFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString)\n\targTp := args[0].GetType()\n\tbf.tp.Flen = argTp.Flen\n\tSetBinFlagOrBinStr(argTp, bf.tp)\n\tsig := &builtinTrimSig{bf}\n\treturn sig, nil\n}\n"
  },
  {
    "path": "pkg/expression/builtin_time.go",
    "content": "// Copyright 2013 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/constant\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n\t\"github.com/secretflow/scql/pkg/util/mathutil\"\n)\n\nvar (\n\t_ functionClass = &dateDiffFunctionClass{}\n\t_ functionClass = &currentDateFunctionClass{}\n\t_ functionClass = &currentTimeFunctionClass{}\n\t_ functionClass = &dateFormatFunctionClass{}\n\t_ functionClass = &addDateFunctionClass{}\n\t_ functionClass = &subDateFunctionClass{}\n\t_ functionClass = &addTimeFunctionClass{}\n\t_ functionClass = &subTimeFunctionClass{}\n\t_ functionClass = &timeDiffFunctionClass{}\n\t_ functionClass = &nowFunctionClass{}\n\t_ functionClass = &lastDayFunctionClass{}\n\t_ functionClass = &strToDateFunctionClass{}\n\t_ functionClass = &dateFormatFunctionClass{}\n)\n\ntype dateDiffFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *dateDiffFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime, types.ETDatetime)\n\tsig := &builtinDateDiffSig{bf}\n\treturn sig, nil\n}\n\ntype builtinDateDiffSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinDateDiffSig) Clone() builtinFunc {\n\tnewSig := &builtinDateDiffSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// baseDateArithmitical is the base class for all \"builtinAddDateXXXSig\" and \"builtinSubDateXXXSig\",\n// which provides parameter getter and date arithmetical calculate functions.\ntype baseDateArithmitical struct {\n\t// intervalRegexp is \"*Regexp\" used to extract string interval for \"DAY\" unit.\n\tintervalRegexp *regexp.Regexp\n}\n\nfunc newDateArighmeticalUtil() baseDateArithmitical {\n\treturn baseDateArithmitical{\n\t\tintervalRegexp: regexp.MustCompile(`-?[\\d]+`),\n\t}\n}\n\nfunc (du *baseDateArithmitical) getDateFromString(ctx sessionctx.Context, args []Expression, row chunk.Row, unit string) (types.Time, bool, error) {\n\tdateStr, isNull, err := args[0].EvalString(ctx, row)\n\tif isNull || err != nil {\n\t\treturn types.ZeroTime, true, err\n\t}\n\n\tdateTp := mysql.TypeDate\n\tif !types.IsDateFormat(dateStr) || types.IsClockUnit(unit) {\n\t\tdateTp = mysql.TypeDatetime\n\t}\n\n\tsc := ctx.GetSessionVars().StmtCtx\n\tdate, err := types.ParseTime(sc, dateStr, dateTp, types.MaxFsp)\n\treturn date, err != nil, handleInvalidTimeError(ctx, err)\n}\n\nfunc (du *baseDateArithmitical) getDateFromInt(ctx sessionctx.Context, args []Expression, row chunk.Row, unit string) (types.Time, bool, error) {\n\tdateInt, isNull, err := args[0].EvalInt(ctx, row)\n\tif isNull || err != nil {\n\t\treturn types.ZeroTime, true, err\n\t}\n\n\tsc := ctx.GetSessionVars().StmtCtx\n\tdate, err := types.ParseTimeFromInt64(sc, dateInt)\n\tif err != nil {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(ctx, err)\n\t}\n\n\tdateTp := mysql.TypeDate\n\tif date.Type() == mysql.TypeDatetime || date.Type() == mysql.TypeTimestamp || types.IsClockUnit(unit) {\n\t\tdateTp = mysql.TypeDatetime\n\t}\n\tdate.SetType(dateTp)\n\treturn date, false, nil\n}\n\nfunc (du *baseDateArithmitical) getDateFromDatetime(ctx sessionctx.Context, args []Expression, row chunk.Row, unit string) (types.Time, bool, error) {\n\tdate, isNull, err := args[0].EvalTime(ctx, row)\n\tif isNull || err != nil {\n\t\treturn types.ZeroTime, true, err\n\t}\n\n\tdateTp := mysql.TypeDate\n\tif date.Type() == mysql.TypeDatetime || date.Type() == mysql.TypeTimestamp || types.IsClockUnit(unit) {\n\t\tdateTp = mysql.TypeDatetime\n\t}\n\tdate.SetType(dateTp)\n\treturn date, false, nil\n}\n\nfunc (du *baseDateArithmitical) getIntervalFromString(ctx sessionctx.Context, args []Expression, row chunk.Row, unit string) (string, bool, error) {\n\tinterval, isNull, err := args[1].EvalString(ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\t// unit \"DAY\" and \"HOUR\" has to be specially handled.\n\tif toLower := strings.ToLower(unit); toLower == \"day\" || toLower == \"hour\" {\n\t\tif strings.ToLower(interval) == \"true\" {\n\t\t\tinterval = \"1\"\n\t\t} else if strings.ToLower(interval) == \"false\" {\n\t\t\tinterval = \"0\"\n\t\t} else {\n\t\t\tinterval = du.intervalRegexp.FindString(interval)\n\t\t}\n\t}\n\treturn interval, false, nil\n}\n\nfunc (du *baseDateArithmitical) getIntervalFromDecimal(ctx sessionctx.Context, args []Expression, row chunk.Row, unit string) (string, bool, error) {\n\tdecimal, isNull, err := args[1].EvalDecimal(ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\tinterval := decimal.String()\n\n\tswitch strings.ToUpper(unit) {\n\tcase \"HOUR_MINUTE\", \"MINUTE_SECOND\", \"YEAR_MONTH\", \"DAY_HOUR\", \"DAY_MINUTE\",\n\t\t\"DAY_SECOND\", \"DAY_MICROSECOND\", \"HOUR_MICROSECOND\", \"HOUR_SECOND\", \"MINUTE_MICROSECOND\", \"SECOND_MICROSECOND\":\n\t\tneg := false\n\t\tif interval != \"\" && interval[0] == '-' {\n\t\t\tneg = true\n\t\t\tinterval = interval[1:]\n\t\t}\n\t\tswitch strings.ToUpper(unit) {\n\t\tcase \"HOUR_MINUTE\", \"MINUTE_SECOND\":\n\t\t\tinterval = strings.Replace(interval, \".\", \":\", -1)\n\t\tcase \"YEAR_MONTH\":\n\t\t\tinterval = strings.Replace(interval, \".\", \"-\", -1)\n\t\tcase \"DAY_HOUR\":\n\t\t\tinterval = strings.Replace(interval, \".\", \" \", -1)\n\t\tcase \"DAY_MINUTE\":\n\t\t\tinterval = \"0 \" + strings.Replace(interval, \".\", \":\", -1)\n\t\tcase \"DAY_SECOND\":\n\t\t\tinterval = \"0 00:\" + strings.Replace(interval, \".\", \":\", -1)\n\t\tcase \"DAY_MICROSECOND\":\n\t\t\tinterval = \"0 00:00:\" + interval\n\t\tcase \"HOUR_MICROSECOND\":\n\t\t\tinterval = \"00:00:\" + interval\n\t\tcase \"HOUR_SECOND\":\n\t\t\tinterval = \"00:\" + strings.Replace(interval, \".\", \":\", -1)\n\t\tcase \"MINUTE_MICROSECOND\":\n\t\t\tinterval = \"00:\" + interval\n\t\tcase \"SECOND_MICROSECOND\":\n\t\t\t/* keep interval as original decimal */\n\t\t}\n\t\tif neg {\n\t\t\tinterval = \"-\" + interval\n\t\t}\n\tcase \"SECOND\":\n\t\t// interval is already like the %f format.\n\tdefault:\n\t\t// YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE, MICROSECOND\n\t\tcastExpr := WrapWithCastAsString(ctx, WrapWithCastAsInt(ctx, args[1]))\n\t\tinterval, isNull, err = castExpr.EvalString(ctx, row)\n\t\tif isNull || err != nil {\n\t\t\treturn \"\", true, err\n\t\t}\n\t}\n\n\treturn interval, false, nil\n}\n\nfunc (du *baseDateArithmitical) getIntervalFromInt(ctx sessionctx.Context, args []Expression, row chunk.Row, unit string) (string, bool, error) {\n\tinterval, isNull, err := args[1].EvalInt(ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\treturn strconv.FormatInt(interval, 10), false, nil\n}\n\nfunc (du *baseDateArithmitical) getIntervalFromReal(ctx sessionctx.Context, args []Expression, row chunk.Row, unit string) (string, bool, error) {\n\tinterval, isNull, err := args[1].EvalReal(ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", true, err\n\t}\n\treturn strconv.FormatFloat(interval, 'f', args[1].GetType().Decimal, 64), false, nil\n}\n\nfunc (du *baseDateArithmitical) returnIntervalSeconds(ctx sessionctx.Context, interval string, unit string) (int64, error) {\n\tyear, month, day, nano, err := types.ParseDurationValue(unit, interval)\n\tif err := handleInvalidTimeError(ctx, err); err != nil {\n\t\treturn 0, err\n\t}\n\tif year != 0 && month != 0 {\n\t\treturn 0, fmt.Errorf(\"not supported year and month calc\")\n\t}\n\treturn day*constant.SecondsOneDay + nano/int64(time.Second), nil\n}\nfunc (du *baseDateArithmitical) add(ctx sessionctx.Context, date types.Time, interval string, unit string) (types.Time, bool, error) {\n\tyear, month, day, nano, err := types.ParseDurationValue(unit, interval)\n\tif err := handleInvalidTimeError(ctx, err); err != nil {\n\t\treturn types.ZeroTime, true, err\n\t}\n\n\tgoTime, err := date.GoTime(time.Local)\n\tif err := handleInvalidTimeError(ctx, err); err != nil {\n\t\treturn types.ZeroTime, true, err\n\t}\n\n\tgoTime = goTime.Add(time.Duration(nano))\n\tgoTime = types.AddDate(year, month, day, goTime)\n\n\tif goTime.Nanosecond() == 0 {\n\t\tdate.SetFsp(0)\n\t} else {\n\t\tdate.SetFsp(6)\n\t}\n\n\tif goTime.Year() < 0 || goTime.Year() > (1<<16-1) {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(ctx, types.ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"datetime\"))\n\t}\n\n\tdate.SetCoreTime(types.FromGoTime(goTime))\n\toverflow, err := types.DateTimeIsOverflow(ctx.GetSessionVars().StmtCtx, date)\n\tif err := handleInvalidTimeError(ctx, err); err != nil {\n\t\treturn types.ZeroTime, true, err\n\t}\n\tif overflow {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(ctx, types.ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"datetime\"))\n\t}\n\treturn date, false, nil\n}\n\nfunc (du *baseDateArithmitical) addDuration(ctx sessionctx.Context, d types.Duration, interval string, unit string) (types.Duration, bool, error) {\n\tdur, err := types.ExtractDurationValue(unit, interval)\n\tif err != nil {\n\t\treturn types.ZeroDuration, true, handleInvalidTimeError(ctx, err)\n\t}\n\tretDur, err := d.Add(dur)\n\tif err != nil {\n\t\treturn types.ZeroDuration, true, err\n\t}\n\treturn retDur, false, nil\n}\n\nfunc (du *baseDateArithmitical) subDuration(ctx sessionctx.Context, d types.Duration, interval string, unit string) (types.Duration, bool, error) {\n\tdur, err := types.ExtractDurationValue(unit, interval)\n\tif err != nil {\n\t\treturn types.ZeroDuration, true, handleInvalidTimeError(ctx, err)\n\t}\n\tretDur, err := d.Sub(dur)\n\tif err != nil {\n\t\treturn types.ZeroDuration, true, err\n\t}\n\treturn retDur, false, nil\n}\n\nfunc (du *baseDateArithmitical) sub(ctx sessionctx.Context, date types.Time, interval string, unit string) (types.Time, bool, error) {\n\tyear, month, day, nano, err := types.ParseDurationValue(unit, interval)\n\tif err := handleInvalidTimeError(ctx, err); err != nil {\n\t\treturn types.ZeroTime, true, err\n\t}\n\tyear, month, day, nano = -year, -month, -day, -nano\n\n\tgoTime, err := date.GoTime(time.Local)\n\tif err := handleInvalidTimeError(ctx, err); err != nil {\n\t\treturn types.ZeroTime, true, err\n\t}\n\n\tduration := time.Duration(nano)\n\tgoTime = goTime.Add(duration)\n\tgoTime = types.AddDate(year, month, day, goTime)\n\n\tif goTime.Nanosecond() == 0 {\n\t\tdate.SetFsp(0)\n\t} else {\n\t\tdate.SetFsp(6)\n\t}\n\n\tif goTime.Year() < 0 || goTime.Year() > (1<<16-1) {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(ctx, types.ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"datetime\"))\n\t}\n\n\tdate.SetCoreTime(types.FromGoTime(goTime))\n\toverflow, err := types.DateTimeIsOverflow(ctx.GetSessionVars().StmtCtx, date)\n\tif err := handleInvalidTimeError(ctx, err); err != nil {\n\t\treturn types.ZeroTime, true, err\n\t}\n\tif overflow {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(ctx, types.ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"datetime\"))\n\t}\n\treturn date, false, nil\n}\n\ntype addDateFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\tdateEvalTp := args[0].GetType().EvalType()\n\tif dateEvalTp != types.ETString && dateEvalTp != types.ETInt && dateEvalTp != types.ETDuration && dateEvalTp != types.ETTimestamp {\n\t\tdateEvalTp = types.ETDatetime\n\t}\n\n\tintervalEvalTp := args[1].GetType().EvalType()\n\tif intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal && intervalEvalTp != types.ETReal {\n\t\tintervalEvalTp = types.ETInt\n\t}\n\n\targTps := []types.EvalType{dateEvalTp, intervalEvalTp, types.ETString}\n\tvar bf baseBuiltinFunc\n\tif dateEvalTp == types.ETDuration {\n\t\tunit, _, err := args[2].EvalString(ctx, chunk.Row{})\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tinternalFsp := 0\n\t\tswitch unit {\n\t\t// If the unit has micro second, then the fsp must be the MaxFsp.\n\t\tcase \"MICROSECOND\", \"SECOND_MICROSECOND\", \"MINUTE_MICROSECOND\", \"HOUR_MICROSECOND\", \"DAY_MICROSECOND\":\n\t\t\tinternalFsp = int(types.MaxFsp)\n\t\t// If the unit is second, the fsp is related with the arg[1]'s.\n\t\tcase \"SECOND\":\n\t\t\tinternalFsp = int(types.MaxFsp)\n\t\t\tif intervalEvalTp != types.ETString {\n\t\t\t\tinternalFsp = mathutil.Min(args[1].GetType().Decimal, int(types.MaxFsp))\n\t\t\t}\n\t\t\t// Otherwise, the fsp should be 0.\n\t\t}\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, argTps...)\n\t\targ0Dec, err := getExpressionFsp(ctx, args[0])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tbf.tp.Flen, bf.tp.Decimal = mysql.MaxDurationWidthWithFsp, mathutil.Max(arg0Dec, internalFsp)\n\t} else if dateEvalTp == types.ETTimestamp {\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETTimestamp, argTps...)\n\t\tbf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeFullWidth, types.UnspecifiedLength\n\t} else {\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, argTps...)\n\t\tbf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeFullWidth, types.UnspecifiedLength\n\t}\n\n\tswitch {\n\tcase (dateEvalTp == types.ETDatetime || dateEvalTp == types.ETTimestamp || dateEvalTp == types.ETString) && intervalEvalTp == types.ETInt:\n\t\t// when expression rewrite to sql, do not need support diffrent type args for adddate as tidb,\n\t\t// so here just support args type like: adddate(col_name, INTERVAL 30 day)\n\t\tsig = &builtinAddDateDatetimeIntSig{\n\t\t\tbaseBuiltinFunc:      bf,\n\t\t\tbaseDateArithmitical: newDateArighmeticalUtil(),\n\t\t}\n\tdefault:\n\t\treturn nil, errors.Errorf(\"Invalid args for adddate func\")\n\t}\n\treturn sig, nil\n}\n\n// getExpressionFsp calculates the fsp from given expression.\nfunc getExpressionFsp(ctx sessionctx.Context, expression Expression) (int, error) {\n\tconstExp, isConstant := expression.(*Constant)\n\tif isConstant && types.IsString(expression.GetType().Tp) && !isTemporalColumn(expression) {\n\t\tstr, isNil, err := constExp.EvalString(ctx, chunk.Row{})\n\t\tif isNil || err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\treturn int(types.GetFsp(str)), nil\n\t}\n\treturn mathutil.Min(expression.GetType().Decimal, int(types.MaxFsp)), nil\n}\n\ntype builtinAddDateDatetimeIntSig struct {\n\tbaseBuiltinFunc\n\tbaseDateArithmitical\n}\n\nfunc (b *builtinAddDateDatetimeIntSig) Clone() builtinFunc {\n\tnewSig := &builtinAddDateDatetimeIntSig{baseDateArithmitical: b.baseDateArithmitical}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype subDateFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\tdateEvalTp := args[0].GetType().EvalType()\n\tif dateEvalTp != types.ETString && dateEvalTp != types.ETInt && dateEvalTp != types.ETDuration && dateEvalTp != types.ETTimestamp {\n\t\tdateEvalTp = types.ETDatetime\n\t}\n\n\tintervalEvalTp := args[1].GetType().EvalType()\n\tif intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal && intervalEvalTp != types.ETReal {\n\t\tintervalEvalTp = types.ETInt\n\t}\n\n\targTps := []types.EvalType{dateEvalTp, intervalEvalTp, types.ETString}\n\tvar bf baseBuiltinFunc\n\tif dateEvalTp == types.ETDuration {\n\t\tunit, _, err := args[2].EvalString(ctx, chunk.Row{})\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tinternalFsp := 0\n\t\tswitch unit {\n\t\t// If the unit has micro second, then the fsp must be the MaxFsp.\n\t\tcase \"MICROSECOND\", \"SECOND_MICROSECOND\", \"MINUTE_MICROSECOND\", \"HOUR_MICROSECOND\", \"DAY_MICROSECOND\":\n\t\t\tinternalFsp = int(types.MaxFsp)\n\t\t// If the unit is second, the fsp is related with the arg[1]'s.\n\t\tcase \"SECOND\":\n\t\t\tinternalFsp = int(types.MaxFsp)\n\t\t\tif intervalEvalTp != types.ETString {\n\t\t\t\tinternalFsp = mathutil.Min(args[1].GetType().Decimal, int(types.MaxFsp))\n\t\t\t}\n\t\t\t// Otherwise, the fsp should be 0.\n\t\t}\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, argTps...)\n\t\targ0Dec, err := getExpressionFsp(ctx, args[0])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tbf.tp.Flen, bf.tp.Decimal = mysql.MaxDurationWidthWithFsp, mathutil.Max(arg0Dec, internalFsp)\n\t} else if dateEvalTp == types.ETTimestamp {\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETTimestamp, argTps...)\n\t\tbf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeFullWidth, types.UnspecifiedLength\n\t} else {\n\t\tbf = newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, argTps...)\n\t\tbf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeFullWidth, types.UnspecifiedLength\n\t}\n\n\tswitch {\n\tcase (dateEvalTp == types.ETDatetime || dateEvalTp == types.ETTimestamp || dateEvalTp == types.ETString) && intervalEvalTp == types.ETInt:\n\t\tsig = &builtinSubDateDatetimeIntSig{\n\t\t\tbaseBuiltinFunc:      bf,\n\t\t\tbaseDateArithmitical: newDateArighmeticalUtil(),\n\t\t}\n\tdefault:\n\t\treturn nil, errors.Errorf(\"Invalid args for subdate func\")\n\t}\n\treturn sig, nil\n}\n\ntype builtinSubDateDatetimeIntSig struct {\n\tbaseBuiltinFunc\n\tbaseDateArithmitical\n}\n\nfunc (b *builtinSubDateDatetimeIntSig) Clone() builtinFunc {\n\tnewSig := &builtinSubDateDatetimeIntSig{baseDateArithmitical: b.baseDateArithmitical}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// getBf4TimeAddSub parses input types, generates baseBuiltinFunc and set related attributes for\n// builtin function 'ADDTIME' and 'SUBTIME'\nfunc getBf4TimeAddSub(ctx sessionctx.Context, args []Expression) (tp1, tp2 *types.FieldType, bf baseBuiltinFunc, err error) {\n\ttp1, tp2 = args[0].GetType(), args[1].GetType()\n\tvar argTp1, argTp2, retTp types.EvalType\n\tswitch tp1.Tp {\n\tcase mysql.TypeDatetime, mysql.TypeTimestamp:\n\t\targTp1, retTp = types.ETDatetime, types.ETDatetime\n\tcase mysql.TypeDuration:\n\t\targTp1, retTp = types.ETDuration, types.ETDuration\n\tcase mysql.TypeDate:\n\t\targTp1, retTp = types.ETDuration, types.ETString\n\tdefault:\n\t\targTp1, retTp = types.ETString, types.ETString\n\t}\n\tswitch tp2.Tp {\n\tcase mysql.TypeDatetime, mysql.TypeDuration:\n\t\targTp2 = types.ETDuration\n\tdefault:\n\t\targTp2 = types.ETString\n\t}\n\targ0Dec, err := getExpressionFsp(ctx, args[0])\n\tif err != nil {\n\t\treturn\n\t}\n\targ1Dec, err := getExpressionFsp(ctx, args[1])\n\tif err != nil {\n\t\treturn\n\t}\n\n\tbf = newBaseBuiltinFuncWithTp(ctx, args, retTp, argTp1, argTp2)\n\tbf.tp.Decimal = mathutil.Min(mathutil.Max(arg0Dec, arg1Dec), int(types.MaxFsp))\n\tif retTp == types.ETString {\n\t\tbf.tp.Tp, bf.tp.Flen, bf.tp.Decimal = mysql.TypeString, mysql.MaxDatetimeWidthWithFsp, types.UnspecifiedLength\n\t}\n\treturn\n}\n\ntype addTimeFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *addTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\ttp1, _, bf, err := getBf4TimeAddSub(ctx, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch tp1.Tp {\n\tcase mysql.TypeDatetime, mysql.TypeTimestamp:\n\t\tsig = &builtinAddDatetimeAndStringSig{bf}\n\tdefault:\n\t\treturn nil, errors.Errorf(\"Invalid args for addtime func\")\n\t}\n\treturn sig, nil\n}\n\ntype builtinAddDatetimeAndStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinAddDatetimeAndStringSig) Clone() builtinFunc {\n\tnewSig := &builtinAddDatetimeAndStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype subTimeFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *subTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\ttp1, _, bf, err := getBf4TimeAddSub(ctx, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch tp1.Tp {\n\tcase mysql.TypeDatetime, mysql.TypeTimestamp:\n\t\tsig = &builtinSubDatetimeAndStringSig{bf}\n\tdefault:\n\t\treturn nil, errors.Errorf(\"Invalid args for subtime func\")\n\t}\n\treturn sig, nil\n}\n\ntype builtinSubDatetimeAndStringSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinSubDatetimeAndStringSig) Clone() builtinFunc {\n\tnewSig := &builtinSubDatetimeAndStringSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype timeDiffFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *timeDiffFunctionClass) getArgEvalTp(fieldTp *types.FieldType) types.EvalType {\n\targTp := types.ETString\n\tswitch tp := fieldTp.EvalType(); tp {\n\tcase types.ETDuration, types.ETDatetime, types.ETTimestamp:\n\t\targTp = tp\n\t}\n\treturn argTp\n}\n\nfunc (c *timeDiffFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\targ0FieldTp, arg1FieldTp := args[0].GetType(), args[1].GetType()\n\targ0Tp, arg1Tp := c.getArgEvalTp(arg0FieldTp), c.getArgEvalTp(arg1FieldTp)\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, arg0Tp, arg1Tp)\n\n\targ0Dec, err := getExpressionFsp(ctx, args[0])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\targ1Dec, err := getExpressionFsp(ctx, args[1])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbf.tp.Decimal = mathutil.Max(arg0Dec, arg1Dec)\n\n\tvar sig builtinFunc\n\t// arg0 and arg1 must be the same time type(compatible), or timediff will return NULL.\n\t// TODO: we don't really need Duration type, actually in MySQL, it use Time class to represent\n\t// all the time type, and use filed type to distinguish datetime, date, timestamp or time(duration).\n\t// With the duration type, we are hard to port all the MySQL behavior.\n\tswitch arg0Tp {\n\tcase types.ETDatetime, types.ETTimestamp:\n\t\tsig = &builtinTimeTimeTimeDiffSig{bf}\n\tdefault:\n\t\treturn nil, errors.Errorf(\"Invalid args for timediff func\")\n\t}\n\treturn sig, nil\n}\n\ntype builtinTimeTimeTimeDiffSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinTimeTimeTimeDiffSig) Clone() builtinFunc {\n\tnewSig := &builtinTimeTimeTimeDiffSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype dateFormatFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *dateFormatFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETDatetime, types.ETString)\n\n\t// worst case: formatMask=%r%r%r...%r, each %r takes 11 characters\n\tbf.tp.Flen = (args[1].GetType().Flen + 1) / 2 * 11\n\tsig := &builtinDateFormatSig{bf}\n\treturn sig, nil\n}\n\ntype builtinDateFormatSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinDateFormatSig) Clone() builtinFunc {\n\tnewSig := &builtinDateFormatSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalString evals a builtinDateFormatSig.\n// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format\nfunc (b *builtinDateFormatSig) evalString(row chunk.Row) (string, bool, error) {\n\tt, isNull, err := b.args[0].EvalTime(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", isNull, handleInvalidTimeError(b.ctx, err)\n\t}\n\tformatMask, isNull, err := b.args[1].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn \"\", isNull, err\n\t}\n\t// MySQL compatibility, #11203\n\t// If format mask is 0 then return 0 without warnings\n\tif formatMask == \"0\" {\n\t\treturn \"0\", false, nil\n\t}\n\n\tif t.InvalidZero() {\n\t\t// MySQL compatibility, #11203\n\t\t// 0 | 0.0 should be converted to null without warnings\n\t\tn, err := t.ToNumber().ToInt()\n\t\tisOriginalIntOrDecimalZero := err == nil && n == 0\n\t\t// Args like \"0000-00-00\", \"0000-00-00 00:00:00\" set Fsp to 6\n\t\tisOriginalStringZero := t.Fsp() > 0\n\t\tif isOriginalIntOrDecimalZero && !isOriginalStringZero {\n\t\t\treturn \"\", true, nil\n\t\t}\n\t\treturn \"\", true, handleInvalidTimeError(b.ctx, types.ErrWrongValue.GenWithStackByArgs(types.DateTimeStr, t.String()))\n\t}\n\n\tres, err := t.DateFormat(formatMask)\n\treturn res, isNull, err\n}\n\ntype strToDateFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *strToDateFunctionClass) getRetTp(ctx sessionctx.Context, arg Expression) (tp byte, fsp int) {\n\ttp = mysql.TypeDatetime\n\tif _, ok := arg.(*Constant); !ok {\n\t\treturn tp, int(types.MaxFsp)\n\t}\n\tstrArg := WrapWithCastAsString(ctx, arg)\n\tformat, isNull, err := strArg.EvalString(ctx, chunk.Row{})\n\tif err != nil || isNull {\n\t\treturn\n\t}\n\n\tisDuration, isDate := types.GetFormatType(format)\n\tif isDuration && !isDate {\n\t\ttp = mysql.TypeDuration\n\t} else if !isDuration && isDate {\n\t\ttp = mysql.TypeDate\n\t}\n\tif strings.Contains(format, \"%f\") {\n\t\tfsp = int(types.MaxFsp)\n\t}\n\treturn\n}\n\n// getFunction see https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_str-to-date\nfunc (c *strToDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tretTp, fsp := c.getRetTp(ctx, args[1])\n\tswitch retTp {\n\tcase mysql.TypeDate:\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, types.ETString, types.ETString)\n\t\tbf.setDecimalAndFlenForDate()\n\t\tsig = &builtinStrToDateDateSig{bf}\n\tcase mysql.TypeDatetime:\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, types.ETString, types.ETString)\n\t\tbf.setDecimalAndFlenForDatetime(fsp)\n\t\tsig = &builtinStrToDateDatetimeSig{bf}\n\tcase mysql.TypeDuration:\n\t\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, types.ETString, types.ETString)\n\t\tbf.setDecimalAndFlenForTime(fsp)\n\t\tsig = &builtinStrToDateDurationSig{bf}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported type %v\", retTp)\n\t}\n\treturn sig, nil\n}\n\ntype builtinStrToDateDateSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinStrToDateDateSig) Clone() builtinFunc {\n\tnewSig := &builtinStrToDateDateSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinStrToDateDateSig) evalTime(row chunk.Row) (types.Time, bool, error) {\n\tdate, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn types.ZeroTime, isNull, err\n\t}\n\tformat, isNull, err := b.args[1].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn types.ZeroTime, isNull, err\n\t}\n\tvar t types.Time\n\tsc := b.ctx.GetSessionVars().StmtCtx\n\tsucc := t.StrToDate(sc, date, format)\n\tif !succ {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(b.ctx, types.ErrWrongValue.GenWithStackByArgs(types.DateTimeStr, t.String()))\n\t}\n\tif b.ctx.GetSessionVars().SQLMode.HasNoZeroDateMode() && (t.Year() == 0 || t.Month() == 0 || t.Day() == 0) {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(b.ctx, types.ErrWrongValueForType.GenWithStackByArgs(types.DateTimeStr, date, ast.StrToDate))\n\t}\n\tt.SetType(mysql.TypeDate)\n\tt.SetFsp(types.MinFsp)\n\treturn t, false, nil\n}\n\ntype builtinStrToDateDatetimeSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinStrToDateDatetimeSig) Clone() builtinFunc {\n\tnewSig := &builtinStrToDateDatetimeSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc (b *builtinStrToDateDatetimeSig) evalTime(row chunk.Row) (types.Time, bool, error) {\n\tdate, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn types.ZeroTime, isNull, err\n\t}\n\tformat, isNull, err := b.args[1].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn types.ZeroTime, isNull, err\n\t}\n\tvar t types.Time\n\tsc := b.ctx.GetSessionVars().StmtCtx\n\tsucc := t.StrToDate(sc, date, format)\n\tif !succ {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(b.ctx, types.ErrWrongValue.GenWithStackByArgs(types.DateTimeStr, t.String()))\n\t}\n\tif b.ctx.GetSessionVars().SQLMode.HasNoZeroDateMode() && (t.Year() == 0 || t.Month() == 0 || t.Day() == 0) {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(b.ctx, types.ErrWrongValue.GenWithStackByArgs(types.DateTimeStr, t.String()))\n\t}\n\tt.SetType(mysql.TypeDatetime)\n\tt.SetFsp(int8(b.tp.Decimal))\n\treturn t, false, nil\n}\n\ntype builtinStrToDateDurationSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinStrToDateDurationSig) Clone() builtinFunc {\n\tnewSig := &builtinStrToDateDurationSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalDuration\n// TODO: If the NO_ZERO_DATE or NO_ZERO_IN_DATE SQL mode is enabled, zero dates or part of dates are disallowed.\n// In that case, STR_TO_DATE() returns NULL and generates a warning.\nfunc (b *builtinStrToDateDurationSig) evalDuration(row chunk.Row) (types.Duration, bool, error) {\n\tdate, isNull, err := b.args[0].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn types.Duration{}, isNull, err\n\t}\n\tformat, isNull, err := b.args[1].EvalString(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn types.Duration{}, isNull, err\n\t}\n\tvar t types.Time\n\tsc := b.ctx.GetSessionVars().StmtCtx\n\tsucc := t.StrToDate(sc, date, format)\n\tif !succ {\n\t\treturn types.Duration{}, true, handleInvalidTimeError(b.ctx, types.ErrWrongValue.GenWithStackByArgs(types.DateTimeStr, t.String()))\n\t}\n\tt.SetFsp(int8(b.tp.Decimal))\n\tdur, err := t.ConvertToDuration()\n\treturn dur, err != nil, err\n}\n\ntype currentDateFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *currentDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime)\n\tbf.tp.Flen, bf.tp.Decimal = 10, 0\n\tsig := &builtinCurrentDateSig{bf}\n\treturn sig, nil\n}\n\ntype builtinCurrentDateSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCurrentDateSig) Clone() builtinFunc {\n\tnewSig := &builtinCurrentDateSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\nfunc getFlenAndDecimal4UTCTimestampAndNow(ctx sessionctx.Context, arg Expression) (flen, decimal int) {\n\tif constant, ok := arg.(*Constant); ok {\n\t\tfsp, isNull, err := constant.EvalInt(ctx, chunk.Row{})\n\t\tif isNull || err != nil || fsp > int64(types.MaxFsp) {\n\t\t\tdecimal = int(types.MaxFsp)\n\t\t} else if fsp < int64(types.MinFsp) {\n\t\t\tdecimal = int(types.MinFsp)\n\t\t} else {\n\t\t\tdecimal = int(fsp)\n\t\t}\n\t}\n\tif decimal > 0 {\n\t\tflen = 19 + 1 + decimal\n\t} else {\n\t\tflen = 19\n\t}\n\treturn flen, decimal\n}\n\ntype currentTimeFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *currentTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {\n\tif err = c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(args) != 0 {\n\t\treturn nil, errors.Errorf(\"Invalid arg for cur_time func\")\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration)\n\tbf.tp.Flen, bf.tp.Decimal = mysql.MaxDurationWidthNoFsp, int(types.MinFsp)\n\tsig = &builtinCurrentTime0ArgSig{bf}\n\treturn sig, nil\n}\n\ntype builtinCurrentTime0ArgSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinCurrentTime0ArgSig) Clone() builtinFunc {\n\tnewSig := &builtinCurrentTime0ArgSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype nowFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *nowFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\targTps := make([]types.EvalType, 0, 1)\n\tif len(args) == 1 {\n\t\targTps = append(argTps, types.ETInt)\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, argTps...)\n\n\tif len(args) == 1 {\n\t\tbf.tp.Flen, bf.tp.Decimal = getFlenAndDecimal4UTCTimestampAndNow(bf.ctx, args[0])\n\t} else {\n\t\tbf.tp.Flen, bf.tp.Decimal = 19, 0\n\t}\n\n\tvar sig builtinFunc\n\tif len(args) == 1 {\n\t\tsig = &builtinNowWithArgSig{bf}\n\t} else {\n\t\tsig = &builtinNowWithoutArgSig{bf}\n\t}\n\treturn sig, nil\n}\n\ntype builtinNowWithArgSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinNowWithArgSig) Clone() builtinFunc {\n\tnewSig := &builtinNowWithArgSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype builtinNowWithoutArgSig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinNowWithoutArgSig) Clone() builtinFunc {\n\tnewSig := &builtinNowWithoutArgSig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\ntype lastDayFunctionClass struct {\n\tbaseFunctionClass\n}\n\nfunc (c *lastDayFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {\n\tif err := c.verifyArgs(args); err != nil {\n\t\treturn nil, err\n\t}\n\tbf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, types.ETDatetime)\n\tbf.tp.Tp, bf.tp.Flen, bf.tp.Decimal = mysql.TypeDate, mysql.MaxDateWidth, int(types.DefaultFsp)\n\tsig := &builtinLastDaySig{bf}\n\treturn sig, nil\n}\n\ntype builtinLastDaySig struct {\n\tbaseBuiltinFunc\n}\n\nfunc (b *builtinLastDaySig) Clone() builtinFunc {\n\tnewSig := &builtinLastDaySig{}\n\tnewSig.cloneFrom(&b.baseBuiltinFunc)\n\treturn newSig\n}\n\n// evalTime evals a builtinLastDaySig.\n// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_last-day\nfunc (b *builtinLastDaySig) evalTime(row chunk.Row) (types.Time, bool, error) {\n\targ, isNull, err := b.args[0].EvalTime(b.ctx, row)\n\tif isNull || err != nil {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(b.ctx, err)\n\t}\n\ttm := arg\n\tif arg.InvalidZero() {\n\t\treturn types.ZeroTime, true, handleInvalidTimeError(b.ctx, types.ErrWrongValue.GenWithStackByArgs(types.DateTimeStr, arg.String()))\n\t}\n\tyear, month := tm.Year(), tm.Month()\n\tlastDay := types.GetLastDay(year, month)\n\tret := types.NewTime(types.FromDate(year, month, lastDay, 0, 0, 0, 0), mysql.TypeDate, types.DefaultFsp)\n\treturn ret, false, nil\n}\n"
  },
  {
    "path": "pkg/expression/column.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n\t\"github.com/secretflow/scql/pkg/util/codec\"\n)\n\n// CorrelatedColumn stands for a column in a correlated sub query.\ntype CorrelatedColumn struct {\n\tColumn\n\n\tData *types.Datum\n}\n\ntype Column struct {\n\tRetType *types.FieldType\n\t// ID is used to specify whether this column is ExtraHandleColumn or to access histogram.\n\t// We'll try to remove it in the future.\n\tID int64\n\t// UniqueID is the unique id of this column.\n\tUniqueID int64\n\n\t// Index is used for execution, to tell the column's position in the given row.\n\tIndex int\n\n\thashcode []byte\n\n\t// VirtualExpr is used to save expression for virtual column\n\tVirtualExpr Expression\n\n\tOrigName string // OrigName usually in format DBName.TableName.ColumnName\n\tIsHidden bool\n\n\t// InOperand indicates whether this column is the inner operand of column equal condition converted\n\t// from `[not] in (subq)`.\n\tInOperand      bool\n\tUseAsThreshold bool\n}\n\nfunc (col *Column) Equal(_ sessionctx.Context, expr Expression) bool {\n\tif newCol, ok := expr.(*Column); ok {\n\t\treturn newCol.UniqueID == col.UniqueID\n\t}\n\treturn false\n}\n\nfunc (col *Column) Clone() Expression {\n\tnewCol := *col\n\tif col.hashcode != nil {\n\t\tnewCol.hashcode = make([]byte, len(col.hashcode))\n\t\tcopy(newCol.hashcode, col.hashcode)\n\t}\n\treturn &newCol\n}\n\n// HashCode implements Expression interface.\nfunc (col *Column) HashCode(_ *stmtctx.StatementContext) []byte {\n\t// TODO: refine HashCode for Column\n\t// if len(col.hashcode) != 0 {\n\t// \treturn col.hashcode\n\t// }\n\tcol.hashcode = make([]byte, 0, 9)\n\tcol.hashcode = append(col.hashcode, columnFlag)\n\tcol.hashcode = codec.EncodeInt(col.hashcode, int64(col.UniqueID))\n\treturn col.hashcode\n}\n\nconst columnPrefix = \"Column#\"\n\nfunc (col *Column) String() string {\n\tif col.OrigName != \"\" {\n\t\treturn col.OrigName\n\t}\n\tvar builder strings.Builder\n\tfmt.Fprintf(&builder, \"%s%d\", columnPrefix, col.UniqueID)\n\treturn builder.String()\n}\n\nfunc (col *Column) GetType() *types.FieldType {\n\treturn col.RetType\n}\n\n// Column2Exprs will transfer column slice to expression slice.\nfunc Column2Exprs(cols []*Column) []Expression {\n\tresult := make([]Expression, 0, len(cols))\n\tfor _, col := range cols {\n\t\tresult = append(result, col)\n\t}\n\treturn result\n}\n\n// Decorrelate implements Expression interface.\nfunc (col *Column) Decorrelate(_ *Schema) Expression {\n\treturn col\n}\n\n// EvalInt returns int representation of Column.\nfunc (col *Column) EvalInt(ctx sessionctx.Context, row chunk.Row) (int64, bool, error) {\n\tif col.GetType().Hybrid() {\n\t\tval := row.GetDatum(col.Index, col.RetType)\n\t\tif val.IsNull() {\n\t\t\treturn 0, true, nil\n\t\t}\n\t\tres, err := val.ToInt64(ctx.GetSessionVars().StmtCtx)\n\t\treturn res, err != nil, err\n\t}\n\tif row.IsNull(col.Index) {\n\t\treturn 0, true, nil\n\t}\n\treturn row.GetInt64(col.Index), false, nil\n}\n\n// EvalReal returns real representation of Column.\nfunc (col *Column) EvalReal(ctx sessionctx.Context, row chunk.Row) (float64, bool, error) {\n\tif row.IsNull(col.Index) {\n\t\treturn 0, true, nil\n\t}\n\tif col.GetType().Tp == mysql.TypeFloat {\n\t\treturn float64(row.GetFloat32(col.Index)), false, nil\n\t}\n\treturn row.GetFloat64(col.Index), false, nil\n}\n\n// EvalString returns string representation of Column.\nfunc (col *Column) EvalString(ctx sessionctx.Context, row chunk.Row) (string, bool, error) {\n\tif row.IsNull(col.Index) {\n\t\treturn \"\", true, nil\n\t}\n\n\t// Specially handle the ENUM/SET/BIT input value.\n\tif col.GetType().Hybrid() {\n\t\tval := row.GetDatum(col.Index, col.RetType)\n\t\tres, err := val.ToString()\n\t\treturn res, err != nil, err\n\t}\n\n\tval := row.GetString(col.Index)\n\treturn val, false, nil\n}\n\n// EvalDecimal returns decimal representation of Column.\nfunc (col *Column) EvalDecimal(ctx sessionctx.Context, row chunk.Row) (*types.MyDecimal, bool, error) {\n\tif row.IsNull(col.Index) {\n\t\treturn nil, true, nil\n\t}\n\treturn row.GetMyDecimal(col.Index), false, nil\n}\n\n// Eval implements Expression interface.\nfunc (col *Column) Eval(row chunk.Row) (types.Datum, error) {\n\treturn row.GetDatum(col.Index, col.RetType), nil\n}\n\n// ConstItem implements Expression interface.\nfunc (col *Column) ConstItem(_ *stmtctx.StatementContext) bool {\n\treturn false\n}\n\n// EvalTime returns DATE/DATETIME/TIMESTAMP representation of Column.\nfunc (col *Column) EvalTime(ctx sessionctx.Context, row chunk.Row) (types.Time, bool, error) {\n\tif row.IsNull(col.Index) {\n\t\treturn types.ZeroTime, true, nil\n\t}\n\treturn row.GetTime(col.Index), false, nil\n}\n\n// EvalDuration returns Duration representation of Column.\nfunc (col *Column) EvalDuration(ctx sessionctx.Context, row chunk.Row) (types.Duration, bool, error) {\n\tif row.IsNull(col.Index) {\n\t\treturn types.Duration{}, true, nil\n\t}\n\tduration := row.GetDuration(col.Index, col.RetType.Decimal)\n\treturn duration, false, nil\n}\n"
  },
  {
    "path": "pkg/expression/constant.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\t\"github.com/secretflow/scql/pkg/util/codec\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n)\n\nvar (\n\t// One stands for a number 1.\n\tOne = &Constant{\n\t\tValue:   types.NewDatum(1),\n\t\tRetType: types.NewFieldType(mysql.TypeTiny),\n\t}\n\n\t// Zero stands for a number 0.\n\tZero = &Constant{\n\t\tValue:   types.NewDatum(0),\n\t\tRetType: types.NewFieldType(mysql.TypeTiny),\n\t}\n\n\t// Null stands for null constant.\n\tNull = &Constant{\n\t\tValue:   types.NewDatum(nil),\n\t\tRetType: types.NewFieldType(mysql.TypeTiny),\n\t}\n)\n\n// Constant stands for a constant value.\ntype Constant struct {\n\tValue   types.Datum\n\tRetType *types.FieldType\n\t// DeferredExpr holds deferred function in PlanCache cached plan.\n\t// it's only used to represent non-deterministic functions(see expression.DeferredFunctions)\n\t// in PlanCache cached plan, so let them can be evaluated until cached item be used.\n\tDeferredExpr Expression\n\t// ParamMarker holds param index inside sessionVars.PreparedParams.\n\t// It's only used to reference a user variable provided in the `EXECUTE` statement or `COM_EXECUTE` binary protocol.\n\tParamMarker *ParamMarker\n\thashcode    []byte\n}\n\n// ParamMarker indicates param provided by COM_STMT_EXECUTE.\ntype ParamMarker struct {\n\tctx   sessionctx.Context\n\torder int\n\ttp    types.FieldType\n\tname  string\n}\n\n// variable stored in constant directly\nfunc (d *ParamMarker) GetUserVar() (types.Datum, bool) {\n\treturn types.Datum{}, false\n}\n\n// GetType implements Expression interface.\nfunc (c *Constant) GetType() *types.FieldType {\n\treturn c.RetType\n}\n\n// EvalInt returns int representation of Constant.\nfunc (c *Constant) EvalInt(ctx sessionctx.Context, _ chunk.Row) (int64, bool, error) {\n\tif dt, lazy, err := c.getLazyDatum(); lazy {\n\t\tif err != nil {\n\t\t\treturn 0, true, err\n\t\t}\n\t\tif dt.IsNull() {\n\t\t\treturn 0, true, nil\n\t\t}\n\t\tval, err := dt.ToInt64(ctx.GetSessionVars().StmtCtx)\n\t\tif err != nil {\n\t\t\treturn 0, true, err\n\t\t}\n\t\tc.Value.SetInt64(val)\n\t} else {\n\t\tif c.GetType().Tp == mysql.TypeNull || c.Value.IsNull() {\n\t\t\treturn 0, true, nil\n\t\t}\n\t}\n\tif c.GetType().Hybrid() || c.Value.Kind() == types.KindBinaryLiteral || c.Value.Kind() == types.KindString {\n\t\tres, err := c.Value.ToInt64(ctx.GetSessionVars().StmtCtx)\n\t\treturn res, err != nil, err\n\t}\n\treturn c.Value.GetInt64(), false, nil\n}\n\n// EvalReal returns real representation of Constant.\nfunc (c *Constant) EvalReal(ctx sessionctx.Context, _ chunk.Row) (float64, bool, error) {\n\tif dt, lazy, err := c.getLazyDatum(); lazy {\n\t\tif err != nil {\n\t\t\treturn 0, true, err\n\t\t}\n\t\tif dt.IsNull() {\n\t\t\treturn 0, true, nil\n\t\t}\n\t\tval, err := dt.ToFloat64(ctx.GetSessionVars().StmtCtx)\n\t\tif err != nil {\n\t\t\treturn 0, true, err\n\t\t}\n\t\tc.Value.SetFloat64(val)\n\t} else {\n\t\tif c.GetType().Tp == mysql.TypeNull || c.Value.IsNull() {\n\t\t\treturn 0, true, nil\n\t\t}\n\t}\n\tif c.GetType().Hybrid() || c.Value.Kind() == types.KindBinaryLiteral || c.Value.Kind() == types.KindString {\n\t\tres, err := c.Value.ToFloat64(ctx.GetSessionVars().StmtCtx)\n\t\treturn res, err != nil, err\n\t}\n\treturn c.Value.GetFloat64(), false, nil\n}\n\n// EvalString returns string representation of Constant.\nfunc (c *Constant) EvalString(ctx sessionctx.Context, _ chunk.Row) (string, bool, error) {\n\tif dt, lazy, err := c.getLazyDatum(); lazy {\n\t\tif err != nil {\n\t\t\treturn \"\", true, err\n\t\t}\n\t\tif dt.IsNull() {\n\t\t\treturn \"\", true, nil\n\t\t}\n\t\tval, err := dt.ToString()\n\t\tif err != nil {\n\t\t\treturn \"\", true, err\n\t\t}\n\t\tc.Value.SetString(val)\n\t} else {\n\t\tif c.GetType().Tp == mysql.TypeNull || c.Value.IsNull() {\n\t\t\treturn \"\", true, nil\n\t\t}\n\t}\n\tres, err := c.Value.ToString()\n\treturn res, err != nil, err\n}\n\n// EvalDecimal returns decimal representation of Constant.\nfunc (c *Constant) EvalDecimal(ctx sessionctx.Context, _ chunk.Row) (*types.MyDecimal, bool, error) {\n\tif dt, lazy, err := c.getLazyDatum(); lazy {\n\t\tif err != nil {\n\t\t\treturn nil, true, err\n\t\t}\n\t\tif dt.IsNull() {\n\t\t\treturn nil, true, nil\n\t\t}\n\t\tc.Value.SetValue(dt.GetValue())\n\t} else {\n\t\tif c.GetType().Tp == mysql.TypeNull || c.Value.IsNull() {\n\t\t\treturn nil, true, nil\n\t\t}\n\t}\n\tres, err := c.Value.ToDecimal(ctx.GetSessionVars().StmtCtx)\n\treturn res, err != nil, err\n}\n\n// EvalTime returns DATE/DATETIME/TIMESTAMP representation of Constant.\nfunc (c *Constant) EvalTime(ctx sessionctx.Context, _ chunk.Row) (val types.Time, isNull bool, err error) {\n\tif dt, lazy, err := c.getLazyDatum(); lazy {\n\t\tif err != nil {\n\t\t\treturn types.ZeroTime, true, err\n\t\t}\n\t\tif dt.IsNull() {\n\t\t\treturn types.ZeroTime, true, nil\n\t\t}\n\t\tval, err := dt.ToString()\n\t\tif err != nil {\n\t\t\treturn types.ZeroTime, true, err\n\t\t}\n\t\ttim, err := types.ParseDatetime(ctx.GetSessionVars().StmtCtx, val)\n\t\tif err != nil {\n\t\t\treturn types.ZeroTime, true, err\n\t\t}\n\t\tc.Value.SetMysqlTime(tim)\n\t} else {\n\t\tif c.GetType().Tp == mysql.TypeNull || c.Value.IsNull() {\n\t\t\treturn types.ZeroTime, true, nil\n\t\t}\n\t}\n\treturn c.Value.GetMysqlTime(), false, nil\n}\n\n// EvalDuration returns Duration representation of Constant.\nfunc (c *Constant) EvalDuration(ctx sessionctx.Context, _ chunk.Row) (val types.Duration, isNull bool, err error) {\n\tif dt, lazy, err := c.getLazyDatum(); lazy {\n\t\tif err != nil {\n\t\t\treturn types.Duration{}, true, err\n\t\t}\n\t\tif dt.IsNull() {\n\t\t\treturn types.Duration{}, true, nil\n\t\t}\n\t\tval, err := dt.ToString()\n\t\tif err != nil {\n\t\t\treturn types.Duration{}, true, err\n\t\t}\n\t\tdur, err := types.ParseDuration(ctx.GetSessionVars().StmtCtx, val, types.MaxFsp)\n\t\tif err != nil {\n\t\t\treturn types.Duration{}, true, err\n\t\t}\n\t\tc.Value.SetMysqlDuration(dur)\n\t} else {\n\t\tif c.GetType().Tp == mysql.TypeNull || c.Value.IsNull() {\n\t\t\treturn types.Duration{}, true, nil\n\t\t}\n\t}\n\treturn c.Value.GetMysqlDuration(), false, nil\n}\n\n// String implements fmt.Stringer interface.\nfunc (c *Constant) String() string {\n\treturn fmt.Sprintf(\"%v\", c.Value.GetValue())\n}\n\n// ConstItem implements Expression interface.\nfunc (c *Constant) ConstItem(sc *stmtctx.StatementContext) bool {\n\treturn !sc.UseCache || (c.DeferredExpr == nil)\n}\n\n// Decorrelate implements Expression interface.\nfunc (c *Constant) Decorrelate(_ *Schema) Expression {\n\treturn c\n}\n\n// Clone implements Expression interface.\nfunc (c *Constant) Clone() Expression {\n\treturn c\n}\n\n// Eval implements Expression interface.\n// func (c *Constant) Eval(_ chunk.Row) (types.Datum, error) {\n// \treturn c.Value, nil\n// }\n\nfunc (c *Constant) getLazyDatum() (dt types.Datum, isLazy bool, err error) {\n\treturn\n}\n\n// HashCode implements Expression interface.\nfunc (c *Constant) HashCode(sc *stmtctx.StatementContext) []byte {\n\tif len(c.hashcode) > 0 {\n\t\treturn c.hashcode\n\t}\n\t_, err := c.Eval(chunk.Row{})\n\tif err != nil {\n\t\tterror.Log(err)\n\t}\n\tc.hashcode = append(c.hashcode, constantFlag)\n\tc.hashcode, err = codec.EncodeValue(sc, c.hashcode, c.Value)\n\tif err != nil {\n\t\tterror.Log(err)\n\t}\n\treturn c.hashcode\n}\n\n// Equal implements Expression interface.\nfunc (c *Constant) Equal(ctx sessionctx.Context, b Expression) bool {\n\ty, ok := b.(*Constant)\n\tif !ok {\n\t\treturn false\n\t}\n\t_, err1 := y.Eval(chunk.Row{})\n\t_, err2 := c.Eval(chunk.Row{})\n\tif err1 != nil || err2 != nil {\n\t\treturn false\n\t}\n\tcon, err := c.Value.CompareDatum(ctx.GetSessionVars().StmtCtx, &y.Value)\n\tif err != nil || con != 0 {\n\t\treturn false\n\t}\n\treturn true\n}\n\n// Eval implements Expression interface.\nfunc (c *Constant) Eval(_ chunk.Row) (types.Datum, error) {\n\tif dt, lazy, err := c.getLazyDatum(); lazy {\n\t\tif err != nil {\n\t\t\treturn c.Value, err\n\t\t}\n\t\tif dt.IsNull() {\n\t\t\tc.Value.SetNull()\n\t\t\treturn c.Value, nil\n\t\t}\n\t\tif c.DeferredExpr != nil {\n\t\t\tsf, sfOk := c.DeferredExpr.(*ScalarFunction)\n\t\t\tif sfOk {\n\t\t\t\tval, err := dt.ConvertTo(sf.GetCtx().GetSessionVars().StmtCtx, c.RetType)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn dt, err\n\t\t\t\t}\n\t\t\t\treturn val, nil\n\t\t\t}\n\t\t}\n\t\treturn dt, nil\n\t}\n\treturn c.Value, nil\n}\n"
  },
  {
    "path": "pkg/expression/errors.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\nvar (\n\t// All the exported errors are defined here:\n\tErrIncorrectParameterCount = terror.ClassExpression.New(mysql.ErrWrongParamcountToNativeFct, mysql.MySQLErrName[mysql.ErrWrongParamcountToNativeFct])\n\tErrDivisionByZero          = terror.ClassExpression.New(mysql.ErrDivisionByZero, mysql.MySQLErrName[mysql.ErrDivisionByZero])\n\tErrOperandColumns          = terror.ClassExpression.New(mysql.ErrOperandColumns, mysql.MySQLErrName[mysql.ErrOperandColumns])\n\tErrRegexp                  = terror.ClassExpression.NewStd(mysql.ErrRegexp)\n\t// All the un-exported errors are defined here:\n\terrNonUniq                     = terror.ClassExpression.New(mysql.ErrNonUniq, mysql.MySQLErrName[mysql.ErrNonUniq])\n\terrFunctionNotExists           = terror.ClassExpression.New(mysql.ErrSpDoesNotExist, mysql.MySQLErrName[mysql.ErrSpDoesNotExist])\n\terrWarnAllowedPacketOverflowed = terror.ClassExpression.New(mysql.ErrWarnAllowedPacketOverflowed, mysql.MySQLErrName[mysql.ErrWarnAllowedPacketOverflowed])\n\terrUnsupportedJSONComparison   = terror.ClassExpression.New(mysql.ErrNotSupportedYet, \"comparison of JSON in the LEAST and GREATEST operators\")\n\tErrInvalidArgumentForLogarithm = terror.ClassExpression.NewStd(mysql.ErrInvalidArgumentForLogarithm)\n\terrIncorrectArgs               = terror.ClassExpression.NewStd(mysql.ErrWrongArguments)\n)\n\n// handleDivisionByZeroError reports error or warning depend on the context.\nfunc handleDivisionByZeroError(ctx sessionctx.Context) error {\n\tsc := ctx.GetSessionVars().StmtCtx\n\t// NOTE(yang.y): SCQL doesn't support the following statement\n\t// if sc.InInsertStmt || sc.InUpdateStmt || sc.InDeleteStmt {\n\t// \tif !ctx.GetSessionVars().SQLMode.HasErrorForDivisionByZeroMode() {\n\t// \t\treturn nil\n\t// \t}\n\t// \tif ctx.GetSessionVars().StrictSQLMode && !sc.DividedByZeroAsWarning {\n\t// \t\treturn ErrDivisionByZero\n\t// \t}\n\t// }\n\tsc.AppendWarning(ErrDivisionByZero)\n\treturn nil\n}\n\n// handleInvalidTimeError reports error or warning depend on the context.\nfunc handleInvalidTimeError(ctx sessionctx.Context, err error) error {\n\tif err == nil || !(types.ErrWrongValue.Equal(err) ||\n\t\ttypes.ErrTruncatedWrongVal.Equal(err) || types.ErrInvalidWeekModeFormat.Equal(err) ||\n\t\ttypes.ErrDatetimeFunctionOverflow.Equal(err)) {\n\t\treturn err\n\t}\n\tsc := ctx.GetSessionVars().StmtCtx\n\tif ctx.GetSessionVars().StrictSQLMode && (sc.InInsertStmt || sc.InUpdateStmt || sc.InDeleteStmt) {\n\t\treturn err\n\t}\n\tsc.AppendWarning(err)\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/expression/expression.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// These are byte flags used for `HashCode()`.\nconst (\n\tconstantFlag       byte = 0\n\tcolumnFlag         byte = 1\n\tscalarFunctionFlag byte = 3\n)\n\ntype Expression interface {\n\tfmt.Stringer\n\n\t// Eval evaluates an expression through a row.\n\tEval(row chunk.Row) (types.Datum, error)\n\n\t// EvalInt returns the int64 representation of expression.\n\tEvalInt(ctx sessionctx.Context, row chunk.Row) (val int64, isNull bool, err error)\n\n\t// EvalReal returns the float64 representation of expression.\n\tEvalReal(ctx sessionctx.Context, row chunk.Row) (val float64, isNull bool, err error)\n\n\t// EvalString returns the string representation of expression.\n\tEvalString(ctx sessionctx.Context, row chunk.Row) (val string, isNull bool, err error)\n\n\t// EvalDecimal returns the decimal representation of expression.\n\tEvalDecimal(ctx sessionctx.Context, row chunk.Row) (val *types.MyDecimal, isNull bool, err error)\n\n\t// EvalTime returns the DATE/DATETIME/TIMESTAMP representation of expression.\n\tEvalTime(ctx sessionctx.Context, row chunk.Row) (val types.Time, isNull bool, err error)\n\n\t// EvalDuration returns the duration representation of expression.\n\tEvalDuration(ctx sessionctx.Context, row chunk.Row) (val types.Duration, isNull bool, err error)\n\n\tGetType() *types.FieldType\n\n\t// Clone copies an expression totally.\n\tClone() Expression\n\n\t// Equal checks whether two expressions are equal.\n\tEqual(ctx sessionctx.Context, e Expression) bool\n\n\t// ConstItem checks if this expression is constant item, regardless of query evaluation state.\n\t// An expression is constant item if it:\n\t// refers no tables.\n\t// refers no correlated column.\n\t// refers no subqueries that refers any tables.\n\t// refers no non-deterministic functions.\n\t// refers no statement parameters.\n\t// refers no param markers when prepare plan cache is enabled.\n\tConstItem(sc *stmtctx.StatementContext) bool\n\n\t// Decorrelate try to decorrelate the expression by schema.\n\tDecorrelate(schema *Schema) Expression\n\n\t// HashCode creates the hashcode for expression which can be used to identify itself from other expression.\n\t// It generated as the following:\n\t// Constant: ConstantFlag+encoded value\n\t// Column: ColumnFlag+encoded value\n\t// ScalarFunction: SFFlag+encoded function name + encoded arg_1 + encoded arg_2 + ...\n\tHashCode(sc *stmtctx.StatementContext) []byte\n}\n\n// VarAssignment represents a variable assignment in Set, such as set global a = 1.\ntype VarAssignment struct {\n\tName        string\n\tExpr        Expression\n\tIsDefault   bool\n\tIsGlobal    bool\n\tIsSystem    bool\n\tExtendValue *Constant\n}\n\nfunc isColumnInOperand(c *Column) bool {\n\treturn c.InOperand\n}\n\n// IsEQCondFromIn checks if an expression is equal condition converted from `[not] in (subq)`.\nfunc IsEQCondFromIn(expr Expression) bool {\n\tsf, ok := expr.(*ScalarFunction)\n\tif !ok || sf.FuncName.L != ast.EQ {\n\t\treturn false\n\t}\n\tcols := make([]*Column, 0, 1)\n\tcols = ExtractColumnsFromExpressions(cols, sf.GetArgs(), isColumnInOperand)\n\treturn len(cols) > 0\n}\n\ntype CNFExprs []Expression\n\n// splitNormalFormItems split CNF(conjunctive normal form) like \"a and b and c\", or DNF(disjunctive normal form) like \"a or b or c\"\nfunc splitNormalFormItems(onExpr Expression, funcName string) []Expression {\n\tswitch v := onExpr.(type) {\n\tcase *ScalarFunction:\n\t\tif v.FuncName.L == funcName {\n\t\t\tvar ret []Expression\n\t\t\tfor _, arg := range v.GetArgs() {\n\t\t\t\tret = append(ret, splitNormalFormItems(arg, funcName)...)\n\t\t\t}\n\t\t\treturn ret\n\t\t}\n\t}\n\treturn []Expression{onExpr}\n}\n\n// SplitCNFItems splits CNF items.\n// CNF means conjunctive normal form, e.g. \"a and b and c\".\nfunc SplitCNFItems(onExpr Expression) []Expression {\n\treturn splitNormalFormItems(onExpr, ast.LogicAnd)\n}\n\n// EvaluateExprWithNull sets columns in schema as null and calculate the final result of the scalar function.\n// If the Expression is a non-constant value, it means the result is unknown.\nfunc EvaluateExprWithNull(ctx sessionctx.Context, schema *Schema, expr Expression) Expression {\n\tswitch x := expr.(type) {\n\tcase *ScalarFunction:\n\t\targs := make([]Expression, len(x.GetArgs()))\n\t\tfor i, arg := range x.GetArgs() {\n\t\t\targs[i] = EvaluateExprWithNull(ctx, schema, arg)\n\t\t}\n\t\treturn NewFunctionInternal(ctx, x.FuncName.L, x.RetType, args...)\n\tcase *Column:\n\t\tif !schema.Contains(x) {\n\t\t\treturn x\n\t\t}\n\t\treturn &Constant{Value: types.Datum{}, RetType: types.NewFieldType(mysql.TypeNull)}\n\tcase *Constant:\n\t\t//if x.DeferredExpr != nil {\n\t\t//\treturn FoldConstant(x)\n\t\t//}\n\t}\n\treturn expr\n}\n\n// composeConditionWithBinaryOp composes condition with binary operator into a balance deep tree, which benefits a lot for pb decoder/encoder.\nfunc composeConditionWithBinaryOp(ctx sessionctx.Context, conditions []Expression, funcName string) Expression {\n\tlength := len(conditions)\n\tif length == 0 {\n\t\treturn nil\n\t}\n\tif length == 1 {\n\t\treturn conditions[0]\n\t}\n\texpr := NewFunctionInternal(ctx, funcName,\n\t\ttypes.NewFieldType(mysql.TypeTiny),\n\t\tcomposeConditionWithBinaryOp(ctx, conditions[:length/2], funcName),\n\t\tcomposeConditionWithBinaryOp(ctx, conditions[length/2:], funcName))\n\treturn expr\n}\n\n// ComposeCNFCondition composes CNF items into a balance deep CNF tree, which benefits a lot for pb decoder/encoder.\nfunc ComposeCNFCondition(ctx sessionctx.Context, conditions ...Expression) Expression {\n\treturn composeConditionWithBinaryOp(ctx, conditions, ast.LogicAnd)\n}\n\n// ComposeDNFCondition composes DNF items into a balance deep DNF tree.\nfunc ComposeDNFCondition(ctx sessionctx.Context, conditions ...Expression) Expression {\n\treturn composeConditionWithBinaryOp(ctx, conditions, ast.LogicOr)\n}\n\n// wrapWithIsTrue wraps `arg` with istrue function if the return type of expr is not\n// type int, otherwise, returns `arg` directly.\n// The `keepNull` controls what the istrue function will return when `arg` is null:\n// 1. keepNull is true and arg is null, the istrue function returns null.\n// 2. keepNull is false and arg is null, the istrue function returns 0.\n// TODO: remove this function. ScalarFunction should be newed in one place.\nfunc wrapWithIsTrue(ctx sessionctx.Context, keepNull bool, arg Expression) (Expression, error) {\n\tif arg.GetType().EvalType() == types.ETInt {\n\t\treturn arg, nil\n\t}\n\tfc := &isTrueOrFalseFunctionClass{baseFunctionClass{ast.IsTruth, 1, 1}, opcode.IsTruth, keepNull}\n\tf, err := fc.getFunction(ctx, []Expression{arg})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsf := &ScalarFunction{\n\t\tFuncName: model.NewCIStr(fmt.Sprintf(\"sig_%T\", f)),\n\t\tFunction: f,\n\t\tRetType:  f.getRetTp(),\n\t}\n\treturn sf, nil\n}\n\nfunc extractBinaryOpItems(conditions *ScalarFunction, funcName string) []Expression {\n\tvar ret []Expression\n\tfor _, arg := range conditions.GetArgs() {\n\t\tif sf, ok := arg.(*ScalarFunction); ok && sf.FuncName.L == funcName {\n\t\t\tret = append(ret, extractBinaryOpItems(sf, funcName)...)\n\t\t} else {\n\t\t\tret = append(ret, arg)\n\t\t}\n\t}\n\treturn ret\n}\n\n// FlattenDNFConditions extracts DNF expression's leaf item.\n// e.g. or(or(a=1, a=2), or(a=3, a=4)), we'll get [a=1, a=2, a=3, a=4].\nfunc FlattenDNFConditions(DNFCondition *ScalarFunction) []Expression {\n\treturn extractBinaryOpItems(DNFCondition, ast.LogicOr)\n}\n\n// IsBinaryLiteral checks whether an expression is a binary literal\nfunc IsBinaryLiteral(expr Expression) bool {\n\tcon, ok := expr.(*Constant)\n\treturn ok && con.Value.Kind() == types.KindBinaryLiteral\n}\n\nfunc analyzeScalarFunctionParams(sf *ScalarFunction) (\n\tvarAndConst bool, allVars bool, allConst bool) {\n\thasVar := false\n\thasConst := false\n\tfor _, expr := range sf.GetArgs() {\n\t\tswitch expr.(type) {\n\t\tcase *Constant:\n\t\t\thasConst = true\n\t\tcase *Column, *CorrelatedColumn:\n\t\t\thasVar = true\n\t\tcase *ScalarFunction:\n\t\t\tvc, av, ac := analyzeScalarFunctionParams(\n\t\t\t\texpr.(*ScalarFunction))\n\t\t\tif vc {\n\t\t\t\treturn true, false, false\n\t\t\t}\n\t\t\thasVar = hasVar || av\n\t\t\thasConst = hasConst || ac\n\t\t}\n\t}\n\treturn hasVar && hasConst, hasVar && !hasConst, hasConst && !hasVar\n}\n"
  },
  {
    "path": "pkg/expression/expression_to_stmt.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\tdriver \"github.com/secretflow/scql/pkg/types/parser_driver\"\n)\n\n// ExprConverter converts expression to expr node\ntype ExprConverter struct {\n}\n\nconst (\n\tprecNonOperatorExpression = 100\n)\n\nfunc (c ExprConverter) ConvertExpressionToExprNode(dialect format.Dialect, expr Expression, prec int, idToExpr map[int64]ast.ExprNode) (ast.ExprNode, error) {\n\tswitch x := expr.(type) {\n\tcase *Constant:\n\t\treturn c.convertConst(x)\n\tcase *Column:\n\t\tif expr, ok := idToExpr[x.UniqueID]; ok {\n\t\t\treturn expr, nil\n\t\t}\n\t\treturn c.convertColumn(x)\n\tcase *ScalarFunction:\n\t\treturn c.convertScalarFunction(dialect, x, prec, idToExpr)\n\tdefault:\n\t\treturn nil, errors.Errorf(\"Unknown expression {%v}, type: %s\", expr, reflect.TypeOf(expr))\n\t}\n}\n\nfunc (c ExprConverter) isArgScalarFunc(expr Expression) bool {\n\tswitch expr.(type) {\n\tcase *ScalarFunction:\n\t\treturn true\n\t}\n\treturn false\n}\nfunc (c ExprConverter) convertConst(constant *Constant) (*driver.ValueExpr, error) {\n\treturn &driver.ValueExpr{Datum: constant.Value}, nil\n}\n\nfunc (c ExprConverter) convertColumn(column *Column) (*ast.ColumnNameExpr, error) {\n\tname := ast.ColumnName{}\n\t// TODO(@xiaoyuan) origin name of window funcs may be nil, it's name stored in p.names\n\t// column (not scalar function) can split by \".\"\n\tsubStrs := strings.Split(column.OrigName, \".\")\n\tif len(subStrs) == 0 || len(subStrs) > 3 {\n\t\treturn nil, fmt.Errorf(\"failed to check column name for len(split(%s)) is not in (1,2,3)\", column.OrigName)\n\t}\n\n\tname.Name = model.NewCIStr(subStrs[len(subStrs)-1])\n\tif len(subStrs) >= 2 {\n\t\tname.Table = model.NewCIStr(subStrs[len(subStrs)-2])\n\t}\n\tif len(subStrs) == 3 {\n\t\tname.Schema = model.NewCIStr(subStrs[len(subStrs)-3])\n\t}\n\treturn &ast.ColumnNameExpr{Name: &name}, nil\n}\n\n// for now binary function need Parentheses\n// ref to https://dev.mysql.com/doc/refman/8.0/en/operator-precedence.html\n// TODO: @xiaoyuan we don't support MEMBER OF/IS/BETWEEN......\nfunc (c ExprConverter) getOpPrecedence(expr *ScalarFunction) int {\n\tswitch expr.Function.(type) {\n\tcase *builtinLogicXorSig:\n\t\treturn 10\n\tcase *builtinLogicOrSig:\n\t\treturn 15\n\tcase *builtinLogicAndSig:\n\t\treturn 20\n\tcase *builtinCaseWhenIntSig, *builtinCaseWhenDecimalSig, *builtinCaseWhenRealSig, *builtinCaseWhenStringSig:\n\t\treturn 30\n\tcase *builtinLEIntSig, *builtinLEStringSig, *builtinLERealSig, *builtinLEDecimalSig,\n\t\t*builtinGTIntSig, *builtinGTStringSig, *builtinGTRealSig, *builtinGTDecimalSig,\n\t\t*builtinGEIntSig, *builtinGEStringSig, *builtinGERealSig, *builtinGEDecimalSig,\n\t\t*builtinLTIntSig, *builtinLTStringSig, *builtinLTRealSig, *builtinLTDecimalSig,\n\t\t*builtinEQIntSig, *builtinEQStringSig, *builtinEQRealSig, *builtinEQDecimalSig,\n\t\t*builtinNEIntSig, *builtinNEStringSig, *builtinNERealSig, *builtinNEDecimalSig,\n\t\t*builtinLikeSig, *builtinInIntSig, *builtinInStringSig:\n\t\treturn 40\n\tcase *builtinArithmeticPlusRealSig, *builtinArithmeticPlusDecimalSig,\n\t\t*builtinArithmeticPlusIntSig, *builtinArithmeticMinusRealSig,\n\t\t*builtinArithmeticMinusDecimalSig, *builtinArithmeticMinusIntSig:\n\t\treturn 50\n\tcase *builtinArithmeticMultiplyIntUnsignedSig, *builtinArithmeticMultiplyRealSig,\n\t\t*builtinArithmeticMultiplyDecimalSig, *builtinArithmeticMultiplyIntSig,\n\t\t*builtinArithmeticDivideRealSig, *builtinArithmeticDivideDecimalSig,\n\t\t*builtinArithmeticModIntSig, *builtinArithmeticIntDivideIntSig:\n\t\treturn 60\n\tcase *builtinUnaryMinusDecimalSig, *builtinUnaryMinusIntSig, *builtinUnaryMinusRealSig:\n\t\treturn 70\n\t}\n\treturn precNonOperatorExpression\n}\n\nfunc (c ExprConverter) convertScalarFunction(dialect format.Dialect, expr *ScalarFunction, fatherPrec int, idToExpr map[int64]ast.ExprNode) (result ast.ExprNode, err error) {\n\tchildren := make([]ast.ExprNode, 0, len(expr.GetArgs()))\n\tprec := c.getOpPrecedence(expr)\n\tfor _, arg := range expr.GetArgs() {\n\t\targExpr, err := c.ConvertExpressionToExprNode(dialect, arg, prec, idToExpr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"convertScalarFunction: %v\", err)\n\t\t}\n\t\tchildren = append(children, argExpr)\n\t}\n\tdefer func() {\n\t\tif fatherPrec != precNonOperatorExpression && (fatherPrec > prec ||\n\t\t\t(fatherPrec != 0 && IsCompareOp(expr) && dialect.NeedParenthesesForCmpOperand())) {\n\t\t\tresult = &ast.ParenthesesExpr{Expr: result}\n\t\t}\n\t}()\n\tswitch expr.FuncName.L {\n\tcase ast.Cast:\n\t\treturn &ast.FuncCastExpr{Expr: children[0], Tp: expr.RetType, FunctionType: ast.CastFunction}, nil\n\tcase ast.Ifnull, ast.Coalesce:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase ast.If:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase ast.Abs, ast.Round, ast.Log10, ast.Ceil, ast.Floor, ast.Instr, ast.Length, ast.Sin, ast.Acos, ast.Cos, ast.Tan, ast.Cot, ast.Asin, ast.Atan, ast.Atan2, ast.Degrees, ast.Ln, ast.Log2, ast.Sqrt, ast.Pow, ast.Greatest, ast.Least, ast.Radians, ast.Exp:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\t}\n\tswitch expr.Function.(type) {\n\tcase *builtinUnaryMinusDecimalSig, *builtinUnaryMinusIntSig, *builtinUnaryMinusRealSig:\n\t\treturn &ast.UnaryOperationExpr{Op: opcode.Minus, V: children[0]}, nil\n\tcase *builtinArithmeticPlusRealSig, *builtinArithmeticPlusDecimalSig, *builtinArithmeticPlusIntSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.Plus, L: children[0], R: children[1]}, nil\n\tcase *builtinArithmeticMinusRealSig, *builtinArithmeticMinusDecimalSig, *builtinArithmeticMinusIntSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.Minus, L: children[0], R: children[1]}, nil\n\tcase *builtinArithmeticMultiplyDecimalSig, *builtinArithmeticMultiplyIntSig, *builtinArithmeticMultiplyIntUnsignedSig, *builtinArithmeticMultiplyRealSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.Mul, L: children[0], R: children[1]}, nil\n\tcase *builtinArithmeticDivideRealSig, *builtinArithmeticDivideDecimalSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.Div, L: children[0], R: children[1]}, nil\n\tcase *builtinArithmeticModIntSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.Mod, L: children[0], R: children[1]}, nil\n\tcase *builtinArithmeticIntDivideIntSig:\n\t\t// for postgres, intdiv is not a operator but a function call\n\t\tif _, ok := dialect.(*format.PostgresDialect); ok {\n\t\t\treturn &ast.FuncCallExpr{FnName: model.NewCIStr(expr.FuncName.L), Args: children}, nil\n\t\t}\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.IntDiv, L: children[0], R: children[1]}, nil\n\tcase *builtinLTIntSig, *builtinLTStringSig, *builtinLTRealSig, *builtinLTDecimalSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.LT, L: children[0], R: children[1]}, nil\n\tcase *builtinEQIntSig, *builtinEQStringSig, *builtinEQRealSig, *builtinEQDecimalSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.EQ, L: children[0], R: children[1]}, nil\n\tcase *builtinLEIntSig, *builtinLEStringSig, *builtinLERealSig, *builtinLEDecimalSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.LE, L: children[0], R: children[1]}, nil\n\tcase *builtinGTIntSig, *builtinGTStringSig, *builtinGTRealSig, *builtinGTDecimalSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.GT, L: children[0], R: children[1]}, nil\n\tcase *builtinGEIntSig, *builtinGEStringSig, *builtinGERealSig, *builtinGEDecimalSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.GE, L: children[0], R: children[1]}, nil\n\tcase *builtinNEIntSig, *builtinNEStringSig, *builtinNERealSig, *builtinNEDecimalSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.NE, L: children[0], R: children[1]}, nil\n\tcase *builtinLogicAndSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.LogicAnd, L: children[0], R: children[1]}, nil\n\tcase *builtinLogicOrSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.LogicOr, L: children[0], R: children[1]}, nil\n\tcase *builtinLogicXorSig:\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.LogicXor, L: children[0], R: children[1]}, nil\n\tcase *builtinLikeSig:\n\t\tswitch value := children[2].(type) {\n\t\tcase *driver.ValueExpr:\n\t\t\treturn &ast.PatternLikeExpr{Expr: children[0], Pattern: children[1], Escape: byte(value.GetInt64())}, nil\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"value type assertion for like statement failed, type of escape: %s\", reflect.TypeOf(value))\n\t\t}\n\t// case *builtinRegexpSig, *builtinRegexpUTF8Sig:\n\t// \treturn  &ast.ColumnNameExpr{Name: &ast.ColumnName{Table: children[0].}}, nil\n\tcase *builtinDecimalIsNullSig, *builtinIntIsNullSig, *builtinRealIsNullSig, *builtinStringIsNullSig:\n\t\treturn &ast.IsNullExpr{Expr: children[0], Not: false}, nil\n\tcase *builtinInIntSig, *builtinInStringSig:\n\t\treturn &ast.PatternInExpr{Expr: children[0], List: children[1:]}, nil\n\tcase *builtinSubstring2ArgsSig, *builtinSubstring2ArgsUTF8Sig, *builtinSubstring3ArgsSig, *builtinSubstring3ArgsUTF8Sig:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase *builtinTrimSig:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase *builtinUnaryNotRealSig, *builtinUnaryNotDecimalSig, *builtinUnaryNotIntSig:\n\t\t// not always need ()\n\t\treturn &ast.UnaryOperationExpr{Op: opcode.Not, V: &ast.ParenthesesExpr{Expr: children[0]}}, nil\n\tcase *builtinCaseWhenIntSig, *builtinCaseWhenDecimalSig, *builtinCaseWhenRealSig, *builtinCaseWhenStringSig:\n\t\tvar whenClauses []*ast.WhenClause\n\t\tfor i := 0; i < len(children)-1; i = i + 2 {\n\t\t\twhenClauses = append(whenClauses, &ast.WhenClause{Expr: children[i], Result: children[i+1]})\n\t\t}\n\t\tresult := &ast.CaseExpr{WhenClauses: whenClauses}\n\t\tif len(children)%2 == 1 {\n\t\t\tresult.ElseClause = children[len(children)-1]\n\t\t}\n\t\treturn result, nil\n\tcase *builtinConcatSig, *builtinLowerSig, *builtinUpperUTF8Sig:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase *builtinTruncateDecimalSig, *builtinTruncateIntSig, *builtinTruncateRealSig, *builtinTruncateUintSig:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase *builtinNowWithoutArgSig, *builtinCurrentDateSig, *builtinCurrentTime0ArgSig, *builtinLastDaySig:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase *builtinAddDateDatetimeIntSig, *builtinSubDateDatetimeIntSig, *builtinAddDatetimeAndStringSig, *builtinSubDatetimeAndStringSig:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase *builtinDateDiffSig, *builtinTimeTimeTimeDiffSig:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase *builtinStrToDateDateSig, *builtinStrToDateDatetimeSig, *builtinStrToDateDurationSig:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase *builtinDateFormatSig:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\tcase *builtinGeoDist:\n\t\treturn c.buildGeoDistExpr(children, dialect, prec, idToExpr)\n\tcase *builtinReplaceSig:\n\t\treturn &ast.FuncCallExpr{FnName: expr.FuncName, Args: children}, nil\n\t}\n\treturn nil, errors.Errorf(\"Unknown expr: %+v(%s)\", expr.Function, expr.FuncName)\n}\n\nfunc radians(node ast.ExprNode) *ast.FuncCallExpr {\n\treturn &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Radians), Args: []ast.ExprNode{node}}\n}\n\nfunc (c ExprConverter) buildGeoDistExpr(children []ast.ExprNode, dialect format.Dialect, prec int, idToExpr map[int64]ast.ExprNode) (ast.ExprNode, error) {\n\tlo1 := children[0] //longtitude1\n\tla1 := children[1] //latitude1\n\tlo2 := children[2] //longtitude2\n\tla2 := children[3] //latitude2\n\n\tlo1Radians := radians(lo1)\n\tla1Radians := radians(la1)\n\tlo2Radians := radians(lo2)\n\tla2Radians := radians(la2)\n\n\tsinLa1 := &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Sin), Args: []ast.ExprNode{la1Radians}}\n\tsinLa2 := &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Sin), Args: []ast.ExprNode{la2Radians}}\n\tcosLa1 := &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Cos), Args: []ast.ExprNode{la1Radians}}\n\tcosLa2 := &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Cos), Args: []ast.ExprNode{la2Radians}}\n\n\t// lo1 - lo2\n\tlo1MinusLo2 := &ast.BinaryOperationExpr{Op: opcode.Minus, L: lo1Radians, R: lo2Radians}\n\t// cos(lo1 - lo2)\n\tcosLo1MinusLo2 := &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Cos), Args: []ast.ExprNode{lo1MinusLo2}}\n\n\t// sin(la1) * sin(la2)\n\tsinLa1MulSinLa2 := &ast.BinaryOperationExpr{Op: opcode.Mul, L: sinLa1, R: sinLa2}\n\n\t// cos(la1) * cos(la2)\n\tcosLa1MulCosLa2 := &ast.BinaryOperationExpr{Op: opcode.Mul, L: cosLa1, R: cosLa2}\n\t// cos(la1) * cos(la2) * cos(lo1 - lo2)\n\tcosMulCosMulCos := &ast.BinaryOperationExpr{Op: opcode.Mul, L: cosLa1MulCosLa2, R: cosLo1MinusLo2}\n\t// sin(la1) * sin(la2) + cos(la1) * cos(la2) * cos(lo1 - lo2)\n\tsinPlusCos := &ast.BinaryOperationExpr{Op: opcode.Plus, L: sinLa1MulSinLa2, R: cosMulCosMulCos}\n\n\t// arccos(sin(la1) * sin(la2) + cos(la1) * cos(la2) * cos(lo1 - lo2))\n\tarcCos := &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Acos), Args: []ast.ExprNode{sinPlusCos}}\n\n\tif len(children) == 4 {\n\t\tradius := &Constant{\n\t\t\tValue:   types.NewDatum(6371),\n\t\t\tRetType: types.NewFieldType(mysql.TypeInt24),\n\t\t}\n\t\tradiusNode, err := c.ConvertExpressionToExprNode(dialect, radius, prec, idToExpr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.Mul, L: radiusNode, R: arcCos}, nil\n\t} else {\n\t\tradiusNode := children[4]\n\t\treturn &ast.BinaryOperationExpr{Op: opcode.Mul, L: radiusNode, R: arcCos}, nil\n\t}\n}\n\nfunc IsCompareOp(expr *ScalarFunction) bool {\n\tswitch expr.Function.(type) {\n\tcase *builtinLEIntSig, *builtinLEStringSig, *builtinLERealSig, *builtinLEDecimalSig,\n\t\t*builtinGTIntSig, *builtinGTStringSig, *builtinGTRealSig, *builtinGTDecimalSig,\n\t\t*builtinGEIntSig, *builtinGEStringSig, *builtinGERealSig, *builtinGEDecimalSig,\n\t\t*builtinLTIntSig, *builtinLTStringSig, *builtinLTRealSig, *builtinLTDecimalSig,\n\t\t*builtinEQIntSig, *builtinEQStringSig, *builtinEQRealSig, *builtinEQDecimalSig,\n\t\t*builtinNEIntSig, *builtinNEStringSig, *builtinNERealSig, *builtinNEDecimalSig:\n\t\treturn true\n\t}\n\treturn false\n\n}\n"
  },
  {
    "path": "pkg/expression/function_traits.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport \"github.com/secretflow/scql/pkg/parser/ast\"\n\n// DisableFoldFunctions stores functions which prevent child scope functions from being constant folded.\n// Typically, these functions shall also exist in unFoldableFunctions, to stop from being folded when they themselves\n// are in child scope of an outer function, and the outer function is recursively folding its children.\nvar DisableFoldFunctions = map[string]struct{}{\n\tast.Benchmark: {},\n}\n\n// DeferredFunctions stores non-deterministic functions, which can be deferred only when the plan cache is enabled.\nvar DeferredFunctions = map[string]struct{}{\n\tast.Now:              {},\n\tast.CurrentTimestamp: {},\n\tast.UTCTime:          {},\n\tast.Curtime:          {},\n\tast.CurrentTime:      {},\n\tast.UTCTimestamp:     {},\n\tast.UnixTimestamp:    {},\n\tast.Sysdate:          {},\n\tast.Curdate:          {},\n\tast.CurrentDate:      {},\n\tast.UTCDate:          {},\n\tast.Rand:             {},\n\tast.UUID:             {},\n}\n\n// unFoldableFunctions stores functions which can not be folded duration constant folding stage.\nvar unFoldableFunctions = map[string]struct{}{\n\tast.Sysdate:   {},\n\tast.FoundRows: {},\n\tast.Rand:      {},\n\tast.UUID:      {},\n\tast.Sleep:     {},\n\tast.RowFunc:   {},\n\tast.Values:    {},\n\tast.SetVar:    {},\n\tast.GetVar:    {},\n\tast.GetParam:  {},\n\tast.Benchmark: {},\n\tast.DayName:   {},\n\t// ast.NextVal:   {},\n\t// ast.LastVal:   {},\n\t// ast.SetVal:    {},\n}\n"
  },
  {
    "path": "pkg/expression/helper.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nfunc boolToInt64(v bool) int64 {\n\tif v {\n\t\treturn 1\n\t}\n\treturn 0\n}\n"
  },
  {
    "path": "pkg/expression/rand.go",
    "content": "// Copyright 2020 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport \"time\"\n\nconst maxRandValue = 0x3FFFFFFF\n\n// MysqlRng is random number generator and this implementation is ported from MySQL.\n// See https://github.com/tikv/tikv/pull/6117#issuecomment-562489078.\ntype MysqlRng struct {\n\tseed1 uint32\n\tseed2 uint32\n}\n\n// NewWithSeed create a rng with random seed.\nfunc NewWithSeed(seed int64) *MysqlRng {\n\tseed1 := uint32(seed*0x10001+55555555) % maxRandValue\n\tseed2 := uint32(seed*0x10000001) % maxRandValue\n\treturn &MysqlRng{seed1: seed1, seed2: seed2}\n}\n\n// NewWithTime create a rng with time stamp.\nfunc NewWithTime() *MysqlRng {\n\treturn NewWithSeed(time.Now().UnixNano())\n}\n\n// Gen will generate random number.\nfunc (rng *MysqlRng) Gen() float64 {\n\trng.seed1 = (rng.seed1*3 + rng.seed2) % maxRandValue\n\trng.seed2 = (rng.seed1 + rng.seed2 + 33) % maxRandValue\n\treturn float64(rng.seed1) / float64(maxRandValue)\n}\n"
  },
  {
    "path": "pkg/expression/scalar_function.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n\t\"github.com/secretflow/scql/pkg/util/codec\"\n\t\"github.com/secretflow/scql/pkg/util/hack\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// error definitions.\nvar (\n\tErrNoDB = terror.ClassOptimizer.New(mysql.ErrNoDB, mysql.MySQLErrName[mysql.ErrNoDB])\n)\n\n// ScalarFunction is the function that returns a value.\ntype ScalarFunction struct {\n\tFuncName model.CIStr\n\t// RetType is the type that ScalarFunction returns.\n\t// TODO: Implement type inference here, now we use ast's return type temporarily.\n\tRetType  *types.FieldType\n\tFunction builtinFunc\n\thashcode []byte\n}\n\nfunc (sf *ScalarFunction) GetType() *types.FieldType {\n\treturn sf.RetType\n}\n\n// Equal implements Expression interface.\nfunc (sf *ScalarFunction) Equal(ctx sessionctx.Context, e Expression) bool {\n\tfun, ok := e.(*ScalarFunction)\n\tif !ok {\n\t\treturn false\n\t}\n\tif sf.FuncName.L != fun.FuncName.L {\n\t\treturn false\n\t}\n\treturn sf.Function.equal(fun.Function)\n}\n\n// GetArgs gets arguments of function.\nfunc (sf *ScalarFunction) GetArgs() []Expression {\n\treturn sf.Function.getArgs()\n}\n\n// GetCtx gets the context of function.\nfunc (sf *ScalarFunction) GetCtx() sessionctx.Context {\n\treturn sf.Function.getCtx()\n}\n\n// ConstItem implements Expression interface.\nfunc (sf *ScalarFunction) ConstItem(sc *stmtctx.StatementContext) bool {\n\t// Note: some unfoldable functions are deterministic, we use unFoldableFunctions here for simplification.\n\tif _, ok := unFoldableFunctions[sf.FuncName.L]; ok {\n\t\treturn false\n\t}\n\tfor _, arg := range sf.GetArgs() {\n\t\tif !arg.ConstItem(sc) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// String implements fmt.Stringer interface.\nfunc (sf *ScalarFunction) String() string {\n\tvar buffer bytes.Buffer\n\tfmt.Fprintf(&buffer, \"%s(\", sf.FuncName.L)\n\tfor i, arg := range sf.GetArgs() {\n\t\tbuffer.WriteString(arg.String())\n\t\tif i+1 != len(sf.GetArgs()) {\n\t\t\tbuffer.WriteString(\", \")\n\t\t}\n\t}\n\tbuffer.WriteString(\")\")\n\treturn buffer.String()\n}\n\n// typeInferForNull infers the NULL constants field type and set the field type\n// of NULL constant same as other non-null operands.\nfunc typeInferForNull(args []Expression) {\n\tif len(args) < 2 {\n\t\treturn\n\t}\n\tvar isNull = func(expr Expression) bool {\n\t\tcons, ok := expr.(*Constant)\n\t\treturn ok && cons.RetType.Tp == mysql.TypeNull && cons.Value.IsNull()\n\t}\n\t// Infer the actual field type of the NULL constant.\n\tvar retFieldTp *types.FieldType\n\tvar hasNullArg bool\n\tfor _, arg := range args {\n\t\tisNullArg := isNull(arg)\n\t\tif !isNullArg && retFieldTp == nil {\n\t\t\tretFieldTp = arg.GetType()\n\t\t}\n\t\thasNullArg = hasNullArg || isNullArg\n\t\t// Break if there are both NULL and non-NULL expression\n\t\tif hasNullArg && retFieldTp != nil {\n\t\t\tbreak\n\t\t}\n\t}\n\tif !hasNullArg || retFieldTp == nil {\n\t\treturn\n\t}\n\tfor _, arg := range args {\n\t\tif isNull(arg) {\n\t\t\t*arg.GetType() = *retFieldTp\n\t\t}\n\t}\n}\n\n// newFunctionImpl creates a new scalar function or constant.\nfunc newFunctionImpl(ctx sessionctx.Context, fold bool, funcName string, retType *types.FieldType, args ...Expression) (Expression, error) {\n\tif retType == nil {\n\t\treturn nil, errors.Errorf(\"RetType cannot be nil for ScalarFunction\")\n\t}\n\tif funcName == ast.Cast {\n\t\treturn BuildCastFunction(ctx, args[0], retType), nil\n\t}\n\tfc, ok := funcs[funcName]\n\tif !ok {\n\t\tdb := ctx.GetSessionVars().CurrentDB\n\t\tif db == \"\" {\n\t\t\treturn nil, errors.Trace(ErrNoDB)\n\t\t}\n\n\t\treturn nil, errFunctionNotExists.GenWithStackByArgs(\"FUNCTION\", db+\".\"+funcName)\n\t}\n\t/* NOTE(yang.y): not sure we need flag EnableNoopFuncs\n\tif !ctx.GetSessionVars().EnableNoopFuncs {\n\t\tif _, ok := noopFuncs[funcName]; ok {\n\t\t\treturn nil, ErrFunctionsNoopImpl.GenWithStackByArgs(funcName)\n\t\t}\n\t} */\n\tfuncArgs := make([]Expression, len(args))\n\tcopy(funcArgs, args)\n\ttypeInferForNull(funcArgs)\n\tf, err := fc.getFunction(ctx, funcArgs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif builtinRetTp := f.getRetTp(); builtinRetTp.Tp != mysql.TypeUnspecified || retType.Tp == mysql.TypeUnspecified {\n\t\tretType = builtinRetTp\n\t}\n\tsf := &ScalarFunction{\n\t\tFuncName: model.NewCIStr(funcName),\n\t\tRetType:  retType,\n\t\tFunction: f,\n\t}\n\t/* NOTE(yang.y): not sure we need fold constant\n\tif fold {\n\t\treturn FoldConstant(sf), nil\n\t} */\n\treturn sf, nil\n}\n\nfunc TransferDateFuncIntervalToSeconds(funcArgs []Expression) ([]Expression, error) {\n\tres := make([]Expression, len(funcArgs)-1)\n\tcopy(res, funcArgs[:len(funcArgs)-1])\n\tbaseDateArithmitical := newDateArighmeticalUtil()\n\tintervalEvalTp := funcArgs[1].GetType().EvalType()\n\tif intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal && intervalEvalTp != types.ETReal {\n\t\tintervalEvalTp = types.ETInt\n\t}\n\tunit, isNull, err := funcArgs[2].EvalString(nil, chunk.Row{})\n\tif isNull || err != nil {\n\t\treturn nil, err\n\t}\n\tgetIntervalFunction := baseDateArithmitical.getIntervalFromString\n\tswitch intervalEvalTp {\n\tcase types.ETString:\n\tcase types.ETInt:\n\t\tgetIntervalFunction = baseDateArithmitical.getIntervalFromInt\n\tcase types.ETDecimal:\n\t\tgetIntervalFunction = baseDateArithmitical.getIntervalFromDecimal\n\tcase types.ETReal:\n\t\tgetIntervalFunction = baseDateArithmitical.getIntervalFromReal\n\t}\n\tinterval, isNull, err := getIntervalFunction(nil, funcArgs, chunk.Row{}, unit)\n\tif isNull || err != nil {\n\t\treturn nil, err\n\t}\n\tsec, err := baseDateArithmitical.returnIntervalSeconds(nil, interval, unit)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tres[1] = &Constant{\n\t\tValue:   types.NewIntDatum(sec),\n\t\tRetType: types.NewFieldType(mysql.TypeLong),\n\t}\n\treturn res, nil\n}\n\n// NewFunction creates a new scalar function or constant via a constant folding.\nfunc NewFunction(ctx sessionctx.Context, funcName string, retType *types.FieldType, args ...Expression) (Expression, error) {\n\treturn newFunctionImpl(ctx, true, funcName, retType, args...)\n}\n\n// NewFunctionBase creates a new scalar function with no constant folding.\nfunc NewFunctionBase(ctx sessionctx.Context, funcName string, retType *types.FieldType, args ...Expression) (Expression, error) {\n\treturn newFunctionImpl(ctx, false, funcName, retType, args...)\n}\n\n// ScalarFuncs2Exprs converts []*ScalarFunction to []Expression.\nfunc ScalarFuncs2Exprs(funcs []*ScalarFunction) []Expression {\n\tresult := make([]Expression, 0, len(funcs))\n\tfor _, col := range funcs {\n\t\tresult = append(result, col)\n\t}\n\treturn result\n}\n\n// NewFunctionInternal is similar to NewFunction, but do not returns error, should only be used internally.\nfunc NewFunctionInternal(ctx sessionctx.Context, funcName string, retType *types.FieldType, args ...Expression) Expression {\n\texpr, err := NewFunction(ctx, funcName, retType, args...)\n\tterror.Log(err)\n\treturn expr\n}\n\n// Decorrelate implements Expression interface.\nfunc (sf *ScalarFunction) Decorrelate(schema *Schema) Expression {\n\tfor i, arg := range sf.GetArgs() {\n\t\tsf.GetArgs()[i] = arg.Decorrelate(schema)\n\t}\n\treturn sf\n}\n\n// EvalInt implements Expression interface.\nfunc (sf *ScalarFunction) EvalInt(ctx sessionctx.Context, row chunk.Row) (int64, bool, error) {\n\tif f, ok := sf.Function.(builtinFuncNew); ok {\n\t\treturn f.evalIntWithCtx(ctx, row)\n\t}\n\treturn sf.Function.evalInt(row)\n}\n\n// EvalReal implements Expression interface.\nfunc (sf *ScalarFunction) EvalReal(ctx sessionctx.Context, row chunk.Row) (float64, bool, error) {\n\treturn sf.Function.evalReal(row)\n}\n\n// EvalDecimal implements Expression interface.\nfunc (sf *ScalarFunction) EvalDecimal(ctx sessionctx.Context, row chunk.Row) (*types.MyDecimal, bool, error) {\n\treturn sf.Function.evalDecimal(row)\n}\n\n// EvalString implements Expression interface.\nfunc (sf *ScalarFunction) EvalString(ctx sessionctx.Context, row chunk.Row) (string, bool, error) {\n\treturn sf.Function.evalString(row)\n}\n\n// EvalTime implements Expression interface.\nfunc (sf *ScalarFunction) EvalTime(ctx sessionctx.Context, row chunk.Row) (types.Time, bool, error) {\n\treturn sf.Function.evalTime(row)\n}\n\n// EvalDuration implements Expression interface.\nfunc (sf *ScalarFunction) EvalDuration(ctx sessionctx.Context, row chunk.Row) (types.Duration, bool, error) {\n\treturn sf.Function.evalDuration(row)\n}\n\n// Clone implements Expression interface.\nfunc (sf *ScalarFunction) Clone() Expression {\n\treturn &ScalarFunction{\n\t\tFuncName: sf.FuncName,\n\t\tRetType:  sf.RetType,\n\t\tFunction: sf.Function.Clone(),\n\t\thashcode: sf.hashcode,\n\t}\n}\n\n// HashCode implements Expression interface.\nfunc (sf *ScalarFunction) HashCode(sc *stmtctx.StatementContext) []byte {\n\tif len(sf.hashcode) > 0 {\n\t\treturn sf.hashcode\n\t}\n\tsf.hashcode = append(sf.hashcode, scalarFunctionFlag)\n\tsf.hashcode = codec.EncodeCompactBytes(sf.hashcode, hack.Slice(sf.FuncName.L))\n\tfor _, arg := range sf.GetArgs() {\n\t\tsf.hashcode = append(sf.hashcode, arg.HashCode(sc)...)\n\t}\n\treturn sf.hashcode\n}\n\n// Eval implements Expression interface.\nfunc (sf *ScalarFunction) Eval(row chunk.Row) (d types.Datum, err error) {\n\tvar (\n\t\tres    interface{}\n\t\tisNull bool\n\t)\n\tswitch tp, evalType := sf.GetType(), sf.GetType().EvalType(); evalType {\n\tcase types.ETInt:\n\t\tvar intRes int64\n\t\tintRes, isNull, err = sf.EvalInt(sf.GetCtx(), row)\n\t\tif mysql.HasUnsignedFlag(tp.Flag) {\n\t\t\tres = uint64(intRes)\n\t\t} else {\n\t\t\tres = intRes\n\t\t}\n\tcase types.ETReal:\n\t\tres, isNull, err = sf.EvalReal(sf.GetCtx(), row)\n\tcase types.ETDecimal:\n\t\tres, isNull, err = sf.EvalDecimal(sf.GetCtx(), row)\n\tcase types.ETDatetime, types.ETTimestamp:\n\t\tres, isNull, err = sf.EvalTime(sf.GetCtx(), row)\n\tcase types.ETDuration:\n\t\tres, isNull, err = sf.EvalDuration(sf.GetCtx(), row)\n\t// case types.ETJson:\n\t// \tres, isNull, err = sf.EvalJSON(sf.GetCtx(), row)\n\tcase types.ETString:\n\t\tres, isNull, err = sf.EvalString(sf.GetCtx(), row)\n\t}\n\n\tif isNull || err != nil {\n\t\td.SetValue(nil)\n\t\treturn d, err\n\t}\n\td.SetValue(res)\n\treturn\n}\n"
  },
  {
    "path": "pkg/expression/schema.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"strings\"\n)\n\n// KeyInfo stores the columns of one unique key or primary key.\ntype KeyInfo []*Column\n\n// Clone copies the entire UniqueKey.\nfunc (ki KeyInfo) Clone() KeyInfo {\n\tresult := make([]*Column, 0, len(ki))\n\tfor _, col := range ki {\n\t\tcolumn, ok := col.Clone().(*Column)\n\t\tif !ok {\n\t\t\treturn nil\n\t\t}\n\t\tresult = append(result, column)\n\t}\n\treturn result\n}\n\n// Schema stands for the row schema and unique key information get from input.\ntype Schema struct {\n\tColumns []*Column\n\tKeys    []KeyInfo\n}\n\n// String implements fmt.Stringer interface.\nfunc (s *Schema) String() string {\n\tcolStrs := make([]string, 0, len(s.Columns))\n\tfor _, col := range s.Columns {\n\t\tcolStrs = append(colStrs, col.String())\n\t}\n\tukStrs := make([]string, 0, len(s.Keys))\n\tfor _, key := range s.Keys {\n\t\tukColStrs := make([]string, 0, len(key))\n\t\tfor _, col := range key {\n\t\t\tukColStrs = append(ukColStrs, col.String())\n\t\t}\n\t\tukStrs = append(ukStrs, \"[\"+strings.Join(ukColStrs, \",\")+\"]\")\n\t}\n\treturn \"Column: [\" + strings.Join(colStrs, \",\") + \"] Unique key: [\" + strings.Join(ukStrs, \",\") + \"]\"\n}\n\n// Clone copies the total schema.\nfunc (s *Schema) Clone() *Schema {\n\tcols := make([]*Column, 0, s.Len())\n\tkeys := make([]KeyInfo, 0, len(s.Keys))\n\tfor _, col := range s.Columns {\n\t\tcolumn, ok := col.Clone().(*Column)\n\t\tif !ok {\n\t\t\treturn nil\n\t\t}\n\t\tcols = append(cols, column)\n\t}\n\tfor _, key := range s.Keys {\n\t\tkeys = append(keys, key.Clone())\n\t}\n\tschema := NewSchema(cols...)\n\tschema.SetUniqueKeys(keys)\n\treturn schema\n}\n\n// ExprFromSchema checks if all columns of this expression are from the same schema.\nfunc ExprFromSchema(expr Expression, schema *Schema) bool {\n\tswitch v := expr.(type) {\n\tcase *Column:\n\t\treturn schema.Contains(v)\n\tcase *ScalarFunction:\n\t\tfor _, arg := range v.GetArgs() {\n\t\t\tif !ExprFromSchema(arg, schema) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\tcase *CorrelatedColumn, *Constant:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// RetrieveColumn retrieves column in expression from the columns in schema.\nfunc (s *Schema) RetrieveColumn(col *Column) *Column {\n\tindex := s.ColumnIndex(col)\n\tif index != -1 {\n\t\treturn s.Columns[index]\n\t}\n\treturn nil\n}\n\n// IsUniqueKey checks if this column is a unique key.\nfunc (s *Schema) IsUniqueKey(col *Column) bool {\n\tfor _, key := range s.Keys {\n\t\tif len(key) == 1 && key[0].Equal(nil, col) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// ColumnIndex finds the index for a column.\nfunc (s *Schema) ColumnIndex(col *Column) int {\n\tfor i, c := range s.Columns {\n\t\tif c.UniqueID == col.UniqueID {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// Contains checks if the schema contains the column.\nfunc (s *Schema) Contains(col *Column) bool {\n\treturn s.ColumnIndex(col) != -1\n}\n\n// Len returns the number of columns in schema.\nfunc (s *Schema) Len() int {\n\treturn len(s.Columns)\n}\n\n// Append append new column to the columns stored in schema.\nfunc (s *Schema) Append(col ...*Column) {\n\ts.Columns = append(s.Columns, col...)\n}\n\n// SetUniqueKeys will set the value of Schema.Keys.\nfunc (s *Schema) SetUniqueKeys(keys []KeyInfo) {\n\ts.Keys = keys\n}\n\n// ColumnsIndices will return a slice which contains the position of each column in schema.\n// If there is one column that doesn't match, nil will be returned.\nfunc (s *Schema) ColumnsIndices(cols []*Column) (ret []int) {\n\tret = make([]int, 0, len(cols))\n\tfor _, col := range cols {\n\t\tpos := s.ColumnIndex(col)\n\t\tif pos != -1 {\n\t\t\tret = append(ret, pos)\n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn\n}\n\n// ColumnsByIndices returns columns by multiple offsets.\n// Callers should guarantee that all the offsets provided should be valid, which means offset should:\n// 1. not smaller than 0, and\n// 2. not exceed len(s.Columns)\nfunc (s *Schema) ColumnsByIndices(offsets []int) []*Column {\n\tcols := make([]*Column, 0, len(offsets))\n\tfor _, offset := range offsets {\n\t\tcols = append(cols, s.Columns[offset])\n\t}\n\treturn cols\n}\n\n// MergeSchema will merge two schema into one schema. We shouldn't need to consider unique keys.\n// That will be processed in build_key_info.go.\nfunc MergeSchema(lSchema, rSchema *Schema) *Schema {\n\tif lSchema == nil && rSchema == nil {\n\t\treturn nil\n\t}\n\tif lSchema == nil {\n\t\treturn rSchema.Clone()\n\t}\n\tif rSchema == nil {\n\t\treturn lSchema.Clone()\n\t}\n\ttmpL := lSchema.Clone()\n\ttmpR := rSchema.Clone()\n\treturn NewSchema(append(tmpL.Columns, tmpR.Columns...)...)\n}\n\n// NewSchema returns a schema made by its parameter.\nfunc NewSchema(cols ...*Column) *Schema {\n\treturn &Schema{Columns: cols}\n}\n"
  },
  {
    "path": "pkg/expression/simple_rewriter.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// FindFieldName finds the column name from NameSlice.\nfunc FindFieldName(names types.NameSlice, astCol *ast.ColumnName) (int, error) {\n\tdbName, tblName, colName := astCol.Schema, astCol.Table, astCol.Name\n\tidx := -1\n\tfor i, name := range names {\n\t\tif (dbName.L == \"\" || dbName.L == name.DBName.L) &&\n\t\t\t(tblName.L == \"\" || tblName.L == name.TblName.L) &&\n\t\t\t(colName.L == name.ColName.L) {\n\t\t\tif idx == -1 {\n\t\t\t\tidx = i\n\t\t\t} else {\n\t\t\t\treturn -1, errNonUniq.GenWithStackByArgs(name.String(), \"field list\")\n\t\t\t}\n\t\t}\n\t}\n\treturn idx, nil\n}\n\n// FindFieldNameIdxByColName finds the index of corresponding name in the given slice. -1 for not found.\nfunc FindFieldNameIdxByColName(names []*types.FieldName, colName string) int {\n\tfor i, name := range names {\n\t\tif name.ColName.L == colName {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n"
  },
  {
    "path": "pkg/expression/util.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage expression\n\nimport (\n\t\"unicode\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\tdriver \"github.com/secretflow/scql/pkg/types/parser_driver\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n)\n\n// cowExprRef is a copy-on-write slice ref util using in `ColumnSubstitute`\n// to reduce unnecessary allocation for Expression arguments array\ntype cowExprRef struct {\n\trefExpr []Expression\n\tnewExpr []Expression\n}\n\n// Set will allocate new array if changed flag true\nfunc (c *cowExprRef) Set(i int, changed bool, val Expression) {\n\tif c.newExpr != nil {\n\t\tc.newExpr[i] = val\n\t\treturn\n\t}\n\tif !changed {\n\t\treturn\n\t}\n\tc.newExpr = make([]Expression, len(c.refExpr))\n\tcopy(c.newExpr, c.refExpr[:i])\n\tc.newExpr[i] = val\n}\n\n// Result return the final reference\nfunc (c *cowExprRef) Result() []Expression {\n\tif c.newExpr != nil {\n\t\treturn c.newExpr\n\t}\n\treturn c.refExpr\n}\n\nfunc extractColumns(result []*Column, expr Expression, filter func(*Column) bool) []*Column {\n\tswitch v := expr.(type) {\n\tcase *Column:\n\t\tif filter == nil || filter(v) {\n\t\t\tresult = append(result, v)\n\t\t}\n\tcase *ScalarFunction:\n\t\tfor _, arg := range v.GetArgs() {\n\t\t\tresult = extractColumns(result, arg, filter)\n\t\t}\n\t}\n\treturn result\n}\n\nfunc ExtractColumns(expr Expression) []*Column {\n\t// Pre-allocate a slice to reduce allocation, 8 doesn't have special meaning.\n\tresult := make([]*Column, 0, 8)\n\treturn extractColumns(result, expr, nil)\n}\n\n// ExtractColumnsFromExpressions is a more efficient version of ExtractColumns for batch operation.\n// filter can be nil, or a function to filter the result column.\n// It's often observed that the pattern of the caller like this:\n//\n// cols := ExtractColumns(...)\n//\n//\tfor _, col := range cols {\n//\t    if xxx(col) {...}\n//\t}\n//\n// Provide an additional filter argument, this can be done in one step.\n// To avoid allocation for cols that not need.\nfunc ExtractColumnsFromExpressions(result []*Column, exprs []Expression, filter func(*Column) bool) []*Column {\n\tfor _, expr := range exprs {\n\t\tresult = extractColumns(result, expr, filter)\n\t}\n\treturn result\n}\n\n// GetRowLen gets the length if the func is row, returns 1 if not row.\nfunc GetRowLen(e Expression) int {\n\tif f, ok := e.(*ScalarFunction); ok && f.FuncName.L == ast.RowFunc {\n\t\treturn len(f.GetArgs())\n\t}\n\treturn 1\n}\n\n// CheckArgsNotMultiColumnRow checks the args are not multi-column row.\nfunc CheckArgsNotMultiColumnRow(args ...Expression) error {\n\tfor _, arg := range args {\n\t\tif GetRowLen(arg) != 1 {\n\t\t\treturn ErrOperandColumns.GenWithStackByArgs(1)\n\t\t}\n\t}\n\treturn nil\n}\n\n// GetFuncArg gets the argument of the function at idx.\nfunc GetFuncArg(e Expression, idx int) Expression {\n\tif f, ok := e.(*ScalarFunction); ok {\n\t\treturn f.GetArgs()[idx]\n\t}\n\treturn nil\n}\n\n// PopRowFirstArg pops the first element and returns the rest of row.\n// e.g. After this function (1, 2, 3) becomes (2, 3).\nfunc PopRowFirstArg(ctx sessionctx.Context, e Expression) (ret Expression, err error) {\n\tif f, ok := e.(*ScalarFunction); ok && f.FuncName.L == ast.RowFunc {\n\t\targs := f.GetArgs()\n\t\tif len(args) == 2 {\n\t\t\treturn args[1], nil\n\t\t}\n\t\tret, err = NewFunction(ctx, ast.RowFunc, f.GetType(), args[1:]...)\n\t\treturn ret, err\n\t}\n\treturn\n}\n\n// ExtractCorColumns extracts correlated column from given expression.\nfunc ExtractCorColumns(expr Expression) (cols []*CorrelatedColumn) {\n\tswitch v := expr.(type) {\n\tcase *CorrelatedColumn:\n\t\treturn []*CorrelatedColumn{v}\n\tcase *ScalarFunction:\n\t\tfor _, arg := range v.GetArgs() {\n\t\t\tcols = append(cols, ExtractCorColumns(arg)...)\n\t\t}\n\t}\n\treturn\n}\n\n// ColumnSubstitute substitutes the columns in filter to expressions in select fields.\n// e.g. select * from (select b as a from t) k where a < 10 => select * from (select b as a from t where b < 10) k.\nfunc ColumnSubstitute(expr Expression, schema *Schema, newExprs []Expression) Expression {\n\t_, resExpr := ColumnSubstituteImpl(expr, schema, newExprs)\n\treturn resExpr\n}\n\nfunc setExprColumnInOperand(expr Expression) Expression {\n\tswitch v := expr.(type) {\n\tcase *Column:\n\t\tcol := v.Clone().(*Column)\n\t\tcol.InOperand = true\n\t\treturn col\n\tcase *ScalarFunction:\n\t\targs := v.GetArgs()\n\t\tfor i, arg := range args {\n\t\t\targs[i] = setExprColumnInOperand(arg)\n\t\t}\n\t}\n\treturn expr\n}\n\n// ColumnSubstituteImpl tries to substitute column expr using newExprs,\n// the newFunctionInternal is only called if its child is substituted\nfunc ColumnSubstituteImpl(expr Expression, schema *Schema, newExprs []Expression) (bool, Expression) {\n\tswitch v := expr.(type) {\n\tcase *Column:\n\t\tid := schema.ColumnIndex(v)\n\t\tif id == -1 {\n\t\t\treturn false, v\n\t\t}\n\t\tnewExpr := newExprs[id]\n\t\tif v.InOperand {\n\t\t\tnewExpr = setExprColumnInOperand(newExpr)\n\t\t}\n\t\treturn true, newExpr\n\tcase *ScalarFunction:\n\t\tif v.FuncName.L == ast.Cast {\n\t\t\tnewFunc := v.Clone().(*ScalarFunction)\n\t\t\t_, newFunc.GetArgs()[0] = ColumnSubstituteImpl(newFunc.GetArgs()[0], schema, newExprs)\n\t\t\treturn true, newFunc\n\t\t}\n\t\t// cowExprRef is a copy-on-write util, args array allocation happens only\n\t\t// when expr in args is changed\n\t\trefExprArr := cowExprRef{v.GetArgs(), nil}\n\t\tsubstituted := false\n\t\tfor idx, arg := range v.GetArgs() {\n\t\t\tchanged, newFuncExpr := ColumnSubstituteImpl(arg, schema, newExprs)\n\t\t\trefExprArr.Set(idx, changed, newFuncExpr)\n\t\t\tif changed {\n\t\t\t\tsubstituted = true\n\t\t\t}\n\t\t}\n\t\tif substituted {\n\t\t\treturn true, NewFunctionInternal(v.GetCtx(), v.FuncName.L, v.RetType, refExprArr.Result()...)\n\t\t}\n\t}\n\treturn false, expr\n}\n\n// ExtractFiltersFromDNFs checks whether the cond is DNF. If so, it will get the extracted part and the remained part.\n// The original DNF will be replaced by the remained part or just be deleted if remained part is nil.\n// And the extracted part will be appended to the end of the original slice.\nfunc ExtractFiltersFromDNFs(ctx sessionctx.Context, conditions []Expression) []Expression {\n\t// NOTE(yang.y): ExtractFiltersFromDNFs is an optimization techniques to transform\n\t// DNF like\n\t//   (p1 and p2) or (p1 and p3) or (p1 and p4)\n\t// to\n\t//   (p2 or p3 or p4) and p1\n\t//\n\t// We skip this type of optimization for now\n\treturn conditions\n}\n\n// IsMutableEffectsExpr checks if expr contains function which is mutable or has side effects.\nfunc IsMutableEffectsExpr(expr Expression) bool {\n\t// NOTE(yang.y): Mutable functions list https://github.com/pingcap/tidb/blob/6cb4230c8f2e59bf46497738c99cfacd2e967850/expression/function_traits.go#L126-L163\n\t// contains functions like time() and rand(), which currently is not supported in SCQL.\n\treturn false\n}\n\n// RemoveDupExprs removes identical exprs. Not that if expr contains functions which\n// are mutable or have side effects, we cannot remove it even if it has duplicates.\nfunc RemoveDupExprs(ctx sessionctx.Context, exprs []Expression) []Expression {\n\tres := make([]Expression, 0, len(exprs))\n\texists := make(map[string]struct{}, len(exprs))\n\tsc := ctx.GetSessionVars().StmtCtx\n\tfor _, expr := range exprs {\n\t\tkey := string(expr.HashCode(sc))\n\t\tif _, ok := exists[key]; !ok || IsMutableEffectsExpr(expr) {\n\t\t\tres = append(res, expr)\n\t\t\texists[key] = struct{}{}\n\t\t}\n\t}\n\treturn res\n}\n\n// getValidPrefix gets a prefix of string which can parsed to a number with base. the minimum base is 2 and the maximum is 36.\nfunc getValidPrefix(s string, base int64) string {\n\tvar (\n\t\tvalidLen int\n\t\tupper    rune\n\t)\n\tswitch {\n\tcase base >= 2 && base <= 9:\n\t\tupper = rune('0' + base)\n\tcase base <= 36:\n\t\tupper = rune('A' + base - 10)\n\tdefault:\n\t\treturn \"\"\n\t}\nLoop:\n\tfor i := 0; i < len(s); i++ {\n\t\tc := rune(s[i])\n\t\tswitch {\n\t\tcase unicode.IsDigit(c) || unicode.IsLower(c) || unicode.IsUpper(c):\n\t\t\tc = unicode.ToUpper(c)\n\t\t\tif c < upper {\n\t\t\t\tvalidLen = i + 1\n\t\t\t} else {\n\t\t\t\tbreak Loop\n\t\t\t}\n\t\tcase c == '+' || c == '-':\n\t\t\tif i != 0 {\n\t\t\t\tbreak Loop\n\t\t\t}\n\t\tdefault:\n\t\t\tbreak Loop\n\t\t}\n\t}\n\tif validLen > 1 && s[0] == '+' {\n\t\treturn s[1:validLen]\n\t}\n\treturn s[:validLen]\n}\n\n// GetUint64FromConstant gets a uint64 from constant expression.\nfunc GetUint64FromConstant(expr Expression) (uint64, bool, bool) {\n\tcon, ok := expr.(*Constant)\n\tif !ok {\n\t\treturn 0, false, false\n\t}\n\tdt := con.Value\n\tif con.DeferredExpr != nil {\n\t\tvar err error\n\t\tdt, err = con.DeferredExpr.Eval(chunk.Row{})\n\t\tif err != nil {\n\t\t\treturn 0, false, false\n\t\t}\n\t}\n\tswitch dt.Kind() {\n\tcase types.KindNull:\n\t\treturn 0, true, true\n\tcase types.KindInt64:\n\t\tval := dt.GetInt64()\n\t\tif val < 0 {\n\t\t\treturn 0, false, false\n\t\t}\n\t\treturn uint64(val), false, true\n\tcase types.KindUint64:\n\t\treturn dt.GetUint64(), false, true\n\t}\n\treturn 0, false, false\n}\n\n// ConstructPositionExpr constructs PositionExpr with the given ParamMarkerExpr.\nfunc ConstructPositionExpr(p *driver.ParamMarkerExpr) *ast.PositionExpr {\n\treturn &ast.PositionExpr{P: p}\n}\n\n// ParamMarkerExpression generate a getparam function expression.\nfunc ParamMarkerExpression(sctx sessionctx.Context, v *driver.ParamMarkerExpr) (*Constant, error) {\n\tvalue := &Constant{Value: v.Datum, RetType: v.Datum.GetFieldType()}\n\tvalue.ParamMarker = &ParamMarker{\n\t\tname:  v.ParamName,\n\t\torder: v.Order,\n\t\ttp:    *v.Datum.GetFieldType(),\n\t}\n\treturn value, nil\n}\n\n// FilterOutInPlace do the filtering out in place.\n// The remained are the ones who doesn't match the filter, storing in the original slice.\n// The filteredOut are the ones match the filter, storing in a new slice.\nfunc FilterOutInPlace(input []Expression, filter func(Expression) bool) (remained, filteredOut []Expression) {\n\tfor i := len(input) - 1; i >= 0; i-- {\n\t\tif filter(input[i]) {\n\t\t\tfilteredOut = append(filteredOut, input[i])\n\t\t\tinput = append(input[:i], input[i+1:]...)\n\t\t}\n\t}\n\treturn input, filteredOut\n}\n"
  },
  {
    "path": "pkg/infoschema/builder.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage infoschema\n\nimport (\n\t// Note(tony): Import tables package so that MockTableFromMeta is registered\n\t_ \"github.com/secretflow/scql/pkg/table/tables\"\n)\n\nfunc tableBucketIdx(tableID int64) int {\n\treturn int(tableID % bucketCount)\n}\n"
  },
  {
    "path": "pkg/infoschema/infoschema.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Modified by Ant Group in 2023\n\npackage infoschema\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/constant\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/table\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// InfoSchema is the interface used to retrieve the schema information.\n// It works as a in memory cache and doesn't handle any schema change.\n// InfoSchema is read-only, and the returned value is a copy.\ntype InfoSchema interface {\n\tSchemaByName(schema model.CIStr) (*model.DBInfo, bool)\n\tTableByName(schema, table model.CIStr) (table.Table, error)\n}\n\ntype sortedTables []table.Table\n\nfunc (s sortedTables) Len() int {\n\treturn len(s)\n}\n\nfunc (s sortedTables) Swap(i, j int) {\n\ts[i], s[j] = s[j], s[i]\n}\n\nfunc (s sortedTables) Less(i, j int) bool {\n\treturn s[i].Meta().ID < s[j].Meta().ID\n}\n\ntype schemaTables struct {\n\tdbInfo *model.DBInfo\n\ttables map[string]table.Table\n}\n\nconst bucketCount = 512\n\ntype infoSchema struct {\n\tschemaMap map[string]*schemaTables\n\n\t// sortedTablesBuckets is a slice of sortedTables, a table's bucket index is (tableID % bucketCount).\n\tsortedTablesBuckets []sortedTables\n}\n\nfunc (is *infoSchema) TableByName(schema, table model.CIStr) (t table.Table, err error) {\n\tif tbNames, ok := is.schemaMap[schema.O]; ok {\n\t\tif t, ok = tbNames.tables[table.O]; ok {\n\t\t\treturn\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"TableByName: Table '%s.%s' doesn't exist\", schema, table)\n}\n\n// MockInfoSchema only serves for test.\nfunc MockInfoSchema(dbTableList map[string][]*model.TableInfo) InfoSchema {\n\tresult := &infoSchema{}\n\tresult.schemaMap = make(map[string]*schemaTables)\n\tresult.sortedTablesBuckets = make([]sortedTables, bucketCount)\n\tfor dbName, tbList := range dbTableList {\n\t\tdbInfo := &model.DBInfo{\n\t\t\tID:     0,\n\t\t\tName:   model.NewCIStr(dbName),\n\t\t\tTables: tbList,\n\t\t}\n\t\ttableNames := &schemaTables{\n\t\t\tdbInfo: dbInfo,\n\t\t\ttables: make(map[string]table.Table),\n\t\t}\n\t\tresult.schemaMap[dbName] = tableNames\n\t\tfor _, tb := range tbList {\n\t\t\ttbl := table.MockTableFromMeta(tb)\n\t\t\ttableNames.tables[tb.Name.O] = tbl\n\t\t\tbucketIdx := tableBucketIdx(tb.ID)\n\t\t\tresult.sortedTablesBuckets[bucketIdx] = append(result.sortedTablesBuckets[bucketIdx], tbl)\n\t\t}\n\t}\n\tfor i := range result.sortedTablesBuckets {\n\t\tsort.Sort(result.sortedTablesBuckets[i])\n\t}\n\n\treturn result\n}\n\nvar _ InfoSchema = (*infoSchema)(nil)\n\nfunc (is *infoSchema) SchemaByName(schema model.CIStr) (val *model.DBInfo, ok bool) {\n\ttableNames, ok := is.schemaMap[schema.O]\n\tif !ok {\n\t\treturn\n\t}\n\treturn tableNames.dbInfo, true\n}\n\nfunc FromTableSchema(tableSchema []*TableSchema) (InfoSchema, error) {\n\tresult := &infoSchema{\n\t\tschemaMap:           make(map[string]*schemaTables), // dbname -> []tables\n\t\tsortedTablesBuckets: make([]sortedTables, len(tableSchema)),\n\t}\n\tfor i, tbl := range tableSchema {\n\t\tdbName, tableName := tbl.DbName, tbl.TableName\n\t\ttblInfo := &model.TableInfo{\n\t\t\tID:          int64(i),\n\t\t\tTableId:     fmt.Sprint(i),\n\t\t\tName:        model.NewCIStr(tableName),\n\t\t\tColumns:     []*model.ColumnInfo{},\n\t\t\tIndices:     []*model.IndexInfo{},\n\t\t\tForeignKeys: []*model.FKInfo{},\n\t\t\tState:       model.StatePublic,\n\t\t\tPartyCode:   tbl.PartyCode,\n\t\t\tPKIsHandle:  false,\n\t\t}\n\t\tfor i, col := range tbl.Columns {\n\t\t\tcolTyp := strings.ToLower(col.Type)\n\t\t\tdefaultVal, err := TypeDefaultValue(colTyp)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfieldTp, err := TypeConversion(colTyp)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tcolInfo := &model.ColumnInfo{\n\t\t\t\tID:                 int64(i),\n\t\t\t\tName:               model.NewCIStr(col.Name),\n\t\t\t\tOffset:             i,\n\t\t\t\tOriginDefaultValue: defaultVal,\n\t\t\t\tDefaultValue:       defaultVal,\n\t\t\t\tDefaultValueBit:    []byte{},\n\t\t\t\tDependences:        map[string]struct{}{},\n\t\t\t\tFieldType:          fieldTp,\n\t\t\t\tState:              model.StatePublic,\n\t\t\t\tComment:            col.Description,\n\t\t\t}\n\t\t\ttblInfo.Columns = append(tblInfo.Columns, colInfo)\n\t\t}\n\t\tif _, ok := result.schemaMap[dbName]; ok {\n\t\t\tresult.schemaMap[dbName].dbInfo.Tables = append(\n\t\t\t\tresult.schemaMap[dbName].dbInfo.Tables, tblInfo)\n\t\t} else {\n\t\t\tdbInfo := &model.DBInfo{\n\t\t\t\tID:     int64(len(result.schemaMap)),\n\t\t\t\tName:   model.NewCIStr(dbName),\n\t\t\t\tTables: []*model.TableInfo{tblInfo},\n\t\t\t}\n\t\t\tresult.schemaMap[dbName] = &schemaTables{\n\t\t\t\tdbInfo: dbInfo,\n\t\t\t\ttables: map[string]table.Table{},\n\t\t\t}\n\t\t}\n\t}\n\t// fill schema map: tableName -> table\n\tfor dbName := range result.schemaMap {\n\t\tfor _, tblInfo := range result.schemaMap[dbName].dbInfo.Tables {\n\t\t\ttb := table.MockTableFromMeta(tblInfo)\n\t\t\tresult.schemaMap[dbName].tables[tblInfo.Name.O] = tb\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc TypeConversion(tp string) (types.FieldType, error) {\n\tswitch {\n\tcase constant.StringTypeAlias[tp]:\n\t\treturn *(types.NewFieldType(mysql.TypeString)), nil\n\tcase constant.IntegerTypeAlias[tp]:\n\t\treturn *(types.NewFieldType(mysql.TypeLong)), nil\n\tcase constant.FloatTypeAlias[tp]:\n\t\treturn *(types.NewFieldType(mysql.TypeFloat)), nil\n\tcase constant.DoubleTypeAlias[tp]:\n\t\treturn *(types.NewFieldType(mysql.TypeDouble)), nil\n\tcase constant.DateTimeTypeAlias[tp]:\n\t\treturn *(types.NewFieldType(mysql.TypeDatetime)), nil\n\tcase constant.TimeStampTypeAlias[tp]:\n\t\treturn *(types.NewFieldType(mysql.TypeTimestamp)), nil\n\tdefault:\n\t\treturn *(types.NewFieldType(mysql.TypeString)),\n\t\t\tfmt.Errorf(\"unknown type in schema: %s\", tp)\n\t}\n}\n\n// FieldTypeString converts mysql FieldType to scql type string\nfunc FieldTypeString(tp types.FieldType) (string, error) {\n\tswitch tp.EvalType() {\n\tcase types.ETString:\n\t\treturn \"string\", nil\n\tcase types.ETInt:\n\t\treturn \"int\", nil\n\tcase types.ETDatetime:\n\t\treturn \"datetime\", nil\n\tcase types.ETTimestamp:\n\t\treturn \"timestamp\", nil\n\tcase types.ETReal:\n\t\treturn \"double\", nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unknown type: %v\", tp)\n\t}\n}\n\nfunc TypeDefaultValue(tp string) (interface{}, error) {\n\tswitch {\n\tcase constant.StringTypeAlias[tp]:\n\t\treturn \"\", nil\n\tcase constant.IntegerTypeAlias[tp]:\n\t\treturn 0, nil\n\tcase constant.FloatTypeAlias[tp]:\n\t\treturn 0.0, nil\n\tcase constant.DoubleTypeAlias[tp]:\n\t\treturn 0.0, nil\n\tcase constant.DateTimeTypeAlias[tp]:\n\t\t// in mysql default value is current time, this place we set to min datetime\n\t\treturn \"1000-01-01 00:00:00\", nil\n\tcase constant.TimeStampTypeAlias[tp]:\n\t\t// 1970-01-01 00:00:01.000000\n\t\treturn 0, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown type in schema: %s\", tp)\n\t}\n}\n"
  },
  {
    "path": "pkg/infoschema/infoschema_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Modified by Ant Group in 2023\n\npackage infoschema_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nvar _ = Suite(&testSuite{})\n\ntype testSuite struct {\n}\n\nfunc (testSuite) TestMockInfoSchema(c *C) {\n\ttblID := int64(1234)\n\ttblName := model.NewCIStr(\"tbl_m\")\n\ttableInfo := &model.TableInfo{\n\t\tID:    tblID,\n\t\tName:  tblName,\n\t\tState: model.StatePublic,\n\t}\n\tcolInfo := &model.ColumnInfo{\n\t\tState:     model.StatePublic,\n\t\tOffset:    0,\n\t\tName:      model.NewCIStr(\"h\"),\n\t\tFieldType: *types.NewFieldType(mysql.TypeLong),\n\t\tID:        1,\n\t}\n\ttableInfo.Columns = []*model.ColumnInfo{colInfo}\n\tis := infoschema.MockInfoSchema(map[string][]*model.TableInfo{\"test\": {tableInfo}})\n\ttbl, err := is.TableByName(model.NewCIStr(\"test\"), tblName)\n\tc.Assert(err, IsNil)\n\tc.Assert(tbl.Meta().Name, Equals, tblName)\n\tc.Assert(tbl.Cols()[0].ColumnInfo, Equals, colInfo)\n}\n\nfunc TestFromTableSchema(t *testing.T) {\n\ttables := []*infoschema.TableSchema{\n\t\t{\n\t\t\tDbName:    \"d1\",\n\t\t\tTableName: \"t1\",\n\t\t\tColumns: []infoschema.ColumnDesc{\n\t\t\t\t{Name: \"c1\", Type: \"int\", Description: \"foo\"},\n\t\t\t\t{Name: \"c2\", Type: \"string\", Description: \"bar\"},\n\t\t\t\t{Name: \"c3\", Type: \"int\", Description: \"foobar\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tDbName:    \"d1\",\n\t\t\tTableName: \"t2\",\n\t\t\tColumns: []infoschema.ColumnDesc{\n\t\t\t\t{Name: \"c1\", Type: \"int\", Description: \"foo\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tDbName:    \"d2\",\n\t\t\tTableName: \"t1\",\n\t\t\tColumns: []infoschema.ColumnDesc{\n\t\t\t\t{Name: \"c1\", Type: \"int\", Description: \"foo\"},\n\t\t\t},\n\t\t},\n\t}\n\n\ta := require.New(t)\n\tis, err := infoschema.FromTableSchema(tables)\n\ta.NoError(err)\n\n\td1, exists := is.SchemaByName(model.NewCIStr(\"d1\"))\n\ta.True(exists)\n\ta.Equal(2, len(d1.Tables))\n\ta.Equal(model.NewCIStr(\"d1\"), d1.Name)\n\t{\n\t\tt1 := d1.Tables[0]\n\t\ta.Equal(model.NewCIStr(\"t1\"), t1.Name)\n\t\ta.Equal(3, len(t1.Columns))\n\t\ta.Equal(model.NewCIStr(\"c1\"), t1.Columns[0].Name)\n\t\ta.Equal(mysql.TypeLong, t1.Columns[0].Tp)\n\t\ta.Equal(\"foo\", t1.Columns[0].Comment)\n\t\ta.Equal(model.NewCIStr(\"c2\"), t1.Columns[1].Name)\n\t\ta.Equal(mysql.TypeString, t1.Columns[1].Tp)\n\t\ta.Equal(\"bar\", t1.Columns[1].Comment)\n\t\ta.Equal(model.NewCIStr(\"c3\"), t1.Columns[2].Name)\n\t\ta.Equal(mysql.TypeLong, t1.Columns[2].Tp)\n\t\ta.Equal(\"foobar\", t1.Columns[2].Comment)\n\t}\n\t{\n\t\tt2 := d1.Tables[1]\n\t\ta.Equal(model.NewCIStr(\"t2\"), t2.Name)\n\t\ta.Equal(1, len(t2.Columns))\n\t\ta.Equal(model.NewCIStr(\"c1\"), t2.Columns[0].Name)\n\t\ta.Equal(mysql.TypeLong, t2.Columns[0].Tp)\n\t\ta.Equal(\"foo\", t2.Columns[0].Comment)\n\t}\n\n\td2, exists := is.SchemaByName(model.NewCIStr(\"d2\"))\n\ta.True(exists)\n\ta.Equal(1, len(d2.Tables))\n\ta.Equal(model.NewCIStr(\"d2\"), d2.Name)\n\t{\n\t\tt1 := d2.Tables[0]\n\t\ta.Equal(model.NewCIStr(\"t1\"), t1.Name)\n\t\ta.Equal(1, len(t1.Columns))\n\t\ta.Equal(model.NewCIStr(\"c1\"), t1.Columns[0].Name)\n\t\ta.Equal(mysql.TypeLong, t1.Columns[0].Tp)\n\t\ta.Equal(\"foo\", t1.Columns[0].Comment)\n\t}\n}\n"
  },
  {
    "path": "pkg/infoschema/table_schema.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//\thttp://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\npackage infoschema\n\ntype TableSchema struct {\n\tDbName    string\n\tTableName string\n\tColumns   []ColumnDesc\n\t// owner party code\n\tPartyCode string\n}\ntype ColumnDesc struct {\n\tName        string\n\tType        string\n\tDescription string\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/arrow_func_options.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"github.com/apache/arrow/go/v17/arrow\"\n\t\"github.com/apache/arrow/go/v17/arrow/compute\"\n)\n\nvar _ compute.FunctionOptions = &SliceOptions{}\nvar _ compute.FunctionOptions = &TrimOptions{}\nvar _ compute.FunctionOptions = &StrptimeOptions{}\n\ntype SliceOptions struct {\n\tStart int64 `compute:\"start\"`\n\tStop  int64 `compute:\"stop\"`\n\tStep  int64 `compute:\"step\"`\n}\n\nfunc (SliceOptions) TypeName() string { return \"SliceOptions\" }\n\ntype TrimOptions struct {\n\tCharacters string `compute:\"characters\"`\n}\n\nfunc (TrimOptions) TypeName() string { return \"TrimOptions\" }\n\ntype StrptimeOptions struct {\n\tFormat      string         `compute:\"format\"`\n\tUnit        arrow.TimeUnit `compute:\"unit\"`\n\tErrorIsNull bool           `compute:\"error_is_null\"`\n}\n\nfunc (StrptimeOptions) TypeName() string { return \"StrptimeOptions\" }\n"
  },
  {
    "path": "pkg/interpreter/compiler/codegen_pass.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\tpb \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/proto-gen/spu\"\n)\n\n// CodeGenPass generates final executable plan from execution graph\ntype CodeGenPass struct{}\n\n// NewCodeGenPass creates a new codegen pass\nfunc NewCodeGenPass() *CodeGenPass {\n\treturn &CodeGenPass{}\n}\n\n// Name returns the pass name\nfunc (p *CodeGenPass) Name() string {\n\treturn \"CodeGenPass\"\n}\n\n// Run generates final executable plan\nfunc (p *CodeGenPass) Run(c *CompileContext) error {\n\t// Ensure session context is available (should be created in LogicalPlanPass)\n\tif c.SessionCtx == nil {\n\t\treturn fmt.Errorf(\"session context not found - ensure LogicalPlanPass runs before CodeGenPass\")\n\t}\n\n\t// Process execution graph to generate execution plan\n\texecutionPlan, err := processExecutionGraph(\n\t\tc.ExecutionGraph,\n\t\tc.Request.GetCompileOpts().GetSpuConf(),\n\t\ttrue,\n\t\tnil,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to process execution graph: %v\", err)\n\t}\n\n\t// Add warning info when affected by groupby threshold\n\texecutionPlan.Warning = &pb.Warning{\n\t\tMayAffectedByGroupThreshold: c.SessionCtx.GetSessionVars().AffectedByGroupThreshold,\n\t}\n\tlogrus.Debugf(\"execution plan: %s\", executionPlan)\n\n\tc.ExecutionPlan = executionPlan\n\n\treturn nil\n}\n\n// buildCompiledPlan builds a CompiledPlan from execution graph and execution plans\nfunc buildCompiledPlan(spuConf *spu.RuntimeConfig, eGraph *graph.Graph, execPlans map[string]*graph.ExecutionPlan, enableChecksum bool) *pb.CompiledPlan {\n\tplan := &pb.CompiledPlan{\n\t\tSchema:         &pb.TableSchema{},\n\t\tSpuRuntimeConf: spuConf,\n\t\tSubGraphs:      make(map[string]*pb.SubGraph),\n\t}\n\n\t// Fill Schema\n\tfor _, out := range eGraph.OutputNames {\n\t\tplan.Schema.Columns = append(plan.Schema.Columns, &pb.ColumnDesc{\n\t\t\tName: out,\n\t\t\t// TODO: populate Field Type\n\t\t\t// Type: <column data type>\n\t\t})\n\t}\n\n\t// Fill Parties\n\tfor _, party := range eGraph.GetParties() {\n\t\tplan.Parties = append(plan.Parties, &pb.PartyId{\n\t\t\tCode: party,\n\t\t})\n\t}\n\n\t// Fill Subgraphs\n\tfor party, subGraph := range execPlans {\n\t\tgraphProto := &pb.SubGraph{\n\t\t\tNodes: make(map[string]*pb.ExecNode),\n\t\t\tPolicy: &pb.SchedulingPolicy{\n\t\t\t\tWorkerNum: int32(subGraph.Policy.WorkerNumber),\n\t\t\t},\n\t\t}\n\t\t// Fill Nodes\n\t\tfor k, v := range subGraph.Nodes {\n\t\t\tgraphProto.Nodes[strconv.Itoa(k)] = v.ToProto()\n\t\t}\n\t\t// Fill Policy subdags\n\t\tfor _, pipelineJobs := range subGraph.Policy.PipelineJobs {\n\t\t\tpipeline := &pb.Pipeline{}\n\t\t\tfor _, job := range pipelineJobs.Jobs {\n\t\t\t\tsubdag := &pb.SubDAG{\n\t\t\t\t\tJobs:                     make([]*pb.SubDAG_Job, 0),\n\t\t\t\t\tNeedCallBarrierAfterJobs: job.NeedCallBarrierAfterJobs,\n\t\t\t\t}\n\t\t\t\tfor k, v := range job.Jobs {\n\t\t\t\t\tvar ids []string\n\t\t\t\t\tfor _, id := range v {\n\t\t\t\t\t\tids = append(ids, strconv.Itoa(id))\n\t\t\t\t\t}\n\n\t\t\t\t\tj := &pb.SubDAG_Job{\n\t\t\t\t\t\tWorkerId: int32(k),\n\t\t\t\t\t\tNodeIds:  ids,\n\t\t\t\t\t}\n\t\t\t\t\tsubdag.Jobs = append(subdag.Jobs, j)\n\t\t\t\t}\n\t\t\t\tpipeline.Subdags = append(pipeline.Subdags, subdag)\n\t\t\t}\n\t\t\tif pipelineJobs.Batched {\n\t\t\t\tpipeline.Batched = true\n\t\t\t\tfor _, t := range pipelineJobs.InputTensors {\n\t\t\t\t\tpipeline.Inputs = append(pipeline.Inputs, t.ToProto())\n\t\t\t\t}\n\t\t\t\tfor _, t := range pipelineJobs.OutputTensors {\n\t\t\t\t\tpipeline.Outputs = append(pipeline.Outputs, t.ToProto())\n\t\t\t\t}\n\t\t\t}\n\t\t\tgraphProto.Policy.Pipelines = append(graphProto.Policy.Pipelines, pipeline)\n\t\t}\n\n\t\tplan.SubGraphs[party] = graphProto\n\t}\n\n\t// Calculate checksums if enabled\n\tif enableChecksum {\n\t\t// Calculate whole graph checksum\n\t\tgraphvizOutput := eGraph.DumpGraphviz()\n\t\ttableSchemaCrypt := sha256.New()\n\t\ttableSchemaCrypt.Write([]byte(graphvizOutput))\n\t\tplan.WholeGraphChecksum = fmt.Sprintf(\"%x\", tableSchemaCrypt.Sum(nil))\n\n\t\t// Calculate checksum for each party\n\t\tfor _, graphProto := range plan.SubGraphs {\n\t\t\ttableSchemaCrypt := sha256.New()\n\t\t\tsubGraphStr := graphProto.String()\n\t\t\ttableSchemaCrypt.Write([]byte(subGraphStr))\n\t\t\tgraphProto.SubGraphChecksum = fmt.Sprintf(\"%x\", tableSchemaCrypt.Sum(nil))\n\t\t}\n\t}\n\n\treturn plan\n}\n\n// processExecutionGraph process the execution graph and build the compiled plan\nfunc processExecutionGraph(ep *graph.Graph, spuConf *spu.RuntimeConfig, dumpExeGraph bool, warningInfo *pb.Warning) (*pb.CompiledPlan, error) {\n\t// Step 1: Partition the execution graph\n\tpartitioner := graph.NewGraphPartitioner(ep)\n\tif err := partitioner.NaivePartition(); err != nil {\n\t\treturn nil, fmt.Errorf(\"graph partitioning failed: %v\", err)\n\t}\n\n\t// Step 2: Map the execution graph\n\tmapper := graph.NewGraphMapper(ep, partitioner.Pipelines)\n\tmapper.Map()\n\n\t// Step 3: Build the compiled plan\n\tplan := buildCompiledPlan(spuConf, ep, mapper.Codes, false)\n\n\t// Step 4: Handle engine execution graph dumping and checksum calculation\n\t// TODO add related option in additional info\n\tgraphvizOutput := ep.DumpGraphviz()\n\tif dumpExeGraph {\n\t\tplan.Explain = &pb.ExplainInfo{\n\t\t\tExeGraphDot: graphvizOutput,\n\t\t}\n\t}\n\n\t// Step 5: Calculate checksum\n\ttableSchemaCrypt := sha256.New()\n\ttableSchemaCrypt.Write([]byte(graphvizOutput))\n\tplan.WholeGraphChecksum = fmt.Sprintf(\"%x\", tableSchemaCrypt.Sum(nil))\n\n\t// Step 6: Add warning information if provided\n\tif warningInfo != nil {\n\t\tplan.Warning = warningInfo\n\t}\n\n\treturn plan, nil\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/column_security_relaxation.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\ntype TensorVisibilityChecker interface {\n\tIsTensorPublic(t *TensorMeta) bool\n}\n\ntype ColumnSecurityRelaxation interface {\n\t// ApplicableTo returns true if the tensor is applicable to the column security relaxation\n\tApplicableTo(t *TensorMeta, tvc TensorVisibilityChecker) bool\n\n\t// AllApplicable returns true if all the tensors are applicable to the column security relaxation\n\tAllApplicable(tensors []*TensorMeta, tvc TensorVisibilityChecker) bool\n\n\t// MakeApplicable makes the tensor applicable to the column security relaxation\n\tMakeApplicable(t *TensorMeta)\n}\n\ntype ColumnSecurityRelaxationBase struct {\n\twithTensor  map[int]struct{} // tensors where this relaxation applies\n\talwaysApply bool             // whether to always apply regardless of tensor\n}\n\nfunc NewColumnSecurityRelaxationBase(alwaysApply bool) *ColumnSecurityRelaxationBase {\n\treturn &ColumnSecurityRelaxationBase{\n\t\twithTensor:  make(map[int]struct{}),\n\t\talwaysApply: alwaysApply,\n\t}\n}\n\n// IsAlwaysApply returns whether the CSR always applies regardless of tensor state\nfunc (csr *ColumnSecurityRelaxationBase) IsAlwaysApply() bool {\n\treturn csr.alwaysApply\n}\n\nfunc (csr *ColumnSecurityRelaxationBase) ApplicableTo(t *TensorMeta, tvc TensorVisibilityChecker) bool {\n\tif t == nil {\n\t\treturn false\n\t}\n\tif csr.alwaysApply {\n\t\treturn true\n\t}\n\tif tvc != nil && tvc.IsTensorPublic(t) {\n\t\treturn true\n\t}\n\t_, ok := csr.withTensor[t.ID]\n\treturn ok\n}\n\nfunc (csr *ColumnSecurityRelaxationBase) MakeApplicable(t *TensorMeta) {\n\tcsr.withTensor[t.ID] = struct{}{}\n}\n\nfunc (csr *ColumnSecurityRelaxationBase) AllApplicable(tensors []*TensorMeta, tvc TensorVisibilityChecker) bool {\n\tfor _, t := range tensors {\n\t\tif !csr.ApplicableTo(t, tvc) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/column_security_relaxation_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// MockTensorVisibilityChecker is a mock implementation of TensorVisibilityChecker for testing\ntype MockTensorVisibilityChecker struct {\n\tpublicTensors map[int]bool\n}\n\nfunc NewMockTensorVisibilityChecker() *MockTensorVisibilityChecker {\n\treturn &MockTensorVisibilityChecker{\n\t\tpublicTensors: make(map[int]bool),\n\t}\n}\n\nfunc (m *MockTensorVisibilityChecker) IsTensorPublic(t *TensorMeta) bool {\n\treturn m.publicTensors[t.ID]\n}\n\nfunc (m *MockTensorVisibilityChecker) SetTensorPublic(id int, isPublic bool) {\n\tm.publicTensors[id] = isPublic\n}\n\nfunc TestApplicableToAlwaysApply(t *testing.T) {\n\tcsr := NewColumnSecurityRelaxationBase(true)\n\ttensor := &TensorMeta{ID: 1}\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Should always return true regardless of tensor visibility\n\tresult := csr.ApplicableTo(tensor, mockTVC)\n\tassert.True(t, result)\n\n\t// Even with public tensor\n\tmockTVC.SetTensorPublic(1, true)\n\tresult = csr.ApplicableTo(tensor, mockTVC)\n\tassert.True(t, result)\n\n\t// Even with non-public tensor\n\tmockTVC.SetTensorPublic(1, false)\n\tresult = csr.ApplicableTo(tensor, mockTVC)\n\tassert.True(t, result)\n}\n\nfunc TestApplicableToNotAlwaysApply(t *testing.T) {\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\ttensor := &TensorMeta{ID: 1}\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Public tensor should be applicable\n\tmockTVC.SetTensorPublic(1, true)\n\tresult := csr.ApplicableTo(tensor, mockTVC)\n\tassert.True(t, result)\n\n\t// Non-public tensor without MakeApplicable should not be applicable\n\tmockTVC.SetTensorPublic(1, false)\n\tresult = csr.ApplicableTo(tensor, mockTVC)\n\tassert.False(t, result)\n\n\t// Non-public tensor with MakeApplicable should be applicable\n\tcsr.MakeApplicable(tensor)\n\tresult = csr.ApplicableTo(tensor, mockTVC)\n\tassert.True(t, result)\n}\n\nfunc TestMakeApplicable(t *testing.T) {\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\ttensor1 := &TensorMeta{ID: 1}\n\ttensor2 := &TensorMeta{ID: 2}\n\n\t// Initially empty\n\tassert.Empty(t, csr.withTensor)\n\n\t// Add first tensor\n\tcsr.MakeApplicable(tensor1)\n\tassert.Contains(t, csr.withTensor, 1)\n\tassert.Len(t, csr.withTensor, 1)\n\n\t// Add second tensor\n\tcsr.MakeApplicable(tensor2)\n\tassert.Contains(t, csr.withTensor, 1)\n\tassert.Contains(t, csr.withTensor, 2)\n\tassert.Len(t, csr.withTensor, 2)\n\n\t// Add same tensor again (should be idempotent)\n\tcsr.MakeApplicable(tensor1)\n\tassert.Len(t, csr.withTensor, 2)\n}\n\nfunc TestAllApplicable(t *testing.T) {\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\ttensor1 := &TensorMeta{ID: 1}\n\ttensor2 := &TensorMeta{ID: 2}\n\ttensor3 := &TensorMeta{ID: 3}\n\n\ttensors := []*TensorMeta{tensor1, tensor2, tensor3}\n\n\t// Set tensor1 as public, others as non-public\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, false)\n\tmockTVC.SetTensorPublic(3, false)\n\n\t// AllApplicable should return false when not all are applicable\n\tresult := csr.AllApplicable(tensors, mockTVC)\n\tassert.False(t, result)\n\n\t// Make tensor2 applicable\n\tcsr.MakeApplicable(tensor2)\n\tresult = csr.AllApplicable(tensors, mockTVC)\n\tassert.False(t, result)\n\n\t// Make tensor3 applicable\n\tcsr.MakeApplicable(tensor3)\n\tresult = csr.AllApplicable(tensors, mockTVC)\n\tassert.True(t, result)\n}\n\nfunc TestAllApplicableEmptyList(t *testing.T) {\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Empty list should return true\n\tresult := csr.AllApplicable([]*TensorMeta{}, mockTVC)\n\tassert.True(t, result)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/common.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// simpleCount means Complete Count, except count(distinct), e.g: count(colA), count(*), count(1)...\nfunc isSimpleCount(aggFunc *aggregation.AggFuncDesc) bool {\n\treturn aggFunc.Name == ast.AggFuncCount && aggFunc.Mode == aggregation.CompleteMode && !aggFunc.HasDistinct\n}\n\nfunc extractEQColumns(exp *expression.ScalarFunction) ([]*expression.Column, error) {\n\tif exp.FuncName.L != ast.EQ || len(exp.GetArgs()) != 2 {\n\t\treturn nil, fmt.Errorf(\"extractEQColumns: unsupported eq condition %v\", exp)\n\t}\n\tleft, right := exp.GetArgs()[0], exp.GetArgs()[1]\n\tleftCol, ok1 := left.(*expression.Column)\n\trightCol, ok2 := right.(*expression.Column)\n\tif !ok1 || !ok2 {\n\t\treturn nil, fmt.Errorf(\"extractEQColumns: unsupported eq condition %v\", exp)\n\t}\n\treturn []*expression.Column{leftCol, rightCol}, nil\n}\n\nfunc inferAggOutputType(aggFunc *aggregation.AggFuncDesc, inputType *graph.DataType) *graph.DataType {\n\toutputType := inputType\n\tswitch aggFunc.Name {\n\tcase ast.AggFuncAvg:\n\t\toutputType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64)\n\tcase ast.AggFuncSum:\n\t\tif inputType.IsBoolType() {\n\t\t\toutputType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64)\n\t\t} else if isFloatOrDoubleType(inputType.DType) {\n\t\t\toutputType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64)\n\t\t}\n\tcase ast.AggFuncCount:\n\t\toutputType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64)\n\t}\n\treturn outputType\n}\n\nfunc isFloatOrDoubleType(tp proto.PrimitiveDataType) bool {\n\treturn tp == proto.PrimitiveDataType_FLOAT32 || tp == proto.PrimitiveDataType_FLOAT64\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/common_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\nfunc TestConvertDataType(t *testing.T) {\n\t// Test TypeLonglong with boolean flag\n\tboolField := &types.FieldType{\n\t\tTp:   mysql.TypeLonglong,\n\t\tFlag: mysql.IsBooleanFlag,\n\t}\n\tresult, err := graph.ConvertDataType(boolField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_BOOL, result.DType)\n\n\t// Test TypeLonglong without boolean flag\n\tint64Field := &types.FieldType{\n\t\tTp: mysql.TypeLonglong,\n\t}\n\tresult, err = graph.ConvertDataType(int64Field)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_INT64, result.DType)\n\n\t// Test TypeLong\n\tlongField := &types.FieldType{\n\t\tTp: mysql.TypeLong,\n\t}\n\tresult, err = graph.ConvertDataType(longField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_INT64, result.DType)\n\n\t// Test TypeDuration\n\tdurationField := &types.FieldType{\n\t\tTp: mysql.TypeDuration,\n\t}\n\tresult, err = graph.ConvertDataType(durationField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_INT64, result.DType)\n\n\t// Test TypeString\n\tstringField := &types.FieldType{\n\t\tTp: mysql.TypeString,\n\t}\n\tresult, err = graph.ConvertDataType(stringField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_STRING, result.DType)\n\n\t// Test TypeVarchar\n\tvarcharField := &types.FieldType{\n\t\tTp: mysql.TypeVarchar,\n\t}\n\tresult, err = graph.ConvertDataType(varcharField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_STRING, result.DType)\n\n\t// Test TypeVarString\n\tvarStringField := &types.FieldType{\n\t\tTp: mysql.TypeVarString,\n\t}\n\tresult, err = graph.ConvertDataType(varStringField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_STRING, result.DType)\n\n\t// Test TypeTiny\n\ttinyField := &types.FieldType{\n\t\tTp: mysql.TypeTiny,\n\t}\n\tresult, err = graph.ConvertDataType(tinyField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_BOOL, result.DType)\n\n\t// Test TypeFloat\n\tfloatField := &types.FieldType{\n\t\tTp: mysql.TypeFloat,\n\t}\n\tresult, err = graph.ConvertDataType(floatField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_FLOAT32, result.DType)\n\n\t// Test TypeDouble\n\tdoubleField := &types.FieldType{\n\t\tTp: mysql.TypeDouble,\n\t}\n\tresult, err = graph.ConvertDataType(doubleField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_FLOAT64, result.DType)\n\n\t// Test TypeNewDecimal\n\tdecimalField := &types.FieldType{\n\t\tTp: mysql.TypeNewDecimal,\n\t}\n\tresult, err = graph.ConvertDataType(decimalField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_FLOAT64, result.DType)\n\n\t// Test TypeDatetime\n\tdatetimeField := &types.FieldType{\n\t\tTp: mysql.TypeDatetime,\n\t}\n\tresult, err = graph.ConvertDataType(datetimeField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_DATETIME, result.DType)\n\n\t// Test TypeDate\n\tdateField := &types.FieldType{\n\t\tTp: mysql.TypeDate,\n\t}\n\tresult, err = graph.ConvertDataType(dateField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_DATETIME, result.DType)\n\n\t// Test TypeYear\n\tyearField := &types.FieldType{\n\t\tTp: mysql.TypeYear,\n\t}\n\tresult, err = graph.ConvertDataType(yearField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_DATETIME, result.DType)\n\n\t// Test TypeTimestamp\n\ttimestampField := &types.FieldType{\n\t\tTp: mysql.TypeTimestamp,\n\t}\n\tresult, err = graph.ConvertDataType(timestampField)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.PrimitiveDataType_TIMESTAMP, result.DType)\n\n\t// Test unsupported type\n\tjsonField := &types.FieldType{\n\t\tTp: mysql.TypeJSON,\n\t}\n\tresult, err = graph.ConvertDataType(jsonField)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"ConvertDataType doesn't support type\")\n\tassert.Equal(t, proto.PrimitiveDataType_PrimitiveDataType_UNDEFINED, result.DType)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/compiler.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\tpb \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n)\n\ntype CompileTarget int\n\nconst (\n\tTargetAST CompileTarget = iota\n\tTargetLogicalPlan\n\tTargetOperatorGraph\n\tTargetExecutionGraph\n\tTargetExecutionPlan\n)\n\n// Pass represents a single compilation stage in the pipeline\ntype Pass interface {\n\t// Name returns the pass name for logging and debugging\n\tName() string\n\t// Run executes the pass logic, returns error if failed\n\tRun(c *CompileContext) error\n}\n\n// CompileContext contains all state and intermediate representation\n// throughout the compilation pipeline lifecycle\ntype CompileContext struct {\n\t// --- 1. Input ---\n\tCtx     context.Context\n\tRequest *v1.CompileSQLRequest\n\n\t// --- 2. Environment & Meta ---\n\tInfoSchema        infoschema.InfoSchema\n\tSessionCtx        sessionctx.Context\n\tEnginesInfo       *graph.EnginesInfo\n\tTensorMetaManager *TensorMetaManager\n\n\t// --- 3. Security & Visibility ---\n\tInvolvedParties           []string\n\tVisibilityTable           *VisibilityTable\n\tSecurityRelaxationManager *SecurityRelaxationManager\n\n\t// --- 4. Compile Result and Intermediate Representation ---\n\tAST            ast.StmtNode\n\tLogicalPlan    core.LogicalPlan\n\tOperatorGraph  *OperatorGraph\n\tExecutionGraph *graph.Graph\n\tExecutionPlan  *pb.CompiledPlan\n}\n\n// NewCompileContext initializes a new compilation context\nfunc NewCompileContext(ctx context.Context, req *v1.CompileSQLRequest) *CompileContext {\n\treturn &CompileContext{\n\t\tCtx:     ctx,\n\t\tRequest: req,\n\t}\n}\n\ntype CompilationDetails struct {\n\tAST            ast.StmtNode\n\tLogicalPlan    core.LogicalPlan\n\tOperatorGraph  *OperatorGraph\n\tExecutionGraph *graph.Graph\n\tExecutionPlan  *pb.CompiledPlan\n\n\t// for visibility analysis\n\tVisibilityTable *VisibilityTable\n}\n\n// String implements fmt.Stringer interface for CompilationDetails\nfunc (cd *CompilationDetails) String() string {\n\tvar builder strings.Builder\n\n\t// AST section\n\tbuilder.WriteString(\"=== AST ===\\n\")\n\tif cd.AST != nil {\n\t\tbuilder.WriteString(cd.AST.Text())\n\t} else {\n\t\tbuilder.WriteString(\"nil\")\n\t}\n\tbuilder.WriteString(\"\\n\\n\")\n\n\t// LogicalPlan section\n\tbuilder.WriteString(\"=== Logical Plan ===\\n\")\n\tif cd.LogicalPlan != nil {\n\t\tbuilder.WriteString(core.ToString(cd.LogicalPlan))\n\t} else {\n\t\tbuilder.WriteString(\"nil\")\n\t}\n\tbuilder.WriteString(\"\\n\\n\")\n\n\t// OperatorGraph section\n\tbuilder.WriteString(\"=== Operator Graph ===\\n\")\n\tif cd.OperatorGraph != nil {\n\t\t// Use DetailedString if VisibilityTable is available\n\t\tif cd.VisibilityTable != nil {\n\t\t\tbuilder.WriteString(cd.OperatorGraph.DetailedString(cd.VisibilityTable))\n\t\t} else {\n\t\t\tbuilder.WriteString(cd.OperatorGraph.String())\n\t\t}\n\t} else {\n\t\tbuilder.WriteString(\"nil\")\n\t}\n\tbuilder.WriteString(\"\\n\\n\")\n\n\t// ExecutionGraph section\n\tbuilder.WriteString(\"=== Execution Graph ===\\n\")\n\tif cd.ExecutionGraph != nil {\n\t\t// Basic info\n\t\tfmt.Fprintf(&builder, \"Node Count: %d\\n\", cd.ExecutionGraph.NodeCnt)\n\t\tfmt.Fprintf(&builder, \"Pipeline Count: %d\\n\", len(cd.ExecutionGraph.Pipelines))\n\t\tfmt.Fprintf(&builder, \"Output Names: %v\\n\", cd.ExecutionGraph.OutputNames)\n\t\tif cd.ExecutionGraph.PartyInfo != nil {\n\t\t\tfmt.Fprintf(&builder, \"Parties: %v\\n\", cd.ExecutionGraph.PartyInfo.GetParties())\n\t\t}\n\t\t// Graph visualization (use brief for better readability)\n\t\tbuilder.WriteString(\"\\nGraph Visualization (Graphviz):\\n\")\n\t\tbuilder.WriteString(cd.ExecutionGraph.DumpBriefGraphviz())\n\t} else {\n\t\tbuilder.WriteString(\"nil\")\n\t}\n\tbuilder.WriteString(\"\\n\\n\")\n\n\t// ExecutionPlan section\n\tbuilder.WriteString(\"=== Execution Plan ===\\n\")\n\tif cd.ExecutionPlan != nil {\n\t\t// Use custom formatting for ExecutionPlan\n\t\tbuilder.WriteString(formatExecutionPlan(cd.ExecutionPlan))\n\t} else {\n\t\tbuilder.WriteString(\"nil\")\n\t}\n\n\treturn builder.String()\n}\n\n// Compiler is the pipeline-based compiler implementation\ntype Compiler struct {\n\tpasses []Pass\n}\n\n// NewCompiler creates a new compiler with passes based on the target\nfunc NewCompiler(target CompileTarget) *Compiler {\n\tvar passes []Pass\n\n\t// Always include ParserPass as it's the foundation\n\tpasses = append(passes, NewParserPass())\n\n\t// Add passes based on target\n\tif target >= TargetLogicalPlan {\n\t\tpasses = append(passes, NewLogicalPlanPass())\n\t}\n\tif target >= TargetOperatorGraph {\n\t\tpasses = append(passes, NewOperatorGraphPass())\n\t\tpasses = append(passes, NewVisibilityAnalysisPass())\n\t}\n\tif target >= TargetExecutionGraph {\n\t\tpasses = append(passes, NewExecutionGraphPass())\n\t}\n\tif target >= TargetExecutionPlan {\n\t\tpasses = append(passes, NewCodeGenPass())\n\t}\n\n\treturn &Compiler{\n\t\tpasses: passes,\n\t}\n}\n\n// Compile executes the compilation pipeline\nfunc (c *Compiler) compileInternal(ctx context.Context, req *v1.CompileSQLRequest) (*CompileContext, error) {\n\t// Initialize compilation context\n\tcompCtx := NewCompileContext(ctx, req)\n\n\t// Execute pipeline\n\tfor _, pass := range c.passes {\n\t\tlogrus.Debugf(\"Compiling Stage: %s\", pass.Name())\n\t\tif err := pass.Run(compCtx); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"[%s] failed: %w\", pass.Name(), err)\n\t\t}\n\t}\n\n\t// Return result\n\treturn compCtx, nil\n}\n\n// CompileTo parses SQL and returns AST\nfunc CompileToAST(ctx context.Context, req *v1.CompileSQLRequest) (ast.StmtNode, error) {\n\tc := NewCompiler(TargetAST)\n\tcompCtx, err := c.compileInternal(ctx, req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif compCtx.AST == nil {\n\t\treturn nil, fmt.Errorf(\"AST is nil\")\n\t}\n\treturn compCtx.AST, nil\n}\n\n// CompileTo parses SQL and builds logical plan\nfunc CompileToLogicalPlan(ctx context.Context, req *v1.CompileSQLRequest) (core.LogicalPlan, error) {\n\tc := NewCompiler(TargetLogicalPlan)\n\tcompCtx, err := c.compileInternal(ctx, req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif compCtx.LogicalPlan == nil {\n\t\treturn nil, fmt.Errorf(\"LogicalPlan is nil\")\n\t}\n\treturn compCtx.LogicalPlan, nil\n}\n\n// CompileTo parses SQL and builds operator graph\nfunc CompileToOperatorGraph(ctx context.Context, req *v1.CompileSQLRequest) (*OperatorGraph, error) {\n\tc := NewCompiler(TargetOperatorGraph)\n\tcompCtx, err := c.compileInternal(ctx, req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif compCtx.OperatorGraph == nil {\n\t\treturn nil, fmt.Errorf(\"OperatorGraph is nil\")\n\t}\n\treturn compCtx.OperatorGraph, nil\n}\n\n// CompileTo parses SQL and builds execution graph\nfunc CompileToExecutionGraph(ctx context.Context, req *v1.CompileSQLRequest) (*graph.Graph, error) {\n\tc := NewCompiler(TargetExecutionGraph)\n\tcompCtx, err := c.compileInternal(ctx, req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif compCtx.ExecutionGraph == nil {\n\t\treturn nil, fmt.Errorf(\"ExecutionGraph is nil\")\n\t}\n\treturn compCtx.ExecutionGraph, nil\n}\n\n// Compile parses SQL and returns complete execution plan (default behavior)\nfunc Compile(ctx context.Context, req *v1.CompileSQLRequest) (*pb.CompiledPlan, error) {\n\tc := NewCompiler(TargetExecutionPlan)\n\tcompCtx, err := c.compileInternal(ctx, req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif compCtx.ExecutionPlan == nil {\n\t\treturn nil, fmt.Errorf(\"ExecutionPlan is nil\")\n\t}\n\treturn compCtx.ExecutionPlan, nil\n}\n\n// DetailedCompile parses SQL and returns all compilation details including all intermediate representations\nfunc DetailedCompile(ctx context.Context, req *v1.CompileSQLRequest) (*CompilationDetails, error) {\n\tc := NewCompiler(TargetExecutionPlan)\n\tcompCtx, err := c.compileInternal(ctx, req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdetails := &CompilationDetails{\n\t\tAST:             compCtx.AST,\n\t\tLogicalPlan:     compCtx.LogicalPlan,\n\t\tOperatorGraph:   compCtx.OperatorGraph,\n\t\tExecutionGraph:  compCtx.ExecutionGraph,\n\t\tExecutionPlan:   compCtx.ExecutionPlan,\n\t\tVisibilityTable: compCtx.VisibilityTable,\n\t}\n\treturn details, nil\n}\n\n// formatExecutionPlan provides a readable string representation of ExecutionPlan\nfunc formatExecutionPlan(plan *pb.CompiledPlan) string {\n\tvar builder strings.Builder\n\n\t// Parties\n\tif len(plan.Parties) > 0 {\n\t\tfmt.Fprintf(&builder, \"Parties [%d]:\\n\", len(plan.Parties))\n\t\tfor i, party := range plan.Parties {\n\t\t\tfmt.Fprintf(&builder, \"  [%d] PartyID: %s\\n\", i, party.GetCode())\n\t\t}\n\t\tbuilder.WriteString(\"\\n\")\n\t}\n\n\t// Schema\n\tif plan.Schema != nil {\n\t\tfmt.Fprintf(&builder, \"Output Schema [%d columns]:\\n\", len(plan.Schema.Columns))\n\t\tfor _, col := range plan.Schema.Columns {\n\t\t\tfmt.Fprintf(&builder, \"  - %s: %s\\n\", col.Name, col.Type)\n\t\t}\n\t\tbuilder.WriteString(\"\\n\")\n\t}\n\n\t// SubGraphs\n\tif len(plan.SubGraphs) > 0 {\n\t\tfmt.Fprintf(&builder, \"SubGraphs [%d]:\\n\", len(plan.SubGraphs))\n\t\tfor partyID, subgraph := range plan.SubGraphs {\n\t\t\tif subgraph.SubGraphChecksum != \"\" {\n\t\t\t\tfmt.Fprintf(&builder, \"\\nParty: %s (Checksum: %s)\\n\", partyID, subgraph.SubGraphChecksum)\n\t\t\t} else {\n\t\t\t\tfmt.Fprintf(&builder, \"\\nParty: %s\\n\", partyID)\n\t\t\t}\n\t\t\tfmt.Fprintf(&builder, \"  Nodes [%d]:\\n\", len(subgraph.Nodes))\n\n\t\t\t// Sort node keys by node number for ordered output\n\t\t\ttype nodeInfo struct {\n\t\t\t\tkey   string\n\t\t\t\tnode  *pb.ExecNode\n\t\t\t\tindex int\n\t\t\t}\n\t\t\tnodes := make([]nodeInfo, 0, len(subgraph.Nodes))\n\t\t\tfor nodeKey, node := range subgraph.Nodes {\n\t\t\t\t// Extract index from node name (format usually like \"index_0\", \"index_1\", etc.)\n\t\t\t\tvar index int\n\t\t\t\tif node.NodeName != \"\" {\n\t\t\t\t\t_, err := fmt.Sscanf(node.NodeName, \"%*[^0-9]%d\", &index)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t// Try different format patterns\n\t\t\t\t\t\tfor i, r := range node.NodeName {\n\t\t\t\t\t\t\tif r >= '0' && r <= '9' {\n\t\t\t\t\t\t\t\t_, err := fmt.Sscanf(node.NodeName[i:], \"%d\", &index)\n\t\t\t\t\t\t\t\tif err == nil {\n\t\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnodes = append(nodes, nodeInfo{key: nodeKey, node: node, index: index})\n\t\t\t}\n\n\t\t\t// Sort by index\n\t\t\tsort.Slice(nodes, func(i, j int) bool {\n\t\t\t\treturn nodes[i].index < nodes[j].index\n\t\t\t})\n\n\t\t\t// Print sorted nodes\n\t\t\tfor _, nodeInfo := range nodes {\n\t\t\t\tfmt.Fprintf(&builder, \"    %s: %s\\n\", nodeInfo.key, nodeInfo.node.OpType)\n\t\t\t\t// Show input tensors count\n\t\t\t\tif len(nodeInfo.node.Inputs) > 0 {\n\t\t\t\t\tfmt.Fprintf(&builder, \"      Inputs: %d\\n\", len(nodeInfo.node.Inputs))\n\t\t\t\t}\n\t\t\t\t// Show output tensors count\n\t\t\t\tif len(nodeInfo.node.Outputs) > 0 {\n\t\t\t\t\tfmt.Fprintf(&builder, \"      Outputs: %d\\n\", len(nodeInfo.node.Outputs))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// SPU Runtime Config\n\tif plan.SpuRuntimeConf != nil {\n\t\tfmt.Fprintf(&builder, \"\\nSPU Runtime Config:\\n\")\n\t\tfmt.Fprintf(&builder, \"  Protocol: %s\\n\", plan.SpuRuntimeConf.Protocol.String())\n\t\tfmt.Fprintf(&builder, \"  Field: %s\\n\", plan.SpuRuntimeConf.Field.String())\n\t}\n\n\t// Whole Graph Checksum\n\tif plan.WholeGraphChecksum != \"\" {\n\t\tfmt.Fprintf(&builder, \"\\nWhole Graph Checksum: %s\\n\", plan.WholeGraphChecksum)\n\t}\n\n\treturn builder.String()\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/compiler_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\tpb \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n\t\"github.com/secretflow/scql/pkg/proto-gen/spu\"\n\t\"github.com/secretflow/scql/pkg/util/mock\"\n)\n\nfunc TestCompiler(t *testing.T) {\n\tr := require.New(t)\n\n\tfile, err := os.Open(\"data/test_queries.json\")\n\tr.NoError(err)\n\tdefer file.Close()\n\n\tbyteValue, err := io.ReadAll(file)\n\tr.NoError(err)\n\tvar queryCases []QueryCase\n\terr = json.Unmarshal(byteValue, &queryCases)\n\tr.NoError(err)\n\n\tfor _, queryCase := range queryCases {\n\t\tt.Run(queryCase.Name, func(t *testing.T) {\n\t\t\tr := require.New(t)\n\n\t\t\treq, err := createCompileRequest(queryCase.Query)\n\t\t\tr.NoError(err)\n\n\t\t\texecutionPlan, err := Compile(context.Background(), req)\n\t\t\tr.NoError(err)\n\t\t\tr.NotNil(executionPlan)\n\t\t})\n\t}\n}\n\nfunc createCompileRequest(query string) (*v1.CompileSQLRequest, error) {\n\treturn createCompileRequestWithConf(query, testConf{groupThreshold: 4})\n}\n\nfunc createCompileRequestWithConf(query string, conf testConf) (*v1.CompileSQLRequest, error) {\n\tcatalog, err := mock.MockCatalog()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsecurityConfig, err := getTestSecurityConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Update ResultSecurityConf based on testConf\n\tif securityConfig.ResultSecurityConf != nil {\n\t\tsecurityConfig.ResultSecurityConf.GroupbyThreshold = int64(conf.groupThreshold)\n\t}\n\n\tcompileOpts := getTestCompileOptions()\n\tcompileOpts.Batched = conf.batched\n\n\treturn &v1.CompileSQLRequest{\n\t\tQuery: query,\n\t\tDb:    \"test\",\n\t\tIssuer: &pb.PartyId{\n\t\t\tCode: \"alice\",\n\t\t},\n\t\tCatalog:        catalog,\n\t\tCompileOpts:    compileOpts,\n\t\tIssueTime:      timestamppb.New(time.Now()),\n\t\tSecurityConfig: securityConfig,\n\t\tAdditionalInfo: &v1.AdditionalInfoSpec{\n\t\t\tNeedOperatorGraph: true,\n\t\t},\n\t}, nil\n}\n\n// getTestCompileOptions returns standard compile options for testing\nfunc getTestCompileOptions() *v1.CompileOptions {\n\treturn &v1.CompileOptions{\n\t\tSpuConf: &spu.RuntimeConfig{\n\t\t\tProtocol: spu.ProtocolKind_SEMI2K,\n\t\t\tField:    spu.FieldType_FM128,\n\t\t},\n\t\tBatched:          false,\n\t\tPsiAlgorithmType: pb.PsiAlgorithmType_AUTO,\n\t}\n}\n\nfunc getTestSecurityConfig() (*v1.CompilerSecurityConfig, error) {\n\tconfig := &v1.CompilerSecurityConfig{\n\t\tGlobalRelaxation: &v1.GlobalSecurityRelaxation{\n\t\t\tRevealGroupCount:   false,\n\t\t\tRevealGroupMark:    false,\n\t\t\tRevealKeyAfterJoin: true,\n\t\t\tRevealFilterMask:   true,\n\t\t},\n\t\tColumnRelaxationList: nil,\n\t\tReverseInferenceConf: &v1.ReverseInferenceConfig{\n\t\t\tEnableReverseInference: true,\n\t\t},\n\t\tResultSecurityConf: &v1.ResultSecurityConfig{\n\t\t\tGroupbyThreshold: 4,\n\t\t},\n\t}\n\n\t// TODO: only include used columns\n\tcolumnVisibilityList, err := mock.MockColumnVisibility()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tconfig.ColumnVisibilityList = columnVisibilityList\n\n\treturn config, nil\n}\n\nfunc TestCompileToExecutionGraph(t *testing.T) {\n\tr := require.New(t)\n\n\t// Test cases can be added here\n\ttestCases := []sPair{}\n\t// Test with the new generated test cases\n\ttestCases = append(testCases, executionGraphTestCases...)\n\n\tfor _, tc := range testCases {\n\t\tt.Run(\"\", func(t *testing.T) {\n\t\t\t// TODO: remove skipping logic when test cases are ready\n\t\t\t// Skip empty test cases that were generated due to compilation errors\n\t\t\tif tc.dotGraph == \"\" {\n\t\t\t\tt.Skip(\"Skipping test case with empty graph\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\treq, err := createCompileRequestWithConf(tc.sql, tc.conf)\n\t\t\tr.NoError(err)\n\n\t\t\t// Compile to ExecutionGraph\n\t\t\texecutionGraph, err := CompileToExecutionGraph(context.Background(), req)\n\t\t\tr.NoError(err)\n\t\t\tr.NotNil(executionGraph)\n\n\t\t\t// Get graph visualization\n\t\t\tgraphStr := executionGraph.DumpGraphviz()\n\n\t\t\t// Get pipeline info if batched\n\t\t\tactualPipe := \"\"\n\t\t\tif tc.conf.batched {\n\t\t\t\tfor _, pipeline := range executionGraph.Pipelines {\n\t\t\t\t\tif pipeline.Batched {\n\t\t\t\t\t\tactualPipe = fmt.Sprintf(\"Batched pipeline with %d nodes\", len(pipeline.Nodes))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tr.Len(executionGraph.Pipelines, 1, \"for non-batched execution, should have 1 pipeline\")\n\t\t\t\tr.False(executionGraph.Pipelines[0].Batched, \"pipeline should not be batched\")\n\t\t\t\tactualPipe = executionGraph.DumpBriefPipeline()\n\t\t\t}\n\n\t\t\t// Verify basic properties\n\t\t\tr.Greater(executionGraph.NodeCnt, 0)\n\t\t\tr.NotEmpty(executionGraph.Pipelines)\n\t\t\tif executionGraph.PartyInfo != nil {\n\t\t\t\tr.NotEmpty(executionGraph.PartyInfo.GetParties())\n\t\t\t}\n\n\t\t\t// Verify graph structure\n\t\t\tfor _, pipeline := range executionGraph.Pipelines {\n\t\t\t\tr.NotNil(pipeline)\n\t\t\t\tr.NotNil(pipeline.Nodes)\n\t\t\t}\n\n\t\t\t// Compare with expected\n\t\t\tr.Equal(tc.dotGraph, graphStr, \"graph should match expected\")\n\t\t\tif !tc.conf.batched {\n\t\t\t\tr.Equal(tc.briefPipeline, actualPipe, \"pipeline info should match expected\")\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCompilerPlayground(t *testing.T) {\n\tsql := `select count(plain_int_0) from (select plain_int_0, groupby_int_0 from alice.tbl_0 union all select plain_int_0, groupby_int_0 from bob.tbl_1) as u;`\n\n\tr := require.New(t)\n\n\treq, err := createCompileRequest(sql)\n\tr.NoError(err)\n\n\tcompilationDetails, err := DetailedCompile(context.Background(), req)\n\tr.NoError(err)\n\n\tfmt.Println(compilationDetails)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/constant.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n)\n\nconst (\n\tRevealKeyAfterJoin = \"reveal_key_after_join\"\n\tRevealFilterMask   = \"reveal_filter_mask\"\n)\n\nvar isCompareAstFuncMap = map[string]struct{}{\n\tast.GT: {},\n\tast.GE: {},\n\tast.LT: {},\n\tast.LE: {},\n\tast.EQ: {},\n\tast.NE: {},\n}\n\nvar isLogicalAstFuncMap = map[string]struct{}{\n\tast.LogicOr:  {},\n\tast.LogicAnd: {},\n\tast.UnaryNot: {},\n}\n\nvar SupportedJoinType = []core.JoinType{\n\tcore.InnerJoin,\n\tcore.LeftOuterJoin,\n\tcore.RightOuterJoin,\n}\n\nvar constTensorNeedCastFuncs = map[string]struct{}{\n\tast.GT:    {},\n\tast.GE:    {},\n\tast.LT:    {},\n\tast.LE:    {},\n\tast.EQ:    {},\n\tast.NE:    {},\n\tast.Plus:  {},\n\tast.Minus: {},\n}\n\nvar functionArgNum = map[string]int{\n\t/// unary\n\t// the translation of Cast/Cot/Geodist does not need this map\n\t// ast.Cast:      1,\n\tast.UnaryNot: 1, // support variadic inputs in SCQL engine, but limited to be unary in SCQL interpreter\n\tast.Cos:      1,\n\tast.Sin:      1,\n\tast.Acos:     1,\n\tast.Asin:     1,\n\tast.Tan:      1,\n\t//ast.Cot:       1,\n\tast.Atan:      1,\n\tast.Abs:       1,\n\tast.Ceil:      1,\n\tast.Floor:     1,\n\tast.Round:     1,\n\tast.Radians:   1,\n\tast.Degrees:   1,\n\tast.Ln:        1,\n\tast.Log10:     1,\n\tast.Log2:      1,\n\tast.Sqrt:      1,\n\tast.Exp:       1,\n\tast.IsNull:    1,\n\tast.Lower:     1,\n\tast.Upper:     1,\n\tast.Trim:      1,\n\tast.Substr:    1, // const params do not count as arg here\n\tast.Substring: 1,\n\tast.StrToDate: 1,\n\n\t/// binary\n\tast.LT:       2,\n\tast.GT:       2,\n\tast.LE:       2,\n\tast.GE:       2,\n\tast.EQ:       2,\n\tast.NE:       2,\n\tast.LogicOr:  2,\n\tast.LogicAnd: 2,\n\tast.Plus:     2,\n\tast.Minus:    2,\n\tast.Mul:      2,\n\tast.Div:      2,\n\tast.IntDiv:   2,\n\tast.Mod:      2,\n\tast.AddDate:  2,\n\tast.SubDate:  2,\n\tast.DateDiff: 2,\n\tast.Pow:      2,\n\tast.Ifnull:   2,\n\tast.Atan2:    2,\n\n\t/// tenary\n\tast.If: 3,\n\n\t/// Variadic\n\tast.Greatest: -1,\n\tast.Least:    -1,\n\tast.Case:     -1,\n\tast.Coalesce: -1,\n\tast.GeoDist:  -1,\n\tast.Concat:   -1,\n}\n\nvar astName2NodeName = map[string]string{\n\tast.If:         operator.OpNameIf,\n\tast.Greatest:   operator.OpNameGreatest,\n\tast.Least:      operator.OpNameLeast,\n\tast.LT:         operator.OpNameLess,\n\tast.LE:         operator.OpNameLessEqual,\n\tast.GT:         operator.OpNameGreater,\n\tast.GE:         operator.OpNameGreaterEqual,\n\tast.EQ:         operator.OpNameEqual,\n\tast.NE:         operator.OpNameNotEqual,\n\tast.LogicOr:    operator.OpNameLogicalOr,\n\tast.LogicAnd:   operator.OpNameLogicalAnd,\n\tast.Plus:       operator.OpNameAdd,\n\tast.UnaryMinus: operator.OpNameMinus,\n\tast.Minus:      operator.OpNameMinus,\n\tast.Mul:        operator.OpNameMul,\n\tast.Div:        operator.OpNameDiv,\n\tast.IntDiv:     operator.OpNameIntDiv,\n\tast.Mod:        operator.OpNameMod,\n\tast.DateDiff:   operator.OpNameMinus,\n\tast.AddDate:    operator.OpNameAdd,\n\tast.SubDate:    operator.OpNameMinus,\n\tast.Sin:        operator.OpNameSin,\n\tast.Cos:        operator.OpNameCos,\n\tast.Acos:       operator.OpNameACos,\n\tast.Asin:       operator.OpNameASin,\n\tast.Tan:        operator.OpNameTan,\n\tast.Cot:        operator.OpNameCot,\n\tast.Atan:       operator.OpNameATan,\n\tast.Atan2:      operator.OpNameATan2,\n\t// tidb parser does not suport acot function\n\t// ast.Acot:       operator.OpNameACot,\n\tast.Abs:      operator.OpNameAbs,\n\tast.Ceil:     operator.OpNameCeil,\n\tast.Floor:    operator.OpNameFloor,\n\tast.Round:    operator.OpNameRound,\n\tast.Degrees:  operator.OpNameDegrees,\n\tast.Radians:  operator.OpNameRadians,\n\tast.Ln:       operator.OpNameLn,\n\tast.Log2:     operator.OpNameLog2,\n\tast.Log10:    operator.OpNameLog10,\n\tast.Sqrt:     operator.OpNameSqrt,\n\tast.Exp:      operator.OpNameExp,\n\tast.Pow:      operator.OpNamePow,\n\tast.IsNull:   operator.OpNameIsNull,\n\tast.Cast:     operator.OpNameCast,\n\tast.UnaryNot: operator.OpNameNot,\n}\n\nvar JoinTypeLpToEp = map[core.JoinType]int{\n\tcore.InnerJoin:      graph.InnerJoin,\n\tcore.LeftOuterJoin:  graph.LeftOuterJoin,\n\tcore.RightOuterJoin: graph.RightOuterJoin,\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/data/test_queries.json",
    "content": "[\n  {\n    \"name\": \"[single_party]row_number multi partition by/order by\",\n    \"query\": \"select u.* from (select ta.plain_int_0, row_number() over(partition by ta.plain_int_0, ta.plain_int_1 order by ta.plain_float_0, ta.plain_float_1) as num from alice.tbl_0 as ta) as u where u.num = 1;\"\n  },\n  {\n    \"name\": \"[single_party]row_number\",\n    \"query\": \"select ta.plain_int_0, row_number() over(partition by ta.plain_int_0 order by ta.plain_float_0) as num from alice.tbl_0 as ta;\"\n  },\n  {\n    \"name\": \"[single_party]geodist test, param order(longtitude1, latitude1, longtitude2, latitude2, radius)\",\n    \"query\": \"select ta.plain_int_0, ta.plain_float_0, 6300 * acos(sin(radians(ta.plain_int_0)) * sin(radians(ta.plain_float_0)) + cos(radians(ta.plain_int_0)) * cos(radians(ta.plain_float_0)) * cos(radians(ta.plain_int_0) - radians(ta.plain_float_0))) / 100 as distance from alice.tbl_0 as ta;\"\n  },\n  {\n    \"name\": \"[single_party]geodist test, param order(longtitude1, latitude1, longtitude2, latitude2)\",\n    \"query\": \"select ta.plain_int_0, ta.plain_float_0, 6371 * acos(sin(radians(ta.plain_int_0)) * sin(radians(ta.plain_float_0)) + cos(radians(ta.plain_int_0)) * cos(radians(ta.plain_float_0)) * cos(radians(ta.plain_int_0) - radians(ta.plain_float_0))) / 100 as distance from alice.tbl_0 as ta;\"\n  },\n  {\n    \"name\": \"[single_party]plain select\",\n    \"query\": \"select plain_int_0, plain_datetime_0, plain_timestamp_0 from alice.tbl_1\"\n  },\n  {\n    \"name\": \"[single_party]left join\",\n    \"query\": \"select ta.plain_int_0 from alice.tbl_1 as ta left join alice.tbl_2 as tb on ta.plain_int_0 = tb.plain_int_0;\"\n  },\n  {\n    \"name\": \"[single_party]compare (less)\",\n    \"query\": \"select plain_int_0 < 1 as res0, plain_int_0 < 1.5 as res1, plain_float_0 < 1.5 as res2, plain_int_0 < plain_int_1 as res3, plain_int_0 < plain_float_1 as res4, plain_float_0 < plain_float_1 as res5, plain_datetime_0 < now() as res6, plain_datetime_0 < plain_datetime_1 as res7, plain_datetime_0 < plain_timestamp_0 as res8 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]compare (greater)\",\n    \"query\": \"select plain_int_0 > 1 as res0, plain_int_0 > 1.5 as res1, plain_float_0 > 1.5 as res2, plain_int_0 > plain_int_1 as res3, plain_int_0 > plain_float_1 as res4, plain_float_0 > plain_float_1 as res5, plain_datetime_0 > now() as res6, plain_datetime_0 > plain_datetime_1 as res7, plain_datetime_0 > plain_timestamp_0 as res8 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]compare (less or equal)\",\n    \"query\": \"select plain_int_0 <= 1 as res0, plain_int_0 <= 1.5 as res1, plain_float_0 <= 1.5 as res2, plain_int_0 <= plain_int_1 as res3, plain_int_0 <= plain_float_1 as res4, plain_float_0 <= plain_float_1 as res5, plain_datetime_0 <= now() as res6, plain_datetime_0 <= plain_datetime_1 as res7, plain_datetime_0 <= plain_timestamp_0 as res8 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]compare (greater or equal)\",\n    \"query\": \"select plain_int_0 >= 1 as res0, plain_int_0 >= 1.5 as res1, plain_float_0 >= 1.5 as res2, plain_int_0 >= plain_int_1 as res3, plain_int_0 >= plain_float_1 as res4, plain_float_0 >= plain_float_1 as res5, plain_datetime_0 >= now() as res6, plain_datetime_0 >= plain_datetime_1 as res7, plain_datetime_0 >= plain_timestamp_0 as res8 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]compare (not equal)\",\n    \"query\": \"select plain_int_0 <> 1 as res0, plain_int_0 <> 1.5 as res1, plain_float_0 <> 1.5 as res2, plain_int_0 <> plain_int_1 as res3, plain_int_0 <> plain_float_1 as res4, plain_float_0 <> plain_float_1 as res5, plain_datetime_0 <> now() as res6, plain_datetime_0 <> plain_datetime_1 as res7, plain_datetime_0 <> plain_timestamp_0 as res8 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]arithmetic (plus)\",\n    \"query\": \"select plain_int_0 + 1 as res0, plain_int_0 + 1.5 as res1, plain_float_0 + 1.5 as res2, plain_int_0 + plain_int_1 as res3, plain_int_0 + plain_float_0 as res4, plain_float_0 + plain_float_1 as res5 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]arithmetic (subtract)\",\n    \"query\": \"select plain_int_0 - 1 as res0, plain_int_0 - 1.5 as res1, plain_float_0 - 1.5 as res2, plain_int_0 - plain_int_1 as res3, plain_int_0 - plain_float_0 as res4, plain_float_0 - plain_float_1 as res5, plain_datetime_0 - plain_datetime_1 as res6, plain_datetime_0 - plain_timestamp_0 as res7, plain_timestamp_0 - plain_timestamp_1 as res8  from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]arithmetic (multiply)\",\n    \"query\": \"select plain_int_0 * 1 as res0, plain_int_0 * 1.5 as res1, plain_float_0 * 1.5 as res2, plain_int_0 * plain_int_1 as res3, plain_int_0 * plain_float_0 as res4, plain_float_0 * plain_float_1 as res5 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]arithmetic (divide)\",\n    \"query\": \"select plain_int_0 / 1 as res0, plain_int_0 / 1.5 as res1, plain_float_0 / 1.5 as res2, plain_int_0 / (case when plain_int_1 = 0 then 1 else plain_int_1 end) as res3, plain_int_0 / (case when plain_float_0 = 0 then 1.0 else plain_float_0 end) as res4, plain_float_0 / (case when plain_float_1 = 0 then 1.0 else plain_float_1 end) as res5 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]arithmetic (model)\",\n    \"query\": \"select plain_int_0 % 1 as res0, plain_int_0 % (case when plain_int_1 = 0 then 1 else plain_int_1 end) as res1 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]max\",\n    \"query\": \"select max(alice.plain_int_0) as res0, max(alice.plain_float_0) as res1 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]max & arithmetic\",\n    \"query\": \"select max(alice.plain_int_0 + alice.plain_int_0) as res0, max(alice.plain_float_0 - alice.plain_float_1) as res1, max(alice.plain_float_0 * alice.plain_float_0) as res2, max(alice.plain_float_0 / alice.plain_float_0) as res3 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]max & compare\",\n    \"query\": \"select max(alice.plain_int_0) > max(alice.plain_int_0) as res0, max(alice.plain_float_0) < max(alice.plain_float_1) as res1, max(alice.plain_int_0) >= max(alice.plain_float_0) as res2, max(alice.plain_float_0) <= max(alice.plain_float_0) as res3 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]min\",\n    \"query\": \"select min(alice.plain_int_0) as res0, min(alice.plain_float_0) as res1 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]min & arithmetic\",\n    \"query\": \"select min(alice.plain_int_0 + alice.plain_int_0) as res0, min(alice.plain_int_0 - alice.plain_float_1) as res1, min(alice.plain_float_0 * alice.plain_float_0) as res2, min(alice.plain_float_0 / alice.plain_float_0) as res3 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]min & compare\",\n    \"query\": \"select min(alice.plain_int_0) > min(alice.plain_int_0) as res0, min(alice.plain_float_0) < min(alice.plain_float_1) as res1, min(alice.plain_int_0) >= min(alice.plain_float_0) as res2, min(alice.plain_float_0) <= min(alice.plain_float_0) as res3 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]avg\",\n    \"query\": \"select avg(alice.plain_int_0) as res0, avg(alice.plain_float_0) as res1 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]avg & arithmetic\",\n    \"query\": \"select avg(alice.plain_int_0 + alice.plain_int_0) as res0, avg(alice.plain_int_0 - alice.plain_float_1) as res1, avg(alice.plain_float_0 * alice.plain_float_0) as res2, avg(alice.plain_float_0 / alice.plain_float_0) as res3 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]avg & compare\",\n    \"query\": \"select avg(alice.plain_int_0) > avg(alice.plain_int_0) as res0, avg(alice.plain_int_0) < avg(alice.plain_float_1) as res1, avg(alice.plain_int_0) >= avg(alice.plain_float_0) as res2, avg(alice.plain_float_0) <= avg(alice.plain_float_0) as res3 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]sum\",\n    \"query\": \"select sum(alice.plain_int_0) as res0, sum(alice.plain_float_0) as res1 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]sum bool\",\n    \"query\": \"select sum(alice.plain_int_0 > 0) as res0, sum(alice.plain_float_0 > 0) as res1 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]sum & arithmetic\",\n    \"query\": \"select sum(alice.plain_int_0 + alice.plain_int_0) as res0, sum(alice.plain_int_0 - alice.plain_float_1) as res1, sum(alice.plain_float_0 * alice.plain_float_0) as res2, sum(alice.plain_float_0 / alice.plain_float_0) as res3 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]sum & compare\",\n    \"query\": \"select sum(alice.plain_int_0) > sum(alice.plain_int_0) as res0, sum(alice.plain_int_0) < sum(alice.plain_float_1) as res1, sum(alice.plain_int_0) >= sum(alice.plain_float_0) as res2, sum(alice.plain_float_0) <= sum(alice.plain_float_0) as res3 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]count\",\n    \"query\": \"select count(alice.plain_int_0) as res0, count(alice.plain_float_0) as res1, count(alice.plain_string_0) as res2 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]count & distinct\",\n    \"query\": \"select count(distinct alice.plain_int_0) as res0, count(distinct alice.plain_float_0) as res1, count(distinct alice.plain_string_0) as res2 from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[single_party]ifnull & coalesce\",\n    \"query\": \"select plain_int_0, plain_int_1, ifnull(plain_int_0, plain_int_1) as ifnull, coalesce(plain_float_0, plain_float_1, 1.0) as cl from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]if\",\n    \"query\": \"select plain_int_0, if(plain_int_0 > 8, \\\"> 8\\\", \\\"<= 8\\\") as if_select from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]logic\",\n    \"query\": \"select plain_int_0, plain_int_0 > 1 and plain_int_0 >= 1 as and_log, not (plain_int_0 < 5) as not_log, (plain_int_0 <= 5) or (plain_int_0 <> 8) as or_log from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]in & not in\",\n    \"query\": \"select plain_int_0 in (2,4,6,8) as in_column, plain_int_0 not in (2,4,6,8) as not_in from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]apply\",\n    \"query\": \"select alice.plain_int_0 from (select plain_int_0 from alice.tbl_1) as alice;\"\n  },\n  {\n    \"name\": \"[single_party]where condition(arithmetic compare logical)\",\n    \"query\": \"select plain_int_0, plain_int_1 from alice.tbl_1  where plain_int_0 + plain_int_1 > 0 or plain_int_0 - plain_int_1 < 0 or plain_int_0 * plain_int_1 = 4 or plain_int_0 / plain_int_1 <> 1;\"\n  },\n  {\n    \"name\": \"[single_party]where condition(null, not null)\",\n    \"query\": \"select plain_string_0, plain_string_1 from alice.tbl_1 where plain_string_0 is null or plain_string_1 is not null;\"\n  },\n  {\n    \"name\": \"[single_party]where condition(in & not in)\",\n    \"query\": \"select plain_int_0 from alice.tbl_1 where plain_int_0 in (2, 5, 15) and plain_int_1 not in (2, 5, 15);\"\n  },\n  {\n    \"name\": \"[single_party]where(null)\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]compare (less) where(null)\",\n    \"query\": \"select plain_int_0 < 1 as res0, plain_int_0 < 1.5 as res1, plain_float_0 < 1.5 as res2, plain_int_0 < plain_int_1 as res3, plain_int_0 < plain_float_1 as res4, plain_float_0 < plain_float_1 as res5 from alice.tbl_1 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]compare (greater) where(null)\",\n    \"query\": \"select plain_int_0 > 1 as res0, plain_int_0 > 1.5 as res1, plain_float_0 > 1.5 as res2, plain_int_0 > plain_int_1 as res3, plain_int_0 > plain_float_1 as res4, plain_float_0 > plain_float_1 as res5 from alice.tbl_1 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]compare (less or equal) where(null)\",\n    \"query\": \"select plain_int_0 <= 1 as res0, plain_int_0 <= 1.5 as res1, plain_float_0 <= 1.5 as res2, plain_int_0 <= plain_int_1 as res3, plain_int_0 <= plain_float_1 as res4, plain_float_0 <= plain_float_1 as res5 from alice.tbl_1 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]compare (greater or equal) where(null)\",\n    \"query\": \"select plain_int_0 >= 1 as res0, plain_int_0 >= 1.5 as res1, plain_float_0 >= 1.5 as res2, plain_int_0 >= plain_int_1 as res3, plain_int_0 >= plain_float_1 as res4, plain_float_0 >= plain_float_1 as res5 from alice.tbl_1 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]compare (not equal) where(null)\",\n    \"query\": \"select plain_int_0 <> 1 as res0, plain_int_0 <> 1.5 as res1, plain_float_0 <> 1.5 as res2, plain_int_0 <> plain_int_1 as res3, plain_int_0 <> plain_float_1 as res4, plain_float_0 <> plain_float_1 as res5 from alice.tbl_1 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]arithmetic (plus) where(null)\",\n    \"query\": \"select plain_int_0 + 1 as res0, plain_int_0 + 1.5 as res1, plain_float_0 + 1.5 as res2, plain_int_0 + plain_int_1 as res3, plain_int_0 + plain_float_0 as res4, plain_float_0 + plain_float_1 as res5 from alice.tbl_1 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]arithmetic (subtract) where(null)\",\n    \"query\": \"select plain_int_0 - 1 as res0, plain_int_0 - 1.5 as res1, plain_float_0 - 1.5 as res2, plain_int_0 - plain_int_1 as res3, plain_int_0 - plain_float_0 as res4, plain_float_0 - plain_float_1 as res5 from alice.tbl_1 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]arithmetic (multiply) where(null)\",\n    \"query\": \"select plain_int_0 * 1 as res0, plain_int_0 * 1.5 as res1, plain_float_0 * 1.5 as res2, plain_int_0 * plain_int_1 as res3, plain_int_0 * plain_float_0 as res4, plain_float_0 * plain_float_1 as res5 from alice.tbl_1 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]arithmetic (divide) where(null)\",\n    \"query\": \"select plain_int_0 / 1 as res0, plain_int_0 / 1.5 as res1, plain_float_0 / 1.5 as res2, plain_int_0 / (case when plain_int_1 = 0 then 1 else plain_int_1 end) as res3, plain_int_0 / (case when plain_float_0 = 0 then 1 else plain_float_0 end) as res4, plain_float_0 / (case when plain_float_1 = 0 then 1 else plain_float_1 end) as res5 from alice.tbl_1 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]arithmetic (model) where(null)\",\n    \"query\": \"select plain_int_0 % 1 as res0,  plain_int_0 % (case when plain_int_1 = 0 then 1 else plain_int_1 end) as res1 from alice.tbl_1 as alice where alice.plain_int_0 > alice.plain_int_1;\"\n  },\n  {\n    \"name\": \"[single_party]case when\",\n    \"query\": \"select plain_int_0, plain_int_1, case when plain_int_0 >= 5  then -1 else plain_int_0 end as r from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]concat\",\n    \"query\": \"select concat(plain_string_0, plain_string_1) as concat_col from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]substring\",\n    \"query\": \"select substring(plain_string_0, 2, 3) as t from alice.tbl_1 where substring(plain_string_0, 2) != '';\"\n  },\n  {\n    \"name\": \"[single_party]trim\",\n    \"query\": \"select trim(plain_string_0) as t from alice.tbl_1 where trim(plain_string_0) != '';\"\n  },\n  {\n    \"name\": \"[single_party]apply in\",\n    \"query\": \"select plain_int_0 in (select plain_int_0 from alice.tbl_1) as tt, plain_int_0 not in (select plain_int_0 from alice.tbl_1) as ff from alice.tbl_0\"\n  },\n  {\n    \"name\": \"[single_party]where in subquery\",\n    \"query\": \"select plain_int_0 from alice.tbl_0 where plain_int_0 in (select plain_int_0 from alice.tbl_1)\"\n  },\n  {\n    \"name\": \"[single_party]where in subquery\",\n    \"query\": \"select plain_int_0 from alice.tbl_0 where (plain_int_0 in (select plain_int_0 from alice.tbl_1)) and plain_int_0 > 0\"\n  },\n  {\n    \"name\": \"[single_party]date func (now, curdate, last_day, str_to_date, date_format)\",\n    \"query\": \"select plain_datetime_0 < now() as res1, plain_timestamp_0 < now() as res2, plain_datetime_0 < curdate() as res3, plain_timestamp_0 < curdate() as res4, last_day(plain_datetime_0) as res5, last_day(plain_timestamp_0) as res6, str_to_date('August 10 2017', '%M %d %Y') as res7, date_format(plain_datetime_0, '%Y-%m-%d %H:%i:%S') as res8 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]date func (adddate, subdate)\",\n    \"query\": \"select adddate(plain_datetime_0, interval 10 day) as res1, adddate(plain_timestamp_0, interval 10 day) as res2, subdate(plain_datetime_0, interval 10 day) as res3, subdate(plain_timestamp_0, interval 10 day) as res4 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]date func (datediff)\",\n    \"query\": \"select datediff(plain_datetime_0, plain_datetime_1) as res1, datediff(plain_timestamp_0, plain_timestamp_1) as res2 from alice.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]plain select (csv)\",\n    \"query\": \"select plain_int_0, plain_datetime_0, plain_timestamp_0 from bob.tbl_1\"\n  },\n  {\n    \"name\": \"[single_party]date func (now, curdate, last_day, str_to_date, date_format) (csv)\",\n    \"query\": \"select '2020-01-01 00:00:00' < curdate() as res1, last_day(plain_datetime_0) as res2, last_day(plain_timestamp_0) as res3, str_to_date('2017/08/10', '%Y/%m/%d') as res4, date_format(plain_datetime_0, '%Y-%m-%d %H:%i:%S') as res5 from bob.tbl_1;\"\n  },\n  {\n    \"name\": \"[single_party]naive trigonometric function on csv\",\n    \"query\": \"select plain_int_0, sin(plain_int_0) as sin_plain_int_0, cos(plain_int_0) as cos_plain_int_0, acos(plain_int_0 / 100000) as acos_plain_int_0 from bob.tbl_1\"\n  },\n  {\n    \"name\": \"[single_party]naive trigonometric function on mysql\",\n    \"query\": \"select plain_int_0, sin(plain_int_0) as sin_plain_int_0, cos(plain_int_0) as cos_plain_int_0, acos(plain_int_0 / 100000) as acos_plain_int_0 from alice.tbl_1\"\n  },\n  {\n    \"name\": \"[single_party]naive trigonometric function on postgres\",\n    \"query\": \"select plain_int_0, sin(plain_int_0) as sin_plain_int_0, cos(plain_int_0) as cos_plain_int_0, acos(plain_int_0 / 100000) as acos_plain_int_0 from carol.tbl_1\"\n  },\n  {\n    \"name\": \"[two_parties]select into\",\n    \"query\": \"select alice.plain_int_0, bob.joinpayload_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 into outfile party_code 'alice' '/tmp/output.txt' columns terminated BY '|';\"\n  },\n  {\n    \"name\": \"[two parties]compare subquery(lt)\",\n    \"query\": \"select ta.plain_int_0 from alice.tbl_0 as ta where ta.plain_int_0 < any(select ta.plain_int_0 + tb.plain_int_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0)\"\n  },\n  {\n    \"name\": \"[two parties]compare subquery(gt)\",\n    \"query\": \"select ta.plain_int_0 from alice.tbl_0 as ta where ta.plain_int_0 > all(select ta.plain_int_0 + tb.plain_int_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0)\"\n  },\n  {\n    \"name\": \"[two parties]compare subquery(ne)\",\n    \"query\": \"select ta.plain_int_0 from alice.tbl_0 as ta where ta.plain_int_0 != all(select ta.plain_int_0 + tb.plain_int_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0)\"\n  },\n  {\n    \"name\": \"[two parties]compare subquery(eq)\",\n    \"query\": \"select ta.plain_int_0 from alice.tbl_0 as ta where ta.plain_int_0 = any(select ta.plain_int_0 + tb.plain_int_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0)\"\n  },\n  {\n    \"name\": \"[two_parties]limit after join\",\n    \"query\": \"select alice.plain_int_0, bob.joinpayload_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 limit 10;\"\n  },\n  {\n    \"name\": \"[two_parties]sort after join\",\n    \"query\": \"select alice.plain_int_0, bob.joinpayload_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 order by alice.plain_float_0;\"\n  },\n  {\n    \"name\": \"[two_parties]greatest and least\",\n    \"query\": \"select greatest(alice.plain_int_0, alice.plain_int_1, bob.plain_int_0), least(alice.plain_int_0, alice.plain_int_1, bob.plain_int_0) from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]special funcs after join\",\n    \"query\": \"select +alice.plain_int_0, -bob.plain_int_0, cot(alice.plain_float_0) from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]percent_rank(secret)\",\n    \"query\": \"select ta.rank_int_0, percent_rank() over (partition by ta.rank_int_0 order by tb.rank_float_0, tb.rank_float_1) as num,percent_rank() over (partition by ta.rank_int_0 order by tb.rank_float_1) as num2 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0\"\n  },\n  {\n    \"name\": \"[two_parties]percent_rank(private)\",\n    \"query\": \"select ta.plain_int_0, percent_rank() over (partition by ta.plain_int_0 order by ta.plain_float_0 desc, ta.plain_float_1 asc) as num from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]rank & row_number(secret)\",\n    \"query\": \"select ta.rank_int_0, rank() over (partition by ta.rank_int_0 order by tb.rank_float_0, tb.rank_float_1) as rank_num, row_number() over (partition by ta.rank_int_0 order by tb.rank_float_0, tb.rank_float_1) as row_number_num from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0\"\n  },\n  {\n    \"name\": \"[two_parties]rank(secret)\",\n    \"query\": \"select ta.plain_int_0, rank() over (partition by ta.rank_int_0 order by tb.rank_float_0, tb.rank_float_1) as num from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0\"\n  },\n  {\n    \"name\": \"[two_parties]row_number and rank(private)\",\n    \"query\": \"select ta.plain_int_0, rank() over (partition by ta.join_int_1, ta.plain_int_0 order by ta.plain_float_0 desc, ta.plain_float_1 asc) as rank_num, row_number() over (partition by ta.join_int_0, ta.plain_int_0 order by ta.plain_float_0 desc, ta.plain_float_1 asc) as row_number_num from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]rank(private)\",\n    \"query\": \"select ta.plain_int_0, rank() over (partition by ta.join_int_0, ta.plain_int_0 order by ta.plain_float_0 desc, ta.plain_float_1 asc) as num from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]row_number(secret) with filter\",\n    \"query\": \"select u.* from (select ta.plain_int_0, row_number() over (partition by ta.plain_int_0 order by tb.rank_float_0, tb.rank_float_1) as num from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0) as u where u.num = 1;\"\n  },\n  {\n    \"name\": \"[two_parties]row_number(secret)\",\n    \"query\": \"select ta.plain_int_0, row_number() over (partition by ta.plain_int_0 order by tb.rank_float_0, tb.rank_float_1) as num from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]row_number(private) with filter\",\n    \"query\": \"select u.* from(select ta.plain_int_0, row_number() over (partition by ta.join_int_0, ta.plain_int_0 order by ta.plain_float_0 desc, ta.plain_float_1 asc) as num from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0) as u where u.num = 1;\"\n  },\n  {\n    \"name\": \"[two_parties]row_number(private)\",\n    \"query\": \"select ta.plain_int_0, row_number() over (partition by ta.join_int_0, ta.plain_int_0 order by ta.plain_float_0 desc, ta.plain_float_1 asc) as num from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]select with constant\",\n    \"query\": \"select ta.plain_float_0, 1 as constant_value from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0\"\n  },\n  {\n    \"name\": \"[two_parties]geodist test, param order(longtitude1, latitude1, longtitude2, latitude2, radius)\",\n    \"query\": \"select ta.plain_int_0, geodist(ta.plain_float_0, ta.plain_float_0, tb.plain_float_0, tb.plain_float_0, 6300) / 100 as distance from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]geodist test, param order(longtitude1, latitude1, longtitude2, latitude2)\",\n    \"query\": \"select ta.plain_int_0, geodist(ta.plain_float_0, ta.plain_float_0, tb.plain_float_0, tb.plain_float_0) / 100 as distance from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]geodist test(secret), param order(longtitude1, latitude1, longtitude2, latitude2)\",\n    \"query\": \"select u.plain_int_0, u.plain_float_0, geodist(u.plain_int_0, u.plain_int_0, u.plain_float_0, u.plain_float_0) / 1000 as distance from (select ta.plain_int_0, ta.plain_float_0 from alice.tbl_0 as ta union all select tb.plain_int_0, tb.plain_float_0 from bob.tbl_0 as tb) as u;\"\n  },\n  {\n    \"name\": \"[two_parties]all trigono union(make secret)\",\n    \"query\": \"select u.plain_int_0, sin(u.plain_int_0) / 10 as sin_plain_int_0, cos(u.plain_int_0) as cos_plain_int_0, acos(u.plain_int_0 / 10000) as acos_plain_int_0 from (select ta.plain_int_0 from  alice.tbl_0 as ta union all select tb.plain_int_0 from bob.tbl_0 as tb) as u;\"\n  },\n  {\n    \"name\": \"[two_parties]sine union(make secret)\",\n    \"query\": \"select u.plain_int_0, sin(u.plain_int_0) as sin_plain_int_0 from (select ta.plain_int_0 from  alice.tbl_0 as ta union all select tb.plain_int_0 from bob.tbl_0 as tb) as u;\"\n  },\n  {\n    \"name\": \"[two_parties]cosine union(make secret)\",\n    \"query\": \"select u.plain_int_0, cos(u.plain_int_0) as cos_plain_int_0 from (select ta.plain_int_0 from  alice.tbl_0 as ta union all select tb.plain_int_0 from bob.tbl_0 as tb) as u;\"\n  },\n  {\n    \"name\": \"[two_parties]arc cosine union(make secret)\",\n    \"query\": \"select u.plain_int_0, acos(u.plain_int_0 / 10000) as acos_plain_int_0 from (select ta.plain_int_0 from  alice.tbl_0 as ta union all select tb.plain_int_0 from bob.tbl_0 as tb) as u;\"\n  },\n  {\n    \"name\": \"[two_parties]naive trigonometric\",\n    \"query\": \"select ta.plain_int_0, sin(ta.plain_float_0) as sin_plain_float_0, cos(ta.plain_float_0) as cos_plain_float_0, acos(ta.plain_float_0 / 10000) as acos_plain_float_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]naive trigonometric sin/cos/acos\",\n    \"query\": \"select ta.plain_int_0, sin(ta.plain_float_0 * 1.5) as sin_plain_float_0, cos(ta.plain_float_0) as cos_plain_float_0, acos(ta.plain_float_0 / 10000) as acos_plain_float_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]trigonometric add with constant integer value\",\n    \"query\": \"select ta.plain_float_0 + sin(1) as sin_plain_float_0, ta.plain_float_0 + cos(1) as cos_plain_float_0, ta.plain_float_0 + acos(1) as acos_plain_float_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]trigonometric add with constant float value\",\n    \"query\": \"select ta.plain_float_0 + sin(3.14) as sin_plain_float_0, ta.plain_float_0 + cos(3.14) as cos_plain_float_0, ta.plain_float_0 + acos(0.5) as acos_plain_float_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]if after inner join\",\n    \"query\": \"select if(alice.encrypt_int_0>1, -alice.plain_int_0, -1) as cd from alice.tbl_0 as alice inner join bob.tbl_0 as bob on alice.join_string_0=bob.join_string_0;\"\n  },\n  {\n    \"name\": \"[two_parties]join on\",\n    \"query\": \"select alice.plain_int_0, bob.joinpayload_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]left join on\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice left join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]right join on\",\n    \"query\": \"select count(alice.plain_int_0) as t1 from alice.tbl_0 as alice right join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]join where\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice, bob.tbl_0 as bob where alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]join on multi keys\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 and alice.join_string_0 = bob.join_string_0 and alice.plain_datetime_0 = bob.plain_datetime_0 and alice.plain_timestamp_0 = bob.plain_timestamp_0;\"\n  },\n  {\n    \"name\": \"[two_parties]left join on multi keys\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice left join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 and alice.join_string_0 = bob.join_string_0 and alice.plain_datetime_0 = bob.plain_datetime_0 and alice.plain_timestamp_0 = bob.plain_timestamp_0;\"\n  },\n  {\n    \"name\": \"[two_parties]right join on multi keys\",\n    \"query\": \"select count(alice.plain_int_0) as t1 from alice.tbl_0 as alice right join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 and alice.join_string_0 = bob.join_string_0 and alice.plain_datetime_0 = bob.plain_datetime_0 and alice.plain_timestamp_0 = bob.plain_timestamp_0;\"\n  },\n  {\n    \"name\": \"[two_parties]join three table(alice, alice, bob)\",\n    \"query\": \"select alice0.plain_int_0 from alice.tbl_0 as alice0 join alice.tbl_1 as alice1 on alice0.encrypt_int_0 = alice1.encrypt_int_0 join bob.tbl_0 as bob0 on alice1.join_int_0 = bob0.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]join three table(alice, bob, alice)\",\n    \"query\": \"select alice0.plain_int_0 from alice.tbl_0 as alice0 join bob.tbl_0 as bob0 on alice0.join_int_0 = bob0.join_int_0 join alice.tbl_1 as alice1 on bob0.join_int_1 = alice1.join_int_1;\"\n  },\n  {\n    \"name\": \"[two_parties]join three table(alice, bob, bob)\",\n    \"query\": \"select alice0.plain_int_0 from alice.tbl_0 as alice0 join bob.tbl_0 as bob0 on alice0.join_int_0 = bob0.join_int_0 join bob.tbl_1 as bob1 on alice0.join_int_1 = bob1.join_int_1;\"\n  },\n  {\n    \"name\": \"[two_parties]apply in after join\",\n    \"query\": \"select alice.compare_int_0 in (select compare_int_0 from bob.tbl_0) as bob from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[two_parties]compare (less) after join\",\n    \"query\": \"select alice.compare_int_0 < bob.compare_int_0 as res0, alice.compare_int_0 < bob.compare_float_0 as res1, alice.compare_float_0 < bob.compare_float_0 as res2, alice.compare_datetime_0 < bob.compare_datetime_0 as res3, alice.compare_timestamp_0 < bob.compare_timestamp_0 as res4 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare (greater) after join\",\n    \"query\": \"select alice.compare_int_0 > bob.compare_int_0 as res0, alice.compare_int_0 > bob.compare_float_0 as res1, alice.compare_float_0 > bob.compare_float_0 as res2, alice.compare_datetime_0 > bob.compare_datetime_0 as res3, alice.compare_timestamp_0 > bob.compare_timestamp_0 as res4 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare (less or equal) after join\",\n    \"query\": \"select alice.compare_int_0 <= bob.compare_int_0 as res0, alice.compare_int_0 <= bob.compare_float_0 as res1, alice.compare_float_0 <= bob.compare_float_0 as res2, alice.compare_datetime_0 <= bob.compare_datetime_0 as res3, alice.compare_timestamp_0 <= bob.compare_timestamp_0 as res4 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare (greater or equal) after join\",\n    \"query\": \"select alice.compare_int_0 >= bob.compare_int_0 as res0, alice.compare_int_0 >= bob.compare_float_0 as res1, alice.compare_float_0 >= bob.compare_float_0 as res2, alice.compare_datetime_0 >= bob.compare_datetime_0 as res3, alice.compare_timestamp_0 >= bob.compare_timestamp_0 as res4 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare (not equal) after join\",\n    \"query\": \"select alice.compare_int_0 <> bob.compare_int_0 as res0, alice.compare_int_0 <> bob.compare_float_0 as res1, alice.compare_float_0 <> bob.compare_float_0 as res2, alice.compare_datetime_0 <> bob.compare_datetime_0 as res3, alice.compare_timestamp_0 <> bob.compare_timestamp_0 as res4 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic (plus) after join\",\n    \"query\": \"select bob.plain_int_0 + alice.plain_int_0 as res0, alice.plain_int_0 + bob.plain_float_0 as res1, alice.plain_float_0 + bob.plain_float_0 as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic (subtract) after join\",\n    \"query\": \"select bob.plain_int_0 - alice.plain_int_0 as res0, alice.plain_int_0 - bob.plain_float_0 as res1, alice.plain_float_0 - bob.plain_float_0 as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic (multiply) after join\",\n    \"query\": \"select bob.plain_int_0 * alice.plain_int_0 as res0, alice.plain_int_0 * bob.plain_float_0 as res1, alice.plain_float_0 * bob.plain_float_0 as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic (divide) after join\",\n    \"query\": \"select bob.plain_int_0 / (alice.plain_int_0 * alice.plain_int_0 + 1) as res0, alice.plain_int_0 / (bob.plain_float_0 *  bob.plain_float_0 + 1) res1, alice.plain_float_0 / (bob.plain_float_0 * bob.plain_float_0 + 1) as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic (mod) after join\",\n    \"query\": \"select bob.plain_int_0 % (alice.plain_int_0 * alice.plain_int_0 + 1) as res0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]max after join\",\n    \"query\": \"select max(alice.aggregate_int_0) as res0, max(bob.aggregate_int_0) as res1, max(alice.aggregate_float_0) as res2, max(bob.aggregate_float_0) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]max & arithmetic after join\",\n    \"query\": \"select max(alice.aggregate_int_0 + bob.aggregate_int_0) as res0, max(alice.aggregate_float_0 - bob.aggregate_float_1) as res1, max(alice.aggregate_float_0 * bob.aggregate_float_0) as res2, max(alice.aggregate_float_0 /(bob.aggregate_float_0 * bob.aggregate_float_0 + 1)) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]max & compare after join\",\n    \"query\": \"select max(alice.aggregate_int_0) > max(bob.aggregate_int_0) as res0, max(alice.aggregate_float_0) < max(bob.aggregate_float_1) as res1, max(alice.aggregate_int_0) >= max(bob.aggregate_float_0) as res2, max(alice.aggregate_float_0) <= max(bob.aggregate_float_0) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]min after join\",\n    \"query\": \"select min(alice.aggregate_int_0) as res0, min(bob.aggregate_int_0) as res1, min(alice.aggregate_float_0) as res2, min(bob.aggregate_float_0) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]min & arithmetic after join\",\n    \"query\": \"select min(alice.aggregate_int_0 + bob.aggregate_int_0) as res0, min(alice.aggregate_float_0 - bob.aggregate_float_1) as res1, min(alice.aggregate_float_0 * bob.aggregate_float_0) as res2, min(alice.aggregate_float_0 / (bob.aggregate_float_0 * bob.aggregate_float_0 + 1)) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]min & compare after join\",\n    \"query\": \"select min(alice.aggregate_int_0) > min(bob.aggregate_int_0) as res0, min(alice.aggregate_float_0) < min(bob.aggregate_float_1) as res1, min(alice.aggregate_int_0) >= min(bob.aggregate_float_0) as res2, min(alice.aggregate_float_0) <= min(bob.aggregate_float_0) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]avg after join\",\n    \"query\": \"select avg(alice.aggregate_int_0) as res0, avg(bob.aggregate_int_0) as res1, avg(alice.aggregate_float_0) as res2, avg(bob.aggregate_float_0) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]avg & arithmetic after join\",\n    \"query\": \"select avg(alice.aggregate_int_0 + bob.aggregate_int_0) as res0, avg(alice.aggregate_float_0 - bob.aggregate_float_1) as res1, avg(alice.aggregate_float_0 * bob.aggregate_float_0) as res2, avg(alice.aggregate_float_0 / (bob.aggregate_float_0 * bob.aggregate_float_0 + 1)) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]avg & compare after join\",\n    \"query\": \"select avg(alice.aggregate_int_0) > avg(bob.aggregate_int_0) as res0, avg(alice.aggregate_float_0) < avg(bob.aggregate_float_1) as res1, avg(alice.aggregate_int_0) >= avg(bob.aggregate_float_0) as res2, avg(alice.aggregate_float_0) <= avg(bob.aggregate_float_0) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]sum after join\",\n    \"query\": \"select sum(alice.aggregate_int_0) as res0, sum(bob.aggregate_int_0) as res1, sum(alice.aggregate_float_0) as res2, sum(bob.aggregate_float_0) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]sum bool after join\",\n    \"query\": \"select sum(alice.aggregate_int_0 > 0) as res0, sum(bob.aggregate_int_0 > 0) as res1, sum(alice.aggregate_float_0 > 0) as res2, sum(bob.aggregate_float_0 > 0) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]sum & arithmetic after join\",\n    \"query\": \"select sum(alice.aggregate_int_0 + bob.aggregate_int_0) as res0, sum(alice.aggregate_float_0 - bob.aggregate_float_1) as res1, sum(alice.aggregate_float_0 * bob.aggregate_float_0) as res2, sum(alice.aggregate_float_0 /(bob.aggregate_float_0 * bob.aggregate_float_0 + 1)) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]sum & compare after join\",\n    \"query\": \"select sum(alice.aggregate_int_0) > sum(bob.aggregate_int_0) as res0, sum(alice.aggregate_float_0) < sum(bob.aggregate_float_1) as res1, sum(alice.aggregate_int_0) >= sum(bob.aggregate_float_0) as res2, sum(alice.aggregate_float_0) <= sum(bob.aggregate_float_0) as res3 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]count after join\",\n    \"query\": \"select count(alice.aggregate_int_0) as res0, count(bob.aggregate_int_0) as res1, count(alice.aggregate_float_0) as res2, count(bob.aggregate_float_0) as res3, count(alice.aggregate_string_0) as res4, count(bob.aggregate_string_0) as res5, count(alice.aggregate_datetime_0) as res6, count(bob.aggregate_datetime_0) as res7, count(alice.aggregate_timestamp_0) as res8, count(bob.aggregate_timestamp_0) as res9 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]count & distinct after join\",\n    \"query\": \"select count(distinct alice.aggregate_int_0) as res0, count(distinct bob.aggregate_int_0) as res1, count(distinct alice.aggregate_float_0) as res2, count(distinct bob.aggregate_float_0) as res3, count(distinct alice.aggregate_string_0) as res4, count(distinct bob.aggregate_string_0) as res5, count(distinct alice.aggregate_datetime_0) as res6, count(distinct bob.aggregate_datetime_0) as res7, count(distinct alice.aggregate_timestamp_0) as res8, count(distinct bob.aggregate_timestamp_0) as res9 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]count & distinct & if after join\",\n    \"query\": \"select count(distinct (if(alice.encrypt_int_0>1, bob.join_string_0, 'aaaaa'))) as cd from alice.tbl_0 as alice inner join bob.tbl_0 as bob on alice.join_string_0=bob.join_string_0 group by bob.groupby_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]logic after join\",\n    \"query\": \"select alice.plain_int_0 as res0, alice.plain_int_0 > bob.plain_int_0 and alice.plain_int_0 >= bob.plain_int_0 as and_log, (alice.plain_int_0 <= bob.plain_int_0) or (alice.plain_int_0 <> bob.plain_int_0) as or_log from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]cast(private) after join\",\n    \"query\": \"select cast(alice.plain_int_0 as decimal(64,30)) as df, cast(alice.plain_int_0 as char) as ds from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]in after join\",\n    \"query\": \"select  alice.compare_int_0 in (select compare_int_0 from bob.tbl_0) as in_column from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[two_parties]not in after join\",\n    \"query\": \"select alice.compare_int_0 not in (select compare_int_0 from bob.tbl_0) as not_in_column from alice.tbl_0 as alice;\"\n  },\n  {\n    \"name\": \"[two_parties]in list after join\",\n    \"query\": \"select alice.plain_int_0 in (100, 12.3, 10) as res from alice.tbl_0 as alice, bob.tbl_0 as bob where alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]null after join\",\n    \"query\": \"select bob.plain_int_0 is not null as c1, ifnull(bob.plain_string_0, 'null_str') as c2, coalesce(bob.plain_float_0, bob.plain_float_1, 1.0) as c3 from alice.tbl_0 as alice left join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare(less) before join\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 < bob.compare_int_1 and alice.compare_float_0 < bob.compare_int_1 and alice.compare_float_0 < bob.compare_float_1 and alice.compare_datetime_0 < bob.compare_datetime_0 and alice.compare_timestamp_0 < bob.compare_timestamp_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare(greater) before join\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_1 > bob.compare_int_0 and alice.compare_float_1 > bob.compare_int_0 and alice.compare_float_1 > bob.compare_float_0 and alice.compare_datetime_0 > bob.compare_datetime_0 and alice.compare_timestamp_0 > bob.compare_timestamp_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare(less or equal) before join\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 <= bob.compare_int_1 and alice.compare_float_0 <= bob.compare_int_1 and alice.compare_float_0 <= bob.compare_float_1 and alice.compare_datetime_0 <= bob.compare_datetime_0 and alice.compare_timestamp_0 <= bob.compare_timestamp_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare(greater or equal) before join\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_1 >= bob.compare_int_0 and alice.compare_float_1 >= bob.compare_int_0 and alice.compare_float_1 >= bob.compare_float_0 and alice.compare_datetime_0 >= bob.compare_datetime_0 and alice.compare_timestamp_0 >= bob.compare_timestamp_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare(not equal) before join\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_1 <> bob.compare_int_0 and alice.compare_float_1 <> bob.compare_int_0 and alice.compare_float_1 <> bob.compare_float_0 and alice.compare_datetime_0 <> bob.compare_datetime_0 and alice.compare_timestamp_0 <> bob.compare_timestamp_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic(plus) before join \",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 + bob.compare_int_0 > bob.compare_int_0 and alice.compare_int_0 + bob.compare_float_0 > bob.compare_int_0 and alice.compare_float_0 + bob.compare_float_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic(subtract) before join \",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 - bob.compare_int_0 > bob.compare_int_0 or alice.compare_int_0 - bob.compare_float_0 > bob.compare_int_0 or alice.compare_float_0 - bob.compare_float_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic(multiply) before join \",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 * bob.compare_int_0 > bob.compare_int_0 and alice.compare_int_0 * bob.compare_float_0 > bob.compare_int_0 and alice.compare_float_0 * bob.compare_float_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic(divide) before join \",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 / (bob.compare_int_0 * bob.compare_int_0 + 1) > bob.compare_int_0 or alice.compare_int_0 /(bob.compare_float_0 * bob.compare_float_0 + 1) > bob.compare_int_0 or alice.compare_float_0 /(bob.compare_float_0 * bob.compare_float_0 + 1) > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic(intdiv) before join \",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 div (bob.compare_int_0 + 200) > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]null before join\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.join_string_0 is null;\"\n  },\n  {\n    \"name\": \"[two_parties]not null before join\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where bob.plain_string_0 is not null;\"\n  },\n  {\n    \"name\": \"[two_parties]apply in before join\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice where alice.compare_int_0 in (select bob.compare_int_0 from bob.tbl_0 as bob);\"\n  },\n  {\n    \"name\": \"[two_parties]apply not in before join\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice where alice.compare_int_0 not in (select bob.compare_int_0 from bob.tbl_0 as bob);\"\n  },\n  {\n    \"name\": \"[two_parties]in list before join\",\n    \"query\": \"select alice.join_string_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.join_string_0 in (\\\"ejjepeki\\\", \\\"ma\\\");\"\n  },\n  {\n    \"name\": \"[two_parties]where(null)\",\n    \"query\": \"select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare (less) where(null)\",\n    \"query\": \"select alice.compare_int_0 < bob.compare_int_0 as res0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare (greater) where(null)\",\n    \"query\": \"select alice.compare_int_0 > bob.compare_int_0 as res0  from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare (less or equal) where(null)\",\n    \"query\": \"select alice.compare_int_0 <= bob.compare_int_0 as res0, alice.compare_int_0 <= bob.compare_float_0 as res1, alice.compare_float_0 <= bob.compare_float_0 as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare (greater or equal) where(null)\",\n    \"query\": \"select alice.compare_int_0 >= bob.compare_int_0 as res0, alice.compare_int_0 >= bob.compare_float_0 as res1, alice.compare_float_0 >= bob.compare_float_0 as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]compare (not equal) where(null)\",\n    \"query\": \"select alice.compare_int_0 <> bob.compare_int_0 as res0, alice.compare_int_0 <> bob.compare_float_0 as res1, alice.compare_float_0 <> bob.compare_float_0 as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic (plus) where(null)\",\n    \"query\": \"select bob.plain_int_0 + alice.plain_int_0 as res0, alice.plain_int_0 + bob.plain_float_0 as res1, alice.plain_float_0 + bob.plain_float_0 as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic (subtract) where(null)\",\n    \"query\": \"select bob.plain_int_0 - alice.plain_int_0 as res0, alice.plain_int_0 - bob.plain_float_0 as res1, alice.plain_float_0 - bob.plain_float_0 as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic (multiply) where(null)\",\n    \"query\": \"select bob.plain_int_0 * alice.plain_int_0 as res0, alice.plain_int_0 * bob.plain_float_0 as res1, alice.plain_float_0 * bob.plain_float_0 as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arithmetic (divide) where(null)\",\n    \"query\": \"select bob.plain_int_0 / (alice.plain_int_0 * alice.plain_int_0 + 1) as res0, alice.plain_int_0 / (bob.plain_float_0 * bob.plain_float_0 + 1) as res1, alice.plain_float_0 / (bob.plain_float_0 * bob.plain_float_0 + 1) as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]logic where(null)\",\n    \"query\": \"select alice.plain_int_0 as res0, alice.plain_int_0 > bob.plain_int_0 and alice.plain_int_0 >= bob.plain_int_0 as and_log, (alice.plain_int_0 <= bob.plain_int_0) or (alice.plain_int_0 <> bob.plain_int_0) as or_log from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 > bob.compare_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]in where(null)\",\n    \"query\": \"select  alice.compare_int_0 in (select compare_int_0 from bob.tbl_0) as in_column from alice.tbl_0 as alice where alice.compare_int_0 > 1000;\"\n  },\n  {\n    \"name\": \"[two_parties]not in where(null)\",\n    \"query\": \"select alice.compare_int_0 not in (select compare_int_0 from bob.tbl_0) as not_in_column from alice.tbl_0 as alice where alice.compare_int_0 > 1000;\"\n  },\n  {\n    \"name\": \"[two_parties]agg with group by(long), private group by\",\n    \"query\": \"select ta.groupby_int_0, sum(ta.aggregate_int_0) as b, max(ta.aggregate_int_0) as a, min(ta.aggregate_int_0) as d from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 group by ta.groupby_int_0 having count(*) >= 4\"\n  },\n  {\n    \"name\": \"[two_parties]agg with group by(float), private group by\",\n    \"query\": \"select ta.groupby_int_0, sum(ta.aggregate_float_0) as b, max(ta.aggregate_float_0 + ta.aggregate_float_0) as a, min(ta.aggregate_float_0) as d from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 group by ta.groupby_int_0 having count(*) >= 4\"\n  },\n  {\n    \"name\": \"[two_parties]agg with group by(string), private group by\",\n    \"query\": \"select ta.groupby_string_0, count(*) as c, count(distinct ta.aggregate_int_0) as cd, sum(ta.aggregate_int_0) as sum, min(ta.aggregate_int_0) as min, max(ta.aggregate_int_0) as max, avg(ta.aggregate_int_0) as avg from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 group by ta.groupby_string_0 having count(*) >= 4\"\n  },\n  {\n    \"name\": \"[two_parties]agg with group by(datetime), private group by\",\n    \"query\": \"select ta.groupby_datetime_0, count(*) as c, count(distinct ta.aggregate_int_0) as cd, sum(ta.aggregate_int_0) as sum, min(ta.aggregate_int_0) as min, max(ta.aggregate_int_0) as max, avg(ta.aggregate_int_0) as avg from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 group by ta.groupby_datetime_0 having count(*) >= 4\"\n  },\n  {\n    \"name\": \"[two_parties]agg with group by(string2), oblivious group by\",\n    \"query\": \"select ta.groupby_string_0,tb.groupby_string_0, count(*) as c, count(distinct ta.aggregate_int_0) as cd, sum(ta.aggregate_int_0) as sum, min(ta.aggregate_int_0) as min, max(ta.aggregate_int_0) as max, avg(ta.aggregate_int_0) as avg from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 group by ta.groupby_string_0,tb.groupby_string_0\"\n  },\n  {\n    \"name\": \"[two_parties]key merge, oblivious group by\",\n    \"query\": \"select ta.groupby_int_0, ta.groupby_string_0, tb.groupby_string_0 as tbs, count(*) as c, count(distinct ta.aggregate_int_0) as cd, sum(ta.aggregate_int_0) as sum, min(ta.aggregate_int_0) as min, max(ta.aggregate_int_0) as max, avg(ta.aggregate_int_0) as avg from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 group by ta.groupby_int_0, ta.groupby_string_0, tb.groupby_string_0\"\n  },\n  {\n    \"name\": \"[two_parties]private group by with secret sum\",\n    \"query\": \"select ta.groupby_string_0, sum(tb.aggregate_int_0) as sl, sum(tb.aggregate_float_0) as sf, count(tb.encrypt_int_0) as c from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0 group by ta.groupby_string_0;\"\n  },\n  {\n    \"name\": \"[two_parties]select plain data from another party\",\n    \"query\": \"select plain_int_0, plain_string_0, plain_float_0, plain_datetime_0, plain_timestamp_0 from bob.tbl_0\"\n  },\n  {\n    \"name\": \"[two_parties]union all tests\",\n    \"query\": \"select ta.plain_int_0 from alice.tbl_0 as ta union all select tb.plain_int_0 from bob.tbl_0 as tb\"\n  },\n  {\n    \"name\": \"[two_parties]cast(secret) after union\",\n    \"query\": \"select cast(u.plain_int_0 as decimal) as fd from  (select ta.plain_int_0 from  alice.tbl_0 as ta union all select tb.plain_int_0 from bob.tbl_0 as tb) as u;\"\n  },\n  {\n    \"name\": \"[two_parties]union tests\",\n    \"query\": \"select ta.plain_int_0 from alice.tbl_0 as ta union select tb.plain_int_0 from bob.tbl_0 as tb\"\n  },\n  {\n    \"name\": \"[two_parties]distinct tests\",\n    \"query\": \"select distinct plain_int_0 from (select ta.plain_int_0 from alice.tbl_0 as ta union all select tb.plain_int_0 from bob.tbl_0 as tb) as u\"\n  },\n  {\n    \"name\": \"[two_parties]agg func after union all tests\",\n    \"query\": \"select count(*) as cc, max(aggregate_int_0) as mm from (select aggregate_int_0, groupby_int_0 from alice.tbl_0 union all select aggregate_int_0, groupby_int_0 from bob.tbl_1) as u\"\n  },\n  {\n    \"name\": \"[two_parties]group by/agg after union all tests\",\n    \"query\": \"select count(*) as cc, max(groupby_int_0) as mm from (select aggregate_int_0, groupby_int_0 from alice.tbl_0 union all select aggregate_int_0, groupby_int_0 from bob.tbl_1) as u group by u.groupby_int_0 having count(*) >= 4\"\n  },\n  {\n    \"name\": \"[two_parties]if after join\",\n    \"query\": \"select if(ta.plain_int_0, tb.plain_int_0, ta.plain_int_0) as res from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0\"\n  },\n  {\n    \"name\": \"[two_parties]if (compare) after join\",\n    \"query\": \"select if(ta.compare_int_0 > tb.compare_int_0, ta.plain_int_0, tb.plain_int_0) as res from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0\"\n  },\n  {\n    \"name\": \"[two_parties]case when after join\",\n    \"query\": \"select case when alice.compare_int_0 > bob.compare_int_0 then alice.plain_int_0 else bob.plain_int_0 end as case_when1, case when alice.compare_int_0 then 1 else 0 end as case_when2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]case when(multi condition) after join\",\n    \"query\": \"select case when alice.compare_int_0 > bob.compare_int_0 then alice.plain_int_0 when alice.plain_int_0 > 50 then bob.plain_int_0 when alice.plain_int_0 then 1 else 0 end as res1 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]date func (now, curdate)\",\n    \"query\": \"select alice.plain_datetime_0 < now() as res1, alice.plain_datetime_0 < curdate() as res2 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_datetime_0 = bob.join_datetime_0;\"\n  },\n  {\n    \"name\": \"[two_parties]date func (adddate, subdate)\",\n    \"query\": \"select adddate(alice.plain_datetime_0, interval 10 day) as res1, adddate(bob.plain_datetime_0, interval 10 day) as res2, subdate(alice.plain_datetime_0, interval 10 day) as res3, subdate(bob.plain_datetime_0, interval 10 day) as res4 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_datetime_0 = bob.join_datetime_0;\"\n  },\n  {\n    \"name\": \"[two_parties] date func (date_add, date_sub)\",\n    \"query\": \"select bob.plain_datetime_0 > DATE_ADD('2025-04-05', INTERVAL 1 DAY) from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.plain_datetime_0 < DATE_SUB('2025-04-05 10:10:10', INTERVAL 1 DAY);\"\n  },\n  {\n    \"name\": \"[two_parties]date func (datediff)\",\n    \"query\": \"select datediff(alice.plain_datetime_0, bob.plain_datetime_1) as res1 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_datetime_0 = bob.join_datetime_0;\"\n  },\n  {\n    \"name\": \"[two_parties]negative constant\",\n    \"query\": \"select if(ta.plain_float_0, -1.0, -ta.plain_float_0) as res from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties]arrow func (upper, lower, substring, trim, concat, strtodate)\",\n    \"query\": \"select upper(ta.plain_string_0) as up, lower(ta.plain_string_0) as lo, substring(ta.plain_string_0, 2, 3) as sl, trim(ta.plain_string_0) as tr, concat(ta.plain_string_0, ta.join_string_0) as co, str_to_date('2023-12-25', '%Y-%m-%d') as cd, str_to_date(ta.plain_string_0, '%Y-%m-%d') as sd from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;\"\n  },\n  {\n    \"name\": \"[two_parties] exists subquery\",\n    \"query\": \"SELECT t1.plain_int_1 AS o_orderpriority,count(*) AS order_count FROM alice.tbl_0 t1 WHERE t1.plain_int_0>=3 AND t1.plain_int_0<7 AND EXISTS(SELECT * FROM bob.tbl_0 t0 WHERE t0.plain_string_0=t1.plain_string_0 AND t0.plain_int_0<t0.plain_int_1) GROUP BY o_orderpriority ORDER BY o_orderpriority;\"\n  },\n  {\n    \"name\": \"[multi_parties]join on\",\n    \"query\": \"select alice.encrypt_float_1 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 join carol.tbl_0 as carol on bob.join_int_1 = carol.join_int_1;\"\n  },\n  {\n    \"name\": \"[multi_parties]join where\",\n    \"query\": \"select alice.encrypt_float_1 from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_1 = carol.join_int_1;\"\n  },\n  {\n    \"name\": \"[multi_parties]join arithmetics\",\n    \"query\": \"select alice.plain_int_0 + bob.join_int_0 + carol.join_int_0 as add_res, alice.plain_int_0 - bob.join_int_0 - carol.join_int_0 as minus_res, alice.plain_int_0 * bob.join_int_0 * carol.join_int_0 as multi_res, alice.plain_int_0 / bob.join_int_0 / carol.join_int_0 as div_res from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0 and bob.join_int_0 != 0 and carol.join_int_0 != 0;\"\n  },\n  {\n    \"name\": \"[multi_parties]join compare\",\n    \"query\": \"select alice.plain_int_0 > bob.join_int_0 as greater_res, alice.plain_int_0 < carol.join_int_0 as less_res, alice.plain_int_0 = carol.join_int_0 as equal_res, alice.plain_int_0 != carol.join_int_0 as unequal_res from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0;\"\n  },\n  {\n    \"name\": \"[multi_parties]join arithmetics(share) compare\",\n    \"query\": \"select (alice.compare_int_0 + bob.compare_int_0) > (bob.compare_int_0 + carol.join_int_0) as add_res, (alice.compare_int_0 - bob.compare_int_0) < (bob.compare_int_0 - carol.compare_int_0) as minus_res, (alice.compare_int_0 * bob.compare_int_0) >= (bob.compare_int_0 * carol.compare_int_0) as multi_res, (alice.compare_int_0 div bob.compare_int_0) <= (bob.compare_int_0 div carol.compare_int_0) as div_res from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0 and bob.compare_int_0 != 0 and carol.compare_int_0 != 0;\"\n  },\n  {\n    \"name\": \"[multi_parties]join arithmetics(share) equal/not equal\",\n    \"query\": \"select (alice.compare_int_0 + bob.compare_int_0) = (bob.compare_int_0 + carol.join_int_0) as add_res, (alice.compare_int_0 - bob.compare_int_0) != (bob.compare_int_0 - carol.join_int_0) as minus_res from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0 and bob.compare_int_0 != 0 and carol.compare_int_0 != 0;\"\n  },\n  {\n    \"name\": \"[multi_parties]join cast\",\n    \"query\": \"select cast(alice.plain_int_0 as decimal) as cp, cast(alice.compare_int_0 > bob.compare_int_0 as decimal) as cs from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0;\"\n  },\n  {\n    \"name\": \"[multi_parties]join oblivious group by\",\n    \"query\": \"select key1, key2, count(*) as c, count(distinct bob_encrypt) as cd, sum(bob_aggregate) as sb, max(carol_aggregate) as sc, min(carol_aggregate) as min_ca, avg(carol_aggregate) as avg_ca from (select bob.encrypt_int_0 as bob_encrypt, bob.aggregate_int_0 as bob_aggregate, carol.aggregate_int_0 as carol_aggregate, alice.join_int_0 as alice_join, bob.join_int_0 as bob_join, carol.join_int_0 as carol_join, alice.groupby_int_0 + bob.groupby_int_0 as key1, carol.groupby_int_0 + bob.groupby_int_0 as key2 from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol) as tt where alice_join = bob_join and bob_join = carol_join group by key1, key2;\"\n  },\n  {\n    \"name\": \"[multi_parties]join oblivious group by multi keys\",\n    \"query\": \"select count(*) as c, count(distinct bob.encrypt_int_0) as cd, sum(bob.aggregate_int_0) as sb, sum(carol.aggregate_int_0) as sc from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0 group by alice.groupby_int_0, bob.groupby_int_0, carol.groupby_int_0, carol.groupby_string_0 having count(*) > 3;\"\n  },\n  {\n    \"name\": \"[multi_parties]join group by secret agg\",\n    \"query\": \"select count(*) as c, sum(bob.aggregate_int_0) as sb, avg(carol.aggregate_float_0) as ac from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0 group by alice.groupby_int_0 having count(*) > 3;\"\n  },\n  {\n    \"name\": \"[multi_parties]union all group by string\",\n    \"query\": \"select count(*) as c, groupby_string_0 from (select aggregate_int_0, groupby_string_0 from alice.tbl_0 union all select aggregate_int_0, groupby_string_0 from bob.tbl_1 union all select aggregate_int_0, groupby_string_0 from carol.tbl_2) as u group by u.groupby_string_0 having count(*) > 3;\"\n  },\n  {\n    \"name\": \"[multi_parties]union all tests\",\n    \"query\": \"select ta.plain_int_0 from alice.tbl_0 as ta union all select tb.plain_int_0 from bob.tbl_0 as tb union all select tc.plain_int_0 from carol.tbl_0 as tc\"\n  },\n  {\n    \"name\": \"[multi_parties]agg after union all tests\",\n    \"query\": \"select count(*) as cc, max(aggregate_int_0) as mm from (select aggregate_int_0, groupby_int_0 from alice.tbl_0 union all select aggregate_int_0, groupby_int_0 from bob.tbl_1 union all select aggregate_int_0, groupby_int_0 from carol.tbl_2) as u\"\n  },\n  {\n    \"name\": \"[multi_parties]union tests\",\n    \"query\": \"select ta.plain_int_0 from alice.tbl_0 as ta union select tb.plain_int_0 from bob.tbl_0 as tb union select tc.plain_int_0 from carol.tbl_0 as tc\"\n  },\n  {\n    \"name\": \"[multi_parties]join compare\",\n    \"query\": \"select alice.plain_int_0 > bob.join_int_0 as greater_res, alice.plain_int_0 < carol.join_int_0 as less_res, alice.plain_int_0 = carol.join_int_0 as equal_res, alice.plain_int_0 != carol.join_int_0 as unequal_res from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0;\"\n  },\n  {\n    \"name\": \"[multi_parties]agg after union all tests. agg(bool)\",\n    \"query\": \"select count(*) as cc, max(aggregate_int_0 > 0) as mm, min(aggregate_int_0 > 0) as mn, sum(aggregate_int_0 > 0) as su, avg(aggregate_int_0 > 0) as av from (select aggregate_int_0, groupby_int_0 from alice.tbl_0 union all select aggregate_int_0, groupby_int_0 from bob.tbl_1 union all select aggregate_int_0, groupby_int_0 from carol.tbl_2) as u\"\n  },\n  {\n    \"name\": \"[multi_parties]join in\",\n    \"query\": \"select (alice.compare_int_0 + bob.compare_int_0 + carol.compare_int_0) in (100, 12.3, 10) as res, alice.compare_int_0 not in (0, 10, 100) as res1  from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0;\"\n  },\n  {\n    \"name\": \"[multi_parties]if (compare)\",\n    \"query\": \"select if(alice.compare_int_0 > bob.compare_int_0, alice.plain_int_0, bob.plain_int_0) as res1, if(bob.compare_int_0 > carol.compare_int_0, bob.plain_int_0, carol.plain_int_0) as res2 from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0;\"\n  },\n  {\n    \"name\": \"[multi_parties]case when after join\",\n    \"query\": \"select case when alice.compare_int_0 > bob.compare_int_0 then alice.plain_int_0 else bob.plain_int_0 end as case_when1, case when bob.compare_int_0 > carol.compare_int_0 then 1 else 0 end as case_when2 from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0;\"\n  },\n  {\n    \"name\": \"[multi_parties]case when(multi condition) after join\",\n    \"query\": \"select case when alice.compare_int_0 > bob.compare_int_0 then alice.plain_int_0 when carol.compare_int_0 > 100 then carol.plain_int_0 when carol.plain_int_0 then 1 else 0 end as res1 from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0;\"\n  },\n  {\n    \"name\": \"[multi_parties]test case sensitive\",\n    \"query\": \"select alice.groupby_int_0 as r1, alice.GROUPBY_int_1 as r2, bob.join_string_0 as r3, bob.JOIN_STRING_0 as r4 from alice.UPPER_table as alice, bob.UPPER_table as bob, carol.UPPER_table as carol where alice.join_string_0 = bob.JOIN_string_0 and bob.join_string_1 = carol.JOIN_string_1 and carol.COMPARE_float_0 > 0 and carol.compare_float_1 > 0;\"\n  },\n  {\n    \"name\": \"[multi_parties]secret join with union all\",\n    \"query\": \"select ta.join_int_0, ta.groupby_string_0, tu.plain_float_0 from alice.tbl_0 as ta inner join (select tb.join_int_0, tb.plain_float_0 from bob.tbl_0 as tb union all select tc.join_int_0, tc.plain_float_0 from carol.tbl_0 as tc) as tu on ta.join_int_0=tu.join_int_0;\"\n  }\n]\n"
  },
  {
    "path": "pkg/interpreter/compiler/execution_graph_builder.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"maps\"\n\t\"slices\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n)\n\ntype ExecutionGraphBuilder struct {\n\tpipelineEngineNodes []*PipelineExecNode\n\ttensorMetaManager   *TensorMetaManager\n\tsrm                 *SecurityRelaxationManager\n\tvt                  *VisibilityTable\n\ttm                  *TensorManager\n\tinfo                *graph.EnginesInfo\n\n\toutputNames []string\n\n\tpreOpStreamingType operator.StreamingOpType\n\tcompileOpts        *v1.CompileOptions\n}\n\ntype PipelineExecNode struct {\n\tBatched        bool\n\tExecutionNodes []*graph.ExecutionNode\n}\n\nfunc NewExecutionGraphBuilder(tensorMetaManager *TensorMetaManager, srm *SecurityRelaxationManager, vt *VisibilityTable, info *graph.EnginesInfo, compileOpts *v1.CompileOptions) *ExecutionGraphBuilder {\n\tbuilder := &ExecutionGraphBuilder{\n\t\ttensorMetaManager: tensorMetaManager,\n\t\tsrm:               srm,\n\t\tvt:                vt,\n\t\t// make nextTensorID == {the number of existing tensor metas} + 1,\n\t\t// then we can keep tensor id for tensors which are the first placed tensor for their corresponding tensor meta\n\t\ttm:          NewTensorManager(tensorMetaManager.tensorNum + 1),\n\t\tinfo:        info,\n\t\tcompileOpts: compileOpts,\n\t}\n\treturn builder\n}\n\nfunc (builder *ExecutionGraphBuilder) GetAllParties() []string {\n\treturn builder.vt.allParties\n}\n\nfunc (builder *ExecutionGraphBuilder) SetBatched(batched bool) {\n\tif builder.compileOpts != nil {\n\t\tbuilder.compileOpts.Batched = batched\n\t}\n}\n\nfunc (builder *ExecutionGraphBuilder) IsBatched() bool {\n\tif builder.compileOpts != nil {\n\t\treturn builder.compileOpts.Batched\n\t}\n\treturn false\n}\n\nfunc (builder *ExecutionGraphBuilder) TensorManager() *TensorManager {\n\treturn builder.tm\n}\n\nfunc (builder *ExecutionGraphBuilder) DumpPlan() string {\n\tvar sb strings.Builder\n\tfmt.Fprintf(&sb, \"Execution Graph:\\n\")\n\tfor _, pipeline := range builder.pipelineEngineNodes {\n\t\tfor _, node := range pipeline.ExecutionNodes {\n\t\t\tfmt.Fprintf(&sb, \"%s\\n\", node.ToString())\n\t\t}\n\t}\n\treturn sb.String()\n}\n\n// Build converts the OperatorGraph into ExecutionGraph.\nfunc (builder *ExecutionGraphBuilder) Build(operatorGraph *OperatorGraph) (*graph.Graph, error) {\n\tkr := NewKernelResolver(builder.srm, builder.vt, builder.tm, builder.compileOpts)\n\tfor _, node := range operatorGraph.operators {\n\t\tkernel, err := kr.Resolve(node)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"Build Execution Graph failed: %v\", err)\n\t\t}\n\t\tlogrus.Debugf(\"Processing node: %s, kernel: %s\", node.String(), kernel.String())\n\t\tnode.SetKernel(kernel)\n\t\tif err := builder.addKernel(kernel, node); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"Build Execution Graph failed: %v\", err)\n\t\t}\n\t}\n\n\treturn builder.buildGraph()\n}\n\nfunc (builder *ExecutionGraphBuilder) addKernel(kernel Kernel, node Operator) error {\n\tif err := kernel.ensureTensorPlace(builder, node); err != nil {\n\t\treturn fmt.Errorf(\"addKernel: %v\", err)\n\t}\n\tif err := kernel.toEngineNodes(builder, node); err != nil {\n\t\treturn fmt.Errorf(\"addKernel: %v\", err)\n\t}\n\treturn nil\n}\n\n// addEngineNode creates an execution node with the specified operation and adds it to the current pipeline.\n// It handles pipeline batching decisions based on operation streaming type and manages tensor flow between nodes.\nfunc (builder *ExecutionGraphBuilder) addEngineNode(name string, opType string, inputs map[string][]*graph.Tensor, outputs map[string][]*graph.Tensor,\n\tattributes map[string]*graph.Attribute, partyCodes []string) error {\n\topDef, err := operator.FindOpDef(opType)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"addEngineNode: %v\", err)\n\t}\n\n\tif err := operator.CheckParamStatusConstraint(opDef, inputs, outputs); err != nil {\n\t\treturn fmt.Errorf(\"addEngineNode: %v\", err)\n\t}\n\n\tnode := &graph.ExecutionNode{\n\t\tName:       name,\n\t\tOpType:     opType,\n\t\tInputs:     make(map[string][]*graph.Tensor),\n\t\tOutputs:    make(map[string][]*graph.Tensor),\n\t\tAttributes: make(map[string]*graph.Attribute),\n\t\tParties:    partyCodes,\n\t}\n\tfor k, is := range inputs {\n\t\tnode.Inputs[k] = slices.Clone(is)\n\t}\n\tfor k, os := range outputs {\n\t\tnode.Outputs[k] = slices.Clone(os)\n\t}\n\tmaps.Copy(node.Attributes, attributes)\n\n\tfor k, defaultAttr := range opDef.GetDefaultAttribute() {\n\t\tif _, ok := node.Attributes[k]; !ok {\n\t\t\tnode.Attributes[k] = &graph.Attribute{\n\t\t\t\tTensorValue: graph.NewTensorFromProto(defaultAttr.GetT()),\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(builder.pipelineEngineNodes) == 0 ||\n\t\t(builder.IsBatched() && len(builder.getLastPipelineOperator().ExecutionNodes) > 0 && builder.preOpStreamingType != opDef.GetStreamingType()) {\n\t\tbuilder.pipelineEngineNodes = append(builder.pipelineEngineNodes, &PipelineExecNode{})\n\t}\n\tcurPipelineNode := builder.getLastPipelineOperator()\n\tbuilder.preOpStreamingType = opDef.GetStreamingType()\n\tcurPipelineNode.ExecutionNodes = append(curPipelineNode.ExecutionNodes, node)\n\tif builder.IsBatched() && len(curPipelineNode.ExecutionNodes) == 1 {\n\t\tcurPipelineNode.Batched = (opDef.GetStreamingType() == operator.StreamingOp)\n\t}\n\treturn nil\n}\n\n// prepareResultForParty creates tensors for party-specific result handling.\n// It generates input tensors with private placement and output tensors for result names.\nfunc (builder *ExecutionGraphBuilder) prepareResultForParty(originResults []*TensorMeta, resultNames []string, partyCode string) (inputs, outputs []*graph.Tensor, err error) {\n\tif len(originResults) != len(resultNames) {\n\t\treturn nil, nil, fmt.Errorf(\"prepareResultForParty: originResults length:%d != resultNames length:%d\", len(originResults), len(resultNames))\n\t}\n\tfor idx, tensor := range originResults {\n\t\tinput, err := builder.getOrCreatePlacedTensor(tensor, &privatePlacement{partyCode: partyCode})\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"prepareResultForParty: %w\", err)\n\t\t}\n\t\tinputs = append(inputs, input)\n\n\t\toutput := builder.tm.CreateResultTensor(input, resultNames[idx])\n\t\toutputs = append(outputs, output)\n\t}\n\treturn\n}\n\n// buildGraph constructs the ExecutionGraph represented as a graph structure.\n// It organizes ExecutionNodes into pipelines and establishes tensor flow relationships between nodes.\nfunc (builder *ExecutionGraphBuilder) buildGraph() (*graph.Graph, error) {\n\tplan := &graph.Graph{\n\t\tPipelines: make([]*graph.Pipeline, 0),\n\t\tPartyInfo: builder.info.GetPartyInfo(),\n\t}\n\n\ttensorUsers := make(map[int][]*graph.ExecutionNode)\n\ttensorSource := make(map[int]*graph.ExecutionNode)\n\ttensorId2Tensor := make(map[int]*graph.Tensor)\n\n\tfor _, pipelineNode := range builder.pipelineEngineNodes {\n\t\tgraphPipeline := &graph.Pipeline{Nodes: make(map[*graph.ExecutionNode]bool), Batched: pipelineNode.Batched}\n\t\t// 1. create node\n\t\tfor _, node := range pipelineNode.ExecutionNodes {\n\t\t\tnode.ID = plan.NodeCnt\n\t\t\tnode.Edges = make(map[*graph.Edge]bool)\n\t\t\tgraphPipeline.Nodes[node] = true\n\t\t\tplan.NodeCnt++\n\t\t}\n\t\t// 2. create edge\n\t\t// 2.1 collect tensor source and users\n\t\tfor node := range graphPipeline.Nodes {\n\t\t\tfor _, ts := range node.Inputs {\n\t\t\t\tfor _, t := range ts {\n\t\t\t\t\ttensorId2Tensor[t.ID] = t\n\t\t\t\t\t_, ok := tensorUsers[t.ID]\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\ttensorUsers[t.ID] = make([]*graph.ExecutionNode, 0)\n\t\t\t\t\t}\n\t\t\t\t\ttensorUsers[t.ID] = append(tensorUsers[t.ID], node)\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, ts := range node.Outputs {\n\t\t\t\tfor _, t := range ts {\n\t\t\t\t\ttensorId2Tensor[t.ID] = t\n\t\t\t\t\tif sourceNode, ok := tensorSource[t.ID]; ok {\n\t\t\t\t\t\tif sourceNode != node {\n\t\t\t\t\t\t\treturn nil, fmt.Errorf(\"buildGraph: find more than one source for tensor %d, source node %s, current node %s\", t.ID, sourceNode.Name, node.Name)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttensorSource[t.ID] = node\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tplan.Pipelines = append(plan.Pipelines, graphPipeline)\n\t}\n\n\t// 2.2 create edge and set nodes' output edges\n\tfor k, v := range tensorId2Tensor {\n\t\tfor _, user := range tensorUsers[k] {\n\t\t\tedge := &graph.Edge{\n\t\t\t\tFrom:  tensorSource[k],\n\t\t\t\tTo:    user,\n\t\t\t\tValue: v,\n\t\t\t}\n\t\t\ttensorSource[k].Edges[edge] = true\n\t\t}\n\t}\n\n\tplan.OutputNames = builder.outputNames\n\n\t// for batched pipeline\n\tif builder.IsBatched() {\n\t\tbuilder.fillPipeline(plan, tensorId2Tensor)\n\t}\n\n\treturn plan, nil\n}\n\n// fillPipeline determines input/output tensors for each pipeline by analyzing tensor flow across pipelines.\n// It identifies tensors created in one pipeline but consumed by downstream pipelines to set pipeline boundaries.\nfunc (builder *ExecutionGraphBuilder) fillPipeline(plan *graph.Graph, idToTensor map[int]*graph.Tensor) {\n\tvar pipelineCreatedTensors []map[int]bool\n\tfor _, pipeline := range plan.Pipelines {\n\t\tcurPipeOutputTensor := make(map[int]bool)\n\t\tcurPipeInputTensor := make(map[int]bool)\n\t\tfor node := range pipeline.Nodes {\n\t\t\tfor _, ts := range node.Inputs {\n\t\t\t\tfor _, t := range ts {\n\t\t\t\t\t// TODO: Support share tensors\n\t\t\t\t\tif t.Status() != proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\t\t\t\t\tpipeline.Batched = false\n\t\t\t\t\t}\n\t\t\t\t\tcurPipeInputTensor[t.ID] = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, ts := range node.Outputs {\n\t\t\t\tfor _, t := range ts {\n\t\t\t\t\t// TODO: Support share tensors\n\t\t\t\t\tif t.Status() != proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\t\t\t\t\tpipeline.Batched = false\n\t\t\t\t\t}\n\t\t\t\t\tcurPipeOutputTensor[t.ID] = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvar pipelineInputTs []*graph.Tensor\n\t\tfor tid := range curPipeInputTensor {\n\t\t\tif _, ok := curPipeOutputTensor[tid]; !ok {\n\t\t\t\ttmpT := idToTensor[tid]\n\t\t\t\tpipelineInputTs = append(pipelineInputTs, tmpT)\n\t\t\t}\n\t\t}\n\t\t// sort to be determinism\n\t\tsort.Slice(pipelineInputTs, func(i, j int) bool { return pipelineInputTs[i].ID < pipelineInputTs[j].ID })\n\t\tpipeline.InputTensors = pipelineInputTs\n\t\tpipelineCreatedTensors = append(pipelineCreatedTensors, curPipeOutputTensor)\n\t}\n\n\t// choose tensor created by current pipeline but consumed by downstream pipeline as current pipeline's output tensors\n\tfor i, outputTensors := range pipelineCreatedTensors {\n\t\tpipelineOutputTensors := make(map[int]*graph.Tensor, 0)\n\t\tfor j := i + 1; j < len(plan.Pipelines); j++ {\n\t\t\tfor _, t := range plan.Pipelines[j].InputTensors {\n\t\t\t\tif _, ok := outputTensors[t.ID]; ok {\n\t\t\t\t\tpipelineOutputTensors[t.ID] = t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor _, t := range pipelineOutputTensors {\n\t\t\tplan.Pipelines[i].OutputTensors = append(plan.Pipelines[i].OutputTensors, t)\n\t\t}\n\t\t// sort to be determinism\n\t\tsort.Slice(plan.Pipelines[i].OutputTensors, func(m, n int) bool {\n\t\t\treturn plan.Pipelines[i].OutputTensors[m].ID < plan.Pipelines[i].OutputTensors[n].ID\n\t\t})\n\t}\n}\n\nfunc (builder *ExecutionGraphBuilder) getLastPipelineOperator() *PipelineExecNode {\n\treturn builder.pipelineEngineNodes[len(builder.pipelineEngineNodes)-1]\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/execution_graph_builder_ops.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"encoding/base64\"\n\t\"fmt\"\n\n\t\"github.com/apache/arrow/go/v17/arrow/compute\"\n\t\"github.com/apache/arrow/go/v17/arrow/memory\"\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\nfunc (builder *ExecutionGraphBuilder) addOpRunSQL(outs []*graph.Tensor, sourceParty string, sql string, tableRefs []string) error {\n\tattrs := map[string]*graph.Attribute{\n\t\toperator.SqlAttr:       graph.NewStringAttr(sql),\n\t\toperator.TableRefsAttr: graph.NewStringsAttr(tableRefs),\n\t}\n\treturn builder.addEngineNode(\"run_sql\", operator.OpNameRunSQL, nil, map[string][]*graph.Tensor{\"Out\": outs}, attrs, []string{sourceParty})\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpSecretJoin(leftKeys, rightKeys, leftPayloads, rightPayloads, leftOutputs, rightOutputs []*graph.Tensor) error {\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"LeftKey\":  leftKeys,\n\t\t\"RightKey\": rightKeys,\n\t\t\"Left\":     leftPayloads,\n\t\t\"Right\":    rightPayloads,\n\t}\n\toutputs := map[string][]*graph.Tensor{\n\t\t\"LeftOutput\":  leftOutputs,\n\t\t\"RightOutput\": rightOutputs,\n\t}\n\treturn builder.addEngineNode(\"secret_eq_join\", operator.OpNameSecretJoin, inputs, outputs, nil, builder.GetAllParties())\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpPsiJoin(left, right []*graph.Tensor, leftIndex, rightIndex *graph.Tensor, partyCodes []string, joinType int, psiAlg proto.PsiAlgorithmType) error {\n\tattrs := map[string]*graph.Attribute{\n\t\toperator.InputPartyCodesAttr: graph.NewStringsAttr(partyCodes),\n\t\toperator.JoinTypeAttr:        graph.NewInt64Attr(int64(joinType)),\n\t\toperator.PsiAlgorithmAttr:    graph.NewInt64Attr(int64(psiAlg)),\n\t}\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"Left\":  left,\n\t\t\"Right\": right,\n\t}\n\toutputs := map[string][]*graph.Tensor{\n\t\t\"LeftJoinIndex\":  nil,\n\t\t\"RightJoinIndex\": nil,\n\t}\n\tif leftIndex != nil {\n\t\toutputs[\"LeftJoinIndex\"] = []*graph.Tensor{leftIndex}\n\t}\n\tif rightIndex != nil {\n\t\toutputs[\"RightJoinIndex\"] = []*graph.Tensor{rightIndex}\n\t}\n\treturn builder.addEngineNode(\"psi_join\", operator.OpNameJoin, inputs, outputs, attrs, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpFilterByIndex(filter *graph.Tensor, payloads, outs []*graph.Tensor, partyCode string) error {\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"RowsIndexFilter\": {filter},\n\t\t\"Data\":            payloads,\n\t}\n\toutputs := map[string][]*graph.Tensor{\"Out\": outs}\n\treturn builder.addEngineNode(\"filter_by_index\", operator.OpNameFilterByIndex, inputs, outputs, nil, []string{partyCode})\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpReduce(aggName string, in, out *graph.Tensor, attrs map[string]*graph.Attribute) error {\n\topType, ok := operator.ReduceAggOp[aggName]\n\tif !ok {\n\t\treturn fmt.Errorf(\"addOpReduce: %s is not supported\", aggName)\n\t}\n\n\tpartyCodes := builder.GetAllParties()\n\tif in.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\tpartyCodes = []string{in.OwnerPartyCode}\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\"In\": {in}}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {out}}\n\n\treturn builder.addEngineNode(\"reduce[\"+aggName+\"]\", opType, inputs, outputs, attrs, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpUnique(in, out *graph.Tensor) error {\n\tinputs := map[string][]*graph.Tensor{\"Key\": {in}}\n\toutputs := map[string][]*graph.Tensor{\"UniqueKey\": {out}}\n\treturn builder.addEngineNode(\"unique\", operator.OpNameUnique, inputs, outputs, nil, []string{in.OwnerPartyCode})\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpSort(keys, payloads, outs []*graph.Tensor, directions []bool) error {\n\tif len(keys) != len(directions) {\n\t\treturn fmt.Errorf(\"addOpSort: keys length %d not match directions length %d\", len(keys), len(directions))\n\t}\n\tpartyCodes := builder.GetAllParties()\n\tif keys[0].Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\tpartyCodes = []string{keys[0].OwnerPartyCode}\n\t}\n\n\tattrs := map[string]*graph.Attribute{operator.ReverseAttr: graph.NewBoolsAttr(directions)}\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"Key\": keys,\n\t\t\"In\":  payloads,\n\t}\n\toutputs := map[string][]*graph.Tensor{\"Out\": outs}\n\n\treturn builder.addEngineNode(\"sort\", operator.OpNameSort, inputs, outputs, attrs, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpObliviousGroupMark(keys []*graph.Tensor, out *graph.Tensor) error {\n\tinputs := map[string][]*graph.Tensor{\"Key\": keys}\n\toutputs := map[string][]*graph.Tensor{\"Group\": {out}}\n\treturn builder.addEngineNode(\"oblivious_group_mark\", operator.OpNameObliviousGroupMark, inputs, outputs, nil, builder.GetAllParties())\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpShape(in, out *graph.Tensor) error {\n\tinputs := map[string][]*graph.Tensor{\"In\": {in}}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {out}}\n\tattrs := map[string]*graph.Attribute{operator.AxisAttr: graph.NewInt64Attr(0)}\n\treturn builder.addEngineNode(\"shape\", operator.OpNameShape, inputs, outputs, attrs, []string{out.OwnerPartyCode})\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpBroadcastTo(shapeRef *graph.Tensor, in, out []*graph.Tensor) error {\n\tpartyCodes := builder.GetAllParties()\n\tif shapeRef.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\tpartyCodes = []string{shapeRef.OwnerPartyCode}\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"ShapeRefTensor\": {shapeRef},\n\t\t\"In\":             in,\n\t}\n\toutputs := map[string][]*graph.Tensor{\"Out\": out}\n\n\treturn builder.addEngineNode(\"broadcast_to\", operator.OpNameBroadcastTo, inputs, outputs, nil, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpPrivateGroup(keys []*graph.Tensor, groupId, groupNum *graph.Tensor, partyCode string) error {\n\tinputs := map[string][]*graph.Tensor{\"Key\": keys}\n\toutputs := map[string][]*graph.Tensor{\n\t\t\"GroupId\":  {groupId},\n\t\t\"GroupNum\": {groupNum},\n\t}\n\treturn builder.addEngineNode(\"private_group\", operator.OpNameGroup, inputs, outputs, nil, []string{partyCode})\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpPrivateGroupAgg(name string, opType string, groupId, groupNum *graph.Tensor, ins, outs []*graph.Tensor, attrs map[string]*graph.Attribute, partyCode string) error {\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"GroupId\":  {groupId},\n\t\t\"GroupNum\": {groupNum},\n\t\t\"In\":       ins,\n\t}\n\toutputs := map[string][]*graph.Tensor{\"Out\": outs}\n\n\treturn builder.addEngineNode(name, opType, inputs, outputs, attrs, []string{partyCode})\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpGroupSecretAgg(funcName string, groupId, groupNum, in, out *graph.Tensor) error {\n\topName, ok := operator.GroupSecretAggOp[funcName]\n\tif !ok {\n\t\treturn fmt.Errorf(\"addOpGroupSecretAgg: unsupported funcName %s\", funcName)\n\t}\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"GroupId\":  {groupId},\n\t\t\"GroupNum\": {groupNum},\n\t\t\"In\":       {in},\n\t}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {out}}\n\n\treturn builder.addEngineNode(fmt.Sprintf(\"private_group_secret_%s\", funcName), opName, inputs, outputs, nil, builder.GetAllParties())\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpShuffle(ins, outs []*graph.Tensor) error {\n\tinputs := map[string][]*graph.Tensor{\"In\": ins}\n\toutputs := map[string][]*graph.Tensor{\"Out\": outs}\n\treturn builder.addEngineNode(\"shuffle\", operator.OpNameShuffle, inputs, outputs, nil, builder.GetAllParties())\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpObliviousGroupAgg(funcName string, group, in, out *graph.Tensor, attrs map[string]*graph.Attribute) error {\n\topName, ok := operator.ObliviousGroupAggOp[funcName]\n\tif !ok {\n\t\treturn fmt.Errorf(\"addOpObliviousGroupAgg: unsupported funcName %s\", funcName)\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\"Group\": {group}, \"In\": {in}}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {out}}\n\n\treturn builder.addEngineNode(funcName, opName, inputs, outputs, attrs, builder.GetAllParties())\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpFilter(mask *graph.Tensor, ins, outs []*graph.Tensor, partyCodes []string) error {\n\tinputs := map[string][]*graph.Tensor{\"Filter\": {mask}, \"In\": ins}\n\toutputs := map[string][]*graph.Tensor{\"Out\": outs}\n\treturn builder.addEngineNode(\"filter\", operator.OpNameFilter, inputs, outputs, nil, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpReplicate(leftinputs, rightinputs, leftoutputs, rightoutputs []*graph.Tensor, partyCodes []string) error {\n\tattrs := map[string]*graph.Attribute{operator.InputPartyCodesAttr: graph.NewStringsAttr(partyCodes)}\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"Left\":  leftinputs,\n\t\t\"Right\": rightinputs,\n\t}\n\toutputs := map[string][]*graph.Tensor{\n\t\t\"LeftOut\":  leftoutputs,\n\t\t\"RightOut\": rightoutputs,\n\t}\n\treturn builder.addEngineNode(\"replicate\", operator.OpNameReplicate, inputs, outputs, attrs, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpLimit(ins, outs []*graph.Tensor, offset, count int64, partyCodes []string) error {\n\tattrs := map[string]*graph.Attribute{\n\t\toperator.LimitOffsetAttr: graph.NewInt64Attr(offset),\n\t\toperator.LimitCountAttr:  graph.NewInt64Attr(count),\n\t}\n\tinputs := map[string][]*graph.Tensor{\"In\": ins}\n\toutputs := map[string][]*graph.Tensor{\"Out\": outs}\n\treturn builder.addEngineNode(\"limit\", operator.OpNameLimit, inputs, outputs, attrs, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpConcat(ins []*graph.Tensor, out *graph.Tensor) error {\n\tinputs := map[string][]*graph.Tensor{\"In\": ins}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {out}}\n\treturn builder.addEngineNode(\"concat\", operator.OpNameConcat, inputs, outputs, nil, builder.GetAllParties())\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpConstant(value *types.Datum, out *graph.Tensor) error {\n\tvalueAttr := &graph.Attribute{}\n\tswitch value.Kind() {\n\tcase types.KindFloat32:\n\t\tvalueAttr.SetFloat(float32(value.GetFloat64()))\n\tcase types.KindFloat64:\n\t\tvalueAttr.SetDouble(value.GetFloat64())\n\tcase types.KindInt64:\n\t\tvalueAttr.SetInt64(value.GetInt64())\n\tcase types.KindMysqlDecimal:\n\t\t// NOTE(shunde.csd): SCQL Internal does not distinguish decimal and float,\n\t\t// It handles decimal as float.\n\t\t// If users have requirements for precision, they should use integers.\n\t\tv, err := value.GetMysqlDecimal().ToFloat64()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"addOpConstant: convert decimal to float error: %v\", err)\n\t\t}\n\t\tvalueAttr.SetDouble(v)\n\tcase types.KindString:\n\t\tvalueAttr.SetString(value.GetString())\n\tcase types.KindMysqlTime:\n\t\ttime := value.GetMysqlTime()\n\t\ttimestamp := time.CoreTime().ToUnixTimestamp()\n\t\tvalueAttr.SetInt64(timestamp)\n\tdefault:\n\t\treturn fmt.Errorf(\"addOpConstant: unsupported data{%+v}\", value)\n\t}\n\tattrs := map[string]*graph.Attribute{\n\t\toperator.ScalarAttr:   valueAttr,\n\t\toperator.ToStatusAttr: graph.NewInt64Attr(1), // public\n\t}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {out}}\n\treturn builder.addEngineNode(\"constant\", operator.OpNameConstant, nil, outputs, attrs, builder.GetAllParties())\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpIn(left, right, out *graph.Tensor, psiAlg proto.PsiAlgorithmType) error {\n\tpartyCodes := []string{left.OwnerPartyCode, right.OwnerPartyCode}\n\n\tattrs := map[string]*graph.Attribute{\n\t\toperator.PsiAlgorithmAttr:    graph.NewInt64Attr(int64(psiAlg)),\n\t\toperator.InputPartyCodesAttr: graph.NewStringsAttr([]string{left.OwnerPartyCode, right.OwnerPartyCode}),\n\t\toperator.RevealToAttr:        graph.NewStringsAttr([]string{out.OwnerPartyCode}),\n\t}\n\tif left.OwnerPartyCode == right.OwnerPartyCode {\n\t\tattrs[operator.InTypeAttr] = graph.NewInt64Attr(operator.LocalIn)\n\t\tpartyCodes = []string{left.OwnerPartyCode}\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\n\t\tgraph.Left:  {left},\n\t\tgraph.Right: {right},\n\t}\n\toutputs := map[string][]*graph.Tensor{graph.Out: {out}}\n\n\treturn builder.addEngineNode(\"in\", operator.OpNameIn, inputs, outputs, attrs, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpArrowFunc(funcName string, funcOpt compute.FunctionOptions, ins []*graph.Tensor, out *graph.Tensor) error {\n\tattrs := map[string]*graph.Attribute{\n\t\toperator.FuncNameAttr: graph.NewStringAttr(funcName),\n\t}\n\tif funcOpt != nil {\n\t\tattrs[operator.FuncOptTypeAttr] = graph.NewStringAttr(funcOpt.TypeName())\n\n\t\tbuf, err := compute.SerializeOptions(funcOpt, memory.DefaultAllocator)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"addOpArrowFunc: serialize func options failed: %v\", err)\n\t\t}\n\t\t// encode to base64, attribute not support bytes yet.\n\t\tattrs[operator.FuncOptAttr] = graph.NewStringAttr(base64.StdEncoding.EncodeToString(buf.Bytes()))\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\"In\": ins}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {out}}\n\tnodeName := \"arrow_func[\" + funcName + \"]\"\n\n\treturn builder.addEngineNode(nodeName, operator.OpNameArrowFunc, inputs, outputs, attrs, []string{out.OwnerPartyCode})\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpBasicFunc(funcName string, ins []*graph.Tensor, output *graph.Tensor) error {\n\topName, ok := astName2NodeName[funcName]\n\tif !ok {\n\t\treturn fmt.Errorf(\"addOpBasicFunc: unsupported func name: %s\", funcName)\n\t}\n\n\tpartyCodes := builder.GetAllParties()\n\tif output.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\tpartyCodes = []string{output.OwnerPartyCode}\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\"In\": ins}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {output}}\n\n\treturn builder.addEngineNode(opName, opName, inputs, outputs, nil, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpBinaryFunc(funcName string, left *graph.Tensor, right *graph.Tensor, output *graph.Tensor) error {\n\topName, ok := astName2NodeName[funcName]\n\tif !ok {\n\t\treturn fmt.Errorf(\"addOpBinaryFunc: unsupported func name: %s\", funcName)\n\t}\n\n\tpartyCodes := builder.GetAllParties()\n\tif output.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\tpartyCodes = []string{output.OwnerPartyCode}\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\"Left\": {left}, \"Right\": {right}}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {output}}\n\n\treturn builder.addEngineNode(opName, opName, inputs, outputs, nil, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpIf(cond, valueTrue, valueFalse, output *graph.Tensor) error {\n\tpartyCodes := builder.GetAllParties()\n\tif output.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\tpartyCodes = []string{output.OwnerPartyCode}\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"Condition\":    {cond},\n\t\t\"ValueIfTrue\":  {valueTrue},\n\t\t\"ValueIfFalse\": {valueFalse},\n\t}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {output}}\n\n\treturn builder.addEngineNode(\"if\", operator.OpNameIf, inputs, outputs, nil, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpCaseWhen(conds, values []*graph.Tensor, valueElse, output *graph.Tensor) error {\n\tpartyCodes := builder.GetAllParties()\n\tif output.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\tpartyCodes = []string{output.OwnerPartyCode}\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"Condition\": conds,\n\t\t\"Value\":     values,\n\t\t\"ValueElse\": {valueElse},\n\t}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {output}}\n\n\treturn builder.addEngineNode(\"case_when\", operator.OpNameCaseWhen, inputs, outputs, nil, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpIfNull(expr, altValue, output *graph.Tensor) error {\n\tpartyCodes := builder.GetAllParties()\n\tif output.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\tpartyCodes = []string{output.OwnerPartyCode}\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\"Expr\": {expr}, \"AltValue\": {altValue}}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {output}}\n\n\treturn builder.addEngineNode(\"if_null\", operator.OpNameIfNull, inputs, outputs, nil, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpCoalece(exprs []*graph.Tensor, output *graph.Tensor) error {\n\tpartyCodes := builder.GetAllParties()\n\tif output.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\tpartyCodes = []string{output.OwnerPartyCode}\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\"Exprs\": exprs}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {output}}\n\n\treturn builder.addEngineNode(\"coalesce\", operator.OpNameCoalesce, inputs, outputs, nil, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpPrivateWindow(funcName string, keys []*graph.Tensor, partitionId, partitionNum *graph.Tensor, output *graph.Tensor, orderDescs []string) error {\n\tvar opName string\n\tswitch funcName {\n\tcase ast.WindowFuncRowNumber:\n\t\topName = operator.OpNameRowNumber\n\tcase ast.WindowFuncRank:\n\t\topName = operator.OpNameRank\n\tcase ast.WindowFuncPercentRank:\n\t\topName = operator.OpNamePercentRank\n\tdefault:\n\t\treturn fmt.Errorf(\"addOpPrivateWindow: unsupported func name: %s\", funcName)\n\t}\n\n\tattrs := map[string]*graph.Attribute{operator.ReverseAttr: graph.NewStringsAttr(orderDescs)}\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"Key\":          keys,\n\t\t\"PartitionId\":  {partitionId},\n\t\t\"PartitionNum\": {partitionNum},\n\t}\n\toutputs := map[string][]*graph.Tensor{\"Out\": {output}}\n\n\treturn builder.addEngineNode(opName, opName, inputs, outputs, attrs, []string{output.OwnerPartyCode})\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpPublish(results, outs []*graph.Tensor, partyCode string) error {\n\tfor _, out := range outs {\n\t\tbuilder.outputNames = append(builder.outputNames, out.Name)\n\t}\n\n\tinputs := map[string][]*graph.Tensor{\"In\": results}\n\toutputs := map[string][]*graph.Tensor{\"Out\": outs}\n\treturn builder.addEngineNode(\"publish_result\", operator.OpNamePublish, inputs, outputs, nil, []string{partyCode})\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpBucket(keys, ins, outs []*graph.Tensor, partyCodes []string) error {\n\tattrs := map[string]*graph.Attribute{operator.InputPartyCodesAttr: graph.NewStringsAttr(partyCodes)}\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"Key\": keys,\n\t\t\"In\":  ins,\n\t}\n\toutputs := map[string][]*graph.Tensor{\"Out\": outs}\n\treturn builder.addEngineNode(\"bucket\", operator.OpNameBucket, inputs, outputs, attrs, partyCodes)\n}\n\nfunc (builder *ExecutionGraphBuilder) addOpInsertTable(results, outs []*graph.Tensor, partyCode string, opt *core.InsertTableOption) error {\n\tattrs := map[string]*graph.Attribute{\n\t\toperator.TableNameAttr:   graph.NewStringAttr(opt.TableName),\n\t\toperator.ColumnNamesAttr: graph.NewStringsAttr(opt.Columns),\n\t}\n\tinputs := map[string][]*graph.Tensor{\"In\": results}\n\toutputs := map[string][]*graph.Tensor{\"Out\": outs}\n\treturn builder.addEngineNode(\"insert_table\", operator.OpNameInsertTable, inputs, outputs, attrs, []string{partyCode})\n}\n\n// refer to Arrow QuotingStyle: https://github.com/apache/arrow/blob/apache-arrow-14.0.0/cpp/src/arrow/csv/options.h#L174\nconst (\n\t_quotingNone     int64 = 0\n\t_quotingNeeded   int64 = 1\n\t_quotingAllValid int64 = 2\n)\n\nfunc (builder *ExecutionGraphBuilder) addOpDumpFile(ins, outs []*graph.Tensor, intoOpt *ast.SelectIntoOption, partyFile *ast.PartyFile) error {\n\tqsAttr := &graph.Attribute{}\n\tif intoOpt.FieldsInfo.Enclosed == 0 {\n\t\tqsAttr.SetInt64(_quotingNone) // default no quotes\n\t} else {\n\t\t// Limitations from Arrow CSV Writer C++ API: only support (ENCLOSED BY '\"') and not support (ESCAPED BY) option\n\t\t// refer to: https://github.com/apache/arrow/blob/apache-arrow-14.0.0/cpp/src/arrow/csv/options.h#L187\n\t\tif intoOpt.FieldsInfo.Enclosed != '\"' {\n\t\t\treturn fmt.Errorf(\"AddDumpFileNode: only support \\\", not support: %v\", intoOpt.FieldsInfo.Enclosed)\n\t\t}\n\t\tlogrus.Warn(\"not support 'ESCAPED BY' Option, default ignored\")\n\n\t\tif intoOpt.FieldsInfo.OptEnclosed {\n\t\t\tqsAttr.SetInt64(_quotingNeeded) // optionally enclosed valid string data\n\t\t} else {\n\t\t\tqsAttr.SetInt64(_quotingAllValid) // enclosed all valid data\n\t\t}\n\t}\n\n\tattrs := map[string]*graph.Attribute{\n\t\toperator.FilePathAttr:         graph.NewStringAttr(partyFile.FileName),\n\t\toperator.LineTerminatorAttr:   graph.NewStringAttr(intoOpt.LinesInfo.Terminated),\n\t\toperator.FieldDeliminatorAttr: graph.NewStringAttr(intoOpt.FieldsInfo.Terminated),\n\t\toperator.QuotingStyleAttr:     qsAttr,\n\t}\n\tinputs := map[string][]*graph.Tensor{\"In\": ins}\n\toutputs := map[string][]*graph.Tensor{\"Out\": outs}\n\treturn builder.addEngineNode(\"dump_file\", operator.OpNameDumpFile, inputs, outputs, attrs, []string{partyFile.PartyCode})\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/execution_graph_builder_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n)\n\nfunc createTestHelp() (*ExecutionGraphBuilder, func(string, proto.PrimitiveDataType, tensorPlacement, []string) (*TensorMeta, *graph.Tensor)) {\n\ttmm := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\tinfo := &graph.EnginesInfo{}\n\n\tbuilder := NewExecutionGraphBuilder(tmm, srm, vt, info, &v1.CompileOptions{Batched: false})\n\n\tcreatePlacedTensor := func(name string, dtype proto.PrimitiveDataType, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := builder.tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tbuilder.vt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := builder.tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\treturn builder, createPlacedTensor\n}\n\nfunc TestExecutionGraphBuilderBasicMethods(t *testing.T) {\n\tr := require.New(t)\n\n\ttmm := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\tinfo := &graph.EnginesInfo{}\n\n\tbuilder := NewExecutionGraphBuilder(tmm, srm, vt, info, &v1.CompileOptions{Batched: false})\n\n\t// Test GetAllParties\n\tparties := builder.GetAllParties()\n\tr.Equal([]string{\"alice\", \"bob\", \"carol\"}, parties)\n\n\t// Test SetBatched and IsBatched\n\tr.False(builder.IsBatched())\n\tbuilder.SetBatched(true)\n\tr.True(builder.IsBatched())\n\tbuilder.SetBatched(false)\n\tr.False(builder.IsBatched())\n\n\t// Test TensorManager\n\tr.Equal(builder.tm, builder.TensorManager())\n}\n\nfunc TestAddEngineNode(t *testing.T) {\n\tr := require.New(t)\n\n\tbuilder, createPlacedTensor := createTestHelp()\n\n\t// Create test tensors\n\t_, inputTensor1 := createPlacedTensor(\"test_input1\", proto.PrimitiveDataType_INT64, &secretPlacement{}, []string{})\n\t_, inputTensor2 := createPlacedTensor(\"test_input2\", proto.PrimitiveDataType_INT64, &secretPlacement{}, []string{})\n\t_, outputTensor := createPlacedTensor(\"test_output\", proto.PrimitiveDataType_INT64, &secretPlacement{}, []string{})\n\n\tinputs := map[string][]*graph.Tensor{\n\t\t\"Left\":  {inputTensor1},\n\t\t\"Right\": {inputTensor2},\n\t}\n\toutputs := map[string][]*graph.Tensor{\n\t\t\"Out\": {outputTensor},\n\t}\n\tattributes := make(map[string]*graph.Attribute)\n\tpartyCodes := builder.GetAllParties()\n\n\t// Test adding a valid operation\n\terr := builder.addEngineNode(\"node_name\", operator.OpNameAdd, inputs, outputs, attributes, partyCodes)\n\tr.NoError(err)\n\tr.Len(builder.pipelineEngineNodes, 1)\n\tr.Len(builder.pipelineEngineNodes[0].ExecutionNodes, 1)\n\tr.Equal(\"node_name\", builder.pipelineEngineNodes[0].ExecutionNodes[0].Name)\n\tr.Equal(operator.OpNameAdd, builder.pipelineEngineNodes[0].ExecutionNodes[0].OpType)\n\n\t// Test adding an invalid operation\n\terr = builder.addEngineNode(\"node_name2\", \"invalid_op\", inputs, outputs, attributes, partyCodes)\n\tr.Error(err)\n\tr.Contains(err.Error(), \"failed to find opType\")\n}\n\nfunc TestBuildGraph(t *testing.T) {\n\tr := require.New(t)\n\n\tbuilder, createPlacedTensor := createTestHelp()\n\n\t// Create tensors\n\t_, tensor1 := createPlacedTensor(\"tensor1\", proto.PrimitiveDataType_INT64, &privatePlacement{partyCode: \"alice\"}, []string{})\n\t_, tensor2 := createPlacedTensor(\"tensor2\", proto.PrimitiveDataType_INT64, &privatePlacement{partyCode: \"alice\"}, []string{})\n\t_, tensor3 := createPlacedTensor(\"tensor3\", proto.PrimitiveDataType_INT64, &privatePlacement{partyCode: \"alice\"}, []string{})\n\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + 1\n\n\t// For test here, we only fill the input and output tensors, the attributes are empty\n\t// Add RunSQL node\n\terr := builder.addEngineNode(\"runsql\", operator.OpNameRunSQL,\n\t\tmap[string][]*graph.Tensor{},\n\t\tmap[string][]*graph.Tensor{\"Out\": {tensor1}},\n\t\tmake(map[string]*graph.Attribute),\n\t\tbuilder.GetAllParties())\n\tr.NoError(err)\n\n\t// Add Sort node\n\terr = builder.addEngineNode(\"sort\", operator.OpNameSort,\n\t\tmap[string][]*graph.Tensor{\"In\": {tensor1}, \"Key\": {tensor1}},\n\t\tmap[string][]*graph.Tensor{\"Out\": {tensor2}},\n\t\tmake(map[string]*graph.Attribute),\n\t\tbuilder.GetAllParties())\n\tr.NoError(err)\n\n\t// Add Limit node\n\terr = builder.addEngineNode(\"limit\", operator.OpNameLimit,\n\t\tmap[string][]*graph.Tensor{\"In\": {tensor2}},\n\t\tmap[string][]*graph.Tensor{\"Out\": {tensor3}},\n\t\tmake(map[string]*graph.Attribute),\n\t\tbuilder.GetAllParties())\n\tr.NoError(err)\n\n\t// Verify pipeline is properly populated\n\tr.Len(builder.pipelineEngineNodes, 1)\n\tr.Len(builder.pipelineEngineNodes[0].ExecutionNodes, 3)\n\n\t// Build the graph\n\tg, err := builder.buildGraph()\n\tr.NoError(err)\n\tr.NotNil(g)\n\tr.Len(g.Pipelines, 1)\n\tr.Equal(3, g.NodeCnt)\n\tr.Len(g.Pipelines[0].Nodes, 3)\n}\n\nfunc TestPrepareResultForParty(t *testing.T) {\n\tr := require.New(t)\n\n\tbuilder, createPlacedTensor := createTestHelp()\n\n\t// Create test tensors\n\tut1, _ := createPlacedTensor(\"result1\", proto.PrimitiveDataType_INT64, &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\tut2, _ := createPlacedTensor(\"result2\", proto.PrimitiveDataType_STRING, &privatePlacement{partyCode: \"bob\"}, []string{\"alice\", \"bob\"})\n\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + 1\n\n\toriginResults := []*TensorMeta{\n\t\tut1,\n\t\tut2,\n\t}\n\tresultNames := []string{\"count\", \"id\"}\n\tpartyCode := \"alice\"\n\n\t// Test prepareResultForParty\n\tinputs, outputs, err := builder.prepareResultForParty(originResults, resultNames, partyCode)\n\tr.NoError(err)\n\tr.Len(inputs, 2)\n\tr.Len(outputs, 2)\n\tr.Equal(\"count\", outputs[0].Name)\n\tr.Equal(\"id\", outputs[1].Name)\n\tr.Equal(proto.PrimitiveDataType_STRING, outputs[0].DType.DType)\n\tr.Equal(proto.PrimitiveDataType_STRING, outputs[1].DType.DType)\n}\n\nfunc TestPrepareResultForPartyLengthMismatch(t *testing.T) {\n\tr := require.New(t)\n\n\tbuilder, createPlacedTensor := createTestHelp()\n\n\tmeta, _ := createPlacedTensor(\"result1\", proto.PrimitiveDataType_INT64, &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + 1\n\n\toriginResults := []*TensorMeta{\n\t\tmeta,\n\t}\n\tresultNames := []string{\"count\", \"id\"} // Length mismatch\n\tpartyCode := \"alice\"\n\n\t// Test prepareResultForParty with length mismatch\n\tinputs, outputs, err := builder.prepareResultForParty(originResults, resultNames, partyCode)\n\tr.Error(err)\n\tr.Contains(err.Error(), \"length\")\n\tr.Nil(inputs)\n\tr.Nil(outputs)\n}\n\nfunc TestPrepareResultForPartyInvisible(t *testing.T) {\n\tr := require.New(t)\n\n\tbuilder, createPlacedTensor := createTestHelp()\n\n\t// Create tensors with visibility that doesn't include the target party\n\tut1, _ := createPlacedTensor(\"result1\", proto.PrimitiveDataType_INT64, &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\tut2, _ := createPlacedTensor(\"result2\", proto.PrimitiveDataType_STRING, &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + 1\n\n\toriginResults := []*TensorMeta{\n\t\tut1,\n\t\tut2,\n\t}\n\tresultNames := []string{\"count\", \"id\"}\n\tpartyCode := \"alice\" // alice is not in the visibility of bob or carol's tensors\n\n\t// Test prepareResultForParty with visibility mismatch\n\tinputs, outputs, err := builder.prepareResultForParty(originResults, resultNames, partyCode)\n\tr.Error(err)\n\tr.Contains(err.Error(), \"prepareResultForParty\")\n\tr.Nil(inputs)\n\tr.Nil(outputs)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/execution_graph_pass.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// ExecutionGraphPass builds execution graph from operator graph\ntype ExecutionGraphPass struct{}\n\n// NewExecutionGraphPass creates a new execution graph pass\nfunc NewExecutionGraphPass() *ExecutionGraphPass {\n\treturn &ExecutionGraphPass{}\n}\n\n// Name returns the pass name\nfunc (p *ExecutionGraphPass) Name() string {\n\treturn \"ExecutionGraphPass\"\n}\n\n// Run builds execution graph\nfunc (p *ExecutionGraphPass) Run(c *CompileContext) error {\n\t// Build execution graph from operator graph\n\texecutionGraphBuilder := NewExecutionGraphBuilder(\n\t\tc.TensorMetaManager,\n\t\tc.SecurityRelaxationManager,\n\t\tc.VisibilityTable,\n\t\tc.EnginesInfo,\n\t\tc.Request.GetCompileOpts(),\n\t)\n\texecutionGraph, err := executionGraphBuilder.Build(c.OperatorGraph)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build execution graph: %v\", err)\n\t}\n\tlogrus.Debugf(\"execution graph: %s\", executionGraph.DumpGraphviz())\n\n\t// Store execution graph in context\n\tc.ExecutionGraph = executionGraph\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/inference.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\n// inferStandard implements the common inference pattern for most operators\nfunc inferStandard(vs *VisibilitySolver, n Operator) ([]*TensorMeta, error) {\n\tsnapshot := vs.outputVisSnapshot(n)\n\n\tif err := n.InferVis(vs.vt); err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, csr := range vs.srm.csrTable {\n\t\tif err := n.InferCSR(csr, vs.vt); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn vs.getUpdatedTensors(n, snapshot), nil\n}\n\nfunc (n *OperatorResult) Infer(_ *VisibilitySolver, _ bool) ([]*TensorMeta, error) {\n\t// OperatorResult is the last node in the plan, so we don't need to infer its visibility\n\treturn nil, nil\n}\n\nfunc (n *OperatorDataSource) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\tsnapshot := vs.outputVisSnapshot(n)\n\n\tif err := n.InitVis(vs.vt, vs.originalVisibility); err != nil {\n\t\treturn nil, err\n\t}\n\tfor name, csr := range vs.srm.csrTable {\n\t\tapplicableColNames, ok := vs.srm.sourceSecurityRelaxation[name]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif err := n.InitCSR(csr, applicableColNames); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn vs.getUpdatedTensors(n, snapshot), nil\n}\n\nfunc (n *OperatorRunSQL) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\tsnapshot := vs.outputVisSnapshot(n)\n\n\tif n.subGraphTracker != nil {\n\t\touterUnt := vs.consumerTracker\n\t\tvs.consumerTracker = n.subGraphTracker\n\t\tif err := vs.handleRunSQL(n); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvs.consumerTracker = outerUnt\n\t} else {\n\t\tfor _, output := range n.outputs {\n\t\t\tvs.vt.UpdateVisibility(output, NewVisibleParties([]string{n.sourceParty}))\n\t\t\t// TODO: try vs.originalVisibility\n\t\t}\n\t}\n\n\treturn vs.getUpdatedTensors(n, snapshot), nil\n}\n\nfunc (n *OperatorEQJoin) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\tsnapshot := vs.outputVisSnapshot(n)\n\n\tovt := vs.NewOverlayVisibilityTable()\n\n\tif applySecurityRelaxation {\n\t\tcsrRevealKeyAfterJoin := vs.srm.GetCSR(RevealKeyAfterJoin)\n\t\tif err := n.ApplyRevealKeyAfterJoin(ovt, csrRevealKeyAfterJoin); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif err := n.InferVis(ovt); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvs.vt.UpdateTensorsVisibilityLike(ovt, GetNodeOutputs(n))\n\n\tfor _, csr := range vs.srm.csrTable {\n\t\tif err := n.InferCSR(csr, ovt); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn vs.getUpdatedTensors(n, snapshot), nil\n}\n\nfunc (n *OperatorCrossJoin) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\treturn inferStandard(vs, n)\n}\n\nfunc (n *OperatorLimit) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\treturn inferStandard(vs, n)\n}\n\nfunc (n *OperatorFilter) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\treturn inferStandard(vs, n)\n}\n\nfunc (n *OperatorBroadcastTo) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\treturn inferStandard(vs, n)\n}\n\nfunc (n *OperatorConcat) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\treturn inferStandard(vs, n)\n}\n\nfunc (n *OperatorSort) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\treturn inferStandard(vs, n)\n}\n\nfunc (n *OperatorReduce) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\treturn inferStandard(vs, n)\n}\n\nfunc (n *OperatorGroupAgg) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\treturn inferStandard(vs, n)\n}\n\nfunc (n *OperatorWindow) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\treturn inferStandard(vs, n)\n}\n\nfunc (n *OperatorIn) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\tsnapshot := vs.outputVisSnapshot(n)\n\n\tif err := n.InferVis(vs.vt); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, csr := range vs.srm.csrTable {\n\t\tif err := n.InferCSR(csr, vs.vt); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif applySecurityRelaxation {\n\t\tcsrRevealFilterMask := vs.srm.GetCSR(RevealFilterMask)\n\t\tif err := n.ApplyRevealFilterMask(vs.vt, csrRevealFilterMask, vs.consumerTracker); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn vs.getUpdatedTensors(n, snapshot), nil\n}\n\nfunc (n *OperatorFunction) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\tsnapshot := vs.outputVisSnapshot(n)\n\n\tif err := n.InferVis(vs.vt); err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, csr := range vs.srm.csrTable {\n\t\tif err := n.InferCSR(csr, vs.vt); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// use relaxation in even in subPlan to handle selection push down\n\tcsrRevealFilterMask := vs.srm.GetCSR(RevealFilterMask)\n\tif err := n.ApplyRevealFilterMask(vs.vt, csrRevealFilterMask, vs.consumerTracker); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn vs.getUpdatedTensors(n, snapshot), nil\n}\n\nfunc (n *OperatorConstant) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\tsnapshot := vs.outputVisSnapshot(n)\n\n\tif err := n.InferVis(vs.vt); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn vs.getUpdatedTensors(n, snapshot), nil\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/inference_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\nfunc TestOperatorResultInfer(t *testing.T) {\n\tassert := assert.New(t)\n\n\tnode := &OperatorResult{}\n\tvs := &VisibilitySolver{vt: NewVisibilityTable([]string{\"alice\", \"bob\"})}\n\n\ttensors, err := node.Infer(vs, false)\n\tassert.NoError(err)\n\tassert.Nil(tensors)\n\n\t// Test with applySecurityRelaxation=true (should behave the same)\n\ttensors, err = node.Infer(vs, true)\n\tassert.NoError(err)\n\tassert.Nil(tensors)\n}\n\nfunc TestOperatorDataSourceInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{\n\t\t\"col2\": NewVisibleParties([]string{\"bob\"}),\n\t}, nil, false)\n\n\t// Test basic data source inference\n\tt1 := createTestTensor(1)\n\tt2 := createTestTensor(2)\n\tnode := &OperatorDataSource{\n\t\toutputs:     []*TensorMeta{t1, t2},\n\t\tsourceParty: \"alice\",\n\t\toriginNames: []string{\"col1\", \"col2\"},\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\n\t// Two tensors updated\n\tassert.Len(tensors, 2)\n\tassert.Contains(tensors, t1)\n\tassert.Contains(tensors, t2)\n\n\t// Verify visibility was set correctly\n\tvp1 := vs.vt.TensorVisibleParties(t1)\n\tassert.True(vp1.Contains(\"alice\"))\n\tassert.False(vp1.Contains(\"bob\"))\n\n\tvp2 := vs.vt.TensorVisibleParties(t2)\n\tassert.True(vp2.Contains(\"alice\")) // source party\n\tassert.True(vp2.Contains(\"bob\"))   // from original visibility\n}\n\nfunc TestOperatorRunSQLInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\t// Set up sub plan with OperatorDataSource and OperatorFunction\n\tt1 := createTestTensor(1)\n\tt2 := createTestTensor(2)\n\tdataSource := &OperatorDataSource{\n\t\toutputs:     []*TensorMeta{t1, t2},\n\t\tsourceParty: \"alice\",\n\t\toriginNames: []string{\"col1\", \"col2\"},\n\t}\n\n\tt3 := createTestTensor(3)\n\tadd := &OperatorFunction{\n\t\tinputs: []*TensorMeta{t1, t2},\n\t\toutput: t3,\n\t}\n\n\tnode := &OperatorRunSQL{\n\t\toutputs:       []*TensorMeta{t3},\n\t\tsql:           \"SELECT col1 + col2 FROM table1\",\n\t\tsourceParty:   \"alice\",\n\t\ttableRefs:     []string{\"table1\"},\n\t\tsubGraphNodes: []Operator{dataSource, add},\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, t3)\n}\n\nfunc TestOperatorEQJoinInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\tglobal := &GlobalSecurityRelaxation{RevealKeyAfterJoin: true}\n\tsrm := NewSecurityRelaxationManager(global, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\t// Setup tensors for join\n\tleftKey := createTestTensor(1)\n\trightKey := createTestTensor(2)\n\tleftPayload := createTestTensor(3)\n\trightPayload := createTestTensor(4)\n\tleftOutput := createTestTensor(5)\n\trightOutput := createTestTensor(6)\n\n\t// Set initial visibility\n\tvs.vt.UpdateVisibility(leftKey, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvs.vt.UpdateVisibility(rightKey, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\tvs.vt.UpdateVisibility(leftPayload, NewVisibleParties([]string{\"alice\"}))\n\tvs.vt.UpdateVisibility(rightPayload, NewVisibleParties([]string{\"carol\"}))\n\n\tnode := &OperatorEQJoin{\n\t\tleftKeys:      []*TensorMeta{leftKey},\n\t\trightKeys:     []*TensorMeta{rightKey},\n\t\tleftPayloads:  []*TensorMeta{leftPayload},\n\t\trightPayloads: []*TensorMeta{rightPayload},\n\t\tleftOutputs:   []*TensorMeta{leftOutput},\n\t\trightOutputs:  []*TensorMeta{rightOutput},\n\t}\n\n\t// Test without security relaxation\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\t// output tensors' visibility unchanged\n\tassert.Len(tensors, 0)\n\n\t// Test with security relaxation\n\ttensors, err = node.Infer(vs, true)\n\trequire.NoError(err)\n\tassert.Len(tensors, 2)\n\tassert.Equal(vs.vt.TensorVisibleParties(leftOutput), NewVisibleParties([]string{\"alice\"}))\n\tassert.Equal(vs.vt.TensorVisibleParties(rightOutput), NewVisibleParties([]string{\"carol\"}))\n}\n\nfunc TestOperatorConstantInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvs := &VisibilitySolver{vt: NewVisibilityTable(parties)}\n\n\toutput := createTestTensor(1)\n\tnode := &OperatorConstant{\n\t\toutput: output,\n\t\tvalue:  nil,\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, output)\n\n\t// Verify constant is public\n\tassert.True(vs.vt.VisibilityPublic(vs.vt.TensorVisibleParties(output)))\n}\n\nfunc TestOperatorFilterInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\tmask := createTestTensor(1)\n\tinput := createTestTensor(2)\n\toutput := createTestTensor(3)\n\n\tvs.vt.UpdateVisibility(mask, NewVisibleParties([]string{\"alice\"}))\n\tvs.vt.UpdateVisibility(input, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\n\tnode := &OperatorFilter{\n\t\tmask:    mask,\n\t\tinputs:  []*TensorMeta{input},\n\t\toutputs: []*TensorMeta{output},\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Equal(vt.TensorVisibleParties(output).GetParties(), []string{\"alice\"})\n}\n\nfunc TestOperatorConcatInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\tinput1 := createTestTensor(1)\n\tinput2 := createTestTensor(2)\n\toutput := createTestTensor(3)\n\n\tvs.vt.UpdateVisibility(input1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvs.vt.UpdateVisibility(input2, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\n\tnode := &OperatorConcat{\n\t\tinputs: []*TensorMeta{input1, input2},\n\t\toutput: output,\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, output)\n\tassert.Equal(vt.TensorVisibleParties(output).GetParties(), []string{\"bob\"})\n}\n\nfunc TestOperatorSortInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\tsortKey := createTestTensor(1)\n\tpayload := createTestTensor(2)\n\toutput := createTestTensor(3)\n\n\tvs.vt.UpdateVisibility(sortKey, NewVisibleParties([]string{\"alice\"}))\n\tvs.vt.UpdateVisibility(payload, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\n\tnode := &OperatorSort{\n\t\tsortKeys: []*TensorMeta{sortKey},\n\t\tpayloads: []*TensorMeta{payload},\n\t\toutputs:  []*TensorMeta{output},\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, output)\n\tassert.Equal(vt.TensorVisibleParties(output).GetParties(), []string{\"alice\"})\n}\n\nfunc TestOperatorReduceInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\tinput := createTestTensor(1)\n\toutput := createTestTensor(2)\n\tvs.vt.UpdateVisibility(input, NewVisibleParties([]string{\"bob\"}))\n\n\tsumFunc := &aggregation.AggFuncDesc{}\n\tsumFunc.Name = ast.AggFuncSum\n\tnode := &OperatorReduce{\n\t\tinput:   input,\n\t\toutput:  output,\n\t\taggFunc: sumFunc,\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, output)\n\tassert.Equal(vt.TensorVisibleParties(output).GetParties(), []string{\"bob\"})\n}\n\nfunc TestOperatorGroupAggInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\tgroupKey := createTestTensor(1)\n\tpayload := createTestTensor(2)\n\tcountOutput := createTestTensor(3)\n\n\tvs.vt.UpdateVisibility(groupKey, NewVisibleParties([]string{\"alice\"}))\n\tvs.vt.UpdateVisibility(payload, NewVisibleParties([]string{\"bob\"}))\n\n\tnode := &OperatorGroupAgg{\n\t\tgroupKeys:          []*TensorMeta{groupKey},\n\t\taggArgs:            []*TensorMeta{payload},\n\t\targFuncOutputs:     []*TensorMeta{},\n\t\tsimpleCountOutputs: []*TensorMeta{countOutput},\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, countOutput)\n\tassert.Equal(vt.TensorVisibleParties(countOutput).GetParties(), []string{\"alice\"})\n}\n\nfunc TestOperatorRankWindowInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\torderKey := createTestTensor(1)\n\tpayload := createTestTensor(2)\n\toutput := createTestTensor(3)\n\trank := createTestTensor(4)\n\n\tvs.vt.UpdateVisibility(orderKey, NewVisibleParties([]string{\"alice\"}))\n\tvs.vt.UpdateVisibility(payload, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\n\tnode := &OperatorWindow{\n\t\torderKeys:      []*TensorMeta{orderKey},\n\t\tpayloads:       []*TensorMeta{payload},\n\t\tpayloadOutputs: []*TensorMeta{output},\n\t\tfuncOutput:     rank,\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 2)\n\tassert.Contains(tensors, output)\n\tassert.Contains(tensors, rank)\n\tassert.Equal(vt.TensorVisibleParties(rank).GetParties(), []string{\"alice\"})\n\tassert.Equal(vt.TensorVisibleParties(output).GetParties(), []string{\"alice\", \"bob\"})\n\n}\n\nfunc TestOperatorInInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\tleft := createTestTensor(1)\n\tright := createTestTensor(2)\n\toutput := createTestTensor(3)\n\n\tvs.vt.UpdateVisibility(left, NewVisibleParties([]string{\"alice\"}))\n\tvs.vt.UpdateVisibility(right, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\n\tnode := &OperatorIn{\n\t\tleft:   left,\n\t\tright:  right,\n\t\toutput: output,\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, output)\n\tassert.Equal(vt.TensorVisibleParties(output).GetParties(), []string{\"alice\"})\n}\n\nfunc TestOperatorFunctionInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{RevealFilterMask: true}, map[string][]string{})\n\n\t// Test case 1: Basic function without ApplyRevealFilterMask\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\tconsumerTracker := make(TensorConsumerTracker)\n\tvs.consumerTracker = &consumerTracker\n\n\tinput1 := createTestTensor(1)\n\tinput2 := createTestTensor(2)\n\toutput := createTestTensor(3)\n\n\tvs.vt.UpdateVisibility(input1, NewVisibleParties([]string{\"alice\"}))\n\tvs.vt.UpdateVisibility(input2, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\n\tnode := &OperatorFunction{\n\t\tinputs:   []*TensorMeta{input1, input2},\n\t\toutput:   output,\n\t\tfuncName: ast.GT,\n\t}\n\n\t// Test security relaxation ApplyRevealFilterMask not applied\n\ttensors, err := node.Infer(vs, true)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, output)\n\tassert.Equal(vt.TensorVisibleParties(output).GetParties(), []string{\"alice\"})\n\n\t// ApplyRevealFilterMask applied - output used as filter mask\n\tfilterNode := &OperatorFilter{\n\t\tmask:    output,\n\t\tinputs:  []*TensorMeta{createTestTensor(4)},\n\t\toutputs: []*TensorMeta{createTestTensor(5)},\n\t}\n\tconsumerTracker.AddConsumer(output, filterNode)\n\n\t// ApplyRevealFilterMask should make the output public\n\ttensors, err = node.Infer(vs, true)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, output)\n\t// The output should be public due to ApplyRevealFilterMask\n\tassert.True(vt.VisibilityPublic(vt.TensorVisibleParties(output)))\n}\n\nfunc TestOperatorBroadcastToInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\tshapeRef := createTestTensor(1)\n\tscalar := createTestTensor(2)\n\toutput := createTestTensor(3)\n\n\tvs.vt.UpdateVisibility(scalar, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvs.vt.UpdateVisibility(shapeRef, NewVisibleParties([]string{\"alice\"}))\n\n\tnode := &OperatorBroadcastTo{\n\t\tshapeRef: shapeRef,\n\t\tscalars:  []*TensorMeta{scalar},\n\t\toutputs:  []*TensorMeta{output},\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, output)\n\tassert.Equal(vt.TensorVisibleParties(output).GetParties(), []string{\"alice\", \"bob\"})\n}\n\nfunc TestOperatorLimitInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\tinput := createTestTensor(1)\n\toutput := createTestTensor(2)\n\tvs.vt.UpdateVisibility(input, NewVisibleParties([]string{\"bob\"}))\n\n\tnode := &OperatorLimit{\n\t\tinputs:  []*TensorMeta{input},\n\t\toutputs: []*TensorMeta{output},\n\t\toffset:  10,\n\t\tcount:   100,\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 1)\n\tassert.Contains(tensors, output)\n\tassert.Equal(vt.TensorVisibleParties(output).GetParties(), []string{\"bob\"})\n}\n\nfunc TestOperatorCrossJoinInfer(t *testing.T) {\n\tassert := assert.New(t)\n\trequire := require.New(t)\n\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\tvs := NewVisibilitySolver(vt, srm, map[string]*VisibleParties{}, nil, false)\n\n\tleftInput := createTestTensor(1)\n\trightInput := createTestTensor(2)\n\tleftOutput := createTestTensor(3)\n\trightOutput := createTestTensor(4)\n\n\tvs.vt.UpdateVisibility(leftInput, NewVisibleParties([]string{\"alice\"}))\n\tvs.vt.UpdateVisibility(rightInput, NewVisibleParties([]string{\"bob\"}))\n\n\tnode := &OperatorCrossJoin{\n\t\tleftInputs:   []*TensorMeta{leftInput},\n\t\trightInputs:  []*TensorMeta{rightInput},\n\t\tleftOutputs:  []*TensorMeta{leftOutput},\n\t\trightOutputs: []*TensorMeta{rightOutput},\n\t}\n\n\ttensors, err := node.Infer(vs, false)\n\trequire.NoError(err)\n\tassert.Len(tensors, 2)\n\tassert.Contains(tensors, leftOutput)\n\tassert.Contains(tensors, rightOutput)\n\tassert.Equal(vt.TensorVisibleParties(leftOutput).GetParties(), []string{\"alice\"})\n\tassert.Equal(vt.TensorVisibleParties(rightOutput).GetParties(), []string{\"bob\"})\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/kernel.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"slices\"\n\t\"sort\"\n\t\"strconv\"\n\n\t\"github.com/apache/arrow/go/v17/arrow\"\n\t\"github.com/apache/arrow/go/v17/arrow/compute\"\n\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n\t\"github.com/secretflow/scql/pkg/util/stringutil\"\n)\n\ntype Kernel interface {\n\t// ensureTensorPlace ensures the tensor status of the node meets the requirements of the kernel\n\t// tensor status conversion maybe performed when required placed tensor does not exist\n\t// TODO: remove ensureTensorPlace and set placed tensors in kernel directly when resolving kernel\n\tensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) error\n\t// toEngineNodes emit engine ops according to the Operator and the Kernel\n\ttoEngineNodes(builder *ExecutionGraphBuilder, node Operator) error\n\t// String returns the string representation of the kernel\n\tString() string\n\t// Cost returns the cost of the kernel\n\t// Note that comparing Cost values is only meaningful when the original Operator is identical\n\t// range: [0, 1]\n\tCost() float64\n}\n\ntype KernelRunSQL struct {\n}\n\nfunc (k *KernelRunSQL) Cost() float64 {\n\t// not related to MPC\n\treturn 0.0\n}\n\nfunc (k *KernelRunSQL) String() string {\n\treturn \"KernelRunSQL\"\n}\n\nfunc (k *KernelRunSQL) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\t// OperatorRunSQL has no inputs, no need to ensure tensor status\n\treturn nil\n}\n\nfunc (k *KernelRunSQL) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tdataSource, ok := node.(*OperatorRunSQL)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelRunSQL toEngineNodes: expect data source node, but got %T\", node)\n\t}\n\n\toutputs := make([]*graph.Tensor, 0, len(dataSource.outputs))\n\tfor _, meta := range dataSource.outputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: dataSource.sourceParty})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelRunSQL toEngineNodes: %w\", err)\n\t\t}\n\t\toutputs = append(outputs, tensor)\n\t}\n\n\tif err := builder.addOpRunSQL(outputs, dataSource.sourceParty, dataSource.sql, dataSource.tableRefs); err != nil {\n\t\treturn fmt.Errorf(\"KernelRunSQL toEngineNodes: %w\", err)\n\t}\n\treturn nil\n}\n\ntype KernelPublishResult struct {\n\t// Bonded tensors in this kernel\n\tresultTensors []*graph.Tensor\n}\n\nfunc (k *KernelPublishResult) String() string {\n\treturn \"KernelPublishResult\"\n}\n\nfunc (k *KernelPublishResult) Cost() float64 {\n\t// not related to MPC\n\treturn 0.0\n}\n\nfunc (k *KernelPublishResult) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tresult, ok := node.(*OperatorResult)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPublishResult ensureTensorPlace: expect result node, but got %T\", node)\n\t}\n\n\tk.resultTensors, err = createPlacedTensors(builder, result.resultTensors, &privatePlacement{partyCode: result.issuerPartyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPublishResult ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelPublishResult) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tresult, ok := node.(*OperatorResult)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPublishResult toEngineNodes: expect result node, but got %T\", node)\n\t}\n\n\tif len(k.resultTensors) != len(result.outputNames) {\n\t\treturn fmt.Errorf(\"KernelPublishResult toEngineNodes: result tensors and output names length not match\")\n\t}\n\n\toutputs := make([]*graph.Tensor, 0, len(k.resultTensors))\n\tfor idx, tensor := range k.resultTensors {\n\t\toutput := builder.tm.CreateResultTensor(tensor, result.outputNames[idx])\n\t\toutputs = append(outputs, output)\n\t}\n\n\tif err := builder.addOpPublish(k.resultTensors, outputs, result.issuerPartyCode); err != nil {\n\t\treturn fmt.Errorf(\"KernelPublishResult toEngineNodes: %w\", err)\n\t}\n\treturn nil\n}\n\ntype KernelInsertTable struct {\n\tinsertTableOpt *core.InsertTableOption\n\n\t// Bonded tensors in this kernel\n\tresultTensors []*graph.Tensor\n}\n\nfunc (k *KernelInsertTable) Cost() float64 {\n\t// not related to MPC\n\treturn 0.0\n}\n\nfunc (k *KernelInsertTable) String() string {\n\treturn fmt.Sprintf(\"KernelInsertTable(insertTableOpt: %v)\", k.insertTableOpt)\n}\n\nfunc (k *KernelInsertTable) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tresult, ok := node.(*OperatorResult)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelInsertTable ensureTensorPlace: expect result node, but got %T\", node)\n\t}\n\n\tk.resultTensors, err = createPlacedTensors(builder, result.resultTensors, &privatePlacement{partyCode: result.issuerPartyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelInsertTable ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelInsertTable) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tresult, ok := node.(*OperatorResult)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelInsertTable toEngineNodes: expect result node, but got %T\", node)\n\t}\n\n\tif len(k.resultTensors) != len(result.outputNames) {\n\t\treturn fmt.Errorf(\"KernelInsertTable toEngineNodes: result tensors and output names length not match\")\n\t}\n\n\toutputs := make([]*graph.Tensor, 0, len(k.resultTensors))\n\tfor idx, tensor := range k.resultTensors {\n\t\toutput := builder.tm.CreateResultTensor(tensor, result.outputNames[idx])\n\t\toutputs = append(outputs, output)\n\t}\n\n\tif err := builder.addOpInsertTable(k.resultTensors, outputs, result.issuerPartyCode, k.insertTableOpt); err != nil {\n\t\treturn fmt.Errorf(\"KernelInsertTable toEngineNodes: %w\", err)\n\t}\n\treturn nil\n}\n\ntype KernelDumpFile struct {\n\tintoOpt *core.IntoOpt\n}\n\nfunc (k *KernelDumpFile) Cost() float64 {\n\t// not related to MPC\n\treturn 0.0\n}\n\nfunc (k *KernelDumpFile) String() string {\n\treturn fmt.Sprintf(\"KernelDumpFile(intoOpt: %v)\", k.intoOpt)\n}\n\nfunc (k *KernelDumpFile) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\treturn nil\n}\n\nfunc (k *KernelDumpFile) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tresult, ok := node.(*OperatorResult)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelDumpFile toEngineNodes: expect result node, but got %T\", node)\n\t}\n\n\tfor _, partyFile := range k.intoOpt.Opt.PartyFiles {\n\t\tvar partyResults []*TensorMeta\n\t\tvar resultNames []string\n\t\tif len(partyFile.FieldList) == 0 {\n\t\t\tpartyResults = result.resultTensors\n\t\t\tresultNames = result.outputNames\n\t\t} else {\n\t\t\tnameRecords := make(map[string]string)\n\t\t\tfor idx, col := range k.intoOpt.PartyColumns[partyFile.PartyCode] {\n\t\t\t\ttensor, ok := result.resultTable[col.UniqueID]\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"KernelDumpFile toEngineNodes: result tensor %d not found\", idx)\n\t\t\t\t}\n\t\t\t\tpartyResults = append(partyResults, tensor)\n\n\t\t\t\texpr, ok := partyFile.FieldList[idx].Expr.(*ast.ColumnNameExpr)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"KernelDumpFile toEngineNodes: custom into field for party %s must be column name expr\", partyFile.PartyCode)\n\t\t\t\t}\n\t\t\t\tvar colName string\n\t\t\t\tif partyFile.FieldList[idx].AsName.String() != \"\" {\n\t\t\t\t\tcolName = partyFile.FieldList[idx].AsName.String() // using as name\n\t\t\t\t} else {\n\t\t\t\t\tcolName = expr.Name.Name.String()\n\t\t\t\t}\n\t\t\t\tif _, ok := nameRecords[colName]; ok {\n\t\t\t\t\treturn fmt.Errorf(\"KernelDumpFile toEngineNodes:  column name: '%s' duplicated in custom into field for party %s, please remove redundant items or using as name like: 'select ta.id ... (ta.id, ta.id as id2) ...' or 'select ta.id as id1, tb.id as id2 ... (id1, id2) ...'\", colName, partyFile.PartyCode)\n\t\t\t\t}\n\t\t\t\tnameRecords[colName] = expr.Name.String()\n\t\t\t\tresultNames = append(resultNames, colName)\n\t\t\t}\n\t\t}\n\n\t\tinputs, outputs, err := builder.prepareResultForParty(partyResults, resultNames, partyFile.PartyCode)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelDumpFile toEngineNodes: %w\", err)\n\t\t}\n\n\t\tif err := builder.addOpDumpFile(inputs, outputs, k.intoOpt.Opt, partyFile); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelDumpFile toEngineNodes: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\ntype KernelPsiEQJoin struct {\n\tleftParty        string\n\trightParty       string\n\tpsiAlgorithmType proto.PsiAlgorithmType\n\n\tleftPayloadsPlacement  []tensorPlacement\n\trightPayloadsPlacement []tensorPlacement\n\n\tleftTouchResult  bool\n\trightTouchResult bool\n\n\t// Bonded tensors in this kernel\n\tleftKeys      []*graph.Tensor\n\trightKeys     []*graph.Tensor\n\tleftPayloads  []*graph.Tensor\n\trightPayloads []*graph.Tensor\n\tleftOutputs   []*graph.Tensor\n\trightOutputs  []*graph.Tensor\n}\n\nfunc (k *KernelPsiEQJoin) Cost() float64 {\n\t// way faster than secret join\n\t// considering there will be local join in the future, we keep 0 for local join\n\treturn 0.2\n}\n\nfunc (k *KernelPsiEQJoin) String() string {\n\treturn fmt.Sprintf(\"KernelPsiEQJoin(leftParty: %s, rightParty: %s, psiAlgorithmType: %v, leftPayloadsPlacement: %v, rightPayloadsPlacement: %v, leftTouchResult: %t, rightTouchResult: %t)\",\n\t\tk.leftParty, k.rightParty, k.psiAlgorithmType, k.leftPayloadsPlacement, k.rightPayloadsPlacement, k.leftTouchResult, k.rightTouchResult)\n}\n\nfunc (k *KernelPsiEQJoin) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\teqJoin, ok := node.(*OperatorEQJoin)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPsiEQJoin ensureTensorPlace: expect eq join node, but got %T\", node)\n\t}\n\n\tk.leftKeys, err = createPlacedTensors(builder, eqJoin.leftKeys, &privatePlacement{partyCode: k.leftParty})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPsiEQJoin ensureTensorPlace: %w\", err)\n\t}\n\n\tk.rightKeys, err = createPlacedTensors(builder, eqJoin.rightKeys, &privatePlacement{partyCode: k.rightParty})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPsiEQJoin ensureTensorPlace: %w\", err)\n\t}\n\n\tk.leftPayloads = make([]*graph.Tensor, len(eqJoin.leftPayloads))\n\tfor idx, meta := range eqJoin.leftPayloads {\n\t\tvar placement tensorPlacement\n\t\tif builder.IsBatched() {\n\t\t\tplacement = &privatePlacement{partyCode: k.leftParty}\n\t\t} else {\n\t\t\tplacement = k.leftPayloadsPlacement[idx]\n\t\t}\n\t\ttensor, err := builder.getOrCreatePlacedTensor(meta, placement)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPsiEQJoin ensureTensorPlace: %w\", err)\n\t\t}\n\t\tk.leftPayloads[idx] = tensor\n\t}\n\n\tk.rightPayloads = make([]*graph.Tensor, len(eqJoin.rightPayloads))\n\tfor idx, meta := range eqJoin.rightPayloads {\n\t\tvar placement tensorPlacement\n\t\tif builder.IsBatched() {\n\t\t\tplacement = &privatePlacement{partyCode: k.rightParty}\n\t\t} else {\n\t\t\tplacement = k.rightPayloadsPlacement[idx]\n\t\t}\n\t\ttensor, err := builder.getOrCreatePlacedTensor(meta, placement)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPsiEQJoin ensureTensorPlace: %w\", err)\n\t\t}\n\t\tk.rightPayloads[idx] = tensor\n\t}\n\treturn nil\n}\n\nfunc (k *KernelPsiEQJoin) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\teqJoin, ok := node.(*OperatorEQJoin)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: expect eq join node, but got %T\", node)\n\t}\n\n\tif len(k.leftPayloads) != len(eqJoin.leftOutputs) {\n\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: left payloads and left outputs length not match\")\n\t}\n\tif len(k.rightPayloads) != len(eqJoin.rightOutputs) {\n\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: right payloads and right outputs length not match\")\n\t}\n\n\tleftKeys := k.leftKeys\n\trightKeys := k.rightKeys\n\tleftPayloads := k.leftPayloads\n\trightPayloads := k.rightPayloads\n\n\tif builder.IsBatched() {\n\t\tmakeBuckets := func(keys, payloads []*graph.Tensor) ([]*graph.Tensor, []*graph.Tensor, error) {\n\t\t\t// check all tensors are private and belong to the same party code\n\t\t\tpartyCode := keys[0].OwnerPartyCode\n\t\t\tfor _, tensor := range append(keys, payloads...) {\n\t\t\t\tif tensor.Status() != proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\t\t\t\treturn nil, nil, fmt.Errorf(\"all tensors must be private, but got %s\", tensor.Status())\n\t\t\t\t}\n\t\t\t\tif tensor.OwnerPartyCode != partyCode {\n\t\t\t\t\treturn nil, nil, fmt.Errorf(\"all tensors must belong to the same party code %s, but got %s\", partyCode, tensor.OwnerPartyCode)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// use a map to avoid redundant bucket tensor creation\n\t\t\tbucketTensorMap := make(map[int]*graph.Tensor)\n\t\t\toutputs := make([]*graph.Tensor, 0, len(keys)+len(payloads))\n\t\t\tdedupOutputs := make([]*graph.Tensor, 0, len(keys)+len(payloads))\n\t\t\tdedupInputs := make([]*graph.Tensor, 0, len(keys)+len(payloads))\n\t\t\tfor _, tensor := range keys {\n\t\t\t\tbucketTensorMap[tensor.ID] = builder.tm.CreateTensorAs(tensor)\n\t\t\t\toutputs = append(outputs, bucketTensorMap[tensor.ID])\n\t\t\t\tdedupOutputs = append(dedupOutputs, bucketTensorMap[tensor.ID])\n\t\t\t\tdedupInputs = append(dedupInputs, tensor)\n\t\t\t}\n\t\t\tfor _, tensor := range payloads {\n\t\t\t\tif _, ok := bucketTensorMap[tensor.ID]; !ok {\n\t\t\t\t\tbucketTensorMap[tensor.ID] = builder.tm.CreateTensorAs(tensor)\n\t\t\t\t\t// only add payload and corresponding output to dedup inputs and outputs when it has not been added tp bucketTensorMap before\n\t\t\t\t\tdedupOutputs = append(dedupOutputs, bucketTensorMap[tensor.ID])\n\t\t\t\t\tdedupInputs = append(dedupInputs, tensor)\n\t\t\t\t}\n\t\t\t\toutputs = append(outputs, bucketTensorMap[tensor.ID])\n\t\t\t}\n\n\t\t\tif err := builder.addOpBucket(keys, dedupInputs, dedupOutputs, []string{partyCode}); err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\n\t\t\treturn outputs[:len(keys)], outputs[len(keys):], nil\n\t\t}\n\n\t\tvar err error\n\t\tleftKeys, leftPayloads, err = makeBuckets(leftKeys, leftPayloads)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t\t}\n\t\trightKeys, rightPayloads, err = makeBuckets(rightKeys, rightPayloads)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t\t}\n\t}\n\n\tvar leftIndex, rightIndex *graph.Tensor\n\tif k.leftTouchResult {\n\t\tleftIndex = builder.tm.CreateUnbondedTensor(\"left_index\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64), &privatePlacement{partyCode: k.leftParty})\n\t}\n\tif k.rightTouchResult {\n\t\trightIndex = builder.tm.CreateUnbondedTensor(\"right_index\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64), &privatePlacement{partyCode: k.rightParty})\n\t}\n\n\tif err := builder.addOpPsiJoin(leftKeys, rightKeys, leftIndex, rightIndex, []string{k.leftParty, k.rightParty}, JoinTypeLpToEp[eqJoin.joinType], k.psiAlgorithmType); err != nil {\n\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t}\n\n\tk.leftOutputs = make([]*graph.Tensor, len(eqJoin.leftOutputs))\n\tfor idx, meta := range eqJoin.leftOutputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, extractTensorPlacement(leftPayloads[idx]))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t\t}\n\t\tk.leftOutputs[idx] = tensor\n\t}\n\tk.rightOutputs = make([]*graph.Tensor, len(eqJoin.rightOutputs))\n\tfor idx, meta := range eqJoin.rightOutputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, extractTensorPlacement(rightPayloads[idx]))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t\t}\n\t\tk.rightOutputs[idx] = tensor\n\t}\n\n\taddFilterByIndex := func(index *graph.Tensor, payloads, outputs []*graph.Tensor) error {\n\t\tpartyPayloadIdx := make(map[string][]int)\n\t\tfor idx, payload := range payloads {\n\t\t\tpartyPayloadIdx[payload.OwnerPartyCode] = append(partyPayloadIdx[payload.OwnerPartyCode], idx)\n\t\t}\n\n\t\tfor party, idxs := range sliceutil.SortedMap(partyPayloadIdx) {\n\t\t\tpartyPayloads, err := sliceutil.TakeByIndices(payloads, idxs)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t\t\t}\n\t\t\tpartyOutputs, err := sliceutil.TakeByIndices(outputs, idxs)\n\n\t\t\tpartyIndex := index\n\t\t\tif party != index.OwnerPartyCode {\n\t\t\t\tpartyIndex, err = builder.convertStatus(index, &privatePlacement{partyCode: party}, false)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t\t\t}\n\t\t\tif err := builder.addOpFilterByIndex(partyIndex, partyPayloads, partyOutputs, party); err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif err := addFilterByIndex(leftIndex, leftPayloads, k.leftOutputs); err != nil {\n\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t}\n\tif err := addFilterByIndex(rightIndex, rightPayloads, k.rightOutputs); err != nil {\n\t\treturn fmt.Errorf(\"KernelPsiEQJoin toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelSecretEQJoin struct {\n\t// Bonded tensors in this kernel\n\tleftKeys      []*graph.Tensor\n\trightKeys     []*graph.Tensor\n\tleftPayloads  []*graph.Tensor\n\trightPayloads []*graph.Tensor\n\tleftOutputs   []*graph.Tensor\n\trightOutputs  []*graph.Tensor\n}\n\nfunc (k *KernelSecretEQJoin) Cost() float64 {\n\t// secret join is very expensive\n\treturn 1.0\n}\n\nfunc (k *KernelSecretEQJoin) String() string {\n\treturn \"KernelSecretEQJoin\"\n}\n\nfunc (k *KernelSecretEQJoin) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\teqJoin, ok := node.(*OperatorEQJoin)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelSecretEQJoin ensureTensorPlace: expect eq join node, but got %T\", node)\n\t}\n\n\tk.leftKeys, err = createPlacedTensors(builder, eqJoin.leftKeys, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretEQJoin ensureTensorPlace: %w\", err)\n\t}\n\n\tk.rightKeys, err = createPlacedTensors(builder, eqJoin.rightKeys, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretEQJoin ensureTensorPlace: %w\", err)\n\t}\n\n\tk.leftPayloads, err = createPlacedTensors(builder, eqJoin.leftPayloads, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretEQJoin ensureTensorPlace: %w\", err)\n\t}\n\n\tk.rightPayloads, err = createPlacedTensors(builder, eqJoin.rightPayloads, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretEQJoin ensureTensorPlace: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (k *KernelSecretEQJoin) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\teqJoin, ok := node.(*OperatorEQJoin)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelSecretEQJoin toEngineNodes: expect eq join node, but got %T\", node)\n\t}\n\n\tk.leftOutputs = make([]*graph.Tensor, len(eqJoin.leftOutputs))\n\tfor idx, meta := range eqJoin.leftOutputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, &secretPlacement{})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelSecretEQJoin toEngineNodes: %w\", err)\n\t\t}\n\t\tk.leftOutputs[idx] = tensor\n\t}\n\n\tk.rightOutputs = make([]*graph.Tensor, len(eqJoin.rightOutputs))\n\tfor idx, meta := range eqJoin.rightOutputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, &secretPlacement{})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelSecretEQJoin toEngineNodes: %w\", err)\n\t\t}\n\t\tk.rightOutputs[idx] = tensor\n\t}\n\n\tif err := builder.addOpSecretJoin(k.leftKeys, k.rightKeys, k.leftPayloads, k.rightPayloads, k.leftOutputs, k.rightOutputs); err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretEQJoin toEngineNodes: %w\", err)\n\t}\n\treturn nil\n}\n\ntype KernelSimpleReduce struct {\n\tplacement tensorPlacement\n\taggFunc   *aggregation.AggFuncDesc\n\n\t// Bonded tensors in this kernel\n\tinput  *graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelSimpleReduce) Cost() float64 {\n\tif IsSecret(k.placement) {\n\t\t// secret reduce is more expensive than private reduce\n\t\treturn 0.6\n\t}\n\t// private reduce, cheaper than private distinct count\n\treturn 0.1\n}\n\nfunc (k *KernelSimpleReduce) String() string {\n\treturn fmt.Sprintf(\"KernelSimpleReduce(aggName = %s, placement = %s)\", k.aggFunc.Name, k.placement)\n}\n\nfunc (k *KernelSimpleReduce) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\treduce, ok := node.(*OperatorReduce)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelSimpleReduce ensureTensorPlace: expect reduce node, but got %T\", node)\n\t}\n\n\ttensor, err := builder.getOrCreatePlacedTensor(reduce.input, k.placement)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSimpleReduce ensureTensorPlace: %w\", err)\n\t}\n\tk.input = tensor\n\treturn nil\n}\n\nfunc (k *KernelSimpleReduce) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\treduce, ok := node.(*OperatorReduce)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelSimpleReduce toEngineNodes: expect reduce node, but got %T\", node)\n\t}\n\n\ttensor, err := builder.tm.CreateAndSetFirstTensor(reduce.output, k.placement)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSimpleReduce toEngineNodes: %w\", err)\n\t}\n\tk.output = tensor\n\n\tattrs := map[string]*graph.Attribute{}\n\tif k.aggFunc.Name == ast.AggPercentileDisc {\n\t\tif len(k.aggFunc.Args) != 2 {\n\t\t\treturn fmt.Errorf(\"KernelSimpleReduce toEngineNodes: expect 2 args for percentile_disc, but got %d\", len(k.aggFunc.Args))\n\t\t}\n\t\tattr := &graph.Attribute{}\n\t\tpercent, err := strconv.ParseFloat(k.aggFunc.Args[1].String(), 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelSimpleReduce: %s is not a valid float value\", k.aggFunc.Args[1].String())\n\t\t}\n\t\tif percent < 0 || percent > 1 {\n\t\t\treturn fmt.Errorf(\"KernelSimpleReduce: percent should be in [0, 1], but got %v\", percent)\n\t\t}\n\t\tattr.SetDouble(percent)\n\t\tattrs[operator.PercentAttr] = attr\n\t}\n\n\treduceName := k.aggFunc.Name\n\tif reduceName == ast.AggFuncCount && k.aggFunc.Mode == aggregation.FinalMode {\n\t\treduceName = ast.AggFuncSum\n\t}\n\n\tif err := builder.addOpReduce(reduceName, k.input, k.output, attrs); err != nil {\n\t\treturn fmt.Errorf(\"KernelSimpleReduce toEngineNodes: %w\", err)\n\t}\n\treturn nil\n}\n\ntype KernelPrivateDistinctCount struct {\n\tpartyCode string\n\n\t// Bonded tensors in this kernel\n\tinput  *graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelPrivateDistinctCount) Cost() float64 {\n\t// private count is relatively cheap\n\treturn 0.3\n}\n\nfunc (k *KernelPrivateDistinctCount) String() string {\n\treturn fmt.Sprintf(\"KernelPrivateDistinctCount(partyCode = %s)\", k.partyCode)\n}\n\nfunc (k *KernelPrivateDistinctCount) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\treduce, ok := node.(*OperatorReduce)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPrivateDistinctCount ensureTensorPlace: expect reduce node, but got %T\", node)\n\t}\n\n\ttensor, err := builder.getOrCreatePlacedTensor(reduce.input, &privatePlacement{partyCode: k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateDistinctCount ensureTensorPlace: %w\", err)\n\t}\n\tk.input = tensor\n\n\treturn nil\n}\n\nfunc (k *KernelPrivateDistinctCount) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\treduce, ok := node.(*OperatorReduce)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPrivateDistinctCount toEngineNodes: expect reduce node, but got %T\", node)\n\t}\n\n\t// Create unique tensor using kernel's input\n\tuniqueResult := builder.tm.CreateTensorAs(k.input)\n\tuniqueResult.Name = \"unique_\" + uniqueResult.Name\n\tif err := builder.addOpUnique(k.input, uniqueResult); err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateDistinctCount toEngineNodes: %w\", err)\n\t}\n\n\toutput, err := builder.tm.CreateAndSetFirstTensor(reduce.output, &privatePlacement{partyCode: k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateDistinctCount toEngineNodes: %w\", err)\n\t}\n\tk.output = output\n\n\tif err := builder.addOpReduce(ast.AggFuncCount, uniqueResult, k.output, map[string]*graph.Attribute{}); err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateDistinctCount toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelSecretDistinctCount struct {\n\t// Bonded tensors in this kernel\n\tinput  *graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelSecretDistinctCount) Cost() float64 {\n\t// distinct count needs to sort the tensor, which is very expensive\n\treturn 1.0\n}\n\nfunc (k *KernelSecretDistinctCount) String() string {\n\treturn \"KernelSecretDistinctCount\"\n}\n\nfunc (k *KernelSecretDistinctCount) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\treduce, ok := node.(*OperatorReduce)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelSecretDistinctCount ensureTensorPlace: expect reduce node, but got %T\", node)\n\t}\n\n\ttensor, err := builder.getOrCreatePlacedTensor(reduce.input, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretDistinctCount ensureTensorPlace: %w\", err)\n\t}\n\tk.input = tensor\n\n\treturn nil\n}\n\nfunc (k *KernelSecretDistinctCount) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\treduce, ok := node.(*OperatorReduce)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelSecretDistinctCount toEngineNodes: expect reduce node, but got %T\", node)\n\t}\n\n\t// Sort using kernel's input\n\tsorted := builder.tm.CreateTensorAs(k.input)\n\tsorted.Name = \"sorted_\" + sorted.Name\n\tif err := builder.addOpSort([]*graph.Tensor{k.input}, []*graph.Tensor{k.input}, []*graph.Tensor{sorted}, []bool{false}); err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretDistinctCount toEngineNodes: %w\", err)\n\t}\n\n\tgroupMarkDistinct := builder.tm.CreateUnbondedTensor(\"group_mark_distinct\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_BOOL), &secretPlacement{})\n\tif err := builder.addOpObliviousGroupMark([]*graph.Tensor{sorted}, groupMarkDistinct); err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretDistinctCount toEngineNodes: %w\", err)\n\t}\n\n\tout, err := builder.tm.CreateAndSetFirstTensor(reduce.output, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretDistinctCount toEngineNodes: %w\", err)\n\t}\n\tk.output = out\n\tif err := builder.addOpReduce(ast.AggFuncSum, groupMarkDistinct, k.output, map[string]*graph.Attribute{}); err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretDistinctCount toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelShapeCount struct {\n\tinputPlacement tensorPlacement\n\tpartyCode      string\n\n\t// Bonded tensors in this kernel\n\tinput  *graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelShapeCount) Cost() float64 {\n\t// its' easy to get shape of tensor, whether it's private or secret or public\n\treturn 0.0\n}\n\nfunc (k *KernelShapeCount) String() string {\n\treturn fmt.Sprintf(\"KernelShapeCount(inputPlacement = %s, partyCode = %s)\", k.inputPlacement, k.partyCode)\n}\n\nfunc (k *KernelShapeCount) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\treduce, ok := node.(*OperatorReduce)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelShapeCount ensureTensorPlace: expect reduce node, but got %T\", node)\n\t}\n\n\ttensor, err := builder.getOrCreatePlacedTensor(reduce.input, k.inputPlacement)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelShapeCount ensureTensorPlace: %w\", err)\n\t}\n\tk.input = tensor\n\n\treturn nil\n}\n\nfunc (k *KernelShapeCount) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\treduce, ok := node.(*OperatorReduce)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelShapeCount toEngineNodes: expect reduce node, but got %T\", node)\n\t}\n\n\toutput, err := builder.tm.CreateAndSetFirstTensor(reduce.output, &privatePlacement{partyCode: k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelShapeCount toEngineNodes: %w\", err)\n\t}\n\tk.output = output\n\tif err := builder.addOpShape(k.input, k.output); err != nil {\n\t\treturn fmt.Errorf(\"KernelShapeCount toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelBroadcastTo struct {\n\trefPlacement tensorPlacement\n\n\t// Bonded tensors in this kernel\n\tshapeRef *graph.Tensor\n\tscalars  []*graph.Tensor\n\toutputs  []*graph.Tensor\n}\n\nfunc (k *KernelBroadcastTo) Cost() float64 {\n\t// The broadcasted tensor is public and the reference tensor is public or private.\n\t// It's easy to get the shape of reference tensor, whether it's private or secret or public.\n\treturn 0.0\n}\n\nfunc (k *KernelBroadcastTo) String() string {\n\treturn fmt.Sprintf(\"KernelBroadcastTo(inputPlacement = %s)\", k.refPlacement)\n}\n\nfunc (k *KernelBroadcastTo) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tbroadcast, ok := node.(*OperatorBroadcastTo)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelBroadcastTo ensureTensorPlace: expect BroadcastTo node, but got %T\", node)\n\t}\n\n\ttensor, err := builder.getOrCreatePlacedTensor(broadcast.shapeRef, k.refPlacement)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelBroadcastTo ensureTensorPlace: %w\", err)\n\t}\n\tk.shapeRef = tensor\n\n\tk.scalars = make([]*graph.Tensor, len(broadcast.scalars))\n\tfor idx, meta := range broadcast.scalars {\n\t\ttensor, err := builder.getOrCreatePlacedTensor(meta, &publicPlacement{})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelBroadcastTo ensureTensorPlace: %w\", err)\n\t\t}\n\t\tk.scalars[idx] = tensor\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelBroadcastTo) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tbroadcast, ok := node.(*OperatorBroadcastTo)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelBroadcastTo toEngineNodes: expect BroadcastTo node, but got %T\", node)\n\t}\n\n\tvar outputPlacement tensorPlacement\n\tif pp, ok := k.refPlacement.(*privatePlacement); ok {\n\t\toutputPlacement = &privatePlacement{partyCode: pp.partyCode}\n\t} else {\n\t\toutputPlacement = &publicPlacement{}\n\t}\n\tk.outputs = make([]*graph.Tensor, len(broadcast.outputs))\n\tfor idx, meta := range broadcast.outputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, outputPlacement)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelBroadcastTo toEngineNodes: %w\", err)\n\t\t}\n\t\tk.outputs[idx] = tensor\n\t}\n\tif err := builder.addOpBroadcastTo(k.shapeRef, k.scalars, k.outputs); err != nil {\n\t\treturn fmt.Errorf(\"KernelBroadcastTo toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelPrivateGroupAgg struct {\n\tpartyCode string\n\t// PGSParties stores parties suitable for private-groupby secret-agg(PGS) algorithm\n\t// ref: https://github.com/secretflow/spu/pull/1312\n\tPGSParties map[int]string\n\tcost       float64\n\n\t// Bonded tensors in this kernel\n\tgroupKeys          []*graph.Tensor\n\taggArgs            []*graph.Tensor\n\tsimpleCountOutputs []*graph.Tensor\n\targFuncOutputs     []*graph.Tensor\n}\n\nfunc (k *KernelPrivateGroupAgg) Cost() float64 {\n\treturn k.cost\n}\n\nfunc (k *KernelPrivateGroupAgg) String() string {\n\treturn fmt.Sprintf(\"KernelPrivateGroupAgg(partyCode = %s, PGSParties = %v)\", k.partyCode, k.PGSParties)\n}\n\nfunc (k *KernelPrivateGroupAgg) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tgroupAgg, ok := node.(*OperatorGroupAgg)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg ensureTensorPlace: expect GroupAgg node, but got %T\", node)\n\t}\n\n\tk.groupKeys, err = createPlacedTensors(builder, groupAgg.groupKeys, &privatePlacement{partyCode: k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg ensureTensorPlace: %w\", err)\n\t}\n\n\tk.aggArgs = make([]*graph.Tensor, len(groupAgg.aggArgs))\n\tfor idx, meta := range groupAgg.aggArgs {\n\t\ttensorParty := k.partyCode\n\t\tif party, ok := k.PGSParties[meta.ID]; ok {\n\t\t\ttensorParty = party\n\t\t}\n\t\ttensor, err := builder.getOrCreatePlacedTensor(meta, &privatePlacement{partyCode: tensorParty})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg ensureTensorPlace: %w\", err)\n\t\t}\n\t\tk.aggArgs[idx] = tensor\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelPrivateGroupAgg) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tgroupAgg, ok := node.(*OperatorGroupAgg)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: expect GroupAgg node, but got %T\", node)\n\t}\n\n\tgroupId := builder.tm.CreateUnbondedTensor(\"group_id\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64), &privatePlacement{partyCode: k.partyCode})\n\n\tgroupNum := builder.tm.CreateUnbondedTensor(\"group_num\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64), &privatePlacement{partyCode: k.partyCode})\n\n\tif err := builder.addOpPrivateGroup(k.groupKeys, groupId, groupNum, k.partyCode); err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t}\n\n\tk.simpleCountOutputs = make([]*graph.Tensor, len(groupAgg.simpleCountOutputs))\n\tfor idx := range groupAgg.simpleCountOutputs {\n\t\toutput, err := builder.tm.CreateAndSetFirstTensor(groupAgg.simpleCountOutputs[idx], &privatePlacement{partyCode: k.partyCode})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t}\n\t\tk.simpleCountOutputs[idx] = output\n\n\t\tif err := builder.addOpPrivateGroupAgg(ast.AggFuncCount, operator.OpNameGroupCount, groupId, groupNum,\n\t\t\t[]*graph.Tensor{groupId}, []*graph.Tensor{k.simpleCountOutputs[idx]}, map[string]*graph.Attribute{}, k.partyCode); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t}\n\t}\n\n\tk.argFuncOutputs = make([]*graph.Tensor, len(groupAgg.argFuncOutputs))\n\tfor idx, aggFunc := range groupAgg.aggFuncsWithArg {\n\t\toutput, err := builder.tm.CreateAndSetFirstTensor(groupAgg.argFuncOutputs[idx], &privatePlacement{partyCode: k.aggArgs[idx].OwnerPartyCode})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t}\n\t\tk.argFuncOutputs[idx] = output\n\n\t\t// TODO handle aggFunc in addOpPrivateGroupAgg\n\t\tswitch aggFunc.Name {\n\t\tcase ast.AggFuncCount:\n\t\t\tswitch aggFunc.Mode {\n\t\t\tcase aggregation.CompleteMode:\n\t\t\t\tif aggFunc.HasDistinct {\n\t\t\t\t\tif err := builder.addOpPrivateGroupAgg(\"count_distinct\", operator.OpNameGroupCountDistinct, groupId, groupNum,\n\t\t\t\t\t\t[]*graph.Tensor{k.aggArgs[idx]}, []*graph.Tensor{k.argFuncOutputs[idx]}, map[string]*graph.Attribute{}, k.partyCode); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// simpleCount: aggFunc.Mode == aggregation.CompleteMode && !aggFunc.HasDistinct\n\t\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg: aggFuncs are not divided properly\")\n\t\t\t\t}\n\t\t\tcase aggregation.FinalMode:\n\t\t\t\t// In AggFunc Count with FinalMode, we need to sum the count of each group to get the final count\n\t\t\t\tif err := builder.addOpPrivateGroupAgg(\"final_count_sum\", operator.OpNameGroupSum, groupId, groupNum,\n\t\t\t\t\t[]*graph.Tensor{k.aggArgs[idx]}, []*graph.Tensor{k.argFuncOutputs[idx]}, map[string]*graph.Attribute{}, k.partyCode); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: unsupported aggregation mode: %v\", aggFunc.Mode)\n\t\t\t}\n\t\tcase ast.AggFuncFirstRow, ast.AggFuncMin, ast.AggFuncMax:\n\t\t\tif err := builder.addOpPrivateGroupAgg(aggFunc.Name, operator.GroupAggOp[aggFunc.Name], groupId, groupNum,\n\t\t\t\t[]*graph.Tensor{k.aggArgs[idx]}, []*graph.Tensor{k.argFuncOutputs[idx]}, map[string]*graph.Attribute{}, k.partyCode); err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t\t}\n\t\tcase ast.AggPercentileDisc:\n\t\t\tif len(aggFunc.Args) != 2 {\n\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: AggPercentileDisc args length is not 2\")\n\t\t\t}\n\t\t\tattrs := map[string]*graph.Attribute{}\n\t\t\tattr := &graph.Attribute{}\n\t\t\tpercent, err := strconv.ParseFloat(aggFunc.Args[1].String(), 64)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg: %s is not a valid float value\", aggFunc.Args[1].String())\n\t\t\t}\n\t\t\tif percent < 0 || percent > 1 {\n\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg: percent should be in [0, 1], but got %v\", percent)\n\t\t\t}\n\t\t\tattr.SetDouble(percent)\n\t\t\tattrs[operator.PercentAttr] = attr\n\n\t\t\tif err := builder.addOpPrivateGroupAgg(aggFunc.Name, operator.GroupAggOp[aggFunc.Name], groupId, groupNum,\n\t\t\t\t[]*graph.Tensor{k.aggArgs[idx]}, []*graph.Tensor{k.argFuncOutputs[idx]}, attrs, k.partyCode); err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t\t}\n\n\t\tcase ast.AggFuncSum, ast.AggFuncAvg:\n\t\t\tif k.aggArgs[idx].OwnerPartyCode == k.partyCode {\n\t\t\t\tif err := builder.addOpPrivateGroupAgg(aggFunc.Name, operator.GroupAggOp[aggFunc.Name], groupId, groupNum,\n\t\t\t\t\t[]*graph.Tensor{k.aggArgs[idx]}, []*graph.Tensor{k.argFuncOutputs[idx]}, map[string]*graph.Attribute{}, k.partyCode); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// run secret agg for other party's tensor\n\t\t\t\t// 1. convert to shared tensor\n\t\t\t\tpublicGroupNum, err := builder.convertStatus(groupNum, &publicPlacement{}, false)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t}\n\t\t\t\tsecretGroupId, err := builder.convertStatus(groupId, &secretPlacement{}, false)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t}\n\t\t\t\tsecretArg, err := builder.convertStatus(k.aggArgs[idx], &secretPlacement{}, false)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t}\n\t\t\t\tsecretAgg := builder.tm.CreateTensorAs(secretArg)\n\t\t\t\tsecretAgg.DType = inferAggOutputType(aggFunc, secretAgg.DType)\n\t\t\t\tsecretAgg.Name = fmt.Sprintf(\"%s_%s\", secretAgg.Name, aggFunc.Name)\n\t\t\t\t// 2. run secret sum\n\t\t\t\tif err := builder.addOpGroupSecretAgg(aggFunc.Name, secretGroupId, publicGroupNum, secretArg, secretAgg); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t}\n\t\t\t\t// 3. convert result to private result tensor\n\t\t\t\tattr := &graph.Attribute{}\n\t\t\t\tattr.SetString(k.argFuncOutputs[idx].OwnerPartyCode)\n\t\t\t\tif err := builder.addEngineNode(\"make_private\", operator.OpNameMakePrivate, map[string][]*graph.Tensor{\"In\": {secretAgg}},\n\t\t\t\t\tmap[string][]*graph.Tensor{\"Out\": {output}}, map[string]*graph.Attribute{operator.RevealToAttr: attr}, builder.GetAllParties()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: make private failed: %v\", err)\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: unsupported aggFunc: %s\", aggFunc.Name)\n\t\t}\n\n\t}\n\n\treturn nil\n}\n\ntype KernelObliviousGroupAgg struct {\n\tprivateSortParty string\n\trevealGroupMark  bool\n\n\t// Bonded tensors in this kernel\n\tgroupKeys          []*graph.Tensor\n\taggArgs            []*graph.Tensor\n\tsimpleCountOutputs []*graph.Tensor\n\targFuncOutputs     []*graph.Tensor\n}\n\nfunc (k *KernelObliviousGroupAgg) Cost() float64 {\n\tif k.privateSortParty == \"\" {\n\t\t// no private sort party, we need to sort the tensor in secret, which is very expensive\n\t\tif k.revealGroupMark {\n\t\t\t// reveal group mark can avoid shuffling\n\t\t\treturn 0.95\n\t\t}\n\t\treturn 1.0\n\t}\n\n\tif k.revealGroupMark {\n\t\treturn 0.75\n\t}\n\treturn 0.8\n}\n\nfunc (k *KernelObliviousGroupAgg) String() string {\n\treturn fmt.Sprintf(\"KernelObliviousGroupAgg(privateSortParty = %s, revealGroupMark = %t)\", k.privateSortParty, k.revealGroupMark)\n}\n\nfunc (k *KernelObliviousGroupAgg) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tgroupAgg, ok := node.(*OperatorGroupAgg)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg ensureTensorPlace: expect GroupAgg node, but got %T\", node)\n\t}\n\n\tk.groupKeys, err = createPlacedTensors(builder, groupAgg.groupKeys, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg ensureTensorPlace: %w\", err)\n\t}\n\tk.aggArgs, err = createPlacedTensors(builder, groupAgg.aggArgs, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelObliviousGroupAgg) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tgroupAgg, ok := node.(*OperatorGroupAgg)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: expect GroupAgg node, but got %T\", node)\n\t}\n\n\t// sort inputs by keys\n\t// FIXME different with buildObliviousGroupAggregation, which sort/shuffle then build expression.\n\t// Here we build expression before sort/shuffle.\n\tsortInputs := make([]*graph.Tensor, 0, len(k.groupKeys)+len(k.aggArgs))\n\tsortInputs = append(sortInputs, k.groupKeys...)\n\tsortInputs = append(sortInputs, k.aggArgs...)\n\tif k.privateSortParty != \"\" {\n\t\tshuffledInputs := make([]*graph.Tensor, 0, len(sortInputs))\n\t\tfor _, input := range sortInputs {\n\t\t\ttensor := builder.tm.CreateTensorAs(input)\n\t\t\tshuffledInputs = append(shuffledInputs, tensor)\n\t\t}\n\t\tif err := builder.addOpShuffle(sortInputs, shuffledInputs); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t}\n\n\t\t// privateSortParty is visible for key after groupby, key can reveal to privateSortParty in groupby.\n\t\t// which the safety is same with revealing to privateSortParty after groupby\n\n\t\tshuffledKeys := shuffledInputs[:len(k.groupKeys)]\n\t\tprivateKeys := make([]*graph.Tensor, 0, len(shuffledKeys))\n\t\tfor _, secretKey := range shuffledKeys {\n\t\t\tprivateKey, err := builder.convertStatus(secretKey, &privatePlacement{partyCode: k.privateSortParty}, false)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t\t}\n\t\t\tprivateKeys = append(privateKeys, privateKey)\n\t\t}\n\n\t\t// convert to secret again to meet the status requirement of op sort\n\t\tsecretKeys := make([]*graph.Tensor, 0, len(privateKeys))\n\t\tfor _, privateKey := range privateKeys {\n\t\t\tsecretKey, err := builder.convertStatus(privateKey, &secretPlacement{}, false)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t\t}\n\t\t\tsecretKeys = append(secretKeys, secretKey)\n\t\t}\n\n\t\tsortInputs = sortInputs[:0]\n\t\tsortInputs = append(sortInputs, secretKeys...)\n\t\tsortInputs = append(sortInputs, shuffledInputs[len(k.groupKeys):]...)\n\t}\n\n\tsortOutputs := make([]*graph.Tensor, 0, len(sortInputs))\n\tfor _, input := range sortInputs {\n\t\t// TODO: check sorted tensor status\n\t\ttensor := builder.tm.CreateTensorAs(input)\n\t\tsortOutputs = append(sortOutputs, tensor)\n\t}\n\tsortKeys := sortInputs[:len(k.groupKeys)]\n\tif err := builder.addOpSort(sortKeys, sortInputs, sortOutputs, slices.Repeat([]bool{false}, len(sortKeys))); err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t}\n\tsortedKeys := sortOutputs[:len(k.groupKeys)]\n\tsortedPayloads := sortOutputs[len(k.groupKeys):]\n\n\t// create group mark\n\tgroupMark := builder.tm.CreateUnbondedTensor(\"group_mark\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_BOOL), &secretPlacement{})\n\tif err := builder.addOpObliviousGroupMark(sortedKeys, groupMark); err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t}\n\n\t// handle agg funcs\n\taggregatedValues := make([]*graph.Tensor, 0, len(groupAgg.argFuncOutputs)+len(groupAgg.simpleCountOutputs))\n\n\t// FIXME simple count once and only\n\tfor range groupAgg.simpleCountOutputs {\n\t\taggregatedValue := builder.tm.CreateUnbondedTensor(\"aggregated_group_simple_count\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64), &secretPlacement{})\n\t\taggregatedValues = append(aggregatedValues, aggregatedValue)\n\t\tif err := builder.addOpObliviousGroupAgg(ast.AggFuncCount, groupMark, groupMark, aggregatedValue, map[string]*graph.Attribute{}); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t}\n\t}\n\n\tfor idx, aggFunc := range groupAgg.aggFuncsWithArg {\n\t\tswitch aggFunc.Name {\n\t\tcase ast.AggFuncFirstRow:\n\t\t\taggregatedValues = append(aggregatedValues, sortedPayloads[idx])\n\t\tcase ast.AggPercentileDisc:\n\t\t\t// Sort the column along with group keys for percentile calculation\n\t\t\tkeysForPercentileSort := make([]*graph.Tensor, 0, len(sortedKeys)+1)\n\t\t\tkeysForPercentileSort = append(keysForPercentileSort, sortedKeys...)\n\t\t\tkeysForPercentileSort = append(keysForPercentileSort, sortedPayloads[idx])\n\n\t\t\tsortedCol := builder.tm.CreateTensorAs(sortedPayloads[idx])\n\t\t\tsortedCol.Name = \"sorted_percentile_\" + sortedCol.Name\n\t\t\tsortOutputs := []*graph.Tensor{sortedCol}\n\n\t\t\tif err := builder.addOpSort(keysForPercentileSort, []*graph.Tensor{sortedPayloads[idx]}, sortOutputs, slices.Repeat([]bool{false}, len(keysForPercentileSort))); err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t\t}\n\n\t\t\t// Parse and validate percentile value\n\t\t\tif len(aggFunc.Args) != 2 {\n\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: AggPercentileDisc expects 2 args, got %d\", len(aggFunc.Args))\n\t\t\t}\n\n\t\t\tpercent, err := strconv.ParseFloat(aggFunc.Args[1].String(), 64)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %s is not a valid float value\", aggFunc.Args[1].String())\n\t\t\t}\n\n\t\t\tif percent < 0 || percent > 1 {\n\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: percent should be in [0, 1], but got %v\", percent)\n\t\t\t}\n\n\t\t\t// Create aggregated value tensor with percentile\n\t\t\taggregatedValue := builder.tm.CreateTensorAs(sortedPayloads[idx])\n\t\t\taggregatedValue.DType = inferAggOutputType(aggFunc, aggregatedValue.DType)\n\t\t\taggregatedValue.Name = fmt.Sprintf(\"%s_%s\", aggregatedValue.Name, aggFunc.Name)\n\t\t\taggregatedValue.SetStatus(proto.TensorStatus_TENSORSTATUS_SECRET)\n\t\t\taggregatedValues = append(aggregatedValues, aggregatedValue)\n\n\t\t\t// Create attribute for percentile\n\t\t\tattrs := map[string]*graph.Attribute{}\n\t\t\tattr := &graph.Attribute{}\n\t\t\tattr.SetDouble(percent)\n\t\t\tattrs[operator.PercentAttr] = attr\n\n\t\t\t// Add oblivious group aggregation with percentile\n\t\t\tif err := builder.addOpObliviousGroupAgg(aggFunc.Name, groupMark, sortedCol, aggregatedValue, attrs); err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t\t}\n\n\t\tcase ast.AggFuncSum, ast.AggFuncMax, ast.AggFuncMin, ast.AggFuncAvg:\n\t\t\taggregatedValue := builder.tm.CreateTensorAs(sortedPayloads[idx])\n\t\t\taggregatedValue.DType = inferAggOutputType(aggFunc, aggregatedValue.DType)\n\t\t\taggregatedValue.Name = fmt.Sprintf(\"%s_%s\", aggregatedValue.Name, aggFunc.Name)\n\t\t\taggregatedValue.SetStatus(proto.TensorStatus_TENSORSTATUS_SECRET)\n\t\t\taggregatedValues = append(aggregatedValues, aggregatedValue)\n\t\t\tif err := builder.addOpObliviousGroupAgg(aggFunc.Name, groupMark, sortedPayloads[idx], aggregatedValue, map[string]*graph.Attribute{}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t\t}\n\t\tcase ast.AggFuncCount:\n\t\t\t// NOTE(yang.y): There are two mode for count function.\n\t\t\t// - The CompleteMode is the default mode in queries like `select count(*) from t`.\n\t\t\t//   In this mode, count function should be translated to ObliviousGroupCount.\n\t\t\t// - The FinalMode appears at `select count(*) from (t1 union all t2)`.\n\t\t\t//   The aggregation push down optimizer will rewrite the query plan to\n\t\t\t//   `select count_final(*) from (select count(*) from t1 union all select count(*) from t2)`.\n\t\t\t//   In this mode, count function will be translated to ObliviousGroupSum.\n\t\t\taggregatedValue := builder.tm.CreateTensorAs(sortedPayloads[idx])\n\t\t\taggregatedValue.DType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64)\n\t\t\taggregatedValue.Name = fmt.Sprintf(\"%s_%s\", aggregatedValue.Name, aggFunc.Name)\n\t\t\taggregatedValue.SetStatus(proto.TensorStatus_TENSORSTATUS_SECRET)\n\t\t\taggregatedValues = append(aggregatedValues, aggregatedValue)\n\t\t\tswitch aggFunc.Mode {\n\t\t\tcase aggregation.CompleteMode:\n\t\t\t\t// do complete count\n\t\t\t\tif aggFunc.HasDistinct {\n\t\t\t\t\t// Sort with group by key(maybe keyTs or groupIds) and distinct column.\n\t\t\t\t\t// Please note that group by key is the major sort key,\n\t\t\t\t\t// so the groupMark is still valid.\n\t\t\t\t\tkeyAndDistinct := make([]*graph.Tensor, 0, len(sortedKeys)+1)\n\t\t\t\t\tkeyAndDistinct = append(keyAndDistinct, sortedKeys...)\n\t\t\t\t\tkeyAndDistinct = append(keyAndDistinct, sortedPayloads[idx])\n\n\t\t\t\t\tsortedDistinctCol := builder.tm.CreateTensorAs(sortedPayloads[idx])\n\t\t\t\t\tif err := builder.addOpSort(keyAndDistinct, []*graph.Tensor{sortedPayloads[idx]}, []*graph.Tensor{sortedDistinctCol}, slices.Repeat([]bool{false}, len(keyAndDistinct))); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use group by keys and distinctCol to create groupMarkFull,\n\t\t\t\t\t// which is equivalent to the result of groupMark logic or groupMarkDistinct\n\t\t\t\t\tgroupMarkDistinct := builder.tm.CreateUnbondedTensor(\"group_mark_distinct\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_BOOL), &secretPlacement{})\n\t\t\t\t\tif err := builder.addOpObliviousGroupMark([]*graph.Tensor{sortedDistinctCol}, groupMarkDistinct); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tgroupMarkFull := builder.tm.CreateTensorAs(groupMarkDistinct)\n\t\t\t\t\tgroupMarkFull.SetStatus(proto.TensorStatus_TENSORSTATUS_SECRET)\n\t\t\t\t\tgroupMarkFull.Name = \"group_mark_full\"\n\t\t\t\t\tif err := builder.addOpBinaryFunc(ast.LogicOr, groupMark, groupMarkDistinct, groupMarkFull); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tif err := builder.addOpObliviousGroupAgg(ast.AggFuncSum, groupMark, groupMarkFull, aggregatedValue, map[string]*graph.Attribute{}); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// simpleCount: aggFunc.Mode == aggregation.CompleteMode && !aggFunc.HasDistinct\n\t\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg: aggFuncs are not divided properly\")\n\t\t\t\t}\n\t\t\tcase aggregation.FinalMode:\n\t\t\t\t// sum up partial count\n\t\t\t\tif err := builder.addOpObliviousGroupAgg(ast.AggFuncSum, groupMark, sortedPayloads[idx], aggregatedValue, map[string]*graph.Attribute{}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: unsupported agg func mode %v\", aggFunc.Mode)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: unsupported agg func %s\", aggFunc.Name)\n\t\t}\n\t}\n\n\t// TODO(jingshi): temporary remove shuffle here for simplicity, make group_mark public and support aggregation with public group_mark later for efficiency\n\tif !k.revealGroupMark {\n\t\tvalueAndMark := make([]*graph.Tensor, 0, len(aggregatedValues)+1)\n\t\tvalueAndMark = append(valueAndMark, aggregatedValues...)\n\t\tvalueAndMark = append(valueAndMark, groupMark)\n\n\t\tshuffledValueAndMark := make([]*graph.Tensor, 0, len(aggregatedValues)+1)\n\t\tfor _, tensor := range valueAndMark {\n\t\t\tshuffled := builder.tm.CreateTensorAs(tensor)\n\t\t\tshuffledValueAndMark = append(shuffledValueAndMark, shuffled)\n\t\t}\n\t\tif err := builder.addOpShuffle(valueAndMark, shuffledValueAndMark); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t}\n\t\taggregatedValues = shuffledValueAndMark[:len(aggregatedValues)]\n\t\tgroupMark = shuffledValueAndMark[len(shuffledValueAndMark)-1]\n\t}\n\n\tgroupMarkPub, err := builder.convertStatus(groupMark, &publicPlacement{}, false)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t}\n\n\t// filter to only keep group aggregated values\n\tfiltered := make([]*graph.Tensor, 0, len(aggregatedValues))\n\tk.simpleCountOutputs = make([]*graph.Tensor, 0, len(groupAgg.simpleCountOutputs))\n\tfor idx, meta := range groupAgg.simpleCountOutputs {\n\t\tplacement := extractTensorPlacement(aggregatedValues[idx])\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, placement)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t}\n\t\tfiltered = append(filtered, tensor)\n\t\tk.simpleCountOutputs = append(k.simpleCountOutputs, tensor)\n\t}\n\tk.argFuncOutputs = make([]*graph.Tensor, 0, len(groupAgg.argFuncOutputs))\n\tfor idx, meta := range groupAgg.argFuncOutputs {\n\t\tplacement := extractTensorPlacement(aggregatedValues[idx+len(groupAgg.simpleCountOutputs)])\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, placement)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t\t}\n\t\tfiltered = append(filtered, tensor)\n\t\tk.argFuncOutputs = append(k.argFuncOutputs, tensor)\n\t}\n\tif err := builder.addOpFilter(groupMarkPub, aggregatedValues, filtered, builder.GetAllParties()); err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousGroupAgg toEngineNodes: %w\", err)\n\t}\n\treturn nil\n}\n\ntype KernelCrossJoin struct {\n\tleftParty, rightParty string\n\n\t// Bonded tensors in this kernel\n\tleftInputs   []*graph.Tensor\n\trightInputs  []*graph.Tensor\n\tleftOutputs  []*graph.Tensor\n\trightOutputs []*graph.Tensor\n}\n\nfunc (k *KernelCrossJoin) Cost() float64 {\n\t// currently, there is only one kernel for cross join\n\treturn 0.0\n}\n\nfunc (k *KernelCrossJoin) String() string {\n\treturn fmt.Sprintf(\"KernelCrossJoin(leftParty: %s, rightParty: %s)\", k.leftParty, k.rightParty)\n}\n\nfunc (k *KernelCrossJoin) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tcrossJoin, ok := node.(*OperatorCrossJoin)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelCrossJoin ensureTensorPlace: expect CrossJoin node, but got %T\", node)\n\t}\n\n\tk.leftInputs, err = createPlacedTensors(builder, crossJoin.leftInputs, &privatePlacement{partyCode: k.leftParty})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelCrossJoin ensureTensorPlace: %w\", err)\n\t}\n\n\tk.rightInputs, err = createPlacedTensors(builder, crossJoin.rightInputs, &privatePlacement{partyCode: k.rightParty})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelCrossJoin ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelCrossJoin) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tcrossJoin, ok := node.(*OperatorCrossJoin)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelCrossJoin toEngineNodes: expect CrossJoin node, but got %T\", node)\n\t}\n\n\tk.leftOutputs = make([]*graph.Tensor, len(crossJoin.leftOutputs))\n\tfor idx, meta := range crossJoin.leftOutputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: k.leftParty})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelCrossJoin toEngineNodes: %w\", err)\n\t\t}\n\t\tk.leftOutputs[idx] = tensor\n\t}\n\n\tk.rightOutputs = make([]*graph.Tensor, len(crossJoin.rightOutputs))\n\tfor idx, meta := range crossJoin.rightOutputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: k.rightParty})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelCrossJoin toEngineNodes: %w\", err)\n\t\t}\n\t\tk.rightOutputs[idx] = tensor\n\t}\n\n\tif err := builder.addOpReplicate(k.leftInputs, k.rightInputs, k.leftOutputs, k.rightOutputs, []string{k.leftParty, k.rightParty}); err != nil {\n\t\treturn fmt.Errorf(\"KernelCrossJoin toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelLimit struct {\n\t// Bonded tensors in this kernel\n\tinputs  []*graph.Tensor\n\toutputs []*graph.Tensor\n}\n\nfunc (k *KernelLimit) Cost() float64 {\n\t// the efficiency of applying the limit is similar across various statuses\n\treturn 0.0\n}\n\nfunc (k *KernelLimit) String() string {\n\treturn \"KernelLimit\"\n}\n\nfunc (k *KernelLimit) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tlimit, ok := node.(*OperatorLimit)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelLimit ensureTensorPlace: expect Limit node, but got %T\", node)\n\t}\n\n\tk.inputs = make([]*graph.Tensor, len(limit.inputs))\n\tfor idx, meta := range limit.inputs {\n\t\ttensor, err := builder.tm.getOnePlacedTensor(meta)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelLimit ensureTensorPlace: %w\", err)\n\t\t}\n\t\tk.inputs[idx] = tensor\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelLimit) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tlimit, ok := node.(*OperatorLimit)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelLimit toEngineNodes: expect Limit node, but got %T\", node)\n\t}\n\n\t// Create output placed tensors and store in kernel\n\tk.outputs = make([]*graph.Tensor, len(limit.outputs))\n\tvar allPartyInputs []*graph.Tensor\n\tvar allPartyOutputs []*graph.Tensor\n\tprivateInputs := make(map[string][]*graph.Tensor)\n\tprivateOutputs := make(map[string][]*graph.Tensor)\n\tfor idx, meta := range limit.outputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, extractTensorPlacement(k.inputs[idx]))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelLimit toEngineNodes: %w\", err)\n\t\t}\n\t\tk.outputs[idx] = tensor\n\n\t\t// divide input/output tensor into groups to handle different parties\n\t\tswitch tensor.Status() {\n\t\tcase proto.TensorStatus_TENSORSTATUS_PRIVATE:\n\t\t\tprivateInputs[tensor.OwnerPartyCode] = append(privateInputs[tensor.OwnerPartyCode], k.inputs[idx])\n\t\t\tprivateOutputs[tensor.OwnerPartyCode] = append(privateOutputs[tensor.OwnerPartyCode], tensor)\n\t\tcase proto.TensorStatus_TENSORSTATUS_PUBLIC, proto.TensorStatus_TENSORSTATUS_SECRET:\n\t\t\tallPartyInputs = append(allPartyInputs, k.inputs[idx])\n\t\t\tallPartyOutputs = append(allPartyOutputs, k.outputs[idx])\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"KernelLimit toEngineNodes: unexpected tensor status %s\", tensor.Status())\n\t\t}\n\t}\n\n\tif len(allPartyInputs) != 0 {\n\t\tif err := builder.addOpLimit(allPartyInputs, allPartyOutputs, int64(limit.offset), int64(limit.count), builder.GetAllParties()); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelLimit toEngineNodes: %w\", err)\n\t\t}\n\t}\n\tfor party, inputs := range sliceutil.SortedMap(privateInputs) {\n\t\tif err := builder.addOpLimit(inputs, privateOutputs[party], int64(limit.offset), int64(limit.count), []string{party}); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelLimit toEngineNodes: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\ntype KernelFilter struct {\n\tinputPlacements []tensorPlacement\n\n\t// Bonded tensors in this kernel\n\tinputs  []*graph.Tensor\n\toutputs []*graph.Tensor\n}\n\nfunc (k *KernelFilter) Cost() float64 {\n\t// TODO: benchmark the cost of filter\n\treturn 0.0\n}\n\nfunc (k *KernelFilter) String() string {\n\treturn \"KernelFilter\"\n}\n\nfunc (k *KernelFilter) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfilter, ok := node.(*OperatorFilter)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelFilter ensureTensorPlace: expect Filter node, but got %T\", node)\n\t}\n\n\tk.inputs = make([]*graph.Tensor, len(filter.inputs))\n\tfor idx, meta := range filter.inputs {\n\t\ttensor, err := builder.getOrCreatePlacedTensor(meta, k.inputPlacements[idx])\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelFilter ensureTensorPlace: %w\", err)\n\t\t}\n\t\tk.inputs[idx] = tensor\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelFilter) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfilter, ok := node.(*OperatorFilter)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelFilter toEngineNodes: expect Filter node, but got %T\", node)\n\t}\n\n\tk.outputs = make([]*graph.Tensor, len(filter.outputs))\n\tfor idx, meta := range filter.outputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, extractTensorPlacement(k.inputs[idx]))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelFilter toEngineNodes: %w\", err)\n\t\t}\n\t\tk.outputs[idx] = tensor\n\t}\n\n\tpartyIndexes := make(map[string][]int)\n\tsecretIndexes := make([]int, 0)\n\tfor idx, input := range k.inputs {\n\t\tif input.Status() == proto.TensorStatus_TENSORSTATUS_SECRET {\n\t\t\tsecretIndexes = append(secretIndexes, idx)\n\t\t} else if input.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\t\tpartyIndexes[input.OwnerPartyCode] = append(partyIndexes[input.OwnerPartyCode], idx)\n\t\t}\n\t}\n\n\tfor party, indexes := range sliceutil.SortedMap(partyIndexes) {\n\t\tsort.Slice(indexes, func(i, j int) bool { return k.inputs[indexes[i]].ID < k.inputs[indexes[j]].ID })\n\n\t\tprivateInputs, err := sliceutil.TakeByIndices(k.inputs, indexes)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelFilter toEngineNodes: %w\", err)\n\t\t}\n\t\tprivateOutputs, err := sliceutil.TakeByIndices(k.outputs, indexes)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelFilter toEngineNodes: %w\", err)\n\t\t}\n\n\t\tprivateMask, err := builder.getOrCreatePlacedTensor(filter.mask, &privatePlacement{partyCode: party})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelFilter toEngineNodes: %w\", err)\n\t\t}\n\n\t\tif err := builder.addOpFilter(privateMask, privateInputs, privateOutputs, []string{party}); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelFilter toEngineNodes: %w\", err)\n\t\t}\n\t}\n\n\tif len(secretIndexes) > 0 {\n\t\tsecretInputs, err := sliceutil.TakeByIndices(k.inputs, secretIndexes)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelFilter toEngineNodes: %w\", err)\n\t\t}\n\t\tsecretOutputs, err := sliceutil.TakeByIndices(k.outputs, secretIndexes)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelFilter toEngineNodes: %w\", err)\n\t\t}\n\n\t\tpublicMask, err := builder.getOrCreatePlacedTensor(filter.mask, &publicPlacement{})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelFilter toEngineNodes: %w\", err)\n\t\t}\n\n\t\tif err := builder.addOpFilter(publicMask, secretInputs, secretOutputs, builder.GetAllParties()); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelFilter toEngineNodes: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\ntype KernelSecretConcat struct {\n\t// Bonded tensors in this kernel\n\tinputs []*graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelSecretConcat) Cost() float64 {\n\t// only one kernel for concat for now\n\treturn 0.0\n}\n\nfunc (k *KernelSecretConcat) String() string {\n\treturn \"KernelSecretConcat\"\n}\n\nfunc (k *KernelSecretConcat) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tconcat, ok := node.(*OperatorConcat)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelSecretConcat ensureTensorPlace: expect Concat node, but got %T\", node)\n\t}\n\n\tk.inputs, err = createPlacedTensors(builder, concat.inputs, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretConcat ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelSecretConcat) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tconcat, ok := node.(*OperatorConcat)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelSecretConcat toEngineNodes: expect Concat node, but got %T\", node)\n\t}\n\n\ttensor, err := builder.tm.CreateAndSetFirstTensor(concat.output, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretConcat toEngineNodes: %w\", err)\n\t}\n\tfor _, input := range k.inputs {\n\t\ttensor.SecretStringOwners = append(tensor.SecretStringOwners, input.SecretStringOwners...)\n\t}\n\tk.output = tensor\n\n\tif err := builder.addOpConcat(k.inputs, k.output); err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretConcat toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelSecretSort struct {\n\t// Bonded tensors in this kernel\n\tsortKeys []*graph.Tensor\n\tpayloads []*graph.Tensor\n\toutputs  []*graph.Tensor\n}\n\nfunc (k *KernelSecretSort) Cost() float64 {\n\t// secret sort is very expensive\n\treturn 1.0\n}\n\nfunc (k *KernelSecretSort) String() string {\n\treturn \"KernelSecretSort\"\n}\n\nfunc (k *KernelSecretSort) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tsort, ok := node.(*OperatorSort)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelSecretSort ensureTensorPlace: expect Sort node, but got %T\", node)\n\t}\n\n\tk.sortKeys, err = createPlacedTensors(builder, sort.sortKeys, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretSort ensureTensorPlace: %w\", err)\n\t}\n\n\tk.payloads, err = createPlacedTensors(builder, sort.payloads, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretSort ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelSecretSort) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tsort, ok := node.(*OperatorSort)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelSecretSort toEngineNodes: expect Sort node, but got %T\", node)\n\t}\n\n\tk.outputs = make([]*graph.Tensor, len(sort.outputs))\n\tfor idx, meta := range sort.outputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, &secretPlacement{})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelSecretSort toEngineNodes: %w\", err)\n\t\t}\n\t\tk.outputs[idx] = tensor\n\t}\n\n\tif err := builder.addOpSort(k.sortKeys, k.payloads, k.outputs, sort.descending); err != nil {\n\t\treturn fmt.Errorf(\"KernelSecretSort toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelPrivateSort struct {\n\tpartyCode string\n\n\t// Bonded tensors in this kernel\n\tsortKeys []*graph.Tensor\n\tpayloads []*graph.Tensor\n\toutputs  []*graph.Tensor\n}\n\nfunc (k *KernelPrivateSort) Cost() float64 {\n\t// chepeast sort kernel\n\treturn 0.0\n}\n\nfunc (k *KernelPrivateSort) String() string {\n\treturn fmt.Sprintf(\"KernelPrivateSort(partyCode: %s)\", k.partyCode)\n}\n\nfunc (k *KernelPrivateSort) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tsort, ok := node.(*OperatorSort)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPrivateSort ensureTensorPlace: expect Sort node, but got %T\", node)\n\t}\n\n\tk.sortKeys, err = createPlacedTensors(builder, sort.sortKeys, &privatePlacement{partyCode: k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateSort ensureTensorPlace: %w\", err)\n\t}\n\n\tk.payloads, err = createPlacedTensors(builder, sort.payloads, &privatePlacement{partyCode: k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateSort ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelPrivateSort) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tsort, ok := node.(*OperatorSort)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPrivateSort toEngineNodes: expect Sort node, but got %T\", node)\n\t}\n\n\tk.outputs = make([]*graph.Tensor, len(sort.outputs))\n\tfor idx, meta := range sort.outputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: k.partyCode})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPrivateSort toEngineNodes: %w\", err)\n\t\t}\n\t\tk.outputs[idx] = tensor\n\t}\n\n\tif err := builder.addOpSort(k.sortKeys, k.payloads, k.outputs, sort.descending); err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateSort toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelConstant struct {\n}\n\nfunc (k *KernelConstant) Cost() float64 {\n\t// always emit public tensor\n\treturn 0.0\n}\n\nfunc (k *KernelConstant) String() string {\n\treturn \"KernelConstant\"\n}\n\nfunc (k *KernelConstant) ensureTensorPlace(_ *ExecutionGraphBuilder, _ Operator) (err error) {\n\treturn nil\n}\n\nfunc (k *KernelConstant) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tconstant, ok := node.(*OperatorConstant)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelConstant toEngineNodes: expect Constant node, but got %T\", node)\n\t}\n\n\ttensor, err := builder.tm.CreateAndSetFirstTensor(constant.output, &publicPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelConstant toEngineNodes: %w\", err)\n\t}\n\n\tif err := builder.addOpConstant(constant.value, tensor); err != nil {\n\t\treturn fmt.Errorf(\"KernelConstant toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelLocalIn struct {\n\tpartyCode string\n\n\t// Bonded tensors in this kernel\n\tleft   *graph.Tensor\n\tright  *graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelLocalIn) Cost() float64 {\n\t// local in is cheapest kernel for in\n\treturn 0.0\n}\n\nfunc (k *KernelLocalIn) String() string {\n\treturn fmt.Sprintf(\"KernelLocalIn(partyCode: %s)\", k.partyCode)\n}\n\nfunc (k *KernelLocalIn) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tin, ok := node.(*OperatorIn)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelLocalIn ensureTensorPlace: expect In node, but got %T\", node)\n\t}\n\n\tleftTensor, err := builder.getOrCreatePlacedTensor(in.left, &privatePlacement{k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelLocalIn ensureTensorPlace: %w\", err)\n\t}\n\tk.left = leftTensor\n\n\trightTensor, err := builder.getOrCreatePlacedTensor(in.right, &privatePlacement{k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelLocalIn ensureTensorPlace: %w\", err)\n\t}\n\tk.right = rightTensor\n\n\treturn nil\n}\n\nfunc (k *KernelLocalIn) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tin, ok := node.(*OperatorIn)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelLocalIn toEngineNodes: expect In node, but got %T\", node)\n\t}\n\n\toutputTensor, err := builder.tm.CreateAndSetFirstTensor(in.output, &privatePlacement{k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelLocalIn toEngineNodes: %w\", err)\n\t}\n\tk.output = outputTensor\n\n\tif err := builder.addOpIn(k.left, k.right, k.output, proto.PsiAlgorithmType_AUTO); err != nil {\n\t\treturn fmt.Errorf(\"KernelLocalIn toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelPsiIn struct {\n\tleftParty        string\n\trightParty       string\n\tpsiAlgorithmType proto.PsiAlgorithmType\n\n\t// Bonded tensors in this kernel\n\tleft   *graph.Tensor\n\tright  *graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelPsiIn) Cost() float64 {\n\t// psi in is more expensive than local in but cheaper than secret in (which will be implemented in the future)\n\treturn 0.5\n}\n\nfunc (k *KernelPsiIn) String() string {\n\treturn fmt.Sprintf(\"KernelPsiIn(leftParty: %s, rightParty: %s, psiAlgorithmType: %v)\", k.leftParty, k.rightParty, k.psiAlgorithmType)\n}\n\nfunc (k *KernelPsiIn) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tin, ok := node.(*OperatorIn)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPsiIn ensureTensorPlace: expect In node, but got %T\", node)\n\t}\n\n\tleftTensor, err := builder.getOrCreatePlacedTensor(in.left, &privatePlacement{k.leftParty})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPsiIn ensureTensorPlace: %w\", err)\n\t}\n\tk.left = leftTensor\n\n\trightTensor, err := builder.getOrCreatePlacedTensor(in.right, &privatePlacement{k.rightParty})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPsiIn ensureTensorPlace: %w\", err)\n\t}\n\tk.right = rightTensor\n\n\treturn nil\n}\n\nfunc (k *KernelPsiIn) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tin, ok := node.(*OperatorIn)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPsiIn toEngineNodes: expect In node, but got %T\", node)\n\t}\n\n\t// TODO condider reveal party\n\toutputTensor, err := builder.tm.CreateAndSetFirstTensor(in.output, &privatePlacement{k.leftParty})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPsiIn toEngineNodes: %w\", err)\n\t}\n\tk.output = outputTensor\n\n\tif err := builder.addOpIn(k.left, k.right, k.output, k.psiAlgorithmType); err != nil {\n\t\treturn fmt.Errorf(\"KernelPsiIn toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelArrowFunction struct {\n\tpartyCode string\n\n\t// Bonded tensors in this kernel\n\tinputs []*graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelArrowFunction) Cost() float64 {\n\t// Arrow function is always executed under private placement\n\treturn 0.0\n}\n\nfunc (k *KernelArrowFunction) String() string {\n\treturn fmt.Sprintf(\"KernelArrowFunction(partyCode: %s)\", k.partyCode)\n}\n\nfunc (k *KernelArrowFunction) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelArrowFunction ensureTensorPlace: expect Function node, but got %T\", node)\n\t}\n\n\tk.inputs, err = createPlacedTensors(builder, function.inputs, &privatePlacement{partyCode: k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelArrowFunction ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelArrowFunction) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelArrowFunction toEngineNodes: expect ArrowFunction node, but got %T\", node)\n\t}\n\n\ttensor, err := builder.tm.CreateAndSetFirstTensor(function.output, &privatePlacement{partyCode: k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelArrowFunction toEngineNodes: %w\", err)\n\t}\n\tk.output = tensor\n\n\tvar arrowFuncName string\n\tvar funcOpt compute.FunctionOptions\n\tswitch function.funcName {\n\tcase ast.Trim:\n\t\tarrowFuncName = \"utf8_trim\"\n\t\tfuncOpt = TrimOptions{Characters: \" \"}\n\tcase ast.Lower:\n\t\tarrowFuncName = \"utf8_lower\"\n\tcase ast.Upper:\n\t\tarrowFuncName = \"utf8_upper\"\n\tcase ast.Substr, ast.Substring:\n\t\tarrowFuncName = \"utf8_slice_codeunits\"\n\t\topt := SliceOptions{\n\t\t\tStart: 0,\n\t\t\tStop:  math.MaxInt64,\n\t\t\tStep:  1,\n\t\t}\n\t\tif len(function.constParams) >= 1 {\n\t\t\topt.Start = function.constParams[0].Value.GetInt64() - 1\n\t\t}\n\t\tif len(function.constParams) >= 2 {\n\t\t\tlength := function.constParams[1].Value.GetInt64()\n\t\t\topt.Stop = opt.Start + length\n\t\t}\n\t\tfuncOpt = opt\n\tcase ast.StrToDate:\n\t\tarrowFuncName = \"strptime\"\n\t\tformatStr := function.constParams[0].Value.GetString()\n\t\tarrowFormatStr, err := stringutil.MySQLDateFormatToArrowFormat(formatStr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelArrowFunction toEngineNodes: format string '%s' is invalid: %w\", formatStr, err)\n\t\t}\n\t\tfuncOpt = &StrptimeOptions{\n\t\t\tFormat:      arrowFormatStr,\n\t\t\tUnit:        arrow.Second,\n\t\t\tErrorIsNull: true,\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"KernelArrowFunction toEngineNodes: unsupported function %s\", function.funcName)\n\t}\n\tif err := builder.addOpArrowFunc(arrowFuncName, funcOpt, k.inputs, k.output); err != nil {\n\t\treturn fmt.Errorf(\"KernelArrowFunction toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelUnary struct {\n\tplace tensorPlacement\n\n\t// Bonded tensors in this kernel\n\tinput  *graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelUnary) Cost() float64 {\n\tif IsSecret(k.place) {\n\t\treturn 1.0\n\t}\n\treturn 0.0\n}\n\nfunc (k *KernelUnary) String() string {\n\treturn fmt.Sprintf(\"KernelUnary(place: %s)\", k.place)\n}\n\nfunc (k *KernelUnary) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelUnary ensureTensorPlace: expect Function node, but got %T\", node)\n\t}\n\n\tinputTensor, err := builder.getOrCreatePlacedTensor(function.inputs[0], k.place)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelUnary ensureTensorPlace: %w\", err)\n\t}\n\tk.input = inputTensor\n\n\treturn nil\n}\n\nfunc (k *KernelUnary) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelUnary toEngineNodes: expect Function node, but got %T\", node)\n\t}\n\n\toutputTensor, err := builder.tm.CreateAndSetFirstTensor(function.output, extractTensorPlacement(k.input))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelUnary toEngineNodes: %w\", err)\n\t}\n\tk.output = outputTensor\n\n\tif err := builder.addOpBasicFunc(function.funcName, []*graph.Tensor{k.input}, k.output); err != nil {\n\t\treturn fmt.Errorf(\"KernelUnary toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelBinary struct {\n\tlhsPlace, rhsPlace tensorPlacement\n\toutPlace           tensorPlacement\n\n\t// Bonded tensors in this kernel\n\tlhs    *graph.Tensor\n\trhs    *graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelBinary) Cost() float64 {\n\tinputSecretNum := 0\n\tif IsSecret(k.lhsPlace) {\n\t\tinputSecretNum++\n\t}\n\tif IsSecret(k.rhsPlace) {\n\t\tinputSecretNum++\n\t}\n\treturn float64(inputSecretNum) / 2.0\n}\n\nfunc (k *KernelBinary) String() string {\n\treturn fmt.Sprintf(\"KernelBinary(lhs: %s, rhs: %s, out: %s)\", k.lhsPlace, k.rhsPlace, k.outPlace)\n}\n\nfunc (k *KernelBinary) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelBinary ensureTensorPlace: expect Function node, but got %T\", node)\n\t}\n\n\tlhsTensor, err := builder.getOrCreatePlacedTensor(function.inputs[0], k.lhsPlace)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelBinary ensureTensorPlace: %w\", err)\n\t}\n\tk.lhs = lhsTensor\n\n\trhsTensor, err := builder.getOrCreatePlacedTensor(function.inputs[1], k.rhsPlace)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelBinary ensureTensorPlace: %w\", err)\n\t}\n\tk.rhs = rhsTensor\n\n\treturn nil\n}\n\nfunc (k *KernelBinary) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelBinary toEngineNodes: expect Function node, but got %T\", node)\n\t}\n\n\toutputTensor, err := builder.tm.CreateAndSetFirstTensor(function.output, k.outPlace)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelBinary toEngineNodes: %w\", err)\n\t}\n\tk.output = outputTensor\n\n\tif err := builder.addOpBinaryFunc(function.funcName, k.lhs, k.rhs, k.output); err != nil {\n\t\treturn fmt.Errorf(\"KernelBinary toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelVariadicCompare struct {\n\tplacement tensorPlacement\n\n\t// Bonded tensors in this kernel\n\tinputs []*graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelVariadicCompare) Cost() float64 {\n\tif IsSecret(k.placement) {\n\t\treturn 1.0\n\t}\n\treturn 0.0\n}\n\nfunc (k *KernelVariadicCompare) String() string {\n\treturn fmt.Sprintf(\"KernelVariadicCompare(placement: %s)\", k.placement)\n}\n\nfunc (k *KernelVariadicCompare) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelVariadicCompare ensureTensorPlace: expect Function node, but got %T\", node)\n\t}\n\n\tk.inputs, err = createPlacedTensors(builder, function.inputs, k.placement)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelVariadicCompare ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelVariadicCompare) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelVariadicCompare toEngineNodes: expect Function node, but got %T\", node)\n\t}\n\n\toutputTensor, err := builder.tm.CreateAndSetFirstTensor(function.output, k.placement)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelVariadicCompare toEngineNodes: %w\", err)\n\t}\n\tk.output = outputTensor\n\n\tif err := builder.addOpBasicFunc(function.funcName, k.inputs, k.output); err != nil {\n\t\treturn fmt.Errorf(\"KernelVariadicCompare toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelPrivateFunc struct {\n\tpartyCode string\n\n\t// Bonded tensors in this kernel\n\tinputs []*graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelPrivateFunc) Cost() float64 {\n\treturn 0.0\n}\n\nfunc (k *KernelPrivateFunc) String() string {\n\treturn fmt.Sprintf(\"KernelPrivateFunc(partyCode: %s)\", k.partyCode)\n}\n\nfunc (k *KernelPrivateFunc) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPrivateFunc ensureTensorPlace: expect Function node, but got %T\", node)\n\t}\n\n\tk.inputs, err = createPlacedTensors(builder, function.inputs, &privatePlacement{k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateFunc ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelPrivateFunc) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPrivateFunc toEngineNodes: expect Function node, but got %T\", node)\n\t}\n\n\toutputTensor, err := builder.tm.CreateAndSetFirstTensor(function.output, &privatePlacement{k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateFunc toEngineNodes: %w\", err)\n\t}\n\tk.output = outputTensor\n\n\tswitch function.funcName {\n\tcase ast.Ifnull:\n\t\tif err := builder.addOpIfNull(k.inputs[0], k.inputs[1], k.output); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPrivateFunc toEngineNodes: %w\", err)\n\t\t}\n\tcase ast.IsNull:\n\t\tif err := builder.addOpBasicFunc(function.funcName, k.inputs, k.output); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPrivateFunc toEngineNodes: %w\", err)\n\t\t}\n\tcase ast.Coalesce:\n\t\tif err := builder.addOpCoalece(k.inputs, k.output); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPrivateFunc toEngineNodes: %w\", err)\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"KernelPrivateFunc toEngineNodes: not support function %s\", function.funcName)\n\t}\n\n\treturn nil\n}\n\ntype KernelCast struct {\n\tplacement tensorPlacement\n\n\t// Bonded tensors in this kernel\n\tinput  *graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelCast) Cost() float64 {\n\tif IsSecret(k.placement) {\n\t\treturn 1.0\n\t}\n\treturn 0.0\n}\n\nfunc (k *KernelCast) String() string {\n\treturn fmt.Sprintf(\"KernelCast(placement: %s)\", k.placement)\n}\n\nfunc (k *KernelCast) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelCast ensureTensorPlace: expect Function node, but got %T\", node)\n\t}\n\n\ttensor, err := builder.getOrCreatePlacedTensor(function.inputs[0], k.placement)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelCast ensureTensorPlace: %w\", err)\n\t}\n\tk.input = tensor\n\n\treturn nil\n}\n\nfunc (k *KernelCast) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelCast toEngineNodes: expect Function node, but got %T\", node)\n\t}\n\n\toutputTensor, err := builder.tm.CreateAndSetFirstTensor(function.output, k.placement)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelCast toEngineNodes: %w\", err)\n\t}\n\tk.output = outputTensor\n\n\tif err := builder.addOpBasicFunc(function.funcName, []*graph.Tensor{k.input}, k.output); err != nil {\n\t\treturn fmt.Errorf(\"KernelCast toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelIf struct {\n\tcondPlace       tensorPlacement\n\ttrueValuePlace  tensorPlacement\n\tfalseValuePlace tensorPlacement\n\toutputPlace     tensorPlacement\n\n\t// Bonded tensors in this kernel\n\tcond       *graph.Tensor\n\ttrueValue  *graph.Tensor\n\tfalseValue *graph.Tensor\n\toutput     *graph.Tensor\n}\n\nfunc (k *KernelIf) Cost() float64 {\n\tinputSecretNum := 0\n\tif IsSecret(k.condPlace) {\n\t\tinputSecretNum++\n\t}\n\tif IsSecret(k.trueValuePlace) {\n\t\tinputSecretNum++\n\t}\n\tif IsSecret(k.falseValuePlace) {\n\t\tinputSecretNum++\n\t}\n\treturn float64(inputSecretNum) / 3.0\n}\n\nfunc (k *KernelIf) String() string {\n\treturn fmt.Sprintf(\"KernelIf(condPlace: %s, trueValuePlace: %s, falseValuePlace: %s, outputPlace: %s)\", k.condPlace, k.trueValuePlace, k.falseValuePlace, k.outputPlace)\n}\n\nfunc (k *KernelIf) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelIf ensureTensorPlace: expect Function node, but got %T\", node)\n\t}\n\n\tcondTensor, err := builder.getOrCreatePlacedTensor(function.inputs[0], k.condPlace)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelIf ensureTensorPlace: %w\", err)\n\t}\n\tk.cond = condTensor\n\n\ttrueValueTensor, err := builder.getOrCreatePlacedTensor(function.inputs[1], k.trueValuePlace)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelIf ensureTensorPlace: %w\", err)\n\t}\n\tk.trueValue = trueValueTensor\n\n\tfalseValueTensor, err := builder.getOrCreatePlacedTensor(function.inputs[2], k.falseValuePlace)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelIf ensureTensorPlace: %w\", err)\n\t}\n\tk.falseValue = falseValueTensor\n\n\treturn nil\n}\n\nfunc (k *KernelIf) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelIf toEngineNodes: expect Function node, but got %T\", node)\n\t}\n\n\toutputTensor, err := builder.tm.CreateAndSetFirstTensor(function.output, k.outputPlace)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelIf toEngineNodes: %w\", err)\n\t}\n\tk.output = outputTensor\n\n\tif err := builder.addOpIf(k.cond, k.trueValue, k.falseValue, k.output); err != nil {\n\t\treturn fmt.Errorf(\"KernelIf toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelCase struct {\n\tinputPlacements []tensorPlacement\n\toutputPlacement tensorPlacement\n\n\t// Bonded tensors in this kernel\n\tinputs []*graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelCase) Cost() float64 {\n\tinputSecretNum := 0\n\tif IsSecret(k.outputPlacement) {\n\t\tinputSecretNum++\n\t}\n\treturn float64(inputSecretNum) / float64(len(k.inputPlacements))\n}\n\nfunc (k *KernelCase) String() string {\n\treturn fmt.Sprintf(\"KernelCase(inputPlacements: %s, outputPlacement: %s)\", k.inputPlacements, k.outputPlacement)\n}\n\nfunc (k *KernelCase) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelCase ensureTensorPlace: expect Function node, but got %T\", node)\n\t}\n\n\tif len(function.inputs) != len(k.inputPlacements) {\n\t\treturn fmt.Errorf(\"KernelCase ensureTensorPlace: input placements info does not match input tensors\")\n\t}\n\n\tk.inputs = make([]*graph.Tensor, len(function.inputs))\n\tfor idx, meta := range function.inputs {\n\t\ttensor, err := builder.getOrCreatePlacedTensor(meta, k.inputPlacements[idx])\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelCase ensureTensorPlace: %w\", err)\n\t\t}\n\t\tk.inputs[idx] = tensor\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelCase) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelCase toEngineNodes: expect Function node, but got %T\", node)\n\t}\n\n\toutputTensor, err := builder.tm.CreateAndSetFirstTensor(function.output, k.outputPlacement)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelCase toEngineNodes: %w\", err)\n\t}\n\tk.output = outputTensor\n\n\tconditions := make([]*graph.Tensor, 0, len(k.inputs)/2)\n\tvalues := make([]*graph.Tensor, 0, len(k.inputs)/2)\n\tfor i := range len(k.inputs) / 2 {\n\t\tconditions = append(conditions, k.inputs[i*2])\n\t\tvalues = append(values, k.inputs[i*2+1])\n\t}\n\tif err := builder.addOpCaseWhen(conditions, values, k.inputs[len(k.inputs)-1], k.output); err != nil {\n\t\treturn fmt.Errorf(\"KernelCase toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelConcatString struct {\n\tpartyCode string\n\n\t// Bonded tensors in this kernel\n\tinputs []*graph.Tensor\n\toutput *graph.Tensor\n}\n\nfunc (k *KernelConcatString) Cost() float64 {\n\t// ConcatString is always executed under private placement\n\treturn 0.0\n}\n\nfunc (k *KernelConcatString) String() string {\n\treturn fmt.Sprintf(\"KernelConcatString(partyCode: %s)\", k.partyCode)\n}\n\nfunc (k *KernelConcatString) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelConcatString ensureTensorPlace: expect Function node, but got %T\", node)\n\t}\n\n\tk.inputs, err = createPlacedTensors(builder, function.inputs, &privatePlacement{k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelConcatString ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelConcatString) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\tfunction, ok := node.(*OperatorFunction)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelConcatString toEngineNodes: expect Function node, but got %T\", node)\n\t}\n\n\tseparator := types.NewStringDatum(\"\") // only support nil separator now\n\tsepScalar := builder.tm.CreateUnbondedTensor(\"concat_separator\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING), &publicPlacement{})\n\tsepScalar.IsConstScalar = true\n\tif err := builder.addOpConstant(&separator, sepScalar); err != nil {\n\t\treturn nil\n\t}\n\n\trefTensor := k.inputs[0]\n\tsepTensor := builder.tm.CreateTensorAs(refTensor)\n\tsepTensor.DType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING)\n\tsepTensor.Name = \"broadcasted_concat_separator\"\n\tif err := builder.addOpBroadcastTo(refTensor, []*graph.Tensor{sepScalar}, []*graph.Tensor{sepTensor}); err != nil {\n\t\treturn fmt.Errorf(\"KernelConcatString toEngineNodes: %w\", err)\n\t}\n\n\ttensor, err := builder.tm.CreateAndSetFirstTensor(function.output, &privatePlacement{k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelArrowFunction toEngineNodes: %w\", err)\n\t}\n\tk.output = tensor\n\n\tif err := builder.addOpArrowFunc(\"binary_join_element_wise\", nil, append(k.inputs, sepTensor), k.output); err != nil {\n\t\treturn fmt.Errorf(\"KernelArrowFunction toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelPrivateWindow struct {\n\tpartyCode string\n\n\t// Bonded tensors in this kernel\n\torderKeys     []*graph.Tensor\n\tpartitionKeys []*graph.Tensor\n}\n\nfunc (k *KernelPrivateWindow) Cost() float64 {\n\treturn 0.0\n}\n\nfunc (k *KernelPrivateWindow) String() string {\n\treturn \"KernelPrivateRankWindow\"\n}\n\nfunc (k *KernelPrivateWindow) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\twindow, ok := node.(*OperatorWindow)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPrivateRankWindow ensureTensorPlace: expect RankWindow node, but got %T\", node)\n\t}\n\n\tk.orderKeys, err = createPlacedTensors(builder, window.orderKeys, &privatePlacement{k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateRankWindow ensureTensorPlace: %w\", err)\n\t}\n\tk.partitionKeys, err = createPlacedTensors(builder, window.partitionKeys, &privatePlacement{k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateRankWindow ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelPrivateWindow) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\twindow, ok := node.(*OperatorWindow)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelPrivateRankWindow toEngineNodes: expect RankWindow node, but got %T\", node)\n\t}\n\n\tfor idx := range window.payloads {\n\t\t// the payloads are not modified in private rank window\n\t\tif err := builder.tensorMetaManager.setTensorsEquivalent(window.payloads[idx], window.payloadOutputs[idx]); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelPrivateRankWindow toEngineNodes: %w\", err)\n\t\t}\n\t}\n\n\tpartitionId := builder.tm.CreateUnbondedTensor(\"window_group_id\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64), &privatePlacement{k.partyCode})\n\tpartitionNum := builder.tm.CreateUnbondedTensor(\"window_group_num\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64), &privatePlacement{k.partyCode})\n\n\tif err := builder.addOpPrivateGroup(k.partitionKeys, partitionId, partitionNum, k.partyCode); err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateGroupAgg toEngineNodes: %w\", err)\n\t}\n\n\trankTensor, err := builder.tm.CreateAndSetFirstTensor(window.funcOutput, &privatePlacement{partyCode: k.partyCode})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateRankWindow toEngineNodes: %w\", err)\n\t}\n\tif err := builder.addOpPrivateWindow(window.funcName, k.orderKeys, partitionId, partitionNum, rankTensor, window.descs); err != nil {\n\t\treturn fmt.Errorf(\"KernelPrivateRankWindow toEngineNodes: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype KernelObliviousWindow struct {\n\t// Bonded tensors in this kernel\n\torderKeys      []*graph.Tensor\n\tpartitionKeys  []*graph.Tensor\n\tpayloads       []*graph.Tensor\n\tpayloadOutputs []*graph.Tensor\n\tfuncOutput     *graph.Tensor\n}\n\nfunc (k *KernelObliviousWindow) Cost() float64 {\n\treturn 1.0\n}\n\nfunc (k *KernelObliviousWindow) String() string {\n\treturn \"KernelObliviousRankWindow\"\n}\n\nfunc (k *KernelObliviousWindow) ensureTensorPlace(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\twindow, ok := node.(*OperatorWindow)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelObliviousWindow ensureTensorPlace: expect RankWindow node, but got %T\", node)\n\t}\n\n\tk.partitionKeys, err = createPlacedTensors(builder, window.partitionKeys, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousWindow ensureTensorPlace: %w\", err)\n\t}\n\n\tk.orderKeys, err = createPlacedTensors(builder, window.orderKeys, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousWindow ensureTensorPlace: %w\", err)\n\t}\n\n\tk.payloads, err = createPlacedTensors(builder, window.payloads, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousWindow ensureTensorPlace: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *KernelObliviousWindow) toEngineNodes(builder *ExecutionGraphBuilder, node Operator) (err error) {\n\twindow, ok := node.(*OperatorWindow)\n\tif !ok {\n\t\treturn fmt.Errorf(\"KernelObliviousWindow toEngineNodes: expect RankWindow node, but got %T\", node)\n\t}\n\n\tsortedPartitionKeys := make([]*graph.Tensor, 0, len(k.partitionKeys))\n\tfor _, key := range k.partitionKeys {\n\t\tsortedKey := builder.tm.CreateTensorAs(key)\n\t\tsortedPartitionKeys = append(sortedPartitionKeys, sortedKey)\n\t}\n\tsortedOrderKeys := make([]*graph.Tensor, 0, len(k.orderKeys))\n\tfor _, key := range k.orderKeys {\n\t\tsortedKey := builder.tm.CreateTensorAs(key)\n\t\tsortedOrderKeys = append(sortedOrderKeys, sortedKey)\n\t}\n\tk.payloadOutputs = make([]*graph.Tensor, len(window.payloadOutputs))\n\tfor idx, meta := range window.payloadOutputs {\n\t\ttensor, err := builder.tm.CreateAndSetFirstTensor(meta, &secretPlacement{})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"KernelObliviousWindow toEngineNodes: %w\", err)\n\t\t}\n\t\tk.payloadOutputs[idx] = tensor\n\t}\n\tsortKeys := append(k.partitionKeys, k.orderKeys...)\n\tsortPayloads := append(sortKeys, k.payloads...)\n\tsortResults := append(sortedPartitionKeys, sortedOrderKeys...)\n\tsortResults = append(sortResults, k.payloadOutputs...)\n\tif err := builder.addOpSort(sortKeys, sortPayloads, sortResults, slices.Repeat([]bool{false}, len(sortKeys))); err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousWindow toEngineNodes: %w\", err)\n\t}\n\n\tgroupMark := builder.tm.CreateUnbondedTensor(\"group_mark\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_BOOL), &secretPlacement{})\n\tif err := builder.addOpObliviousGroupMark(sortedPartitionKeys, groupMark); err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousWindow toEngineNodes: %w\", err)\n\t}\n\n\tfuncOutput, err := builder.tm.CreateAndSetFirstTensor(window.funcOutput, &secretPlacement{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"KernelObliviousWindow toEngineNodes: %w\", err)\n\t}\n\tk.funcOutput = funcOutput\n\n\tswitch window.funcName {\n\tcase ast.WindowFuncRowNumber:\n\t\tif err := builder.addOpObliviousGroupAgg(ast.AggFuncCount, groupMark, groupMark, k.funcOutput, map[string]*graph.Attribute{}); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelObliviousWindow toEngineNodes: %w\", err)\n\t\t}\n\tcase ast.WindowFuncRank, ast.WindowFuncPercentRank:\n\t\torderMarkKeys := sortResults[0:len(sortKeys)]\n\t\torderMark := builder.tm.CreateUnbondedTensor(\"order_mark\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_BOOL), &secretPlacement{})\n\t\tif err := builder.addOpObliviousGroupMark(orderMarkKeys, orderMark); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelObliviousWindow toEngineNodes: %w\", err)\n\t\t}\n\t\tif err := builder.addOpObliviousGroupAgg(window.funcName, groupMark, orderMark, k.funcOutput, map[string]*graph.Attribute{}); err != nil {\n\t\t\treturn fmt.Errorf(\"KernelObliviousWindow toEngineNodes: %w\", err)\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"KernelObliviousWindow toEngineNodes: unknown function name %s\", window.funcName)\n\t}\n\n\treturn nil\n}\n\n// ============================================================================\n//                             Helper Functions\n// ============================================================================\n\nfunc createPlacedTensors(builder *ExecutionGraphBuilder, tensorMetas []*TensorMeta, placement tensorPlacement) ([]*graph.Tensor, error) {\n\tplacedTensors := make([]*graph.Tensor, len(tensorMetas))\n\tfor idx, meta := range tensorMetas {\n\t\ttensor, err := builder.getOrCreatePlacedTensor(meta, placement)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tplacedTensors[idx] = tensor\n\t}\n\treturn placedTensors, nil\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/kernel_resolver.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n)\n\ntype KernelResolver struct {\n\tsrm         *SecurityRelaxationManager\n\tvt          *VisibilityTable\n\ttm          *TensorManager\n\tcompileOpts *v1.CompileOptions\n}\n\nfunc NewKernelResolver(srm *SecurityRelaxationManager, vt *VisibilityTable, tm *TensorManager, compileOpts *v1.CompileOptions) *KernelResolver {\n\treturn &KernelResolver{\n\t\tsrm:         srm,\n\t\tvt:          vt,\n\t\ttm:          tm,\n\t\tcompileOpts: compileOpts,\n\t}\n}\n\n// choosePlacement determines the optimal placement for a tensor meta with standard rules.\n// Secret placement is chosen only when corresponding tensor meta has empty visible parties.\nfunc (kr *KernelResolver) choosePlacement(meta *TensorMeta) tensorPlacement {\n\treturn kr.vt.choosePlacement(meta, kr.tm, true, true, false)\n}\n\n// chooseSecretOrPrivatePlacement determines placement considering only private and secret options.\nfunc (kr *KernelResolver) chooseSecretOrPrivatePlacement(meta *TensorMeta) tensorPlacement {\n\treturn kr.vt.choosePlacement(meta, kr.tm, false, true, false)\n}\n\n// choosePlacementAllFine determines placement with relaxed constraints.\n// Secret placement is chosen only when corresponding tensor meta has empty visible parties,\n// or when there are only one existing tensor and its status is secret.\nfunc (kr *KernelResolver) choosePlacementAllFine(meta *TensorMeta) tensorPlacement {\n\treturn kr.vt.choosePlacement(meta, kr.tm, true, true, true)\n}\n\nfunc (kr *KernelResolver) Resolve(n Operator) (Kernel, error) {\n\tswitch x := n.(type) {\n\tcase *OperatorEQJoin:\n\t\treturn kr.resolveEQJoin(x)\n\tcase *OperatorRunSQL:\n\t\treturn kr.resolveRunSQL(x)\n\tcase *OperatorResult:\n\t\treturn kr.resolveResult(x)\n\tcase *OperatorReduce:\n\t\treturn kr.resolveReduce(x)\n\tcase *OperatorBroadcastTo:\n\t\treturn kr.resolveBroadcastTo(x)\n\tcase *OperatorGroupAgg:\n\t\treturn kr.resolveGroupAgg(x)\n\tcase *OperatorCrossJoin:\n\t\treturn kr.resolveCrossJoin(x)\n\tcase *OperatorLimit:\n\t\treturn kr.resolveLimit(x)\n\tcase *OperatorFilter:\n\t\treturn kr.resolveFilter(x)\n\tcase *OperatorConcat:\n\t\treturn kr.resolveConcat(x)\n\tcase *OperatorSort:\n\t\treturn kr.resolveSort(x)\n\tcase *OperatorConstant:\n\t\treturn kr.resolveConstant(x)\n\tcase *OperatorIn:\n\t\treturn kr.resolveIn(x)\n\tcase *OperatorFunction:\n\t\treturn kr.resolveFunction(x)\n\tcase *OperatorWindow:\n\t\treturn kr.resolveWindow(x)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"Resolve Kernel: unsupported node type: %T\", n)\n\t}\n}\n\nfunc (kr *KernelResolver) resolveRunSQL(_ *OperatorRunSQL) (Kernel, error) {\n\treturn &KernelRunSQL{}, nil\n}\n\nfunc (kr *KernelResolver) resolveResult(n *OperatorResult) (Kernel, error) {\n\tif n.intoOpt != nil {\n\t\treturn &KernelDumpFile{intoOpt: n.intoOpt}, nil\n\t}\n\tif n.insertTableOpt != nil {\n\t\treturn &KernelInsertTable{insertTableOpt: n.insertTableOpt}, nil\n\t}\n\treturn &KernelPublishResult{}, nil\n}\n\nfunc (kr *KernelResolver) resolveEQJoin(n *OperatorEQJoin) (Kernel, error) {\n\t// TODO add check\n\tleftKeysVP := kr.vt.CommonVisibleParties(n.leftKeys)\n\trightKeysVp := kr.vt.CommonVisibleParties(n.rightKeys)\n\n\t// TODO implement local join\n\t// try local join\n\t// allKeysVP := VPIntersection(leftKeysVP, rightKeysVp)\n\t// localJoinParty := allKeysVP.GetOneParty()\n\n\t// If len(n.leftOutputs) == 0, then the left party do not need to filter the join payload, thus do not need to get the join result index\n\t// TODO: Currently, in LeftOuterJoin, left party should always get the join result index. This maybe improved in the future.\n\t// OPRF does not allow flexible configuration of which party receives the result; when using the OPRF algorithm, by default both parties obtain the result.\n\tuseOprf := kr.compileOpts != nil && kr.compileOpts.PsiAlgorithmType == proto.PsiAlgorithmType_OPRF\n\tleftTouchResult := len(n.leftOutputs) > 0 || n.joinType == core.LeftOuterJoin || useOprf\n\trightTouchResult := len(n.rightOutputs) > 0 || n.joinType == core.RightOuterJoin || useOprf\n\tcheckPsiParties := func(leftParty, rightParty string) bool {\n\t\tif leftParty == rightParty {\n\t\t\treturn false\n\t\t}\n\t\t// leftTouchResult == true means left party should get the join result index\n\t\tif leftTouchResult {\n\t\t\t// right keys should be visible to left party after join\n\t\t\tif !kr.srm.GetCSR(RevealKeyAfterJoin).AllApplicable(n.rightKeys, kr.vt) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\tif rightTouchResult {\n\t\t\t// left keys should be visible to right party after join\n\t\t\tif !kr.srm.GetCSR(RevealKeyAfterJoin).AllApplicable(n.leftKeys, kr.vt) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n\n\t// try psi join\n\tgetPsiParties := func(leftParties, rightParties []string) (string, string) {\n\t\tpartyPairs := [][]string{}\n\t\texistingTensorCount := []int{}\n\t\tfor _, leftParty := range leftParties {\n\t\t\tfor _, rightParty := range rightParties {\n\t\t\t\tif !checkPsiParties(leftParty, rightParty) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tpartyPairs = append(partyPairs, []string{leftParty, rightParty})\n\t\t\t\tcount := 0\n\t\t\t\tfor _, meta := range n.leftKeys {\n\t\t\t\t\tif kr.tm.hasPlacedTensor(meta, &privatePlacement{partyCode: leftParty}) {\n\t\t\t\t\t\tcount = count + 2 // heuristic\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor _, meta := range n.rightKeys {\n\t\t\t\t\tif kr.tm.hasPlacedTensor(meta, &privatePlacement{partyCode: rightParty}) {\n\t\t\t\t\t\tcount = count + 2\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor _, meta := range n.leftPayloads {\n\t\t\t\t\tif kr.tm.hasPlacedTensor(meta, &privatePlacement{partyCode: leftParty}) || kr.tm.hasPlacedTensor(meta, &privatePlacement{partyCode: rightParty}) {\n\t\t\t\t\t\tcount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor _, meta := range n.rightPayloads {\n\t\t\t\t\tif kr.tm.hasPlacedTensor(meta, &privatePlacement{partyCode: leftParty}) || kr.tm.hasPlacedTensor(meta, &privatePlacement{partyCode: rightParty}) {\n\t\t\t\t\t\tcount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\texistingTensorCount = append(existingTensorCount, count)\n\t\t\t}\n\t\t}\n\n\t\tif len(partyPairs) == 0 {\n\t\t\treturn \"\", \"\"\n\t\t}\n\n\t\tchosenPairIdx := 0\n\t\tfor idx, count := range existingTensorCount {\n\t\t\tif existingTensorCount[chosenPairIdx] < count {\n\t\t\t\tchosenPairIdx = idx\n\t\t\t}\n\t\t}\n\t\treturn partyPairs[chosenPairIdx][0], partyPairs[chosenPairIdx][1]\n\t}\n\tleftParty, rightParty := getPsiParties(leftKeysVP.GetParties(), rightKeysVp.GetParties())\n\n\tif leftParty != \"\" && rightParty != \"\" {\n\t\tleftPayloadsPlacement := []tensorPlacement{}\n\t\tfor _, payload := range n.leftPayloads {\n\t\t\tplacement := kr.chooseSecretOrPrivatePlacement(payload)\n\t\t\tif IsSecret(placement) {\n\t\t\t\treturn &KernelSecretEQJoin{}, nil\n\t\t\t}\n\t\t\tleftPayloadsPlacement = append(leftPayloadsPlacement, placement)\n\t\t}\n\t\trightPayloadsPlacement := []tensorPlacement{}\n\t\tfor _, payload := range n.rightPayloads {\n\t\t\tplacement := kr.chooseSecretOrPrivatePlacement(payload)\n\t\t\tif IsSecret(placement) {\n\t\t\t\treturn &KernelSecretEQJoin{}, nil\n\t\t\t}\n\t\t\trightPayloadsPlacement = append(rightPayloadsPlacement, placement)\n\t\t}\n\t\tpsiAlg := proto.PsiAlgorithmType_AUTO\n\t\tif kr.compileOpts != nil {\n\t\t\tpsiAlg = kr.compileOpts.GetPsiAlgorithmType()\n\t\t}\n\n\t\treturn &KernelPsiEQJoin{\n\t\t\tleftParty:              leftParty,\n\t\t\trightParty:             rightParty,\n\t\t\tpsiAlgorithmType:       psiAlg,\n\t\t\tleftPayloadsPlacement:  leftPayloadsPlacement,\n\t\t\trightPayloadsPlacement: rightPayloadsPlacement,\n\t\t\tleftTouchResult:        leftTouchResult,\n\t\t\trightTouchResult:       rightTouchResult,\n\t\t}, nil\n\t}\n\n\treturn &KernelSecretEQJoin{}, nil\n}\n\nfunc (kr *KernelResolver) resolveReduce(n *OperatorReduce) (Kernel, error) {\n\tswitch n.aggFunc.Name {\n\tcase ast.AggFuncSum, ast.AggFuncMax, ast.AggFuncMin, ast.AggFuncAvg, ast.AggPercentileDisc:\n\t\t// simple reduce only support private and secret inputs\n\t\tplacement := kr.chooseSecretOrPrivatePlacement(n.input)\n\t\treturn &KernelSimpleReduce{placement: placement, aggFunc: n.aggFunc}, nil\n\tcase ast.AggFuncCount:\n\t\tswitch n.aggFunc.Mode {\n\t\tcase aggregation.CompleteMode:\n\t\t\tif n.aggFunc.HasDistinct {\n\t\t\t\tvis := kr.vt.TensorVisibleParties(n.input)\n\t\t\t\t// for now we only support private and secret distinct count\n\t\t\t\tif vis.IsEmpty() {\n\t\t\t\t\treturn &KernelSecretDistinctCount{}, nil\n\t\t\t\t}\n\t\t\t\treturn &KernelPrivateDistinctCount{partyCode: vis.GetOneParty()}, nil\n\t\t\t} else {\n\t\t\t\tif _, ok := n.aggFunc.Args[0].(*expression.Constant); ok {\n\t\t\t\t\tplacement := kr.choosePlacement(n.input)\n\t\t\t\t\tif pp, ok := placement.(*privatePlacement); ok {\n\t\t\t\t\t\treturn &KernelShapeCount{inputPlacement: placement, partyCode: pp.partyCode}, nil\n\t\t\t\t\t}\n\t\t\t\t\treturn &KernelShapeCount{inputPlacement: placement, partyCode: kr.vt.PublicVisibility().GetOneParty()}, nil\n\t\t\t\t}\n\t\t\t\tplacement := kr.chooseSecretOrPrivatePlacement(n.input)\n\t\t\t\treturn &KernelSimpleReduce{placement: placement, aggFunc: n.aggFunc}, nil\n\t\t\t}\n\t\tcase aggregation.FinalMode:\n\t\t\tplacement := kr.chooseSecretOrPrivatePlacement(n.input)\n\t\t\treturn &KernelSimpleReduce{placement: placement, aggFunc: n.aggFunc}, nil\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"resolveReduce: unsupported aggregation mode %v\", n.aggFunc.Mode)\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"resolveReduce: unsupported aggregation function %v\", n.aggFunc)\n}\n\nfunc (kr *KernelResolver) resolveBroadcastTo(n *OperatorBroadcastTo) (Kernel, error) {\n\tfor _, scalar := range n.scalars {\n\t\tif !kr.vt.VisibilityPublic(kr.vt.TensorVisibleParties(scalar)) {\n\t\t\treturn nil, fmt.Errorf(\"resolveBroadcastTo: scalar %v is not public\", scalar)\n\t\t}\n\t}\n\n\t// TODO consider cost of status conversion\n\tplacement := kr.choosePlacementAllFine(n.shapeRef)\n\treturn &KernelBroadcastTo{refPlacement: placement}, nil\n}\n\nfunc (kr *KernelResolver) resolveGroupAgg(n *OperatorGroupAgg) (Kernel, error) {\n\tprivateCandidates := kr.vt.CommonVisibleParties(n.groupKeys)\n\n\tfor idx, aggFunc := range n.aggFuncsWithArg {\n\t\targVP := kr.vt.TensorVisibleParties(n.aggArgs[idx])\n\t\t// check if private groupby secret sum(PGS) is suitable, ref: https://github.com/secretflow/spu/pull/1312\n\t\tif (aggFunc.Name == ast.AggFuncSum || aggFunc.Name == ast.AggFuncAvg) && !argVP.IsEmpty() {\n\t\t\tcontinue\n\t\t}\n\n\t\tprivateCandidates = VPIntersection(privateCandidates, argVP)\n\t}\n\n\tif !privateCandidates.IsEmpty() {\n\t\t// TODO choose best candidate\n\t\tpartyCode := privateCandidates.GetOneParty()\n\t\tkernel := &KernelPrivateGroupAgg{\n\t\t\tpartyCode:  partyCode,\n\t\t\tPGSParties: make(map[int]string),\n\t\t}\n\t\tPGSFuncNum := 0\n\t\tfor idx, aggFunc := range n.aggFuncsWithArg {\n\t\t\tif aggFunc.Name == ast.AggFuncSum || aggFunc.Name == ast.AggFuncAvg {\n\t\t\t\targVP := kr.vt.TensorVisibleParties(n.aggArgs[idx])\n\t\t\t\tif !argVP.Contains(partyCode) {\n\t\t\t\t\tkernel.PGSParties[n.aggArgs[idx].ID] = argVP.GetOneParty()\n\t\t\t\t\tPGSFuncNum++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tkernel.cost = float64(PGSFuncNum) / float64(len(n.aggFuncsWithArg)) * 0.3\n\t\treturn kernel, nil\n\t}\n\n\tprivateSortCandidates := NewVisibleParties([]string{})\n\tif kr.srm.global.RevealGroupCount {\n\t\tif n.keysVisAfterAgg != nil {\n\t\t\t// keysVisAfterAgg will be set if reverse inference is performed on this OperatorGroupAgg.\n\t\t\tprivateSortCandidates = n.keysVisAfterAgg.CommonVisibleParties(n.groupKeys)\n\t\t} else {\n\t\t\tprivateSortCandidates = kr.vt.CommonVisibleParties(n.groupKeys)\n\t\t}\n\n\t\t// skip if only one group-by key\n\t\t// TODO: check logic here\n\t\tif len(n.groupKeys) == 1 {\n\t\t\tprivateSortCandidates = NewVisibleParties([]string{})\n\t\t}\n\t}\n\treturn &KernelObliviousGroupAgg{privateSortParty: privateSortCandidates.GetOneParty(), revealGroupMark: kr.srm.global.RevealGroupMark}, nil\n}\n\nfunc (kr *KernelResolver) resolveCrossJoin(n *OperatorCrossJoin) (Kernel, error) {\n\tleftVP := kr.vt.CommonVisibleParties(n.leftInputs)\n\trightVP := kr.vt.CommonVisibleParties(n.rightInputs)\n\n\t// TODO: support local replicate\n\t// inputsVP := VPIntersection(leftVP, rightVP)\n\t// if !inputsVP.IsEmpty() {\n\t// \tparty := inputsVP.GetOneParty()\n\t// \treturn &KernelCrossJoin{leftParty: party, rightParty: party}, nil\n\t// }\n\n\tgetPartyPair := func(leftParties, rightParties []string) (string, string) {\n\t\tleftRes := \"\"\n\t\trightRes := \"\"\n\t\tresExitingCount := -1\n\t\tfor _, lp := range leftParties {\n\t\t\tfor _, rp := range rightParties {\n\t\t\t\texistingTensorCount := 0\n\t\t\t\tfor _, meta := range n.leftInputs {\n\t\t\t\t\tif kr.tm.hasPlacedTensor(meta, &privatePlacement{partyCode: lp}) {\n\t\t\t\t\t\texistingTensorCount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor _, meta := range n.rightInputs {\n\t\t\t\t\tif kr.tm.hasPlacedTensor(meta, &privatePlacement{partyCode: rp}) {\n\t\t\t\t\t\texistingTensorCount++\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif existingTensorCount > resExitingCount {\n\t\t\t\t\tleftRes = lp\n\t\t\t\t\trightRes = rp\n\t\t\t\t\tresExitingCount = existingTensorCount\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn leftRes, rightRes\n\t}\n\n\tleftParty, rightParty := getPartyPair(leftVP.GetParties(), rightVP.GetParties())\n\tif leftParty != \"\" && rightParty != \"\" {\n\t\treturn &KernelCrossJoin{leftParty: leftParty, rightParty: rightParty}, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"resolveCrossJoin: no valid kernel, left inputs VP : %v, right inputs VP : %v\", leftVP, rightVP)\n}\n\nfunc (kr *KernelResolver) resolveLimit(_ *OperatorLimit) (Kernel, error) {\n\treturn &KernelLimit{}, nil\n}\n\nfunc (kr *KernelResolver) resolveFilter(n *OperatorFilter) (Kernel, error) {\n\t// for now, filter Op in engine support secret and private input:\n\t// when input is secret, a public filter is required,\n\t// when input is private, a public or colocated private filter is required\n\n\tfilterVP := kr.vt.TensorVisibleParties(n.mask)\n\n\t// tensor2Partition := make(map[*TensorMeta]*VisibleParties)\n\tprivatePartitions := []*VisibleParties{}\n\ttensor2PartitionIdx := make(map[*TensorMeta]int)\n\tfor _, idx := range sliceutil.ArgSort(n.inputs, func(a, b *TensorMeta) bool { return a.ID < b.ID }) {\n\t\tinput := n.inputs[idx]\n\t\tinputVP := kr.vt.TensorVisibleParties(input)\n\t\tfindPartition := false\n\t\tfor idx, partitionVP := range privatePartitions {\n\t\t\tintersection := VPIntersection(partitionVP, inputVP)\n\t\t\tif !intersection.IsEmpty() {\n\t\t\t\tpartitionVP.CopyFrom(intersection)\n\t\t\t\ttensor2PartitionIdx[input] = idx\n\t\t\t\tfindPartition = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !findPartition {\n\t\t\tintersection := VPIntersection(filterVP, inputVP)\n\t\t\tif !intersection.IsEmpty() {\n\t\t\t\tprivatePartitions = append(privatePartitions, intersection)\n\t\t\t\ttensor2PartitionIdx[input] = len(privatePartitions) - 1\n\t\t\t} else {\n\t\t\t\tif !kr.vt.VisibilityPublic(filterVP) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"resolveFilter: can not find proper party for input: %v, input VP: %v, filter VP: %v\", input, inputVP, filterVP)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivateParties := make([]string, 0, len(privatePartitions))\n\tfor _, partition := range privatePartitions {\n\t\tprivateParties = append(privateParties, partition.GetOneParty())\n\t}\n\n\tinputPlacements := make([]tensorPlacement, 0, len(n.inputs))\n\tfor _, input := range n.inputs {\n\t\tpartitionIdx, ok := tensor2PartitionIdx[input]\n\t\tif !ok {\n\t\t\tinputPlacements = append(inputPlacements, &secretPlacement{})\n\t\t\tcontinue\n\t\t}\n\t\tchosenParty := privateParties[partitionIdx]\n\n\t\texistingParties := kr.tm.existingPrivateParties(input)\n\t\tfor _, party := range privateParties {\n\t\t\tif slices.Contains(existingParties, party) {\n\t\t\t\tchosenParty = party\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tinputPlacements = append(inputPlacements, &privatePlacement{partyCode: chosenParty})\n\t}\n\treturn &KernelFilter{inputPlacements: inputPlacements}, nil\n}\n\nfunc (kr *KernelResolver) resolveConcat(_ *OperatorConcat) (Kernel, error) {\n\t// only support secret concat now\n\t// question: should we support private concat?\n\n\treturn &KernelSecretConcat{}, nil\n}\n\nfunc (kr *KernelResolver) resolveSort(n *OperatorSort) (Kernel, error) {\n\tprivateCandidates := kr.vt.CommonVisibleParties(append(n.sortKeys, n.payloads...))\n\tif privateCandidates.IsEmpty() {\n\t\treturn &KernelSecretSort{}, nil\n\t}\n\treturn &KernelPrivateSort{partyCode: privateCandidates.GetOneParty()}, nil\n}\n\nfunc (kr *KernelResolver) resolveConstant(_ *OperatorConstant) (Kernel, error) {\n\treturn &KernelConstant{}, nil\n}\n\nfunc (kr *KernelResolver) resolveIn(n *OperatorIn) (Kernel, error) {\n\t// TODO consider transition cost\n\t// TODO support secret In\n\tleftVP := kr.vt.TensorVisibleParties(n.left)\n\trightVP := kr.vt.TensorVisibleParties(n.right)\n\tlocalInCandidates := VPIntersection(leftVP, rightVP)\n\tif !localInCandidates.IsEmpty() {\n\t\treturn &KernelLocalIn{partyCode: localInCandidates.GetOneParty()}, nil\n\t}\n\tif !leftVP.IsEmpty() && !rightVP.IsEmpty() {\n\t\tpsiAlg := proto.PsiAlgorithmType_AUTO\n\t\tif kr.compileOpts != nil {\n\t\t\tpsiAlg = kr.compileOpts.GetPsiAlgorithmType()\n\t\t}\n\t\treturn &KernelPsiIn{leftParty: leftVP.GetOneParty(), rightParty: rightVP.GetOneParty(), psiAlgorithmType: psiAlg}, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"resolveIn: no valid kernel, left VP : %v, right VP : %v\", leftVP, rightVP)\n}\n\nfunc (kr *KernelResolver) resolveFunction(n *OperatorFunction) (Kernel, error) {\n\t// TODO consider transition cost\n\tprivateCandidates := kr.vt.CommonVisibleParties(n.inputs)\n\tgetPublicOrSecretPlace := func(v *VisibleParties) tensorPlacement {\n\t\tif kr.vt.VisibilityPublic(v) {\n\t\t\treturn &publicPlacement{}\n\t\t}\n\t\treturn &secretPlacement{}\n\t}\n\n\tswitch n.funcName {\n\tcase ast.Lower, ast.Upper, ast.Trim, ast.Substr, ast.Substring, ast.StrToDate:\n\t\tif privateCandidates.IsEmpty() {\n\t\t\treturn nil, fmt.Errorf(\"resolveFunction: could not find proper candidate for ArrowFunc\")\n\t\t}\n\t\treturn &KernelArrowFunction{partyCode: privateCandidates.GetOneParty()}, nil\n\tcase ast.Abs, ast.Ceil, ast.Floor, ast.Round, ast.Radians, ast.Degrees, ast.Ln, ast.Log10, ast.Log2, ast.Sqrt, ast.Exp, ast.UnaryNot, ast.Cos, ast.Sin, ast.Acos, ast.Asin, ast.Tan, ast.Atan:\n\t\treturn &KernelUnary{place: kr.choosePlacement(n.inputs[0])}, nil\n\tcase ast.LT, ast.GT, ast.LE, ast.GE, ast.EQ, ast.NE, ast.LogicOr, ast.LogicAnd, ast.Plus, ast.Minus, ast.Mul, ast.Div, ast.IntDiv, ast.Mod, ast.AddDate, ast.SubDate, ast.DateDiff, ast.Pow, ast.Atan2:\n\t\tif !privateCandidates.IsEmpty() {\n\t\t\t// TODO consider all public\n\t\t\tplacement := kr.tm.choosePrivatePlacement(privateCandidates, n.inputs)\n\t\t\treturn &KernelBinary{lhsPlace: placement, rhsPlace: placement, outPlace: placement}, nil\n\t\t}\n\n\t\tlhsVP := kr.vt.TensorVisibleParties(n.inputs[0])\n\t\trhsVP := kr.vt.TensorVisibleParties(n.inputs[1])\n\n\t\treturn &KernelBinary{lhsPlace: getPublicOrSecretPlace(lhsVP), rhsPlace: getPublicOrSecretPlace(rhsVP), outPlace: &secretPlacement{}}, nil\n\tcase ast.Greatest, ast.Least:\n\t\tif privateCandidates.IsEmpty() {\n\t\t\treturn &KernelVariadicCompare{placement: &secretPlacement{}}, nil\n\t\t}\n\t\treturn &KernelVariadicCompare{placement: kr.tm.choosePrivatePlacement(privateCandidates, n.inputs)}, nil\n\tcase ast.Ifnull, ast.IsNull, ast.Coalesce:\n\t\tif privateCandidates.IsEmpty() {\n\t\t\treturn nil, fmt.Errorf(\"resolveFunction: could not find proper candidate for %s\", n.funcName)\n\t\t}\n\t\treturn &KernelPrivateFunc{partyCode: kr.tm.choosePrivatePlacement(privateCandidates, n.inputs).partyCode}, nil\n\tcase ast.Cast:\n\t\t// TODO consider public cast\n\t\tplacement := kr.chooseSecretOrPrivatePlacement(n.inputs[0])\n\t\tif IsSecret(placement) && n.output.DType.IsStringType() {\n\t\t\treturn nil, fmt.Errorf(\"resolveFunction:not support cast for string in spu, which exists in hash form\")\n\t\t}\n\t\treturn &KernelCast{placement: placement}, nil\n\tcase ast.If:\n\t\tparty := privateCandidates.GetOneParty()\n\t\tif party != \"\" {\n\t\t\tplace := &privatePlacement{partyCode: party}\n\t\t\treturn &KernelIf{condPlace: place, trueValuePlace: place, falseValuePlace: place, outputPlace: place}, nil\n\t\t} else {\n\t\t\tcondPlace := getPublicOrSecretPlace(kr.vt.TensorVisibleParties(n.inputs[0]))\n\t\t\ttrueValuePlace := getPublicOrSecretPlace(kr.vt.TensorVisibleParties(n.inputs[1]))\n\t\t\tfalseValuePlace := getPublicOrSecretPlace(kr.vt.TensorVisibleParties(n.inputs[2]))\n\t\t\treturn &KernelIf{condPlace: condPlace, trueValuePlace: trueValuePlace, falseValuePlace: falseValuePlace, outputPlace: &secretPlacement{}}, nil\n\t\t}\n\tcase ast.Case:\n\t\tinputPlacements := make([]tensorPlacement, 0, len(n.inputs))\n\t\tif privateCandidates.IsEmpty() {\n\t\t\tfor _, input := range n.inputs {\n\t\t\t\tinputPlacements = append(inputPlacements, getPublicOrSecretPlace(kr.vt.TensorVisibleParties(input)))\n\t\t\t}\n\t\t\treturn &KernelCase{inputPlacements: inputPlacements, outputPlacement: &secretPlacement{}}, nil\n\t\t} else {\n\t\t\tplace := kr.tm.choosePrivatePlacement(privateCandidates, n.inputs)\n\t\t\tfor range n.inputs {\n\t\t\t\tinputPlacements = append(inputPlacements, place)\n\t\t\t}\n\t\t\treturn &KernelCase{inputPlacements: inputPlacements, outputPlacement: place}, nil\n\t\t}\n\tcase ast.Concat:\n\t\tpartyCode := privateCandidates.GetOneParty()\n\t\tif partyCode == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"resolveFunction: could not find proper candidate for string concat\")\n\t\t}\n\t\treturn &KernelConcatString{partyCode: partyCode}, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"resolveFunction: unsupported function %s\", n.funcName)\n\t}\n}\n\nfunc (kr *KernelResolver) resolveWindow(n *OperatorWindow) (Kernel, error) {\n\tprivateCandidates := kr.vt.CommonVisibleParties(append(n.partitionKeys, n.orderKeys...))\n\tif privateCandidates.IsEmpty() {\n\t\treturn &KernelObliviousWindow{}, nil\n\t} else {\n\t\treturn &KernelPrivateWindow{partyCode: privateCandidates.GetOneParty()}, nil\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/kernel_resolver_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\nfunc TestChoosePlacement(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(nil, vt, tm, nil)\n\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\", DType: graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING)}\n\n\ttests := []struct {\n\t\tname       string\n\t\tsetup      func()\n\t\twantStatus proto.TensorStatus\n\t}{\n\t\t{\n\t\t\tname: \"empty visibility returns secret placement\",\n\t\t\tsetup: func() {\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_SECRET,\n\t\t},\n\t\t{\n\t\t\tname: \"public visibility returns public placement\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, vt.PublicVisibility())\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_PUBLIC,\n\t\t},\n\t\t{\n\t\t\tname: \"single party visibility returns private placement\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, NewVisibleParties([]string{\"alice\"}))\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_PRIVATE,\n\t\t},\n\t\t{\n\t\t\tname: \"existing private placement is preferred over non-existing public placement\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, vt.PublicVisibility())\n\t\t\t\ttm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: \"alice\"})\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_PRIVATE,\n\t\t},\n\t\t{\n\t\t\tname: \"existing private placement is preferred\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, NewVisibleParties([]string{\"alice\"}))\n\t\t\t\tprivateTensor := &graph.Tensor{ID: 101, Name: \"private_tensor\", OwnerPartyCode: \"alice\"}\n\t\t\t\tprivateTensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\t\t\t\ttm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: \"alice\"})\n\t\t\t\ttm.setPlacedTensor(meta, privateTensor, &privatePlacement{partyCode: \"alice\"})\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_PRIVATE,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\tvt = NewVisibilityTable(parties)\n\t\t\ttm = NewTensorManager(1)\n\t\t\tkr = NewKernelResolver(nil, vt, tm, nil)\n\n\t\t\tif tt.setup != nil {\n\t\t\t\t(tt.setup)()\n\t\t\t}\n\n\t\t\tresult := kr.choosePlacement(meta)\n\n\t\t\tassert.Equal(t, tt.wantStatus, result.Status())\n\t\t})\n\t}\n}\n\nfunc TestChooseSecretOrPrivatePlacement(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(nil, vt, tm, nil)\n\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\"}\n\n\ttests := []struct {\n\t\tname       string\n\t\tsetup      func()\n\t\twantStatus proto.TensorStatus\n\t}{\n\t\t{\n\t\t\tname: \"empty visibility returns secret placement\",\n\t\t\tsetup: func() {\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_SECRET,\n\t\t},\n\t\t{\n\t\t\tname: \"public visibility returns private placement (public not allowed)\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, vt.PublicVisibility())\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_PRIVATE,\n\t\t},\n\t\t{\n\t\t\tname: \"single party visibility returns private placement\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, NewVisibleParties([]string{\"alice\"}))\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_PRIVATE,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\tvt = NewVisibilityTable(parties)\n\t\t\ttm = NewTensorManager(1)\n\t\t\tkr = NewKernelResolver(nil, vt, tm, nil)\n\n\t\t\tif tt.setup != nil {\n\t\t\t\t(tt.setup)()\n\t\t\t}\n\n\t\t\tresult := kr.chooseSecretOrPrivatePlacement(meta)\n\n\t\t\tassert.Equal(t, tt.wantStatus, result.Status())\n\t\t})\n\t}\n}\n\nfunc TestChoosePlacementAllFine(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(nil, vt, tm, nil)\n\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\"}\n\n\ttests := []struct {\n\t\tname       string\n\t\tsetup      func()\n\t\twantStatus proto.TensorStatus\n\t}{\n\t\t{\n\t\t\tname: \"empty visibility returns secret placement\",\n\t\t\tsetup: func() {\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_SECRET,\n\t\t},\n\t\t{\n\t\t\tname: \"public visibility returns public placement\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, vt.PublicVisibility())\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_PUBLIC,\n\t\t},\n\t\t{\n\t\t\tname: \"single party visibility returns private placement\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, NewVisibleParties([]string{\"alice\"}))\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_PRIVATE,\n\t\t},\n\t\t{\n\t\t\tname: \"existing placement is preferred even when it is secret\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, NewVisibleParties([]string{\"alice\"}))\n\t\t\t\ttm.CreateAndSetFirstTensor(meta, &secretPlacement{})\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_SECRET,\n\t\t},\n\t\t{\n\t\t\tname: \"existing public placement is preferred over existing private placement\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, vt.PublicVisibility())\n\t\t\t\ttm.CreateAndSetFirstTensor(meta, &publicPlacement{})\n\t\t\t\tprivateTensor := &graph.Tensor{ID: 101, Name: \"private_tensor\", OwnerPartyCode: \"alice\"}\n\t\t\t\tprivateTensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\t\t\t\ttm.setPlacedTensor(meta, privateTensor, &privatePlacement{partyCode: \"alice\"})\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_PUBLIC,\n\t\t},\n\t\t{\n\t\t\tname: \"existing private placement is preferred over existing secret placement\",\n\t\t\tsetup: func() {\n\t\t\t\tvt.UpdateVisibility(meta, NewVisibleParties([]string{\"alice\"}))\n\t\t\t\ttm.CreateAndSetFirstTensor(meta, &secretPlacement{})\n\t\t\t\tprivateTensor := &graph.Tensor{ID: 101, Name: \"private_tensor\", OwnerPartyCode: \"alice\"}\n\t\t\t\tprivateTensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\t\t\t\ttm.setPlacedTensor(meta, privateTensor, &privatePlacement{partyCode: \"alice\"})\n\t\t\t},\n\t\t\twantStatus: proto.TensorStatus_TENSORSTATUS_PRIVATE,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\tvt = NewVisibilityTable(parties)\n\t\t\ttm = NewTensorManager(1)\n\t\t\tkr = NewKernelResolver(nil, vt, tm, nil)\n\n\t\t\tif tt.setup != nil {\n\t\t\t\t(tt.setup)()\n\t\t\t}\n\n\t\t\tresult := kr.choosePlacementAllFine(meta)\n\n\t\t\tassert.Equal(t, tt.wantStatus, result.Status())\n\t\t})\n\t}\n}\n\nfunc TestResolveEQJoin(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{RevealKeyAfterJoin: true}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(srm, vt, tm, nil)\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\ttests := []struct {\n\t\tname               string\n\t\trevealKeyAfterJoin bool\n\t\tsetup              func() *OperatorEQJoin\n\t\twantKernelType     any\n\t\twantLeftParty      string\n\t\twantRightParty     string\n\t\twantErr            bool\n\t\twantErrMsg         string\n\t}{\n\t\t{\n\t\t\tname:               \"psi join with valid parties and need tensor status conversion\",\n\t\t\trevealKeyAfterJoin: true,\n\t\t\tsetup: func() *OperatorEQJoin {\n\t\t\t\tleftKey, _ := createPlacedTensor(\"left_key\", &secretPlacement{}, []string{\"alice\"})\n\t\t\t\trightKey, _ := createPlacedTensor(\"right_key\", &secretPlacement{}, []string{\"bob\"})\n\t\t\t\tleftPayload, _ := createPlacedTensor(\"left_payload\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\trightPayload, _ := createPlacedTensor(\"right_payload\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\n\t\t\t\treturn &OperatorEQJoin{\n\t\t\t\t\tbaseOperator:  baseOperator{id: 1},\n\t\t\t\t\tleftKeys:      []*TensorMeta{leftKey},\n\t\t\t\t\trightKeys:     []*TensorMeta{rightKey},\n\t\t\t\t\tleftPayloads:  []*TensorMeta{leftPayload},\n\t\t\t\t\trightPayloads: []*TensorMeta{rightPayload},\n\t\t\t\t\tleftOutputs:   []*TensorMeta{leftPayload},\n\t\t\t\t\trightOutputs:  []*TensorMeta{rightPayload},\n\t\t\t\t\tjoinType:      core.InnerJoin,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelPsiEQJoin{},\n\t\t\twantLeftParty:  \"alice\",\n\t\t\twantRightParty: \"bob\",\n\t\t},\n\t\t{\n\t\t\tname:               \"psi join using existing private placement\",\n\t\t\trevealKeyAfterJoin: true,\n\t\t\tsetup: func() *OperatorEQJoin {\n\t\t\t\tleftKey, _ := createPlacedTensor(\"left_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"bob\"})\n\t\t\t\trightKey, _ := createPlacedTensor(\"right_key\", &privatePlacement{partyCode: \"bob\"}, []string{\"alice\", \"bob\"})\n\t\t\t\tleftPayload, _ := createPlacedTensor(\"left_payload\", &privatePlacement{partyCode: \"bob\"}, []string{\"alice\", \"bob\"})\n\t\t\t\trightPayload, _ := createPlacedTensor(\"right_payload\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"bob\"})\n\n\t\t\t\treturn &OperatorEQJoin{\n\t\t\t\t\tbaseOperator:  baseOperator{id: 1},\n\t\t\t\t\tleftKeys:      []*TensorMeta{leftKey},\n\t\t\t\t\trightKeys:     []*TensorMeta{rightKey},\n\t\t\t\t\tleftPayloads:  []*TensorMeta{leftPayload},\n\t\t\t\t\trightPayloads: []*TensorMeta{rightPayload},\n\t\t\t\t\tleftOutputs:   []*TensorMeta{leftPayload},\n\t\t\t\t\trightOutputs:  []*TensorMeta{rightPayload},\n\t\t\t\t\tjoinType:      core.InnerJoin,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelPsiEQJoin{},\n\t\t\twantLeftParty:  \"alice\",\n\t\t\twantRightParty: \"bob\",\n\t\t},\n\t\t{\n\t\t\tname:               \"secret join when no valid parties\",\n\t\t\trevealKeyAfterJoin: false,\n\t\t\tsetup: func() *OperatorEQJoin {\n\t\t\t\tleftKey, _ := createPlacedTensor(\"left_key\", &secretPlacement{}, []string{})\n\t\t\t\trightKey, _ := createPlacedTensor(\"right_key\", &secretPlacement{}, []string{\"alice\"})\n\t\t\t\tleftPayload, _ := createPlacedTensor(\"left_payload\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\trightPayload, _ := createPlacedTensor(\"right_payload\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\n\t\t\t\treturn &OperatorEQJoin{\n\t\t\t\t\tbaseOperator:  baseOperator{id: 1},\n\t\t\t\t\tleftKeys:      []*TensorMeta{leftKey},\n\t\t\t\t\trightKeys:     []*TensorMeta{rightKey},\n\t\t\t\t\tleftPayloads:  []*TensorMeta{leftPayload},\n\t\t\t\t\trightPayloads: []*TensorMeta{rightPayload},\n\t\t\t\t\tleftOutputs:   []*TensorMeta{leftPayload},\n\t\t\t\t\trightOutputs:  []*TensorMeta{rightPayload},\n\t\t\t\t\tjoinType:      core.InnerJoin,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelSecretEQJoin{},\n\t\t},\n\t\t{\n\t\t\tname:               \"valid parties to perform psi but RevealKeyAfterJoin=false\",\n\t\t\trevealKeyAfterJoin: false,\n\t\t\tsetup: func() *OperatorEQJoin {\n\t\t\t\tleftKey, _ := createPlacedTensor(\"left_key\", &secretPlacement{}, []string{\"alice\"})\n\t\t\t\trightKey, _ := createPlacedTensor(\"right_key\", &secretPlacement{}, []string{\"bob\"})\n\t\t\t\tleftPayload, _ := createPlacedTensor(\"left_payload\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\trightPayload, _ := createPlacedTensor(\"right_payload\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\n\t\t\t\treturn &OperatorEQJoin{\n\t\t\t\t\tbaseOperator:  baseOperator{id: 1},\n\t\t\t\t\tleftKeys:      []*TensorMeta{leftKey},\n\t\t\t\t\trightKeys:     []*TensorMeta{rightKey},\n\t\t\t\t\tleftPayloads:  []*TensorMeta{leftPayload},\n\t\t\t\t\trightPayloads: []*TensorMeta{rightPayload},\n\t\t\t\t\tleftOutputs:   []*TensorMeta{leftPayload},\n\t\t\t\t\trightOutputs:  []*TensorMeta{rightPayload},\n\t\t\t\t\tjoinType:      core.InnerJoin,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelSecretEQJoin{},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\ttensorMetaManager = NewTensorMetaManager()\n\t\t\ttm = NewTensorManager(1)\n\t\t\tvt = NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\t\t\tsrm = NewSecurityRelaxationManager(&GlobalSecurityRelaxation{RevealKeyAfterJoin: tt.revealKeyAfterJoin}, nil)\n\t\t\tkr = NewKernelResolver(srm, vt, tm, nil)\n\n\t\t\tn := tt.setup()\n\t\t\tkernel, err := kr.resolveEQJoin(n)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\n\t\t\t// Check specific fields for PsiEQJoin\n\t\t\tif psiKernel, ok := kernel.(*KernelPsiEQJoin); ok {\n\t\t\t\tassert.Equal(t, tt.wantLeftParty, psiKernel.leftParty)\n\t\t\t\tassert.Equal(t, tt.wantRightParty, psiKernel.rightParty)\n\t\t\t\t// Since compileOpts is nil, it should use default value\n\t\t\t\tassert.Equal(t, proto.PsiAlgorithmType_AUTO, psiKernel.psiAlgorithmType)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResolveRunSQL(t *testing.T) {\n\tkr := NewKernelResolver(nil, nil, nil, nil)\n\n\tn := &OperatorRunSQL{\n\t\tbaseOperator: baseOperator{id: 1},\n\t\tsql:          \"SELECT * FROM test\",\n\t\tsourceParty:  \"alice\",\n\t}\n\n\tkernel, err := kr.resolveRunSQL(n)\n\n\tassert.NoError(t, err)\n\tassert.IsType(t, &KernelRunSQL{}, kernel)\n}\n\nfunc TestResolveResult(t *testing.T) {\n\tkr := NewKernelResolver(nil, nil, nil, nil)\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetup          func() *OperatorResult\n\t\twantKernelType any\n\t}{\n\t\t{\n\t\t\tname: \"result with intoOpt\",\n\t\t\tsetup: func() *OperatorResult {\n\t\t\t\treturn &OperatorResult{\n\t\t\t\t\tbaseOperator: baseOperator{id: 1},\n\t\t\t\t\tintoOpt:      &core.IntoOpt{},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelDumpFile{},\n\t\t},\n\t\t{\n\t\t\tname: \"result with insertTableOpt\",\n\t\t\tsetup: func() *OperatorResult {\n\t\t\t\treturn &OperatorResult{\n\t\t\t\t\tbaseOperator:   baseOperator{id: 2},\n\t\t\t\t\tinsertTableOpt: &core.InsertTableOption{TableName: \"test_table\"},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelInsertTable{},\n\t\t},\n\t\t{\n\t\t\tname: \"result with neither option\",\n\t\t\tsetup: func() *OperatorResult {\n\t\t\t\treturn &OperatorResult{\n\t\t\t\t\tbaseOperator: baseOperator{id: 3},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelPublishResult{},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tn := tt.setup()\n\t\t\tkernel, err := kr.resolveResult(n)\n\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\t\t})\n\t}\n}\n\nfunc TestResolveLimit(t *testing.T) {\n\tkr := NewKernelResolver(nil, nil, nil, nil)\n\n\tn := &OperatorLimit{\n\t\tbaseOperator: baseOperator{id: 1},\n\t}\n\n\tkernel, err := kr.resolveLimit(n)\n\n\tassert.NoError(t, err)\n\tassert.IsType(t, &KernelLimit{}, kernel)\n}\n\nfunc TestResolveConcat(t *testing.T) {\n\tkr := NewKernelResolver(nil, nil, nil, nil)\n\n\tn := &OperatorConcat{\n\t\tbaseOperator: baseOperator{id: 1},\n\t}\n\n\tkernel, err := kr.resolveConcat(n)\n\n\tassert.NoError(t, err)\n\tassert.IsType(t, &KernelSecretConcat{}, kernel)\n}\n\nfunc TestResolveConstant(t *testing.T) {\n\tkr := NewKernelResolver(nil, nil, nil, nil)\n\n\tn := &OperatorConstant{\n\t\tbaseOperator: baseOperator{id: 1},\n\t}\n\n\tkernel, err := kr.resolveConstant(n)\n\n\tassert.NoError(t, err)\n\tassert.IsType(t, &KernelConstant{}, kernel)\n}\n\nfunc TestResolveGroupAgg(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{RevealGroupCount: false, RevealGroupMark: false}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(srm, vt, tm, nil)\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\tcreateAggFunc := func(name string) *aggregation.AggFuncDesc {\n\t\tagg := &aggregation.AggFuncDesc{}\n\t\tagg.Name = name\n\t\treturn agg\n\t}\n\n\ttests := []struct {\n\t\tname                string\n\t\trevealGroupCount    bool\n\t\trevealGroupMark     bool\n\t\tsetup               func() *OperatorGroupAgg\n\t\twantKernelType      any\n\t\twantPrivateParty    string\n\t\twantPrivateSort     string\n\t\twantRevealGroupMark bool\n\t\twantPGSFuncNum      int\n\t}{\n\t\t{\n\t\t\tname: \"private group agg with all tensors visible to same party\",\n\t\t\tsetup: func() *OperatorGroupAgg {\n\t\t\t\tgroupKey, _ := createPlacedTensor(\"group_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tpayload, _ := createPlacedTensor(\"payload\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\n\t\t\t\treturn &OperatorGroupAgg{\n\t\t\t\t\tbaseOperator:    baseOperator{id: 1},\n\t\t\t\t\tgroupKeys:       []*TensorMeta{groupKey},\n\t\t\t\t\taggArgs:         []*TensorMeta{payload},\n\t\t\t\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{createAggFunc(ast.AggFuncSum)},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType:   &KernelPrivateGroupAgg{},\n\t\t\twantPrivateParty: \"alice\",\n\t\t\twantPGSFuncNum:   0,\n\t\t},\n\t\t{\n\t\t\tname: \"private group agg with secret sum optimization\",\n\t\t\tsetup: func() *OperatorGroupAgg {\n\t\t\t\tgroupKey, _ := createPlacedTensor(\"group_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tpayload, _ := createPlacedTensor(\"payload\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\n\t\t\t\treturn &OperatorGroupAgg{\n\t\t\t\t\tbaseOperator:    baseOperator{id: 2},\n\t\t\t\t\tgroupKeys:       []*TensorMeta{groupKey},\n\t\t\t\t\taggArgs:         []*TensorMeta{payload},\n\t\t\t\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{createAggFunc(ast.AggFuncSum)},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType:   &KernelPrivateGroupAgg{},\n\t\t\twantPrivateParty: \"alice\",\n\t\t\twantPGSFuncNum:   1,\n\t\t},\n\t\t{\n\t\t\tname:             \"oblivious group agg when no common private party\",\n\t\t\trevealGroupCount: false,\n\t\t\tsetup: func() *OperatorGroupAgg {\n\t\t\t\tgroupKey, _ := createPlacedTensor(\"group_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tpayload, _ := createPlacedTensor(\"payload\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\n\t\t\t\treturn &OperatorGroupAgg{\n\t\t\t\t\tbaseOperator:    baseOperator{id: 3},\n\t\t\t\t\tgroupKeys:       []*TensorMeta{groupKey},\n\t\t\t\t\taggArgs:         []*TensorMeta{payload},\n\t\t\t\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{createAggFunc(ast.AggFuncMax)},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType:      &KernelObliviousGroupAgg{},\n\t\t\twantPrivateSort:     \"\",\n\t\t\twantRevealGroupMark: false,\n\t\t},\n\t\t{\n\t\t\tname:             \"oblivious group agg with reveal group count enabled\",\n\t\t\trevealGroupCount: true,\n\t\t\tsetup: func() *OperatorGroupAgg {\n\t\t\t\tgroupKey1, _ := createPlacedTensor(\"group_key1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tgroupKey2, _ := createPlacedTensor(\"group_key2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tpayload, _ := createPlacedTensor(\"payload\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\n\t\t\t\treturn &OperatorGroupAgg{\n\t\t\t\t\tbaseOperator:    baseOperator{id: 4},\n\t\t\t\t\tgroupKeys:       []*TensorMeta{groupKey1, groupKey2},\n\t\t\t\t\taggArgs:         []*TensorMeta{payload},\n\t\t\t\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{createAggFunc(ast.AggFuncMin)},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType:      &KernelObliviousGroupAgg{},\n\t\t\twantPrivateSort:     \"alice\",\n\t\t\twantRevealGroupMark: false,\n\t\t},\n\t\t{\n\t\t\tname:            \"oblivious group agg with reveal group mark enabled\",\n\t\t\trevealGroupMark: true,\n\t\t\tsetup: func() *OperatorGroupAgg {\n\t\t\t\tgroupKey, _ := createPlacedTensor(\"group_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tpayload, _ := createPlacedTensor(\"payload\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\n\t\t\t\treturn &OperatorGroupAgg{\n\t\t\t\t\tbaseOperator:    baseOperator{id: 5},\n\t\t\t\t\tgroupKeys:       []*TensorMeta{groupKey},\n\t\t\t\t\taggArgs:         []*TensorMeta{payload},\n\t\t\t\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{createAggFunc(ast.AggFuncMax)},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType:      &KernelObliviousGroupAgg{},\n\t\t\twantPrivateSort:     \"\",\n\t\t\twantRevealGroupMark: true,\n\t\t},\n\t\t{\n\t\t\tname: \"private group agg with multiple group keys\",\n\t\t\tsetup: func() *OperatorGroupAgg {\n\t\t\t\tgroupKey1, _ := createPlacedTensor(\"group_key1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tgroupKey2, _ := createPlacedTensor(\"group_key2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tpayload, _ := createPlacedTensor(\"payload\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\n\t\t\t\treturn &OperatorGroupAgg{\n\t\t\t\t\tbaseOperator:    baseOperator{id: 6},\n\t\t\t\t\tgroupKeys:       []*TensorMeta{groupKey1, groupKey2},\n\t\t\t\t\taggArgs:         []*TensorMeta{payload},\n\t\t\t\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{createAggFunc(ast.AggFuncCount)},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType:   &KernelPrivateGroupAgg{},\n\t\t\twantPrivateParty: \"alice\",\n\t\t\twantPGSFuncNum:   0,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\ttensorMetaManager = NewTensorMetaManager()\n\t\t\ttm = NewTensorManager(1)\n\t\t\tvt = NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\t\t\tsrm = NewSecurityRelaxationManager(&GlobalSecurityRelaxation{RevealGroupCount: tt.revealGroupCount, RevealGroupMark: tt.revealGroupMark}, nil)\n\t\t\tkr = NewKernelResolver(srm, vt, tm, nil)\n\n\t\t\tn := tt.setup()\n\t\t\tkernel, err := kr.resolveGroupAgg(n)\n\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\n\t\t\tif privateKernel, ok := kernel.(*KernelPrivateGroupAgg); ok {\n\t\t\t\tassert.Equal(t, tt.wantPrivateParty, privateKernel.partyCode)\n\t\t\t\tassert.Equal(t, tt.wantPGSFuncNum, len(privateKernel.PGSParties))\n\t\t\t}\n\n\t\t\tif obliviousKernel, ok := kernel.(*KernelObliviousGroupAgg); ok {\n\t\t\t\tassert.Equal(t, tt.wantPrivateSort, obliviousKernel.privateSortParty)\n\t\t\t\tassert.Equal(t, tt.wantRevealGroupMark, obliviousKernel.revealGroupMark)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResolveFilter(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(srm, vt, tm, nil)\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\ttests := []struct {\n\t\tname            string\n\t\tsetup           func() *OperatorFilter\n\t\twantKernelType  any\n\t\twantErr         bool\n\t\twantErrMsg      string\n\t\tcheckPlacements func([]tensorPlacement)\n\t}{\n\t\t{\n\t\t\tname: \"all tensors visible to same party\",\n\t\t\tsetup: func() *OperatorFilter {\n\t\t\t\tmask, _ := createPlacedTensor(\"mask\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\n\t\t\t\treturn &OperatorFilter{\n\t\t\t\t\tbaseOperator: baseOperator{id: 1},\n\t\t\t\t\tmask:         mask,\n\t\t\t\t\tinputs:       []*TensorMeta{input},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelFilter{},\n\t\t\tcheckPlacements: func(placements []tensorPlacement) {\n\t\t\t\trequire.Len(t, placements, 1)\n\t\t\t\tprivatePlace, ok := placements[0].(*privatePlacement)\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, \"alice\", privatePlace.partyCode)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"secret input with public filter\",\n\t\t\tsetup: func() *OperatorFilter {\n\t\t\t\tmask, _ := createPlacedTensor(\"mask\", &publicPlacement{}, []string{\"alice\", \"bob\", \"carol\"})\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &secretPlacement{}, []string{})\n\n\t\t\t\treturn &OperatorFilter{\n\t\t\t\t\tbaseOperator: baseOperator{id: 2},\n\t\t\t\t\tmask:         mask,\n\t\t\t\t\tinputs:       []*TensorMeta{input},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelFilter{},\n\t\t\tcheckPlacements: func(placements []tensorPlacement) {\n\t\t\t\trequire.Len(t, placements, 1)\n\t\t\t\t_, ok := placements[0].(*secretPlacement)\n\t\t\t\tassert.True(t, ok)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"no common visibility between filter and input\",\n\t\t\tsetup: func() *OperatorFilter {\n\t\t\t\tmask, _ := createPlacedTensor(\"mask\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\n\t\t\t\treturn &OperatorFilter{\n\t\t\t\t\tbaseOperator: baseOperator{id: 3},\n\t\t\t\t\tmask:         mask,\n\t\t\t\t\tinputs:       []*TensorMeta{input},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantErr:    true,\n\t\t\twantErrMsg: \"resolveFilter: can not find proper party\",\n\t\t},\n\t\t{\n\t\t\tname: \"multiple inputs with intersection visibility\",\n\t\t\tsetup: func() *OperatorFilter {\n\t\t\t\tmask, _ := createPlacedTensor(\"mask\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"bob\"})\n\t\t\t\tinput1, _ := createPlacedTensor(\"input1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"carol\"})\n\t\t\t\tinput2, _ := createPlacedTensor(\"input2\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\", \"carol\"})\n\n\t\t\t\treturn &OperatorFilter{\n\t\t\t\t\tbaseOperator: baseOperator{id: 4},\n\t\t\t\t\tmask:         mask,\n\t\t\t\t\tinputs:       []*TensorMeta{input1, input2},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelFilter{},\n\t\t\tcheckPlacements: func(placements []tensorPlacement) {\n\t\t\t\trequire.Len(t, placements, 2)\n\n\t\t\t\t// Check that each placement is a private placement with the expected party\n\t\t\t\talicePlace, ok1 := placements[0].(*privatePlacement)\n\t\t\t\tassert.True(t, ok1)\n\t\t\t\tassert.Equal(t, \"alice\", alicePlace.partyCode)\n\n\t\t\t\tbobPlace, ok2 := placements[1].(*privatePlacement)\n\t\t\t\tassert.True(t, ok2)\n\t\t\t\tassert.Equal(t, \"bob\", bobPlace.partyCode)\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\ttensorMetaManager = NewTensorMetaManager()\n\t\t\ttm = NewTensorManager(1)\n\t\t\tvt = NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\t\t\tsrm = NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\t\t\tkr = NewKernelResolver(srm, vt, tm, nil)\n\n\t\t\tn := tt.setup()\n\t\t\tkernel, err := kr.resolveFilter(n)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\n\t\t\tif tt.checkPlacements != nil {\n\t\t\t\tfilterKernel, ok := kernel.(*KernelFilter)\n\t\t\t\trequire.True(t, ok)\n\t\t\t\ttt.checkPlacements(filterKernel.inputPlacements)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResolveReduce(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tscm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(scm, vt, tm, nil)\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\tcreateAggFunc := func(name string, mode aggregation.AggFunctionMode, hasDistinct bool) *aggregation.AggFuncDesc {\n\t\tagg := &aggregation.AggFuncDesc{}\n\t\tagg.Name = name\n\t\tagg.Mode = mode\n\t\tagg.HasDistinct = hasDistinct\n\t\treturn agg\n\t}\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetup          func() *OperatorReduce\n\t\twantKernelType any\n\t\twantErr        bool\n\t\twantErrMsg     string\n\t\tcheckKernel    func(Kernel)\n\t}{\n\t\t{\n\t\t\tname: \"simple reduce SUM with private input\",\n\t\t\tsetup: func() *OperatorReduce {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\taggFunc := createAggFunc(ast.AggFuncSum, aggregation.CompleteMode, false)\n\n\t\t\t\treturn &OperatorReduce{\n\t\t\t\t\tbaseOperator: baseOperator{id: 1},\n\t\t\t\t\tinput:        input,\n\t\t\t\t\taggFunc:      aggFunc,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelSimpleReduce{},\n\t\t\tcheckKernel: func(k Kernel) {\n\t\t\t\treduceKernel := k.(*KernelSimpleReduce)\n\t\t\t\tassert.Equal(t, ast.AggFuncSum, reduceKernel.aggFunc.Name)\n\t\t\t\tprivatePlace, ok := reduceKernel.placement.(*privatePlacement)\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, \"alice\", privatePlace.partyCode)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"simple reduce SUM with secret input\",\n\t\t\tsetup: func() *OperatorReduce {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &secretPlacement{}, []string{})\n\t\t\t\taggFunc := createAggFunc(ast.AggFuncSum, aggregation.CompleteMode, false)\n\n\t\t\t\treturn &OperatorReduce{\n\t\t\t\t\tbaseOperator: baseOperator{id: 2},\n\t\t\t\t\tinput:        input,\n\t\t\t\t\taggFunc:      aggFunc,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelSimpleReduce{},\n\t\t\tcheckKernel: func(k Kernel) {\n\t\t\t\treduceKernel := k.(*KernelSimpleReduce)\n\t\t\t\tassert.Equal(t, ast.AggFuncSum, reduceKernel.aggFunc.Name)\n\t\t\t\t_, ok := reduceKernel.placement.(*secretPlacement)\n\t\t\t\tassert.True(t, ok)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"COUNT DISTINCT with private input\",\n\t\t\tsetup: func() *OperatorReduce {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\taggFunc := createAggFunc(ast.AggFuncCount, aggregation.CompleteMode, true)\n\n\t\t\t\treturn &OperatorReduce{\n\t\t\t\t\tbaseOperator: baseOperator{id: 3},\n\t\t\t\t\tinput:        input,\n\t\t\t\t\taggFunc:      aggFunc,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelPrivateDistinctCount{},\n\t\t\tcheckKernel: func(k Kernel) {\n\t\t\t\tdistinctCount := k.(*KernelPrivateDistinctCount)\n\t\t\t\tassert.Equal(t, \"alice\", distinctCount.partyCode)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"COUNT DISTINCT with secret input\",\n\t\t\tsetup: func() *OperatorReduce {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &secretPlacement{}, []string{})\n\t\t\t\taggFunc := createAggFunc(ast.AggFuncCount, aggregation.CompleteMode, true)\n\n\t\t\t\treturn &OperatorReduce{\n\t\t\t\t\tbaseOperator: baseOperator{id: 4},\n\t\t\t\t\tinput:        input,\n\t\t\t\t\taggFunc:      aggFunc,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelSecretDistinctCount{},\n\t\t},\n\t\t{\n\t\t\tname: \"unsupported aggregation function\",\n\t\t\tsetup: func() *OperatorReduce {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\taggFunc := createAggFunc(\"unsupported\", aggregation.CompleteMode, false)\n\n\t\t\t\treturn &OperatorReduce{\n\t\t\t\t\tbaseOperator: baseOperator{id: 5},\n\t\t\t\t\tinput:        input,\n\t\t\t\t\taggFunc:      aggFunc,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantErr:    true,\n\t\t\twantErrMsg: \"resolveReduce: unsupported aggregation function\",\n\t\t},\n\t\t{\n\t\t\tname: \"unsupported aggregation mode\",\n\t\t\tsetup: func() *OperatorReduce {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\taggFunc := createAggFunc(ast.AggFuncCount, aggregation.Partial1Mode, false)\n\n\t\t\t\treturn &OperatorReduce{\n\t\t\t\t\tbaseOperator: baseOperator{id: 6},\n\t\t\t\t\tinput:        input,\n\t\t\t\t\taggFunc:      aggFunc,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantErr:    true,\n\t\t\twantErrMsg: \"resolveReduce: unsupported aggregation mode\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\ttensorMetaManager = NewTensorMetaManager()\n\t\t\ttm = NewTensorManager(1)\n\t\t\tvt = NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\t\t\tscm = NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\t\t\tkr = NewKernelResolver(scm, vt, tm, nil)\n\n\t\t\tn := tt.setup()\n\t\t\tkernel, err := kr.resolveReduce(n)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\n\t\t\tif tt.checkKernel != nil {\n\t\t\t\ttt.checkKernel(kernel)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResolveBroadcastTo(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tscm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(scm, vt, tm, nil)\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetup          func() *OperatorBroadcastTo\n\t\twantKernelType any\n\t\twantErr        bool\n\t\twantErrMsg     string\n\t\tcheckKernel    func(Kernel)\n\t}{\n\t\t{\n\t\t\tname: \"broadcast with private shapeRef\",\n\t\t\tsetup: func() *OperatorBroadcastTo {\n\t\t\t\tshapeRef, _ := createPlacedTensor(\"shapeRef\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tscalar1, _ := createPlacedTensor(\"scalar1\", &publicPlacement{}, []string{\"alice\", \"bob\", \"carol\"})\n\t\t\t\tscalar2, _ := createPlacedTensor(\"scalar2\", &publicPlacement{}, []string{\"alice\", \"bob\", \"carol\"})\n\n\t\t\t\treturn &OperatorBroadcastTo{\n\t\t\t\t\tbaseOperator: baseOperator{id: 1},\n\t\t\t\t\tshapeRef:     shapeRef,\n\t\t\t\t\tscalars:      []*TensorMeta{scalar1, scalar2},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelBroadcastTo{},\n\t\t\tcheckKernel: func(k Kernel) {\n\t\t\t\tbroadcastKernel := k.(*KernelBroadcastTo)\n\t\t\t\tprivatePlace, ok := broadcastKernel.refPlacement.(*privatePlacement)\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, \"alice\", privatePlace.partyCode)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"broadcast with secret shapeRef\",\n\t\t\tsetup: func() *OperatorBroadcastTo {\n\t\t\t\tshapeRef, _ := createPlacedTensor(\"shapeRef\", &secretPlacement{}, []string{\"alice\", \"bob\"})\n\t\t\t\tscalar, _ := createPlacedTensor(\"scalar\", &publicPlacement{}, []string{\"alice\", \"bob\", \"carol\"})\n\n\t\t\t\treturn &OperatorBroadcastTo{\n\t\t\t\t\tbaseOperator: baseOperator{id: 2},\n\t\t\t\t\tshapeRef:     shapeRef,\n\t\t\t\t\tscalars:      []*TensorMeta{scalar},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelBroadcastTo{},\n\t\t\tcheckKernel: func(k Kernel) {\n\t\t\t\tbroadcastKernel := k.(*KernelBroadcastTo)\n\t\t\t\t_, ok := broadcastKernel.refPlacement.(*secretPlacement)\n\t\t\t\tassert.True(t, ok)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"non-public scalar error\",\n\t\t\tsetup: func() *OperatorBroadcastTo {\n\t\t\t\tshapeRef, _ := createPlacedTensor(\"shapeRef\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tscalar, _ := createPlacedTensor(\"scalar\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\n\t\t\t\treturn &OperatorBroadcastTo{\n\t\t\t\t\tbaseOperator: baseOperator{id: 3},\n\t\t\t\t\tshapeRef:     shapeRef,\n\t\t\t\t\tscalars:      []*TensorMeta{scalar},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantErr:    true,\n\t\t\twantErrMsg: \"resolveBroadcastTo: scalar\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\ttensorMetaManager = NewTensorMetaManager()\n\t\t\ttm = NewTensorManager(1)\n\t\t\tvt = NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\t\t\tscm = NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\t\t\tkr = NewKernelResolver(scm, vt, tm, nil)\n\n\t\t\tn := tt.setup()\n\t\t\tkernel, err := kr.resolveBroadcastTo(n)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\n\t\t\tif tt.checkKernel != nil {\n\t\t\t\ttt.checkKernel(kernel)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResolveCrossJoin(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(srm, vt, tm, nil)\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetup          func() *OperatorCrossJoin\n\t\twantKernelType any\n\t\twantLeftParty  string\n\t\twantRightParty string\n\t\twantErr        bool\n\t\twantErrMsg     string\n\t}{\n\t\t{\n\t\t\tname: \"cross join with valid party pair\",\n\t\t\tsetup: func() *OperatorCrossJoin {\n\t\t\t\tleftInput, _ := createPlacedTensor(\"left_input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\trightInput, _ := createPlacedTensor(\"right_input\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\n\t\t\t\treturn &OperatorCrossJoin{\n\t\t\t\t\tbaseOperator: baseOperator{id: 1},\n\t\t\t\t\tleftInputs:   []*TensorMeta{leftInput},\n\t\t\t\t\trightInputs:  []*TensorMeta{rightInput},\n\t\t\t\t\tleftOutputs:  []*TensorMeta{{ID: 101}},\n\t\t\t\t\trightOutputs: []*TensorMeta{{ID: 102}},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelCrossJoin{},\n\t\t\twantLeftParty:  \"alice\",\n\t\t\twantRightParty: \"bob\",\n\t\t},\n\t\t{\n\t\t\tname: \"cross join with existing placed tensors\",\n\t\t\tsetup: func() *OperatorCrossJoin {\n\t\t\t\tleftInput, _ := createPlacedTensor(\"left_input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"bob\"})\n\t\t\t\trightInput, _ := createPlacedTensor(\"right_input\", &privatePlacement{partyCode: \"bob\"}, []string{\"alice\", \"bob\"})\n\n\t\t\t\t// Create additional existing tensors\n\t\t\t\tleftInput2, _ := createPlacedTensor(\"left_input2\", &privatePlacement{partyCode: \"bob\"}, []string{\"alice\", \"bob\"})\n\t\t\t\trightInput2, _ := createPlacedTensor(\"right_input2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"bob\"})\n\t\t\t\tleftInput3, _ := createPlacedTensor(\"left_input3\", &privatePlacement{partyCode: \"bob\"}, []string{\"alice\", \"bob\"})\n\t\t\t\trightInput3, _ := createPlacedTensor(\"right_input3\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"bob\"})\n\n\t\t\t\treturn &OperatorCrossJoin{\n\t\t\t\t\tbaseOperator: baseOperator{id: 2},\n\t\t\t\t\tleftInputs:   []*TensorMeta{leftInput, leftInput2, leftInput3},\n\t\t\t\t\trightInputs:  []*TensorMeta{rightInput, rightInput2, rightInput3},\n\t\t\t\t\tleftOutputs:  []*TensorMeta{{ID: 201}},\n\t\t\t\t\trightOutputs: []*TensorMeta{{ID: 202}},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelCrossJoin{},\n\t\t\twantLeftParty:  \"bob\",\n\t\t\twantRightParty: \"alice\",\n\t\t},\n\t\t{\n\t\t\tname: \"cross join single party\",\n\t\t\tsetup: func() *OperatorCrossJoin {\n\t\t\t\tleftInput, _ := createPlacedTensor(\"left_input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\trightInput, _ := createPlacedTensor(\"right_input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\n\t\t\t\treturn &OperatorCrossJoin{\n\t\t\t\t\tbaseOperator: baseOperator{id: 3},\n\t\t\t\t\tleftInputs:   []*TensorMeta{leftInput},\n\t\t\t\t\trightInputs:  []*TensorMeta{rightInput},\n\t\t\t\t\tleftOutputs:  []*TensorMeta{{ID: 301}},\n\t\t\t\t\trightOutputs: []*TensorMeta{{ID: 302}},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelCrossJoin{},\n\t\t\twantLeftParty:  \"alice\",\n\t\t\twantRightParty: \"alice\",\n\t\t},\n\t\t{\n\t\t\tname: \"cross join with single party\",\n\t\t\tsetup: func() *OperatorCrossJoin {\n\t\t\t\tleftInput, _ := createPlacedTensor(\"left_input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\trightInput, _ := createPlacedTensor(\"right_input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\n\t\t\t\treturn &OperatorCrossJoin{\n\t\t\t\t\tbaseOperator: baseOperator{id: 4},\n\t\t\t\t\tleftInputs:   []*TensorMeta{leftInput},\n\t\t\t\t\trightInputs:  []*TensorMeta{rightInput},\n\t\t\t\t\tleftOutputs:  []*TensorMeta{{ID: 401}},\n\t\t\t\t\trightOutputs: []*TensorMeta{{ID: 402}},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelCrossJoin{},\n\t\t\twantLeftParty:  \"alice\",\n\t\t\twantRightParty: \"alice\",\n\t\t},\n\t\t{\n\t\t\tname: \"cross join with multiple parties choosing best pair\",\n\t\t\tsetup: func() *OperatorCrossJoin {\n\t\t\t\tleftInput, _ := createPlacedTensor(\"left_input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"carol\"})\n\t\t\t\trightInput, _ := createPlacedTensor(\"right_input\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\", \"carol\"})\n\n\t\t\t\t// Create existing tensors to influence heuristic\n\t\t\t\tleftInput2, _ := createPlacedTensor(\"left_input2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"carol\"})\n\t\t\t\trightInput2, _ := createPlacedTensor(\"right_input2\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\", \"carol\"})\n\n\t\t\t\treturn &OperatorCrossJoin{\n\t\t\t\t\tbaseOperator: baseOperator{id: 5},\n\t\t\t\t\tleftInputs:   []*TensorMeta{leftInput, leftInput2},\n\t\t\t\t\trightInputs:  []*TensorMeta{rightInput, rightInput2},\n\t\t\t\t\tleftOutputs:  []*TensorMeta{{ID: 501}},\n\t\t\t\t\trightOutputs: []*TensorMeta{{ID: 502}},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelCrossJoin{},\n\t\t\twantLeftParty:  \"alice\",\n\t\t\twantRightParty: \"bob\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\ttensorMetaManager = NewTensorMetaManager()\n\t\t\ttm = NewTensorManager(1)\n\t\t\tvt = NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\t\t\tsrm = NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\t\t\tkr = NewKernelResolver(srm, vt, tm, nil)\n\n\t\t\tn := tt.setup()\n\t\t\tkernel, err := kr.resolveCrossJoin(n)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\n\t\t\tif crossJoinKernel, ok := kernel.(*KernelCrossJoin); ok {\n\t\t\t\tassert.Equal(t, tt.wantLeftParty, crossJoinKernel.leftParty)\n\t\t\t\tassert.Equal(t, tt.wantRightParty, crossJoinKernel.rightParty)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResolveSort(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(srm, vt, tm, nil)\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetup          func() *OperatorSort\n\t\twantKernelType any\n\t\twantParty      string\n\t}{\n\t\t{\n\t\t\tname: \"sort with all tensors visible to same party\",\n\t\t\tsetup: func() *OperatorSort {\n\t\t\t\tsortKey, _ := createPlacedTensor(\"sort_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tpayload, _ := createPlacedTensor(\"payload\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\n\t\t\t\treturn &OperatorSort{\n\t\t\t\t\tbaseOperator: baseOperator{id: 1},\n\t\t\t\t\tsortKeys:     []*TensorMeta{sortKey},\n\t\t\t\t\tpayloads:     []*TensorMeta{payload},\n\t\t\t\t\toutputs:      []*TensorMeta{{ID: 101}},\n\t\t\t\t\tdescending:   []bool{false},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelPrivateSort{},\n\t\t\twantParty:      \"alice\",\n\t\t},\n\t\t{\n\t\t\tname: \"sort with secret inputs\",\n\t\t\tsetup: func() *OperatorSort {\n\t\t\t\tsortKey, _ := createPlacedTensor(\"sort_key\", &secretPlacement{}, []string{})\n\t\t\t\tpayload, _ := createPlacedTensor(\"payload\", &secretPlacement{}, []string{})\n\n\t\t\t\treturn &OperatorSort{\n\t\t\t\t\tbaseOperator: baseOperator{id: 3},\n\t\t\t\t\tsortKeys:     []*TensorMeta{sortKey},\n\t\t\t\t\tpayloads:     []*TensorMeta{payload},\n\t\t\t\t\toutputs:      []*TensorMeta{{ID: 301}},\n\t\t\t\t\tdescending:   []bool{false},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelSecretSort{},\n\t\t},\n\t\t{\n\t\t\tname: \"sort with public inputs - secret placement\",\n\t\t\tsetup: func() *OperatorSort {\n\t\t\t\tsortKey, _ := createPlacedTensor(\"sort_key\", &publicPlacement{}, []string{\"alice\", \"bob\", \"carol\"})\n\t\t\t\tpayload, _ := createPlacedTensor(\"payload\", &publicPlacement{}, []string{\"alice\", \"bob\", \"carol\"})\n\n\t\t\t\treturn &OperatorSort{\n\t\t\t\t\tbaseOperator: baseOperator{id: 4},\n\t\t\t\t\tsortKeys:     []*TensorMeta{sortKey},\n\t\t\t\t\tpayloads:     []*TensorMeta{payload},\n\t\t\t\t\toutputs:      []*TensorMeta{{ID: 401}},\n\t\t\t\t\tdescending:   []bool{false},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelPrivateSort{},\n\t\t\twantParty:      \"alice\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\ttensorMetaManager = NewTensorMetaManager()\n\t\t\ttm = NewTensorManager(1)\n\t\t\tvt = NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\t\t\tsrm = NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\t\t\tkr = NewKernelResolver(srm, vt, tm, nil)\n\n\t\t\tn := tt.setup()\n\t\t\tkernel, err := kr.resolveSort(n)\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\n\t\t\tif privateSortKernel, ok := kernel.(*KernelPrivateSort); ok {\n\t\t\t\tassert.Equal(t, tt.wantParty, privateSortKernel.partyCode)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResolveIn(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(srm, vt, tm, nil)\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetup          func() *OperatorIn\n\t\twantKernelType any\n\t\twantLeftParty  string\n\t\twantRightParty string\n\t\twantParty      string\n\t\twantErr        bool\n\t\twantErrMsg     string\n\t}{\n\t\t{\n\t\t\tname: \"local in with common party\",\n\t\t\tsetup: func() *OperatorIn {\n\t\t\t\tleft, _ := createPlacedTensor(\"left\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tright, _ := createPlacedTensor(\"right\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\n\t\t\t\treturn &OperatorIn{\n\t\t\t\t\tbaseOperator: baseOperator{id: 1},\n\t\t\t\t\tleft:         left,\n\t\t\t\t\tright:        right,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelLocalIn{},\n\t\t\twantParty:      \"alice\",\n\t\t},\n\t\t{\n\t\t\tname: \"psi in with different parties\",\n\t\t\tsetup: func() *OperatorIn {\n\t\t\t\tleft, _ := createPlacedTensor(\"left\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tright, _ := createPlacedTensor(\"right\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\n\t\t\t\treturn &OperatorIn{\n\t\t\t\t\tbaseOperator: baseOperator{id: 2},\n\t\t\t\t\tleft:         left,\n\t\t\t\t\tright:        right,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelPsiIn{},\n\t\t\twantLeftParty:  \"alice\",\n\t\t\twantRightParty: \"bob\",\n\t\t},\n\t\t{\n\t\t\tname: \"in with secret inputs\",\n\t\t\tsetup: func() *OperatorIn {\n\t\t\t\tleft, _ := createPlacedTensor(\"left\", &secretPlacement{}, []string{})\n\t\t\t\tright, _ := createPlacedTensor(\"right\", &secretPlacement{}, []string{})\n\n\t\t\t\treturn &OperatorIn{\n\t\t\t\t\tbaseOperator: baseOperator{id: 4},\n\t\t\t\t\tleft:         left,\n\t\t\t\t\tright:        right,\n\t\t\t\t}\n\t\t\t},\n\t\t\twantErr:    true,\n\t\t\twantErrMsg: \"resolveIn: no valid kernel\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\ttensorMetaManager = NewTensorMetaManager()\n\t\t\ttm = NewTensorManager(1)\n\t\t\tvt = NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\t\t\tsrm = NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\t\t\tkr = NewKernelResolver(srm, vt, tm, nil)\n\n\t\t\tn := tt.setup()\n\t\t\tkernel, err := kr.resolveIn(n)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\n\t\t\tswitch k := kernel.(type) {\n\t\t\tcase *KernelLocalIn:\n\t\t\t\tassert.Equal(t, tt.wantParty, k.partyCode)\n\t\t\tcase *KernelPsiIn:\n\t\t\t\tassert.Equal(t, tt.wantLeftParty, k.leftParty)\n\t\t\t\tassert.Equal(t, tt.wantRightParty, k.rightParty)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResolveWindow(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(srm, vt, tm, nil)\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetup          func() *OperatorWindow\n\t\twantKernelType any\n\t\twantParty      string\n\t}{\n\t\t{\n\t\t\tname: \"private window with common party\",\n\t\t\tsetup: func() *OperatorWindow {\n\t\t\t\tpartitionKey, _ := createPlacedTensor(\"partition_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\torderKey, _ := createPlacedTensor(\"order_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\n\t\t\t\treturn &OperatorWindow{\n\t\t\t\t\tbaseOperator:  baseOperator{id: 1},\n\t\t\t\t\tpartitionKeys: []*TensorMeta{partitionKey},\n\t\t\t\t\torderKeys:     []*TensorMeta{orderKey},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelPrivateWindow{},\n\t\t\twantParty:      \"alice\",\n\t\t},\n\t\t{\n\t\t\tname: \"oblivious window with no common party\",\n\t\t\tsetup: func() *OperatorWindow {\n\t\t\t\tpartitionKey, _ := createPlacedTensor(\"partition_key\", &secretPlacement{}, []string{\"alice\"})\n\t\t\t\torderKey, _ := createPlacedTensor(\"order_key\", &secretPlacement{}, []string{})\n\n\t\t\t\treturn &OperatorWindow{\n\t\t\t\t\tbaseOperator:  baseOperator{id: 2},\n\t\t\t\t\tpartitionKeys: []*TensorMeta{partitionKey},\n\t\t\t\t\torderKeys:     []*TensorMeta{orderKey},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantKernelType: &KernelObliviousWindow{},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\ttensorMetaManager = NewTensorMetaManager()\n\t\t\ttm = NewTensorManager(1)\n\t\t\tvt = NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\t\t\tsrm = NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\t\t\tkr = NewKernelResolver(srm, vt, tm, nil)\n\n\t\t\tn := tt.setup()\n\t\t\tkernel, err := kr.resolveWindow(n)\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\n\t\t\tif privateWindowKernel, ok := kernel.(*KernelPrivateWindow); ok {\n\t\t\t\tassert.Equal(t, tt.wantParty, privateWindowKernel.partyCode)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResolveFunction(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\ttm := NewTensorManager(1)\n\tkr := NewKernelResolver(srm, vt, tm, nil)\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) (*TensorMeta, *graph.Tensor) {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta, tensor\n\t}\n\n\ttests := []struct {\n\t\tname           string\n\t\tfuncName       string\n\t\tsetup          func() []*TensorMeta\n\t\twantKernelType any\n\t\twantParty      string\n\t\twantErr        bool\n\t\twantErrMsg     string\n\t}{\n\t\t// ArrowFunction cases\n\t\t{\n\t\t\tname:     \"arrow function with private party\",\n\t\t\tfuncName: ast.Lower,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\treturn []*TensorMeta{input}\n\t\t\t},\n\t\t\twantKernelType: &KernelArrowFunction{},\n\t\t\twantParty:      \"alice\",\n\t\t},\n\t\t{\n\t\t\tname:     \"arrow function with no private party\",\n\t\t\tfuncName: ast.Upper,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &secretPlacement{}, []string{})\n\t\t\t\treturn []*TensorMeta{input}\n\t\t\t},\n\t\t\twantErr:    true,\n\t\t\twantErrMsg: \"resolveFunction: could not find proper candidate\",\n\t\t},\n\n\t\t// Unary cases\n\t\t{\n\t\t\tname:     \"unary with private input\",\n\t\t\tfuncName: ast.Abs,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\t\t\t\treturn []*TensorMeta{input}\n\t\t\t},\n\t\t\twantKernelType: &KernelUnary{},\n\t\t},\n\t\t{\n\t\t\tname:     \"unary with secret input\",\n\t\t\tfuncName: ast.Sqrt,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &secretPlacement{}, []string{})\n\t\t\t\treturn []*TensorMeta{input}\n\t\t\t},\n\t\t\twantKernelType: &KernelUnary{},\n\t\t},\n\n\t\t// Binary cases\n\t\t{\n\t\t\tname:     \"binary with common private party\",\n\t\t\tfuncName: ast.Plus,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tleft, _ := createPlacedTensor(\"left\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tright, _ := createPlacedTensor(\"right\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\treturn []*TensorMeta{left, right}\n\t\t\t},\n\t\t\twantKernelType: &KernelBinary{},\n\t\t\twantParty:      \"alice\",\n\t\t},\n\t\t{\n\t\t\tname:     \"binary with secret inputs\",\n\t\t\tfuncName: ast.Mul,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tleft, _ := createPlacedTensor(\"left\", &secretPlacement{}, []string{})\n\t\t\t\tright, _ := createPlacedTensor(\"right\", &secretPlacement{}, []string{})\n\t\t\t\treturn []*TensorMeta{left, right}\n\t\t\t},\n\t\t\twantKernelType: &KernelBinary{},\n\t\t},\n\n\t\t// VariadicCompare cases\n\t\t{\n\t\t\tname:     \"variadic compare with private party\",\n\t\t\tfuncName: ast.Greatest,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput1, _ := createPlacedTensor(\"input1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tinput2, _ := createPlacedTensor(\"input2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\treturn []*TensorMeta{input1, input2}\n\t\t\t},\n\t\t\twantKernelType: &KernelVariadicCompare{},\n\t\t\twantParty:      \"alice\",\n\t\t},\n\t\t{\n\t\t\tname:     \"variadic compare with secret inputs\",\n\t\t\tfuncName: ast.Least,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput1, _ := createPlacedTensor(\"input1\", &secretPlacement{}, []string{})\n\t\t\t\tinput2, _ := createPlacedTensor(\"input2\", &secretPlacement{}, []string{})\n\t\t\t\treturn []*TensorMeta{input1, input2}\n\t\t\t},\n\t\t\twantKernelType: &KernelVariadicCompare{},\n\t\t},\n\n\t\t// PrivateFunc cases\n\t\t{\n\t\t\tname:     \"private function with common party\",\n\t\t\tfuncName: ast.Ifnull,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput1, _ := createPlacedTensor(\"input1\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\t\t\t\tinput2, _ := createPlacedTensor(\"input2\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\t\t\t\treturn []*TensorMeta{input1, input2}\n\t\t\t},\n\t\t\twantKernelType: &KernelPrivateFunc{},\n\t\t\twantParty:      \"bob\",\n\t\t},\n\t\t{\n\t\t\tname:     \"private function with no common party\",\n\t\t\tfuncName: ast.IsNull,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput1, _ := createPlacedTensor(\"input1\", &secretPlacement{}, []string{})\n\t\t\t\tinput2, _ := createPlacedTensor(\"input2\", &secretPlacement{}, []string{})\n\t\t\t\treturn []*TensorMeta{input1, input2}\n\t\t\t},\n\t\t\twantErr:    true,\n\t\t\twantErrMsg: \"resolveFunction: could not find proper candidate\",\n\t\t},\n\n\t\t// Cast cases\n\t\t{\n\t\t\tname:     \"cast with private input\",\n\t\t\tfuncName: ast.Cast,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\treturn []*TensorMeta{input}\n\t\t\t},\n\t\t\twantKernelType: &KernelCast{},\n\t\t},\n\t\t{\n\t\t\tname:     \"cast with secret input\",\n\t\t\tfuncName: ast.Cast,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput, _ := createPlacedTensor(\"input\", &secretPlacement{}, []string{})\n\t\t\t\treturn []*TensorMeta{input}\n\t\t\t},\n\t\t\twantErr:    true,\n\t\t\twantErrMsg: \"not support cast for string in spu\",\n\t\t},\n\n\t\t// If cases\n\t\t{\n\t\t\tname:     \"if with common private party\",\n\t\t\tfuncName: ast.If,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tcond, _ := createPlacedTensor(\"cond\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\ttrueVal, _ := createPlacedTensor(\"true\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tfalseVal, _ := createPlacedTensor(\"false\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\treturn []*TensorMeta{cond, trueVal, falseVal}\n\t\t\t},\n\t\t\twantKernelType: &KernelIf{},\n\t\t\twantParty:      \"alice\",\n\t\t},\n\t\t{\n\t\t\tname:     \"if with secret inputs\",\n\t\t\tfuncName: ast.If,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tcond, _ := createPlacedTensor(\"cond\", &secretPlacement{}, []string{})\n\t\t\t\ttrueVal, _ := createPlacedTensor(\"true\", &secretPlacement{}, []string{})\n\t\t\t\tfalseVal, _ := createPlacedTensor(\"false\", &secretPlacement{}, []string{})\n\t\t\t\treturn []*TensorMeta{cond, trueVal, falseVal}\n\t\t\t},\n\t\t\twantKernelType: &KernelIf{},\n\t\t},\n\n\t\t// Case cases\n\t\t{\n\t\t\tname:     \"case with common private party\",\n\t\t\tfuncName: ast.Case,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput1, _ := createPlacedTensor(\"input1\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\t\t\t\tinput2, _ := createPlacedTensor(\"input2\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\t\t\t\tinput3, _ := createPlacedTensor(\"input3\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})\n\t\t\t\treturn []*TensorMeta{input1, input2, input3}\n\t\t\t},\n\t\t\twantKernelType: &KernelCase{},\n\t\t\twantParty:      \"bob\",\n\t\t},\n\t\t{\n\t\t\tname:     \"case with secret inputs\",\n\t\t\tfuncName: ast.Case,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput1, _ := createPlacedTensor(\"input1\", &secretPlacement{}, []string{})\n\t\t\t\tinput2, _ := createPlacedTensor(\"input2\", &secretPlacement{}, []string{})\n\t\t\t\tinput3, _ := createPlacedTensor(\"input3\", &secretPlacement{}, []string{})\n\t\t\t\treturn []*TensorMeta{input1, input2, input3}\n\t\t\t},\n\t\t\twantKernelType: &KernelCase{},\n\t\t},\n\n\t\t// Concat cases\n\t\t{\n\t\t\tname:     \"concat with private party\",\n\t\t\tfuncName: ast.Concat,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput1, _ := createPlacedTensor(\"input1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\tinput2, _ := createPlacedTensor(\"input2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})\n\t\t\t\treturn []*TensorMeta{input1, input2}\n\t\t\t},\n\t\t\twantKernelType: &KernelConcatString{},\n\t\t\twantParty:      \"alice\",\n\t\t},\n\t\t{\n\t\t\tname:     \"concat with no common party\",\n\t\t\tfuncName: ast.Concat,\n\t\t\tsetup: func() []*TensorMeta {\n\t\t\t\tinput1, _ := createPlacedTensor(\"input1\", &secretPlacement{}, []string{})\n\t\t\t\tinput2, _ := createPlacedTensor(\"input2\", &secretPlacement{}, []string{})\n\t\t\t\treturn []*TensorMeta{input1, input2}\n\t\t\t},\n\t\t\twantErr:    true,\n\t\t\twantErrMsg: \"could not find proper candidate for string concat\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset for each test\n\t\t\ttensorMetaManager = NewTensorMetaManager()\n\t\t\ttm = NewTensorManager(1)\n\t\t\tvt = NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\t\t\tsrm = NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\t\t\tkr = NewKernelResolver(srm, vt, tm, nil)\n\n\t\t\tinputs := tt.setup()\n\t\t\tn := &OperatorFunction{\n\t\t\t\tbaseOperator: baseOperator{id: 1},\n\t\t\t\tfuncName:     tt.funcName,\n\t\t\t\tinputs:       inputs,\n\t\t\t}\n\n\t\t\tif tt.funcName == ast.Cast {\n\t\t\t\toutput := &TensorMeta{\n\t\t\t\t\tDType: graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING),\n\t\t\t\t}\n\t\t\t\t// output type need to be checked when resolving cast\n\t\t\t\tn.output = output\n\t\t\t}\n\n\t\t\tkernel, err := kr.resolveFunction(n)\n\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantKernelType, kernel)\n\n\t\t\tswitch k := kernel.(type) {\n\t\t\tcase *KernelArrowFunction:\n\t\t\t\tassert.Equal(t, tt.wantParty, k.partyCode)\n\t\t\tcase *KernelBinary:\n\t\t\t\tif tt.wantParty != \"\" {\n\t\t\t\t\tassert.Equal(t, &privatePlacement{partyCode: tt.wantParty}, k.lhsPlace)\n\t\t\t\t\tassert.Equal(t, &privatePlacement{partyCode: tt.wantParty}, k.rhsPlace)\n\t\t\t\t}\n\t\t\tcase *KernelVariadicCompare:\n\t\t\t\tif tt.wantParty != \"\" {\n\t\t\t\t\tassert.Equal(t, &privatePlacement{partyCode: tt.wantParty}, k.placement)\n\t\t\t\t}\n\t\t\tcase *KernelPrivateFunc:\n\t\t\t\tassert.Equal(t, tt.wantParty, k.partyCode)\n\t\t\tcase *KernelIf:\n\t\t\t\tif tt.wantParty != \"\" {\n\t\t\t\t\tassert.Equal(t, &privatePlacement{partyCode: tt.wantParty}, k.condPlace)\n\t\t\t\t}\n\t\t\tcase *KernelCase:\n\t\t\t\tif tt.wantParty != \"\" {\n\t\t\t\t\tassert.Equal(t, &privatePlacement{partyCode: tt.wantParty}, k.outputPlacement)\n\t\t\t\t}\n\t\t\tcase *KernelConcatString:\n\t\t\t\tassert.Equal(t, tt.wantParty, k.partyCode)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/kernel_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\ntype kernelTestCase struct {\n\tname               string\n\tnode               Operator\n\tkernel             Kernel\n\twantEnsureErr      bool\n\twantEnsureErrMsg   string\n\twantToEngineErr    bool\n\twantToEngineErrMsg string\n\texecNodeChecker    func(engineOps []*graph.ExecutionNode)\n}\n\nfunc createAggFunc(name string, hasDistinct bool, mode aggregation.AggFunctionMode) *aggregation.AggFuncDesc {\n\taggFunc := &aggregation.AggFuncDesc{}\n\taggFunc.Name = name\n\taggFunc.HasDistinct = hasDistinct\n\taggFunc.Mode = mode\n\treturn aggFunc\n}\n\nfunc createTestSuit() (*ExecutionGraphBuilder, func(string, tensorPlacement, []string) *TensorMeta, func(string) *TensorMeta) {\n\ttensorMetaManager := NewTensorMetaManager()\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\", \"carol\"})\n\tinfo := &graph.EnginesInfo{}\n\n\tbuilder := NewExecutionGraphBuilder(tensorMetaManager, srm, vt, info, &v1.CompileOptions{Batched: false})\n\n\tcreateInputTensor := func(name string, place tensorPlacement, vis []string) *TensorMeta {\n\t\tmeta := tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tvt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\t_, _ = builder.tm.CreateAndSetFirstTensor(meta, place)\n\t\treturn meta\n\t}\n\n\tcreateOutputTensor := func(name string) *TensorMeta {\n\t\treturn tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t}\n\n\treturn builder, createInputTensor, createOutputTensor\n}\n\nfunc runKernelTests(t *testing.T, builder *ExecutionGraphBuilder, tests []kernelTestCase) {\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Reset builder state for each test\n\t\t\tbuilder.pipelineEngineNodes = nil\n\n\t\t\t// Set proper next tensor ID, since tensor meta may be created after TensorManager is created\n\t\t\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + 1\n\n\t\t\t// Test ensureTensorPlace\n\t\t\terr := tt.kernel.ensureTensorPlace(builder, tt.node)\n\t\t\tif tt.wantEnsureErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantEnsureErrMsg)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tassert.NoError(t, err)\n\n\t\t\t// Test toEngineNodes\n\t\t\terr = tt.kernel.toEngineNodes(builder, tt.node)\n\t\t\tif tt.wantToEngineErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantToEngineErrMsg)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tassert.NoError(t, err)\n\n\t\t\t// Verify the operation was added\n\t\t\tassert.Len(t, builder.pipelineEngineNodes, 1)\n\n\t\t\tif tt.execNodeChecker != nil {\n\t\t\t\ttt.execNodeChecker(builder.pipelineEngineNodes[0].ExecutionNodes)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestKernelRunSQL(t *testing.T) {\n\tbuilder, _, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic test\",\n\t\t\tnode: &OperatorRunSQL{\n\t\t\t\tsourceParty: \"alice\",\n\t\t\t\tsql:         \"SELECT * FROM table1\",\n\t\t\t\toutputs: []*TensorMeta{\n\t\t\t\t\tcreateOutputTensor(\"col1\"),\n\t\t\t\t\tcreateOutputTensor(\"col2\"),\n\t\t\t\t},\n\t\t\t\ttableRefs: []string{\"table1\"},\n\t\t\t},\n\t\t\tkernel: &KernelRunSQL{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameRunSQL, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, 2, len(engineOps[0].Outputs[\"Out\"]))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"empty outputs\",\n\t\t\tnode: &OperatorRunSQL{\n\t\t\t\tsourceParty: \"bob\",\n\t\t\t\tsql:         \"SELECT 1\",\n\t\t\t\toutputs:     []*TensorMeta{},\n\t\t\t\ttableRefs:   []string{},\n\t\t\t},\n\t\t\tkernel:             &KernelRunSQL{},\n\t\t\twantToEngineErr:    true,\n\t\t\twantToEngineErrMsg: \"must contains at least one argument\",\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelPublishResult(t *testing.T) {\n\tbuilder, createInputTensor, _ := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic publish result\",\n\t\t\tnode: &OperatorResult{\n\t\t\t\tresultTensors: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"col1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"col2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutputNames:     []string{\"result1\", \"result2\"},\n\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t},\n\t\t\tkernel: &KernelPublishResult{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNamePublish, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, 2, len(engineOps[0].Outputs[\"Out\"]))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"length mismatch\",\n\t\t\tnode: &OperatorResult{\n\t\t\t\tresultTensors: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"col1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutputNames:     []string{\"result1\", \"result2\"}, // mismatch\n\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t},\n\t\t\tkernel:             &KernelPublishResult{},\n\t\t\twantToEngineErr:    true,\n\t\t\twantToEngineErrMsg: \"length not match\",\n\t\t},\n\t\t{\n\t\t\tname: \"invisible to issuer\",\n\t\t\tnode: &OperatorResult{\n\t\t\t\tresultTensors: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"col1\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"}),\n\t\t\t\t},\n\t\t\t\toutputNames:     []string{\"result1\"},\n\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t},\n\t\t\tkernel:           &KernelPublishResult{},\n\t\t\twantEnsureErr:    true,\n\t\t\twantEnsureErrMsg: \"not visible\",\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelInsertTable(t *testing.T) {\n\tbuilder, createInputTensor, _ := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic insert table\",\n\t\t\tnode: &OperatorResult{\n\t\t\t\tresultTensors: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"col1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"col2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutputNames:     []string{\"result1\", \"result2\"},\n\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t},\n\t\t\tkernel: &KernelInsertTable{insertTableOpt: &core.InsertTableOption{}},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameInsertTable, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, 2, len(engineOps[0].Outputs[\"Out\"]))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"length mismatch\",\n\t\t\tnode: &OperatorResult{\n\t\t\t\tresultTensors: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"col1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutputNames:     []string{\"result1\", \"result2\"}, // mismatch\n\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t},\n\t\t\tkernel:             &KernelInsertTable{insertTableOpt: &core.InsertTableOption{}},\n\t\t\twantToEngineErr:    true,\n\t\t\twantToEngineErrMsg: \"length not match\",\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelDumpFile(t *testing.T) {\n\tbuilder, createInputTensor, _ := createTestSuit()\n\n\tintoOpt := &core.IntoOpt{\n\t\tOpt: &ast.SelectIntoOption{\n\t\t\tPartyFiles: []*ast.PartyFile{\n\t\t\t\t{PartyCode: \"alice\", FileName: \"/tmp/test.csv\"},\n\t\t\t},\n\t\t\tLinesInfo:  &ast.LinesClause{},\n\t\t\tFieldsInfo: &ast.FieldsClause{},\n\t\t},\n\t}\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic dump file\",\n\t\t\tnode: &OperatorResult{\n\t\t\t\tresultTensors: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"col1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"col2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutputNames:     []string{\"result1\", \"result2\"},\n\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t},\n\t\t\tkernel: &KernelDumpFile{intoOpt: intoOpt},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameDumpFile, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"length mismatch\",\n\t\t\tnode: &OperatorResult{\n\t\t\t\tresultTensors: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"col1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutputNames:     []string{\"result1\", \"result2\"}, // mismatch\n\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t},\n\t\t\tkernel:             &KernelDumpFile{intoOpt: intoOpt},\n\t\t\twantToEngineErr:    true,\n\t\t\twantToEngineErrMsg: \"length\",\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelPsiEQJoin(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"cross-party index tensor copying\",\n\t\t\tnode: &OperatorEQJoin{\n\t\t\t\tleftKeys:      []*TensorMeta{createInputTensor(\"left_key1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\trightKeys:     []*TensorMeta{createInputTensor(\"right_key1\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})},\n\t\t\t\tleftPayloads:  []*TensorMeta{createInputTensor(\"left_payload1\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})},\n\t\t\t\trightPayloads: []*TensorMeta{createInputTensor(\"right_payload1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\tleftOutputs:   []*TensorMeta{createOutputTensor(\"left_out1\")},\n\t\t\t\trightOutputs:  []*TensorMeta{createOutputTensor(\"right_out1\")},\n\t\t\t\tjoinType:      core.InnerJoin,\n\t\t\t},\n\t\t\tkernel: &KernelPsiEQJoin{\n\t\t\t\tleftParty:              \"alice\",\n\t\t\t\trightParty:             \"bob\",\n\t\t\t\tleftPayloadsPlacement:  []tensorPlacement{&privatePlacement{partyCode: \"bob\"}},\n\t\t\t\trightPayloadsPlacement: []tensorPlacement{&privatePlacement{partyCode: \"alice\"}},\n\t\t\t\tleftTouchResult:        true,\n\t\t\t\trightTouchResult:       true,\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, len(engineOps), 5) // PSI join + left filter + right filter + 2 copies\n\t\t\t\tassert.Equal(t, operator.OpNameJoin, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"basic psi join with keys and payloads\",\n\t\t\tnode: &OperatorEQJoin{\n\t\t\t\tleftKeys:      []*TensorMeta{createInputTensor(\"left_key1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\trightKeys:     []*TensorMeta{createInputTensor(\"right_key1\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})},\n\t\t\t\tleftPayloads:  []*TensorMeta{createInputTensor(\"left_payload1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\trightPayloads: []*TensorMeta{createInputTensor(\"right_payload1\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})},\n\t\t\t\tleftOutputs:   []*TensorMeta{createOutputTensor(\"left_out1\")},\n\t\t\t\trightOutputs:  []*TensorMeta{createOutputTensor(\"right_out1\")},\n\t\t\t\tjoinType:      core.InnerJoin,\n\t\t\t},\n\t\t\tkernel: &KernelPsiEQJoin{\n\t\t\t\tleftParty:              \"alice\",\n\t\t\t\trightParty:             \"bob\",\n\t\t\t\tleftPayloadsPlacement:  []tensorPlacement{&privatePlacement{partyCode: \"alice\"}},\n\t\t\t\trightPayloadsPlacement: []tensorPlacement{&privatePlacement{partyCode: \"bob\"}},\n\t\t\t\tleftTouchResult:        true,\n\t\t\t\trightTouchResult:       true,\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, len(engineOps), 3) // PSI join + left filter + right filter\n\t\t\t\tassert.Equal(t, operator.OpNameJoin, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"payload and output mismatch\",\n\t\t\tnode: &OperatorEQJoin{\n\t\t\t\tleftKeys:      []*TensorMeta{createInputTensor(\"left_key1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\trightKeys:     []*TensorMeta{createInputTensor(\"right_key1\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})},\n\t\t\t\tleftPayloads:  []*TensorMeta{},\n\t\t\t\trightPayloads: []*TensorMeta{},\n\t\t\t\tleftOutputs:   []*TensorMeta{createOutputTensor(\"left_out1\")},\n\t\t\t\trightOutputs:  []*TensorMeta{createOutputTensor(\"right_out1\")},\n\t\t\t\tjoinType:      core.InnerJoin,\n\t\t\t},\n\t\t\tkernel: &KernelPsiEQJoin{\n\t\t\t\tleftParty:              \"alice\",\n\t\t\t\trightParty:             \"bob\",\n\t\t\t\tleftPayloadsPlacement:  []tensorPlacement{},\n\t\t\t\trightPayloadsPlacement: []tensorPlacement{},\n\t\t\t\tleftTouchResult:        true,\n\t\t\t\trightTouchResult:       true,\n\t\t\t},\n\t\t\twantToEngineErr:    true,\n\t\t\twantToEngineErrMsg: \"length not match\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid operator type\",\n\t\t\tnode: &OperatorRunSQL{\n\t\t\t\tsourceParty: \"alice\",\n\t\t\t\tsql:         \"SELECT 1\",\n\t\t\t\toutputs:     []*TensorMeta{createOutputTensor(\"col1\")},\n\t\t\t\ttableRefs:   []string{},\n\t\t\t},\n\t\t\tkernel:           &KernelPsiEQJoin{},\n\t\t\twantEnsureErr:    true,\n\t\t\twantEnsureErrMsg: \"expect eq join node\",\n\t\t},\n\t\t{\n\t\t\tname: \"empty payloads handling\",\n\t\t\tnode: &OperatorEQJoin{\n\t\t\t\tleftKeys:      []*TensorMeta{createInputTensor(\"left_key1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\trightKeys:     []*TensorMeta{createInputTensor(\"right_key1\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})},\n\t\t\t\tleftPayloads:  []*TensorMeta{},\n\t\t\t\trightPayloads: []*TensorMeta{},\n\t\t\t\tleftOutputs:   []*TensorMeta{},\n\t\t\t\trightOutputs:  []*TensorMeta{},\n\t\t\t\tjoinType:      core.InnerJoin,\n\t\t\t},\n\t\t\tkernel: &KernelPsiEQJoin{\n\t\t\t\tleftParty:              \"alice\",\n\t\t\t\trightParty:             \"bob\",\n\t\t\t\tleftPayloadsPlacement:  []tensorPlacement{},\n\t\t\t\trightPayloadsPlacement: []tensorPlacement{},\n\t\t\t\tleftTouchResult:        false,\n\t\t\t\trightTouchResult:       false,\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, len(engineOps), 1) // PSI join\n\t\t\t\tassert.Equal(t, operator.OpNameJoin, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelSecretEQJoin(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic secret join with keys and payloads\",\n\t\t\tnode: &OperatorEQJoin{\n\t\t\t\tleftKeys:      []*TensorMeta{createInputTensor(\"left_key1\", &secretPlacement{}, []string{})},\n\t\t\t\trightKeys:     []*TensorMeta{createInputTensor(\"right_key1\", &secretPlacement{}, []string{})},\n\t\t\t\tleftPayloads:  []*TensorMeta{createInputTensor(\"left_payload1\", &secretPlacement{}, []string{})},\n\t\t\t\trightPayloads: []*TensorMeta{createInputTensor(\"right_payload1\", &secretPlacement{}, []string{})},\n\t\t\t\tleftOutputs:   []*TensorMeta{createOutputTensor(\"left_out1\")},\n\t\t\t\trightOutputs:  []*TensorMeta{createOutputTensor(\"right_out1\")},\n\t\t\t\tjoinType:      core.InnerJoin,\n\t\t\t},\n\t\t\tkernel: &KernelSecretEQJoin{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, len(engineOps), 1)\n\t\t\t\tassert.Equal(t, operator.OpNameSecretJoin, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"secret join with keys only\",\n\t\t\tnode: &OperatorEQJoin{\n\t\t\t\tleftKeys:      []*TensorMeta{createInputTensor(\"left_key1\", &secretPlacement{}, []string{})},\n\t\t\t\trightKeys:     []*TensorMeta{createInputTensor(\"right_key1\", &secretPlacement{}, []string{})},\n\t\t\t\tleftPayloads:  []*TensorMeta{},\n\t\t\t\trightPayloads: []*TensorMeta{},\n\t\t\t\tleftOutputs:   []*TensorMeta{createOutputTensor(\"left_out1\")},\n\t\t\t\trightOutputs:  []*TensorMeta{createOutputTensor(\"right_out1\")},\n\t\t\t\tjoinType:      core.InnerJoin,\n\t\t\t},\n\t\t\tkernel: &KernelSecretEQJoin{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, len(engineOps), 1)\n\t\t\t\tassert.Equal(t, operator.OpNameSecretJoin, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelSimpleReduce(t *testing.T) {\n\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic secret reduce with SUM\",\n\t\t\tnode: &OperatorReduce{\n\t\t\t\tinput:   createInputTensor(\"input\", &secretPlacement{}, []string{}),\n\t\t\t\toutput:  createOutputTensor(\"output\"),\n\t\t\t\taggFunc: createAggFunc(ast.AggFuncSum, false, aggregation.CompleteMode),\n\t\t\t},\n\t\t\tkernel: &KernelSimpleReduce{placement: &secretPlacement{}, aggFunc: createAggFunc(ast.AggFuncSum, false, aggregation.CompleteMode)},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, len(engineOps), 1)\n\t\t\t\tassert.Equal(t, operator.OpNameReduceSum, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"basic private reduce with MAX\",\n\t\t\tnode: &OperatorReduce{\n\t\t\t\tinput:   createInputTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\toutput:  createOutputTensor(\"output\"),\n\t\t\t\taggFunc: createAggFunc(ast.AggFuncMax, false, aggregation.CompleteMode),\n\t\t\t},\n\t\t\tkernel: &KernelSimpleReduce{placement: &privatePlacement{partyCode: \"alice\"}, aggFunc: createAggFunc(ast.AggFuncMax, false, aggregation.CompleteMode)},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, len(engineOps), 1)\n\t\t\t\tassert.Equal(t, operator.OpNameReduceMax, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelPrivateDistinctCount(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic private distinct count\",\n\t\t\tnode: &OperatorReduce{\n\t\t\t\tinput:   createInputTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\toutput:  createOutputTensor(\"output\"),\n\t\t\t\taggFunc: createAggFunc(ast.AggFuncCount, true, aggregation.CompleteMode),\n\t\t\t},\n\t\t\tkernel: &KernelPrivateDistinctCount{partyCode: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 2, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameUnique, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameReduceCount, engineOps[1].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelSecretDistinctCount(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic secret distinct count\",\n\t\t\tnode: &OperatorReduce{\n\t\t\t\tinput:   createInputTensor(\"input\", &secretPlacement{}, []string{}),\n\t\t\t\toutput:  createOutputTensor(\"output\"),\n\t\t\t\taggFunc: createAggFunc(ast.AggFuncCount, true, aggregation.CompleteMode),\n\t\t\t},\n\t\t\tkernel: &KernelSecretDistinctCount{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 3, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameSort, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupMark, engineOps[1].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameReduceSum, engineOps[2].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelShapeCount(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic shape count\",\n\t\t\tnode: &OperatorReduce{\n\t\t\t\tinput:   createInputTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\toutput:  createOutputTensor(\"output\"),\n\t\t\t\taggFunc: createAggFunc(ast.AggFuncCount, false, aggregation.CompleteMode),\n\t\t\t},\n\t\t\tkernel: &KernelShapeCount{inputPlacement: &privatePlacement{partyCode: \"alice\"}, partyCode: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameShape, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelBroadcastTo(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic broadcast to private\",\n\t\t\tnode: &OperatorBroadcastTo{\n\t\t\t\tshapeRef: createInputTensor(\"shape_ref\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\tscalars:  []*TensorMeta{createInputTensor(\"scalar\", &publicPlacement{}, []string{\"alice\", \"bob\", \"carol\"})},\n\t\t\t\toutputs:  []*TensorMeta{createOutputTensor(\"output\")},\n\t\t\t},\n\t\t\tkernel: &KernelBroadcastTo{refPlacement: &privatePlacement{partyCode: \"alice\"}},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameBroadcastTo, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, engineOps[0].Outputs[\"Out\"][0].Status())\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"broadcast to public\",\n\t\t\tnode: &OperatorBroadcastTo{\n\t\t\t\tshapeRef: createInputTensor(\"shape_ref\", &publicPlacement{}, []string{\"alice\", \"bob\", \"carol\"}),\n\t\t\t\tscalars:  []*TensorMeta{createInputTensor(\"scalar\", &publicPlacement{}, []string{\"alice\", \"bob\", \"carol\"})},\n\t\t\t\toutputs:  []*TensorMeta{createOutputTensor(\"output\")},\n\t\t\t},\n\t\t\tkernel: &KernelBroadcastTo{refPlacement: &publicPlacement{}},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameBroadcastTo, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, engineOps[0].Outputs[\"Out\"][0].Status())\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelPrivateGroupAgg(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic private group by with SUM\",\n\t\t\tnode: &OperatorGroupAgg{\n\t\t\t\tgroupKeys:          []*TensorMeta{createInputTensor(\"group_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\taggArgs:            []*TensorMeta{createInputTensor(\"payload\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\targFuncOutputs:     []*TensorMeta{createOutputTensor(\"output\")},\n\t\t\t\tsimpleCountOutputs: []*TensorMeta{},\n\t\t\t\taggFuncsWithArg:    []*aggregation.AggFuncDesc{createAggFunc(ast.AggFuncSum, false, aggregation.CompleteMode)},\n\t\t\t},\n\t\t\tkernel: &KernelPrivateGroupAgg{partyCode: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 2, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameGroup, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameGroupSum, engineOps[1].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"private group by with COUNT DISTINCT\",\n\t\t\tnode: &OperatorGroupAgg{\n\t\t\t\tgroupKeys:          []*TensorMeta{createInputTensor(\"group_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\taggArgs:            []*TensorMeta{createInputTensor(\"payload\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\targFuncOutputs:     []*TensorMeta{createOutputTensor(\"output\")},\n\t\t\t\tsimpleCountOutputs: []*TensorMeta{},\n\t\t\t\taggFuncsWithArg:    []*aggregation.AggFuncDesc{createAggFunc(ast.AggFuncCount, true, aggregation.CompleteMode)},\n\t\t\t},\n\t\t\tkernel: &KernelPrivateGroupAgg{partyCode: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 2, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameGroup, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameGroupCountDistinct, engineOps[1].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"private group by with secret SUM\",\n\t\t\tnode: &OperatorGroupAgg{\n\t\t\t\tgroupKeys:          []*TensorMeta{createInputTensor(\"group_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\taggArgs:            []*TensorMeta{createInputTensor(\"payload\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})},\n\t\t\t\targFuncOutputs:     []*TensorMeta{createOutputTensor(\"output\")},\n\t\t\t\tsimpleCountOutputs: []*TensorMeta{},\n\t\t\t\taggFuncsWithArg:    []*aggregation.AggFuncDesc{createAggFunc(ast.AggFuncSum, false, aggregation.CompleteMode)},\n\t\t\t},\n\t\t\tkernel: &KernelPrivateGroupAgg{partyCode: \"alice\", PGSParties: map[int]string{8: \"bob\"}},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 6, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameGroup, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameGroupSecretSum, engineOps[4].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelObliviousGroupAgg(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic oblivious group by with multiple agg funcs\",\n\t\t\tnode: &OperatorGroupAgg{\n\t\t\t\tgroupKeys:          []*TensorMeta{createInputTensor(\"group_key\", &secretPlacement{}, []string{})},\n\t\t\t\taggArgs:            []*TensorMeta{createInputTensor(\"payload1\", &secretPlacement{}, []string{}), createInputTensor(\"payload2\", &secretPlacement{}, []string{}), createInputTensor(\"payload3\", &secretPlacement{}, []string{})},\n\t\t\t\targFuncOutputs:     []*TensorMeta{createOutputTensor(\"sum_out\"), createOutputTensor(\"avg_out\"), createOutputTensor(\"count_distinct_out\")},\n\t\t\t\tsimpleCountOutputs: []*TensorMeta{createOutputTensor(\"count_out\")},\n\t\t\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{\n\t\t\t\t\tcreateAggFunc(ast.AggFuncSum, false, aggregation.CompleteMode),\n\t\t\t\t\tcreateAggFunc(ast.AggFuncAvg, false, aggregation.CompleteMode),\n\t\t\t\t\tcreateAggFunc(ast.AggFuncCount, true, aggregation.CompleteMode),\n\t\t\t\t},\n\t\t\t},\n\t\t\tkernel: &KernelObliviousGroupAgg{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Len(t, engineOps, 12)\n\t\t\t\tassert.Equal(t, operator.OpNameSort, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupMark, engineOps[1].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupCount, engineOps[2].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupSum, engineOps[3].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupAvg, engineOps[4].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameSort, engineOps[5].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupMark, engineOps[6].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameLogicalOr, engineOps[7].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupSum, engineOps[8].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameShuffle, engineOps[9].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameMakePublic, engineOps[10].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameFilter, engineOps[11].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"oblivious group by with alice private sort\",\n\t\t\tnode: &OperatorGroupAgg{\n\t\t\t\tgroupKeys:          []*TensorMeta{createInputTensor(\"group_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\taggArgs:            []*TensorMeta{createInputTensor(\"payload1\", &secretPlacement{}, []string{}), createInputTensor(\"payload2\", &secretPlacement{}, []string{}), createInputTensor(\"payload3\", &secretPlacement{}, []string{})},\n\t\t\t\targFuncOutputs:     []*TensorMeta{createOutputTensor(\"sum_out\"), createOutputTensor(\"avg_out\"), createOutputTensor(\"count_distinct_out\")},\n\t\t\t\tsimpleCountOutputs: []*TensorMeta{createOutputTensor(\"count_out\")},\n\t\t\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{\n\t\t\t\t\tcreateAggFunc(ast.AggFuncSum, false, aggregation.CompleteMode),\n\t\t\t\t\tcreateAggFunc(ast.AggFuncAvg, false, aggregation.CompleteMode),\n\t\t\t\t\tcreateAggFunc(ast.AggFuncCount, true, aggregation.CompleteMode),\n\t\t\t\t},\n\t\t\t},\n\t\t\tkernel: &KernelObliviousGroupAgg{privateSortParty: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Len(t, engineOps, 16)\n\t\t\t\tassert.Equal(t, operator.OpNameMakeShare, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameShuffle, engineOps[1].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameMakePrivate, engineOps[2].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameMakeShare, engineOps[3].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameSort, engineOps[4].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupMark, engineOps[5].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupCount, engineOps[6].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupSum, engineOps[7].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupAvg, engineOps[8].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameSort, engineOps[9].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupMark, engineOps[10].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameLogicalOr, engineOps[11].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupSum, engineOps[12].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameShuffle, engineOps[13].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameMakePublic, engineOps[14].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameFilter, engineOps[15].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"oblivious group by with reveal group mark\",\n\t\t\tnode: &OperatorGroupAgg{\n\t\t\t\tgroupKeys:          []*TensorMeta{createInputTensor(\"group_key\", &secretPlacement{}, []string{})},\n\t\t\t\taggArgs:            []*TensorMeta{createInputTensor(\"payload1\", &secretPlacement{}, []string{}), createInputTensor(\"payload2\", &secretPlacement{}, []string{}), createInputTensor(\"payload3\", &secretPlacement{}, []string{})},\n\t\t\t\targFuncOutputs:     []*TensorMeta{createOutputTensor(\"sum_out\"), createOutputTensor(\"avg_out\"), createOutputTensor(\"count_distinct_out\")},\n\t\t\t\tsimpleCountOutputs: []*TensorMeta{createOutputTensor(\"count_out\")},\n\t\t\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{\n\t\t\t\t\tcreateAggFunc(ast.AggFuncSum, false, aggregation.CompleteMode),\n\t\t\t\t\tcreateAggFunc(ast.AggFuncAvg, false, aggregation.CompleteMode),\n\t\t\t\t\tcreateAggFunc(ast.AggFuncCount, true, aggregation.CompleteMode),\n\t\t\t\t},\n\t\t\t},\n\t\t\tkernel: &KernelObliviousGroupAgg{revealGroupMark: true},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Len(t, engineOps, 11)\n\t\t\t\tassert.Equal(t, operator.OpNameSort, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupMark, engineOps[1].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupCount, engineOps[2].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupSum, engineOps[3].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupAvg, engineOps[4].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameSort, engineOps[5].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupMark, engineOps[6].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameLogicalOr, engineOps[7].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupSum, engineOps[8].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameMakePublic, engineOps[9].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameFilter, engineOps[10].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelCrossJoin(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic cross join between alice and bob\",\n\t\t\tnode: &OperatorCrossJoin{\n\t\t\t\tleftInputs:   []*TensorMeta{createInputTensor(\"left_col1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\trightInputs:  []*TensorMeta{createInputTensor(\"right_col1\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"})},\n\t\t\t\tleftOutputs:  []*TensorMeta{createOutputTensor(\"left_out1\")},\n\t\t\t\trightOutputs: []*TensorMeta{createOutputTensor(\"right_out1\")},\n\t\t\t},\n\t\t\tkernel: &KernelCrossJoin{\n\t\t\t\tleftParty:    \"alice\",\n\t\t\t\trightParty:   \"bob\",\n\t\t\t\tleftInputs:   []*graph.Tensor{},\n\t\t\t\trightInputs:  []*graph.Tensor{},\n\t\t\t\tleftOutputs:  []*graph.Tensor{},\n\t\t\t\trightOutputs: []*graph.Tensor{},\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameReplicate, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelLimit(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic limit with private placement\",\n\t\t\tnode: &OperatorLimit{\n\t\t\t\tinputs:  []*TensorMeta{createInputTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\toutputs: []*TensorMeta{createOutputTensor(\"output\")},\n\t\t\t\toffset:  10,\n\t\t\t\tcount:   100,\n\t\t\t},\n\t\t\tkernel: &KernelLimit{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameLimit, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, int64(10), engineOps[0].Attributes[operator.LimitOffsetAttr].GetAttrValue())\n\t\t\t\tassert.Equal(t, int64(100), engineOps[0].Attributes[operator.LimitCountAttr].GetAttrValue())\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelFilter(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"filter with private placement and private mask\",\n\t\t\tnode: &OperatorFilter{\n\t\t\t\tmask:    createInputTensor(\"mask\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\tinputs:  []*TensorMeta{createInputTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"})},\n\t\t\t\toutputs: []*TensorMeta{createOutputTensor(\"output\")},\n\t\t\t},\n\t\t\tkernel: &KernelFilter{\n\t\t\t\tinputPlacements: []tensorPlacement{&privatePlacement{partyCode: \"alice\"}},\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameFilter, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"filter with secret placement and public mask\",\n\t\t\tnode: &OperatorFilter{\n\t\t\t\tmask:    createInputTensor(\"mask\", &publicPlacement{}, []string{\"alice\", \"bob\", \"carol\"}),\n\t\t\t\tinputs:  []*TensorMeta{createInputTensor(\"input\", &secretPlacement{}, []string{})},\n\t\t\t\toutputs: []*TensorMeta{createOutputTensor(\"output\")},\n\t\t\t},\n\t\t\tkernel: &KernelFilter{\n\t\t\t\tinputPlacements: []tensorPlacement{&secretPlacement{}},\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameFilter, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelSecretConcat(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic secret concat with multiple inputs\",\n\t\t\tnode: &OperatorConcat{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"input1\", &secretPlacement{}, []string{}),\n\t\t\t\t\tcreateInputTensor(\"input2\", &secretPlacement{}, []string{}),\n\t\t\t\t\tcreateInputTensor(\"input3\", &secretPlacement{}, []string{}),\n\t\t\t\t},\n\t\t\t\toutput: createOutputTensor(\"output\"),\n\t\t\t},\n\t\t\tkernel: &KernelSecretConcat{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameConcat, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelSecretSort(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic secret sort with keys and payloads\",\n\t\t\tnode: &OperatorSort{\n\t\t\t\tsortKeys: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"sort_key\", &secretPlacement{}, []string{}),\n\t\t\t\t},\n\t\t\t\tpayloads: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"payload1\", &secretPlacement{}, []string{}),\n\t\t\t\t\tcreateInputTensor(\"payload2\", &secretPlacement{}, []string{}),\n\t\t\t\t},\n\t\t\t\toutputs: []*TensorMeta{\n\t\t\t\t\tcreateOutputTensor(\"sorted_key\"),\n\t\t\t\t\tcreateOutputTensor(\"sorted_payload1\"),\n\t\t\t\t\tcreateOutputTensor(\"sorted_payload2\"),\n\t\t\t\t},\n\t\t\t\tdescending: []bool{false},\n\t\t\t},\n\t\t\tkernel: &KernelSecretSort{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameSort, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelPrivateSort(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic private sort with alice party\",\n\t\t\tnode: &OperatorSort{\n\t\t\t\tsortKeys: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"sort_key\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\tpayloads: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"payload1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutputs: []*TensorMeta{\n\t\t\t\t\tcreateOutputTensor(\"sorted_key\"),\n\t\t\t\t\tcreateOutputTensor(\"sorted_payload1\"),\n\t\t\t\t},\n\t\t\t\tdescending: []bool{false},\n\t\t\t},\n\t\t\tkernel: &KernelPrivateSort{partyCode: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameSort, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelConstant(t *testing.T) {\n\tbuilder, _, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic integer constant\",\n\t\t\tnode: &OperatorConstant{\n\t\t\t\toutput: createOutputTensor(\"const_output\"),\n\t\t\t\tvalue: func() *types.Datum {\n\t\t\t\t\td := types.NewDatum(42)\n\t\t\t\t\treturn &d\n\t\t\t\t}(),\n\t\t\t},\n\t\t\tkernel: &KernelConstant{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameConstant, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelLocalIn(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic local in with alice party\",\n\t\t\tnode: &OperatorIn{\n\t\t\t\tleft:   createInputTensor(\"left_col\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\tright:  createInputTensor(\"right_col\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\toutput: createOutputTensor(\"in_result\"),\n\t\t\t},\n\t\t\tkernel: &KernelLocalIn{partyCode: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameIn, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelPsiIn(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic psi in between alice and bob\",\n\t\t\tnode: &OperatorIn{\n\t\t\t\tleft:   createInputTensor(\"left_col\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\tright:  createInputTensor(\"right_col\", &privatePlacement{partyCode: \"bob\"}, []string{\"bob\"}),\n\t\t\t\toutput: createOutputTensor(\"in_result\"),\n\t\t\t},\n\t\t\tkernel: &KernelPsiIn{\n\t\t\t\tleftParty:  \"alice\",\n\t\t\t\trightParty: \"bob\",\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameIn, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelPrivateWindow(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic private window row_number with alice party\",\n\t\t\tnode: &OperatorWindow{\n\t\t\t\tpartitionKeys: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"partition_col\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\torderKeys: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"order_col\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\tpayloads: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"payload1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\tpayloadOutputs: []*TensorMeta{\n\t\t\t\t\tcreateOutputTensor(\"payload_out1\"),\n\t\t\t\t},\n\t\t\t\tfuncOutput: createOutputTensor(\"row_number_result\"),\n\t\t\t\tfuncName:   ast.WindowFuncRowNumber,\n\t\t\t\tdescs:      []string{\"false\"},\n\t\t\t},\n\t\t\tkernel: &KernelPrivateWindow{partyCode: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 2, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameGroup, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameRowNumber, engineOps[1].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelObliviousWindow(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic oblivious window row_number with secret placement\",\n\t\t\tnode: &OperatorWindow{\n\t\t\t\tpartitionKeys: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"partition_col\", &secretPlacement{}, []string{}),\n\t\t\t\t},\n\t\t\t\torderKeys: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"order_col\", &secretPlacement{}, []string{}),\n\t\t\t\t},\n\t\t\t\tpayloads: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"payload1\", &secretPlacement{}, []string{}),\n\t\t\t\t},\n\t\t\t\tpayloadOutputs: []*TensorMeta{\n\t\t\t\t\tcreateOutputTensor(\"payload_out1\"),\n\t\t\t\t},\n\t\t\t\tfuncOutput: createOutputTensor(\"row_number_result\"),\n\t\t\t\tfuncName:   ast.WindowFuncRowNumber,\n\t\t\t\tdescs:      []string{\"false\"},\n\t\t\t},\n\t\t\tkernel: &KernelObliviousWindow{},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 3, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameSort, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupMark, engineOps[1].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameObliviousGroupCount, engineOps[2].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelArrowFunction(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic arrow function substr with alice party\",\n\t\t\tnode: &OperatorFunction{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutput: createOutputTensor(\"output\"),\n\t\t\t\tconstParams: []*expression.Constant{\n\t\t\t\t\t{Value: types.NewDatum(int64(2))}, {Value: types.NewDatum(int64(5))},\n\t\t\t\t},\n\t\t\t\tfuncName: ast.Substr,\n\t\t\t},\n\t\t\tkernel: &KernelArrowFunction{partyCode: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameArrowFunc, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelUnary(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic unary abs with secret placement\",\n\t\t\tnode: &OperatorFunction{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"input\", &secretPlacement{}, []string{}),\n\t\t\t\t},\n\t\t\t\toutput:   createOutputTensor(\"output\"),\n\t\t\t\tfuncName: ast.Abs,\n\t\t\t},\n\t\t\tkernel: &KernelUnary{place: &secretPlacement{}},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameAbs, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelBinary(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic binary add with secret placement\",\n\t\t\tnode: &OperatorFunction{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"lhs\", &secretPlacement{}, []string{}),\n\t\t\t\t\tcreateInputTensor(\"rhs\", &secretPlacement{}, []string{}),\n\t\t\t\t},\n\t\t\t\toutput:   createOutputTensor(\"output\"),\n\t\t\t\tfuncName: ast.Plus,\n\t\t\t},\n\t\t\tkernel: &KernelBinary{\n\t\t\t\tlhsPlace: &secretPlacement{},\n\t\t\t\trhsPlace: &secretPlacement{},\n\t\t\t\toutPlace: &secretPlacement{},\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameAdd, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelVariadicCompare(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic variadic compare greatest with secret placement\",\n\t\t\tnode: &OperatorFunction{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"input1\", &secretPlacement{}, []string{}),\n\t\t\t\t\tcreateInputTensor(\"input2\", &secretPlacement{}, []string{}),\n\t\t\t\t\tcreateInputTensor(\"input3\", &secretPlacement{}, []string{}),\n\t\t\t\t},\n\t\t\t\toutput:   createOutputTensor(\"output\"),\n\t\t\t\tfuncName: ast.Greatest,\n\t\t\t},\n\t\t\tkernel: &KernelVariadicCompare{placement: &secretPlacement{}},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameGreatest, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelPrivateFunc(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic private func ifnull with alice party\",\n\t\t\tnode: &OperatorFunction{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"input1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"input2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutput:   createOutputTensor(\"output\"),\n\t\t\t\tfuncName: ast.Ifnull,\n\t\t\t},\n\t\t\tkernel: &KernelPrivateFunc{partyCode: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameIfNull, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelCast(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\t// Helper function to create output tensor with specific dtype\n\tcreateOutputTensorWithType := func(name string, dtype *graph.DataType) *TensorMeta {\n\t\ttensor := createOutputTensor(name)\n\t\ttensor.DType = dtype\n\t\treturn tensor\n\t}\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic cast with private placement\",\n\t\t\tnode: &OperatorFunction{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"input\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutput:   createOutputTensorWithType(\"output\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT32)),\n\t\t\t\tfuncName: ast.Cast,\n\t\t\t},\n\t\t\tkernel: &KernelCast{placement: &privatePlacement{partyCode: \"alice\"}},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameCast, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelIf(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic if with alice party\",\n\t\t\tnode: &OperatorFunction{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"cond\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"true_value\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"false_value\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutput:   createOutputTensor(\"output\"),\n\t\t\t\tfuncName: ast.If,\n\t\t\t},\n\t\t\tkernel: &KernelIf{\n\t\t\t\tcondPlace:       &privatePlacement{partyCode: \"alice\"},\n\t\t\t\ttrueValuePlace:  &privatePlacement{partyCode: \"alice\"},\n\t\t\t\tfalseValuePlace: &privatePlacement{partyCode: \"alice\"},\n\t\t\t\toutputPlace:     &privatePlacement{partyCode: \"alice\"},\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameIf, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"if with secret placement\",\n\t\t\tnode: &OperatorFunction{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"cond\", &secretPlacement{}, []string{}),\n\t\t\t\t\tcreateInputTensor(\"true_value\", &secretPlacement{}, []string{}),\n\t\t\t\t\tcreateInputTensor(\"false_value\", &secretPlacement{}, []string{}),\n\t\t\t\t},\n\t\t\t\toutput:   createOutputTensor(\"output\"),\n\t\t\t\tfuncName: ast.If,\n\t\t\t},\n\t\t\tkernel: &KernelIf{\n\t\t\t\tcondPlace:       &secretPlacement{},\n\t\t\t\ttrueValuePlace:  &secretPlacement{},\n\t\t\t\tfalseValuePlace: &secretPlacement{},\n\t\t\t\toutputPlace:     &secretPlacement{},\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameIf, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelCase(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic case with alice party\",\n\t\t\tnode: &OperatorFunction{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"cond1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"value1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"cond2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"value2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"else_value\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutput:   createOutputTensor(\"output\"),\n\t\t\t\tfuncName: ast.Case,\n\t\t\t},\n\t\t\tkernel: &KernelCase{\n\t\t\t\tinputPlacements: []tensorPlacement{\n\t\t\t\t\t&privatePlacement{partyCode: \"alice\"},\n\t\t\t\t\t&privatePlacement{partyCode: \"alice\"},\n\t\t\t\t\t&privatePlacement{partyCode: \"alice\"},\n\t\t\t\t\t&privatePlacement{partyCode: \"alice\"},\n\t\t\t\t\t&privatePlacement{partyCode: \"alice\"},\n\t\t\t\t},\n\t\t\t\toutputPlacement: &privatePlacement{partyCode: \"alice\"},\n\t\t\t},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 1, len(engineOps))\n\t\t\t\tassert.Equal(t, operator.OpNameCaseWhen, engineOps[0].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n\nfunc TestKernelConcatString(t *testing.T) {\n\tbuilder, createInputTensor, createOutputTensor := createTestSuit()\n\n\ttests := []kernelTestCase{\n\t\t{\n\t\t\tname: \"basic concat string with alice party\",\n\t\t\tnode: &OperatorFunction{\n\t\t\t\tinputs: []*TensorMeta{\n\t\t\t\t\tcreateInputTensor(\"str1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"str2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t\tcreateInputTensor(\"str3\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\"}),\n\t\t\t\t},\n\t\t\t\toutput:   createOutputTensor(\"output\"),\n\t\t\t\tfuncName: ast.Concat,\n\t\t\t},\n\t\t\tkernel: &KernelConcatString{partyCode: \"alice\"},\n\t\t\texecNodeChecker: func(engineOps []*graph.ExecutionNode) {\n\t\t\t\tassert.Equal(t, 3, len(engineOps)) // constant + broadcast + arrow func\n\t\t\t\tassert.Equal(t, operator.OpNameConstant, engineOps[0].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameBroadcastTo, engineOps[1].OpType)\n\t\t\t\tassert.Equal(t, operator.OpNameArrowFunc, engineOps[2].OpType)\n\t\t\t},\n\t\t},\n\t}\n\n\trunKernelTests(t, builder, tests)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/logical_plan_pass.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n)\n\n// LogicalPlanPass converts AST to logical plan\ntype LogicalPlanPass struct{}\n\n// NewLogicalPlanPass creates a new logical plan pass\nfunc NewLogicalPlanPass() *LogicalPlanPass {\n\treturn &LogicalPlanPass{}\n}\n\n// Name returns the pass name\nfunc (p *LogicalPlanPass) Name() string {\n\treturn \"LogicalPlanPass\"\n}\n\n// Run builds logical plan from AST\nfunc (p *LogicalPlanPass) Run(c *CompileContext) error {\n\t// 1. Create and configure session context\n\tsctx := sessionctx.NewContext()\n\tsctx.GetSessionVars().StmtCtx = &stmtctx.StatementContext{}\n\tsctx.GetSessionVars().PlanID = 0\n\tsctx.GetSessionVars().PlanColumnID = 0\n\tsctx.GetSessionVars().CurrentDB = c.Request.GetDb()\n\n\t// Set groupby threshold\n\tvar groupbyThreshold uint64\n\tif c.Request.SecurityConfig.ResultSecurityConf == nil {\n\t\tgroupbyThreshold = 4\n\t} else {\n\t\tif c.Request.SecurityConfig.ResultSecurityConf.GroupbyThreshold <= 0 {\n\t\t\treturn fmt.Errorf(\"groupby threshold must be greater than 0\")\n\t\t}\n\t\tgroupbyThreshold = uint64(c.Request.SecurityConfig.ResultSecurityConf.GroupbyThreshold)\n\t}\n\tsctx.GetSessionVars().GroupByThreshold = groupbyThreshold\n\tc.SessionCtx = sctx\n\n\t// 2. Get statement from AST\n\tif c.AST == nil {\n\t\treturn fmt.Errorf(\"no AST found in context\")\n\t}\n\tstmt := c.AST\n\n\t// 3. Build logical plan\n\tlp, _, err := core.BuildLogicalPlanWithOptimization(c.Ctx, sctx, stmt, c.InfoSchema)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build logical plan: %v\", err)\n\t}\n\n\t// Store logical plan in context\n\tc.LogicalPlan = lp\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/operator.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// Operator represents a computational node in the SCQL operator graph.\n// It defines the interface for all operators that perform data transformations.\ntype Operator interface {\n\tID() int\n\tSetID(id int)\n\tSetKernel(k Kernel)\n\tKernel() Kernel\n\n\tString() string\n\n\t// Label returns a human-readable name for this operator type.\n\t// Used for debugging and visualization purposes.\n\tLabel() string\n\n\t// Inputs returns a map of input tensors grouped by logical names.\n\t// Each key represents a logical input group (e.g., \"left\", \"right\" for joins),\n\t// and the value is a slice of tensor metadata for that group.\n\tInputs() map[string][]*TensorMeta\n\n\t// Outputs returns a map of output tensors grouped by logical names.\n\t// Similar to Inputs(), but represents the results produced by this operator.\n\tOutputs() map[string][]*TensorMeta\n\n\t// Attrs returns operator-specific attributes and configuration parameters.\n\t// These attributes control the behavior of the operator during execution.\n\tAttrs() map[string]any\n\n\t// Infer the visibility of the output tensors based on the visibility of the input tensors\n\t// Handle the basic operator-specific visibility inference part in Infer\n\tInferVis(vr VisibilityRegistry) error\n\t// Infer the CSR of the output tensors based on the CSR of the input tensors\n\t// Handle CSR updating part in Infer\n\tInferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error\n\t// Infer the visibility of the output tensors based on the visibility of the input tensors\n\t// Security relaxation will be considered if applySecurityRelaxation is true\n\t// In addition, the CSC will also be updated during the inference\n\tInfer(v *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error)\n\t// Infer the visibility of the input tensors based on the visibility of the output tensors\n\tReverseInfer(v *VisibilitySolver) ([]*TensorMeta, error)\n}\n\n// GetNodeInputs returns all input tensors flattened from node's Inputs\nfunc GetNodeInputs(node Operator) []*TensorMeta {\n\tvar inputs []*TensorMeta\n\tfor _, tensors := range node.Inputs() {\n\t\tinputs = append(inputs, tensors...)\n\t}\n\treturn inputs\n}\n\n// GetNodeOutputs returns all output tensors flattened from node's Outputs\nfunc GetNodeOutputs(node Operator) []*TensorMeta {\n\tvar outputs []*TensorMeta\n\tfor _, tensors := range node.Outputs() {\n\t\toutputs = append(outputs, tensors...)\n\t}\n\treturn outputs\n}\n\ntype baseOperator struct {\n\tid     int\n\tlabel  string // human-friendly node label\n\tkernel Kernel\n}\n\nfunc (n *baseOperator) ID() int {\n\treturn n.id\n}\n\nfunc (n *baseOperator) SetID(id int) {\n\tn.id = id\n}\n\nfunc (n *baseOperator) SetKernel(k Kernel) {\n\tn.kernel = k\n}\n\nfunc (n *baseOperator) Kernel() Kernel {\n\treturn n.kernel\n}\n\nfunc (n *baseOperator) Label() string {\n\treturn n.label\n}\n\n// toSerializable converts complex types to simple, JSON-serializable formats.\nfunc toSerializable(v any) any {\n\tswitch t := v.(type) {\n\tcase *TensorMeta:\n\t\tif t == nil {\n\t\t\treturn nil\n\t\t}\n\t\treturn t.ID\n\tcase []*TensorMeta:\n\t\tresult := make([]int, len(t))\n\t\tfor i, tensor := range t {\n\t\t\tresult[i] = tensor.ID\n\t\t}\n\t\treturn result\n\tcase *aggregation.AggFuncDesc:\n\t\tif t == nil {\n\t\t\treturn nil\n\t\t}\n\t\treturn formatAggFuncDesc(t)\n\tcase []*aggregation.AggFuncDesc:\n\t\treturn stringifyAggFuncDescs(t)\n\tcase *types.Datum:\n\t\tif t == nil {\n\t\t\treturn nil\n\t\t}\n\t\treturn formatDatum(t)\n\tdefault:\n\t\treturn v\n\t}\n}\n\n// formatNodeString provides a consistent string representation for all Operator types\nfunc formatNodeString(nodeType string, node Operator) string {\n\tinputs := node.Inputs()\n\toutputs := node.Outputs()\n\tattrs := node.Attrs()\n\n\tvar sb strings.Builder\n\tsb.WriteString(fmt.Sprintf(\"{\\n%s:\\n\", nodeType))\n\n\t// Inputs\n\tsb.WriteString(\"  Inputs:\\n\")\n\tif len(inputs) == 0 {\n\t\tsb.WriteString(\"    no input tensors\\n\")\n\t} else {\n\t\tfor key, tensors := range inputs {\n\t\t\tsb.WriteString(fmt.Sprintf(\"    %s: %v\\n\", key, tensors))\n\t\t}\n\t}\n\n\t// Outputs\n\tsb.WriteString(\"  Outputs:\\n\")\n\tif len(outputs) == 0 {\n\t\tsb.WriteString(\"    no output tensors\\n\")\n\t} else {\n\t\tfor key, tensors := range outputs {\n\t\t\tsb.WriteString(fmt.Sprintf(\"    %s: %v\\n\", key, tensors))\n\t\t}\n\t}\n\n\t// Attrs\n\tsb.WriteString(\"  Attrs:\\n\")\n\tif len(attrs) == 0 {\n\t\tsb.WriteString(\"    no attrs\\n\")\n\t} else {\n\t\tfor key, val := range attrs {\n\t\t\tsb.WriteString(fmt.Sprintf(\"    %s: %v\\n\", key, val))\n\t\t}\n\t}\n\n\tsb.WriteString(\"}\")\n\treturn sb.String()\n}\n\nfunc makeNodeJSON(id int, label string, inputTensors map[string]any, outputTensors map[string]any, otherAttrs map[string]any) ([]byte, error) {\n\t// Process tensor attributes\n\tfor k, v := range inputTensors {\n\t\tinputTensors[k] = toSerializable(v)\n\t}\n\tfor k, v := range outputTensors {\n\t\toutputTensors[k] = toSerializable(v)\n\t}\n\tfor k, v := range otherAttrs {\n\t\totherAttrs[k] = toSerializable(v)\n\t}\n\n\tnodeData := struct {\n\t\tID            int            `json:\"id\"`\n\t\tLabel         string         `json:\"label\"`\n\t\tInputTensors  map[string]any `json:\"inputTensors\"`\n\t\tOutputTensors map[string]any `json:\"outputTensors\"`\n\t\tAttrs         map[string]any `json:\"attrs,omitempty\"`\n\t}{\n\t\tID:            id,\n\t\tLabel:         label,\n\t\tInputTensors:  inputTensors,\n\t\tOutputTensors: outputTensors,\n\t\tAttrs:         otherAttrs,\n\t}\n\n\treturn json.Marshal(nodeData)\n}\n\ntype OperatorResult struct {\n\tbaseOperator\n\n\tresultTensors []*TensorMeta\n\n\toutputNames     []string\n\tissuerPartyCode string\n\tintoOpt         *core.IntoOpt\n\tinsertTableOpt  *core.InsertTableOption\n\tresultTable     map[int64]*TensorMeta\n}\n\nfunc (n *OperatorResult) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"resultTensors\": n.resultTensors,\n\t}\n}\n\nfunc (n *OperatorResult) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{} // Result node has no outputs\n}\n\nfunc (n *OperatorResult) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"outputNames\": n.outputNames,\n\t\t\"issuerParty\": n.issuerPartyCode,\n\t\t\"intoOpt\":     n.intoOpt,\n\t\t\"insertOpt\":   n.insertTableOpt,\n\t\t\"resultTable\": n.resultTable,\n\t}\n}\n\nfunc (n *OperatorResult) Label() string {\n\treturn \"Result\"\n}\n\nfunc (n *OperatorResult) String() string {\n\treturn formatNodeString(\"OperatorResult\", n)\n}\n\n// JSON serialization for OperatorResult\nfunc (n *OperatorResult) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"resultTensors\": n.resultTensors,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"outputNames\": n.outputNames,\n\t}\n\treturn makeNodeJSON(n.id, \"Result\", inputTensors, map[string]any{}, otherAttrs)\n}\n\ntype OperatorDataSource struct {\n\tbaseOperator\n\n\toutputs []*TensorMeta\n\n\tsourceParty string\n\toriginNames []string\n}\n\nfunc (n *OperatorDataSource) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{} // DataSource node has no inputs\n}\n\nfunc (n *OperatorDataSource) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"outputs\": n.outputs,\n\t}\n}\n\nfunc (n *OperatorDataSource) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"sourceParty\": n.sourceParty,\n\t\t\"originNames\": n.originNames,\n\t}\n}\n\nfunc (n *OperatorDataSource) Label() string {\n\treturn \"DataSource\"\n}\n\nfunc (n *OperatorDataSource) String() string {\n\treturn formatNodeString(\"OperatorDataSource\", n)\n}\n\n// JSON serialization for OperatorDataSource\nfunc (n *OperatorDataSource) MarshalJSON() ([]byte, error) {\n\toutputTensors := map[string]any{\n\t\t\"outputs\": n.outputs,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"sourceParty\": n.sourceParty,\n\t\t\"originNames\": n.originNames,\n\t}\n\treturn makeNodeJSON(n.id, \"DataSource\", map[string]any{}, outputTensors, otherAttrs)\n}\n\ntype OperatorRunSQL struct {\n\tbaseOperator\n\n\toutputs []*TensorMeta\n\n\tsql             string\n\tsourceParty     string\n\ttableRefs       []string\n\tsubGraphNodes   []Operator\n\tsubGraphTracker *TensorConsumerTracker\n}\n\nfunc (n *OperatorRunSQL) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{} // RunSQL node has no inputs\n}\n\nfunc (n *OperatorRunSQL) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"outputs\": n.outputs,\n\t}\n}\n\nfunc (n *OperatorRunSQL) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"sql\":           n.sql,\n\t\t\"sourceParty\":   n.sourceParty,\n\t\t\"tableRefs\":     n.tableRefs,\n\t\t\"subGraphNodes\": n.subGraphNodes,\n\t\t// Ignore subGraphTracker to avoid too much details\n\t}\n}\n\nfunc (n *OperatorRunSQL) Label() string {\n\treturn \"RunSQL\"\n}\n\nfunc (n *OperatorRunSQL) String() string {\n\treturn formatNodeString(\"OperatorRunSQL\", n)\n}\n\n// JSON serialization for OperatorRunSQL\nfunc (n *OperatorRunSQL) MarshalJSON() ([]byte, error) {\n\toutputTensors := map[string]any{\n\t\t\"outputs\": n.outputs,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"sql\":         n.sql,\n\t\t\"sourceParty\": n.sourceParty,\n\t\t\"tableRefs\":   n.tableRefs,\n\t}\n\treturn makeNodeJSON(n.id, \"RunSQL\", map[string]any{}, outputTensors, otherAttrs)\n}\n\ntype OperatorEQJoin struct {\n\tbaseOperator\n\n\tleftKeys      []*TensorMeta\n\trightKeys     []*TensorMeta\n\tleftPayloads  []*TensorMeta\n\trightPayloads []*TensorMeta\n\tleftOutputs   []*TensorMeta\n\trightOutputs  []*TensorMeta\n\n\tjoinType core.JoinType\n}\n\nfunc (n *OperatorEQJoin) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"leftKeys\":      n.leftKeys,\n\t\t\"rightKeys\":     n.rightKeys,\n\t\t\"leftPayloads\":  n.leftPayloads,\n\t\t\"rightPayloads\": n.rightPayloads,\n\t}\n}\n\nfunc (n *OperatorEQJoin) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"leftOutputs\":  n.leftOutputs,\n\t\t\"rightOutputs\": n.rightOutputs,\n\t}\n}\n\nfunc (n *OperatorEQJoin) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"joinType\": n.joinType.String(),\n\t}\n}\n\nfunc (n *OperatorEQJoin) Label() string {\n\treturn \"EQJoin\"\n}\n\nfunc (n *OperatorEQJoin) String() string {\n\treturn formatNodeString(\"OperatorEQJoin\", n)\n}\n\n// JSON serialization for OperatorEQJoin\nfunc (n *OperatorEQJoin) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"leftKeys\":      n.leftKeys,\n\t\t\"rightKeys\":     n.rightKeys,\n\t\t\"leftPayloads\":  n.leftPayloads,\n\t\t\"rightPayloads\": n.rightPayloads,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"leftOutputs\":  n.leftOutputs,\n\t\t\"rightOutputs\": n.rightOutputs,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"joinType\": n.joinType.String(),\n\t}\n\treturn makeNodeJSON(n.id, \"EQJoin\", inputTensors, outputTensors, otherAttrs)\n}\n\ntype OperatorCrossJoin struct {\n\tbaseOperator\n\n\tleftInputs   []*TensorMeta\n\trightInputs  []*TensorMeta\n\tleftOutputs  []*TensorMeta\n\trightOutputs []*TensorMeta\n}\n\nfunc (n *OperatorCrossJoin) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"leftInputs\":  n.leftInputs,\n\t\t\"rightInputs\": n.rightInputs,\n\t}\n}\n\nfunc (n *OperatorCrossJoin) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"leftOutputs\":  n.leftOutputs,\n\t\t\"rightOutputs\": n.rightOutputs,\n\t}\n}\n\nfunc (n *OperatorCrossJoin) Attrs() map[string]any {\n\treturn nil // No additional attributes\n}\n\nfunc (n *OperatorCrossJoin) Label() string {\n\treturn \"CrossJoin\"\n}\n\nfunc (n *OperatorCrossJoin) String() string {\n\treturn formatNodeString(\"OperatorCrossJoin\", n)\n}\n\n// JSON serialization for OperatorCrossJoin\nfunc (n *OperatorCrossJoin) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"leftInputs\":  n.leftInputs,\n\t\t\"rightInputs\": n.rightInputs,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"leftOutputs\":  n.leftOutputs,\n\t\t\"rightOutputs\": n.rightOutputs,\n\t}\n\treturn makeNodeJSON(n.id, \"CrossJoin\", inputTensors, outputTensors, map[string]any{})\n}\n\ntype OperatorLimit struct {\n\tbaseOperator\n\n\tinputs  []*TensorMeta\n\toutputs []*TensorMeta\n\n\toffset uint64\n\tcount  uint64\n}\n\nfunc (n *OperatorLimit) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"inputs\": n.inputs,\n\t}\n}\n\nfunc (n *OperatorLimit) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"outputs\": n.outputs,\n\t}\n}\n\nfunc (n *OperatorLimit) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"offset\": n.offset,\n\t\t\"count\":  n.count,\n\t}\n}\n\nfunc (n *OperatorLimit) Label() string {\n\treturn \"Limit\"\n}\n\nfunc (n *OperatorLimit) String() string {\n\treturn formatNodeString(\"OperatorLimit\", n)\n}\n\n// JSON serialization for OperatorLimit\nfunc (n *OperatorLimit) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"inputs\": n.inputs,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"outputs\": n.outputs,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"offset\": n.offset,\n\t\t\"count\":  n.count,\n\t}\n\treturn makeNodeJSON(n.id, \"Limit\", inputTensors, outputTensors, otherAttrs)\n}\n\ntype OperatorFilter struct {\n\tbaseOperator\n\n\tmask    *TensorMeta\n\tinputs  []*TensorMeta\n\toutputs []*TensorMeta\n}\n\nfunc (n *OperatorFilter) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"mask\":   {n.mask},\n\t\t\"inputs\": n.inputs,\n\t}\n}\n\nfunc (n *OperatorFilter) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"outputs\": n.outputs,\n\t}\n}\n\nfunc (n *OperatorFilter) Attrs() map[string]any {\n\treturn nil // No additional attributes\n}\n\nfunc (n *OperatorFilter) Label() string {\n\treturn \"Filter\"\n}\n\nfunc (n *OperatorFilter) String() string {\n\treturn formatNodeString(\"OperatorFilter\", n)\n}\n\n// JSON serialization for OperatorFilter\nfunc (n *OperatorFilter) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"mask\":   n.mask,\n\t\t\"inputs\": n.inputs,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"outputs\": n.outputs,\n\t}\n\treturn makeNodeJSON(n.id, \"Filter\", inputTensors, outputTensors, map[string]any{})\n}\n\ntype OperatorBroadcastTo struct {\n\tbaseOperator\n\n\tshapeRef *TensorMeta\n\tscalars  []*TensorMeta\n\toutputs  []*TensorMeta\n}\n\nfunc (n *OperatorBroadcastTo) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"shapeRef\": {n.shapeRef},\n\t\t\"scalars\":  n.scalars,\n\t}\n}\n\nfunc (n *OperatorBroadcastTo) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"outputs\": n.outputs,\n\t}\n}\n\nfunc (n *OperatorBroadcastTo) Attrs() map[string]any {\n\treturn nil // No additional attributes\n}\n\nfunc (n *OperatorBroadcastTo) Label() string {\n\treturn \"BroadcastTo\"\n}\n\nfunc (n *OperatorBroadcastTo) String() string {\n\treturn formatNodeString(\"OperatorBroadcastTo\", n)\n}\n\n// JSON serialization for OperatorBroadcastTo\nfunc (n *OperatorBroadcastTo) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"shapeRef\": n.shapeRef,\n\t\t\"scalars\":  n.scalars,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"outputs\": n.outputs,\n\t}\n\treturn makeNodeJSON(n.id, \"BroadcastTo\", inputTensors, outputTensors, map[string]any{})\n}\n\ntype OperatorConcat struct {\n\tbaseOperator\n\n\tinputs []*TensorMeta\n\toutput *TensorMeta\n}\n\nfunc (n *OperatorConcat) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"inputs\": n.inputs,\n\t}\n}\n\nfunc (n *OperatorConcat) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"output\": {n.output},\n\t}\n}\n\nfunc (n *OperatorConcat) Attrs() map[string]any {\n\treturn nil // No additional attributes\n}\n\nfunc (n *OperatorConcat) Label() string {\n\treturn \"Concat\"\n}\n\nfunc (n *OperatorConcat) String() string {\n\treturn formatNodeString(\"OperatorConcat\", n)\n}\n\n// JSON serialization for OperatorConcat\nfunc (n *OperatorConcat) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"inputs\": n.inputs,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"output\": n.output,\n\t}\n\treturn makeNodeJSON(n.id, \"Concat\", inputTensors, outputTensors, map[string]any{})\n}\n\ntype OperatorSort struct {\n\tbaseOperator\n\n\tsortKeys   []*TensorMeta\n\tpayloads   []*TensorMeta\n\toutputs    []*TensorMeta\n\tdescending []bool\n}\n\nfunc (n *OperatorSort) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"sortKeys\": n.sortKeys,\n\t\t\"payloads\": n.payloads,\n\t}\n}\n\nfunc (n *OperatorSort) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"outputs\": n.outputs,\n\t}\n}\n\nfunc (n *OperatorSort) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"descending\": n.descending,\n\t}\n}\n\nfunc (n *OperatorSort) Label() string {\n\treturn \"Sort\"\n}\n\nfunc (n *OperatorSort) String() string {\n\treturn formatNodeString(\"OperatorSort\", n)\n}\n\n// JSON serialization for OperatorSort\nfunc (n *OperatorSort) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"sortKeys\": n.sortKeys,\n\t\t\"payloads\": n.payloads,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"outputs\": n.outputs,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"descending\": n.descending,\n\t}\n\treturn makeNodeJSON(n.id, \"Sort\", inputTensors, outputTensors, otherAttrs)\n}\n\ntype OperatorReduce struct {\n\tbaseOperator\n\n\tinput   *TensorMeta\n\toutput  *TensorMeta\n\taggFunc *aggregation.AggFuncDesc\n}\n\nfunc (n *OperatorReduce) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"input\": {n.input},\n\t}\n}\n\nfunc (n *OperatorReduce) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"output\": {n.output},\n\t}\n}\n\nfunc (n *OperatorReduce) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"aggFunc\": n.aggFunc,\n\t}\n}\n\nfunc (n *OperatorReduce) Label() string {\n\treturn \"Reduce\"\n}\n\nfunc (n *OperatorReduce) String() string {\n\treturn formatNodeString(\"OperatorReduce\", n)\n}\n\n// JSON serialization for OperatorReduce\nfunc (n *OperatorReduce) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"input\": n.input,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"output\": n.output,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"aggFunc\": n.aggFunc,\n\t}\n\treturn makeNodeJSON(n.id, \"Reduce\", inputTensors, outputTensors, otherAttrs)\n}\n\ntype OperatorGroupAgg struct {\n\tbaseOperator\n\n\tgroupKeys          []*TensorMeta\n\taggArgs            []*TensorMeta\n\targFuncOutputs     []*TensorMeta\n\tsimpleCountOutputs []*TensorMeta\n\n\taggFuncsWithArg []*aggregation.AggFuncDesc\n\n\tkeysVisAfterAgg *OverlayVisibilityTable\n}\n\nfunc (n *OperatorGroupAgg) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"groupKeys\": n.groupKeys,\n\t\t\"payloads\":  n.aggArgs,\n\t}\n}\n\nfunc (n *OperatorGroupAgg) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"argFuncOutputs\":     n.argFuncOutputs,\n\t\t\"simpleCountOutputs\": n.simpleCountOutputs,\n\t}\n}\n\nfunc (n *OperatorGroupAgg) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"aggFuncsWithArg\": n.aggFuncsWithArg,\n\t}\n}\n\nfunc (n *OperatorGroupAgg) Label() string {\n\treturn \"GroupAgg\"\n}\n\nfunc (n *OperatorGroupAgg) String() string {\n\treturn formatNodeString(\"OperatorGroupAgg\", n)\n}\n\n// JSON serialization for OperatorGroupAgg\nfunc (n *OperatorGroupAgg) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"groupKeys\": n.groupKeys,\n\t\t\"aggArgs\":   n.aggArgs,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"argFuncOutputs\":     n.argFuncOutputs,\n\t\t\"simpleCountOutputs\": n.simpleCountOutputs,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"aggFuncsWithArg\": n.aggFuncsWithArg,\n\t}\n\treturn makeNodeJSON(n.id, \"GroupAgg\", inputTensors, outputTensors, otherAttrs)\n}\n\ntype OperatorWindow struct {\n\tbaseOperator\n\n\tpartitionKeys []*TensorMeta\n\torderKeys     []*TensorMeta\n\tpayloads      []*TensorMeta\n\n\t// In the current implementation, payloads are sorted in the secret window rank, while the private window rank outputs the raw payloads.\n\t// We treat payloads and outputs as different tensors in OperatorGraph, although they maybe the same tensors in the ExecutionGraph.\n\tpayloadOutputs []*TensorMeta\n\t// Output tensor for window function\n\t// Currently, we only support one window function in a window node.\n\tfuncOutput *TensorMeta\n\n\t// Window function name\n\tfuncName string\n\t// order by desc attrs, currently effective only in private rank window.\n\tdescs []string\n}\n\nfunc (n *OperatorWindow) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"partitionKeys\": n.partitionKeys,\n\t\t\"orderKeys\":     n.orderKeys,\n\t\t\"payloads\":      n.payloads,\n\t}\n}\n\nfunc (n *OperatorWindow) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"payloadOutputs\": n.payloadOutputs,\n\t\t\"funcOutput\":     {n.funcOutput},\n\t}\n}\n\nfunc (n *OperatorWindow) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"descs\":    n.descs,\n\t\t\"funcName\": n.funcName,\n\t}\n}\n\nfunc (n *OperatorWindow) Label() string {\n\treturn \"Window\"\n}\n\nfunc (n *OperatorWindow) String() string {\n\treturn formatNodeString(\"OperatorWindow\", n)\n}\n\n// JSON serialization for OperatorRankWindow\nfunc (n *OperatorWindow) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"partitionKeys\": n.partitionKeys,\n\t\t\"orderKeys\":     n.orderKeys,\n\t\t\"payloads\":      n.payloads,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"payloadOutputs\": n.payloadOutputs,\n\t\t\"funcOutput\":     n.funcOutput,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"descs\": n.descs,\n\t}\n\treturn makeNodeJSON(n.id, \"Window\", inputTensors, outputTensors, otherAttrs)\n}\n\ntype OperatorIn struct {\n\tbaseOperator\n\n\tleft   *TensorMeta\n\tright  *TensorMeta\n\toutput *TensorMeta\n}\n\nfunc (n *OperatorIn) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"left\":  {n.left},\n\t\t\"right\": {n.right},\n\t}\n}\n\nfunc (n *OperatorIn) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"output\": {n.output},\n\t}\n}\n\nfunc (n *OperatorIn) Attrs() map[string]any {\n\treturn nil // No additional attributes\n}\n\nfunc (n *OperatorIn) Label() string {\n\treturn \"In\"\n}\n\nfunc (n *OperatorIn) String() string {\n\treturn formatNodeString(\"OperatorIn\", n)\n}\n\n// JSON serialization for OperatorIn\nfunc (n *OperatorIn) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"left\":  n.left,\n\t\t\"right\": n.right,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"output\": n.output,\n\t}\n\treturn makeNodeJSON(n.id, \"In\", inputTensors, outputTensors, map[string]any{})\n}\n\ntype OperatorConstant struct {\n\tbaseOperator\n\n\toutput *TensorMeta\n\n\tvalue *types.Datum\n}\n\nfunc (n *OperatorConstant) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{} // No inputs\n}\n\nfunc (n *OperatorConstant) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"output\": {n.output},\n\t}\n}\n\nfunc (n *OperatorConstant) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"value\": n.value,\n\t}\n}\n\nfunc (n *OperatorConstant) Label() string {\n\treturn \"Constant\"\n}\n\nfunc (n *OperatorConstant) String() string {\n\treturn formatNodeString(\"OperatorConstant\", n)\n}\n\n// JSON serialization for OperatorConstant\nfunc (n *OperatorConstant) MarshalJSON() ([]byte, error) {\n\toutputTensors := map[string]any{\n\t\t\"output\": n.output,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"value\": n.value,\n\t}\n\treturn makeNodeJSON(n.id, \"Constant\", map[string]any{}, outputTensors, otherAttrs)\n}\n\ntype OperatorFunction struct {\n\tbaseOperator\n\n\tinputs []*TensorMeta\n\toutput *TensorMeta\n\n\tconstParams []*expression.Constant\n\tfuncName    string\n}\n\nfunc (n *OperatorFunction) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"inputs\": n.inputs,\n\t}\n}\n\nfunc (n *OperatorFunction) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\n\t\t\"output\": {n.output},\n\t}\n}\n\nfunc (n *OperatorFunction) Attrs() map[string]any {\n\treturn map[string]any{\n\t\t\"constParams\": n.constParams,\n\t\t\"funcName\":    n.funcName,\n\t}\n}\n\nfunc (n *OperatorFunction) Label() string {\n\treturn \"Func \" + n.funcName\n}\n\nfunc (n *OperatorFunction) String() string {\n\treturn formatNodeString(\"OperatorFunction\", n)\n}\n\n// JSON serialization for OperatorFunction\nfunc (n *OperatorFunction) MarshalJSON() ([]byte, error) {\n\tinputTensors := map[string]any{\n\t\t\"inputs\": n.inputs,\n\t}\n\toutputTensors := map[string]any{\n\t\t\"output\": n.output,\n\t}\n\totherAttrs := map[string]any{\n\t\t\"constParams\": n.constParams,\n\t\t\"funcName\":    n.funcName,\n\t}\n\tlabel := \"Func \" + strings.ToUpper(n.funcName)\n\treturn makeNodeJSON(n.id, label, inputTensors, outputTensors, otherAttrs)\n}\n\n// Helper function to format AggFuncDesc with name and suffixes\nfunc formatAggFuncDesc(aggFunc *aggregation.AggFuncDesc) string {\n\tname := aggFunc.Name\n\tif aggFunc.HasDistinct {\n\t\tname += \"_dist\"\n\t}\n\tif aggFunc.Mode == aggregation.FinalMode {\n\t\tname += \"_final\"\n\t}\n\treturn name\n}\n\n// Helper function to convert AggFuncDesc slice to their string representations\nfunc stringifyAggFuncDescs(aggFuncs []*aggregation.AggFuncDesc) []string {\n\tresult := make([]string, len(aggFuncs))\n\tfor i, aggFunc := range aggFuncs {\n\t\tresult[i] = formatAggFuncDesc(aggFunc)\n\t}\n\treturn result\n}\n\n// Helper function to format Datum with type and value information\nfunc formatDatum(datum *types.Datum) string {\n\tif datum.IsNull() {\n\t\treturn \"NULL\"\n\t}\n\n\t// Use the existing String() method which already formats as \"Type Value\"\n\treturn datum.String()\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/operator_graph.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype OperatorGraph struct {\n\toperators       []Operator\n\ttensors         []*TensorMeta\n\tproducerTracker *TensorProducerTracker\n\tconsumerTracker *TensorConsumerTracker\n}\n\n// Nodes returns all execution nodes.\nfunc (og *OperatorGraph) Nodes() []Operator {\n\treturn og.operators\n}\n\n// Tensors returns the global tensor catalogue.\nfunc (og *OperatorGraph) Tensors() []*TensorMeta {\n\treturn og.tensors\n}\n\nfunc (og *OperatorGraph) String() string {\n\tvar sb strings.Builder\n\tfmt.Fprintln(&sb, \"Operators: \")\n\tfor _, node := range og.operators {\n\t\tfmt.Fprintf(&sb, \"%s\\n\", node)\n\t\t// fmt.Fprintf(&sb, \"Kernel: %s\\n\", node.Kernel())\n\t}\n\tfmt.Fprintln(&sb, \"Tensors: \")\n\tfor _, tensor := range og.tensors {\n\t\tfmt.Fprintf(&sb, \"Tensor[%d]: %s, Type: %v\\n\", tensor.ID, tensor.Name, tensor.DType)\n\t}\n\treturn sb.String()\n}\n\n// DetailedString returns a detailed string representation of the OperatorGraph including visibility information\nfunc (og *OperatorGraph) DetailedString(visibilityRegistry VisibilityRegistry) string {\n\tvar sb strings.Builder\n\t// Operators section\n\tfmt.Fprintln(&sb, \"Operators: \")\n\tfor _, node := range og.operators {\n\t\tfmt.Fprintf(&sb, \"%s\\n\", node)\n\t}\n\n\t// Tensors with visibility section\n\tfmt.Fprintln(&sb, \"Tensors: \")\n\tfor _, tensor := range og.tensors {\n\t\tfmt.Fprintf(&sb, \"Tensor[%d]: %s, Type: %v\", tensor.ID, tensor.Name, tensor.DType)\n\t\tif tensor.IsConstScalar {\n\t\t\tfmt.Fprintf(&sb, \", ConstScalar: true\")\n\t\t}\n\n\t\tif visibilityRegistry != nil {\n\t\t\tvisibleParties := visibilityRegistry.TensorVisibleParties(tensor)\n\t\t\tif visibleParties != nil && !visibleParties.IsEmpty() {\n\t\t\t\tfmt.Fprintf(&sb, \", VisibleParties: [%s]\", visibleParties.String())\n\t\t\t} else {\n\t\t\t\tfmt.Fprintf(&sb, \", VisibleParties: []\")\n\t\t\t}\n\t\t}\n\t\tfmt.Fprintln(&sb)\n\t}\n\treturn sb.String()\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/operator_graph_builder.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/status\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n\t\"github.com/secretflow/scql/pkg/util/stringutil\"\n)\n\ntype SourcePartiesTracker struct {\n\tlpSourceParties map[core.LogicalPlan][]string\n\tenginesInfo     *graph.EnginesInfo\n}\n\nfunc NewSourcePartiesTracker(enginesInfo *graph.EnginesInfo) *SourcePartiesTracker {\n\treturn &SourcePartiesTracker{\n\t\tlpSourceParties: make(map[core.LogicalPlan][]string),\n\t\tenginesInfo:     enginesInfo,\n\t}\n}\n\nfunc (spt *SourcePartiesTracker) GetSourceParties(lp core.LogicalPlan) ([]string, error) {\n\tif parties, ok := spt.lpSourceParties[lp]; ok {\n\t\treturn parties, nil\n\t}\n\n\tif ds, ok := lp.(*core.DataSource); ok {\n\t\tdt, err := core.NewDbTableFromString(ds.DBName.O + \".\" + ds.TableInfo().Name.O)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsourceParty := spt.enginesInfo.GetPartyByTable(dt)\n\t\tif sourceParty == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"fail to get party by table: %s\", dt.String())\n\t\t}\n\t\tparties := []string{sourceParty}\n\t\tspt.lpSourceParties[lp] = parties\n\t\treturn parties, nil\n\t}\n\n\tif len(lp.Children()) == 0 {\n\t\treturn nil, fmt.Errorf(\"logical plan which is not Datasouce has no children\")\n\t}\n\tparties := []string{}\n\tfor _, child := range lp.Children() {\n\t\tchildParties, err := spt.GetSourceParties(child)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tparties = append(parties, childParties...)\n\t}\n\tparties = sliceutil.SliceDeDup(parties)\n\tspt.lpSourceParties[lp] = parties\n\treturn parties, nil\n}\n\ntype OperatorGraphBuilder struct {\n\toperators            []Operator\n\tsourcePartiesTracker *SourcePartiesTracker\n\tenginesInfo          *graph.EnginesInfo\n\ttensorMetaManager    *TensorMetaManager\n\tissuerPartyCode      string\n\tcreatedAt            time.Time\n\tcheckFuncs           bool\n\tproducerTracker      *TensorProducerTracker\n\tconsumerTracker      *TensorConsumerTracker\n}\n\nfunc NewOperatorGraphBuilder(tensorMetaManager *TensorMetaManager, enginesInfo *graph.EnginesInfo, issuerPartyCode string, createdAt time.Time) *OperatorGraphBuilder {\n\treturn &OperatorGraphBuilder{\n\t\toperators:            []Operator{},\n\t\tsourcePartiesTracker: NewSourcePartiesTracker(enginesInfo),\n\t\tenginesInfo:          enginesInfo,\n\t\ttensorMetaManager:    tensorMetaManager,\n\t\tissuerPartyCode:      issuerPartyCode,\n\t\tcreatedAt:            createdAt,\n\t\tcheckFuncs:           true,\n\t\tproducerTracker:      &TensorProducerTracker{},\n\t\tconsumerTracker:      &TensorConsumerTracker{},\n\t}\n}\n\nfunc (builder *OperatorGraphBuilder) GetInvolvedParties(lp core.LogicalPlan) ([]string, error) {\n\tinvolvedParties, err := builder.sourcePartiesTracker.GetSourceParties(lp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tinvolvedParties = append(involvedParties, builder.issuerPartyCode)\n\tinvolvedParties = sliceutil.SliceDeDup(involvedParties)\n\treturn involvedParties, nil\n}\n\nfunc (builder *OperatorGraphBuilder) Build(lp core.LogicalPlan) (*OperatorGraph, error) {\n\tif err := builder.buildInternal(lp, false); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := builder.buildResult(lp); err != nil {\n\t\treturn nil, err\n\t}\n\toperatorGraph := &OperatorGraph{\n\t\toperators:       builder.operators,\n\t\ttensors:         builder.tensorMetaManager.Tensors(),\n\t\tproducerTracker: builder.producerTracker,\n\t\tconsumerTracker: builder.consumerTracker,\n\t}\n\treturn operatorGraph, nil\n}\n\nfunc (builder *OperatorGraphBuilder) addOperator(operator Operator) {\n\tbuilder.operators = append(builder.operators, operator)\n\t// id start from 1\n\toperator.SetID(len(builder.operators))\n\n\t// set source node for all output tensors\n\tfor _, output := range GetNodeOutputs(operator) {\n\t\tbuilder.producerTracker.SetProducer(output, operator)\n\t}\n\n\t// set user node for all input tensors\n\tfor _, input := range GetNodeInputs(operator) {\n\t\tbuilder.consumerTracker.AddConsumer(input, operator)\n\t}\n}\n\nfunc (builder *OperatorGraphBuilder) buildInternal(lp core.LogicalPlan, alreadyInSingleParty bool) error {\n\tif !alreadyInSingleParty {\n\t\tsourceParties, err := builder.sourcePartiesTracker.GetSourceParties(lp)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(sourceParties) == 1 {\n\t\t\treturn builder.buildSinglePartySQL(lp, sourceParties[0])\n\t\t}\n\t}\n\n\tfor _, childLP := range lp.Children() {\n\t\tif err := builder.buildInternal(childLP, alreadyInSingleParty); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tswitch x := lp.(type) {\n\tcase *core.DataSource:\n\t\tsourceParties, err := builder.sourcePartiesTracker.GetSourceParties(lp)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn builder.buildDataSource(x, sourceParties[0])\n\tcase *core.LogicalAggregation:\n\t\treturn builder.buildLogicalAggregation(x)\n\tcase *core.LogicalApply:\n\t\treturn builder.buildLogicalJoin(&x.LogicalJoin)\n\tcase *core.LogicalJoin:\n\t\treturn builder.buildLogicalJoin(x)\n\tcase *core.LogicalLimit:\n\t\treturn builder.buildLogicalLimit(x)\n\tcase *core.LogicalProjection:\n\t\treturn builder.buildLogicalProjection(x)\n\tcase *core.LogicalSelection:\n\t\treturn builder.buildLogicalSelection(x)\n\tcase *core.LogicalSort:\n\t\treturn builder.buildLogicalSort(x)\n\tcase *core.LogicalUnionAll:\n\t\treturn builder.buildLogicalUnionAll(x)\n\tcase *core.LogicalWindow:\n\t\treturn builder.buildLogicalWindow(x)\n\tcase *core.LogicalMaxOneRow:\n\t\treturn builder.buildMaxOneRow(x)\n\tdefault:\n\t\treturn fmt.Errorf(\"build OperatorGraph: unsupported logical plan type: %T\", lp)\n\t}\n}\n\n// ============================================================================\n// Handle Logical Plan Nodes\n// ============================================================================\n\nfunc (builder *OperatorGraphBuilder) buildDataSource(lp core.LogicalPlan, sourceParty string) error {\n\tresultTable := ResultTable{}\n\n\ttensors := make([]*TensorMeta, 0, len(lp.Schema().Columns))\n\toriginNames := make([]string, 0, len(lp.Schema().Columns))\n\tfor _, column := range lp.Schema().Columns {\n\t\ttp, err := graph.ConvertDataType(column.RetType)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildDataSource: %v\", err)\n\t\t}\n\t\tname := column.String()\n\t\ttensor := builder.tensorMetaManager.CreateTensorMeta(name, tp)\n\t\tresultTable[column.UniqueID] = tensor\n\t\ttensors = append(tensors, tensor)\n\t\toriginNames = append(originNames, column.OrigName)\n\t}\n\n\tif err := builder.tensorMetaManager.setLPResultTable(lp, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildDataSource: %v\", err)\n\t}\n\n\toperator := &OperatorDataSource{\n\t\toutputs:     tensors,\n\t\tsourceParty: sourceParty,\n\t\toriginNames: originNames,\n\t}\n\tbuilder.addOperator(operator)\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildSemiJoin(join *core.LogicalJoin) error {\n\tif len(join.Children()) != 2 {\n\t\treturn fmt.Errorf(\"buildSemiJoin: unsupported children number: %d\", len(join.Children()))\n\t}\n\n\tif len(join.OtherConditions)+len(join.EqualConditions) != 1 || len(join.LeftConditions) != 0 || len(join.RightConditions) != 0 {\n\t\treturn fmt.Errorf(\"buildSemiJoin: doesn't support condition other:%s, equal:%s,  right condition (%s), left condition (%s)\",\n\t\t\tjoin.OtherConditions, join.EqualConditions, join.RightConditions, join.LeftConditions)\n\t}\n\n\tleftResultTable, err := builder.tensorMetaManager.getLPResultTable(join.Children()[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildSemiJoin: %v\", err)\n\t}\n\trightResultTable, err := builder.tensorMetaManager.getLPResultTable(join.Children()[1])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildSemiJoin: %v\", err)\n\t}\n\tchildrenReusltTable := sliceutil.MergeMaps(leftResultTable, rightResultTable)\n\n\tvar sFunc *expression.ScalarFunction\n\tif len(join.OtherConditions) > 0 {\n\t\tvar ok bool\n\t\tsFunc, ok = join.OtherConditions[0].(*expression.ScalarFunction)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"buildSemiJoin: type assertion failed\")\n\t\t}\n\t}\n\tif len(join.EqualConditions) > 0 {\n\t\tsFunc = join.EqualConditions[0]\n\t}\n\tif sFunc.FuncName.L != ast.EQ || len(sFunc.GetArgs()) != 2 {\n\t\treturn fmt.Errorf(\"buildSemiJoin: invalid condition func: %v\", sFunc)\n\t}\n\n\tleftKey, err := builder.getTensorFromExpression(sFunc.GetArgs()[0], childrenReusltTable, true)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildSemiJoin: %v\", err)\n\t}\n\trightKey, err := builder.getTensorFromExpression(sFunc.GetArgs()[1], childrenReusltTable, true)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildSemiJoin: %v\", err)\n\t}\n\n\tinResult, err := builder.addInOp(leftKey, rightKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildSemiJoin: %v\", err)\n\t}\n\n\tselectIn := func(reversed bool) error {\n\t\tvar filter *TensorMeta\n\t\tif reversed {\n\t\t\tfilter, err = builder.addFunctionNode(ast.UnaryNot, []*TensorMeta{inResult}, []*expression.Constant{})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"buildSemiJoin: %v\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tfilter = inResult\n\t\t}\n\n\t\tresultTable := ResultTable{}\n\t\tfor _, col := range join.Schema().Columns {\n\t\t\tresultTable[col.UniqueID] = childrenReusltTable[col.UniqueID]\n\t\t}\n\t\tresultTable[join.Schema().Columns[len(join.Schema().Columns)-1].UniqueID] = filter\n\n\t\tif err := builder.tensorMetaManager.setLPResultTable(join, resultTable, builder.checkFuncs); err != nil {\n\t\t\treturn fmt.Errorf(\"buildSemiJoin: %v\", err)\n\t\t}\n\t\treturn nil\n\t}\n\n\twhereIn := func(reversed bool) error {\n\t\tvar filter *TensorMeta\n\t\tif reversed {\n\t\t\tfilter, err = builder.addFunctionNode(ast.UnaryNot, []*TensorMeta{inResult}, []*expression.Constant{})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"buildSemiJoin: %v\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tfilter = inResult\n\t\t}\n\t\tinputs := make([]*TensorMeta, 0, len(join.Schema().Columns))\n\t\tfor _, col := range join.Schema().Columns {\n\t\t\tinput := childrenReusltTable[col.UniqueID]\n\t\t\tinputs = append(inputs, input)\n\t\t}\n\t\toutputs := builder.addFilterOp(filter, inputs)\n\t\tresultTable := ResultTable{}\n\t\tfor idx, col := range join.Schema().Columns {\n\t\t\tresultTable[col.UniqueID] = outputs[idx]\n\t\t}\n\n\t\tif err := builder.tensorMetaManager.setLPResultTable(join, resultTable, builder.checkFuncs); err != nil {\n\t\t\treturn fmt.Errorf(\"buildSemiJoin: %v\", err)\n\t\t}\n\t\treturn nil\n\t}\n\n\tswitch join.JoinType {\n\tcase core.AntiLeftOuterSemiJoin: // SELECT ta.id NOT IN (select tb.id from tb) as f from ta\n\t\treturn selectIn(true)\n\tcase core.LeftOuterSemiJoin: // SELECT ta.id IN (select tb.id from tb) as f from ta\n\t\treturn selectIn(false)\n\tcase core.AntiSemiJoin: // select ta.id, ta.x1 from ta WHERE ta.id NOT IN (select tb.id from tb)\n\t\treturn whereIn(true)\n\tcase core.SemiJoin: // select ta.id, ta.x1 from ta WHERE ta.id IN (select tb.id from tb)\n\t\treturn whereIn(false)\n\tdefault:\n\t\treturn fmt.Errorf(\"buildSemiJoin: invalid join type %s\", join.JoinType)\n\t}\n}\n\nfunc (builder *OperatorGraphBuilder) buildLogicalJoin(join *core.LogicalJoin) error {\n\tif len(join.Children()) != 2 {\n\t\treturn fmt.Errorf(\"buildLogicalJoin: unexpected children number: %d\", len(join.Children()))\n\t}\n\n\tswitch join.JoinType {\n\tcase core.SemiJoin, core.AntiSemiJoin, core.AntiLeftOuterSemiJoin, core.LeftOuterSemiJoin:\n\t\treturn builder.buildSemiJoin(join)\n\t}\n\tif !slices.Contains(SupportedJoinType, join.JoinType) {\n\t\treturn status.Wrap(proto.Code_NOT_SUPPORTED, fmt.Errorf(\"buildLogicalJoin: unsupported join type: %s\", join.JoinType))\n\t}\n\tif len(join.OtherConditions) != 0 || len(join.LeftConditions) != 0 || len(join.RightConditions) != 0 {\n\t\treturn status.Wrap(proto.Code_NOT_SUPPORTED, fmt.Errorf(\"buildLogicalJoin doesn't support other condition (%+v), right condition (%+v), left condition (%+v)\", join.OtherConditions, join.RightConditions, join.LeftConditions))\n\t}\n\n\tif len(join.EqualConditions) > 0 {\n\t\treturn builder.buildEQJoin(join)\n\t}\n\treturn builder.buildCrossJoin(join)\n}\n\nfunc (builder *OperatorGraphBuilder) buildLogicalAggregation(agg *core.LogicalAggregation) error {\n\tif len(agg.Children()) != 1 {\n\t\treturn fmt.Errorf(\"buildLogicalAggregation: unexpected children number: %d\", len(agg.Children()))\n\t}\n\tif len(agg.GroupByItems) > 0 {\n\t\treturn builder.buildGroupAggregation(agg)\n\t}\n\t// No grouping - use reduce aggregation\n\treturn builder.buildReduceAggregation(agg)\n}\n\nfunc (builder *OperatorGraphBuilder) buildLogicalLimit(limit *core.LogicalLimit) error {\n\tif len(limit.Children()) != 1 {\n\t\treturn fmt.Errorf(\"buildLogicalLimit: unexpected children number: %d\", len(limit.Children()))\n\t}\n\n\tresultTable := ResultTable{}\n\n\tchildResultTable, err := builder.tensorMetaManager.getLPResultTable(limit.Children()[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalLimit: %v\", err)\n\t}\n\tvar inputs = make([]*TensorMeta, 0, len(childResultTable))\n\tvar outputs = make([]*TensorMeta, 0, len(childResultTable))\n\tfor colId, input := range sliceutil.SortedMap(childResultTable) {\n\t\toutput := builder.tensorMetaManager.CreateTensorMetaAs(input)\n\t\tinputs = append(inputs, input)\n\t\toutputs = append(outputs, output)\n\t\tresultTable[colId] = output\n\t}\n\n\tif err := builder.tensorMetaManager.setLPResultTable(limit, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalLimit: %v\", err)\n\t}\n\n\toperator := &OperatorLimit{\n\t\tinputs:  inputs,\n\t\toutputs: outputs,\n\t\toffset:  limit.Offset,\n\t\tcount:   limit.Count,\n\t}\n\tbuilder.addOperator(operator)\n\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildLogicalProjection(projection *core.LogicalProjection) error {\n\tresultTable := ResultTable{}\n\n\tif len(projection.Children()) != 1 {\n\t\treturn fmt.Errorf(\"buildLogicalProjection: unexpected children number: %d\", len(projection.Children()))\n\t}\n\tchild := projection.Children()[0]\n\tchildResultTable, err := builder.tensorMetaManager.getLPResultTable(child)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalProjection: %v\", err)\n\t}\n\n\ttensors := []*TensorMeta{}\n\tfor _, expr := range projection.Exprs {\n\t\ttensor, err := builder.getTensorFromExpression(expr, childResultTable, false)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildLogicalProjection: %v\", err)\n\t\t}\n\t\ttensors = append(tensors, tensor)\n\t}\n\n\toutputTs, err := builder.addBroadcastToOndemand(tensors)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalProjection: %v\", err)\n\t}\n\n\tfor idx := range projection.Exprs {\n\t\tcolId := projection.Schema().Columns[idx].UniqueID\n\t\tresultTable[colId] = outputTs[idx]\n\t}\n\n\tif err := builder.tensorMetaManager.setLPResultTable(projection, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalProjection: %v\", err)\n\t}\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildLogicalSelection(selection *core.LogicalSelection) error {\n\tif len(selection.Children()) != 1 {\n\t\treturn fmt.Errorf(\"buildLogicalSelection: unexpected children number: %d\", len(selection.Children()))\n\t}\n\n\tchildResultTable, err := builder.tensorMetaManager.getLPResultTable(selection.Children()[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalSelection: %v\", err)\n\t}\n\n\t// If there are no filter conditions, then the Selection acts as a no-op\n\tif len(selection.Conditions) == 0 {\n\t\tif err := builder.tensorMetaManager.setLPResultTable(selection, childResultTable, builder.checkFuncs); err != nil {\n\t\t\treturn fmt.Errorf(\"buildLogicalSelection: %v\", err)\n\t\t}\n\t\treturn nil\n\t}\n\n\tresultTable := ResultTable{}\n\n\tfilters := []*TensorMeta{}\n\tfor _, cond := range selection.Conditions {\n\t\tfilter, err := builder.getTensorFromExpression(cond, childResultTable, false)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildLogicalSelection: %v\", err)\n\t\t}\n\t\tfilters = append(filters, filter)\n\t}\n\n\tfinalFilter := filters[0]\n\tfor i := 1; i < len(filters); i++ {\n\t\tfinalFilter, err = builder.addFunctionNode(ast.LogicAnd, []*TensorMeta{finalFilter, filters[i]}, []*expression.Constant{})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildLogicalSelection: %v\", err)\n\t\t}\n\t}\n\n\tinputs := []*TensorMeta{}\n\tfor _, col := range selection.Schema().Columns {\n\t\tinput, err := childResultTable.getColumnTensorMeta(col)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildLogicalSelection: %v\", err)\n\t\t}\n\t\tinputs = append(inputs, input)\n\t}\n\toutputs := builder.addFilterOp(finalFilter, inputs)\n\tfor idx, col := range selection.Schema().Columns {\n\t\tresultTable[col.UniqueID] = outputs[idx]\n\t}\n\n\tif err := builder.tensorMetaManager.setLPResultTable(selection, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalSelection: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildLogicalSort(sort *core.LogicalSort) error {\n\tif len(sort.Children()) != 1 {\n\t\treturn fmt.Errorf(\"buildLogicalSort: unexpected children number: %d\", len(sort.Children()))\n\t}\n\tif len(sort.ByItems) == 0 {\n\t\treturn fmt.Errorf(\"buildLogicalSort: unexpected byItems number: %d\", len(sort.ByItems))\n\t}\n\n\tresultTable := ResultTable{}\n\tchildResultTable, err := builder.tensorMetaManager.getLPResultTable(sort.Children()[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalSort: %v\", err)\n\t}\n\n\tsortKeys := make([]*TensorMeta, 0, len(sort.ByItems))\n\tvar desc []bool\n\tfor _, col := range sort.ByItems {\n\t\tdesc = append(desc, col.Desc)\n\n\t\ttensor, err := builder.getTensorFromExpression(col.Expr, childResultTable, false)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildLogicalSort: %v\", err)\n\t\t}\n\t\tsortKeys = append(sortKeys, tensor)\n\t}\n\n\tpayloads, outputs, err := builder.processPayloads(resultTable, sort.Children()[0], sort.Schema().Columns)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalSort: %v\", err)\n\t}\n\n\tif err := builder.tensorMetaManager.setLPResultTable(sort, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalSort: %v\", err)\n\t}\n\n\toperator := &OperatorSort{\n\t\tsortKeys:   sortKeys,\n\t\tpayloads:   payloads,\n\t\toutputs:    outputs,\n\t\tdescending: desc,\n\t}\n\tbuilder.addOperator(operator)\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildLogicalUnionAll(union *core.LogicalUnionAll) error {\n\tresultTable := ResultTable{}\n\tfor idx, col := range union.Schema().Columns {\n\t\ttensors := make([]*TensorMeta, 0, len(union.Children()))\n\t\tfor _, child := range union.Children() {\n\t\t\tchildResults, err := builder.tensorMetaManager.getLPSchemaTensors(child)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"buildLogicalUnionAll: %v\", err)\n\t\t\t}\n\t\t\ttensors = append(tensors, childResults[idx])\n\t\t}\n\t\tout, err := builder.addConcatOp(tensors)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildLogicalUnionAll: %v\", err)\n\t\t}\n\t\tresultTable[col.UniqueID] = out\n\t}\n\n\tif err := builder.tensorMetaManager.setLPResultTable(union, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalUnionAll: %v\", err)\n\t}\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildLogicalWindow(window *core.LogicalWindow) error {\n\tif len(window.Children()) != 1 {\n\t\treturn fmt.Errorf(\"buildLogicalWindow: unsupported children number: %d\", len(window.Children()))\n\t}\n\tif len(window.WindowFuncDescs) != 1 {\n\t\treturn fmt.Errorf(\"buildLogicalWindow: unsupported window function number: %d\", len(window.WindowFuncDescs))\n\t}\n\n\tchildResultTable, err := builder.tensorMetaManager.getLPResultTable(window.Children()[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalWindow: %v\", err)\n\t}\n\tresultTable := ResultTable{}\n\n\tpartitionKeys := make([]*TensorMeta, 0, len(window.PartitionBy))\n\tfor _, item := range window.PartitionBy {\n\t\tpartitionKey, err := childResultTable.getColumnTensorMeta(item.Col)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildLogicalWindow: %v\", err)\n\t\t}\n\t\tpartitionKeys = append(partitionKeys, partitionKey)\n\t}\n\n\torderKeys := make([]*TensorMeta, 0, len(window.OrderBy))\n\torderDescs := make([]string, 0, len(window.OrderBy))\n\tfor _, item := range window.OrderBy {\n\t\torderKey, err := childResultTable.getColumnTensorMeta(item.Col)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildLogicalWindow: %v\", err)\n\t\t}\n\t\torderKeys = append(orderKeys, orderKey)\n\n\t\tdesc := \"0\"\n\t\tif item.Desc {\n\t\t\tdesc = \"1\"\n\t\t}\n\t\torderDescs = append(orderDescs, desc)\n\t}\n\n\tpayloads, payloadOutputs, err := builder.processPayloads(resultTable, window.Children()[0], window.Schema().Columns[:len(window.Schema().Columns)-1])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalWindow: %v\", err)\n\t}\n\n\tdesc := window.WindowFuncDescs[0]\n\tvar outputType *graph.DataType\n\tswitch desc.Name {\n\tcase ast.WindowFuncRowNumber:\n\t\toutputType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64)\n\tcase ast.WindowFuncPercentRank:\n\t\toutputType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64)\n\tcase ast.WindowFuncRank:\n\t\toutputType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64)\n\tdefault:\n\t\treturn fmt.Errorf(\"buildLogicalWindow: unsupported window function: %s\", desc.Name)\n\t}\n\toutputName := desc.Name\n\n\tfuncOutput := builder.tensorMetaManager.CreateTensorMeta(outputName, outputType)\n\tresultTable[window.Schema().Columns[len(window.Schema().Columns)-1].UniqueID] = funcOutput\n\n\tif err := builder.tensorMetaManager.setLPResultTable(window, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalWindow: %v\", err)\n\t}\n\n\toperator := &OperatorWindow{\n\t\tpartitionKeys:  partitionKeys,\n\t\torderKeys:      orderKeys,\n\t\tpayloads:       payloads,\n\t\tpayloadOutputs: payloadOutputs,\n\t\tfuncOutput:     funcOutput,\n\t\tdescs:          orderDescs,\n\t\tfuncName:       desc.Name,\n\t}\n\tbuilder.addOperator(operator)\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildResult(lp core.LogicalPlan) error {\n\tresultTs, err := builder.tensorMetaManager.getLPSchemaTensors(lp)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar outputNames []string\n\tfor idx, column := range lp.Schema().Columns {\n\t\toutputName := lp.OutputNames()[idx].ColName.String()\n\t\tif outputName == \"\" {\n\t\t\toutputName = column.String()\n\t\t}\n\t\toutputNames = append(outputNames, outputName)\n\t}\n\n\tif lp.IntoOpt() != nil && len(lp.IntoOpt().Opt.PartyFiles) == 1 && lp.IntoOpt().Opt.PartyFiles[0].PartyCode == \"\" {\n\t\tlp.IntoOpt().Opt.PartyFiles[0].PartyCode = builder.issuerPartyCode\n\t}\n\n\toperator := &OperatorResult{\n\t\tresultTensors:   resultTs,\n\t\toutputNames:     outputNames,\n\t\tissuerPartyCode: builder.issuerPartyCode,\n\t\tintoOpt:         lp.IntoOpt(),\n\t\tinsertTableOpt:  lp.InsertTableOpt(),\n\t}\n\tif operator.intoOpt != nil {\n\t\toperator.resultTable, err = builder.tensorMetaManager.getLPResultTable(lp)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildResult: %v\", err)\n\t\t}\n\t}\n\tbuilder.addOperator(operator)\n\treturn nil\n}\n\n// ============================================================================\n// Handle tensor alignment\n// ============================================================================\n\nfunc (builder *OperatorGraphBuilder) addBroadcastToOndemand(inputTs []*TensorMeta) ([]*TensorMeta, error) {\n\tif len(inputTs) == 1 {\n\t\treturn inputTs, nil\n\t}\n\toutputTs := make([]*TensorMeta, len(inputTs))\n\n\tvar shapeT *TensorMeta\n\tvar constScalars []*TensorMeta\n\tfor _, input := range inputTs {\n\t\tif input.IsConstScalar {\n\t\t\tconstScalars = append(constScalars, input)\n\t\t\tcontinue\n\t\t}\n\t\tshapeT = input\n\t}\n\tif len(constScalars) == 0 {\n\t\treturn inputTs, nil\n\t}\n\tif shapeT == nil {\n\t\treturn nil, fmt.Errorf(\"addBroadcastToOndemand: no shape tensor found\")\n\t}\n\n\tboradcastedTs, err := builder.addBroadCastToOp(constScalars, shapeT)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"addBroadcastToOndemand: %v\", err)\n\t}\n\n\tbroadcastedIdx := 0\n\tfor outputIdx, input := range inputTs {\n\t\tif input.IsConstScalar {\n\t\t\toutputTs[outputIdx] = boradcastedTs[broadcastedIdx]\n\t\t\tbroadcastedIdx++\n\t\t} else {\n\t\t\toutputTs[outputIdx] = input\n\t\t}\n\t}\n\treturn outputTs, nil\n}\n\nfunc (builder *OperatorGraphBuilder) addBroadCastToOp(constScalars []*TensorMeta, shapeT *TensorMeta) ([]*TensorMeta, error) {\n\touts := make([]*TensorMeta, 0, len(constScalars))\n\tfor _, scalarIn := range constScalars {\n\t\tout := builder.tensorMetaManager.CreateTensorMetaAs(scalarIn)\n\t\tout.IsConstScalar = false\n\t\touts = append(outs, out)\n\t}\n\n\toperator := &OperatorBroadcastTo{\n\t\tshapeRef: shapeT,\n\t\tscalars:  constScalars,\n\t\toutputs:  outs,\n\t}\n\tbuilder.addOperator(operator)\n\n\treturn outs, nil\n}\n\n// ============================================================================\n// Helpers to handle Logical Plan Nodes\n// ============================================================================\n\n// runSQLString create sql string from lp with dialect\nfunc (builder *OperatorGraphBuilder) runSQLString(lp core.LogicalPlan) (sql string, newTableRefs []string, err error) {\n\tneedRewrite := false\n\tfor _, party := range builder.enginesInfo.GetParties() {\n\t\tif len(builder.enginesInfo.GetTablesByParty(party)) > 0 {\n\t\t\tneedRewrite = true\n\t\t}\n\t}\n\tvar m map[core.DbTable]core.DbTable\n\tif needRewrite {\n\t\tm = builder.enginesInfo.GetDbTableMap()\n\t}\n\n\treturn core.RewriteSQLFromLP(lp, m, needRewrite)\n}\n\nfunc (builder *OperatorGraphBuilder) buildSinglePartySQL(lp core.LogicalPlan, sourceParty string) error {\n\t// sql and newTableRefs are used for building runSQL op in SCQL engine\n\tsql, newTableRefs, err := builder.runSQLString(lp)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildSinglePartySQL: failed to rewrite sql=\\\"%s\\\", err: %w\", sql, err)\n\t}\n\n\tsubGraphBuilder := NewOperatorGraphBuilder(builder.tensorMetaManager, builder.enginesInfo, builder.issuerPartyCode, builder.createdAt)\n\t// SCQL currently supports limited functions.\n\t// Some are unsupported by the SCQL Engine and not listed in the compiler's constant.go.\n\t// Enabling function checks leads to errors.\n\t// However, these functions can run in single-party setups, so we skip function checks when generating a single-party OperatorGraph.\n\tsubGraphBuilder.checkFuncs = false\n\n\toutputs := make([]*TensorMeta, 0, len(lp.Schema().Columns))\n\tvar subGraphNodes []Operator\n\tvar subGraphTracker *TensorConsumerTracker\n\tif err := subGraphBuilder.buildInternal(lp, true); err != nil {\n\t\tlogrus.Warnf(\"buildSinglePartySQL: failed to build the sub plan for party %s, err: %v\", sourceParty, err)\n\t\t// Build single party SQL failed\n\t\t// Just follow the logical plan to get RunSQL output\n\t\t// TODO: clean sub-graph tensors in TensorMetaManager\n\t\tresultTable := ResultTable{}\n\t\tfor _, column := range lp.Schema().Columns {\n\t\t\ttp, err := graph.ConvertDataType(column.RetType)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"buildSinglePartySQL: %v\", err)\n\t\t\t}\n\t\t\t// Can not infer name from datasource due to sub-plan compilation fail.\n\t\t\tname := column.String()\n\t\t\ttensor := builder.tensorMetaManager.CreateTensorMeta(name, tp)\n\t\t\toutputs = append(outputs, tensor)\n\t\t\tresultTable[column.UniqueID] = tensor\n\t\t}\n\t\tsubGraphNodes = nil\n\t\tsubGraphTracker = nil\n\n\t\tif err := builder.tensorMetaManager.setLPResultTable(lp, resultTable, false); err != nil {\n\t\t\treturn fmt.Errorf(\"buildSinglePartySQL: %v\", err)\n\t\t}\n\t} else {\n\t\tresultTable, err := subGraphBuilder.tensorMetaManager.getLPResultTable(lp)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildSinglePartySQL: failed to get result table for party %s, err: %w\", sourceParty, err)\n\t\t}\n\t\tfor _, column := range lp.Schema().Columns {\n\t\t\ttensor, ok := resultTable[column.UniqueID]\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"buildSinglePartySQL: failed to get tensor for column %s\", column.String())\n\t\t\t}\n\t\t\ttp, err := graph.ConvertDataType(column.RetType)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"buildSinglePartySQL: %v\", err)\n\t\t\t}\n\t\t\t// tensor.Name = column.String() // This is the way to get name in old translator. For now, we infer name from datasource.\n\t\t\ttensor.DType = tp\n\t\t\toutputs = append(outputs, tensor)\n\t\t}\n\t\tsubGraphNodes = subGraphBuilder.operators\n\t\tsubGraphTracker = subGraphBuilder.consumerTracker\n\t}\n\n\toperator := &OperatorRunSQL{\n\t\toutputs:         outputs,\n\t\tsql:             sql,\n\t\ttableRefs:       newTableRefs,\n\t\tsourceParty:     sourceParty,\n\t\tsubGraphNodes:   subGraphNodes,\n\t\tsubGraphTracker: subGraphTracker,\n\t}\n\tbuilder.addOperator(operator)\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildEQJoin(join *core.LogicalJoin) error {\n\tresultTable := ResultTable{}\n\tleft, right := join.Children()[0], join.Children()[1]\n\tvar leftKeyTs = []*TensorMeta{}\n\tvar rightKeyTs = []*TensorMeta{}\n\n\tfor _, equalCondition := range join.EqualConditions {\n\t\tcols, err := extractEQColumns(equalCondition)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildEQJoin: %v\", err)\n\t\t}\n\t\tleftKeyCol, rightKeyCol := cols[0], cols[1]\n\t\tleftKeyT, err := builder.tensorMetaManager.getLPColumnTensor(left, leftKeyCol)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildEQJoin: %v\", err)\n\t\t}\n\t\tleftKeyTs = append(leftKeyTs, leftKeyT)\n\t\trightKeyT, err := builder.tensorMetaManager.getLPColumnTensor(right, rightKeyCol)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildEQJoin: %v\", err)\n\t\t}\n\t\trightKeyTs = append(rightKeyTs, rightKeyT)\n\t}\n\n\t// TODO: support empty payload in SCQL engine\n\n\tleftUsed := core.GetUsedList(join.Schema().Columns, left.Schema())\n\tleftUsedCols := sliceutil.Take(left.Schema().Columns, leftUsed)\n\tleftPayloads, leftOutputs, err := builder.processPayloads(resultTable, left, leftUsedCols)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildEQJoin: %v\", err)\n\t}\n\n\trightUsed := core.GetUsedList(join.Schema().Columns, right.Schema())\n\trightUsedCols := sliceutil.Take(right.Schema().Columns, rightUsed)\n\trightPayloads, rightOutputs, err := builder.processPayloads(resultTable, right, rightUsedCols)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildEQJoin: %v\", err)\n\t}\n\n\tif err := builder.tensorMetaManager.setLPResultTable(join, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildEQJoin: %v\", err)\n\t}\n\n\toperator := &OperatorEQJoin{\n\t\tleftKeys:      leftKeyTs,\n\t\trightKeys:     rightKeyTs,\n\t\tleftPayloads:  leftPayloads,\n\t\trightPayloads: rightPayloads,\n\t\tleftOutputs:   leftOutputs,\n\t\trightOutputs:  rightOutputs,\n\t\tjoinType:      join.JoinType,\n\t}\n\tbuilder.addOperator(operator)\n\treturn nil\n}\n\n// LogicalMaxOneRow checks if a query returns no more than one row.\nfunc (builder *OperatorGraphBuilder) buildMaxOneRow(plan *core.LogicalMaxOneRow) error {\n\tif len(plan.Children()) != 1 {\n\t\treturn fmt.Errorf(\"buildMaxOneRow: must contain one children but got %d\", len(plan.Children()))\n\t}\n\t// It is a no-op in the operator graph. Just pass through the result table from its child.\n\tresultTable, err := builder.tensorMetaManager.getLPResultTable(plan.Children()[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildMaxOneRow: %v\", err)\n\t}\n\tif err := builder.tensorMetaManager.setLPResultTable(plan, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildMaxOneRow: %v\", err)\n\t}\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildCrossJoin(join *core.LogicalJoin) error {\n\tresultTable := ResultTable{}\n\n\tlhs := join.Children()[0]\n\trhs := join.Children()[1]\n\n\tleftOutputs := make([]*TensorMeta, 0, len(lhs.Schema().Columns))\n\tleftChildResult, err := builder.tensorMetaManager.getLPSchemaTensors(lhs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildCrossJoin: %v\", err)\n\t}\n\tfor idx, tensor := range leftChildResult {\n\t\toutput := builder.tensorMetaManager.CreateTensorMetaAs(tensor)\n\t\tleftOutputs = append(leftOutputs, output)\n\t\tresultTable[lhs.Schema().Columns[idx].UniqueID] = output\n\t}\n\n\trightOutputs := make([]*TensorMeta, 0, len(rhs.Schema().Columns))\n\trightChildResult, err := builder.tensorMetaManager.getLPSchemaTensors(rhs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildCrossJoin: %v\", err)\n\t}\n\tfor idx, tensor := range rightChildResult {\n\t\toutput := builder.tensorMetaManager.CreateTensorMetaAs(tensor)\n\t\trightOutputs = append(rightOutputs, output)\n\t\tresultTable[rhs.Schema().Columns[idx].UniqueID] = output\n\t}\n\n\tif err := builder.tensorMetaManager.setLPResultTable(join, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildLogicalJoin: %v\", err)\n\t}\n\n\toperator := &OperatorCrossJoin{\n\t\tleftInputs:   leftChildResult,\n\t\trightInputs:  rightChildResult,\n\t\tleftOutputs:  leftOutputs,\n\t\trightOutputs: rightOutputs,\n\t}\n\tbuilder.addOperator(operator)\n\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildReduceAggregation(agg *core.LogicalAggregation) error {\n\tchildResultTable, err := builder.tensorMetaManager.getLPResultTable(agg.Children()[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildReduceAggregation: %v\", err)\n\t}\n\tresultTable := ResultTable{}\n\n\tfor idx, aggFunc := range agg.AggFuncs {\n\t\tif len(aggFunc.Args) != 1 && aggFunc.Name != ast.AggPercentileDisc {\n\t\t\treturn fmt.Errorf(\"buildReduceAggregation: invalid parameter count for %v\", aggFunc)\n\t\t}\n\t\tif len(aggFunc.Args) != 2 && aggFunc.Name == ast.AggPercentileDisc {\n\t\t\treturn fmt.Errorf(\"buildReduceAggregation: invalid parameter count for %v\", aggFunc)\n\t\t}\n\t\tvar argTensor *TensorMeta\n\t\t_, constArg := aggFunc.Args[0].(*expression.Constant)\n\t\tif aggFunc.Name == ast.AggFuncCount && !aggFunc.HasDistinct && constArg {\n\t\t\tchildResults, err := builder.tensorMetaManager.getLPSchemaTensors(agg.Children()[0])\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"buildReduceAggregation: %v\", err)\n\t\t\t}\n\t\t\tif len(childResults) == 0 {\n\t\t\t\treturn fmt.Errorf(\"buildReduceAggregation: count(*) with empty child result\")\n\t\t\t}\n\t\t\t// when count(*), we use child node's result to get shape\n\t\t\t// here we select the 0th result arbitrarily，since the visibility does not have much impact on performance\n\t\t\t// FIXME？ maybe we should introduce OperatorShape instead of handling special case in OperatorReduce\n\t\t\targTensor = childResults[0]\n\t\t} else {\n\t\t\targTensor, err = builder.getTensorFromExpression(aggFunc.Args[0], childResultTable, false)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildReduceAggregation: %v\", err)\n\t\t}\n\n\t\tif aggFunc.Name != ast.AggFuncCount {\n\t\t\tif aggFunc.Args[0].GetType().Tp == mysql.TypeString {\n\t\t\t\treturn fmt.Errorf(\"buildReduceAggregation: unsupported aggregation function %v with a string type argument\", aggFunc.Name)\n\t\t\t}\n\t\t}\n\n\t\toutput, err := builder.addReduceAggOp(aggFunc, argTensor)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildReduceAggregation: %v\", err)\n\t\t}\n\t\tresultTable[agg.Schema().Columns[idx].UniqueID] = output\n\t}\n\n\tif err := builder.tensorMetaManager.setLPResultTable(agg, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildReduceAggregation: %v\", err)\n\t}\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildGroupAggregation(agg *core.LogicalAggregation) error {\n\tchildResultTable, err := builder.tensorMetaManager.getLPResultTable(agg.Children()[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"buildGroupAggregation: %v\", err)\n\t}\n\tresultTable := ResultTable{}\n\n\t// build group keys\n\tgroupKeys := make([]*TensorMeta, 0, len(agg.GroupByItems))\n\tfor _, key := range agg.GroupByItems {\n\t\ttensor, err := builder.getTensorFromExpression(key, childResultTable, false)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"buildGroupAggregation: %v\", err)\n\t\t}\n\t\tgroupKeys = append(groupKeys, tensor)\n\t}\n\n\taggArgs := make([]*TensorMeta, 0, len(agg.AggFuncs))\n\tsimpleCountOutputs := make([]*TensorMeta, 0, len(agg.AggFuncs))\n\targFuncOutputs := make([]*TensorMeta, 0, len(agg.AggFuncs))\n\taggFuncsWithArg := make([]*aggregation.AggFuncDesc, 0, len(agg.AggFuncs))\n\n\tfor idx, aggFunc := range agg.AggFuncs {\n\t\tif len(aggFunc.Args) != 1 && aggFunc.Name != ast.AggPercentileDisc {\n\t\t\treturn fmt.Errorf(\"buildGroupAggregation: invalid parameter count for %v\", aggFunc)\n\t\t}\n\t\tif len(aggFunc.Args) != 2 && aggFunc.Name == ast.AggPercentileDisc {\n\t\t\treturn fmt.Errorf(\"buildGroupAggregation: invalid parameter count for %v\", aggFunc)\n\t\t}\n\n\t\tif aggFunc.Name != ast.AggFuncCount && aggFunc.Name != ast.AggFuncFirstRow && aggFunc.Args[0].GetType().Tp == mysql.TypeString {\n\t\t\treturn fmt.Errorf(\"buildGroupAggregation: unsupported aggregation function %v with a string type argument\", aggFunc.Name)\n\t\t}\n\n\t\t// deal with simple count, which no need to build expression for agg func argument\n\t\tvar payload *TensorMeta\n\t\tif isSimpleCount(aggFunc) {\n\t\t\toutput := builder.tensorMetaManager.CreateTensorMeta(\"simple_count_result\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\t\tsimpleCountOutputs = append(simpleCountOutputs, output)\n\t\t\tresultTable[agg.Schema().Columns[idx].UniqueID] = output\n\t\t} else {\n\t\t\tif aggFunc.Name == ast.AggFuncCount && aggFunc.Mode == aggregation.FinalMode {\n\t\t\t\tif _, ok := aggFunc.Args[0].(*expression.Column); !ok {\n\t\t\t\t\treturn fmt.Errorf(\"buildGroupAggregation: unsupported count final type %v\", aggFunc)\n\t\t\t\t}\n\t\t\t}\n\t\t\tpayload, err = builder.getTensorFromExpression(aggFunc.Args[0], childResultTable, false)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"buildGroupAggregation: %v\", err)\n\t\t\t}\n\n\t\t\taggArgs = append(aggArgs, payload)\n\t\t\toutput := builder.tensorMetaManager.CreateTensorMetaAs(payload)\n\t\t\toutput.DType = inferAggOutputType(aggFunc, payload.DType)\n\t\t\toutput.Name = fmt.Sprintf(\"%v_%v\", output.Name, aggFunc.Name)\n\t\t\targFuncOutputs = append(argFuncOutputs, output)\n\t\t\tresultTable[agg.Schema().Columns[idx].UniqueID] = output\n\n\t\t\taggFuncsWithArg = append(aggFuncsWithArg, aggFunc)\n\t\t}\n\t}\n\n\tif err := builder.tensorMetaManager.setLPResultTable(agg, resultTable, builder.checkFuncs); err != nil {\n\t\treturn fmt.Errorf(\"buildGroupAggregation: %v\", err)\n\t}\n\n\toperator := &OperatorGroupAgg{\n\t\tgroupKeys:          groupKeys,\n\t\taggArgs:            aggArgs,\n\t\targFuncOutputs:     argFuncOutputs,\n\t\tsimpleCountOutputs: simpleCountOutputs,\n\t\taggFuncsWithArg:    aggFuncsWithArg,\n\t}\n\tbuilder.addOperator(operator)\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) addFilterOp(mask *TensorMeta, inputs []*TensorMeta) []*TensorMeta {\n\toutputs := make([]*TensorMeta, 0, len(inputs))\n\tfor _, input := range inputs {\n\t\toutput := builder.tensorMetaManager.CreateTensorMetaAs(input)\n\t\toutputs = append(outputs, output)\n\t}\n\n\toperator := &OperatorFilter{\n\t\tmask:    mask,\n\t\tinputs:  inputs,\n\t\toutputs: outputs,\n\t}\n\tbuilder.addOperator(operator)\n\n\treturn outputs\n}\n\nfunc (builder *OperatorGraphBuilder) addConcatOp(inputs []*TensorMeta) (*TensorMeta, error) {\n\tif len(inputs) == 0 {\n\t\treturn nil, fmt.Errorf(\"addConcatOp: unexpected inputs number: %d\", len(inputs))\n\t}\n\n\toutput := builder.tensorMetaManager.CreateTensorMetaAs(inputs[0])\n\tfor _, input := range inputs[1:] {\n\t\tif !input.DType.Equal(output.DType) {\n\t\t\treturn nil, fmt.Errorf(\"addConcatOp: inputs have different types: %s, %s\", input.DType, output.DType)\n\t\t}\n\t}\n\n\toperator := &OperatorConcat{\n\t\tinputs: inputs,\n\t\toutput: output,\n\t}\n\tbuilder.addOperator(operator)\n\treturn output, nil\n}\n\nfunc (builder *OperatorGraphBuilder) addReduceAggOp(aggFunc *aggregation.AggFuncDesc, input *TensorMeta) (*TensorMeta, error) {\n\toutput := builder.tensorMetaManager.CreateTensorMetaAs(input)\n\toutput.DType = inferAggOutputType(aggFunc, input.DType)\n\toutput.Name = fmt.Sprintf(\"%v_%v\", output.Name, aggFunc.Name)\n\n\toperator := &OperatorReduce{\n\t\tinput:   input,\n\t\toutput:  output,\n\t\taggFunc: aggFunc,\n\t}\n\tbuilder.addOperator(operator)\n\treturn output, nil\n}\n\nfunc (builder *OperatorGraphBuilder) addInOp(left, right *TensorMeta) (*TensorMeta, error) {\n\tif !left.DType.Equal(right.DType) {\n\t\treturn nil, fmt.Errorf(\"addInOp: type mismatch: %s, %s\", left.DType, right.DType)\n\t}\n\n\toutput := builder.tensorMetaManager.CreateTensorMeta(\"in_result\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_BOOL))\n\n\toperator := &OperatorIn{\n\t\tleft:   left,\n\t\tright:  right,\n\t\toutput: output,\n\t}\n\tbuilder.addOperator(operator)\n\n\treturn output, nil\n}\n\nfunc (builder *OperatorGraphBuilder) processPayloads(resultTable ResultTable, lp core.LogicalPlan, payloadCols []*expression.Column) ([]*TensorMeta, []*TensorMeta, error) {\n\tpayloads := make([]*TensorMeta, 0, len(payloadCols))\n\toutputs := make([]*TensorMeta, 0, len(payloadCols))\n\tfor _, col := range payloadCols {\n\t\tpayload, err := builder.tensorMetaManager.getLPColumnTensor(lp, col)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"processPayloads: %v\", err)\n\t\t}\n\t\tpayloads = append(payloads, payload)\n\n\t\toutput := builder.tensorMetaManager.CreateTensorMetaAs(payload)\n\t\toutputs = append(outputs, output)\n\t\tresultTable[col.UniqueID] = output\n\t}\n\treturn payloads, outputs, nil\n}\n\n// ============================================================================\n// Handle Expression\n// ============================================================================\n\nfunc (builder *OperatorGraphBuilder) getTensorFromExpression(expr expression.Expression, tensorTable ResultTable, isApply bool) (*TensorMeta, error) {\n\tswitch x := expr.(type) {\n\tcase *expression.Column:\n\t\treturn tensorTable.getColumnTensorMeta(x)\n\tcase *expression.ScalarFunction:\n\t\treturn builder.buildExprScalarFunction(x, tensorTable, isApply)\n\tcase *expression.Constant:\n\t\treturn builder.buildExprConstant(x)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"getTensorFromExpression: unsupported expression type: %T\", x)\n\t}\n}\n\nfunc checkFuncInputsType(funcName string, inputs []*TensorMeta) error {\n\tswitch funcName {\n\tcase ast.UnaryNot, ast.LogicOr, ast.LogicAnd:\n\t\tfor idx, input := range inputs {\n\t\t\tif input.DType.DType != proto.PrimitiveDataType_BOOL {\n\t\t\t\treturn fmt.Errorf(\"function %s expect bool input, but got %s for input_%d\", funcName, input.DType.String(), idx)\n\t\t\t}\n\t\t}\n\tcase ast.Lower, ast.Upper, ast.Trim:\n\t\tfor idx, input := range inputs {\n\t\t\tif input.DType.DType != proto.PrimitiveDataType_STRING {\n\t\t\t\treturn fmt.Errorf(\"function %s expect string input, but got %s for input_%d\", funcName, input.DType.String(), idx)\n\t\t\t}\n\t\t}\n\tcase ast.Sin, ast.Cos, ast.Acos, ast.Asin, ast.Tan, ast.Cot, ast.Atan, ast.GeoDist, ast.Abs, ast.Ceil, ast.Floor, ast.Round, ast.Radians, ast.Degrees, ast.Ln, ast.Log10, ast.Log2, ast.Sqrt, ast.Exp:\n\t\tfor idx, input := range inputs {\n\t\t\tif !input.DType.IsNumericType() {\n\t\t\t\treturn fmt.Errorf(\"function %s expect numeric input, but got %s for input_%d\", funcName, input.DType.String(), idx)\n\t\t\t}\n\t\t}\n\tcase ast.LT, ast.LE, ast.GT, ast.GE, ast.Plus, ast.Minus, ast.Mul, ast.Div:\n\t\tfor idx, input := range inputs {\n\t\t\tif input.DType.IsStringType() {\n\t\t\t\treturn fmt.Errorf(\"function %s got string input for input_%d\", funcName, idx)\n\t\t\t}\n\t\t}\n\tcase ast.IntDiv, ast.Mod:\n\t\tif (inputs[0].DType.DType != proto.PrimitiveDataType_INT64 && inputs[0].DType.DType != proto.PrimitiveDataType_DATETIME && inputs[0].DType.DType != proto.PrimitiveDataType_TIMESTAMP) ||\n\t\t\t(inputs[1].DType.DType != proto.PrimitiveDataType_INT64) {\n\t\t\treturn fmt.Errorf(\"function %s: requires both left and right operands be int64-like\", funcName)\n\t\t}\n\tcase ast.Case, ast.If:\n\t\ttp := inputs[len(inputs)-1].DType\n\t\tfor i := 0; i < len(inputs)/2; i++ {\n\t\t\tif inputs[i*2].DType.IsStringType() {\n\t\t\t\treturn fmt.Errorf(\"function %s does not support string condition\", funcName)\n\t\t\t}\n\t\t\tif !inputs[i*2+1].DType.Equal(tp) {\n\t\t\t\treturn fmt.Errorf(\"function %s: all values must have the same type\", funcName)\n\t\t\t}\n\t\t}\n\tcase ast.Ifnull:\n\t\tif !inputs[0].DType.Equal(inputs[1].DType) {\n\t\t\treturn fmt.Errorf(\"function Ifnull: both arguments must have the same type\")\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc getOutputType(funcName string, inputs []*TensorMeta) (*graph.DataType, error) {\n\tvar outType *graph.DataType\n\tswitch funcName {\n\tcase ast.UnaryNot, ast.IsNull, ast.LT, ast.LE, ast.GT, ast.GE, ast.EQ, ast.NE, ast.LogicAnd, ast.LogicOr:\n\t\toutType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_BOOL)\n\tcase ast.Lower, ast.Upper, ast.Trim, ast.Concat, ast.Substr, ast.Substring:\n\t\toutType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING)\n\tcase ast.StrToDate:\n\t\toutType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_DATETIME)\n\tcase ast.Ifnull, ast.Abs, ast.AddDate, ast.SubDate:\n\t\toutType = inputs[0].DType\n\tcase ast.Coalesce:\n\t\toutType = inputs[0].DType\n\t\tif outType.DType == proto.PrimitiveDataType_FLOAT32 {\n\t\t\toutType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64)\n\t\t}\n\tcase ast.Case, ast.If:\n\t\toutType = inputs[len(inputs)-1].DType\n\tcase ast.Sin, ast.Cos, ast.Acos, ast.Asin, ast.Tan, ast.Cot, ast.Atan, ast.GeoDist, ast.Radians, ast.Degrees, ast.Ln, ast.Log10, ast.Log2, ast.Sqrt, ast.Exp, ast.Div, ast.Atan2:\n\t\toutType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64)\n\tcase ast.Ceil, ast.Floor, ast.Round, ast.Mod, ast.IntDiv, ast.DateDiff:\n\t\toutType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64)\n\tcase ast.Plus, ast.Minus, ast.Mul, ast.Pow:\n\t\tif funcName == ast.Minus && inputs[0].DType.IsTimeType() {\n\t\t\treturn graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64), nil\n\t\t}\n\t\tif isFloatOrDoubleType(inputs[0].DType.DType) || isFloatOrDoubleType(inputs[1].DType.DType) {\n\t\t\treturn graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64), nil\n\t\t}\n\t\tif inputs[0].DType.Equal(inputs[1].DType) {\n\t\t\treturn inputs[0].DType, nil\n\t\t}\n\t\treturn graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64), nil\n\tcase ast.Greatest, ast.Least:\n\t\toutType = inputs[0].DType\n\t\tisTimestamp := inputs[0].DType.IsTimeType()\n\t\tfor _, input := range inputs[1:] {\n\t\t\tif isTimestamp {\n\t\t\t\tif !input.DType.IsTimeType() {\n\t\t\t\t\treturn nil, fmt.Errorf(\"function Least/Greatest got wrong type %s\", input.DType.String())\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif !input.DType.IsNumericType() {\n\t\t\t\t\treturn nil, fmt.Errorf(\"function Least/Greatest got wrong type %s\", input.DType.String())\n\t\t\t\t}\n\t\t\t\ttp, err := graph.GetWiderType(outType, input.DType)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"function Least/Greatest: %v\", err)\n\t\t\t\t}\n\t\t\t\toutType = tp\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn graph.NewPrimitiveDataType(proto.PrimitiveDataType_PrimitiveDataType_UNDEFINED), fmt.Errorf(\"checkAndGetOutputType: unsupported function: %s\", funcName)\n\t}\n\n\treturn outType, nil\n}\n\nfunc checkArgsNum(funcName string, inputs []*TensorMeta, constParams []*expression.Constant) error {\n\tif len(inputs) == 0 {\n\t\treturn fmt.Errorf(\"checkArgsNum: %s expects at least 1 input tensor, but got 0\", funcName)\n\t}\n\targNum, ok := functionArgNum[funcName]\n\tif !ok {\n\t\treturn fmt.Errorf(\"checkArgsNum: unsupported function: %s\", funcName)\n\t}\n\tif argNum >= 0 && len(inputs) != argNum {\n\t\treturn fmt.Errorf(\"checkArgsNum: %s expects %d arguments, but got %d\", funcName, argNum, len(inputs))\n\t}\n\n\t// handle special cases\n\t// TODO: Maintain a detailed function table and unify the check logic\n\tswitch funcName {\n\tcase ast.Substr, ast.Substring:\n\t\tif len(inputs) != 1 {\n\t\t\treturn fmt.Errorf(\"checkArgsNum: %s expects 1 input tensor, but got %d\", funcName, len(inputs))\n\t\t}\n\t\tif len(constParams) != 1 && len(constParams) != 2 {\n\t\t\treturn fmt.Errorf(\"checkArgsNum: %s expects 1 or 2 constant parameters, but got %d\", funcName, len(constParams))\n\t\t}\n\tcase ast.StrToDate:\n\t\tif len(inputs) != 1 {\n\t\t\treturn fmt.Errorf(\"checkArgsNum: %s expects 1 input tensor, but got %d\", funcName, len(inputs))\n\t\t}\n\t\tif len(constParams) != 1 {\n\t\t\treturn fmt.Errorf(\"checkArgsNum: %s expects 1 constant parameters, but got %d\", funcName, len(constParams))\n\t\t}\n\tcase ast.Case:\n\t\tif len(inputs)%2 != 1 {\n\t\t\treturn fmt.Errorf(\"checkArgsNum: %s expects odd number of arguments\", funcName)\n\t\t}\n\tcase ast.GeoDist:\n\t\tif len(inputs) != 4 && len(inputs) != 5 {\n\t\t\treturn fmt.Errorf(\"checkArgsNum: %s expects 4 or 5 arguments\", funcName)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (builder *OperatorGraphBuilder) addFunctionNode(funcName string, inputs []*TensorMeta, constParams []*expression.Constant) (*TensorMeta, error) {\n\n\tif builder.checkFuncs {\n\t\tif err := checkArgsNum(funcName, inputs, constParams); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"addFunctionNode: %v\", err)\n\t\t}\n\t\tif err := checkFuncInputsType(funcName, inputs); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"addFunctionNode: %v\", err)\n\t\t}\n\t}\n\n\toutType, err := getOutputType(funcName, inputs)\n\tif err != nil {\n\t\tif builder.checkFuncs {\n\t\t\treturn nil, fmt.Errorf(\"addFunctionNode: %v\", err)\n\t\t} else {\n\t\t\toutType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_PrimitiveDataType_UNDEFINED)\n\t\t}\n\t}\n\n\toutput := builder.tensorMetaManager.CreateTensorMeta(fmt.Sprintf(\"%s_out\", funcName), outType)\n\n\tif builder.checkFuncs {\n\t\t// check if is scalar\n\t\tisScalar := inputs[0].IsConstScalar\n\t\tfor _, input := range inputs[1:] {\n\t\t\tif input.IsConstScalar != isScalar {\n\t\t\t\treturn nil, fmt.Errorf(\"addFunctionNode: input tensors should all be scalar or all be tensor\")\n\t\t\t}\n\t\t}\n\t\toutput.IsConstScalar = isScalar\n\t}\n\n\toperator := &OperatorFunction{\n\t\tinputs:      inputs,\n\t\toutput:      output,\n\t\tconstParams: constParams,\n\t\tfuncName:    funcName,\n\t}\n\tbuilder.addOperator(operator)\n\n\treturn output, nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildExprScalarFunction(sf *expression.ScalarFunction, tensorTable ResultTable, isApply bool) (*TensorMeta, error) {\n\t// for functions without arguments, generate OperatorConstant\n\tif sf.FuncName.L == ast.Now || sf.FuncName.L == ast.Curdate {\n\t\tunix_time := builder.createdAt\n\t\tvar timeDatum types.Datum\n\t\tswitch sf.FuncName.L {\n\t\tcase ast.Now:\n\t\t\ttimeDatum = types.NewTimeDatum(types.NewTime(types.NewMysqlTime(unix_time), mysql.TypeDate, types.DefaultFsp))\n\t\tcase ast.Curdate:\n\t\t\tdate := time.Date(unix_time.Year(), unix_time.Month(), unix_time.Day(), 0, 0, 0, 0, builder.createdAt.Location())\n\t\t\ttimeDatum = types.NewTimeDatum(types.NewTime(types.NewMysqlTime(date), mysql.TypeDate, types.DefaultFsp))\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: unsupported function: %s\", sf.FuncName.L)\n\t\t}\n\t\treturn builder.addConstantNode(&timeDatum)\n\t}\n\n\t// for funcitons with arguments, generate OperatorFunction\n\targs := sf.GetArgs()\n\n\t// handle function with const params\n\tif sf.FuncName.L == ast.Substr || sf.FuncName.L == ast.Substring {\n\t\tstrInput, err := builder.getTensorFromExpression(args[0], tensorTable, false)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: err input for %s\", sf.FuncName.L)\n\t\t}\n\t\tif strInput.DType.DType != proto.PrimitiveDataType_STRING {\n\t\t\t// TODO: support other types\n\t\t\treturn nil, fmt.Errorf(\"buildScalarFunction: err input type{%s} for %s\", strInput.DType, sf.FuncName.L)\n\t\t}\n\n\t\t// substr(str, start) or substr(str, start, length)\n\t\tconstParams := []*expression.Constant{}\n\t\tif len(args) >= 2 {\n\t\t\tstart, ok := args[1].(*expression.Constant)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"buildScalarFunction: args[1] should be constant for %s\", sf.FuncName.L)\n\t\t\t}\n\t\t\tconstParams = append(constParams, start)\n\t\t}\n\t\t// substr(str, start, length)\n\t\tif len(args) >= 3 {\n\t\t\tlength, ok := args[2].(*expression.Constant)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"buildScalarFunction: args[2] should be constant for %s\", sf.FuncName.L)\n\t\t\t}\n\t\t\tconstParams = append(constParams, length)\n\t\t}\n\t\treturn builder.addFunctionNode(sf.FuncName.L, []*TensorMeta{strInput}, constParams)\n\t}\n\tif sf.FuncName.L == ast.StrToDate {\n\t\tif len(args) != 2 {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction StrToDate: incorrect arguments num, expecting 2 but get %v\", len(args))\n\t\t}\n\t\tdateStrExpr, formatStrExpr := args[0], args[1]\n\t\tdateStrConst, dateIsConst := dateStrExpr.(*expression.Constant)\n\t\tformatStrConst, formatIsConst := formatStrExpr.(*expression.Constant)\n\n\t\t// check format str arg\n\t\tif !formatIsConst {\n\t\t\treturn nil, fmt.Errorf(\"buildScalarFunction StrToDate: format string should be constant\")\n\t\t}\n\t\tformatStr := formatStrConst.Value.GetString()\n\t\tif formatStrConst.Value.Kind() != types.KindString {\n\t\t\treturn nil, fmt.Errorf(\"buildScalarFunction StrToDate: invalid right argument type, exepecting %d but got %d\", types.KindString, formatStrConst.Value.Kind())\n\t\t}\n\n\t\t// add constant node for constant dateStr - str_to_date('2025-06-05', '%Y-%m-%d')\n\t\tif dateIsConst {\n\t\t\tif dateStrConst.Value.Kind() != types.KindString {\n\t\t\t\treturn nil, fmt.Errorf(\"buildScalarFunction StrToDate: invalid left argument type, exepecting %d but got %d\", types.KindString, dateStrConst.Value.Kind())\n\t\t\t}\n\t\t\tgoLayout, err := stringutil.MySQLDateFormatToGoLayout(formatStr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"buildScalarFunction StrToDate: format string '%s' is invalid: %w\", formatStr, err)\n\t\t\t}\n\n\t\t\tdateStr := dateStrConst.Value.GetString()\n\t\t\tparsedTime, err := time.Parse(goLayout, dateStr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"buildScalarFunction StrToDate: date string '%s' is invalid: %w\", dateStr, err)\n\t\t\t}\n\n\t\t\tmysqlTime := types.NewTime(\n\t\t\t\ttypes.NewMysqlTime(parsedTime),\n\t\t\t\tmysql.TypeDate,\n\t\t\t\ttypes.DefaultFsp,\n\t\t\t)\n\n\t\t\tvar datum types.Datum\n\t\t\tdatum.SetMysqlTime(mysqlTime)\n\t\t\treturn builder.addConstantNode(&datum)\n\t\t}\n\n\t\t// format str is a const expression, and date str is not\n\t\tdateTensor, err := builder.getTensorFromExpression(dateStrExpr, tensorTable, false)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %v\", err)\n\t\t}\n\t\treturn builder.addFunctionNode(sf.FuncName.L, []*TensorMeta{dateTensor}, []*expression.Constant{formatStrConst})\n\t}\n\n\t// handle input tensors\n\tinputs := []*TensorMeta{}\n\tif sf.FuncName.L == ast.AddDate || sf.FuncName.L == ast.DateAdd || sf.FuncName.L == ast.SubDate || sf.FuncName.L == ast.DateSub {\n\t\tvar err error\n\t\targs, err = expression.TransferDateFuncIntervalToSeconds(args)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// add constant node for constant dateStr - eg. DATE_ADD/SUB('2025-04-05', INTERVAL 10 DAY)\n\t\tif dateStrConst, ok := args[0].(*expression.Constant); ok && dateStrConst.Value.Kind() == types.KindString {\n\t\t\tif intervalConst, ok := args[1].(*expression.Constant); ok {\n\t\t\t\treturn builder.buildConstantDateAdd(dateStrConst, intervalConst, sf.FuncName.L)\n\t\t\t}\n\t\t}\n\t}\n\tfor _, arg := range args {\n\t\tinput, err := builder.getTensorFromExpression(arg, tensorTable, false)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %v\", err)\n\t\t}\n\t\tinputs = append(inputs, input)\n\t}\n\t// Inputs may need cast\n\tif _, exist := constTensorNeedCastFuncs[sf.FuncName.L]; exist {\n\n\t\tcastOndemand := func(constTensor, otherTensor *TensorMeta) (*TensorMeta, error) {\n\t\t\t// Only support string to time currently\n\t\t\tif !constTensor.IsConstScalar {\n\t\t\t\treturn constTensor, nil\n\t\t\t}\n\t\t\tif !constTensor.DType.IsStringType() {\n\t\t\t\treturn constTensor, nil\n\t\t\t}\n\t\t\tif !otherTensor.DType.IsTimeType() {\n\t\t\t\treturn constTensor, nil\n\t\t\t}\n\n\t\t\t// Check passed, do the cast\n\t\t\tcasted := builder.tensorMetaManager.CreateTensorMetaAs(inputs[0])\n\t\t\tcasted.DType = otherTensor.DType\n\n\t\t\tcastInputs := []*TensorMeta{constTensor}\n\t\t\toperator := &OperatorFunction{\n\t\t\t\tinputs:      castInputs,\n\t\t\t\toutput:      casted,\n\t\t\t\tconstParams: []*expression.Constant{},\n\t\t\t\tfuncName:    ast.Cast,\n\t\t\t}\n\t\t\tbuilder.addOperator(operator)\n\n\t\t\treturn casted, nil\n\t\t}\n\n\t\tif len(inputs) != 2 {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %s expects 2 arguments\", sf.FuncName.L)\n\t\t}\n\t\tleft, err := castOndemand(inputs[0], inputs[1])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %v\", err)\n\t\t}\n\t\tright, err := castOndemand(inputs[1], left)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %v\", err)\n\t\t}\n\t\tinputs[0] = left\n\t\tinputs[1] = right\n\t}\n\n\tif !isApply && builder.checkFuncs {\n\t\tvar err error\n\t\tinputs, err = builder.addBroadcastToOndemand(inputs)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %v\", err)\n\t\t}\n\t}\n\n\t// some functions requires special handling\n\tswitch sf.FuncName.L {\n\tcase ast.Cot:\n\t\tif len(inputs) != 1 {\n\t\t\treturn nil, fmt.Errorf(\"buildScalarFunction: expect 1 argument for %s, got %d\", sf.FuncName.L, len(inputs))\n\t\t}\n\n\t\ttan, err := builder.addFunctionNode(ast.Tan, inputs, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Cot: %v\", err)\n\t\t}\n\n\t\toneDatum := types.NewIntDatum(int64(1))\n\t\toneScalar, err := builder.addConstantNode(&oneDatum)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Cot: %v\", err)\n\t\t}\n\n\t\talligned, err := builder.addBroadcastToOndemand([]*TensorMeta{oneScalar, tan})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Cot: %v\", err)\n\t\t}\n\n\t\toutput, err := builder.addFunctionNode(ast.Div, alligned, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Cot: %v\", err)\n\t\t}\n\t\treturn output, nil\n\n\tcase ast.UnaryMinus:\n\t\tzeroDatum := types.NewIntDatum(0)\n\t\tzeroScalar, err := builder.addConstantNode(&zeroDatum)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %v\", err)\n\t\t}\n\t\tallignedInputs, err := builder.addBroadcastToOndemand([]*TensorMeta{zeroScalar, inputs[0]})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %v\", err)\n\t\t}\n\t\toutput, err := builder.addFunctionNode(ast.Minus, allignedInputs, []*expression.Constant{})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %v\", err)\n\t\t}\n\t\treturn output, nil\n\tcase ast.UnaryPlus:\n\t\treturn inputs[0], nil\n\tcase ast.Cast:\n\t\tif len(inputs) != 1 {\n\t\t\treturn nil, fmt.Errorf(\"buildScalarFunction:err input for %s expected for %d got %d\", sf.FuncName.L, 1, len(inputs))\n\t\t}\n\t\toutput := builder.tensorMetaManager.CreateTensorMetaAs(inputs[0])\n\t\toutType, err := graph.ConvertDataType(sf.RetType)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %v\", err)\n\t\t}\n\t\toutput.DType = outType\n\t\toperator := &OperatorFunction{\n\t\t\tinputs:      inputs,\n\t\t\toutput:      output,\n\t\t\tconstParams: []*expression.Constant{},\n\t\t\tfuncName:    ast.Cast,\n\t\t}\n\t\tbuilder.addOperator(operator)\n\t\treturn output, nil\n\tcase ast.GeoDist:\n\t\tif len(inputs) != 4 && len(inputs) != 5 {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: incorrect arguments for function Geodist, exepcting (longittude1, latitude1, longtitude2, latitude2)\")\n\t\t}\n\t\t// distance = radius * arc cos(sin(latitude1) * sin(latitude2) + cos(latitude1) * cos(latitude2) * cos(longtitude1 - longtidude2))\n\t\t// convertDegreeToRadians\n\t\tdegreeToRadianCoefficient := math.Pi / 180\n\t\tcoeffDatum := types.NewFloat64Datum(degreeToRadianCoefficient)\n\t\tcoeffScalar, err := builder.addConstantNode(&coeffDatum)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\tallignedInputs, err := builder.addBroadcastToOndemand([]*TensorMeta{coeffScalar, inputs[0]})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\tcoeffTensor := allignedInputs[0]\n\n\t\tlongtitude1, err := builder.addFunctionNode(ast.Mul, []*TensorMeta{coeffTensor, inputs[0]}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\tlatidude1, err := builder.addFunctionNode(ast.Mul, []*TensorMeta{coeffTensor, inputs[1]}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\tlongtitude2, err := builder.addFunctionNode(ast.Mul, []*TensorMeta{coeffTensor, inputs[2]}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\tlatidude2, err := builder.addFunctionNode(ast.Mul, []*TensorMeta{coeffTensor, inputs[3]}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\n\t\t//sin(latitude1)\n\t\tsinLatitude1, err := builder.addFunctionNode(ast.Sin, []*TensorMeta{latidude1}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\t//sin(latitude2)\n\t\tsinLatitude2, err := builder.addFunctionNode(ast.Sin, []*TensorMeta{latidude2}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\t// sin(latitude1) * sin(latitude2)\n\t\tsinMulSin, err := builder.addFunctionNode(ast.Mul, []*TensorMeta{sinLatitude1, sinLatitude2}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\n\t\t// cos(latitude1)\n\t\tcosLatitude1, err := builder.addFunctionNode(ast.Cos, []*TensorMeta{latidude1}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\t// cos(latitude2)\n\t\tcosLatitude2, err := builder.addFunctionNode(ast.Cos, []*TensorMeta{latidude2}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\t// cos(latittude1) * cos(latitude2)\n\t\tcosMulCos, err := builder.addFunctionNode(ast.Mul, []*TensorMeta{cosLatitude1, cosLatitude2}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\n\t\t// longtitude1 - longtitude2\n\t\tlongtitudeDiff, err := builder.addFunctionNode(ast.Minus, []*TensorMeta{longtitude1, longtitude2}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\t// cos(longtitude1 - longtitude2)\n\t\tcosDiff, err := builder.addFunctionNode(ast.Cos, []*TensorMeta{longtitudeDiff}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\n\t\t// cos(latitude1) * cos(latitude2) * cos(longtitude1 - longtitude2)\n\t\tcosMulCosMulCos, err := builder.addFunctionNode(ast.Mul, []*TensorMeta{cosMulCos, cosDiff}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\n\t\t// sin(latitude1) * sin(latitude2) + cos(latitude1) * cos(latitude2) * cos(longtitude1 - longtitude2)\n\t\tsum, err := builder.addFunctionNode(ast.Plus, []*TensorMeta{sinMulSin, cosMulCosMulCos}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\n\t\t// arc cos(sin(latitude1) * sin(latitude2) + cos(latitude1) * cos(latitude2) * cos(longtitude1 - longtitude2))\n\t\tarcCos, err := builder.addFunctionNode(ast.Acos, []*TensorMeta{sum}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\n\t\tradius := &TensorMeta{}\n\t\tif len(inputs) == 4 {\n\t\t\taverageRadius := 6371 // average radius of earth from https://simple.wikipedia.org/wiki/Earth_radius\n\t\t\tradiusDatum := types.NewIntDatum(int64(averageRadius))\n\t\t\tradius, err = builder.addConstantNode(&radiusDatum)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t} else {\n\t\t\tradius = inputs[4]\n\t\t}\n\n\t\t// radius * arc cos(sin(latitude1) * sin(latitude2) + cos(latitude1) * cos(latitude2) * cos(longtitude1 - longtitude2))\n\t\talligned, err := builder.addBroadcastToOndemand([]*TensorMeta{radius, arcCos})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\n\t\toutput, err := builder.addFunctionNode(ast.Mul, alligned, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction Geodist: %v\", err)\n\t\t}\n\t\treturn output, nil\n\t}\n\n\toutput, err := builder.addFunctionNode(sf.FuncName.L, inputs, []*expression.Constant{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"buildExprScalarFunction: %v\", err)\n\t}\n\treturn output, nil\n}\n\nfunc (builder *OperatorGraphBuilder) buildExprConstant(c *expression.Constant) (*TensorMeta, error) {\n\treturn builder.addConstantNode(&c.Value)\n}\n\nfunc (builder *OperatorGraphBuilder) addConstantNode(value *types.Datum) (*TensorMeta, error) {\n\tvar dType *graph.DataType\n\tswitch value.Kind() {\n\tcase types.KindFloat32:\n\t\tdType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT32)\n\tcase types.KindFloat64:\n\t\tdType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64)\n\tcase types.KindInt64:\n\t\tdType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64)\n\tcase types.KindMysqlDecimal:\n\t\t// NOTE(shunde.csd): SCQL Internal does not distinguish decimal and float,\n\t\t// It handles decimal as float.\n\t\t// If users have requirements for precision, they should use integers.\n\t\tdType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64)\n\tcase types.KindString:\n\t\tdType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING)\n\tcase types.KindMysqlTime:\n\t\tdType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_DATETIME)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"buildExprConstant: unsupported data{%+v}\", value)\n\t}\n\n\toutput := builder.tensorMetaManager.CreateTensorMeta(\"constant_data\", dType)\n\toutput.IsConstScalar = true\n\n\toperator := &OperatorConstant{\n\t\toutput: output,\n\t\tvalue:  value,\n\t}\n\tbuilder.addOperator(operator)\n\treturn output, nil\n}\n\n// buildConstantDateAdd computes date addition/subtraction for string constant dates\nfunc (builder *OperatorGraphBuilder) buildConstantDateAdd(dateStrConst *expression.Constant, intervalSecondsConst *expression.Constant, funcName string) (*TensorMeta, error) {\n\tdateStr := dateStrConst.Value.GetString()\n\tintervalSeconds := intervalSecondsConst.Value.GetInt64()\n\n\tformats := []string{\n\t\t\"2006-01-02\",                 // DATE format\n\t\t\"2006-01-02 15:04:05\",        // DATETIME format\n\t\t\"2006-01-02T15:04:05\",        // ISO format\n\t\t\"2006-01-02 15:04:05.999999\", // DATETIME with microseconds\n\t}\n\n\tvar parsedTime time.Time\n\tvar err error\n\tmysqlType := mysql.TypeDate\n\n\tfor _, format := range formats {\n\t\tparsedTime, err = time.Parse(format, dateStr)\n\t\tif err == nil {\n\t\t\t// Determine MySQL type based on format\n\t\t\tif strings.Contains(format, \"15:04\") {\n\t\t\t\tmysqlType = mysql.TypeDatetime\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"buildConstantDateAdd: invalid date string '%s': %w\", dateStr, err)\n\t}\n\n\t// Apply interval (negative for subtraction functions)\n\tif funcName == ast.SubDate || funcName == ast.DateSub {\n\t\tintervalSeconds = -intervalSeconds\n\t}\n\tresultTime := parsedTime.Add(time.Duration(intervalSeconds) * time.Second)\n\n\tmysqlTime := types.NewTime(\n\t\ttypes.NewMysqlTime(resultTime),\n\t\tmysqlType,\n\t\ttypes.DefaultFsp,\n\t)\n\n\tvar datum types.Datum\n\tdatum.SetMysqlTime(mysqlTime)\n\treturn builder.addConstantNode(&datum)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/operator_graph_builder_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\t\"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/mock\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n)\n\nfunc ConvertMockEnginesToEnginesInfo(info *mock.MockEnginesInfo) (*graph.EnginesInfo, error) {\n\tparticipants := make([]*graph.Participant, 0, len(info.PartyToUrls))\n\tfor code, url := range sliceutil.SortedMap(info.PartyToUrls) {\n\t\tparticipants = append(participants, &graph.Participant{\n\t\t\tPartyCode: code,\n\t\t\tEndpoints: []string{url},\n\t\t\tToken:     info.PartyToCredentials[code],\n\t\t})\n\t}\n\tpartyToTables := make(map[string][]core.DbTable)\n\ttableToRefs := make(map[core.DbTable]core.DbTable)\n\tfor p, tables := range info.PartyToTables {\n\t\tvar dbTables []core.DbTable\n\t\tfor _, t := range tables {\n\t\t\tdt, err := core.NewDbTableFromString(t)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tdbTables = append(dbTables, dt)\n\t\t}\n\t\tpartyToTables[p] = dbTables\n\t}\n\n\tengineInfo := graph.NewEnginesInfo(graph.NewPartyInfo(participants), partyToTables)\n\tfor table, refTable := range info.TableToRefs {\n\t\tref, err := core.NewDbTableFromString(refTable)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttbl, err := core.NewDbTableFromString(table)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttableToRefs[tbl] = ref\n\t}\n\tengineInfo.UpdateTableToRefs(tableToRefs)\n\treturn engineInfo, nil\n}\n\ntype QueryCase struct {\n\tName  string `json:\"name\"`\n\tQuery string `json:\"query\"`\n}\n\nfunc TestBuilder(t *testing.T) {\n\tr := require.New(t)\n\n\tfile, err := os.Open(\"data/test_queries.json\")\n\tr.NoError(err)\n\tdefer file.Close()\n\n\tbyteValue, err := io.ReadAll(file)\n\tr.NoError(err)\n\tvar queryCases []QueryCase\n\terr = json.Unmarshal(byteValue, &queryCases)\n\tr.NoError(err)\n\n\tmockTables, err := mock.MockAllTables()\n\tr.NoError(err)\n\tis := infoschema.MockInfoSchema(mockTables)\n\tparser := parser.New()\n\tctx := mock.MockContext()\n\tmockEngines, err := mock.MockEngines()\n\tr.NoError(err)\n\tinfo, err := ConvertMockEnginesToEnginesInfo(mockEngines)\n\tr.NoError(err)\n\n\tfor _, queryCase := range queryCases {\n\t\tfmt.Println(\"query: \", queryCase.Name)\n\t\tstmt, err := parser.ParseOneStmt(queryCase.Query, \"\", \"\")\n\t\tr.NoError(err)\n\t\terr = core.Preprocess(ctx, stmt, is)\n\t\tr.NoError(err)\n\t\tlp, _, err := core.BuildLogicalPlanWithOptimization(context.Background(), ctx, stmt, is)\n\t\tr.NoError(err)\n\n\t\ttensorMetaManager := NewTensorMetaManager()\n\t\tbuilder := NewOperatorGraphBuilder(tensorMetaManager, info, \"alice\", time.Now())\n\t\t_, err = builder.Build(lp)\n\t\tr.NoError(err)\n\t}\n}\n\nfunc TestCheckFuncInputsType(t *testing.T) {\n\tr := require.New(t)\n\n\tnewTensorMeta := func(dtype *graph.DataType) *TensorMeta {\n\t\treturn &TensorMeta{DType: dtype}\n\t}\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tfuncName string\n\t\tinputs   []*TensorMeta\n\t\twantErr  bool\n\t\terrMsg   string\n\t}{\n\t\t// Boolean functions - valid cases\n\t\t{\"UnaryNot valid\", ast.UnaryNot, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL))}, false, \"\"},\n\t\t{\"LogicOr valid\", ast.LogicOr, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL))}, false, \"\"},\n\n\t\t// Boolean functions - invalid cases\n\t\t{\"UnaryNot invalid type\", ast.UnaryNot, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, true, \"expect bool input\"},\n\t\t{\"LogicAnd invalid type\", ast.LogicAnd, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, true, \"expect bool input\"},\n\n\t\t// String functions - valid cases\n\t\t{\"Lower valid\", ast.Lower, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, false, \"\"},\n\t\t{\"Upper valid\", ast.Upper, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, false, \"\"},\n\n\t\t// String functions - invalid cases\n\t\t{\"Trim invalid type\", ast.Trim, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, true, \"expect string input\"},\n\n\t\t// Numeric functions - valid cases\n\t\t{\"Sin valid int\", ast.Sin, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, false, \"\"},\n\t\t{\"Cos valid float\", ast.Cos, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64))}, false, \"\"},\n\t\t{\"Abs valid\", ast.Abs, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32))}, false, \"\"},\n\n\t\t// Numeric functions - invalid cases\n\t\t{\"Sin invalid string\", ast.Sin, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, true, \"expect numeric input\"},\n\t\t{\"Tan invalid bool\", ast.Tan, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL))}, true, \"expect numeric input\"},\n\n\t\t// Comparison/arithmetic functions - valid cases\n\t\t{\"LT valid int\", ast.LT, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, false, \"\"},\n\t\t{\"Plus valid float\", ast.Plus, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64))}, false, \"\"},\n\t\t{\"GE valid bool\", ast.GE, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL))}, false, \"\"},\n\n\t\t// Comparison/arithmetic functions - invalid cases\n\t\t{\"LT invalid string\", ast.LT, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, true, \"got string input\"},\n\t\t{\"Minus invalid string\", ast.Minus, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, true, \"got string input\"},\n\n\t\t// IntDiv/Mod - valid cases\n\t\t{\"IntDiv valid int\", ast.IntDiv, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, false, \"\"},\n\t\t{\"Mod valid datetime\", ast.Mod, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_DATETIME)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, false, \"\"},\n\t\t{\"IntDiv valid timestamp\", ast.IntDiv, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_TIMESTAMP)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, false, \"\"},\n\n\t\t// IntDiv/Mod - invalid cases\n\t\t{\"IntDiv invalid left\", ast.IntDiv, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, true, \"requires both left and right operands be int64-like\"},\n\t\t{\"Mod invalid right\", ast.Mod, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, true, \"requires both left and right operands be int64-like\"},\n\n\t\t// Case/If - valid cases\n\t\t{\"Case valid\", ast.Case, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, false, \"\"},\n\t\t{\"If valid\", ast.If, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64))}, false, \"\"},\n\n\t\t// Case/If - invalid cases\n\t\t{\"Case invalid condition string\", ast.Case, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, true, \"does not support string condition\"},\n\t\t{\"If inconsistent types\", ast.If, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64))}, true, \"all values must have the same type\"},\n\n\t\t// Ifnull - valid cases\n\t\t{\"Ifnull valid same type\", ast.Ifnull, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, false, \"\"},\n\t\t{\"Ifnull valid string\", ast.Ifnull, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, false, \"\"},\n\n\t\t// Ifnull - invalid cases\n\t\t{\"Ifnull different types\", ast.Ifnull, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64))}, true, \"both arguments must have the same type\"},\n\n\t\t// Unknown function - should pass\n\t\t{\"Unknown function\", \"unknown_func\", []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, false, \"\"},\n\t}\n\n\t// Run all test cases\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := checkFuncInputsType(tc.funcName, tc.inputs)\n\t\t\tif tc.wantErr {\n\t\t\t\tr.Error(err)\n\t\t\t\tr.Contains(err.Error(), tc.errMsg)\n\t\t\t} else {\n\t\t\t\tr.NoError(err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetOutputType(t *testing.T) {\n\tr := require.New(t)\n\n\tnewTensorMeta := func(dtype *graph.DataType) *TensorMeta {\n\t\treturn &TensorMeta{DType: dtype}\n\t}\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tfuncName string\n\t\tinputs   []*TensorMeta\n\t\twant     *graph.DataType\n\t\twantErr  bool\n\t\terrMsg   string\n\t}{\n\t\t// Boolean output functions\n\t\t{\"UnaryNot\", ast.UnaryNot, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL), false, \"\"},\n\t\t{\"IsNull\", ast.IsNull, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL), false, \"\"},\n\t\t{\"LT\", ast.LT, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL), false, \"\"},\n\t\t{\"LogicAnd\", ast.LogicAnd, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL), false, \"\"},\n\n\t\t// String output functions\n\t\t{\"Lower\", ast.Lower, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING), false, \"\"},\n\t\t{\"Upper\", ast.Upper, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING), false, \"\"},\n\t\t{\"Concat\", ast.Concat, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING), false, \"\"},\n\n\t\t// Greatest/Least - numeric\n\t\t{\"Greatest int\", ast.Greatest, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"Greatest float32\", ast.Greatest, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32), false, \"\"},\n\t\t{\"Greatest mixed numeric\", ast.Greatest, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64), false, \"\"},\n\t\t{\"Greatest timestamp\", ast.Greatest, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_TIMESTAMP)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_TIMESTAMP))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_TIMESTAMP), false, \"\"},\n\n\t\t// Greatest/Least - invalid cases\n\t\t{\"Greatest mixed timestamp_numeric\", ast.Greatest, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_TIMESTAMP)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_PrimitiveDataType_UNDEFINED), true, \"got wrong type\"},\n\t\t{\"Least mixed numeric_timestamp\", ast.Least, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_DATETIME))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_PrimitiveDataType_UNDEFINED), true, \"got wrong type\"},\n\t\t{\"Least mixed timestamp_numeric\", ast.Least, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_TIMESTAMP)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_PrimitiveDataType_UNDEFINED), true, \"got wrong type\"},\n\t\t// Case/If functions\n\t\t{\"Case\", ast.Case, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"If\", ast.If, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_BOOL)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64), false, \"\"},\n\n\t\t// Type preservation functions\n\t\t{\"Ifnull int\", ast.Ifnull, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"Ifnull string\", ast.Ifnull, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_STRING), false, \"\"},\n\t\t{\"Abs\", ast.Abs, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64), false, \"\"},\n\t\t{\"Coalesce int\", ast.Coalesce, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"Coalesce float32\", ast.Coalesce, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64), false, \"\"},\n\t\t// Float64 output functions\n\t\t{\"Sin\", ast.Sin, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64), false, \"\"},\n\t\t{\"Cos\", ast.Cos, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64), false, \"\"},\n\t\t{\"Div\", ast.Div, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64), false, \"\"},\n\t\t{\"Atan2\", ast.Atan2, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64), false, \"\"},\n\n\t\t// Int64 output functions\n\t\t{\"Ceil\", ast.Ceil, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"Floor\", ast.Floor, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"IntDiv\", ast.IntDiv, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"Mod\", ast.Mod, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"DateDiff\", ast.DateDiff, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_DATETIME)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_DATETIME))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\n\t\t// Plus/Minus with datetime\n\t\t{\"Plus int\", ast.Plus, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"Minus int\", ast.Minus, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"Minus datetime\", ast.Minus, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_DATETIME)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_DATETIME))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"Minus timestamp\", ast.Minus, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_TIMESTAMP)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_TIMESTAMP))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\n\t\t// Mul/Pow\n\t\t{\"Mul int\", ast.Mul, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64), false, \"\"},\n\t\t{\"Pow float32\", ast.Pow, []*TensorMeta{newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32)), newTensorMeta(graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT32))}, graph.NewPrimitiveDataType(scql.PrimitiveDataType_FLOAT64), false, \"\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tgot, err := getOutputType(tc.funcName, tc.inputs)\n\t\t\tif tc.wantErr {\n\t\t\t\tr.Error(err)\n\t\t\t\tr.Contains(err.Error(), tc.errMsg)\n\t\t\t} else {\n\t\t\t\tr.NoError(err)\n\t\t\t\tr.True(tc.want.Equal(got))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCheckArgsNum(t *testing.T) {\n\tr := require.New(t)\n\n\tnewTensorMeta := func() *TensorMeta {\n\t\treturn &TensorMeta{DType: graph.NewPrimitiveDataType(scql.PrimitiveDataType_INT64)}\n\t}\n\n\tnewConst := func(value interface{}) *expression.Constant {\n\t\treturn &expression.Constant{Value: types.NewDatum(value)}\n\t}\n\n\ttestCases := []struct {\n\t\tname        string\n\t\tfuncName    string\n\t\tinputs      []*TensorMeta\n\t\tconstParams []*expression.Constant\n\t\twantErr     bool\n\t\terrMsg      string\n\t}{\n\t\t// Invalid inputs number\n\t\t{\"no inputs\", \"sin\", []*TensorMeta{}, []*expression.Constant{}, true, \"expects at least 1 input tensor\"},\n\t\t// Unsupported function\n\t\t{\"unsupported function\", \"unknown_func\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{}, true, \"unsupported function\"},\n\n\t\t// Fixed argument count functions\n\t\t{\"sin valid\", \"sin\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"sin invalid count\", \"sin\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, true, \"expects 1 arguments\"},\n\t\t{\"cos valid\", \"cos\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"abs valid\", \"abs\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\n\t\t// Two argument functions\n\t\t{\"plus valid\", \"plus\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"plus invalid\", \"plus\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{}, true, \"expects 2 arguments\"},\n\t\t{\"minus valid\", \"minus\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"lt valid\", \"lt\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\n\t\t// Three argument functions\n\t\t{\"case valid\", \"case\", []*TensorMeta{newTensorMeta(), newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"case invalid even\", \"case\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, true, \"expects odd number of arguments\"},\n\t\t{\"case valid 5 args\", \"case\", []*TensorMeta{newTensorMeta(), newTensorMeta(), newTensorMeta(), newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\n\t\t// Substr/Substring special cases\n\t\t{\"substr valid 2 args\", \"substr\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{newConst(1)}, false, \"\"},\n\t\t{\"substr valid 3 args\", \"substr\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{newConst(1), newConst(5)}, false, \"\"},\n\t\t{\"substr invalid tensor count\", \"substr\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{newConst(1)}, true, \"substr expects 1 arguments, but got 2\"},\n\t\t{\"substr invalid const count\", \"substr\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{newConst(1), newConst(5), newConst(10)}, true, \"expects 1 or 2 constant parameters\"},\n\t\t{\"substring valid\", \"substring\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{newConst(1), newConst(5)}, false, \"\"},\n\n\t\t// GeoDist special cases\n\t\t{\"geodist valid 4 args\", \"geodist\", []*TensorMeta{newTensorMeta(), newTensorMeta(), newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"geodist valid 5 args\", \"geodist\", []*TensorMeta{newTensorMeta(), newTensorMeta(), newTensorMeta(), newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"geodist invalid 3 args\", \"geodist\", []*TensorMeta{newTensorMeta(), newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, true, \"expects 4 or 5 arguments\"},\n\t\t{\"geodist invalid 6 args\", \"geodist\", []*TensorMeta{newTensorMeta(), newTensorMeta(), newTensorMeta(), newTensorMeta(), newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, true, \"expects 4 or 5 arguments\"},\n\n\t\t// Variadic functions\n\t\t{\"greatest valid 2 args\", \"greatest\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"greatest valid 3 args\", \"greatest\", []*TensorMeta{newTensorMeta(), newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"least valid 2 args\", \"least\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"coalesce valid 2 args\", \"coalesce\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"concat valid 2 args\", \"concat\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"concat valid 3 args\", \"concat\", []*TensorMeta{newTensorMeta(), newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\n\t\t// Single argument functions\n\t\t{\"ceil valid\", \"ceil\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"floor valid\", \"floor\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"exp valid\", \"exp\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"ln valid\", \"ln\", []*TensorMeta{newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\n\t\t// Two argument functions with different counts\n\t\t{\"atan2 valid\", \"atan2\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"pow valid\", \"pow\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t\t{\"mod valid\", \"mod\", []*TensorMeta{newTensorMeta(), newTensorMeta()}, []*expression.Constant{}, false, \"\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := checkArgsNum(tc.funcName, tc.inputs, tc.constParams)\n\t\t\tif tc.wantErr {\n\t\t\t\tr.Error(err)\n\t\t\t\tr.Contains(err.Error(), tc.errMsg)\n\t\t\t} else {\n\t\t\t\tr.NoError(err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/operator_graph_pass.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\t\"sort\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\tpb \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// OperatorGraphPass builds operator graph from logical plan\ntype OperatorGraphPass struct{}\n\n// NewOperatorGraphPass creates a new operator graph pass\nfunc NewOperatorGraphPass() *OperatorGraphPass {\n\treturn &OperatorGraphPass{}\n}\n\n// Name returns the pass name\nfunc (p *OperatorGraphPass) Name() string {\n\treturn \"OperatorGraphPass\"\n}\n\n// Run builds operator graph and related components\nfunc (p *OperatorGraphPass) Run(c *CompileContext) error {\n\t// 1. Build engines info from catalog\n\t// TODO: support issuerAsParticipant\n\tenginesInfo, err := buildEnginesInfoFromCatalog(\n\t\tc.LogicalPlan,\n\t\tc.Request.GetCatalog(),\n\t\tc.Request.GetDb(),\n\t\tc.Request.GetIssuer().GetCode(),\n\t\ttrue,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build engines info: %v\", err)\n\t}\n\tc.EnginesInfo = enginesInfo\n\n\t// 2. Create tensor meta manager\n\ttensorMetaManager := NewTensorMetaManager()\n\tc.TensorMetaManager = tensorMetaManager\n\n\t// 3. Build operator graph\n\toperatorGraphBuilder := NewOperatorGraphBuilder(\n\t\ttensorMetaManager,\n\t\tenginesInfo,\n\t\tc.Request.GetIssuer().GetCode(),\n\t\tc.Request.GetIssueTime().AsTime(),\n\t)\n\toperatorGraph, err := operatorGraphBuilder.Build(c.LogicalPlan)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build operator graph: %v\", err)\n\t}\n\tlogrus.Debugf(\"operator graph: %s\", operatorGraph)\n\tc.OperatorGraph = operatorGraph\n\n\t// 4. Get and store involved parties (to avoid re-creating builder later)\n\tinvolvedParties, err := operatorGraphBuilder.GetInvolvedParties(c.LogicalPlan)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get involved parties: %v\", err)\n\t}\n\tc.InvolvedParties = involvedParties\n\n\t// TODO: Add operator graph optimizer here in future\n\n\treturn nil\n}\n\n// collectDataSourceNodes recursively collects all DataSource nodes from a logical plan\nfunc collectDataSourceNodes(lp core.LogicalPlan) []*core.DataSource {\n\tvar result []*core.DataSource\n\tfor _, child := range lp.Children() {\n\t\tdsList := collectDataSourceNodes(child)\n\t\tresult = append(result, dsList...)\n\t}\n\n\tif len(lp.Children()) > 0 {\n\t\treturn result\n\t}\n\n\tif ds, ok := lp.(*core.DataSource); ok {\n\t\treturn []*core.DataSource{ds}\n\t}\n\treturn nil\n}\n\n// buildEnginesInfoFromCatalog builds EnginesInfo from catalog and logical plan\nfunc buildEnginesInfoFromCatalog(lp core.LogicalPlan, catalog *pb.Catalog, currentDb string, queryIssuer string, issuerAsParticipant bool) (*graph.EnginesInfo, error) {\n\t// Construct catalog map\n\tcatalogMap := make(map[string]*pb.TableEntry)\n\tfor _, table := range catalog.GetTables() {\n\t\ttn := table.GetTableName()\n\t\tif _, exists := catalogMap[tn]; exists {\n\t\t\treturn nil, fmt.Errorf(\"duplicate table exists in catalog\")\n\t\t}\n\t\tcatalogMap[tn] = table\n\t}\n\n\tparty2Tables := make(map[string][]core.DbTable)\n\ttableToRefs := make(map[core.DbTable]core.DbTable)\n\n\t// Collect data source nodes\n\tdsList := collectDataSourceNodes(lp)\n\tif len(dsList) == 0 {\n\t\treturn nil, fmt.Errorf(\"no data source in query\")\n\t}\n\n\tfor _, ds := range dsList {\n\t\tdbName := ds.DBName.String()\n\t\ttblName := ds.TableInfo().Name.String()\n\n\t\tif len(dbName) == 0 {\n\t\t\tdbName = currentDb\n\t\t}\n\t\tdbTable := core.NewDbTable(dbName, tblName)\n\t\ttn := dbTable.String()\n\n\t\ttblEntry, exists := catalogMap[tn]\n\t\tif !exists {\n\t\t\treturn nil, fmt.Errorf(\"table `%s` not found in catalog\", tn)\n\t\t}\n\n\t\ttblOwner := tblEntry.GetOwner().GetCode()\n\t\tparty2Tables[tblOwner] = append(party2Tables[tblOwner], dbTable)\n\n\t\trefTblName := tblEntry.GetRefTable()\n\t\tif len(refTblName) == 0 {\n\t\t\trefTblName = tblEntry.GetTableName()\n\t\t}\n\t\trefDbTable, err := core.NewDbTableFromString(refTblName)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create DbTable from %s: %+v\", tblEntry.GetRefTable(), err)\n\t\t}\n\n\t\terr = refDbTable.SetDBTypeFromString(tblEntry.GetDbType(), tblEntry.TableName)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"buildEnginesInfoFromCatalog: %v\", err)\n\t\t}\n\n\t\ttableToRefs[dbTable] = refDbTable\n\t}\n\n\tparties := make([]*graph.Participant, 0)\n\tfor party := range party2Tables {\n\t\tparties = append(parties, &graph.Participant{\n\t\t\tPartyCode: party,\n\t\t})\n\t}\n\n\t// Add query issuer if not already present and should participate\n\tif _, exists := party2Tables[queryIssuer]; !exists {\n\t\tif issuerAsParticipant {\n\t\t\tparties = append(parties, &graph.Participant{\n\t\t\t\tPartyCode: queryIssuer,\n\t\t\t})\n\t\t}\n\t}\n\n\t// Handle INTO clause party codes\n\tvar intoPartyCodes []string\n\tif lp.IntoOpt() != nil {\n\t\tfor _, partyFile := range lp.IntoOpt().Opt.PartyFiles {\n\t\t\tif partyFile.PartyCode == \"\" {\n\t\t\t\tintoPartyCodes = append(intoPartyCodes, queryIssuer)\n\t\t\t} else {\n\t\t\t\tintoPartyCodes = append(intoPartyCodes, partyFile.PartyCode)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add into party codes if specified\n\tif len(intoPartyCodes) > 0 {\n\t\tfor _, partyCode := range intoPartyCodes {\n\t\t\tparties = append(parties, &graph.Participant{\n\t\t\t\tPartyCode: partyCode,\n\t\t\t})\n\t\t}\n\t}\n\n\t// Sort parties for deterministic behavior\n\tsort.Slice(parties, func(i, j int) bool {\n\t\treturn parties[i].PartyCode < parties[j].PartyCode\n\t})\n\tparties = slices.CompactFunc(parties, func(i, j *graph.Participant) bool {\n\t\treturn i.PartyCode == j.PartyCode\n\t})\n\n\tpartyInfo := graph.NewPartyInfo(parties)\n\tengineInfo := graph.NewEnginesInfo(partyInfo, party2Tables)\n\tengineInfo.UpdateTableToRefs(tableToRefs)\n\n\treturn engineInfo, nil\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/parser_pass.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/constant\"\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\tpb \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/variable\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// ParserPass handles SQL parsing and initial setup\ntype ParserPass struct{}\n\n// NewParserPass creates a new parser pass\nfunc NewParserPass() *ParserPass {\n\treturn &ParserPass{}\n}\n\n// Name returns the pass name\nfunc (p *ParserPass) Name() string {\n\treturn \"ParserPass\"\n}\n\n// Run builds InfoSchema, parses SQL, and processes variables\nfunc (p *ParserPass) Run(c *CompileContext) error {\n\t// 1. Build InfoSchema from catalog\n\tis, err := BuildInfoSchemaFromCatalogProto(c.Request.GetCatalog())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build info schema: %v\", err)\n\t}\n\tc.InfoSchema = is\n\n\t// 2. Parse SQL\n\tparser := parser.New()\n\tstmts, _, err := parser.Parse(c.Request.GetQuery(), \"\", \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse SQL: %v\", err)\n\t}\n\tif len(stmts) == 0 {\n\t\treturn fmt.Errorf(\"no statement found in SQL\")\n\t}\n\tif len(stmts) > 1 {\n\t\treturn fmt.Errorf(\"only support one query one time, but got %d queries\", len(stmts))\n\t}\n\n\t// 3. Process variables and placeholders\n\tnode, err := processVariablesAndPlaceholders(stmts[0], c.Request.GetVariables(), c.Request.GetPlaceholders())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to process variables and placeholders: %v\", err)\n\t}\n\n\t// Type assertion to convert ast.Node to ast.StmtNode\n\tstmt, ok := node.(ast.StmtNode)\n\tif !ok {\n\t\treturn fmt.Errorf(\"processed node is not a statement\")\n\t}\n\n\t// Store result in context\n\tc.AST = stmt\n\n\treturn nil\n}\n\nfunc createDatumFromVariable(dataType string, variable *pb.Variable) (*types.Datum, error) {\n\tif variable == nil {\n\t\treturn nil, fmt.Errorf(\"variable is nil\")\n\t}\n\t// TODO: @xiaoyuan support bool type\n\tswitch {\n\tcase constant.StringTypeAlias[dataType]:\n\t\td := types.NewStringDatum(variable.StringData)\n\t\treturn &d, nil\n\tcase constant.IntegerTypeAlias[dataType]:\n\t\td := types.NewIntDatum(variable.Int64Data)\n\t\treturn &d, nil\n\tcase constant.FloatTypeAlias[dataType], constant.DoubleTypeAlias[dataType]:\n\t\td := types.NewFloat32Datum(variable.FloatData)\n\t\treturn &d, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown type in schema: %s\", dataType)\n\t}\n}\n\n// processVariablesAndPlaceholders processes variables and placeholders in SQL statement\nfunc processVariablesAndPlaceholders(stmt ast.Node, variables []*pb.Variable, placeholders *pb.Placeholders) (ast.Node, error) {\n\tif variables == nil {\n\t\treturn stmt, nil\n\t}\n\n\tif len(variables) != len(placeholders.Placeholders) {\n\t\treturn nil, fmt.Errorf(\"processVariablesAndPlaceholders: variables {%+v} in request are not related to placeholders {%+v}\", variables, placeholders.Placeholders)\n\t}\n\n\tpreparedParams := variable.PreparedParams{}\n\tplaceholderMap := make(map[string]*pb.Placeholder, len(placeholders.Placeholders))\n\tfor _, v := range placeholders.Placeholders {\n\t\tplaceholderMap[v.Name] = v\n\t}\n\tif len(placeholderMap) != len(placeholders.Placeholders) {\n\t\treturn nil, fmt.Errorf(\"processVariablesAndPlaceholders: duplicate placeholder name in placeholders {%+v}\", placeholders.Placeholders)\n\t}\n\n\tfor _, v := range variables {\n\t\tif placeholder, ok := placeholderMap[v.Name]; ok {\n\t\t\td, err := createDatumFromVariable(placeholder.DataType, v)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tpreparedParams[v.Name] = d\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"processVariablesAndPlaceholders: missing variable for placeholder %s\", v.Name)\n\t\t}\n\t}\n\n\tparamVisitor := core.NewPreparedParamsVisitor(&preparedParams)\n\tprocessedStmt, ok := stmt.Accept(paramVisitor)\n\tif !ok || paramVisitor.Error() != nil {\n\t\treturn nil, fmt.Errorf(\"failed to accept prepared params visitor: %s\", paramVisitor.Error())\n\t}\n\n\treturn processedStmt, nil\n}\n\n// BuildInfoSchemaFromCatalogProto builds an InfoSchema from catalog proto\nfunc BuildInfoSchemaFromCatalogProto(catalog *pb.Catalog) (infoschema.InfoSchema, error) {\n\ttblInfoMap := make(map[string][]*model.TableInfo)\n\tfor i, tblEntry := range catalog.GetTables() {\n\t\tdbTable, err := core.NewDbTableFromString(tblEntry.GetTableName())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttblInfo := &model.TableInfo{\n\t\t\tID:          int64(i),\n\t\t\tTableId:     fmt.Sprint(i),\n\t\t\tName:        model.NewCIStr(dbTable.GetTableName()),\n\t\t\tColumns:     []*model.ColumnInfo{},\n\t\t\tIndices:     []*model.IndexInfo{},\n\t\t\tForeignKeys: []*model.FKInfo{},\n\t\t\tState:       model.StatePublic,\n\t\t\tPKIsHandle:  false,\n\t\t}\n\n\t\tif tblEntry.Owner != nil {\n\t\t\ttblInfo.PartyCode = tblEntry.Owner.Code\n\t\t}\n\n\t\tif tblEntry.GetIsView() {\n\t\t\ttblInfo.View = &model.ViewInfo{\n\t\t\t\tAlgorithm:  model.AlgorithmMerge,\n\t\t\t\tSelectStmt: tblEntry.SelectString,\n\t\t\t}\n\t\t}\n\t\t// sort columns by ordinal position\n\t\tsort.Slice(tblEntry.Columns, func(i, j int) bool {\n\t\t\treturn tblEntry.Columns[i].OrdinalPosition < tblEntry.Columns[j].OrdinalPosition\n\t\t})\n\n\t\tfor idx, col := range tblEntry.GetColumns() {\n\t\t\tcolTp := strings.ToLower(col.GetType())\n\t\t\tdefaultVal, err := infoschema.TypeDefaultValue(colTp)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfieldTp, err := infoschema.TypeConversion(colTp)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tcolInfo := &model.ColumnInfo{\n\t\t\t\tID:                 int64(idx),\n\t\t\t\tName:               model.NewCIStr(col.GetName()),\n\t\t\t\tOffset:             idx,\n\t\t\t\tOriginDefaultValue: defaultVal,\n\t\t\t\tDefaultValue:       defaultVal,\n\t\t\t\tDefaultValueBit:    []byte{},\n\t\t\t\tDependences:        map[string]struct{}{},\n\t\t\t\tFieldType:          fieldTp,\n\t\t\t\tState:              model.StatePublic,\n\t\t\t}\n\t\t\ttblInfo.Columns = append(tblInfo.Columns, colInfo)\n\t\t}\n\t\ttblInfoMap[dbTable.GetDbName()] = append(tblInfoMap[dbTable.GetDbName()], tblInfo)\n\t}\n\treturn infoschema.MockInfoSchema(tblInfoMap), nil\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/reverse_inference.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\nfunc (n *OperatorResult) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\treturn nil, fmt.Errorf(\"OperatorResult is not any tensor's source node. Thus, we nerver need to call ReverseInfer on it\")\n}\n\nfunc (n *OperatorRunSQL) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\t// RunSQL node does not have any inputs, so we do not need to perform reverse inference\n\treturn nil, nil\n}\n\nfunc (n *OperatorDataSource) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\treturn nil, fmt.Errorf(\"OperatorDataSource should only exist in OperatorRunSQL's subPlanNodes. Thus, we never need to call ReverseInfer on it\")\n}\n\nfunc (n *OperatorEQJoin) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\t// can not perform reverse inference on EQJoin\n\treturn nil, nil\n}\n\nfunc (n *OperatorCrossJoin) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\tupdatedTensors := make([]*TensorMeta, 0)\n\n\tfor idx, output := range n.leftOutputs {\n\t\tinput := n.leftInputs[idx]\n\t\tif vs.vt.TryUpdateVisibility(input, vs.vt.TensorVisibleParties(output)) {\n\t\t\tupdatedTensors = append(updatedTensors, input)\n\t\t}\n\t}\n\tfor idx, output := range n.rightOutputs {\n\t\tinput := n.rightInputs[idx]\n\t\tif vs.vt.TryUpdateVisibility(input, vs.vt.TensorVisibleParties(output)) {\n\t\t\tupdatedTensors = append(updatedTensors, input)\n\t\t}\n\t}\n\n\treturn updatedTensors, nil\n}\n\nfunc (n *OperatorLimit) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\t// can not perform reverse inference on Limit\n\treturn nil, nil\n}\n\nfunc (n *OperatorFilter) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\t// can not perform reverse inference on Filter\n\treturn nil, nil\n}\n\nfunc (n *OperatorBroadcastTo) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\t// no need to perform reverse inference on Broadcast\n\t// it's input scalar tensor always has public visibility\n\treturn nil, nil\n}\n\nfunc (n *OperatorConcat) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\tupdatedTensors := make([]*TensorMeta, 0)\n\n\tvis := vs.vt.TensorVisibleParties(n.output)\n\tfor _, input := range n.inputs {\n\t\tif vs.vt.TryUpdateVisibility(input, vis) {\n\t\t\tupdatedTensors = append(updatedTensors, input)\n\t\t}\n\t}\n\n\treturn updatedTensors, nil\n}\n\nfunc (n *OperatorSort) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\tupdatedTensors := make([]*TensorMeta, 0)\n\n\tfor idx, output := range n.outputs {\n\t\tinput := n.payloads[idx]\n\t\tif vs.vt.TryUpdateVisibility(input, vs.vt.TensorVisibleParties(output)) {\n\t\t\tupdatedTensors = append(updatedTensors, input)\n\t\t}\n\t}\n\n\treturn updatedTensors, nil\n}\n\nfunc (n *OperatorReduce) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\t// can not perform reverse inference on Reduce\n\treturn nil, nil\n}\n\nfunc (n *OperatorGroupAgg) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\t// can not perform reverse inference on GroupAgg\n\t// here we just fill the keysVisAfterAgg, which will be useful when resolving kernels\n\tisGroupKey := func(t *TensorMeta) bool {\n\t\tfor _, key := range n.groupKeys {\n\t\t\tif key.ID == t.ID {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n\n\tovt := vs.NewOverlayVisibilityTable()\n\tfor idx, arg := range n.aggArgs {\n\t\taggFunc := n.aggFuncsWithArg[idx]\n\t\tif aggFunc.Name != ast.AggFuncFirstRow {\n\t\t\tcontinue\n\t\t}\n\n\t\tif isGroupKey(arg) {\n\t\t\toutput := n.argFuncOutputs[idx]\n\t\t\tovt.UpdateVisibility(arg, vs.vt.TensorVisibleParties(output))\n\t\t}\n\t}\n\tn.keysVisAfterAgg = ovt\n\n\treturn nil, nil\n}\n\nfunc (n *OperatorWindow) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\tupdatedTensors := make([]*TensorMeta, 0)\n\n\tfor idx, output := range n.payloadOutputs {\n\t\tinput := n.payloads[idx]\n\t\tif vs.vt.TryUpdateVisibility(input, vs.vt.TensorVisibleParties(output)) {\n\t\t\tupdatedTensors = append(updatedTensors, input)\n\t\t}\n\t}\n\n\treturn updatedTensors, nil\n}\n\nfunc (n *OperatorIn) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\t// can not perform reverse inference on In\n\treturn nil, nil\n}\n\nfunc (n *OperatorConstant) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\t// no need to perform reverse inference on Constant\n\t// it's output tensor always has public visibility\n\treturn nil, nil\n}\n\nfunc (n *OperatorFunction) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\tupdatedTensors := make([]*TensorMeta, 0)\n\toutputVis := vs.vt.TensorVisibleParties(n.output)\n\tswitch n.funcName {\n\tcase ast.UnaryNot:\n\t\tif vs.vt.TryUpdateVisibility(n.inputs[0], outputVis) {\n\t\t\tupdatedTensors = append(updatedTensors, n.inputs[0])\n\t\t}\n\tcase ast.Lower, ast.Upper, ast.Trim:\n\t\t// question: can we update visibility of n.inputs[0] here?\n\t\tif vs.vt.TryUpdateVisibility(n.inputs[0], outputVis) {\n\t\t\tupdatedTensors = append(updatedTensors, n.inputs[0])\n\t\t}\n\tcase ast.Abs, ast.Floor, ast.Ceil, ast.Round:\n\t\t// question: can we update visibility of n.inputs[0] here?\n\t\t// if vs.vt.TryUpdateVisibility(n.inputs[0], outputVis) {\n\t\t// \tupdatedTensors = append(updatedTensors, n.inputs[0])\n\t\t// }\n\tcase ast.Ln, ast.Log10, ast.Log2, ast.Exp, ast.Sqrt:\n\t\tif vs.vt.TryUpdateVisibility(n.inputs[0], outputVis) {\n\t\t\tupdatedTensors = append(updatedTensors, n.inputs[0])\n\t\t}\n\tcase ast.Cos, ast.Sin, ast.Tan, ast.Acos, ast.Asin, ast.Atan:\n\t\t// question: can we update visibility of n.inputs[0] here?\n\t\t// if vs.vt.TryUpdateVisibility(n.inputs[0], outputVis) {\n\t\t// \tupdatedTensors = append(updatedTensors, n.inputs[0])\n\t\t// }\n\tcase ast.Pow, ast.IntDiv:\n\t\t// question: can we update visibility of inputs here?\n\tcase ast.Plus, ast.Minus, ast.Mul, ast.Div, ast.AddDate, ast.SubDate, ast.DateDiff:\n\t\toldLhsVis := vs.vt.TensorVisibleParties(n.inputs[0])\n\t\toldRhsVis := vs.vt.TensorVisibleParties(n.inputs[1])\n\t\t// infer one input visibility from the visibility of the other input and the output\n\t\tnewLhsVis := VPIntersection(oldRhsVis, outputVis)\n\t\tnewRhsVis := VPIntersection(oldLhsVis, outputVis)\n\n\t\tif vs.vt.TryUpdateVisibility(n.inputs[0], newLhsVis) {\n\t\t\tupdatedTensors = append(updatedTensors, n.inputs[0])\n\t\t}\n\t\tif vs.vt.TryUpdateVisibility(n.inputs[1], newRhsVis) {\n\t\t\tupdatedTensors = append(updatedTensors, n.inputs[1])\n\t\t}\n\t}\n\treturn updatedTensors, nil\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/reverse_inference_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\nfunc TestReverseInferenceOperatorResult(t *testing.T) {\n\tassert := assert.New(t)\n\n\tnode := &OperatorResult{}\n\tvs := &VisibilitySolver{vt: NewVisibilityTable([]string{})}\n\n\ttensors, err := node.ReverseInfer(vs)\n\tassert.Error(err)\n\tassert.Contains(err.Error(), \"OperatorResult is not any tensor's source node\")\n\tassert.Nil(tensors)\n}\n\nfunc TestReverseInferenceOperatorDataSource(t *testing.T) {\n\tassert := assert.New(t)\n\n\tnode := &OperatorDataSource{}\n\tvs := &VisibilitySolver{vt: NewVisibilityTable([]string{})}\n\n\ttensors, err := node.ReverseInfer(vs)\n\tassert.Error(err)\n\tassert.Contains(err.Error(), \"OperatorDataSource should only exist in OperatorRunSQL's subPlanNodes\")\n\tassert.Nil(tensors)\n}\n\nfunc TestReverseInferenceSimpleNodes(t *testing.T) {\n\tassert := assert.New(t)\n\n\ttestCases := []struct {\n\t\tname string\n\t\tnode interface {\n\t\t\tReverseInfer(*VisibilitySolver) ([]*TensorMeta, error)\n\t\t}\n\t}{\n\t\t{name: \"OperatorRunSQL\", node: &OperatorRunSQL{}},\n\t\t{name: \"OperatorEQJoin\", node: &OperatorEQJoin{}},\n\t\t{name: \"OperatorLimit\", node: &OperatorLimit{}},\n\t\t{name: \"OperatorFilter\", node: &OperatorFilter{}},\n\t\t{name: \"OperatorBroadcastTo\", node: &OperatorBroadcastTo{}},\n\t\t{name: \"OperatorReduce\", node: &OperatorReduce{}},\n\t\t{name: \"OperatorGroupAgg\", node: &OperatorGroupAgg{}},\n\t\t{name: \"OperatorIn\", node: &OperatorIn{}},\n\t\t{name: \"OperatorConstant\", node: &OperatorConstant{}},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tvs := &VisibilitySolver{vt: NewVisibilityTable([]string{})}\n\t\t\ttensors, err := tc.node.ReverseInfer(vs)\n\t\t\tassert.NoError(err)\n\t\t\tassert.Nil(tensors)\n\t\t})\n\t}\n}\n\nfunc TestReverseInferenceCrossJoin(t *testing.T) {\n\tassert := assert.New(t)\n\n\tvt := NewVisibilityTable([]string{\"party1\", \"party2\", \"party3\"})\n\n\t// Create tensors with proper IDs\n\tleftInput1 := &TensorMeta{ID: 1}\n\tleftOutput1 := &TensorMeta{ID: 2}\n\tleftInput2 := &TensorMeta{ID: 3}\n\tleftOutput2 := &TensorMeta{ID: 4}\n\n\trightInput1 := &TensorMeta{ID: 5}\n\trightOutput1 := &TensorMeta{ID: 6}\n\trightInput2 := &TensorMeta{ID: 7}\n\trightOutput2 := &TensorMeta{ID: 8}\n\n\t// Set initial visibilities\n\tvt.UpdateVisibility(leftOutput1, NewVisibleParties([]string{\"party1\"}))\n\tvt.UpdateVisibility(leftOutput2, NewVisibleParties([]string{\"party2\"}))\n\tvt.UpdateVisibility(rightOutput1, NewVisibleParties([]string{\"party1\"}))\n\tvt.UpdateVisibility(rightOutput2, NewVisibleParties([]string{\"party3\"}))\n\n\tnode := &OperatorCrossJoin{\n\t\tleftInputs:   []*TensorMeta{leftInput1, leftInput2},\n\t\tleftOutputs:  []*TensorMeta{leftOutput1, leftOutput2},\n\t\trightInputs:  []*TensorMeta{rightInput1, rightInput2},\n\t\trightOutputs: []*TensorMeta{rightOutput1, rightOutput2},\n\t}\n\n\tvs := &VisibilitySolver{vt: vt}\n\ttensors, err := node.ReverseInfer(vs)\n\n\tassert.NoError(err)\n\tassert.Len(tensors, 4)\n\n\tassert.Equal([]string{\"party1\"}, vt.TensorVisibleParties(leftInput1).GetParties())\n\tassert.Equal([]string{\"party2\"}, vt.TensorVisibleParties(leftInput2).GetParties())\n\tassert.Equal([]string{\"party1\"}, vt.TensorVisibleParties(rightInput1).GetParties())\n\tassert.Equal([]string{\"party3\"}, vt.TensorVisibleParties(rightInput2).GetParties())\n}\n\nfunc TestReverseInferenceConcat(t *testing.T) {\n\tassert := assert.New(t)\n\n\tvt := NewVisibilityTable([]string{\"party1\", \"party2\"})\n\n\toutput := &TensorMeta{ID: 1}\n\tinput1 := &TensorMeta{ID: 2}\n\tinput2 := &TensorMeta{ID: 3}\n\tinput3 := &TensorMeta{ID: 4}\n\n\tvt.UpdateVisibility(output, NewVisibleParties([]string{\"party1\"}))\n\n\tnode := &OperatorConcat{\n\t\toutput: output,\n\t\tinputs: []*TensorMeta{input1, input2, input3},\n\t}\n\n\tvs := &VisibilitySolver{vt: vt}\n\ttensors, err := node.ReverseInfer(vs)\n\n\tassert.NoError(err)\n\tassert.Len(tensors, 3)\n\n\texpectedParties := []string{\"party1\"}\n\tassert.Equal(expectedParties, vt.TensorVisibleParties(input1).GetParties())\n\tassert.Equal(expectedParties, vt.TensorVisibleParties(input2).GetParties())\n\tassert.Equal(expectedParties, vt.TensorVisibleParties(input3).GetParties())\n}\n\nfunc TestReverseInferenceSort(t *testing.T) {\n\tassert := assert.New(t)\n\n\tvt := NewVisibilityTable([]string{\"party1\", \"party2\"})\n\n\toutput1 := &TensorMeta{ID: 1}\n\tpayload1 := &TensorMeta{ID: 2}\n\toutput2 := &TensorMeta{ID: 3}\n\tpayload2 := &TensorMeta{ID: 4}\n\n\tvt.UpdateVisibility(output1, NewVisibleParties([]string{\"party1\"}))\n\tvt.UpdateVisibility(output2, NewVisibleParties([]string{\"party2\"}))\n\n\tnode := &OperatorSort{\n\t\toutputs:  []*TensorMeta{output1, output2},\n\t\tpayloads: []*TensorMeta{payload1, payload2},\n\t}\n\n\tvs := &VisibilitySolver{vt: vt}\n\ttensors, err := node.ReverseInfer(vs)\n\n\tassert.NoError(err)\n\tassert.Len(tensors, 2)\n\n\tassert.Equal([]string{\"party1\"}, vt.TensorVisibleParties(payload1).GetParties())\n\tassert.Equal([]string{\"party2\"}, vt.TensorVisibleParties(payload2).GetParties())\n}\n\nfunc TestReverseInferenceRankWindow(t *testing.T) {\n\tassert := assert.New(t)\n\n\tvt := NewVisibilityTable([]string{\"party1\", \"party2\"})\n\n\toutput1 := &TensorMeta{ID: 1}\n\tpayload1 := &TensorMeta{ID: 2}\n\toutput2 := &TensorMeta{ID: 3}\n\tpayload2 := &TensorMeta{ID: 4}\n\n\tvt.UpdateVisibility(output1, NewVisibleParties([]string{\"party1\"}))\n\tvt.UpdateVisibility(output2, NewVisibleParties([]string{\"party2\"}))\n\n\tnode := &OperatorWindow{\n\t\tpayloadOutputs: []*TensorMeta{output1, output2},\n\t\tpayloads:       []*TensorMeta{payload1, payload2},\n\t}\n\n\tvs := &VisibilitySolver{vt: vt}\n\ttensors, err := node.ReverseInfer(vs)\n\n\tassert.NoError(err)\n\tassert.Len(tensors, 2)\n\n\tassert.Equal([]string{\"party1\"}, vt.TensorVisibleParties(payload1).GetParties())\n\tassert.Equal([]string{\"party2\"}, vt.TensorVisibleParties(payload2).GetParties())\n}\n\nfunc TestReverseInferenceFunctionUnaryNot(t *testing.T) {\n\tassert := assert.New(t)\n\n\tvt := NewVisibilityTable([]string{\"party1\", \"party2\"})\n\n\toutput := &TensorMeta{ID: 100}\n\tinput := &TensorMeta{ID: 101}\n\n\tvt.UpdateVisibility(output, NewVisibleParties([]string{\"party1\"}))\n\tvt.UpdateVisibility(input, NewVisibleParties([]string{\"party2\"}))\n\n\tnode := &OperatorFunction{\n\t\tfuncName: ast.UnaryNot,\n\t\tinputs:   []*TensorMeta{input},\n\t\toutput:   output,\n\t}\n\n\tvs := &VisibilitySolver{vt: vt}\n\ttensors, err := node.ReverseInfer(vs)\n\n\tassert.NoError(err)\n\t// One tensor's visiblity was updated\n\tassert.Len(tensors, 1)\n\t// Party1 has been added to input's visible parties\n\tassert.Equal([]string{\"party1\", \"party2\"}, vt.TensorVisibleParties(input).GetParties())\n}\n\nfunc TestReverseInferenceFunctionStringOps(t *testing.T) {\n\tassert := assert.New(t)\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tfuncName string\n\t}{\n\t\t{name: \"Lower\", funcName: ast.Lower},\n\t\t{name: \"Upper\", funcName: ast.Upper},\n\t\t{name: \"Trim\", funcName: ast.Trim},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tvt := NewVisibilityTable([]string{\"party1\", \"party2\"})\n\n\t\t\toutput := &TensorMeta{ID: 200}\n\t\t\tinput := &TensorMeta{ID: 201}\n\n\t\t\tvt.UpdateVisibility(output, NewVisibleParties([]string{\"party1\"}))\n\t\t\tvt.UpdateVisibility(input, NewVisibleParties([]string{\"party2\"}))\n\n\t\t\tnode := &OperatorFunction{\n\t\t\t\tfuncName: tc.funcName,\n\t\t\t\tinputs:   []*TensorMeta{input},\n\t\t\t\toutput:   output,\n\t\t\t}\n\n\t\t\tvs := &VisibilitySolver{vt: vt}\n\t\t\ttensors, err := node.ReverseInfer(vs)\n\n\t\t\tassert.NoError(err)\n\t\t\t// One tensor's visiblity was updated\n\t\t\tassert.Len(tensors, 1)\n\t\t\t// Party1 has been added to input's visible parties\n\t\t\tassert.Equal([]string{\"party1\", \"party2\"}, vt.TensorVisibleParties(input).GetParties())\n\t\t})\n\t}\n}\n\nfunc TestReverseInferenceFunctionUnaryMathOps(t *testing.T) {\n\tassert := assert.New(t)\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tfuncName string\n\t}{\n\t\t{name: \"Ln\", funcName: ast.Ln},\n\t\t{name: \"Log10\", funcName: ast.Log10},\n\t\t{name: \"Log2\", funcName: ast.Log2},\n\t\t{name: \"Exp\", funcName: ast.Exp},\n\t\t{name: \"Sqrt\", funcName: ast.Sqrt},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tvt := NewVisibilityTable([]string{\"party1\", \"party2\"})\n\n\t\t\toutput := &TensorMeta{ID: 300}\n\t\t\tinput := &TensorMeta{ID: 301}\n\n\t\t\tvt.UpdateVisibility(output, NewVisibleParties([]string{\"party1\"}))\n\t\t\tvt.UpdateVisibility(input, NewVisibleParties([]string{\"party2\"}))\n\n\t\t\tnode := &OperatorFunction{\n\t\t\t\tfuncName: tc.funcName,\n\t\t\t\tinputs:   []*TensorMeta{input},\n\t\t\t\toutput:   output,\n\t\t\t}\n\n\t\t\tvs := &VisibilitySolver{vt: vt}\n\t\t\ttensors, err := node.ReverseInfer(vs)\n\n\t\t\tassert.NoError(err)\n\t\t\t// One tensor's visiblity was updated\n\t\t\tassert.Len(tensors, 1)\n\t\t\t// Party1 has been added to input's visible parties\n\t\t\tassert.Equal([]string{\"party1\", \"party2\"}, vt.TensorVisibleParties(input).GetParties())\n\t\t})\n\t}\n}\n\nfunc TestReverseInferenceFunctionBinaryOps(t *testing.T) {\n\tassert := assert.New(t)\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tfuncName string\n\t}{\n\t\t{name: \"Plus\", funcName: ast.Plus},\n\t\t{name: \"Minus\", funcName: ast.Minus},\n\t\t{name: \"Mul\", funcName: ast.Mul},\n\t\t{name: \"Div\", funcName: ast.Div},\n\t\t{name: \"AddDate\", funcName: ast.AddDate},\n\t\t{name: \"SubDate\", funcName: ast.SubDate},\n\t\t{name: \"DateDiff\", funcName: ast.DateDiff},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tvt := NewVisibilityTable([]string{\"party1\", \"party2\", \"party3\"})\n\n\t\t\toutput := &TensorMeta{ID: 400}\n\t\t\tinput1 := &TensorMeta{ID: 401}\n\t\t\tinput2 := &TensorMeta{ID: 402}\n\n\t\t\t// Set up scenario where intersection will produce updates\n\t\t\tvt.UpdateVisibility(output, NewVisibleParties([]string{\"party1\", \"party2\"}))\n\t\t\tvt.UpdateVisibility(input1, NewVisibleParties([]string{\"party2\", \"party3\"}))\n\t\t\tvt.UpdateVisibility(input2, NewVisibleParties([]string{\"party1\", \"party3\"}))\n\n\t\t\tnode := &OperatorFunction{\n\t\t\t\tfuncName: tc.funcName,\n\t\t\t\tinputs:   []*TensorMeta{input1, input2},\n\t\t\t\toutput:   output,\n\t\t\t}\n\n\t\t\tintersection1 := VPIntersection(vt.TensorVisibleParties(input2), vt.TensorVisibleParties(output))\n\t\t\tassert.Len(intersection1.GetParties(), 1)\n\t\t\tintersection2 := VPIntersection(vt.TensorVisibleParties(input1), vt.TensorVisibleParties(output))\n\t\t\tassert.Len(intersection2.GetParties(), 1)\n\n\t\t\tvs := &VisibilitySolver{vt: vt}\n\t\t\ttensors, err := node.ReverseInfer(vs)\n\n\t\t\tassert.NoError(err)\n\t\t\t// Two inputs' visiblity was updated\n\t\t\tassert.Len(tensors, 2)\n\n\t\t\t// Intersection has been added to input's visible parties\n\t\t\tassert.Contains(vt.TensorVisibleParties(input1).GetParties(), intersection1.GetParties()[0])\n\t\t\tassert.Contains(vt.TensorVisibleParties(input2).GetParties(), intersection2.GetParties()[0])\n\t\t})\n\t}\n}\n\nfunc TestReverseInferenceFunctionBinaryOpsNoUpdate(t *testing.T) {\n\tassert := assert.New(t)\n\n\tvt := NewVisibilityTable([]string{\"party1\", \"party2\", \"party3\"})\n\n\toutput := &TensorMeta{ID: 500}\n\tinput1 := &TensorMeta{ID: 501}\n\tinput2 := &TensorMeta{ID: 502}\n\n\t// Set up scenario where intersection will be empty (no updates)\n\tvt.UpdateVisibility(output, NewVisibleParties([]string{\"party1\"}))\n\tvt.UpdateVisibility(input1, NewVisibleParties([]string{\"party2\"}))\n\tvt.UpdateVisibility(input2, NewVisibleParties([]string{\"party3\"}))\n\n\tnode := &OperatorFunction{\n\t\tfuncName: ast.Plus,\n\t\tinputs:   []*TensorMeta{input1, input2},\n\t\toutput:   output,\n\t}\n\n\tvs := &VisibilitySolver{vt: vt}\n\ttensors, err := node.ReverseInfer(vs)\n\n\tassert.NoError(err)\n\tassert.Len(tensors, 0) // No updates since intersection is empty\n\n\t// Verify visibilities remain unchanged\n\tassert.Equal([]string{\"party2\"}, vt.TensorVisibleParties(input1).GetParties())\n\tassert.Equal([]string{\"party3\"}, vt.TensorVisibleParties(input2).GetParties())\n}\n\nfunc TestReverseInferenceFunctionCommentedCases(t *testing.T) {\n\tassert := assert.New(t)\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tfuncName string\n\t}{\n\t\t{name: \"Abs\", funcName: ast.Abs},\n\t\t{name: \"Floor\", funcName: ast.Floor},\n\t\t{name: \"Ceil\", funcName: ast.Ceil},\n\t\t{name: \"Round\", funcName: ast.Round},\n\t\t{name: \"Cos\", funcName: ast.Cos},\n\t\t{name: \"Sin\", funcName: ast.Sin},\n\t\t{name: \"Tan\", funcName: ast.Tan},\n\t\t{name: \"Acos\", funcName: ast.Acos},\n\t\t{name: \"Asin\", funcName: ast.Asin},\n\t\t{name: \"Atan\", funcName: ast.Atan},\n\t\t{name: \"Pow\", funcName: ast.Pow},\n\t\t{name: \"IntDiv\", funcName: ast.IntDiv},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tvt := NewVisibilityTable([]string{\"party1\", \"party2\"})\n\n\t\t\toutput := &TensorMeta{ID: 600}\n\t\t\tinput := &TensorMeta{ID: 601}\n\n\t\t\tvt.UpdateVisibility(output, NewVisibleParties([]string{\"party1\"}))\n\t\t\tvt.UpdateVisibility(input, NewVisibleParties([]string{\"party2\"}))\n\n\t\t\tnode := &OperatorFunction{\n\t\t\t\tfuncName: tc.funcName,\n\t\t\t\tinputs:   []*TensorMeta{input},\n\t\t\t\toutput:   output,\n\t\t\t}\n\n\t\t\tvs := &VisibilitySolver{vt: vt}\n\t\t\ttensors, err := node.ReverseInfer(vs)\n\n\t\t\tassert.NoError(err)\n\n\t\t\t// These cases have no implementation (commented out)\n\t\t\t// So they should return empty tensors slice\n\t\t\tassert.Len(tensors, 0)\n\n\t\t\t// Verify input visibility remains unchanged\n\t\t\tassert.Equal([]string{\"party2\"}, vt.TensorVisibleParties(input).GetParties())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/security_relaxation_manager.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\ntype SecurityRelaxationManager struct {\n\tglobal                   *GlobalSecurityRelaxation                // global relaxation settings\n\tcsrTable                 map[string]*ColumnSecurityRelaxationBase // column-level relaxation policies\n\tsourceSecurityRelaxation map[string][]string                      // relaxation name -> list of column full names; used during inference to initialize CSR for specific columns\n}\n\nfunc NewSecurityRelaxationManager(global *GlobalSecurityRelaxation, sourceSecurityRelaxation map[string][]string) *SecurityRelaxationManager {\n\tcsrTable := make(map[string]*ColumnSecurityRelaxationBase)\n\tcsrTable[RevealKeyAfterJoin] = NewColumnSecurityRelaxationBase(global.RevealKeyAfterJoin)\n\tcsrTable[RevealFilterMask] = NewColumnSecurityRelaxationBase(global.RevealFilterMask)\n\n\treturn &SecurityRelaxationManager{\n\t\tglobal:                   global,\n\t\tcsrTable:                 csrTable,\n\t\tsourceSecurityRelaxation: sourceSecurityRelaxation,\n\t}\n}\n\ntype GlobalSecurityRelaxation struct {\n\tRevealFilterMask   bool // reveal tensor when used as filter mask, this relaxation affects tensor visibility\n\tRevealKeyAfterJoin bool // reveal join keys after joining, this relaxation affects tensor visibility\n\tRevealGroupCount   bool // reveal group aggregation counts, this relaxation does not affect tensor visibility, but may affect behavior in KernelObliviousGroupAgg\n\tRevealGroupMark    bool // reveal group aggregation markers, this relaxation does not affect tensor visibility, but may affect behavior in KernelObliviousGroupAgg\n}\n\n// GetCSR returns the ColumnSecurityRelaxationBase for the given name\nfunc (srm *SecurityRelaxationManager) GetCSR(name string) *ColumnSecurityRelaxationBase {\n\treturn srm.csrTable[name]\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_manager.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n)\n\n// TensorPlaceMap is a map from tensor placement string to placed tensor\ntype TensorPlaceMap map[string]*graph.Tensor\n\n// TensorManager manages the lifecycle and relationships between tensor metas\n// and their corresponding placed tensors across different parties and placements.\n//\n// It maintains two key mappings:\n// 1. MetaId2Pt: Maps TensorMeta IDs to their coresponding placed tensor by placement string\n// 2. tensorId2Meta: Maps placed tensor IDs back to their corresponding TensorMeta IDs\n//\n// This enables tracking of how a single logical tensor exists in different states\n// (public, private, secret) across multiple parties while maintaining referential integrity.\ntype TensorManager struct {\n\ttensors      []*graph.Tensor // note that tensors in this slice are not in the order of their IDs\n\tnextTensorID int\n\t// TODO: use slice instead of map\n\tmetaId2Tpm    map[int]TensorPlaceMap // use TensorMeta id as key\n\ttensorId2Meta map[int]*TensorMeta    // use placed tensor id as key\n}\n\nfunc NewTensorManager(nextTensorID int) *TensorManager {\n\treturn &TensorManager{\n\t\tnextTensorID:  nextTensorID,\n\t\tmetaId2Tpm:    make(map[int]TensorPlaceMap),\n\t\ttensorId2Meta: make(map[int]*TensorMeta),\n\t}\n}\n\nfunc (tm *TensorManager) Tensors() []*graph.Tensor {\n\treturn tm.tensors\n}\n\nfunc (tm *TensorManager) CreateTensorAs(source *graph.Tensor) *graph.Tensor {\n\ttensor := tm.newTensor(source.Name)\n\ttensor.DType = source.DType\n\ttensor.Option = source.Option\n\ttensor.IsConstScalar = source.IsConstScalar\n\ttensor.OwnerPartyCode = source.OwnerPartyCode\n\ttensor.SecretStringOwners = source.SecretStringOwners\n\ttensor.SetStatus(source.Status())\n\treturn tensor\n}\n\nfunc (tm *TensorManager) CreateResultTensor(source *graph.Tensor, outputName string) *graph.Tensor {\n\ttensor := tm.CreateTensorAs(source)\n\ttensor.Option = proto.TensorOptions_VALUE\n\ttensor.Name = outputName\n\ttensor.DType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING)\n\ttensor.StringS = []string{outputName}\n\treturn tensor\n}\n\nfunc (tm *TensorManager) CreateConvertedTensor(source *graph.Tensor, placement tensorPlacement) (*graph.Tensor, error) {\n\ttensor := tm.CreateTensorAs(source)\n\tswitch place := placement.(type) {\n\tcase *privatePlacement:\n\t\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\t\ttensor.OwnerPartyCode = place.partyCode\n\tcase *publicPlacement:\n\t\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PUBLIC)\n\tcase *secretPlacement:\n\t\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_SECRET)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"CreateConvertedTensor: unsupported placement type %T\", place)\n\t}\n\n\tmeta, metaExist := tm.tensorId2Meta[source.ID]\n\tif metaExist {\n\t\tif err := tm.setPlacedTensor(meta, tensor, placement); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"CreateConvertedTensor: setPlacedTensor failed: %v\", err)\n\t\t}\n\t}\n\n\treturn tensor, nil\n}\n\n// CreateUnbondedTensor creates a new unbonded tensor with the specified name, data type, and placement\n// If a tensor does not have corresponding schema column in LogicalPlan(in another word, does not have corresponding TensorMeta in OperatorGraph), it is unbonded tensor\nfunc (tm *TensorManager) CreateUnbondedTensor(name string, dtype *graph.DataType, placement tensorPlacement) *graph.Tensor {\n\ttensor := tm.newTensor(name)\n\ttensor.DType = dtype\n\n\tswitch place := placement.(type) {\n\tcase *privatePlacement:\n\t\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\t\ttensor.OwnerPartyCode = place.partyCode\n\tcase *publicPlacement:\n\t\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PUBLIC)\n\tcase *secretPlacement:\n\t\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_SECRET)\n\t}\n\n\treturn tensor\n}\n\n// CreateAndSetFirstTensor creates the initial placed tensor for a tensor meta\n// at a specific placement.\n// Note that we need to distinguish the first placed tensor from the other placed tensors\n// because the first placed tensor has the same tensor ID with corresponding tensor meta.\nfunc (tm *TensorManager) CreateAndSetFirstTensor(meta *TensorMeta, place tensorPlacement) (*graph.Tensor, error) {\n\t_, ok := tm.metaId2Tpm[meta.ID]\n\tif ok {\n\t\treturn nil, fmt.Errorf(\"CreateAndSetFirstTensor: tensorPlaceMap already exists\")\n\t}\n\n\ttensorPlaceMap := make(TensorPlaceMap)\n\ttensor := tm.tensorFromMeta(meta, place)\n\n\ttensorPlaceMap[place.String()] = tensor\n\ttm.metaId2Tpm[meta.ID] = tensorPlaceMap\n\ttm.tensorId2Meta[tensor.ID] = meta\n\treturn tensor, nil\n}\n\n// CorrespondingMeta returns the tensor meta corresponding to a placed tensor.\nfunc (tm *TensorManager) CorrespondingMeta(pt *graph.Tensor) (*TensorMeta, error) {\n\tmeta, ok := tm.tensorId2Meta[pt.ID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"CorrespondingMeta: can not find corresponding meta for tensor %s\", pt)\n\t} else {\n\t\treturn meta, nil\n\t}\n}\n\nfunc (tm *TensorManager) newTensorID() int {\n\tid := tm.nextTensorID\n\ttm.nextTensorID++\n\treturn id\n}\n\nfunc (tm *TensorManager) newTensor(name string) *graph.Tensor {\n\ttensor := graph.NewTensor(tm.newTensorID(), name)\n\ttm.tensors = append(tm.tensors, tensor)\n\treturn tensor\n}\n\nfunc (tm *TensorManager) tensorFromMeta(meta *TensorMeta, place tensorPlacement) *graph.Tensor {\n\ttensor := graph.NewTensor(meta.ID, meta.Name)\n\ttensor.DType = meta.DType\n\ttensor.IsConstScalar = meta.IsConstScalar\n\ttensor.Option = proto.TensorOptions_REFERENCE\n\n\tswitch x := place.(type) {\n\tcase *privatePlacement:\n\t\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\t\ttensor.OwnerPartyCode = x.partyCode\n\tcase *publicPlacement:\n\t\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PUBLIC)\n\tcase *secretPlacement:\n\t\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_SECRET)\n\tdefault:\n\t\tlogrus.Warnf(\"tensorFromMeta: unknown placement type %T\", x)\n\t}\n\n\treturn tensor\n}\n\nfunc (tm *TensorManager) getPlacedTensor(meta *TensorMeta, expectPlace tensorPlacement) (*graph.Tensor, error) {\n\ttensorPlaceMap, ok := tm.metaId2Tpm[meta.ID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"getPlacedTensor: the input tensor does not have any corresponding placed tensor\")\n\t}\n\n\tpt, ok := tensorPlaceMap[expectPlace.String()]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"getPlacedTensor: the input tensor does not have any corresponding placed tensor with place %s\", expectPlace.String())\n\t}\n\treturn pt, nil\n}\n\nfunc (tm *TensorManager) hasPlacedTensor(meta *TensorMeta, place tensorPlacement) bool {\n\ttensorPlaceMap, ok := tm.metaId2Tpm[meta.ID]\n\tif !ok {\n\t\treturn false\n\t}\n\n\t_, ok = tensorPlaceMap[place.String()]\n\treturn ok\n}\n\n// existingPrivateParties returns the list of parties that have private placed tensors\n// for the given tensor meta.\nfunc (tm *TensorManager) existingPrivateParties(meta *TensorMeta) []string {\n\ttensorPlaceMap, ok := tm.metaId2Tpm[meta.ID]\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tprivateParties := []string{}\n\tfor _, pt := range tensorPlaceMap {\n\t\tif pt.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\t\tprivateParties = append(privateParties, pt.OwnerPartyCode)\n\t\t}\n\t}\n\treturn privateParties\n}\n\n// findTensorForConversion determines which placed tensor of the given tensor meta\n// should be used as the source for converting an placed tensor to a new placement.\nfunc (tm *TensorManager) findTensorForConversion(meta *TensorMeta, expectPlace tensorPlacement) (*graph.Tensor, error) {\n\ttensorPlaceMap, ok := tm.metaId2Tpm[meta.ID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"findTensorForConversion: the input tensor does not have any corresponding placed tensor\")\n\t}\n\torderedTensors := slices.Collect(sliceutil.ValueSortedByMapKey(tensorPlaceMap))\n\tif len(orderedTensors) == 0 {\n\t\treturn nil, fmt.Errorf(\"findTensorForConversion: the input tensor does not have any corresponding placed tensor\")\n\t}\n\n\t// TODO choose best tensor\n\tif IsSecret(expectPlace) {\n\t\tfor _, pt := range orderedTensors {\n\t\t\tif pt.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\t\t\treturn pt, nil\n\t\t\t}\n\t\t}\n\t\treturn nil, fmt.Errorf(\"findTensorForConversion: no private tensor found to convert to secret\")\n\t}\n\n\treturn orderedTensors[0], nil\n}\n\n// setPlacedTensor sets a placed tensor for the given tensor meta.\nfunc (tm *TensorManager) setPlacedTensor(meta *TensorMeta, pt *graph.Tensor, place tensorPlacement) error {\n\ttensorPlaceMap, ok := tm.metaId2Tpm[meta.ID]\n\tif !ok {\n\t\treturn fmt.Errorf(\"setPlacedTensor: the input tensor does not have any corresponding placed tensor\")\n\t}\n\n\t// Validate state consistency: tensor status must match placement status\n\texpectedStatus := place.Status()\n\tif pt.Status() != expectedStatus {\n\t\treturn fmt.Errorf(\"setPlacedTensor: tensor status %v does not match placement status %v\",\n\t\t\tpt.Status(), expectedStatus)\n\t}\n\n\ttensorPlaceMap[place.String()] = pt\n\n\tif _, ok := tm.tensorId2Meta[pt.ID]; ok {\n\t\treturn fmt.Errorf(\"setPlacedTensor: placed tensor %s already been set\", pt)\n\t}\n\ttm.tensorId2Meta[pt.ID] = meta\n\n\treturn nil\n}\n\n// getOnePlacedTensor returns a single placed tensor for the given tensor meta\n// with specific priority: public tensors first, then private tensors (sorted by party code),\n// then any remaining tensor as fallback.\nfunc (tm *TensorManager) getOnePlacedTensor(meta *TensorMeta) (*graph.Tensor, error) {\n\ttensorPlaceMap, ok := tm.metaId2Tpm[meta.ID]\n\tif !ok || len(tensorPlaceMap) == 0 {\n\t\treturn nil, fmt.Errorf(\"getOnePlacedTensor: the input tensor meta does not have any corresponding placed tensor\")\n\t}\n\n\t// TODO more elegantly\n\tfor pt := range sliceutil.ValueSortedByMapKey(tensorPlaceMap) {\n\t\tif pt.Status() == proto.TensorStatus_TENSORSTATUS_PUBLIC {\n\t\t\treturn pt, nil\n\t\t}\n\t}\n\tfor pt := range sliceutil.ValueSortedByMapKey(tensorPlaceMap) {\n\t\tif pt.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\t\treturn pt, nil\n\t\t}\n\t}\n\tfor pt := range sliceutil.ValueSortedByMapKey(tensorPlaceMap) {\n\t\treturn pt, nil\n\t}\n\treturn nil, fmt.Errorf(\"getOnePlacedTensor: should not reach here\")\n}\n\n// choosePrivatePlacement selects the best private placement party for tensors based on\n// existing tensor locations. It counts existing tensors per candidate party and selects\n// the party with the most existing tensors to minimize data movement.\n// This is useful when generating private kernels.\nfunc (tm *TensorManager) choosePrivatePlacement(candidates *VisibleParties, tensors []*TensorMeta) *privatePlacement {\n\texistingTensorCount := make(map[string]int)\n\tfor _, candidate := range candidates.GetParties() {\n\t\tfor _, meta := range tensors {\n\t\t\tif tm.hasPlacedTensor(meta, &privatePlacement{partyCode: candidate}) {\n\t\t\t\texistingTensorCount[candidate]++\n\t\t\t}\n\t\t}\n\t}\n\tchosenParty := \"\"\n\tpartyTensorCount := -1\n\tfor party, count := range sliceutil.SortedMap(existingTensorCount) {\n\t\tif count > partyTensorCount {\n\t\t\tchosenParty = party\n\t\t\tpartyTensorCount = count\n\t\t}\n\t}\n\n\tif chosenParty == \"\" {\n\t\treturn &privatePlacement{partyCode: candidates.GetOneParty()}\n\t}\n\treturn &privatePlacement{partyCode: chosenParty}\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_manager_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//\thttp://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\nfunc TestNewTensorManager(t *testing.T) {\n\ttm := NewTensorManager(1)\n\tassert.NotNil(t, tm)\n\tassert.NotNil(t, tm.metaId2Tpm)\n\tassert.NotNil(t, tm.tensorId2Meta)\n\tassert.Empty(t, tm.metaId2Tpm)\n\tassert.Empty(t, tm.tensorId2Meta)\n}\n\nfunc TestCorrespondingMeta(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\t// Create test tensor\n\tpt := &graph.Tensor{ID: 100, Name: \"test_tensor\"}\n\n\t// Test error when tensor not found\n\t_, err := tm.CorrespondingMeta(pt)\n\tassert.Error(t, err)\n\n\t// Setup mapping\n\ttm.tensorId2Meta[100] = &TensorMeta{\n\t\tID:   100,\n\t\tName: \"test_tensor\",\n\t}\n\n\t// Test successful lookup\n\tmeta, err := tm.CorrespondingMeta(pt)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, meta)\n}\n\nfunc TestCreateAndSetFirstPlacedTensor(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\", DType: graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64)}\n\n\t// Test successful creation\n\ttensor, err := tm.CreateAndSetFirstTensor(meta, &publicPlacement{})\n\tassert.NoError(t, err)\n\tassert.NotNil(t, tensor)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, tensor.Status())\n\tassert.Equal(t, 1, tensor.ID)\n\n\t// Test duplicate creation\n\t_, err = tm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: \"alice\"})\n\tassert.Error(t, err)\n\n\t// Test private placement\n\tut2 := &TensorMeta{ID: 2, Name: \"test_tensor2\", DType: graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64)}\n\ttensor2, err := tm.CreateAndSetFirstTensor(ut2, &privatePlacement{partyCode: \"bob\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"bob\", tensor2.OwnerPartyCode)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, tensor2.Status())\n}\n\nfunc TestSetStatusedTensor(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\t// Setup initial state\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\"}\n\t_, err := tm.CreateAndSetFirstTensor(meta, &publicPlacement{})\n\tassert.NoError(t, err)\n\n\t// Create placed tensor\n\tpt := &graph.Tensor{ID: 100, Name: \"statused_tensor\"}\n\tpt.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\n\t// Test successful set\n\terr = tm.setPlacedTensor(meta, pt, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\n\t// Test duplicate tensor ID\n\tpt2 := &graph.Tensor{ID: 100, Name: \"duplicate_tensor\"}\n\tpt2.SetStatus(proto.TensorStatus_TENSORSTATUS_PUBLIC)\n\terr = tm.setPlacedTensor(meta, pt2, &publicPlacement{})\n\tassert.Error(t, err)\n\n\t// Must use CreateAndSetFirstTensor to create the first placed tensor\n\tut2 := &TensorMeta{ID: 999, Name: \"nonexistent\"}\n\terr = tm.setPlacedTensor(ut2, pt, &publicPlacement{})\n\tassert.Error(t, err)\n\n\t// Test state consistency validation\n\tpt3 := &graph.Tensor{ID: 200, Name: \"mismatch_tensor\", OwnerPartyCode: \"charlie\"}\n\tpt3.SetStatus(proto.TensorStatus_TENSORSTATUS_PUBLIC) // Public tensor with private placement\n\terr = tm.setPlacedTensor(meta, pt3, &privatePlacement{partyCode: \"charlie\"})\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"tensor status\")\n}\n\nfunc TestGetPlacedTensor(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\"}\n\t_, err := tm.CreateAndSetFirstTensor(meta, &publicPlacement{})\n\tassert.NoError(t, err)\n\n\t// Test successful get\n\ttensor, err := tm.getPlacedTensor(meta, &publicPlacement{})\n\tassert.NoError(t, err)\n\tassert.NotNil(t, tensor)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, tensor.Status())\n\n\t// Test non-existent placement\n\t_, err = tm.getPlacedTensor(meta, &privatePlacement{partyCode: \"alice\"})\n\tassert.Error(t, err)\n\n\t// Test non-existent UT\n\tut2 := &TensorMeta{ID: 999, Name: \"nonexistent\"}\n\t_, err = tm.getPlacedTensor(ut2, &publicPlacement{})\n\tassert.Error(t, err)\n}\n\nfunc TestGetOnePlacedTensor(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\"}\n\n\t// Test no placed tensors\n\t_, err := tm.getOnePlacedTensor(meta)\n\tassert.Error(t, err)\n\n\t// Add public tensor\n\t_, err = tm.CreateAndSetFirstTensor(meta, &publicPlacement{})\n\tassert.NoError(t, err)\n\n\t// Should return public tensor\n\ttensor, err := tm.getOnePlacedTensor(meta)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, tensor.Status())\n\n\t// Add private tensor\n\tut2 := &TensorMeta{ID: 2, Name: \"test_tensor2\"}\n\t_, err = tm.CreateAndSetFirstTensor(ut2, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\n\t// Should return private tensor when no public\n\ttensor2, err := tm.getOnePlacedTensor(ut2)\n\tassert.NoError(t, err)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, tensor2.Status())\n}\n\nfunc TestExistingPrivateParties(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\"}\n\n\t// Test empty result\n\tparties := tm.existingPrivateParties(meta)\n\tassert.Empty(t, parties)\n\n\t// Add private tensor\n\t_, err := tm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\n\t// Test single party\n\tparties = tm.existingPrivateParties(meta)\n\tassert.Equal(t, []string{\"alice\"}, parties)\n\n\t// Add another private tensor (simulated)\n\ttensor2 := &graph.Tensor{ID: 100, Name: \"private_tensor\", OwnerPartyCode: \"bob\"}\n\ttensor2.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\ttm.setPlacedTensor(meta, tensor2, &privatePlacement{partyCode: \"bob\"})\n\n\t// Test multiple parties\n\tparties = tm.existingPrivateParties(meta)\n\tassert.Contains(t, parties, \"alice\")\n\tassert.Contains(t, parties, \"bob\")\n\tassert.Len(t, parties, 2)\n}\n\nfunc TestChoosePrivatePlacement(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\tut1 := &TensorMeta{ID: 1, Name: \"tensor1\"}\n\tut2 := &TensorMeta{ID: 2, Name: \"tensor2\"}\n\n\t// Setup: create tensors for alice and bob\n\t_, err := tm.CreateAndSetFirstTensor(ut1, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\t_, err = tm.CreateAndSetFirstTensor(ut2, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\n\tcandidates := NewVisibleParties([]string{\"alice\", \"bob\", \"charlie\"})\n\ttensors := []*TensorMeta{ut1, ut2}\n\n\t// Should choose alice due to more existing tensors\n\tplacement := tm.choosePrivatePlacement(candidates, tensors)\n\tassert.Equal(t, \"alice\", placement.partyCode)\n\n\t// Test fallback to any candidate when no existing tensors\n\tut3 := &TensorMeta{ID: 3, Name: \"tensor3\"}\n\tplacement = tm.choosePrivatePlacement(candidates, []*TensorMeta{ut3})\n\tassert.Contains(t, []string{\"alice\", \"bob\", \"charlie\"}, placement.partyCode)\n}\n\nfunc TestTensors(t *testing.T) {\n\ttm := NewTensorManager(1)\n\tassert.Empty(t, tm.Tensors())\n\n\t// Create some tensors\n\ttm.newTensor(\"tensor1\")\n\ttm.newTensor(\"tensor2\")\n\n\ttensors := tm.Tensors()\n\tassert.Len(t, tensors, 2)\n\tassert.Equal(t, \"tensor1\", tensors[0].Name)\n\tassert.Equal(t, \"tensor2\", tensors[1].Name)\n}\n\nfunc TestCreateTensorAs(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\tsource := &graph.Tensor{\n\t\tName:               \"source_tensor\",\n\t\tDType:              graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t\tIsConstScalar:      true,\n\t\tOwnerPartyCode:     \"alice\",\n\t\tSecretStringOwners: []string{\"alice\", \"bob\"},\n\t}\n\tsource.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\n\tnewTensor := tm.CreateTensorAs(source)\n\tassert.NotNil(t, newTensor)\n\tassert.Equal(t, source.Name, newTensor.Name)\n\tassert.True(t, source.DType.Equal(newTensor.DType))\n\tassert.Equal(t, source.IsConstScalar, newTensor.IsConstScalar)\n\tassert.Equal(t, source.OwnerPartyCode, newTensor.OwnerPartyCode)\n\tassert.Equal(t, source.SecretStringOwners, newTensor.SecretStringOwners)\n\tassert.Equal(t, source.Status(), newTensor.Status())\n}\n\nfunc TestCreateResultTensor(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\tsource := &graph.Tensor{\n\t\tName:          \"source_tensor\",\n\t\tDType:         graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t\tIsConstScalar: false,\n\t}\n\n\toutputName := \"result_output\"\n\tresultTensor := tm.CreateResultTensor(source, outputName)\n\tassert.NotNil(t, resultTensor)\n\tassert.Equal(t, outputName, resultTensor.Name)\n\tassert.Equal(t, proto.TensorOptions_VALUE, resultTensor.Option)\n\tassert.Equal(t, proto.PrimitiveDataType_STRING, resultTensor.DType.DType)\n\tassert.Equal(t, []string{outputName}, resultTensor.StringS)\n\tassert.Equal(t, source.IsConstScalar, resultTensor.IsConstScalar)\n}\n\nfunc TestCreateUnbondedTensor(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\t// Test public placement\n\tpublicTensor := tm.CreateUnbondedTensor(\"public_tensor\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT32), &publicPlacement{})\n\tassert.NotNil(t, publicTensor)\n\tassert.Equal(t, \"public_tensor\", publicTensor.Name)\n\tassert.Equal(t, proto.PrimitiveDataType_FLOAT32, publicTensor.DType.DType)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, publicTensor.Status())\n\n\t// Test private placement\n\tprivateTensor := tm.CreateUnbondedTensor(\"private_tensor\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64), &privatePlacement{partyCode: \"alice\"})\n\tassert.NotNil(t, privateTensor)\n\tassert.Equal(t, \"private_tensor\", privateTensor.Name)\n\tassert.Equal(t, proto.PrimitiveDataType_INT64, privateTensor.DType.DType)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, privateTensor.Status())\n\tassert.Equal(t, \"alice\", privateTensor.OwnerPartyCode)\n\n\t// Test secret placement\n\tsecretTensor := tm.CreateUnbondedTensor(\"secret_tensor\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING), &secretPlacement{})\n\tassert.NotNil(t, secretTensor)\n\tassert.Equal(t, \"secret_tensor\", secretTensor.Name)\n\tassert.Equal(t, proto.PrimitiveDataType_STRING, secretTensor.DType.DType)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_SECRET, secretTensor.Status())\n}\n\nfunc TestCreateConvertedTensor(t *testing.T) {\n\ttm := NewTensorManager(2)\n\n\t// Setup: create a tensor meta and its first placed tensor\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\", DType: graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64)}\n\tsource, err := tm.CreateAndSetFirstTensor(meta, &publicPlacement{})\n\tassert.NoError(t, err)\n\n\t// Test successful conversion to private\n\tprivateTensor, err := tm.CreateConvertedTensor(source, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\tassert.NotNil(t, privateTensor)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, privateTensor.Status())\n\tassert.Equal(t, \"alice\", privateTensor.OwnerPartyCode)\n\n\t// Test successful conversion to secret\n\tsecretTensor, err := tm.CreateConvertedTensor(source, &secretPlacement{})\n\tassert.NoError(t, err)\n\tassert.NotNil(t, secretTensor)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_SECRET, secretTensor.Status())\n\n\t// Test unsupported placement type\n\t// graph.Tensor also implements TensorPlacement interface, we do not need to mock new placement type here\n\t_, err = tm.CreateConvertedTensor(source, secretTensor)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"unsupported placement type\")\n\n\t// Test without corresponding meta\n\torphanTensor := &graph.Tensor{ID: 999, Name: \"orphan\"}\n\tconvertedOrphan, err := tm.CreateConvertedTensor(orphanTensor, &publicPlacement{})\n\tassert.NoError(t, err)\n\tassert.NotNil(t, convertedOrphan)\n}\n\nfunc TestFindTensorForConversion(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\"}\n\n\t// Test no placed tensors\n\t_, err := tm.findTensorForConversion(meta, &secretPlacement{})\n\tassert.Error(t, err)\n\n\t// Setup: create public tensor\n\t_, err = tm.CreateAndSetFirstTensor(meta, &publicPlacement{})\n\tassert.NoError(t, err)\n\n\t// Test conversion from public to secret (should fail - need private)\n\t_, err = tm.findTensorForConversion(meta, &secretPlacement{})\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"no private tensor found\")\n\n\t// Setup: create private tensor\n\tmeta2 := &TensorMeta{ID: 2, Name: \"private_tensor\"}\n\t_, err = tm.CreateAndSetFirstTensor(meta2, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\n\t// Test conversion from private to secret\n\tsource, err := tm.findTensorForConversion(meta2, &secretPlacement{})\n\tassert.NoError(t, err)\n\tassert.NotNil(t, source)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, source.Status())\n\n\t// Test conversion from any to public\n\tsource, err = tm.findTensorForConversion(meta, &publicPlacement{})\n\tassert.NoError(t, err)\n\tassert.NotNil(t, source)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, source.Status())\n}\n\nfunc TestHasPlacedTensor(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\tmeta := &TensorMeta{ID: 1, Name: \"test_tensor\"}\n\n\t// Test no placed tensors\n\tassert.False(t, tm.hasPlacedTensor(meta, &publicPlacement{}))\n\n\t// Setup: create placed tensor\n\t_, err := tm.CreateAndSetFirstTensor(meta, &publicPlacement{})\n\tassert.NoError(t, err)\n\n\t// Test existing placement\n\tassert.True(t, tm.hasPlacedTensor(meta, &publicPlacement{}))\n\n\t// Test non-existing placement\n\tassert.False(t, tm.hasPlacedTensor(meta, &privatePlacement{partyCode: \"alice\"}))\n}\n\nfunc TestNewTensorID(t *testing.T) {\n\ttm := NewTensorManager(100)\n\n\tid1 := tm.newTensorID()\n\tassert.Equal(t, 100, id1)\n\n\tid2 := tm.newTensorID()\n\tassert.Equal(t, 101, id2)\n\n\t// Verify the counter incremented\n\tassert.Equal(t, 102, tm.nextTensorID)\n}\n\nfunc TestTensorFromMeta(t *testing.T) {\n\ttm := NewTensorManager(1)\n\n\tmeta := &TensorMeta{\n\t\tID:            42,\n\t\tName:          \"test_tensor\",\n\t\tDType:         graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT32),\n\t\tIsConstScalar: true,\n\t}\n\n\t// Test public placement\n\tpublicTensor := tm.tensorFromMeta(meta, &publicPlacement{})\n\tassert.NotNil(t, publicTensor)\n\tassert.Equal(t, meta.ID, publicTensor.ID)\n\tassert.Equal(t, meta.Name, publicTensor.Name)\n\tassert.True(t, meta.DType.Equal(publicTensor.DType))\n\tassert.Equal(t, meta.IsConstScalar, publicTensor.IsConstScalar)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, publicTensor.Status())\n\n\t// Test private placement\n\tprivateTensor := tm.tensorFromMeta(meta, &privatePlacement{partyCode: \"alice\"})\n\tassert.NotNil(t, privateTensor)\n\tassert.Equal(t, \"alice\", privateTensor.OwnerPartyCode)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, privateTensor.Status())\n\n\t// Test secret placement\n\tsecretTensor := tm.tensorFromMeta(meta, &secretPlacement{})\n\tassert.NotNil(t, secretTensor)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_SECRET, secretTensor.Status())\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_meta.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n)\n\n// TODO: add flag to mark temporary tensor\ntype TensorMeta struct {\n\tID            int\n\tName          string\n\tDType         *graph.DataType\n\tIsConstScalar bool\n}\n\nfunc (t *TensorMeta) UniqueName() string {\n\treturn fmt.Sprintf(\"%s.%d\", t.Name, t.ID)\n}\n\nfunc (t *TensorMeta) String() string {\n\treturn t.UniqueName()\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_meta_manager.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n)\n\n// ResultTable maps column IDs to their corresponding tensor metas for logical plan results.\ntype ResultTable map[int64]*TensorMeta\n\nfunc (rt ResultTable) getColumnTensorMeta(col *expression.Column) (*TensorMeta, error) {\n\ttensor, ok := rt[col.UniqueID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"getColumnTensorMeta: unable to find columnID %v\", col.UniqueID)\n\t}\n\treturn tensor, nil\n}\n\n// TensorMetaManager manages the lifecycle of all tensor and maintain the mapping between logical plans and their result tensors.\ntype TensorMetaManager struct {\n\ttensors         []*TensorMeta\n\ttensorNum       int\n\tlpResultTensors map[core.LogicalPlan]ResultTable\n}\n\nfunc NewTensorMetaManager() *TensorMetaManager {\n\ttmm := &TensorMetaManager{\n\t\ttensors:         []*TensorMeta{},\n\t\ttensorNum:       0,\n\t\tlpResultTensors: map[core.LogicalPlan]ResultTable{},\n\t}\n\treturn tmm\n}\n\n// ============================================================================\n// TensorMeta Management\n// ============================================================================\n\nfunc (tmm *TensorMetaManager) Tensors() []*TensorMeta {\n\treturn tmm.tensors\n}\n\nfunc (tmm *TensorMetaManager) newTensorMeta() *TensorMeta {\n\ttmm.tensorNum++\n\tt := &TensorMeta{\n\t\tID: tmm.tensorNum,\n\t}\n\ttmm.tensors = append(tmm.tensors, t)\n\treturn t\n}\n\nfunc (tmm *TensorMetaManager) CreateTensorMeta(name string, dType *graph.DataType) *TensorMeta {\n\tt := tmm.newTensorMeta()\n\n\tt.Name = name\n\tt.DType = dType\n\n\treturn t\n}\n\nfunc (tmm *TensorMetaManager) CreateTensorMetaAs(ref *TensorMeta) *TensorMeta {\n\treturn tmm.CreateTensorMeta(ref.Name, ref.DType)\n}\n\nfunc areTensorMetasSimilar(t1, t2 *TensorMeta) bool {\n\treturn t1.IsConstScalar == t2.IsConstScalar && t1.DType.Equal(t2.DType)\n}\n\n// FIXME: this is a hack for OperatorWindow, where private and secret kernels have different output behaviors.\n// OperatorWindow will not create new payloads tensor when the private kernel is used.\nfunc (tmm *TensorMetaManager) setTensorsEquivalent(mainTensor, replicaTensor *TensorMeta) error {\n\tif !areTensorMetasSimilar(mainTensor, replicaTensor) {\n\t\treturn fmt.Errorf(\"setTensorsEquivalent: tensor metas %v and %v need to be similar\", mainTensor, replicaTensor)\n\t}\n\treplicaTensor.ID = mainTensor.ID\n\treturn nil\n}\n\n// ============================================================================\n// LogicalPlan ResultTable Management\n// ============================================================================\n\n// checkLPResultTable validates that result tensor metas match the logical plan's schema.\n// Returns an error if any column is missing or has mismatched data types.\nfunc (tmm *TensorMetaManager) checkLPResultTable(lp core.LogicalPlan, resultTable ResultTable) error {\n\tfor _, column := range lp.Schema().Columns {\n\t\ttensorMeta, ok := resultTable[column.UniqueID]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"checkLPResultTable: result tensors%v does not contain column %v\", resultTable, column)\n\t\t}\n\t\texpectTp, err := graph.ConvertDataType(column.RetType)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"checkLPResultTable: %v\", err)\n\t\t}\n\t\tif !tensorMeta.DType.Equal(expectTp) {\n\t\t\treturn fmt.Errorf(\"checkLPResultTable: tensor %v type(=%v) doesn't match scheme type(=%v)\", tensorMeta.UniqueName(), tensorMeta.DType, expectTp)\n\t\t}\n\t}\n\treturn nil\n}\n\n// setLPResultTable stores result tensor metas for a logical plan.\n// The flag checkType is provided, so we can skip the type check if necessary.\n// This is important because we can not do type check for single party OperatorGraph, which may contains unknown function.\nfunc (tmm *TensorMetaManager) setLPResultTable(lp core.LogicalPlan, resultTable ResultTable, checkType bool) error {\n\tif _, exist := tmm.lpResultTensors[lp]; exist {\n\t\treturn fmt.Errorf(\"setLPResultTable: logical plan %v has already set result tensors\", lp)\n\t}\n\tif checkType {\n\t\tif err := tmm.checkLPResultTable(lp, resultTable); err != nil {\n\t\t\treturn fmt.Errorf(\"setLPResultTable: %v\", err)\n\t\t}\n\t}\n\n\ttmm.lpResultTensors[lp] = resultTable\n\treturn nil\n}\n\nfunc (tmm *TensorMetaManager) getLPResultTable(lp core.LogicalPlan) (ResultTable, error) {\n\tif _, exist := tmm.lpResultTensors[lp]; !exist {\n\t\treturn nil, fmt.Errorf(\"getLPResultTable: logical plan %v has not set result tensors\", lp)\n\t}\n\treturn tmm.lpResultTensors[lp], nil\n}\n\n// getLPResultTensors returns result tensors with the same order as logical plan's schema.\nfunc (tmm *TensorMetaManager) getLPSchemaTensors(lp core.LogicalPlan) ([]*TensorMeta, error) {\n\tresultTable, err := tmm.getLPResultTable(lp)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getLPResultTensors: %v\", err)\n\t}\n\n\tresults := make([]*TensorMeta, 0, len(lp.Schema().Columns))\n\tfor _, col := range lp.Schema().Columns {\n\t\ttensor, ok := resultTable[col.UniqueID]\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"getLPSchemaTensors: unable to find columnID %v\", col.UniqueID)\n\t\t}\n\t\tresults = append(results, tensor)\n\t}\n\treturn results, nil\n}\n\nfunc (tmm *TensorMetaManager) getLPColumnTensor(lp core.LogicalPlan, col *expression.Column) (*TensorMeta, error) {\n\tresultTable, err := tmm.getLPResultTable(lp)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getLPColumnTensor: %v\", err)\n\t}\n\treturn resultTable.getColumnTensorMeta(col)\n}\n\n// DumpTensorMetas returns a string representation of all tensors managed by this TensorMetaManager.\n// If visibilityRegistry is not nil, includes visible parties information for each tensor.\nfunc (tmm *TensorMetaManager) DumpTensorMetas(visibilityRegistry VisibilityRegistry) string {\n\tvar sb strings.Builder\n\tfmt.Fprintf(&sb, \"TensorMetaManager Dump:\\n\")\n\tfmt.Fprintf(&sb, \"Total TensorMetas: %d\\n\", len(tmm.tensors))\n\n\tfor _, tensor := range tmm.tensors {\n\t\tfmt.Fprintf(&sb, \"Tensor[%d]: %s, Type: %v\", tensor.ID, tensor.Name, tensor.DType)\n\t\tif tensor.IsConstScalar {\n\t\t\tfmt.Fprintf(&sb, \", ConstScalar: true\")\n\t\t}\n\n\t\tif visibilityRegistry != nil {\n\t\t\tvisibleParties := visibilityRegistry.TensorVisibleParties(tensor)\n\t\t\tif visibleParties != nil && !visibleParties.IsEmpty() {\n\t\t\t\tfmt.Fprintf(&sb, \", VisibleParties: [%s]\", visibleParties.String())\n\t\t\t} else {\n\t\t\t\tfmt.Fprintf(&sb, \", VisibleParties: []\")\n\t\t\t}\n\t\t}\n\n\t\tfmt.Fprintf(&sb, \"\\n\")\n\t}\n\n\treturn sb.String()\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_meta_manager_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/mock\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n\tpb \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// Mock object definitions\ntype mockLogicalPlan struct {\n\tmock.Mock\n\n\t// dummy fields to satisfy the interface\n\tcore.LogicalPlan\n}\n\nfunc (m *mockLogicalPlan) Schema() *expression.Schema {\n\targs := m.Called()\n\treturn args.Get(0).(*expression.Schema)\n}\n\nfunc TestTensorManagerBasic(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\n\t// Test initial state\n\tassert.Empty(t, tensorMetaManager.Tensors())\n\tassert.Equal(t, 0, tensorMetaManager.tensorNum)\n\n\t// Test tensor creation\n\ttensor1 := tensorMetaManager.CreateTensorMeta(\"test1\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_INT64))\n\tassert.NotNil(t, tensor1)\n\tassert.Equal(t, \"test1\", tensor1.Name)\n\tassert.Equal(t, pb.PrimitiveDataType_INT64, tensor1.DType.DType)\n\tassert.Len(t, tensorMetaManager.Tensors(), 1)\n\n\t// Test CreateTensorAs\n\ttensor2 := tensorMetaManager.CreateTensorMetaAs(tensor1)\n\tassert.NotNil(t, tensor2)\n\tassert.Equal(t, tensor1.DType, tensor2.DType)\n\tassert.Len(t, tensorMetaManager.Tensors(), 2)\n}\n\nfunc TestSetTensorsEquivalent(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\n\t// Create similar tensors\n\ttensor1 := tensorMetaManager.CreateTensorMeta(\"test1\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_INT64))\n\ttensor2 := tensorMetaManager.CreateTensorMeta(\"test2\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_INT64))\n\n\t// Test setting equivalent tensors\n\terr := tensorMetaManager.setTensorsEquivalent(tensor1, tensor2)\n\tassert.NoError(t, err)\n\tassert.Equal(t, tensor1.ID, tensor2.ID)\n\n\t// Test error case with dissimilar tensors\n\ttensor3 := tensorMetaManager.CreateTensorMeta(\"test3\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_STRING))\n\terr = tensorMetaManager.setTensorsEquivalent(tensor1, tensor3)\n\tassert.Error(t, err)\n}\n\nfunc TestLPResultTableBasic(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\ttensor := tensorMetaManager.CreateTensorMeta(\"test\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_INT64))\n\n\t// Mock LogicalPlan and Schema\n\tmockLP := &mockLogicalPlan{}\n\tmockSchema := &expression.Schema{\n\t\tColumns: []*expression.Column{\n\t\t\t{UniqueID: 123, RetType: &types.FieldType{}}},\n\t}\n\tmockLP.On(\"Schema\").Return(mockSchema)\n\n\t// Test getting non-existent LogicalPlan result table\n\t_, err := tensorMetaManager.getLPResultTable(mockLP)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"has not set result tensors\")\n\n\tresultTable := ResultTable{123: tensor}\n\t// Test setting result table with type check and wrong type\n\terr = tensorMetaManager.setLPResultTable(mockLP, resultTable, true)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"doesn't support type\")\n\t// Test setting result table\n\terr = tensorMetaManager.setLPResultTable(mockLP, resultTable, false) // Skip type check\n\tassert.NoError(t, err)\n\t// Test getting result table\n\tretrieved, err := tensorMetaManager.getLPResultTable(mockLP)\n\tassert.NoError(t, err)\n\tassert.Equal(t, resultTable, retrieved)\n\n\t// Test duplicate setting error\n\terr = tensorMetaManager.setLPResultTable(mockLP, resultTable, false)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"has already set result tensors\")\n}\n\nfunc TestTensorManagerGetLPSchemaTensors(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\ttensor1 := tensorMetaManager.CreateTensorMeta(\"test1\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_INT64))\n\ttensor2 := tensorMetaManager.CreateTensorMeta(\"test2\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_STRING))\n\n\t// Mock LogicalPlan\n\tmockLP := &mockLogicalPlan{}\n\tmockSchema := &expression.Schema{\n\t\tColumns: []*expression.Column{{UniqueID: 123},\n\t\t\t{UniqueID: 456},\n\t\t},\n\t}\n\tmockLP.On(\"Schema\").Return(mockSchema)\n\tresultTable := ResultTable{\n\t\t123: tensor1, 456: tensor2,\n\t}\n\n\t// Test getting tensors before setting result table\n\t_, err := tensorMetaManager.getLPSchemaTensors(mockLP)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"has not set result tensors\")\n\n\t// Set result table\n\terr = tensorMetaManager.setLPResultTable(mockLP, resultTable, false)\n\tassert.NoError(t, err)\n\n\t// Test getting tensors in schema order\n\ttensors, err := tensorMetaManager.getLPSchemaTensors(mockLP)\n\tassert.NoError(t, err)\n\tassert.Len(t, tensors, 2)\n\tassert.Equal(t, tensor1, tensors[0])\n\tassert.Equal(t, tensor2, tensors[1])\n\n\t// Test missing column error\n\tmockSchema.Columns = []*expression.Column{{UniqueID: 789}}\n\t_, err = tensorMetaManager.getLPSchemaTensors(mockLP)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"unable to find columnID\")\n}\n\nfunc TestGetLPColumnTensor(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\ttensor := tensorMetaManager.CreateTensorMeta(\"test\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_INT64))\n\tmockLP := &mockLogicalPlan{}\n\tresultTable := ResultTable{123: tensor}\n\n\t// Test getting tensor before setting result table\n\t_, err := tensorMetaManager.getLPColumnTensor(mockLP, &expression.Column{UniqueID: 123})\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"has not set result tensors\")\n\n\t// Set result table\n\terr = tensorMetaManager.setLPResultTable(mockLP, resultTable, false)\n\tassert.NoError(t, err)\n\n\t// Test getting tensor for specific column\n\tcol := &expression.Column{UniqueID: 123}\n\tresult, err := tensorMetaManager.getLPColumnTensor(mockLP, col)\n\tassert.NoError(t, err)\n\tassert.Equal(t, tensor, result)\n\n\t// Test getting non-existent column\n\tcol2 := &expression.Column{UniqueID: 999}\n\tresult, err = tensorMetaManager.getLPColumnTensor(mockLP, col2)\n\tassert.Error(t, err)\n\tassert.Nil(t, result)\n}\n\nfunc TestCheckLPResultTable(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\n\tmockLP := &mockLogicalPlan{}\n\tmockSchema := &expression.Schema{\n\t\tColumns: []*expression.Column{\n\t\t\t{UniqueID: 123, RetType: &types.FieldType{Tp: mysql.TypeLonglong}},\n\t\t},\n\t}\n\tmockLP.On(\"Schema\").Return(mockSchema)\n\n\ttensor := tensorMetaManager.CreateTensorMeta(\"test\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_INT64))\n\tresultTable := ResultTable{123: tensor}\n\n\t// Test with valid result table\n\terr := tensorMetaManager.setLPResultTable(mockLP, resultTable, true)\n\tassert.NoError(t, err, \"Should not error when setting result table\")\n\tretrievedTable, err := tensorMetaManager.getLPResultTable(mockLP)\n\tassert.NoError(t, err)\n\tassert.Equal(t, resultTable, retrievedTable)\n\tmockLP.AssertExpectations(t)\n\n\t// Test check with invalid result table\n\ttensor2 := tensorMetaManager.CreateTensorMeta(\"test\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_STRING))\n\tresultTable[123] = tensor2\n\terr = tensorMetaManager.setLPResultTable(mockLP, resultTable, true)\n\tassert.Error(t, err)\n\n\t// Test with missing column\n\tmockSchema.Columns = []*expression.Column{\n\t\t{UniqueID: 456, RetType: &types.FieldType{Tp: mysql.TypeLonglong}},\n\t}\n\terr = tensorMetaManager.checkLPResultTable(mockLP, resultTable)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"does not contain column\")\n\n\t// Test with unsupported type\n\tmockSchema.Columns = []*expression.Column{\n\t\t{UniqueID: 123, RetType: &types.FieldType{Tp: mysql.TypeBlob}},\n\t}\n\terr = tensorMetaManager.checkLPResultTable(mockLP, resultTable)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"doesn't support type\")\n\n\t// Test with unexpected type\n\tmockSchema.Columns = []*expression.Column{\n\t\t{UniqueID: 123, RetType: &types.FieldType{Tp: mysql.TypeLonglong}},\n\t}\n\terr = tensorMetaManager.checkLPResultTable(mockLP, resultTable)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"doesn't match scheme type\")\n}\n\nfunc TestGetTensorFromColumn(t *testing.T) {\n\ttensorMetaManager := NewTensorMetaManager()\n\ttensor := tensorMetaManager.CreateTensorMeta(\"test\", graph.NewPrimitiveDataType(pb.PrimitiveDataType_INT64))\n\trt := ResultTable{\n\t\t123: tensor,\n\t}\n\n\t// Test successful retrieval\n\tcol := &expression.Column{UniqueID: 123}\n\tresult, err := rt.getColumnTensorMeta(col)\n\tassert.NoError(t, err)\n\tassert.Equal(t, tensor, result)\n\n\t// Test column not found case\n\tcol2 := &expression.Column{UniqueID: 456}\n\tresult, err = rt.getColumnTensorMeta(col2)\n\tassert.Error(t, err)\n\tassert.Nil(t, result)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_meta_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\nfunc TestTensorMeta(t *testing.T) {\n\tmeta := &TensorMeta{\n\t\tID:            1,\n\t\tName:          \"test_tensor\",\n\t\tDType:         graph.NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT32),\n\t\tIsConstScalar: true,\n\t}\n\n\t// Test UniqueName\n\tassert.Equal(t, \"test_tensor.1\", meta.UniqueName())\n\n\t// Test String\n\tassert.Equal(t, \"test_tensor.1\", meta.String())\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_placement.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\ntype tensorPlacement interface {\n\tStatus() proto.TensorStatus\n\tString() string\n}\n\ntype privatePlacement struct {\n\tpartyCode string\n}\n\nfunc (p *privatePlacement) Status() proto.TensorStatus {\n\treturn proto.TensorStatus_TENSORSTATUS_PRIVATE\n}\n\nfunc (p *privatePlacement) String() string {\n\treturn \"private-\" + p.partyCode\n}\n\ntype publicPlacement struct {\n}\n\nfunc (p *publicPlacement) Status() proto.TensorStatus {\n\treturn proto.TensorStatus_TENSORSTATUS_PUBLIC\n}\n\nfunc (p *publicPlacement) String() string {\n\treturn \"public\"\n}\n\ntype secretPlacement struct {\n}\n\nfunc (p *secretPlacement) Status() proto.TensorStatus {\n\treturn proto.TensorStatus_TENSORSTATUS_SECRET\n}\n\nfunc (p *secretPlacement) String() string {\n\treturn \"secret\"\n}\n\nfunc IsPrivate(p tensorPlacement) bool {\n\treturn p.Status() == proto.TensorStatus_TENSORSTATUS_PRIVATE\n}\n\nfunc IsPublic(p tensorPlacement) bool {\n\treturn p.Status() == proto.TensorStatus_TENSORSTATUS_PUBLIC\n}\n\nfunc IsSecret(p tensorPlacement) bool {\n\treturn p.Status() == proto.TensorStatus_TENSORSTATUS_SECRET\n}\n\nfunc extractTensorPlacement(tensor *graph.Tensor) tensorPlacement {\n\tswitch tensor.Status() {\n\tcase proto.TensorStatus_TENSORSTATUS_PRIVATE:\n\t\tif tensor.OwnerPartyCode == \"\" {\n\t\t\treturn nil\n\t\t}\n\t\treturn &privatePlacement{partyCode: tensor.OwnerPartyCode}\n\tcase proto.TensorStatus_TENSORSTATUS_PUBLIC:\n\t\treturn &publicPlacement{}\n\tcase proto.TensorStatus_TENSORSTATUS_SECRET:\n\t\treturn &secretPlacement{}\n\tdefault:\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_placement_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\nfunc TestPrivatePlacement(t *testing.T) {\n\tparty := \"alice\"\n\tplacement := &privatePlacement{partyCode: party}\n\n\tt.Run(\"Status returns private\", func(t *testing.T) {\n\t\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, placement.Status())\n\t})\n\n\tt.Run(\"String returns correct format\", func(t *testing.T) {\n\t\tassert.Equal(t, \"private-alice\", placement.String())\n\t})\n\n\tt.Run(\"IsPrivate returns true\", func(t *testing.T) {\n\t\tassert.True(t, IsPrivate(placement))\n\t})\n\n\tt.Run(\"IsPublic returns false\", func(t *testing.T) {\n\t\tassert.False(t, IsPublic(placement))\n\t})\n\n\tt.Run(\"IsSecret returns false\", func(t *testing.T) {\n\t\tassert.False(t, IsSecret(placement))\n\t})\n}\n\nfunc TestPublicPlacement(t *testing.T) {\n\tplacement := &publicPlacement{}\n\n\tt.Run(\"Status returns public\", func(t *testing.T) {\n\t\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, placement.Status())\n\t})\n\n\tt.Run(\"String returns public\", func(t *testing.T) {\n\t\tassert.Equal(t, \"public\", placement.String())\n\t})\n\n\tt.Run(\"IsPrivate returns false\", func(t *testing.T) {\n\t\tassert.False(t, IsPrivate(placement))\n\t})\n\n\tt.Run(\"IsPublic returns true\", func(t *testing.T) {\n\t\tassert.True(t, IsPublic(placement))\n\t})\n\n\tt.Run(\"IsSecret returns false\", func(t *testing.T) {\n\t\tassert.False(t, IsSecret(placement))\n\t})\n}\n\nfunc TestSecretPlacement(t *testing.T) {\n\tplacement := &secretPlacement{}\n\n\tt.Run(\"Status returns secret\", func(t *testing.T) {\n\t\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_SECRET, placement.Status())\n\t})\n\n\tt.Run(\"String returns secret\", func(t *testing.T) {\n\t\tassert.Equal(t, \"secret\", placement.String())\n\t})\n\n\tt.Run(\"IsPrivate returns false\", func(t *testing.T) {\n\t\tassert.False(t, IsPrivate(placement))\n\t})\n\n\tt.Run(\"IsPublic returns false\", func(t *testing.T) {\n\t\tassert.False(t, IsPublic(placement))\n\t})\n\n\tt.Run(\"IsSecret returns true\", func(t *testing.T) {\n\t\tassert.True(t, IsSecret(placement))\n\t})\n}\n\nfunc TestExtractTensorPlacement(t *testing.T) {\n\ttestCases := []struct {\n\t\tname           string\n\t\tstatus         proto.TensorStatus\n\t\townerPartyCode string\n\t\texpectedType   string\n\t}{\n\t\t{\n\t\t\tname:           \"private tensor with owner\",\n\t\t\tstatus:         proto.TensorStatus_TENSORSTATUS_PRIVATE,\n\t\t\townerPartyCode: \"alice\",\n\t\t\texpectedType:   \"*compiler.privatePlacement\",\n\t\t},\n\t\t{\n\t\t\tname:           \"private tensor without owner\",\n\t\t\tstatus:         proto.TensorStatus_TENSORSTATUS_PRIVATE,\n\t\t\townerPartyCode: \"\",\n\t\t\texpectedType:   \"<nil>\",\n\t\t},\n\t\t{\n\t\t\tname:           \"public tensor\",\n\t\t\tstatus:         proto.TensorStatus_TENSORSTATUS_PUBLIC,\n\t\t\townerPartyCode: \"\",\n\t\t\texpectedType:   \"*compiler.publicPlacement\",\n\t\t},\n\t\t{\n\t\t\tname:           \"secret tensor\",\n\t\t\tstatus:         proto.TensorStatus_TENSORSTATUS_SECRET,\n\t\t\townerPartyCode: \"\",\n\t\t\texpectedType:   \"*compiler.secretPlacement\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\ttensor := &graph.Tensor{\n\t\t\t\tOwnerPartyCode: tc.ownerPartyCode,\n\t\t\t}\n\t\t\t// Mock the Status method\n\t\t\ttensor.SetStatus(tc.status)\n\n\t\t\tresult := extractTensorPlacement(tensor)\n\t\t\tassert.Equal(t, tc.expectedType, fmt.Sprintf(\"%T\", result))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_status_converter.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// convertStatus converts a tensor from its current status to the expected placement.\n// It handles transitions between private, secret, and public tensor states.\n// The fromTensor must be bonded.\nfunc (builder *ExecutionGraphBuilder) convertStatus(fromTensor *graph.Tensor, expectPlace tensorPlacement, checkVis bool) (*graph.Tensor, error) {\n\tif checkVis {\n\t\tmeta, err := builder.tm.CorrespondingMeta(fromTensor)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"convertStatus: %v\", err)\n\t\t}\n\t\tif err := builder.checkVis(meta, expectPlace); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"convertStatus: %v\", err)\n\t\t}\n\t}\n\n\tswitch fromTensor.Status() {\n\tcase proto.TensorStatus_TENSORSTATUS_PRIVATE:\n\t\tswitch place := expectPlace.(type) {\n\t\tcase *privatePlacement:\n\t\t\tfromParty := fromTensor.OwnerPartyCode\n\t\t\texpectParty := place.partyCode\n\t\t\tif fromParty == expectParty {\n\t\t\t\treturn nil, fmt.Errorf(\"convertStatus: %s has already met expect place %s\", fromTensor, expectPlace)\n\t\t\t}\n\t\t\treturn builder.addCopyNode(fromTensor, fromParty, expectParty)\n\t\tcase *publicPlacement:\n\t\t\treturn builder.addMakePublicNode(fromTensor)\n\t\tcase *secretPlacement:\n\t\t\treturn builder.addMakeShareNode(fromTensor)\n\t\t}\n\tcase proto.TensorStatus_TENSORSTATUS_SECRET:\n\t\tswitch place := expectPlace.(type) {\n\t\tcase *privatePlacement:\n\t\t\tif fromTensor.DType.IsStringType() {\n\t\t\t\treturn builder.revealString(fromTensor, place.partyCode)\n\t\t\t}\n\t\t\treturn builder.addMakePrivateNode(fromTensor, place.partyCode)\n\t\tcase *publicPlacement:\n\t\t\treturn builder.addMakePublicNode(fromTensor)\n\t\tcase *secretPlacement:\n\t\t\treturn nil, fmt.Errorf(\"convertStatus: %s has already met expect place %s\", fromTensor, expectPlace)\n\t\t}\n\tcase proto.TensorStatus_TENSORSTATUS_PUBLIC:\n\t\tswitch place := expectPlace.(type) {\n\t\tcase *privatePlacement:\n\t\t\tif fromTensor.DType.IsStringType() {\n\t\t\t\treturn builder.revealString(fromTensor, place.partyCode)\n\t\t\t}\n\t\t\treturn builder.addMakePrivateNode(fromTensor, place.partyCode)\n\t\tcase *publicPlacement:\n\t\t\treturn nil, fmt.Errorf(\"convertStatus: %s has already met expect place %s\", fromTensor, expectPlace)\n\t\tcase *secretPlacement:\n\t\t\treturn builder.addMakeShareNode(fromTensor)\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"convertStatus doesn't support converting from %v to %v\", fromTensor.Status(), expectPlace.Status())\n}\n\n// revealString converts a string tensor to private status for the specified party.\n// String tensors require special handling because the underlying SPU does not fully support secret strings.\n// String are stored in hashed form when secret-shared, and only the secret string owner can convert it back to original string.\nfunc (builder *ExecutionGraphBuilder) revealString(tensor *graph.Tensor, revealParty string) (*graph.Tensor, error) {\n\tif tensor.Status() != proto.TensorStatus_TENSORSTATUS_SECRET && tensor.Status() != proto.TensorStatus_TENSORSTATUS_PUBLIC {\n\t\treturn nil, fmt.Errorf(\"revealString: input tensor %s must be secret or public\", tensor)\n\t}\n\n\tif len(tensor.SecretStringOwners) == 1 {\n\t\townerPrivateTensor, err := builder.addMakePrivateNode(tensor, tensor.SecretStringOwners[0])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"revealString: %v\", err)\n\t\t}\n\t\tif tensor.SecretStringOwners[0] == revealParty {\n\t\t\treturn ownerPrivateTensor, nil\n\t\t}\n\t\treturn builder.addCopyNode(ownerPrivateTensor, tensor.SecretStringOwners[0], revealParty)\n\t}\n\n\tif tensor.Status() != proto.TensorStatus_TENSORSTATUS_PUBLIC {\n\t\tpublicTensor, err := builder.addMakePublicNode(tensor)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"revealString: %v\", err)\n\t\t}\n\t\treturn builder.addMakePrivateNode(publicTensor, revealParty)\n\t} else {\n\t\treturn builder.addMakePrivateNode(tensor, revealParty)\n\t}\n}\n\n// addMakeShareNode creates a new node that converts a tensor to secret-shared status.\n// The output tensor will have TENSORSTATUS_SECRET status.\nfunc (builder *ExecutionGraphBuilder) addMakeShareNode(input *graph.Tensor) (*graph.Tensor, error) {\n\tif input.Status() != proto.TensorStatus_TENSORSTATUS_PRIVATE {\n\t\treturn nil, fmt.Errorf(\"addMakeShareNode: input tensor %s must be private\", input)\n\t}\n\n\toutput, err := builder.tm.CreateConvertedTensor(input, &secretPlacement{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"addMakeShareNode: %v\", err)\n\t}\n\n\toutput.SecretStringOwners = []string{input.OwnerPartyCode}\n\n\t// TODO handle secret string owner\n\tif err := builder.addEngineNode(\"make_share\", operator.OpNameMakeShare, map[string][]*graph.Tensor{\"In\": {input}},\n\t\tmap[string][]*graph.Tensor{\"Out\": {output}}, map[string]*graph.Attribute{}, builder.GetAllParties()); err != nil {\n\t\treturn nil, fmt.Errorf(\"addMakeShareNode: %v\", err)\n\t}\n\treturn output, nil\n}\n\n// addMakePrivateNode creates a new node that converts a tensor to private status for a specific party.\n// The output tensor will have TENSORSTATUS_PRIVATE status and be owned by placementParty.\nfunc (builder *ExecutionGraphBuilder) addMakePrivateNode(input *graph.Tensor, placementParty string) (*graph.Tensor, error) {\n\toutput, err := builder.tm.CreateConvertedTensor(input, &privatePlacement{placementParty})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"addMakePrivateNode: %v\", err)\n\t}\n\n\tattr := &graph.Attribute{}\n\tattr.SetString(placementParty)\n\tif err := builder.addEngineNode(\"make_private\", operator.OpNameMakePrivate, map[string][]*graph.Tensor{\"In\": {input}},\n\t\tmap[string][]*graph.Tensor{\"Out\": {output}}, map[string]*graph.Attribute{operator.RevealToAttr: attr}, builder.GetAllParties()); err != nil {\n\t\treturn nil, fmt.Errorf(\"addMakePrivateNode: %v\", err)\n\t}\n\treturn output, nil\n}\n\n// addMakePublicNode creates a new node that converts a tensor to public status.\n// The output tensor will have TENSORSTATUS_PUBLIC status.\nfunc (builder *ExecutionGraphBuilder) addMakePublicNode(input *graph.Tensor) (*graph.Tensor, error) {\n\toutput, err := builder.tm.CreateConvertedTensor(input, &publicPlacement{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"addMakePublicNode: %v\", err)\n\t}\n\n\tif err := builder.addEngineNode(\"make_public\", operator.OpNameMakePublic, map[string][]*graph.Tensor{\"In\": {input}},\n\t\tmap[string][]*graph.Tensor{\"Out\": {output}}, map[string]*graph.Attribute{}, builder.GetAllParties()); err != nil {\n\t\treturn nil, fmt.Errorf(\"addMakePublicNode: %v\", err)\n\t}\n\treturn output, nil\n}\n\n// addCopyNode creates a new node that copies a tensor from one party to another.\n// The output tensor will have TENSORSTATUS_PRIVATE status and be owned by the target party.\nfunc (builder *ExecutionGraphBuilder) addCopyNode(input *graph.Tensor, fromParty, toParty string) (*graph.Tensor, error) {\n\toutput, err := builder.tm.CreateConvertedTensor(input, &privatePlacement{toParty})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"addCopyNode: %v\", err)\n\t}\n\n\tinPartyAttr := &graph.Attribute{}\n\tinPartyAttr.SetString(fromParty)\n\toutPartyAttr := &graph.Attribute{}\n\toutPartyAttr.SetString(toParty)\n\n\tif err := builder.addEngineNode(\"copy\", operator.OpNameCopy, map[string][]*graph.Tensor{\"In\": {input}}, map[string][]*graph.Tensor{\"Out\": {output}},\n\t\tmap[string]*graph.Attribute{operator.InputPartyCodesAttr: inPartyAttr, operator.OutputPartyCodesAttr: outPartyAttr}, []string{fromParty, toParty}); err != nil {\n\t\treturn nil, fmt.Errorf(\"addCopyNode: %v\", err)\n\t}\n\treturn output, nil\n}\n\n// getOrCreatePlacedTensor retrieves or creates a tensor with the expected placement.\n// It first checks if a tensor with the expected placement already exists, otherwise it performs\n// the necessary conversion from the original tensor.\nfunc (builder *ExecutionGraphBuilder) getOrCreatePlacedTensor(meta *TensorMeta, expectPlace tensorPlacement) (*graph.Tensor, error) {\n\t// already exists\n\ttensor, err := builder.tm.getPlacedTensor(meta, expectPlace)\n\tif err == nil {\n\t\treturn tensor, nil\n\t}\n\n\t// need conversion\n\tfromTensor, err := builder.tm.findTensorForConversion(meta, expectPlace)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getOrCreatePlacedTensor: %v\", err)\n\t}\n\n\ttensor, err = builder.convertStatus(fromTensor, expectPlace, true)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getOrCreatePlacedTensor: %v\", err)\n\t}\n\treturn tensor, nil\n}\n\nfunc (builder *ExecutionGraphBuilder) checkVis(tensorMeta *TensorMeta, place tensorPlacement) error {\n\tswitch place := place.(type) {\n\tcase *privatePlacement:\n\t\tvisibilityFine := builder.vt.TensorVisibleTo(tensorMeta, place.partyCode)\n\t\tif !visibilityFine {\n\t\t\treturn fmt.Errorf(\"checkVis: %s is not visible for party %s\", tensorMeta, place.partyCode)\n\t\t}\n\tcase *publicPlacement:\n\t\tif !builder.vt.IsTensorPublic(tensorMeta) {\n\t\t\treturn fmt.Errorf(\"checkVis: %s is not visible for all parties\", tensorMeta)\n\t\t}\n\tcase *secretPlacement:\n\t\t// no need to check visibility for secret placement\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"checkVis: unsupported placement type %T\", place)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_status_converter_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/graph\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n)\n\n// createTestBuilder creates a properly initialized ExecutionGraphBuilder for testing\nfunc createTestBuilder() *ExecutionGraphBuilder {\n\ttmm := NewTensorMetaManager()\n\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, nil)\n\tinfo := &graph.EnginesInfo{}\n\n\treturn NewExecutionGraphBuilder(tmm, srm, vt, info, &v1.CompileOptions{Batched: false})\n}\n\nfunc TestConvertStatus(t *testing.T) {\n\tbuilder := createTestBuilder()\n\n\tcreatePlacedTensor := func(name string, place tensorPlacement, vis []string) *graph.Tensor {\n\t\tmeta := builder.tensorMetaManager.CreateTensorMeta(name, graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\t\tbuilder.vt.UpdateVisibility(meta, NewVisibleParties(vis))\n\t\ttensor, _ := builder.tm.CreateAndSetFirstTensor(meta, place)\n\t\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + len(builder.tm.tensors) + 1\n\t\treturn tensor\n\t}\n\n\t// test case 1: private -> same private (should fail)\n\tinput := createPlacedTensor(\"test_tensor1\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"bob\"})\n\toutput, err := builder.convertStatus(input, &privatePlacement{partyCode: \"alice\"}, true)\n\tassert.Error(t, err)\n\tassert.Nil(t, output)\n\tassert.Contains(t, err.Error(), \"has already met expect place\")\n\n\t// test case 2: private -> different private (copy)\n\tinput = createPlacedTensor(\"test_tensor2\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"bob\"})\n\toutput, err = builder.convertStatus(input, &privatePlacement{partyCode: \"bob\"}, true)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, output.Status())\n\tassert.Equal(t, \"bob\", output.OwnerPartyCode)\n\n\t// test case 3: private -> public\n\tinput = createPlacedTensor(\"test_tensor3\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"bob\"})\n\toutput, err = builder.convertStatus(input, &publicPlacement{}, true)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, output.Status())\n\n\t// test case 4: private -> secret\n\tinput = createPlacedTensor(\"test_tensor4\", &privatePlacement{partyCode: \"alice\"}, []string{\"alice\", \"bob\"})\n\toutput, err = builder.convertStatus(input, &secretPlacement{}, true)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_SECRET, output.Status())\n\n\t// test case 5: secret -> private\n\tinput = createPlacedTensor(\"test_tensor5\", &secretPlacement{}, []string{\"alice\", \"bob\"})\n\toutput, err = builder.convertStatus(input, &privatePlacement{partyCode: \"alice\"}, true)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, output.Status())\n\tassert.Equal(t, \"alice\", output.OwnerPartyCode)\n\n\t// test case 6: secret -> public\n\tinput = createPlacedTensor(\"test_tensor6\", &secretPlacement{}, []string{\"alice\", \"bob\"})\n\toutput, err = builder.convertStatus(input, &publicPlacement{}, true)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, output.Status())\n\n\t// test case 7: secret -> same secret (should fail)\n\tinput = createPlacedTensor(\"test_tensor7\", &secretPlacement{}, []string{\"alice\", \"bob\"})\n\toutput, err = builder.convertStatus(input, &secretPlacement{}, true)\n\tassert.Error(t, err)\n\tassert.Nil(t, output)\n\tassert.Contains(t, err.Error(), \"has already met expect place\")\n\n\t// test case 8: public -> private\n\tinput = createPlacedTensor(\"test_tensor8\", &publicPlacement{}, []string{\"alice\", \"bob\"})\n\toutput, err = builder.convertStatus(input, &privatePlacement{partyCode: \"alice\"}, true)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, output.Status())\n\tassert.Equal(t, \"alice\", output.OwnerPartyCode)\n\n\t// test case 9: public -> secret (should fail)\n\tinput = createPlacedTensor(\"test_tensor9\", &publicPlacement{}, []string{\"alice\", \"bob\"})\n\toutput, err = builder.convertStatus(input, &secretPlacement{}, true)\n\tassert.Error(t, err)\n\tassert.Nil(t, output)\n\tassert.Contains(t, err.Error(), \"must be private\")\n\n\t// test case 10: public -> same public (should fail)\n\tinput = createPlacedTensor(\"test_tensor10\", &publicPlacement{}, []string{\"alice\", \"bob\"})\n\toutput, err = builder.convertStatus(input, &publicPlacement{}, true)\n\tassert.Error(t, err)\n\tassert.Nil(t, output)\n\tassert.Contains(t, err.Error(), \"has already met expect place\")\n\n\t// test case 11: secret string -> private\n\tinput = createPlacedTensor(\"test_tensor11\", &secretPlacement{}, []string{\"alice\", \"bob\"})\n\tinput.DType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING)\n\toutput, err = builder.convertStatus(input, &privatePlacement{partyCode: \"alice\"}, true)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, output.Status())\n\tassert.Equal(t, \"alice\", output.OwnerPartyCode)\n\n\t// test case 12: public string -> private\n\tinput = createPlacedTensor(\"test_tensor12\", &publicPlacement{}, []string{\"alice\", \"bob\"})\n\tinput.DType = graph.NewPrimitiveDataType(proto.PrimitiveDataType_STRING)\n\toutput, err = builder.convertStatus(input, &privatePlacement{partyCode: \"alice\"}, true)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, output.Status())\n\tassert.Equal(t, \"alice\", output.OwnerPartyCode)\n}\n\nfunc TestAddMakeShareNode(t *testing.T) {\n\tbuilder := createTestBuilder()\n\tmeta := builder.tensorMetaManager.CreateTensorMeta(\"test_tensor\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\tbuilder.tm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: \"alice\"})\n\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + 1\n\n\tinput, err := builder.tm.findTensorForConversion(meta, &secretPlacement{})\n\tassert.NoError(t, err)\n\n\toutput, err := builder.addMakeShareNode(input)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_SECRET, output.Status())\n}\n\nfunc TestAddMakePrivateNode(t *testing.T) {\n\tbuilder := createTestBuilder()\n\tmeta := builder.tensorMetaManager.CreateTensorMeta(\"test_tensor\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\tbuilder.tm.CreateAndSetFirstTensor(meta, &secretPlacement{})\n\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + 1\n\n\tinput, err := builder.tm.findTensorForConversion(meta, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\n\toutput, err := builder.addMakePrivateNode(input, \"alice\")\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, output.Status())\n\tassert.Equal(t, \"alice\", output.OwnerPartyCode)\n}\n\nfunc TestAddMakePublicNode(t *testing.T) {\n\tbuilder := createTestBuilder()\n\tmeta := builder.tensorMetaManager.CreateTensorMeta(\"test_tensor\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\tbuilder.tm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: \"alice\"})\n\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + 1\n\n\tinput, err := builder.tm.findTensorForConversion(meta, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\n\toutput, err := builder.addMakePublicNode(input)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PUBLIC, output.Status())\n}\n\nfunc TestAddCopyNode(t *testing.T) {\n\tbuilder := createTestBuilder()\n\tmeta := builder.tensorMetaManager.CreateTensorMeta(\"test_tensor\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\tbuilder.tm.CreateAndSetFirstTensor(meta, &privatePlacement{partyCode: \"alice\"})\n\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + 1\n\n\tinput, err := builder.tm.findTensorForConversion(meta, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\n\toutput, err := builder.addCopyNode(input, \"alice\", \"bob\")\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\tassert.Equal(t, proto.TensorStatus_TENSORSTATUS_PRIVATE, output.Status())\n\tassert.Equal(t, \"bob\", output.OwnerPartyCode)\n\n}\n\nfunc TestGetOrCreatePlacedTensor(t *testing.T) {\n\tbuilder := createTestBuilder()\n\tmeta := builder.tensorMetaManager.CreateTensorMeta(\"test_tensor\", graph.NewPrimitiveDataType(proto.PrimitiveDataType_INT64))\n\tbuilder.vt.UpdateVisibility(meta, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tbuilder.tm.nextTensorID = builder.tensorMetaManager.tensorNum + 1\n\n\t// Test case 1: input tensor has no corresponding placed tensor\n\toutput, err := builder.getOrCreatePlacedTensor(meta, &publicPlacement{})\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"the input tensor does not have any corresponding placed tensor\")\n\tassert.Nil(t, output)\n\n\t// Test case 2: input tensor has wanted placed tensor\n\tbuilder.tm.CreateAndSetFirstTensor(meta, &publicPlacement{})\n\toutput, err = builder.getOrCreatePlacedTensor(meta, &publicPlacement{})\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n\n\t// Test case 3: input tensor has corresponding placed tensor with different placement\n\toutput, err = builder.getOrCreatePlacedTensor(meta, &privatePlacement{partyCode: \"alice\"})\n\tassert.NoError(t, err)\n\tassert.NotNil(t, output)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_tracker.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\n\t\"slices\"\n)\n\n// TensorProducerTracker is a map from tensor ID to the source operator that produces the tensor.\n// If a Operator's output tensors contains tensor t1, then t1's producer is this Operator.\ntype TensorProducerTracker map[int]Operator\n\n// GetProducer returns the source node that produces the given tensor.\n// Returns an error if the tensor has no recorded source node.\nfunc (t TensorProducerTracker) GetProducer(tensor *TensorMeta) (Operator, error) {\n\tnode, ok := t[tensor.ID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"GetProducer: unable to find tensor %v\", tensor)\n\t}\n\treturn node, nil\n}\n\n// SetProducer records that the given node produces the specified tensor.\nfunc (t TensorProducerTracker) SetProducer(tensor *TensorMeta, node Operator) {\n\tt[tensor.ID] = node\n}\n\n// RemoveRecord removes the producer operator record for the given tensor.\nfunc (t TensorProducerTracker) RemoveRecord(tensor *TensorMeta) {\n\tdelete(t, tensor.ID)\n}\n\n// TensorConsumerTracker is a map from tensor ID to the user nodes that use the tensor.\n// If a Operator's input tensors contains tensor t1, then this Operator is one of t1's consumers.\ntype TensorConsumerTracker map[int][]Operator\n\n// GetConsumers returns all nodes that use the given tensor as input.\n// Returns nil if the tensor has no recorded user nodes.\nfunc (t TensorConsumerTracker) GetConsumers(tensor *TensorMeta) []Operator {\n\tnodes, ok := t[tensor.ID]\n\tif !ok {\n\t\treturn nil\n\t}\n\treturn nodes\n}\n\n// AddConsumer records that the given node uses the specified tensor as input.\nfunc (t TensorConsumerTracker) AddConsumer(tensor *TensorMeta, node Operator) {\n\tnodes := t[tensor.ID]\n\tif slices.Contains(nodes, node) {\n\t\treturn\n\t}\n\tt[tensor.ID] = append(nodes, node)\n}\n\n// RemoveRecord removes all consumer operator records for the given tensor.\nfunc (t TensorConsumerTracker) RemoveRecord(tensor *TensorMeta) {\n\tdelete(t, tensor.ID)\n}\n\n// UsedAsFilterMask returns true if the tensor is used as a filter mask\n// in any OperatorFilter.\n// This is useful for applying the security relaxation 'RevealFilterMask'\nfunc (t TensorConsumerTracker) UsedAsFilterMask(tensor *TensorMeta) bool {\n\tnodes := t.GetConsumers(tensor)\n\tfor _, node := range nodes {\n\t\tif filter, ok := node.(*OperatorFilter); ok {\n\t\t\tif filter.mask.ID == tensor.ID {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/tensor_tracker_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTensorProducerTracker(t *testing.T) {\n\ttensor1 := &TensorMeta{ID: 1}\n\ttensor2 := &TensorMeta{ID: 2}\n\n\t// Create a node using existing OperatorConstant\n\tnode := &OperatorConstant{output: tensor1}\n\n\ttracker := make(TensorProducerTracker)\n\n\t// Test SetProducer\n\ttracker.SetProducer(tensor1, node)\n\n\t// Test GetProducer - success\n\tretrievedNode, err := tracker.GetProducer(tensor1)\n\tassert.NoError(t, err)\n\tassert.Equal(t, node, retrievedNode)\n\n\t// Test GetProducer - not found\n\tretrievedNode, err = tracker.GetProducer(tensor2)\n\tassert.Error(t, err)\n\tassert.Nil(t, retrievedNode)\n\n\t// Test RemoveRecord\n\ttracker.RemoveRecord(tensor1)\n\tretrievedNode, err = tracker.GetProducer(tensor1)\n\tassert.Error(t, err)\n\tassert.Nil(t, retrievedNode)\n}\n\nfunc TestTensorConsumerTracker(t *testing.T) {\n\ttensor1 := &TensorMeta{ID: 1}\n\ttensor2 := &TensorMeta{ID: 2}\n\n\t// Create mock nodes\n\tmockNode1 := &OperatorConstant{output: tensor1}\n\tmockNode2 := &OperatorConstant{output: tensor2}\n\tmockFilterNode := &OperatorFilter{mask: tensor1}\n\n\ttracker := make(TensorConsumerTracker)\n\n\t// Test AddConsumer and GetConsumers - single node\n\ttracker.AddConsumer(tensor1, mockNode1)\n\tnodes := tracker.GetConsumers(tensor1)\n\tassert.Len(t, nodes, 1)\n\tassert.Equal(t, mockNode1, nodes[0])\n\n\t// Test AddConsumer - duplicate (should be ignored)\n\ttracker.AddConsumer(tensor1, mockNode1)\n\tnodes = tracker.GetConsumers(tensor1)\n\tassert.Len(t, nodes, 1)\n\n\t// Test AddConsumer - multiple nodes\n\ttracker.AddConsumer(tensor1, mockNode2)\n\tnodes = tracker.GetConsumers(tensor1)\n\tassert.Len(t, nodes, 2)\n\n\t// Test GetConsumers - not found\n\tnodes = tracker.GetConsumers(tensor2)\n\tassert.Nil(t, nodes)\n\n\t// Test UsedAsFilterMask - true\n\ttracker.AddConsumer(tensor1, mockFilterNode)\n\tassert.True(t, tracker.UsedAsFilterMask(tensor1))\n\n\t// Test UsedAsFilterMask - false\n\tassert.False(t, tracker.UsedAsFilterMask(tensor2))\n\n\t// Test RemoveRecord\n\ttracker.RemoveRecord(tensor1)\n\tnodes = tracker.GetConsumers(tensor1)\n\tassert.Nil(t, nodes)\n\tassert.False(t, tracker.UsedAsFilterMask(tensor1))\n}\n\nfunc TestUsedAsFilterMask(t *testing.T) {\n\ttensor := &TensorMeta{ID: 1}\n\totherTensor := &TensorMeta{ID: 2}\n\n\t// Create nodes\n\tconstantNode := &OperatorConstant{output: tensor}\n\tfilterNode := &OperatorFilter{mask: tensor}\n\n\ttracker := make(TensorConsumerTracker)\n\n\t// Test with constant node only\n\ttracker.AddConsumer(tensor, constantNode)\n\tassert.False(t, tracker.UsedAsFilterMask(tensor))\n\n\t// Test with filter node\n\ttracker.AddConsumer(tensor, filterNode)\n\tassert.True(t, tracker.UsedAsFilterMask(tensor))\n\n\t// Test with non-filter node type\n\tassert.False(t, tracker.UsedAsFilterMask(otherTensor))\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/test_execution_graph_input.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\ntype testConf struct {\n\tgroupThreshold   int\n\tbatched          bool\n\trevealGroupCount bool\n}\n\ntype sPair struct {\n\tsql           string\n\tdotGraph      string\n\tbriefPipeline string\n\tconf          testConf\n}\n\nvar executionGraphTestCases = []sPair{\n\t{`select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2;,table_refs:[alice.tbl_1 alice.tbl_2],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_3,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_3:{plain_float_0:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select alice.plain_datetime_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on bob.join_string_0 = alice.encrypt_string_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select alice.encrypt_string_0,alice.plain_datetime_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'bob'.'join_string_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_5,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_5,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"publish_result:{in:[In:{t_4,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{encrypt_string_0:PRIVATE:STRING}\"]\n0 -> 3 [label = \"t_2:{plain_datetime_0:PRIVATE:DATETIME}\"]\n1 -> 2 [label = \"t_3:{join_string_0:PRIVATE:STRING}\"]\n2 -> 3 [label = \"t_5:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_4:{plain_datetime_0:PRIVATE:DATETIME}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 publish_result_4]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ABS(ta.plain_int_0) AS abs_out,\n\tCEIL(ta.plain_int_0) AS ceil_out,\n\tFLOOR(ta.plain_int_0) AS floor_out,\n\tROUND(ta.plain_int_0) AS round_out,\n\tRADIANS(ta.plain_int_0) AS radians_out,\n\tDEGREES(ta.plain_int_0) AS degrees_out,\n\tLN(ta.plain_int_0) AS ln_out,\n\tLOG10(ta.plain_int_0) AS log10_out,\n\tLOG2(ta.plain_int_0) AS log2_out,\n\tSQRT(ta.plain_int_0) AS sqrt_out,\n\tEXP(ta.plain_int_0) AS exp_out\n\tFROM alice.tbl_0 as ta INNER JOIN bob.tbl_0 as tb\n\tON ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_16,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_16,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"Abs:{in:[In:{t_4,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n5 [label=\"Ceil:{in:[In:{t_4,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n6 [label=\"Floor:{in:[In:{t_4,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n7 [label=\"Round:{in:[In:{t_4,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n8 [label=\"Radians:{in:[In:{t_4,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n9 [label=\"Degrees:{in:[In:{t_4,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n10 [label=\"Ln:{in:[In:{t_4,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n11 [label=\"Log10:{in:[In:{t_4,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n12 [label=\"Log2:{in:[In:{t_4,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n13 [label=\"Sqrt:{in:[In:{t_4,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n14 [label=\"Exp:{in:[In:{t_4,},],out:[Out:{t_15,},],attr:[],party:[alice,]}\"]\n15 [label=\"publish_result:{in:[In:{t_5,t_6,t_7,t_8,t_9,t_10,t_11,t_12,t_13,t_14,t_15,},],out:[Out:{t_17,t_18,t_19,t_20,t_21,t_22,t_23,t_24,t_25,t_26,t_27,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n10 -> 15 [label = \"t_11:{ln_out:PRIVATE:FLOAT64}\"]\n11 -> 15 [label = \"t_12:{log10_out:PRIVATE:FLOAT64}\"]\n12 -> 15 [label = \"t_13:{log2_out:PRIVATE:FLOAT64}\"]\n13 -> 15 [label = \"t_14:{sqrt_out:PRIVATE:FLOAT64}\"]\n14 -> 15 [label = \"t_15:{exp_out:PRIVATE:FLOAT64}\"]\n2 -> 3 [label = \"t_16:{left_index:PRIVATE:INT64}\"]\n3 -> 10 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 11 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 12 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 13 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 14 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 9 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 15 [label = \"t_5:{abs_out:PRIVATE:INT64}\"]\n5 -> 15 [label = \"t_6:{ceil_out:PRIVATE:INT64}\"]\n6 -> 15 [label = \"t_7:{floor_out:PRIVATE:INT64}\"]\n7 -> 15 [label = \"t_8:{round_out:PRIVATE:INT64}\"]\n8 -> 15 [label = \"t_9:{radians_out:PRIVATE:FLOAT64}\"]\n9 -> 15 [label = \"t_10:{degrees_out:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 Abs_4 Ceil_5 Floor_6 Round_7 Radians_8 Degrees_9 Ln_10 Log10_11 Log2_12 Sqrt_13 Exp_14 publish_result_15]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT RANK() OVER(PARTITION BY ta.plain_int_0 ORDER BY ta.plain_float_0 DESC) AS r1, PERCENT_RANK() OVER(PARTITION BY ta.plain_int_0 ORDER BY ta.plain_float_0 DESC) AS r2, ROW_NUMBER() OVER(PARTITION BY ta.plain_int_0 ORDER BY ta.plain_float_0 DESC) AS r3 FROM alice.tbl_0 AS ta`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_11,t_12,t_10,},],attr:[sql:select t_0.expr_125 as r1,percent_rank() over (partition by t_0.r1 order by t_0.r2 desc) as r2,t_0.r3 from (select t_0.r1,t_0.r2,t_0.r3,rank() over (partition by t_0.r1 order by t_0.r2 desc) as expr_125 from (select ta.plain_int_0 as r1,ta.plain_float_0 as r2,row_number() over (partition by ta.plain_int_0 order by ta.plain_float_0 desc) as r3 from alice.tbl_0 as ta) as t_0) as t_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_11,t_12,t_10,},],out:[Out:{t_13,t_14,t_15,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_10:{row_number:PRIVATE:INT64}\"]\n0 -> 1 [label = \"t_11:{rank:PRIVATE:INT64}\"]\n0 -> 1 [label = \"t_12:{percent_rank:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.rank_int_0, rank() over (partition by ta.rank_int_0 order by tb.rank_float_0, tb.rank_float_1) as rank_num, row_number() over (partition by ta.rank_int_0 order by tb.rank_float_0, tb.rank_float_1) as row_number_num\nFROM alice.tbl_0 as ta JOIN bob.tbl_0 as tb ON ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.rank_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,t_5,},],attr:[sql:select 'tb'.'join_int_0','tb'.'rank_float_0','tb'.'rank_float_1' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_16,},RightJoinIndex:{t_17,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_16,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,t_5,},RowsIndexFilter:{t_17,},],out:[Out:{t_7,t_8,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_18,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_7,},],out:[Out:{t_19,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"make_share:{in:[In:{t_8,},],out:[Out:{t_20,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"sort:{in:[In:{t_18,t_19,t_20,t_18,t_19,t_20,},Key:{t_18,t_19,t_20,},],out:[Out:{t_21,t_22,t_23,t_9,t_10,t_11,},],attr:[reverse:[false false false],],party:[alice,bob,]}\"]\n9 [label=\"oblivious_group_mark:{in:[Key:{t_21,},],out:[Group:{t_24,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"count:{in:[Group:{t_24,},In:{t_24,},],out:[Out:{t_12,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"sort:{in:[In:{t_9,t_10,t_11,t_9,t_12,},Key:{t_9,t_10,t_11,},],out:[Out:{t_25,t_26,t_27,t_13,t_14,},],attr:[reverse:[false false false],],party:[alice,bob,]}\"]\n12 [label=\"oblivious_group_mark:{in:[Key:{t_25,},],out:[Group:{t_28,},],attr:[],party:[alice,bob,]}\"]\n13 [label=\"oblivious_group_mark:{in:[Key:{t_25,t_26,t_27,},],out:[Group:{t_29,},],attr:[],party:[alice,bob,]}\"]\n14 [label=\"rank:{in:[Group:{t_28,},In:{t_29,},],out:[Out:{t_15,},],attr:[],party:[alice,bob,]}\"]\n15 [label=\"make_private:{in:[In:{t_13,},],out:[Out:{t_30,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n16 [label=\"make_private:{in:[In:{t_15,},],out:[Out:{t_31,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n17 [label=\"make_private:{in:[In:{t_14,},],out:[Out:{t_32,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n18 [label=\"publish_result:{in:[In:{t_30,t_31,t_32,},],out:[Out:{t_33,t_34,t_35,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{rank_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{rank_float_0:PRIVATE:FLOAT64}\"]\n1 -> 4 [label = \"t_5:{rank_float_1:PRIVATE:FLOAT64}\"]\n10 -> 11 [label = \"t_12:{row_number:SECRET:INT64}\"]\n11 -> 12 [label = \"t_25:{rank_int_0:SECRET:INT64}\"]\n11 -> 13 [label = \"t_25:{rank_int_0:SECRET:INT64}\"]\n11 -> 13 [label = \"t_26:{rank_float_0:SECRET:FLOAT64}\"]\n11 -> 13 [label = \"t_27:{rank_float_1:SECRET:FLOAT64}\"]\n11 -> 15 [label = \"t_13:{rank_int_0:SECRET:INT64}\"]\n11 -> 17 [label = \"t_14:{row_number:SECRET:INT64}\"]\n12 -> 14 [label = \"t_28:{group_mark:SECRET:BOOL}\"]\n13 -> 14 [label = \"t_29:{order_mark:SECRET:BOOL}\"]\n14 -> 16 [label = \"t_15:{rank:SECRET:INT64}\"]\n15 -> 18 [label = \"t_30:{rank_int_0:PRIVATE:INT64}\"]\n16 -> 18 [label = \"t_31:{rank:PRIVATE:INT64}\"]\n17 -> 18 [label = \"t_32:{row_number:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_16:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_17:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_6:{rank_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_7:{rank_float_0:PRIVATE:FLOAT64}\"]\n4 -> 7 [label = \"t_8:{rank_float_1:PRIVATE:FLOAT64}\"]\n5 -> 8 [label = \"t_18:{rank_int_0:SECRET:INT64}\"]\n5 -> 8 [label = \"t_18:{rank_int_0:SECRET:INT64}\"]\n5 -> 8 [label = \"t_18:{rank_int_0:SECRET:INT64}\"]\n6 -> 8 [label = \"t_19:{rank_float_0:SECRET:FLOAT64}\"]\n6 -> 8 [label = \"t_19:{rank_float_0:SECRET:FLOAT64}\"]\n6 -> 8 [label = \"t_19:{rank_float_0:SECRET:FLOAT64}\"]\n7 -> 8 [label = \"t_20:{rank_float_1:SECRET:FLOAT64}\"]\n7 -> 8 [label = \"t_20:{rank_float_1:SECRET:FLOAT64}\"]\n7 -> 8 [label = \"t_20:{rank_float_1:SECRET:FLOAT64}\"]\n8 -> 11 [label = \"t_10:{rank_float_0:SECRET:FLOAT64}\"]\n8 -> 11 [label = \"t_10:{rank_float_0:SECRET:FLOAT64}\"]\n8 -> 11 [label = \"t_11:{rank_float_1:SECRET:FLOAT64}\"]\n8 -> 11 [label = \"t_11:{rank_float_1:SECRET:FLOAT64}\"]\n8 -> 11 [label = \"t_9:{rank_int_0:SECRET:INT64}\"]\n8 -> 11 [label = \"t_9:{rank_int_0:SECRET:INT64}\"]\n8 -> 11 [label = \"t_9:{rank_int_0:SECRET:INT64}\"]\n8 -> 9 [label = \"t_21:{rank_int_0:SECRET:INT64}\"]\n9 -> 10 [label = \"t_24:{group_mark:SECRET:BOOL}\"]\n9 -> 10 [label = \"t_24:{group_mark:SECRET:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 make_share_7 sort_8 oblivious_group_mark_9 count_10 sort_11 oblivious_group_mark_12 oblivious_group_mark_13 rank_14 make_private_15 make_private_16 make_private_17 publish_result_18]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT rank() OVER(PARTITION BY ta.rank_int_0 ORDER BY tb.rank_int_0) FROM alice.tbl_0 as ta JOIN bob.tbl_0 as tb ON ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.rank_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'join_int_0','tb'.'rank_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_8,},RightJoinIndex:{t_9,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_8,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_9,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_10,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_11,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"sort:{in:[In:{t_10,t_11,},Key:{t_10,t_11,},],out:[Out:{t_12,t_13,},],attr:[reverse:[false false],],party:[alice,bob,]}\"]\n8 [label=\"oblivious_group_mark:{in:[Key:{t_12,},],out:[Group:{t_14,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"oblivious_group_mark:{in:[Key:{t_12,t_13,},],out:[Group:{t_15,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"rank:{in:[Group:{t_14,},In:{t_15,},],out:[Out:{t_7,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"make_private:{in:[In:{t_7,},],out:[Out:{t_16,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n12 [label=\"publish_result:{in:[In:{t_16,},],out:[Out:{t_17,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{rank_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{rank_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_7:{rank:SECRET:INT64}\"]\n11 -> 12 [label = \"t_16:{rank:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_8:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_9:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_5:{rank_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_6:{rank_int_0:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_10:{rank_int_0:SECRET:INT64}\"]\n5 -> 7 [label = \"t_10:{rank_int_0:SECRET:INT64}\"]\n6 -> 7 [label = \"t_11:{rank_int_0:SECRET:INT64}\"]\n6 -> 7 [label = \"t_11:{rank_int_0:SECRET:INT64}\"]\n7 -> 8 [label = \"t_12:{rank_int_0:SECRET:INT64}\"]\n7 -> 9 [label = \"t_12:{rank_int_0:SECRET:INT64}\"]\n7 -> 9 [label = \"t_13:{rank_int_0:SECRET:INT64}\"]\n8 -> 10 [label = \"t_14:{group_mark:SECRET:BOOL}\"]\n9 -> 10 [label = \"t_15:{order_mark:SECRET:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 sort_7 oblivious_group_mark_8 oblivious_group_mark_9 rank_10 make_private_11 publish_result_12]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT rank() OVER(PARTITION BY ta.join_int_0 ORDER BY ta.plain_int_0) FROM alice.tbl_0 as ta JOIN bob.tbl_0 as tb ON ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_7,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_7,},],out:[Out:{t_4,t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"private_group:{in:[Key:{t_5,},],out:[GroupId:{t_8,},GroupNum:{t_9,},],attr:[],party:[alice,]}\"]\n5 [label=\"Rank:{in:[Key:{t_4,},PartitionId:{t_8,},PartitionNum:{t_9,},],out:[Out:{t_6,},],attr:[reverse:[0],],party:[alice,]}\"]\n6 [label=\"publish_result:{in:[In:{t_6,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_7:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_8:{window_group_id:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_9:{window_group_num:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_6:{rank:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 private_group_4 Rank_5 publish_result_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT rank() OVER(PARTITION BY ta.join_int_0 ORDER BY ta.plain_int_0) FROM alice.tbl_0 as ta JOIN bob.tbl_0 as tb ON ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_7,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_7,},],out:[Out:{t_4,t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"private_group:{in:[Key:{t_5,},],out:[GroupId:{t_8,},GroupNum:{t_9,},],attr:[],party:[alice,]}\"]\n5 [label=\"Rank:{in:[Key:{t_4,},PartitionId:{t_8,},PartitionNum:{t_9,},],out:[Out:{t_6,},],attr:[reverse:[0],],party:[alice,]}\"]\n6 [label=\"publish_result:{in:[In:{t_6,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_7:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_8:{window_group_id:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_9:{window_group_num:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_6:{rank:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 private_group_4 Rank_5 publish_result_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0, ta.plain_datetime_0 from alice.tbl_0 as ta right join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0 where ta.plain_datetime_0 > str_to_date(tb.plain_string_0, '%Y-%m-%d')`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.plain_datetime_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'join_int_0','tb'.'plain_string_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_12,},RightJoinIndex:{t_13,},],attr:[input_party_codes:[alice bob],join_type:2,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_12,},],out:[Out:{t_5,t_6,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_13,},],out:[Out:{t_7,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_7,},],out:[Out:{t_14,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"arrow_func[strptime]:{in:[In:{t_14,},],out:[Out:{t_8,},],attr:[func_name:strptime,func_opt_type:StrptimeOptions,],party:[alice,]}\"]\n7 [label=\"Greater:{in:[Left:{t_6,},Right:{t_8,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n8 [label=\"filter:{in:[Filter:{t_9,},In:{t_5,t_6,},],out:[Out:{t_10,t_11,},],attr:[],party:[alice,]}\"]\n9 [label=\"publish_result:{in:[In:{t_10,t_11,},],out:[Out:{t_15,t_16,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{plain_datetime_0:PRIVATE:DATETIME}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{plain_string_0:PRIVATE:STRING}\"]\n2 -> 3 [label = \"t_12:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_13:{right_index:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_6:{plain_datetime_0:PRIVATE:DATETIME}\"]\n3 -> 8 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_6:{plain_datetime_0:PRIVATE:DATETIME}\"]\n4 -> 5 [label = \"t_7:{plain_string_0:PRIVATE:STRING}\"]\n5 -> 6 [label = \"t_14:{plain_string_0:PRIVATE:STRING}\"]\n6 -> 7 [label = \"t_8:{str_to_date_out:PRIVATE:DATETIME}\"]\n7 -> 8 [label = \"t_9:{gt_out:PRIVATE:BOOL}\"]\n8 -> 9 [label = \"t_10:{join_int_0:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_11:{plain_datetime_0:PRIVATE:DATETIME}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 arrow_func[strptime]_6 Greater_7 filter_8 publish_result_9]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.plain_timestamp_0 from alice.tbl_0 as ta where ta.plain_timestamp_0 > '2025-04-23 12:25:42'`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_5,},],attr:[sql:select ta.plain_timestamp_0 from alice.tbl_0 as ta where ta.plain_timestamp_0>'2025-04-23 12:25:42';,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_5,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_5:{plain_timestamp_0:PRIVATE:TIMESTAMP}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0, ta.plain_datetime_0 from alice.tbl_0 as ta right join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0 where ta.plain_datetime_0 > str_to_date('2025-06-05', '%Y-%m-%d')`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.plain_datetime_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_11,},RightJoinIndex:{t_12,},],attr:[input_party_codes:[alice bob],join_type:2,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_11,},],out:[Out:{t_4,t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"constant:{in:[],out:[Out:{t_6,},],attr:[scalar:1749081600,to_status:1,],party:[alice,bob,]}\"]\n5 [label=\"broadcast_to:{in:[In:{t_6,},ShapeRefTensor:{t_5,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n6 [label=\"Greater:{in:[Left:{t_5,},Right:{t_7,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n7 [label=\"filter:{in:[Filter:{t_8,},In:{t_4,t_5,},],out:[Out:{t_9,t_10,},],attr:[],party:[alice,]}\"]\n8 [label=\"publish_result:{in:[In:{t_9,t_10,},],out:[Out:{t_13,t_14,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{plain_datetime_0:PRIVATE:DATETIME}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_11:{left_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_5:{plain_datetime_0:PRIVATE:DATETIME}\"]\n3 -> 6 [label = \"t_5:{plain_datetime_0:PRIVATE:DATETIME}\"]\n3 -> 7 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_5:{plain_datetime_0:PRIVATE:DATETIME}\"]\n4 -> 5 [label = \"t_6:{constant_data:PUBLIC:DATETIME}\"]\n5 -> 6 [label = \"t_7:{constant_data:PRIVATE:DATETIME}\"]\n6 -> 7 [label = \"t_8:{gt_out:PRIVATE:BOOL}\"]\n7 -> 8 [label = \"t_10:{plain_datetime_0:PRIVATE:DATETIME}\"]\n7 -> 8 [label = \"t_9:{join_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 constant_4 broadcast_to_5 Greater_6 filter_7 publish_result_8]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0, ta.plain_datetime_0 from alice.tbl_0 as ta right join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0 where ta.plain_datetime_0 between '2025-04-23 12:25:42' and '2025-05-29 15:36:36'`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.plain_datetime_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_15,},RightJoinIndex:{t_16,},],attr:[input_party_codes:[alice bob],join_type:2,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_15,},],out:[Out:{t_4,t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"constant:{in:[],out:[Out:{t_6,},],attr:[scalar:2025-04-23 12:25:42,to_status:1,],party:[alice,bob,]}\"]\n5 [label=\"make_private:{in:[In:{t_6,},],out:[Out:{t_17,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n6 [label=\"Cast:{in:[In:{t_17,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n7 [label=\"GreaterEqual:{in:[Left:{t_5,},Right:{t_7,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n8 [label=\"constant:{in:[],out:[Out:{t_9,},],attr:[scalar:2025-05-29 15:36:36,to_status:1,],party:[alice,bob,]}\"]\n9 [label=\"make_private:{in:[In:{t_9,},],out:[Out:{t_18,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n10 [label=\"Cast:{in:[In:{t_18,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n11 [label=\"LessEqual:{in:[Left:{t_5,},Right:{t_10,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n12 [label=\"LogicalAnd:{in:[Left:{t_8,},Right:{t_11,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n13 [label=\"filter:{in:[Filter:{t_12,},In:{t_4,t_5,},],out:[Out:{t_13,t_14,},],attr:[],party:[alice,]}\"]\n14 [label=\"publish_result:{in:[In:{t_13,t_14,},],out:[Out:{t_19,t_20,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{plain_datetime_0:PRIVATE:DATETIME}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_10:{plain_datetime_0:PRIVATE:DATETIME}\"]\n11 -> 12 [label = \"t_11:{le_out:PRIVATE:BOOL}\"]\n12 -> 13 [label = \"t_12:{and_out:PRIVATE:BOOL}\"]\n13 -> 14 [label = \"t_13:{join_int_0:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_14:{plain_datetime_0:PRIVATE:DATETIME}\"]\n2 -> 3 [label = \"t_15:{left_index:PRIVATE:INT64}\"]\n3 -> 11 [label = \"t_5:{plain_datetime_0:PRIVATE:DATETIME}\"]\n3 -> 13 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n3 -> 13 [label = \"t_5:{plain_datetime_0:PRIVATE:DATETIME}\"]\n3 -> 7 [label = \"t_5:{plain_datetime_0:PRIVATE:DATETIME}\"]\n4 -> 5 [label = \"t_6:{constant_data:PUBLIC:STRING}\"]\n5 -> 6 [label = \"t_17:{constant_data:PRIVATE:STRING}\"]\n6 -> 7 [label = \"t_7:{plain_datetime_0:PRIVATE:DATETIME}\"]\n7 -> 12 [label = \"t_8:{ge_out:PRIVATE:BOOL}\"]\n8 -> 9 [label = \"t_9:{constant_data:PUBLIC:STRING}\"]\n9 -> 10 [label = \"t_18:{constant_data:PRIVATE:STRING}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 constant_4 make_private_5 Cast_6 GreaterEqual_7 constant_8 make_private_9 Cast_10 LessEqual_11 LogicalAnd_12 filter_13 publish_result_14]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0, ta.plain_datetime_0 from alice.tbl_0 as ta right join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0 where ta.plain_datetime_0 > '2025-04-23 12:25:42'`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.plain_datetime_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_11,},RightJoinIndex:{t_12,},],attr:[input_party_codes:[alice bob],join_type:2,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_11,},],out:[Out:{t_4,t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"constant:{in:[],out:[Out:{t_6,},],attr:[scalar:2025-04-23 12:25:42,to_status:1,],party:[alice,bob,]}\"]\n5 [label=\"make_private:{in:[In:{t_6,},],out:[Out:{t_13,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n6 [label=\"Cast:{in:[In:{t_13,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n7 [label=\"Greater:{in:[Left:{t_5,},Right:{t_7,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n8 [label=\"filter:{in:[Filter:{t_8,},In:{t_4,t_5,},],out:[Out:{t_9,t_10,},],attr:[],party:[alice,]}\"]\n9 [label=\"publish_result:{in:[In:{t_9,t_10,},],out:[Out:{t_14,t_15,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{plain_datetime_0:PRIVATE:DATETIME}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_11:{left_index:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_5:{plain_datetime_0:PRIVATE:DATETIME}\"]\n3 -> 8 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_5:{plain_datetime_0:PRIVATE:DATETIME}\"]\n4 -> 5 [label = \"t_6:{constant_data:PUBLIC:STRING}\"]\n5 -> 6 [label = \"t_13:{constant_data:PRIVATE:STRING}\"]\n6 -> 7 [label = \"t_7:{plain_datetime_0:PRIVATE:DATETIME}\"]\n7 -> 8 [label = \"t_8:{gt_out:PRIVATE:BOOL}\"]\n8 -> 9 [label = \"t_10:{plain_datetime_0:PRIVATE:DATETIME}\"]\n8 -> 9 [label = \"t_9:{join_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 constant_4 make_private_5 Cast_6 Greater_7 filter_8 publish_result_9]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT PERCENTILE_DISC(u.int_0, 0.3) AS _30percent FROM (SELECT ta.plain_int_0 as int_0 FROM alice.tbl_0 AS ta UNION ALL SELECT tb.plain_int_0 as int_0 FROM bob.tbl_0 AS tb) as u`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"make_share:{in:[In:{t_1,},],out:[Out:{t_5,},],attr:[],party:[alice,bob,]}\"]\n3 [label=\"make_share:{in:[In:{t_2,},],out:[Out:{t_6,},],attr:[],party:[alice,bob,]}\"]\n4 [label=\"concat:{in:[In:{t_5,t_6,},],out:[Out:{t_3,},],attr:[axis:0,],party:[alice,bob,]}\"]\n5 [label=\"make_private:{in:[In:{t_3,},],out:[Out:{t_7,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n6 [label=\"reduce[percentile_disc]:{in:[In:{t_7,},],out:[Out:{t_4,},],attr:[percent:0.3,],party:[alice,]}\"]\n7 [label=\"publish_result:{in:[In:{t_4,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_5:{plain_int_0:SECRET:INT64}\"]\n3 -> 4 [label = \"t_6:{plain_int_0:SECRET:INT64}\"]\n4 -> 5 [label = \"t_3:{plain_int_0:SECRET:INT64}\"]\n5 -> 6 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_4:{plain_int_0_percentile_disc:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 make_share_2 make_share_3 concat_4 make_private_5 reduce[percentile_disc]_6 publish_result_7]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT PERCENTILE_DISC(ta.plain_int_0, 0.3) AS _30percent_plain_int FROM alice.tbl_0 AS ta JOIN bob.tbl_0 AS tb ON ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_6,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_6,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"reduce[percentile_disc]:{in:[In:{t_4,},],out:[Out:{t_5,},],attr:[percent:0.3,],party:[alice,]}\"]\n5 [label=\"publish_result:{in:[In:{t_5,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_6:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_5:{plain_int_0_percentile_disc:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 reduce[percentile_disc]_4 publish_result_5]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.groupby_string_0,tb.groupby_string_0, percentile_disc(ta.aggregate_int_0, 0.5) _50percent from alice.tbl_0 AS ta JOIN bob.tbl_0 AS tb ON ta.join_int_0 = tb.join_int_0 group by ta.groupby_string_0,tb.groupby_string_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,t_3,},],attr:[sql:select ta.join_int_0,ta.aggregate_int_0,ta.groupby_string_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,t_5,},],attr:[sql:select 'tb'.'join_int_0','tb'.'groupby_string_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_4,},],out:[LeftJoinIndex:{t_20,},RightJoinIndex:{t_21,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,t_3,},RowsIndexFilter:{t_20,},],out:[Out:{t_6,t_7,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_5,},RowsIndexFilter:{t_21,},],out:[Out:{t_8,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_7,},],out:[Out:{t_22,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_8,},],out:[Out:{t_23,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_24,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"sort:{in:[In:{t_22,t_23,t_24,t_22,t_23,},Key:{t_22,t_23,},],out:[Out:{t_25,t_26,t_27,t_28,t_29,},],attr:[reverse:[false false],],party:[alice,bob,]}\"]\n9 [label=\"oblivious_group_mark:{in:[Key:{t_25,t_26,},],out:[Group:{t_30,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"count:{in:[Group:{t_30,},In:{t_30,},],out:[Out:{t_31,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"sort:{in:[In:{t_27,},Key:{t_25,t_26,t_27,},],out:[Out:{t_32,},],attr:[reverse:[false false false],],party:[alice,bob,]}\"]\n12 [label=\"percentile_disc:{in:[Group:{t_30,},In:{t_32,},],out:[Out:{t_33,},],attr:[percent:0.5,],party:[alice,bob,]}\"]\n13 [label=\"shuffle:{in:[In:{t_31,t_33,t_28,t_29,t_30,},],out:[Out:{t_34,t_35,t_36,t_37,t_38,},],attr:[],party:[alice,bob,]}\"]\n14 [label=\"make_public:{in:[In:{t_38,},],out:[Out:{t_39,},],attr:[],party:[alice,bob,]}\"]\n15 [label=\"filter:{in:[Filter:{t_39,},In:{t_34,t_35,t_36,t_37,},],out:[Out:{t_12,t_9,t_10,t_11,},],attr:[],party:[alice,bob,]}\"]\n16 [label=\"constant:{in:[],out:[Out:{t_13,},],attr:[scalar:4,to_status:1,],party:[alice,bob,]}\"]\n17 [label=\"broadcast_to:{in:[In:{t_13,},ShapeRefTensor:{t_12,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,]}\"]\n18 [label=\"GreaterEqual:{in:[Left:{t_12,},Right:{t_14,},],out:[Out:{t_15,},],attr:[],party:[alice,bob,]}\"]\n19 [label=\"make_public:{in:[In:{t_15,},],out:[Out:{t_40,},],attr:[],party:[alice,bob,]}\"]\n20 [label=\"filter:{in:[Filter:{t_40,},In:{t_9,t_10,t_11,t_12,},],out:[Out:{t_16,t_17,t_18,t_19,},],attr:[],party:[alice,bob,]}\"]\n21 [label=\"make_public:{in:[In:{t_17,},],out:[Out:{t_41,},],attr:[],party:[alice,bob,]}\"]\n22 [label=\"make_private:{in:[In:{t_41,},],out:[Out:{t_42,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n23 [label=\"make_public:{in:[In:{t_18,},],out:[Out:{t_43,},],attr:[],party:[alice,bob,]}\"]\n24 [label=\"make_private:{in:[In:{t_43,},],out:[Out:{t_44,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n25 [label=\"make_private:{in:[In:{t_16,},],out:[Out:{t_45,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n26 [label=\"publish_result:{in:[In:{t_42,t_44,t_45,},],out:[Out:{t_46,t_47,t_48,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{aggregate_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{groupby_string_0:PRIVATE:STRING}\"]\n1 -> 2 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_5:{groupby_string_0:PRIVATE:STRING}\"]\n10 -> 13 [label = \"t_31:{aggregated_group_simple_count:SECRET:INT64}\"]\n11 -> 12 [label = \"t_32:{aggregate_int_0:SECRET:INT64}\"]\n12 -> 13 [label = \"t_33:{aggregate_int_0_percentile_disc:SECRET:INT64}\"]\n13 -> 14 [label = \"t_38:{group_mark:SECRET:BOOL}\"]\n13 -> 15 [label = \"t_34:{aggregated_group_simple_count:SECRET:INT64}\"]\n13 -> 15 [label = \"t_35:{aggregate_int_0_percentile_disc:SECRET:INT64}\"]\n13 -> 15 [label = \"t_36:{groupby_string_0:SECRET:STRING}\"]\n13 -> 15 [label = \"t_37:{groupby_string_0:SECRET:STRING}\"]\n14 -> 15 [label = \"t_39:{group_mark:PUBLIC:BOOL}\"]\n15 -> 17 [label = \"t_12:{simple_count_result:SECRET:INT64}\"]\n15 -> 18 [label = \"t_12:{simple_count_result:SECRET:INT64}\"]\n15 -> 20 [label = \"t_10:{groupby_string_0_firstrow:SECRET:STRING}\"]\n15 -> 20 [label = \"t_11:{groupby_string_0_firstrow:SECRET:STRING}\"]\n15 -> 20 [label = \"t_12:{simple_count_result:SECRET:INT64}\"]\n15 -> 20 [label = \"t_9:{aggregate_int_0_percentile_disc:SECRET:INT64}\"]\n16 -> 17 [label = \"t_13:{constant_data:PUBLIC:INT64}\"]\n17 -> 18 [label = \"t_14:{constant_data:PUBLIC:INT64}\"]\n18 -> 19 [label = \"t_15:{ge_out:SECRET:BOOL}\"]\n19 -> 20 [label = \"t_40:{ge_out:PUBLIC:BOOL}\"]\n2 -> 3 [label = \"t_20:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_21:{right_index:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_17:{groupby_string_0_firstrow:SECRET:STRING}\"]\n20 -> 23 [label = \"t_18:{groupby_string_0_firstrow:SECRET:STRING}\"]\n20 -> 25 [label = \"t_16:{aggregate_int_0_percentile_disc:SECRET:INT64}\"]\n21 -> 22 [label = \"t_41:{groupby_string_0_firstrow:PUBLIC:STRING}\"]\n22 -> 26 [label = \"t_42:{groupby_string_0_firstrow:PRIVATE:STRING}\"]\n23 -> 24 [label = \"t_43:{groupby_string_0_firstrow:PUBLIC:STRING}\"]\n24 -> 26 [label = \"t_44:{groupby_string_0_firstrow:PRIVATE:STRING}\"]\n25 -> 26 [label = \"t_45:{aggregate_int_0_percentile_disc:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_7:{groupby_string_0:PRIVATE:STRING}\"]\n3 -> 7 [label = \"t_6:{aggregate_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_8:{groupby_string_0:PRIVATE:STRING}\"]\n5 -> 8 [label = \"t_22:{groupby_string_0:SECRET:STRING}\"]\n5 -> 8 [label = \"t_22:{groupby_string_0:SECRET:STRING}\"]\n5 -> 8 [label = \"t_22:{groupby_string_0:SECRET:STRING}\"]\n6 -> 8 [label = \"t_23:{groupby_string_0:SECRET:STRING}\"]\n6 -> 8 [label = \"t_23:{groupby_string_0:SECRET:STRING}\"]\n6 -> 8 [label = \"t_23:{groupby_string_0:SECRET:STRING}\"]\n7 -> 8 [label = \"t_24:{aggregate_int_0:SECRET:INT64}\"]\n8 -> 11 [label = \"t_25:{groupby_string_0:SECRET:STRING}\"]\n8 -> 11 [label = \"t_26:{groupby_string_0:SECRET:STRING}\"]\n8 -> 11 [label = \"t_27:{aggregate_int_0:SECRET:INT64}\"]\n8 -> 11 [label = \"t_27:{aggregate_int_0:SECRET:INT64}\"]\n8 -> 13 [label = \"t_28:{groupby_string_0:SECRET:STRING}\"]\n8 -> 13 [label = \"t_29:{groupby_string_0:SECRET:STRING}\"]\n8 -> 9 [label = \"t_25:{groupby_string_0:SECRET:STRING}\"]\n8 -> 9 [label = \"t_26:{groupby_string_0:SECRET:STRING}\"]\n9 -> 10 [label = \"t_30:{group_mark:SECRET:BOOL}\"]\n9 -> 10 [label = \"t_30:{group_mark:SECRET:BOOL}\"]\n9 -> 12 [label = \"t_30:{group_mark:SECRET:BOOL}\"]\n9 -> 13 [label = \"t_30:{group_mark:SECRET:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 make_share_7 sort_8 oblivious_group_mark_9 count_10 sort_11 percentile_disc_12 shuffle_13 make_public_14 filter_15 constant_16 broadcast_to_17 GreaterEqual_18 make_public_19 filter_20 make_public_21 make_private_22 make_public_23 make_private_24 make_private_25 publish_result_26]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0, PERCENTILE_DISC(ta.plain_int_0, 0.3) AS _30percent_plain_int FROM alice.tbl_0 AS ta JOIN bob.tbl_0 AS tb ON ta.join_int_0 = tb.join_int_0 GROUP BY ta.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_15,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_15,},],out:[Out:{t_4,t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"private_group:{in:[Key:{t_5,},],out:[GroupId:{t_16,},GroupNum:{t_17,},],attr:[],party:[alice,]}\"]\n5 [label=\"count:{in:[GroupId:{t_16,},GroupNum:{t_17,},In:{t_16,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n6 [label=\"percentile_disc:{in:[GroupId:{t_16,},GroupNum:{t_17,},In:{t_4,},],out:[Out:{t_6,},],attr:[percent:0.3,],party:[alice,]}\"]\n7 [label=\"firstrow:{in:[GroupId:{t_16,},GroupNum:{t_17,},In:{t_5,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n8 [label=\"constant:{in:[],out:[Out:{t_9,},],attr:[scalar:4,to_status:1,],party:[alice,bob,]}\"]\n9 [label=\"broadcast_to:{in:[In:{t_9,},ShapeRefTensor:{t_8,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n10 [label=\"GreaterEqual:{in:[Left:{t_8,},Right:{t_10,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n11 [label=\"filter:{in:[Filter:{t_11,},In:{t_6,t_7,t_8,},],out:[Out:{t_12,t_13,t_14,},],attr:[],party:[alice,]}\"]\n12 [label=\"publish_result:{in:[In:{t_13,t_12,},],out:[Out:{t_18,t_19,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_11:{ge_out:PRIVATE:BOOL}\"]\n11 -> 12 [label = \"t_12:{plain_int_0_percentile_disc:PRIVATE:INT64}\"]\n11 -> 12 [label = \"t_13:{join_int_0_firstrow:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_15:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_16:{group_id:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_16:{group_id:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_17:{group_num:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_16:{group_id:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_17:{group_num:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_16:{group_id:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_17:{group_num:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_8:{simple_count_result:PRIVATE:INT64}\"]\n5 -> 11 [label = \"t_8:{simple_count_result:PRIVATE:INT64}\"]\n5 -> 9 [label = \"t_8:{simple_count_result:PRIVATE:INT64}\"]\n6 -> 11 [label = \"t_6:{plain_int_0_percentile_disc:PRIVATE:INT64}\"]\n7 -> 11 [label = \"t_7:{join_int_0_firstrow:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_9:{constant_data:PUBLIC:INT64}\"]\n9 -> 10 [label = \"t_10:{constant_data:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 private_group_4 count_5 percentile_disc_6 firstrow_7 constant_8 broadcast_to_9 GreaterEqual_10 filter_11 publish_result_12]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0 FROM alice.tbl_0 AS ta JOIN bob.tbl_0 AS tb ON ta.join_int_0 = tb.join_int_0 GROUP BY ta.join_int_0 HAVING SUM(ta.plain_int_0) = ANY(SELECT ta.plain_int_0 FROM alice.tbl_0 AS ta)`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_18,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_18,},],out:[Out:{t_4,t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"private_group:{in:[Key:{t_5,},],out:[GroupId:{t_19,},GroupNum:{t_20,},],attr:[],party:[alice,]}\"]\n5 [label=\"count:{in:[GroupId:{t_19,},GroupNum:{t_20,},In:{t_19,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n6 [label=\"sum:{in:[GroupId:{t_19,},GroupNum:{t_20,},In:{t_4,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n7 [label=\"firstrow:{in:[GroupId:{t_19,},GroupNum:{t_20,},In:{t_5,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n8 [label=\"constant:{in:[],out:[Out:{t_9,},],attr:[scalar:4,to_status:1,],party:[alice,bob,]}\"]\n9 [label=\"broadcast_to:{in:[In:{t_9,},ShapeRefTensor:{t_8,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n10 [label=\"GreaterEqual:{in:[Left:{t_8,},Right:{t_10,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n11 [label=\"filter:{in:[Filter:{t_11,},In:{t_6,t_7,t_8,},],out:[Out:{t_12,t_13,t_14,},],attr:[],party:[alice,]}\"]\n12 [label=\"run_sql:{in:[],out:[Out:{t_15,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n13 [label=\"in:{in:[Left:{t_12,},Right:{t_15,},],out:[Out:{t_16,},],attr:[in_type:2,input_party_codes:[alice alice],psi_algorithm:0,reveal_to:[alice],],party:[alice,]}\"]\n14 [label=\"filter:{in:[Filter:{t_16,},In:{t_13,},],out:[Out:{t_17,},],attr:[],party:[alice,]}\"]\n15 [label=\"publish_result:{in:[In:{t_17,},],out:[Out:{t_21,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_11:{ge_out:PRIVATE:BOOL}\"]\n11 -> 13 [label = \"t_12:{plain_int_0_sum:PRIVATE:INT64}\"]\n11 -> 14 [label = \"t_13:{join_int_0_firstrow:PRIVATE:INT64}\"]\n12 -> 13 [label = \"t_15:{plain_int_0:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_16:{in_result:PRIVATE:BOOL}\"]\n14 -> 15 [label = \"t_17:{join_int_0_firstrow:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_18:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_19:{group_id:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_19:{group_id:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_20:{group_num:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_19:{group_id:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_20:{group_num:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_19:{group_id:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_20:{group_num:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_8:{simple_count_result:PRIVATE:INT64}\"]\n5 -> 11 [label = \"t_8:{simple_count_result:PRIVATE:INT64}\"]\n5 -> 9 [label = \"t_8:{simple_count_result:PRIVATE:INT64}\"]\n6 -> 11 [label = \"t_6:{plain_int_0_sum:PRIVATE:INT64}\"]\n7 -> 11 [label = \"t_7:{join_int_0_firstrow:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_9:{constant_data:PUBLIC:INT64}\"]\n9 -> 10 [label = \"t_10:{constant_data:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 private_group_4 count_5 sum_6 firstrow_7 constant_8 broadcast_to_9 GreaterEqual_10 filter_11 run_sql_12 in_13 filter_14 publish_result_15]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0 FROM alice.tbl_0 AS ta JOIN bob.tbl_0 AS tb ON ta.join_int_0 = tb.join_int_0 GROUP BY ta.join_int_0 HAVING SUM(ta.plain_int_0) > ANY(SELECT ta.plain_int_0 FROM alice.tbl_0 AS ta)`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_23,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_23,},],out:[Out:{t_4,t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"private_group:{in:[Key:{t_5,},],out:[GroupId:{t_24,},GroupNum:{t_25,},],attr:[],party:[alice,]}\"]\n5 [label=\"count:{in:[GroupId:{t_24,},GroupNum:{t_25,},In:{t_24,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n6 [label=\"sum:{in:[GroupId:{t_24,},GroupNum:{t_25,},In:{t_4,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n7 [label=\"firstrow:{in:[GroupId:{t_24,},GroupNum:{t_25,},In:{t_5,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n8 [label=\"constant:{in:[],out:[Out:{t_9,},],attr:[scalar:4,to_status:1,],party:[alice,bob,]}\"]\n9 [label=\"broadcast_to:{in:[In:{t_9,},ShapeRefTensor:{t_8,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n10 [label=\"GreaterEqual:{in:[Left:{t_8,},Right:{t_10,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n11 [label=\"filter:{in:[Filter:{t_11,},In:{t_6,t_7,t_8,},],out:[Out:{t_12,t_13,t_14,},],attr:[],party:[alice,]}\"]\n12 [label=\"run_sql:{in:[],out:[Out:{t_16,},],attr:[sql:select min(ta.plain_int_0) as expr_362 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n13 [label=\"replicate:{in:[Left:{t_12,t_13,t_14,},Right:{t_16,},],out:[LeftOut:{t_17,t_18,t_19,},RightOut:{t_20,},],attr:[input_party_codes:[alice alice],],party:[alice,alice,]}\"]\n14 [label=\"Greater:{in:[Left:{t_17,},Right:{t_20,},],out:[Out:{t_21,},],attr:[],party:[alice,]}\"]\n15 [label=\"filter:{in:[Filter:{t_21,},In:{t_18,},],out:[Out:{t_22,},],attr:[],party:[alice,]}\"]\n16 [label=\"publish_result:{in:[In:{t_22,},],out:[Out:{t_26,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_11:{ge_out:PRIVATE:BOOL}\"]\n11 -> 13 [label = \"t_12:{plain_int_0_sum:PRIVATE:INT64}\"]\n11 -> 13 [label = \"t_13:{join_int_0_firstrow:PRIVATE:INT64}\"]\n11 -> 13 [label = \"t_14:{simple_count_result:PRIVATE:INT64}\"]\n12 -> 13 [label = \"t_16:{plain_int_0_min:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_17:{plain_int_0_sum:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_20:{plain_int_0_min:PRIVATE:INT64}\"]\n13 -> 15 [label = \"t_18:{join_int_0_firstrow:PRIVATE:INT64}\"]\n14 -> 15 [label = \"t_21:{gt_out:PRIVATE:BOOL}\"]\n15 -> 16 [label = \"t_22:{join_int_0_firstrow:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_23:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_24:{group_id:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_24:{group_id:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_25:{group_num:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_24:{group_id:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_25:{group_num:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_24:{group_id:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_25:{group_num:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_8:{simple_count_result:PRIVATE:INT64}\"]\n5 -> 11 [label = \"t_8:{simple_count_result:PRIVATE:INT64}\"]\n5 -> 9 [label = \"t_8:{simple_count_result:PRIVATE:INT64}\"]\n6 -> 11 [label = \"t_6:{plain_int_0_sum:PRIVATE:INT64}\"]\n7 -> 11 [label = \"t_7:{join_int_0_firstrow:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_9:{constant_data:PUBLIC:INT64}\"]\n9 -> 10 [label = \"t_10:{constant_data:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 private_group_4 count_5 sum_6 firstrow_7 constant_8 broadcast_to_9 GreaterEqual_10 filter_11 run_sql_12 replicate_13 Greater_14 filter_15 publish_result_16]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0, PERCENT_RANK() OVER(PARTITION BY ta.rank_float_0 ORDER BY tb.rank_float_0) as rank_percent FROM alice.tbl_0 AS ta JOIN bob.tbl_0 AS tb ON ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.rank_float_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'join_int_0','tb'.'rank_float_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_10,},RightJoinIndex:{t_11,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_10,},],out:[Out:{t_5,t_6,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_11,},],out:[Out:{t_7,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_12,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_7,},],out:[Out:{t_13,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"sort:{in:[In:{t_12,t_13,t_14,},Key:{t_12,t_13,},],out:[Out:{t_15,t_16,t_8,},],attr:[reverse:[false false],],party:[alice,bob,]}\"]\n9 [label=\"oblivious_group_mark:{in:[Key:{t_15,},],out:[Group:{t_17,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"oblivious_group_mark:{in:[Key:{t_15,t_16,},],out:[Group:{t_18,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"percent_rank:{in:[Group:{t_17,},In:{t_18,},],out:[Out:{t_9,},],attr:[],party:[alice,bob,]}\"]\n12 [label=\"make_private:{in:[In:{t_8,},],out:[Out:{t_19,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n13 [label=\"make_private:{in:[In:{t_9,},],out:[Out:{t_20,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n14 [label=\"publish_result:{in:[In:{t_19,t_20,},],out:[Out:{t_21,t_22,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{rank_float_0:PRIVATE:FLOAT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{rank_float_0:PRIVATE:FLOAT64}\"]\n10 -> 11 [label = \"t_18:{order_mark:SECRET:BOOL}\"]\n11 -> 13 [label = \"t_9:{percent_rank:SECRET:FLOAT64}\"]\n12 -> 14 [label = \"t_19:{join_int_0:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_20:{percent_rank:PRIVATE:FLOAT64}\"]\n2 -> 3 [label = \"t_10:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_11:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_6:{rank_float_0:PRIVATE:FLOAT64}\"]\n3 -> 7 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_7:{rank_float_0:PRIVATE:FLOAT64}\"]\n5 -> 8 [label = \"t_12:{rank_float_0:SECRET:FLOAT64}\"]\n5 -> 8 [label = \"t_12:{rank_float_0:SECRET:FLOAT64}\"]\n6 -> 8 [label = \"t_13:{rank_float_0:SECRET:FLOAT64}\"]\n6 -> 8 [label = \"t_13:{rank_float_0:SECRET:FLOAT64}\"]\n7 -> 8 [label = \"t_14:{join_int_0:SECRET:INT64}\"]\n8 -> 10 [label = \"t_15:{rank_float_0:SECRET:FLOAT64}\"]\n8 -> 10 [label = \"t_16:{rank_float_0:SECRET:FLOAT64}\"]\n8 -> 12 [label = \"t_8:{join_int_0:SECRET:INT64}\"]\n8 -> 9 [label = \"t_15:{rank_float_0:SECRET:FLOAT64}\"]\n9 -> 11 [label = \"t_17:{group_mark:SECRET:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 make_share_7 sort_8 oblivious_group_mark_9 oblivious_group_mark_10 percent_rank_11 make_private_12 make_private_13 publish_result_14]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0, PERCENT_RANK() OVER(PARTITION BY ta.join_int_0 ORDER BY ta.plain_int_0) as rank_percent FROM alice.tbl_0 AS ta JOIN bob.tbl_0 AS tb ON ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_8,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_8,},],out:[Out:{t_4,t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"private_group:{in:[Key:{t_5,},],out:[GroupId:{t_9,},GroupNum:{t_10,},],attr:[],party:[alice,]}\"]\n5 [label=\"PercentRank:{in:[Key:{t_4,},PartitionId:{t_9,},PartitionNum:{t_10,},],out:[Out:{t_7,},],attr:[reverse:[0],],party:[alice,]}\"]\n6 [label=\"publish_result:{in:[In:{t_5,t_7,},],out:[Out:{t_11,t_12,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_8:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_10:{window_group_num:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_9:{window_group_id:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_7:{percent_rank:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 private_group_4 PercentRank_5 publish_result_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0 FROM\n\t\talice.tbl_0 AS ta INNER JOIN bob.tbl_0 AS tb\n\t\tON ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_4,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_4,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"publish_result:{in:[In:{t_3,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_4:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 publish_result_4]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.join_string_0 is null`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_5,t_6,},],attr:[sql:select alice.plain_int_0,alice.join_int_0 from alice.tbl_0 as alice where alice.join_string_0 is null;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_7,},],attr:[sql:select 'bob'.'join_int_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_6,},Right:{t_7,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_5,},RowsIndexFilter:{t_9,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n4 [label=\"publish_result:{in:[In:{t_8,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_6:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_7:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_8:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 publish_result_4]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.plain_int_0 FROM alice.tbl_0 AS ta INNER JOIN bob.tbl_0 AS tb ON ta.join_int_0 = tb.join_int_0 where ta.plain_int_0 > tb.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'plain_int_0','tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_4,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{t_10,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_9,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_3,},RowsIndexFilter:{t_10,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_6,},],out:[Out:{t_11,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"Greater:{in:[Left:{t_5,},Right:{t_11,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n7 [label=\"filter:{in:[Filter:{t_7,},In:{t_5,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n8 [label=\"publish_result:{in:[In:{t_8,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_10:{right_index:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_6:{plain_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_11:{plain_int_0:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_7:{gt_out:PRIVATE:BOOL}\"]\n7 -> 8 [label = \"t_8:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 Greater_6 filter_7 publish_result_8]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.plain_int_0 FROM alice.tbl_0 as ta WHERE ta.plain_int_0 = ANY(SELECT ta.plain_int_0 + ta.plain_int_1 + 1 FROM alice.tbl_0 AS ta INNER JOIN bob.tbl_0 AS tb ON ta.plain_int_0 = tb.plain_int_0)`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,t_3,},],attr:[sql:select ta.plain_int_0,ta.plain_int_1 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n2 [label=\"run_sql:{in:[],out:[Out:{t_4,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n3 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_4,},],out:[LeftJoinIndex:{t_13,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_2,t_3,},RowsIndexFilter:{t_13,},],out:[Out:{t_5,t_6,},],attr:[],party:[alice,]}\"]\n5 [label=\"Add:{in:[Left:{t_5,},Right:{t_6,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n6 [label=\"constant:{in:[],out:[Out:{t_8,},],attr:[scalar:1,to_status:1,],party:[alice,bob,]}\"]\n7 [label=\"broadcast_to:{in:[In:{t_8,},ShapeRefTensor:{t_7,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n8 [label=\"Add:{in:[Left:{t_7,},Right:{t_9,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n9 [label=\"in:{in:[Left:{t_1,},Right:{t_10,},],out:[Out:{t_11,},],attr:[in_type:2,input_party_codes:[alice alice],psi_algorithm:0,reveal_to:[alice],],party:[alice,]}\"]\n10 [label=\"filter:{in:[Filter:{t_11,},In:{t_1,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n11 [label=\"publish_result:{in:[In:{t_12,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n0 -> 10 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 9 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{plain_int_1:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_12:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_13:{left_index:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_6:{plain_int_1:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_7:{plus_out:PRIVATE:INT64}\"]\n5 -> 8 [label = \"t_7:{plus_out:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_8:{constant_data:PUBLIC:INT64}\"]\n7 -> 8 [label = \"t_9:{constant_data:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_10:{plus_out:PRIVATE:INT64}\"]\n9 -> 10 [label = \"t_11:{in_result:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 run_sql_2 psi_join_3 filter_by_index_4 Add_5 constant_6 broadcast_to_7 Add_8 in_9 filter_10 publish_result_11]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.plain_int_0 FROM alice.tbl_0 as ta WHERE ta.plain_int_0 > (SELECT AVG(ta.plain_int_0) + SUM(ta.plain_int_1) + 1 FROM alice.tbl_0 AS ta INNER JOIN bob.tbl_0 AS tb ON ta.plain_int_0 = tb.plain_int_0)`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,t_3,},],attr:[sql:select ta.plain_int_0,ta.plain_int_1 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n2 [label=\"run_sql:{in:[],out:[Out:{t_4,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n3 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_4,},],out:[LeftJoinIndex:{t_17,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_2,t_3,},RowsIndexFilter:{t_17,},],out:[Out:{t_5,t_6,},],attr:[],party:[alice,]}\"]\n5 [label=\"reduce[avg]:{in:[In:{t_5,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n6 [label=\"reduce[sum]:{in:[In:{t_6,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n7 [label=\"Add:{in:[Left:{t_7,},Right:{t_8,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n8 [label=\"constant:{in:[],out:[Out:{t_10,},],attr:[scalar:1,to_status:1,],party:[alice,bob,]}\"]\n9 [label=\"broadcast_to:{in:[In:{t_10,},ShapeRefTensor:{t_9,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n10 [label=\"Add:{in:[Left:{t_9,},Right:{t_11,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n11 [label=\"replicate:{in:[Left:{t_1,},Right:{t_12,},],out:[LeftOut:{t_13,},RightOut:{t_14,},],attr:[input_party_codes:[alice alice],],party:[alice,alice,]}\"]\n12 [label=\"Greater:{in:[Left:{t_13,},Right:{t_14,},],out:[Out:{t_15,},],attr:[],party:[alice,]}\"]\n13 [label=\"filter:{in:[Filter:{t_15,},In:{t_13,},],out:[Out:{t_16,},],attr:[],party:[alice,]}\"]\n14 [label=\"publish_result:{in:[In:{t_16,},],out:[Out:{t_18,},],attr:[],party:[alice,]}\"]\n0 -> 11 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{plain_int_1:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_12:{plus_out:PRIVATE:FLOAT64}\"]\n11 -> 12 [label = \"t_13:{plain_int_0:PRIVATE:INT64}\"]\n11 -> 12 [label = \"t_14:{plus_out:PRIVATE:FLOAT64}\"]\n11 -> 13 [label = \"t_13:{plain_int_0:PRIVATE:INT64}\"]\n12 -> 13 [label = \"t_15:{gt_out:PRIVATE:BOOL}\"]\n13 -> 14 [label = \"t_16:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_17:{left_index:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_6:{plain_int_1:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_7:{plain_int_0_avg:PRIVATE:FLOAT64}\"]\n6 -> 7 [label = \"t_8:{plain_int_1_sum:PRIVATE:INT64}\"]\n7 -> 10 [label = \"t_9:{plus_out:PRIVATE:FLOAT64}\"]\n7 -> 9 [label = \"t_9:{plus_out:PRIVATE:FLOAT64}\"]\n8 -> 9 [label = \"t_10:{constant_data:PUBLIC:INT64}\"]\n9 -> 10 [label = \"t_11:{constant_data:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 run_sql_2 psi_join_3 filter_by_index_4 reduce[avg]_5 reduce[sum]_6 Add_7 constant_8 broadcast_to_9 Add_10 replicate_11 Greater_12 filter_13 publish_result_14]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t// TODO: fix case 26 and 27\n\t// Case 26 skipped due to compilation error: [OperatorGraphPass] failed: failed to build operator graph: buildLogicalProjection: setLPResultTable: checkLPResultTable: tensor greatest_out.15 type(=TIMESTAMP) doesn't match scheme type(=STRING)\n\t{`SELECT GREATEST(ta.plain_int_0, tb.plain_float_0), LEAST(ta.plain_int_0, tb.plain_int_0), GREATEST(ta.plain_timestamp_0, tb.plain_timestamp_0) FROM alice.tbl_0 as ta INNER JOIN bob.tbl_0 as tb ON ta.join_int_0 = tb.join_int_0`, ``, ``, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t// Case 27 skipped due to compilation error: [OperatorGraphPass] failed: failed to build operator graph: buildLogicalProjection: setLPResultTable: checkLPResultTable: tensor pow_out.9 type(=INT64) doesn't match scheme type(=FLOAT64)\n\t{`SELECT POW(ta.plain_int_0, 2) as pow_2_int, POW(ta.plain_float_0, 3) as pow_3_float  FROM\n\talice.tbl_0 AS ta INNER JOIN bob.tbl_0 AS tb\n\tON ta.join_int_0 = tb.join_int_0`, ``, ``, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ATAN2(ta.plain_int_0, tb.plain_int_0) as atan2_plain_int FROM\n\talice.tbl_0 AS ta INNER JOIN bob.tbl_0 AS tb\n\tON ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'plain_int_0','tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_4,},],out:[LeftJoinIndex:{t_8,},RightJoinIndex:{t_9,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_8,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_3,},RowsIndexFilter:{t_9,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_6,},],out:[Out:{t_10,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"ATan2:{in:[Left:{t_5,},Right:{t_10,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n7 [label=\"publish_result:{in:[In:{t_7,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_8:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_9:{right_index:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_6:{plain_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_10:{plain_int_0:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_7:{atan2_out:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 ATan2_6 publish_result_7]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`SELECT ta.join_int_0, TAN(ta.plain_int_0) AS tan_plain_int_0, TAN(ta.plain_float_0) AS tan_plain_float_0,\n\tCOT(ta.plain_int_0) AS cot_plain_int_0, COT(ta.plain_float_0) AS cot_plain_float_0,\n\tASIN(ta.plain_int_0) AS asin_plain_int_0, ASIN(ta.plain_float_0) AS asin_plain_float_0,\n\tATAN(ta.plain_int_0) AS atan_plain_int_0, ATAN(ta.plain_float_0) AS atan_plain_float_0\n\t\tFROM alice.tbl_0 as ta INNER JOIN bob.tbl_0 as tb\n\t\tON ta.join_int_0 = tb.join_int_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,t_3,},],attr:[sql:select ta.plain_int_0,ta.join_int_0,ta.plain_float_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_4,},],out:[LeftJoinIndex:{t_22,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,t_3,},RowsIndexFilter:{t_22,},],out:[Out:{t_5,t_6,t_7,},],attr:[],party:[alice,]}\"]\n4 [label=\"Tan:{in:[In:{t_5,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n5 [label=\"Tan:{in:[In:{t_7,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n6 [label=\"Tan:{in:[In:{t_5,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n7 [label=\"constant:{in:[],out:[Out:{t_11,},],attr:[scalar:1,to_status:1,],party:[alice,bob,]}\"]\n8 [label=\"broadcast_to:{in:[In:{t_11,},ShapeRefTensor:{t_10,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n9 [label=\"Div:{in:[Left:{t_12,},Right:{t_10,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n10 [label=\"Tan:{in:[In:{t_7,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n11 [label=\"constant:{in:[],out:[Out:{t_15,},],attr:[scalar:1,to_status:1,],party:[alice,bob,]}\"]\n12 [label=\"broadcast_to:{in:[In:{t_15,},ShapeRefTensor:{t_14,},],out:[Out:{t_16,},],attr:[],party:[alice,]}\"]\n13 [label=\"Div:{in:[Left:{t_16,},Right:{t_14,},],out:[Out:{t_17,},],attr:[],party:[alice,]}\"]\n14 [label=\"ASin:{in:[In:{t_5,},],out:[Out:{t_18,},],attr:[],party:[alice,]}\"]\n15 [label=\"ASin:{in:[In:{t_7,},],out:[Out:{t_19,},],attr:[],party:[alice,]}\"]\n16 [label=\"ATan:{in:[In:{t_5,},],out:[Out:{t_20,},],attr:[],party:[alice,]}\"]\n17 [label=\"ATan:{in:[In:{t_7,},],out:[Out:{t_21,},],attr:[],party:[alice,]}\"]\n18 [label=\"publish_result:{in:[In:{t_6,t_8,t_9,t_13,t_17,t_18,t_19,t_20,t_21,},],out:[Out:{t_23,t_24,t_25,t_26,t_27,t_28,t_29,t_30,t_31,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{plain_float_0:PRIVATE:FLOAT64}\"]\n1 -> 2 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n10 -> 12 [label = \"t_14:{tan_out:PRIVATE:FLOAT64}\"]\n10 -> 13 [label = \"t_14:{tan_out:PRIVATE:FLOAT64}\"]\n11 -> 12 [label = \"t_15:{constant_data:PUBLIC:INT64}\"]\n12 -> 13 [label = \"t_16:{constant_data:PRIVATE:INT64}\"]\n13 -> 18 [label = \"t_17:{div_out:PRIVATE:FLOAT64}\"]\n14 -> 18 [label = \"t_18:{asin_out:PRIVATE:FLOAT64}\"]\n15 -> 18 [label = \"t_19:{asin_out:PRIVATE:FLOAT64}\"]\n16 -> 18 [label = \"t_20:{atan_out:PRIVATE:FLOAT64}\"]\n17 -> 18 [label = \"t_21:{atan_out:PRIVATE:FLOAT64}\"]\n2 -> 3 [label = \"t_22:{left_index:PRIVATE:INT64}\"]\n3 -> 10 [label = \"t_7:{plain_float_0:PRIVATE:FLOAT64}\"]\n3 -> 14 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 15 [label = \"t_7:{plain_float_0:PRIVATE:FLOAT64}\"]\n3 -> 16 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 17 [label = \"t_7:{plain_float_0:PRIVATE:FLOAT64}\"]\n3 -> 18 [label = \"t_6:{join_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_7:{plain_float_0:PRIVATE:FLOAT64}\"]\n3 -> 6 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 18 [label = \"t_8:{tan_out:PRIVATE:FLOAT64}\"]\n5 -> 18 [label = \"t_9:{tan_out:PRIVATE:FLOAT64}\"]\n6 -> 8 [label = \"t_10:{tan_out:PRIVATE:FLOAT64}\"]\n6 -> 9 [label = \"t_10:{tan_out:PRIVATE:FLOAT64}\"]\n7 -> 8 [label = \"t_11:{constant_data:PUBLIC:INT64}\"]\n8 -> 9 [label = \"t_12:{constant_data:PRIVATE:INT64}\"]\n9 -> 18 [label = \"t_13:{div_out:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 Tan_4 Tan_5 Tan_6 constant_7 broadcast_to_8 Div_9 Tan_10 constant_11 broadcast_to_12 Div_13 ASin_14 ASin_15 ATan_16 ATan_17 publish_result_18]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.join_int_0, ta.aggregate_string_0, tu.plain_float_0 from alice.tbl_0 as ta inner join (select tb.join_int_0, tb.plain_float_0 from bob.tbl_0 as tb union all select tc.join_int_0, tc.plain_float_0 from carol.tbl_0 as tc) as tu on ta.join_int_0=tu.join_int_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.aggregate_string_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'join_int_0','tb'.'plain_float_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"run_sql:{in:[],out:[Out:{t_5,t_6,},],attr:[sql:select tc.join_int_0,tc.plain_float_0 from carol.tbl_0 as tc;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n3 [label=\"make_share:{in:[In:{t_3,},],out:[Out:{t_12,},],attr:[],party:[alice,bob,carol,]}\"]\n4 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_13,},],attr:[],party:[alice,bob,carol,]}\"]\n5 [label=\"concat:{in:[In:{t_12,t_13,},],out:[Out:{t_7,},],attr:[axis:0,],party:[alice,bob,carol,]}\"]\n6 [label=\"make_share:{in:[In:{t_4,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,carol,]}\"]\n7 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_15,},],attr:[],party:[alice,bob,carol,]}\"]\n8 [label=\"concat:{in:[In:{t_14,t_15,},],out:[Out:{t_8,},],attr:[axis:0,],party:[alice,bob,carol,]}\"]\n9 [label=\"make_share:{in:[In:{t_1,},],out:[Out:{t_16,},],attr:[],party:[alice,bob,carol,]}\"]\n10 [label=\"make_share:{in:[In:{t_2,},],out:[Out:{t_17,},],attr:[],party:[alice,bob,carol,]}\"]\n11 [label=\"secret_eq_join:{in:[Left:{t_16,t_17,},LeftKey:{t_16,},Right:{t_8,},RightKey:{t_7,},],out:[LeftOutput:{t_9,t_10,},RightOutput:{t_11,},],attr:[],party:[alice,bob,carol,]}\"]\n12 [label=\"make_private:{in:[In:{t_9,},],out:[Out:{t_18,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n13 [label=\"make_public:{in:[In:{t_10,},],out:[Out:{t_19,},],attr:[],party:[alice,bob,carol,]}\"]\n14 [label=\"make_private:{in:[In:{t_19,},],out:[Out:{t_20,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n15 [label=\"make_private:{in:[In:{t_11,},],out:[Out:{t_21,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n16 [label=\"publish_result:{in:[In:{t_18,t_20,t_21,},],out:[Out:{t_22,t_23,t_24,},],attr:[],party:[alice,]}\"]\n0 -> 10 [label = \"t_2:{aggregate_string_0:PRIVATE:STRING}\"]\n0 -> 9 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 6 [label = \"t_4:{plain_float_0:PRIVATE:FLOAT64}\"]\n10 -> 11 [label = \"t_17:{aggregate_string_0:SECRET:STRING}\"]\n11 -> 12 [label = \"t_9:{join_int_0:SECRET:INT64}\"]\n11 -> 13 [label = \"t_10:{aggregate_string_0:SECRET:STRING}\"]\n11 -> 15 [label = \"t_11:{plain_float_0:SECRET:FLOAT64}\"]\n12 -> 16 [label = \"t_18:{join_int_0:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_19:{aggregate_string_0:PUBLIC:STRING}\"]\n14 -> 16 [label = \"t_20:{aggregate_string_0:PRIVATE:STRING}\"]\n15 -> 16 [label = \"t_21:{plain_float_0:PRIVATE:FLOAT64}\"]\n2 -> 4 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n2 -> 7 [label = \"t_6:{plain_float_0:PRIVATE:FLOAT64}\"]\n3 -> 5 [label = \"t_12:{join_int_0:SECRET:INT64}\"]\n4 -> 5 [label = \"t_13:{join_int_0:SECRET:INT64}\"]\n5 -> 11 [label = \"t_7:{join_int_0:SECRET:INT64}\"]\n6 -> 8 [label = \"t_14:{plain_float_0:SECRET:FLOAT64}\"]\n7 -> 8 [label = \"t_15:{plain_float_0:SECRET:FLOAT64}\"]\n8 -> 11 [label = \"t_8:{plain_float_0:SECRET:FLOAT64}\"]\n9 -> 11 [label = \"t_16:{join_int_0:SECRET:INT64}\"]\n9 -> 11 [label = \"t_16:{join_int_0:SECRET:INT64}\"]\n}`, ``, testConf{groupThreshold: 4, batched: true, revealGroupCount: false}},\n\t{`select ta.plain_int_0, ta.plain_int_0 in (select tb.plain_int_0 from bob.tbl_0 as tb) from alice.tbl_0 as ta`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"copy:{in:[In:{t_2,},],out:[Out:{t_4,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n3 [label=\"in:{in:[Left:{t_1,},Right:{t_4,},],out:[Out:{t_3,},],attr:[in_type:2,input_party_codes:[alice alice],psi_algorithm:0,reveal_to:[alice],],party:[alice,]}\"]\n4 [label=\"publish_result:{in:[In:{t_1,t_3,},],out:[Out:{t_5,t_6,},],attr:[],party:[alice,]}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 4 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{in_result:PRIVATE:BOOL}\"]\n}`, `Batched pipeline with 2 nodes`, testConf{groupThreshold: 4, batched: true, revealGroupCount: false}},\n\t{`select ta.plain_int_0 from alice.tbl_0 as ta where ta.plain_int_0 in (select tb.plain_int_0 from bob.tbl_0 as tb)`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"copy:{in:[In:{t_2,},],out:[Out:{t_5,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n3 [label=\"in:{in:[Left:{t_1,},Right:{t_5,},],out:[Out:{t_3,},],attr:[in_type:2,input_party_codes:[alice alice],psi_algorithm:0,reveal_to:[alice],],party:[alice,]}\"]\n4 [label=\"filter:{in:[Filter:{t_3,},In:{t_1,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n5 [label=\"publish_result:{in:[In:{t_4,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 4 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{in_result:PRIVATE:BOOL}\"]\n4 -> 5 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n}`, `Batched pipeline with 3 nodes`, testConf{groupThreshold: 4, batched: true, revealGroupCount: false}},\n\t{`select ta.plain_int_0 in (select tb.plain_int_0 from bob.tbl_0 as tb) and ta.plain_int_1 in (select tb.plain_int_1 from bob.tbl_0 as tb) from alice.tbl_0 as ta`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.plain_int_1 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"copy:{in:[In:{t_3,},],out:[Out:{t_8,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n3 [label=\"in:{in:[Left:{t_1,},Right:{t_8,},],out:[Out:{t_4,},],attr:[in_type:2,input_party_codes:[alice alice],psi_algorithm:0,reveal_to:[alice],],party:[alice,]}\"]\n4 [label=\"run_sql:{in:[],out:[Out:{t_5,},],attr:[sql:select 'tb'.'plain_int_1' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_5,},],out:[Out:{t_9,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"in:{in:[Left:{t_2,},Right:{t_9,},],out:[Out:{t_6,},],attr:[in_type:2,input_party_codes:[alice alice],psi_algorithm:0,reveal_to:[alice],],party:[alice,]}\"]\n7 [label=\"LogicalAnd:{in:[Left:{t_4,},Right:{t_6,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n8 [label=\"publish_result:{in:[In:{t_7,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 6 [label = \"t_2:{plain_int_1:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_8:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_4:{in_result:PRIVATE:BOOL}\"]\n4 -> 5 [label = \"t_5:{plain_int_1:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_9:{plain_int_1:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_6:{in_result:PRIVATE:BOOL}\"]\n7 -> 8 [label = \"t_7:{and_out:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 copy_2 in_3 run_sql_4 copy_5 in_6 LogicalAnd_7 publish_result_8]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select if(ta.plain_float_0, -1.0, -ta.plain_float_0) as res from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.plain_float_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_11,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_11,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"constant:{in:[],out:[Out:{t_5,},],attr:[scalar:-1,to_status:1,],party:[alice,bob,]}\"]\n5 [label=\"constant:{in:[],out:[Out:{t_6,},],attr:[scalar:0,to_status:1,],party:[alice,bob,]}\"]\n6 [label=\"broadcast_to:{in:[In:{t_6,},ShapeRefTensor:{t_4,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n7 [label=\"Minus:{in:[Left:{t_7,},Right:{t_4,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n8 [label=\"broadcast_to:{in:[In:{t_5,},ShapeRefTensor:{t_8,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n9 [label=\"if:{in:[Condition:{t_4,},ValueIfFalse:{t_8,},ValueIfTrue:{t_9,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n10 [label=\"publish_result:{in:[In:{t_10,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{plain_float_0:PRIVATE:FLOAT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_11:{left_index:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_4:{plain_float_0:PRIVATE:FLOAT64}\"]\n3 -> 7 [label = \"t_4:{plain_float_0:PRIVATE:FLOAT64}\"]\n3 -> 9 [label = \"t_4:{plain_float_0:PRIVATE:FLOAT64}\"]\n4 -> 8 [label = \"t_5:{constant_data:PUBLIC:FLOAT64}\"]\n5 -> 6 [label = \"t_6:{constant_data:PUBLIC:INT64}\"]\n6 -> 7 [label = \"t_7:{constant_data:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_8:{minus_out:PRIVATE:FLOAT64}\"]\n7 -> 9 [label = \"t_8:{minus_out:PRIVATE:FLOAT64}\"]\n8 -> 9 [label = \"t_9:{constant_data:PRIVATE:FLOAT64}\"]\n9 -> 10 [label = \"t_10:{if_out:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 constant_4 constant_5 broadcast_to_6 Minus_7 broadcast_to_8 if_9 publish_result_10]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`(SELECT count(alice.groupby_int_1) as test1 FROM alice.tbl_0 as alice WHERE alice.groupby_int_0 >= 0 GROUP BY alice.groupby_int_1 HAVING test1 > 0  limit 3) union all (select count(bob.groupby_int_0) as test1 FROM bob.tbl_0 as bob WHERE bob.groupby_int_0 >= 0  limit 3);`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_13,},],attr:[sql:select t_0.test1 from (select count(alice.groupby_int_1) as test1 from alice.tbl_0 as alice where alice.groupby_int_0>=0 group by alice.groupby_int_1 having (count(alice.groupby_int_1)>0) and (count(alice.groupby_int_1)>=4) limit 3) as t_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_19,},],attr:[sql:select 't_0'.'expr_121' from (select count('bob'.'groupby_int_0') as 'expr_121' from 'bob'.'tbl_0' as 'bob' where 'bob'.'groupby_int_0'>=0 limit 3) as 't_0';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"make_share:{in:[In:{t_13,},],out:[Out:{t_21,},],attr:[],party:[alice,bob,]}\"]\n3 [label=\"make_share:{in:[In:{t_19,},],out:[Out:{t_22,},],attr:[],party:[alice,bob,]}\"]\n4 [label=\"concat:{in:[In:{t_21,t_22,},],out:[Out:{t_20,},],attr:[axis:0,],party:[alice,bob,]}\"]\n5 [label=\"make_private:{in:[In:{t_20,},],out:[Out:{t_23,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n6 [label=\"publish_result:{in:[In:{t_23,},],out:[Out:{t_24,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_13:{simple_count_result:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_19:{groupby_int_0_count:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_21:{simple_count_result:SECRET:INT64}\"]\n3 -> 4 [label = \"t_22:{groupby_int_0_count:SECRET:INT64}\"]\n4 -> 5 [label = \"t_20:{simple_count_result:SECRET:INT64}\"]\n5 -> 6 [label = \"t_23:{simple_count_result:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 make_share_2 make_share_3 concat_4 make_private_5 publish_result_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`(SELECT alice.groupby_int_1 is not null as c1, coalesce(alice.compare_float_0, alice.plain_float_1) as c2, ifnull(alice.join_string_0, \"null\") as c3 FROM alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_string_0=bob.join_string_0);`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,t_3,t_4,},],attr:[sql:select alice.compare_float_0,alice.join_string_0,alice.groupby_int_1,alice.plain_float_1 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_5,},],attr:[sql:select 'bob'.'join_string_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_5,},],out:[LeftJoinIndex:{t_16,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,t_3,t_4,},RowsIndexFilter:{t_16,},],out:[Out:{t_6,t_7,t_8,t_9,},],attr:[],party:[alice,]}\"]\n4 [label=\"IsNull:{in:[In:{t_8,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n5 [label=\"Not:{in:[In:{t_10,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n6 [label=\"coalesce:{in:[Exprs:{t_6,t_9,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n7 [label=\"constant:{in:[],out:[Out:{t_13,},],attr:[scalar:null,to_status:1,],party:[alice,bob,]}\"]\n8 [label=\"broadcast_to:{in:[In:{t_13,},ShapeRefTensor:{t_7,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n9 [label=\"if_null:{in:[AltValue:{t_14,},Expr:{t_7,},],out:[Out:{t_15,},],attr:[],party:[alice,]}\"]\n10 [label=\"publish_result:{in:[In:{t_11,t_12,t_15,},],out:[Out:{t_17,t_18,t_19,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_string_0:PRIVATE:STRING}\"]\n0 -> 3 [label = \"t_1:{compare_float_0:PRIVATE:FLOAT64}\"]\n0 -> 3 [label = \"t_2:{join_string_0:PRIVATE:STRING}\"]\n0 -> 3 [label = \"t_3:{groupby_int_1:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_4:{plain_float_1:PRIVATE:FLOAT64}\"]\n1 -> 2 [label = \"t_5:{join_string_0:PRIVATE:STRING}\"]\n2 -> 3 [label = \"t_16:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_8:{groupby_int_1:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_6:{compare_float_0:PRIVATE:FLOAT64}\"]\n3 -> 6 [label = \"t_9:{plain_float_1:PRIVATE:FLOAT64}\"]\n3 -> 8 [label = \"t_7:{join_string_0:PRIVATE:STRING}\"]\n3 -> 9 [label = \"t_7:{join_string_0:PRIVATE:STRING}\"]\n4 -> 5 [label = \"t_10:{isnull_out:PRIVATE:BOOL}\"]\n5 -> 10 [label = \"t_11:{not_out:PRIVATE:BOOL}\"]\n6 -> 10 [label = \"t_12:{coalesce_out:PRIVATE:FLOAT64}\"]\n7 -> 8 [label = \"t_13:{constant_data:PUBLIC:STRING}\"]\n8 -> 9 [label = \"t_14:{constant_data:PRIVATE:STRING}\"]\n9 -> 10 [label = \"t_15:{ifnull_out:PRIVATE:STRING}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 IsNull_4 Not_5 coalesce_6 constant_7 broadcast_to_8 if_null_9 publish_result_10]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`(SELECT lower(alice.join_string_0) as c1, upper(alice.join_string_0) as c2, trim(alice.join_string_0) as c3, concat('prefix', alice.join_string_0, bob.join_string_0, 'suffix') FROM alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_string_0=bob.join_string_0);`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select alice.join_string_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'bob'.'join_string_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_13,},RightJoinIndex:{t_14,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_13,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_14,},],out:[Out:{t_4,},],attr:[],party:[bob,]}\"]\n5 [label=\"arrow_func[utf8_lower]:{in:[In:{t_3,},],out:[Out:{t_5,},],attr:[func_name:utf8_lower,],party:[alice,]}\"]\n6 [label=\"arrow_func[utf8_upper]:{in:[In:{t_3,},],out:[Out:{t_6,},],attr:[func_name:utf8_upper,],party:[alice,]}\"]\n7 [label=\"arrow_func[utf8_trim]:{in:[In:{t_3,},],out:[Out:{t_7,},],attr:[func_name:utf8_trim,func_opt_type:TrimOptions,],party:[alice,]}\"]\n8 [label=\"constant:{in:[],out:[Out:{t_8,},],attr:[scalar:prefix,to_status:1,],party:[alice,bob,]}\"]\n9 [label=\"constant:{in:[],out:[Out:{t_9,},],attr:[scalar:suffix,to_status:1,],party:[alice,bob,]}\"]\n10 [label=\"broadcast_to:{in:[In:{t_8,t_9,},ShapeRefTensor:{t_4,},],out:[Out:{t_10,t_11,},],attr:[],party:[bob,]}\"]\n11 [label=\"copy:{in:[In:{t_10,},],out:[Out:{t_15,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n12 [label=\"copy:{in:[In:{t_4,},],out:[Out:{t_16,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n13 [label=\"copy:{in:[In:{t_11,},],out:[Out:{t_17,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n14 [label=\"constant:{in:[],out:[Out:{t_18,},],attr:[scalar:,to_status:1,],party:[alice,bob,]}\"]\n15 [label=\"broadcast_to:{in:[In:{t_18,},ShapeRefTensor:{t_15,},],out:[Out:{t_19,},],attr:[],party:[alice,]}\"]\n16 [label=\"arrow_func[binary_join_element_wise]:{in:[In:{t_15,t_3,t_16,t_17,t_19,},],out:[Out:{t_12,},],attr:[func_name:binary_join_element_wise,],party:[alice,]}\"]\n17 [label=\"publish_result:{in:[In:{t_5,t_6,t_7,t_12,},],out:[Out:{t_20,t_21,t_22,t_23,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_string_0:PRIVATE:STRING}\"]\n0 -> 3 [label = \"t_1:{join_string_0:PRIVATE:STRING}\"]\n1 -> 2 [label = \"t_2:{join_string_0:PRIVATE:STRING}\"]\n1 -> 4 [label = \"t_2:{join_string_0:PRIVATE:STRING}\"]\n10 -> 11 [label = \"t_10:{constant_data:PRIVATE:STRING}\"]\n10 -> 13 [label = \"t_11:{constant_data:PRIVATE:STRING}\"]\n11 -> 15 [label = \"t_15:{constant_data:PRIVATE:STRING}\"]\n11 -> 16 [label = \"t_15:{constant_data:PRIVATE:STRING}\"]\n12 -> 16 [label = \"t_16:{join_string_0:PRIVATE:STRING}\"]\n13 -> 16 [label = \"t_17:{constant_data:PRIVATE:STRING}\"]\n14 -> 15 [label = \"t_18:{concat_separator:PUBLIC:STRING}\"]\n15 -> 16 [label = \"t_19:{broadcasted_concat_separator:PRIVATE:STRING}\"]\n16 -> 17 [label = \"t_12:{concat_out:PRIVATE:STRING}\"]\n2 -> 3 [label = \"t_13:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_14:{right_index:PRIVATE:INT64}\"]\n3 -> 16 [label = \"t_3:{join_string_0:PRIVATE:STRING}\"]\n3 -> 5 [label = \"t_3:{join_string_0:PRIVATE:STRING}\"]\n3 -> 6 [label = \"t_3:{join_string_0:PRIVATE:STRING}\"]\n3 -> 7 [label = \"t_3:{join_string_0:PRIVATE:STRING}\"]\n4 -> 10 [label = \"t_4:{join_string_0:PRIVATE:STRING}\"]\n4 -> 12 [label = \"t_4:{join_string_0:PRIVATE:STRING}\"]\n5 -> 17 [label = \"t_5:{lower_out:PRIVATE:STRING}\"]\n6 -> 17 [label = \"t_6:{upper_out:PRIVATE:STRING}\"]\n7 -> 17 [label = \"t_7:{trim_out:PRIVATE:STRING}\"]\n8 -> 10 [label = \"t_8:{constant_data:PUBLIC:STRING}\"]\n9 -> 10 [label = \"t_9:{constant_data:PUBLIC:STRING}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 arrow_func[utf8_lower]_5 arrow_func[utf8_upper]_6 arrow_func[utf8_trim]_7 constant_8 constant_9 broadcast_to_10 copy_11 copy_12 copy_13 constant_14 broadcast_to_15 arrow_func[binary_join_element_wise]_16 publish_result_17]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`(SELECT substring(alice.join_string_0, 2) as c1, substring(alice.join_string_0, 1, 1) as c2 FROM alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_string_0=bob.join_string_0);`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select alice.join_string_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'bob'.'join_string_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_6,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_6,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"arrow_func[utf8_slice_codeunits]:{in:[In:{t_3,},],out:[Out:{t_4,},],attr:[func_name:utf8_slice_codeunits,func_opt_type:SliceOptions,],party:[alice,]}\"]\n5 [label=\"arrow_func[utf8_slice_codeunits]:{in:[In:{t_3,},],out:[Out:{t_5,},],attr:[func_name:utf8_slice_codeunits,func_opt_type:SliceOptions,],party:[alice,]}\"]\n6 [label=\"publish_result:{in:[In:{t_4,t_5,},],out:[Out:{t_7,t_8,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_string_0:PRIVATE:STRING}\"]\n0 -> 3 [label = \"t_1:{join_string_0:PRIVATE:STRING}\"]\n1 -> 2 [label = \"t_2:{join_string_0:PRIVATE:STRING}\"]\n2 -> 3 [label = \"t_6:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{join_string_0:PRIVATE:STRING}\"]\n3 -> 5 [label = \"t_3:{join_string_0:PRIVATE:STRING}\"]\n4 -> 6 [label = \"t_4:{substring_out:PRIVATE:STRING}\"]\n5 -> 6 [label = \"t_5:{substring_out:PRIVATE:STRING}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 arrow_func[utf8_slice_codeunits]_4 arrow_func[utf8_slice_codeunits]_5 publish_result_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`(SELECT count(alice.groupby_int_1) as test1 FROM alice.tbl_0 as alice WHERE alice.groupby_int_0 >= 0 GROUP BY alice.groupby_int_1 HAVING test1 > 0  limit 3) union (select count(bob.groupby_int_0) as test1 FROM bob.tbl_0 as bob WHERE bob.groupby_int_0 >= 0  limit 3);`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_14,},],attr:[sql:select any_value(t_0.test1) as expr_244 from (select count(alice.groupby_int_1) as test1 from alice.tbl_0 as alice where alice.groupby_int_0>=0 group by alice.groupby_int_1 having (count(alice.groupby_int_1)>0) and (count(alice.groupby_int_1)>=4) limit 3) as t_0 group by t_0.test1;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_21,},],attr:[sql:select 't_0'.'expr_121' from (select count('bob'.'groupby_int_0') as 'expr_121' from 'bob'.'tbl_0' as 'bob' where 'bob'.'groupby_int_0'>=0 limit 3) as 't_0' group by 't_0'.'expr_121';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"make_share:{in:[In:{t_14,},],out:[Out:{t_24,},],attr:[],party:[alice,bob,]}\"]\n3 [label=\"make_share:{in:[In:{t_21,},],out:[Out:{t_25,},],attr:[],party:[alice,bob,]}\"]\n4 [label=\"concat:{in:[In:{t_24,t_25,},],out:[Out:{t_22,},],attr:[axis:0,],party:[alice,bob,]}\"]\n5 [label=\"make_private:{in:[In:{t_22,},],out:[Out:{t_26,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n6 [label=\"private_group:{in:[Key:{t_26,},],out:[GroupId:{t_27,},GroupNum:{t_28,},],attr:[],party:[alice,]}\"]\n7 [label=\"firstrow:{in:[GroupId:{t_27,},GroupNum:{t_28,},In:{t_26,},],out:[Out:{t_23,},],attr:[],party:[alice,]}\"]\n8 [label=\"publish_result:{in:[In:{t_23,},],out:[Out:{t_29,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_14:{simple_count_result_firstrow:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_21:{groupby_int_0_count_firstrow:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_24:{simple_count_result_firstrow:SECRET:INT64}\"]\n3 -> 4 [label = \"t_25:{groupby_int_0_count_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_22:{simple_count_result_firstrow:SECRET:INT64}\"]\n5 -> 6 [label = \"t_26:{simple_count_result_firstrow:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_26:{simple_count_result_firstrow:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_27:{group_id:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_28:{group_num:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_23:{simple_count_result_firstrow_firstrow:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 make_share_2 make_share_3 concat_4 make_private_5 private_group_6 firstrow_7 publish_result_8]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select if(ta.plain_int_0, -1, -ta.plain_int_0) as res from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_11,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_11,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"constant:{in:[],out:[Out:{t_5,},],attr:[scalar:-1,to_status:1,],party:[alice,bob,]}\"]\n5 [label=\"constant:{in:[],out:[Out:{t_6,},],attr:[scalar:0,to_status:1,],party:[alice,bob,]}\"]\n6 [label=\"broadcast_to:{in:[In:{t_6,},ShapeRefTensor:{t_4,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n7 [label=\"Minus:{in:[Left:{t_7,},Right:{t_4,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n8 [label=\"broadcast_to:{in:[In:{t_5,},ShapeRefTensor:{t_8,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n9 [label=\"if:{in:[Condition:{t_4,},ValueIfFalse:{t_8,},ValueIfTrue:{t_9,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n10 [label=\"publish_result:{in:[In:{t_10,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_11:{left_index:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 9 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 8 [label = \"t_5:{constant_data:PUBLIC:INT64}\"]\n5 -> 6 [label = \"t_6:{constant_data:PUBLIC:INT64}\"]\n6 -> 7 [label = \"t_7:{constant_data:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_8:{minus_out:PRIVATE:INT64}\"]\n7 -> 9 [label = \"t_8:{minus_out:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_9:{constant_data:PRIVATE:INT64}\"]\n9 -> 10 [label = \"t_10:{if_out:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 constant_4 constant_5 broadcast_to_6 Minus_7 broadcast_to_8 if_9 publish_result_10]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(tb.join_string_0) from  alice.tbl_0 as ta inner join bob.tbl_0 as tb on ta.join_string_0=tb.join_string_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.join_string_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'join_string_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{},RightJoinIndex:{t_5,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_5,},],out:[Out:{t_3,},],attr:[],party:[bob,]}\"]\n4 [label=\"reduce[count]:{in:[In:{t_3,},],out:[Out:{t_4,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_4,},],out:[Out:{t_6,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"publish_result:{in:[In:{t_6,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_string_0:PRIVATE:STRING}\"]\n1 -> 2 [label = \"t_2:{join_string_0:PRIVATE:STRING}\"]\n1 -> 3 [label = \"t_2:{join_string_0:PRIVATE:STRING}\"]\n2 -> 3 [label = \"t_5:{right_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{join_string_0:PRIVATE:STRING}\"]\n4 -> 5 [label = \"t_4:{join_string_0_count:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_6:{join_string_0_count:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 reduce[count]_4 copy_5 publish_result_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select tt.compare_int_0 > 0 from (select compare_int_0 from alice.tbl_0 UNION select compare_int_0 from bob.tbl_0) as tt;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select any_value(tbl_0.compare_int_0) as expr_243 from alice.tbl_0 group by tbl_0.compare_int_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,},],attr:[sql:select 'tbl_0'.'compare_int_0' from 'bob'.'tbl_0' group by 'tbl_0'.'compare_int_0';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"make_share:{in:[In:{t_2,},],out:[Out:{t_10,},],attr:[],party:[alice,bob,]}\"]\n3 [label=\"make_share:{in:[In:{t_4,},],out:[Out:{t_11,},],attr:[],party:[alice,bob,]}\"]\n4 [label=\"concat:{in:[In:{t_10,t_11,},],out:[Out:{t_5,},],attr:[axis:0,],party:[alice,bob,]}\"]\n5 [label=\"sort:{in:[In:{t_5,t_5,},Key:{t_5,},],out:[Out:{t_12,t_13,},],attr:[reverse:[false],],party:[alice,bob,]}\"]\n6 [label=\"oblivious_group_mark:{in:[Key:{t_12,},],out:[Group:{t_14,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"shuffle:{in:[In:{t_13,t_14,},],out:[Out:{t_15,t_16,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"make_public:{in:[In:{t_16,},],out:[Out:{t_17,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"filter:{in:[Filter:{t_17,},In:{t_15,},],out:[Out:{t_6,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"constant:{in:[],out:[Out:{t_7,},],attr:[scalar:0,to_status:1,],party:[alice,bob,]}\"]\n11 [label=\"broadcast_to:{in:[In:{t_7,},ShapeRefTensor:{t_6,},],out:[Out:{t_8,},],attr:[],party:[alice,bob,]}\"]\n12 [label=\"Greater:{in:[Left:{t_6,},Right:{t_8,},],out:[Out:{t_9,},],attr:[],party:[alice,bob,]}\"]\n13 [label=\"make_private:{in:[In:{t_9,},],out:[Out:{t_18,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n14 [label=\"publish_result:{in:[In:{t_18,},],out:[Out:{t_19,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{compare_int_0_firstrow:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_4:{compare_int_0_firstrow:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_7:{constant_data:PUBLIC:INT64}\"]\n11 -> 12 [label = \"t_8:{constant_data:PUBLIC:INT64}\"]\n12 -> 13 [label = \"t_9:{gt_out:SECRET:BOOL}\"]\n13 -> 14 [label = \"t_18:{gt_out:PRIVATE:BOOL}\"]\n2 -> 4 [label = \"t_10:{compare_int_0_firstrow:SECRET:INT64}\"]\n3 -> 4 [label = \"t_11:{compare_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_5:{compare_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_5:{compare_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_5:{compare_int_0_firstrow:SECRET:INT64}\"]\n5 -> 6 [label = \"t_12:{compare_int_0_firstrow:SECRET:INT64}\"]\n5 -> 7 [label = \"t_13:{compare_int_0_firstrow:SECRET:INT64}\"]\n6 -> 7 [label = \"t_14:{group_mark:SECRET:BOOL}\"]\n7 -> 8 [label = \"t_16:{group_mark:SECRET:BOOL}\"]\n7 -> 9 [label = \"t_15:{compare_int_0_firstrow:SECRET:INT64}\"]\n8 -> 9 [label = \"t_17:{group_mark:PUBLIC:BOOL}\"]\n9 -> 11 [label = \"t_6:{compare_int_0_firstrow_firstrow:SECRET:INT64}\"]\n9 -> 12 [label = \"t_6:{compare_int_0_firstrow_firstrow:SECRET:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 make_share_2 make_share_3 concat_4 sort_5 oblivious_group_mark_6 shuffle_7 make_public_8 filter_9 constant_10 broadcast_to_11 Greater_12 make_private_13 publish_result_14]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.join_int_0, tb.join_int_0 from (select distinct tbl_0.join_int_0, tbl_0.join_int_1 from alice.tbl_0) as ta join (select distinct tbl_0.join_int_0, tbl_0.join_int_1 from bob.tbl_0) as tb on ta.join_int_0 = tb.join_int_0 and ta.join_int_1 = tb.join_int_1;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select any_value(tbl_0.join_int_0) as expr_2,any_value(tbl_0.join_int_1) as expr_42 from alice.tbl_0 group by tbl_0.join_int_0,tbl_0.join_int_1;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_7,t_8,},],attr:[sql:select 'tbl_0'.'join_int_0','tbl_0'.'join_int_1' from 'bob'.'tbl_0' group by 'tbl_0'.'join_int_0','tbl_0'.'join_int_1';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_3,t_4,},Right:{t_7,t_8,},],out:[LeftJoinIndex:{t_11,},RightJoinIndex:{t_12,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_3,},RowsIndexFilter:{t_11,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_7,},RowsIndexFilter:{t_12,},],out:[Out:{t_10,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_10,},],out:[Out:{t_13,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"publish_result:{in:[In:{t_9,t_13,},],out:[Out:{t_14,t_15,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_3:{join_int_0_firstrow:PRIVATE:INT64}\"]\n0 -> 2 [label = \"t_4:{join_int_1_firstrow:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{join_int_0_firstrow:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_7:{join_int_0_firstrow:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_8:{join_int_1_firstrow:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_7:{join_int_0_firstrow:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_11:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_12:{right_index:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_9:{join_int_0_firstrow:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_10:{join_int_0_firstrow:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_13:{join_int_0_firstrow:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 publish_result_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.groupby_int_0 from alice.tbl_0 as ta WHERE groupby_int_0>0 UNION (select tb.groupby_int_0 from bob.tbl_0 as tb GROUP BY tb.groupby_int_0);`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_5,},],attr:[sql:select any_value(ta.groupby_int_0) as expr_243 from alice.tbl_0 as ta where ta.groupby_int_0>0 group by ta.groupby_int_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_13,},],attr:[sql:select 't_0'.'groupby_int_0' from (select 'tb'.'groupby_int_0' from 'bob'.'tbl_0' as 'tb' group by 'tb'.'groupby_int_0' having count(1)>=4) as 't_0' group by 't_0'.'groupby_int_0';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_16,},],attr:[],party:[alice,bob,]}\"]\n3 [label=\"make_share:{in:[In:{t_13,},],out:[Out:{t_17,},],attr:[],party:[alice,bob,]}\"]\n4 [label=\"concat:{in:[In:{t_16,t_17,},],out:[Out:{t_14,},],attr:[axis:0,],party:[alice,bob,]}\"]\n5 [label=\"sort:{in:[In:{t_14,t_14,},Key:{t_14,},],out:[Out:{t_18,t_19,},],attr:[reverse:[false],],party:[alice,bob,]}\"]\n6 [label=\"oblivious_group_mark:{in:[Key:{t_18,},],out:[Group:{t_20,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"shuffle:{in:[In:{t_19,t_20,},],out:[Out:{t_21,t_22,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"make_public:{in:[In:{t_22,},],out:[Out:{t_23,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"filter:{in:[Filter:{t_23,},In:{t_21,},],out:[Out:{t_15,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"make_private:{in:[In:{t_15,},],out:[Out:{t_24,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n11 [label=\"publish_result:{in:[In:{t_24,},],out:[Out:{t_25,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_5:{groupby_int_0_firstrow:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_13:{groupby_int_0_firstrow_firstrow:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_24:{groupby_int_0_firstrow_firstrow:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_16:{groupby_int_0_firstrow:SECRET:INT64}\"]\n3 -> 4 [label = \"t_17:{groupby_int_0_firstrow_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_14:{groupby_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_14:{groupby_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_14:{groupby_int_0_firstrow:SECRET:INT64}\"]\n5 -> 6 [label = \"t_18:{groupby_int_0_firstrow:SECRET:INT64}\"]\n5 -> 7 [label = \"t_19:{groupby_int_0_firstrow:SECRET:INT64}\"]\n6 -> 7 [label = \"t_20:{group_mark:SECRET:BOOL}\"]\n7 -> 8 [label = \"t_22:{group_mark:SECRET:BOOL}\"]\n7 -> 9 [label = \"t_21:{groupby_int_0_firstrow:SECRET:INT64}\"]\n8 -> 9 [label = \"t_23:{group_mark:PUBLIC:BOOL}\"]\n9 -> 10 [label = \"t_15:{groupby_int_0_firstrow_firstrow:SECRET:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 make_share_2 make_share_3 concat_4 sort_5 oblivious_group_mark_6 shuffle_7 make_public_8 filter_9 make_private_10 publish_result_11]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(distinct (if(ta.encrypt_int_0>1, tb.join_string_0, \"aa\"))) from  alice.tbl_0 as ta inner join bob.tbl_0 as tb on ta.join_string_0=tb.join_string_0 group by tb.groupby_int_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.encrypt_int_0,ta.join_string_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'groupby_int_0','tb'.'join_string_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_4,},],out:[LeftJoinIndex:{t_21,},RightJoinIndex:{t_22,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_21,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_3,t_4,},RowsIndexFilter:{t_22,},],out:[Out:{t_6,t_7,},],attr:[],party:[bob,]}\"]\n5 [label=\"constant:{in:[],out:[Out:{t_8,},],attr:[scalar:1,to_status:1,],party:[alice,bob,]}\"]\n6 [label=\"broadcast_to:{in:[In:{t_8,},ShapeRefTensor:{t_5,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n7 [label=\"Greater:{in:[Left:{t_5,},Right:{t_9,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n8 [label=\"constant:{in:[],out:[Out:{t_11,},],attr:[scalar:aa,to_status:1,],party:[alice,bob,]}\"]\n9 [label=\"broadcast_to:{in:[In:{t_11,},ShapeRefTensor:{t_7,},],out:[Out:{t_12,},],attr:[],party:[bob,]}\"]\n10 [label=\"copy:{in:[In:{t_7,},],out:[Out:{t_23,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n11 [label=\"copy:{in:[In:{t_12,},],out:[Out:{t_24,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n12 [label=\"if:{in:[Condition:{t_10,},ValueIfFalse:{t_24,},ValueIfTrue:{t_23,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n13 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_25,},],attr:[],party:[alice,bob,]}\"]\n14 [label=\"make_share:{in:[In:{t_13,},],out:[Out:{t_26,},],attr:[],party:[alice,bob,]}\"]\n15 [label=\"sort:{in:[In:{t_25,t_26,},Key:{t_25,},],out:[Out:{t_27,t_28,},],attr:[reverse:[false],],party:[alice,bob,]}\"]\n16 [label=\"oblivious_group_mark:{in:[Key:{t_27,},],out:[Group:{t_29,},],attr:[],party:[alice,bob,]}\"]\n17 [label=\"count:{in:[Group:{t_29,},In:{t_29,},],out:[Out:{t_30,},],attr:[],party:[alice,bob,]}\"]\n18 [label=\"sort:{in:[In:{t_28,},Key:{t_27,t_28,},],out:[Out:{t_32,},],attr:[reverse:[false false],],party:[alice,bob,]}\"]\n19 [label=\"oblivious_group_mark:{in:[Key:{t_32,},],out:[Group:{t_33,},],attr:[],party:[alice,bob,]}\"]\n20 [label=\"LogicalOr:{in:[Left:{t_29,},Right:{t_33,},],out:[Out:{t_34,},],attr:[],party:[alice,bob,]}\"]\n21 [label=\"sum:{in:[Group:{t_29,},In:{t_34,},],out:[Out:{t_31,},],attr:[],party:[alice,bob,]}\"]\n22 [label=\"shuffle:{in:[In:{t_30,t_31,t_29,},],out:[Out:{t_35,t_36,t_37,},],attr:[],party:[alice,bob,]}\"]\n23 [label=\"make_public:{in:[In:{t_37,},],out:[Out:{t_38,},],attr:[],party:[alice,bob,]}\"]\n24 [label=\"filter:{in:[Filter:{t_38,},In:{t_35,t_36,},],out:[Out:{t_15,t_14,},],attr:[],party:[alice,bob,]}\"]\n25 [label=\"constant:{in:[],out:[Out:{t_16,},],attr:[scalar:4,to_status:1,],party:[alice,bob,]}\"]\n26 [label=\"broadcast_to:{in:[In:{t_16,},ShapeRefTensor:{t_15,},],out:[Out:{t_17,},],attr:[],party:[alice,bob,]}\"]\n27 [label=\"make_private:{in:[In:{t_15,},],out:[Out:{t_39,},],attr:[reveal_to:bob,],party:[alice,bob,]}\"]\n28 [label=\"make_private:{in:[In:{t_17,},],out:[Out:{t_40,},],attr:[reveal_to:bob,],party:[alice,bob,]}\"]\n29 [label=\"GreaterEqual:{in:[Left:{t_39,},Right:{t_40,},],out:[Out:{t_18,},],attr:[],party:[bob,]}\"]\n30 [label=\"make_private:{in:[In:{t_14,},],out:[Out:{t_41,},],attr:[reveal_to:bob,],party:[alice,bob,]}\"]\n31 [label=\"filter:{in:[Filter:{t_18,},In:{t_39,t_41,},],out:[Out:{t_20,t_19,},],attr:[],party:[bob,]}\"]\n32 [label=\"copy:{in:[In:{t_19,},],out:[Out:{t_42,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n33 [label=\"publish_result:{in:[In:{t_42,},],out:[Out:{t_43,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_string_0:PRIVATE:STRING}\"]\n0 -> 3 [label = \"t_1:{encrypt_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_4:{join_string_0:PRIVATE:STRING}\"]\n1 -> 4 [label = \"t_3:{groupby_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{join_string_0:PRIVATE:STRING}\"]\n10 -> 12 [label = \"t_23:{join_string_0:PRIVATE:STRING}\"]\n11 -> 12 [label = \"t_24:{constant_data:PRIVATE:STRING}\"]\n12 -> 14 [label = \"t_13:{if_out:PRIVATE:STRING}\"]\n13 -> 15 [label = \"t_25:{groupby_int_0:SECRET:INT64}\"]\n13 -> 15 [label = \"t_25:{groupby_int_0:SECRET:INT64}\"]\n14 -> 15 [label = \"t_26:{if_out:SECRET:STRING}\"]\n15 -> 16 [label = \"t_27:{groupby_int_0:SECRET:INT64}\"]\n15 -> 18 [label = \"t_27:{groupby_int_0:SECRET:INT64}\"]\n15 -> 18 [label = \"t_28:{if_out:SECRET:STRING}\"]\n15 -> 18 [label = \"t_28:{if_out:SECRET:STRING}\"]\n16 -> 17 [label = \"t_29:{group_mark:SECRET:BOOL}\"]\n16 -> 17 [label = \"t_29:{group_mark:SECRET:BOOL}\"]\n16 -> 20 [label = \"t_29:{group_mark:SECRET:BOOL}\"]\n16 -> 21 [label = \"t_29:{group_mark:SECRET:BOOL}\"]\n16 -> 22 [label = \"t_29:{group_mark:SECRET:BOOL}\"]\n17 -> 22 [label = \"t_30:{aggregated_group_simple_count:SECRET:INT64}\"]\n18 -> 19 [label = \"t_32:{if_out:SECRET:STRING}\"]\n19 -> 20 [label = \"t_33:{group_mark_distinct:SECRET:BOOL}\"]\n2 -> 3 [label = \"t_21:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_22:{right_index:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_34:{group_mark_full:SECRET:BOOL}\"]\n21 -> 22 [label = \"t_31:{if_out_count:SECRET:INT64}\"]\n22 -> 23 [label = \"t_37:{group_mark:SECRET:BOOL}\"]\n22 -> 24 [label = \"t_35:{aggregated_group_simple_count:SECRET:INT64}\"]\n22 -> 24 [label = \"t_36:{if_out_count:SECRET:INT64}\"]\n23 -> 24 [label = \"t_38:{group_mark:PUBLIC:BOOL}\"]\n24 -> 26 [label = \"t_15:{simple_count_result:SECRET:INT64}\"]\n24 -> 27 [label = \"t_15:{simple_count_result:SECRET:INT64}\"]\n24 -> 30 [label = \"t_14:{if_out_count:SECRET:INT64}\"]\n25 -> 26 [label = \"t_16:{constant_data:PUBLIC:INT64}\"]\n26 -> 28 [label = \"t_17:{constant_data:PUBLIC:INT64}\"]\n27 -> 29 [label = \"t_39:{simple_count_result:PRIVATE:INT64}\"]\n27 -> 31 [label = \"t_39:{simple_count_result:PRIVATE:INT64}\"]\n28 -> 29 [label = \"t_40:{constant_data:PRIVATE:INT64}\"]\n29 -> 31 [label = \"t_18:{ge_out:PRIVATE:BOOL}\"]\n3 -> 6 [label = \"t_5:{encrypt_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_5:{encrypt_int_0:PRIVATE:INT64}\"]\n30 -> 31 [label = \"t_41:{if_out_count:PRIVATE:INT64}\"]\n31 -> 32 [label = \"t_19:{if_out_count:PRIVATE:INT64}\"]\n32 -> 33 [label = \"t_42:{if_out_count:PRIVATE:INT64}\"]\n4 -> 10 [label = \"t_7:{join_string_0:PRIVATE:STRING}\"]\n4 -> 13 [label = \"t_6:{groupby_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_7:{join_string_0:PRIVATE:STRING}\"]\n5 -> 6 [label = \"t_8:{constant_data:PUBLIC:INT64}\"]\n6 -> 7 [label = \"t_9:{constant_data:PRIVATE:INT64}\"]\n7 -> 12 [label = \"t_10:{gt_out:PRIVATE:BOOL}\"]\n8 -> 9 [label = \"t_11:{constant_data:PUBLIC:STRING}\"]\n9 -> 11 [label = \"t_12:{constant_data:PRIVATE:STRING}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 constant_5 broadcast_to_6 Greater_7 constant_8 broadcast_to_9 copy_10 copy_11 if_12 make_share_13 make_share_14 sort_15 oblivious_group_mark_16 count_17 sort_18 oblivious_group_mark_19 LogicalOr_20 sum_21 shuffle_22 make_public_23 filter_24 constant_25 broadcast_to_26 make_private_27 make_private_28 GreaterEqual_29 make_private_30 filter_31 copy_32 publish_result_33]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(1) from (select aggregate_int_0 from alice.tbl_0 as ta union select aggregate_int_0 from bob.tbl_0) ua;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select any_value(1) as expr_245,any_value(ta.aggregate_int_0) as expr_241 from alice.tbl_0 as ta group by ta.aggregate_int_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_7,t_8,},],attr:[sql:select 1 as 'expr_245','tbl_0'.'aggregate_int_0' from 'bob'.'tbl_0' group by 'tbl_0'.'aggregate_int_0';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"make_share:{in:[In:{t_3,},],out:[Out:{t_13,},],attr:[],party:[alice,bob,]}\"]\n3 [label=\"make_share:{in:[In:{t_7,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,]}\"]\n4 [label=\"concat:{in:[In:{t_13,t_14,},],out:[Out:{t_9,},],attr:[axis:0,],party:[alice,bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_4,},],out:[Out:{t_15,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_8,},],out:[Out:{t_16,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"concat:{in:[In:{t_15,t_16,},],out:[Out:{t_10,},],attr:[axis:0,],party:[alice,bob,]}\"]\n8 [label=\"sort:{in:[In:{t_10,t_9,},Key:{t_10,},],out:[Out:{t_17,t_18,},],attr:[reverse:[false],],party:[alice,bob,]}\"]\n9 [label=\"oblivious_group_mark:{in:[Key:{t_17,},],out:[Group:{t_19,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"shuffle:{in:[In:{t_18,t_19,},],out:[Out:{t_20,t_21,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"make_public:{in:[In:{t_21,},],out:[Out:{t_22,},],attr:[],party:[alice,bob,]}\"]\n12 [label=\"filter:{in:[Filter:{t_22,},In:{t_20,},],out:[Out:{t_11,},],attr:[],party:[alice,bob,]}\"]\n13 [label=\"shape:{in:[In:{t_11,},],out:[Out:{t_12,},],attr:[axis:0,],party:[alice,]}\"]\n14 [label=\"publish_result:{in:[In:{t_12,},],out:[Out:{t_23,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_3:{constant_data_firstrow:PRIVATE:BOOL}\"]\n0 -> 5 [label = \"t_4:{aggregate_int_0_firstrow:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_7:{constant_data_firstrow:PRIVATE:BOOL}\"]\n1 -> 6 [label = \"t_8:{aggregate_int_0_firstrow:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_21:{group_mark:SECRET:BOOL}\"]\n10 -> 12 [label = \"t_20:{constant_data_firstrow:SECRET:BOOL}\"]\n11 -> 12 [label = \"t_22:{group_mark:PUBLIC:BOOL}\"]\n12 -> 13 [label = \"t_11:{constant_data_firstrow_firstrow:SECRET:BOOL}\"]\n13 -> 14 [label = \"t_12:{constant_data_firstrow_firstrow_count:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_13:{constant_data_firstrow:SECRET:BOOL}\"]\n3 -> 4 [label = \"t_14:{constant_data_firstrow:SECRET:BOOL}\"]\n4 -> 8 [label = \"t_9:{constant_data_firstrow:SECRET:BOOL}\"]\n5 -> 7 [label = \"t_15:{aggregate_int_0_firstrow:SECRET:INT64}\"]\n6 -> 7 [label = \"t_16:{aggregate_int_0_firstrow:SECRET:INT64}\"]\n7 -> 8 [label = \"t_10:{aggregate_int_0_firstrow:SECRET:INT64}\"]\n7 -> 8 [label = \"t_10:{aggregate_int_0_firstrow:SECRET:INT64}\"]\n8 -> 10 [label = \"t_18:{constant_data_firstrow:SECRET:BOOL}\"]\n8 -> 9 [label = \"t_17:{aggregate_int_0_firstrow:SECRET:INT64}\"]\n9 -> 10 [label = \"t_19:{group_mark:SECRET:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 make_share_2 make_share_3 concat_4 make_share_5 make_share_6 concat_7 sort_8 oblivious_group_mark_9 shuffle_10 make_public_11 filter_12 shape_13 publish_result_14]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0, ta.compare_int_0 < tb.compare_int_0 from alice.tbl_1 as ta inner join bob.tbl_1 as tb on ta.join_int_0=tb.join_int_0 limit 1,11;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,t_3,},],attr:[sql:select ta.plain_int_0,ta.join_int_0,ta.compare_int_0 from alice.tbl_1 as ta;,table_refs:[alice.tbl_1],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,t_5,},],attr:[sql:select 'tb'.'join_int_0','tb'.'compare_int_0' from 'bob'.'tbl_1' as 'tb';,table_refs:[bob.tbl_1],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_4,},],out:[LeftJoinIndex:{t_12,},RightJoinIndex:{t_13,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_3,},RowsIndexFilter:{t_12,},],out:[Out:{t_6,t_7,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_5,},RowsIndexFilter:{t_13,},],out:[Out:{t_8,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_7,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_8,},],out:[Out:{t_15,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"Less:{in:[Left:{t_14,},Right:{t_15,},],out:[Out:{t_9,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"limit:{in:[In:{t_9,},],out:[Out:{t_11,},],attr:[count:11,offset:1,],party:[alice,bob,]}\"]\n9 [label=\"limit:{in:[In:{t_6,},],out:[Out:{t_10,},],attr:[count:11,offset:1,],party:[alice,]}\"]\n10 [label=\"make_private:{in:[In:{t_11,},],out:[Out:{t_16,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n11 [label=\"publish_result:{in:[In:{t_10,t_16,},],out:[Out:{t_17,t_18,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_5:{compare_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_16:{lt_out:PRIVATE:BOOL}\"]\n2 -> 3 [label = \"t_12:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_13:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_7:{compare_int_0:PRIVATE:INT64}\"]\n3 -> 9 [label = \"t_6:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_8:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_14:{compare_int_0:SECRET:INT64}\"]\n6 -> 7 [label = \"t_15:{compare_int_0:SECRET:INT64}\"]\n7 -> 8 [label = \"t_9:{lt_out:SECRET:BOOL}\"]\n8 -> 10 [label = \"t_11:{lt_out:SECRET:BOOL}\"]\n9 -> 11 [label = \"t_10:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 Less_7 limit_8 limit_9 make_private_10 publish_result_11]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0,tb.plain_int_0, sum(tb.aggregate_int_0), count(tb.encrypt_string_1) from alice.tbl_1 as ta inner join bob.tbl_1 as tb on ta.join_int_0 = tb.join_int_0 group by ta.plain_int_0, tb.plain_int_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_1 as ta;,table_refs:[alice.tbl_1],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,t_5,t_6,},],attr:[sql:select 'tb'.'plain_int_0','tb'.'join_int_0','tb'.'aggregate_int_0','tb'.'encrypt_string_1' from 'bob'.'tbl_1' as 'tb';,table_refs:[bob.tbl_1],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_4,},],out:[LeftJoinIndex:{t_15,},RightJoinIndex:{t_16,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_15,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_3,t_5,t_6,},RowsIndexFilter:{t_16,},],out:[Out:{t_8,t_9,t_10,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_8,},],out:[Out:{t_17,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"private_group:{in:[Key:{t_7,t_17,},],out:[GroupId:{t_18,},GroupNum:{t_19,},],attr:[],party:[alice,]}\"]\n7 [label=\"count:{in:[GroupId:{t_18,},GroupNum:{t_19,},In:{t_18,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n8 [label=\"make_public:{in:[In:{t_19,},],out:[Out:{t_20,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"make_share:{in:[In:{t_18,},],out:[Out:{t_21,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"make_share:{in:[In:{t_9,},],out:[Out:{t_22,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"private_group_secret_sum:{in:[GroupId:{t_21,},GroupNum:{t_20,},In:{t_22,},],out:[Out:{t_23,},],attr:[],party:[alice,bob,]}\"]\n12 [label=\"make_private:{in:[In:{t_23,},],out:[Out:{t_11,},],attr:[reveal_to:bob,],party:[alice,bob,]}\"]\n13 [label=\"firstrow:{in:[GroupId:{t_18,},GroupNum:{t_19,},In:{t_7,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n14 [label=\"firstrow:{in:[GroupId:{t_18,},GroupNum:{t_19,},In:{t_17,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n15 [label=\"copy:{in:[In:{t_11,},],out:[Out:{t_24,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n16 [label=\"publish_result:{in:[In:{t_13,t_14,t_24,t_12,},],out:[Out:{t_25,t_26,t_27,t_28,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_5:{aggregate_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_6:{encrypt_string_1:PRIVATE:STRING}\"]\n10 -> 11 [label = \"t_22:{aggregate_int_0:SECRET:INT64}\"]\n11 -> 12 [label = \"t_23:{aggregate_int_0_sum:SECRET:INT64}\"]\n12 -> 15 [label = \"t_11:{aggregate_int_0_sum:PRIVATE:INT64}\"]\n13 -> 16 [label = \"t_13:{plain_int_0_firstrow:PRIVATE:INT64}\"]\n14 -> 16 [label = \"t_14:{plain_int_0_firstrow:PRIVATE:INT64}\"]\n15 -> 16 [label = \"t_24:{aggregate_int_0_sum:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_15:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_16:{right_index:PRIVATE:INT64}\"]\n3 -> 13 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 10 [label = \"t_9:{aggregate_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_8:{plain_int_0:PRIVATE:INT64}\"]\n5 -> 14 [label = \"t_17:{plain_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_17:{plain_int_0:PRIVATE:INT64}\"]\n6 -> 13 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n6 -> 13 [label = \"t_19:{group_num:PRIVATE:INT64}\"]\n6 -> 14 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n6 -> 14 [label = \"t_19:{group_num:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_19:{group_num:PRIVATE:INT64}\"]\n6 -> 8 [label = \"t_19:{group_num:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n7 -> 16 [label = \"t_12:{simple_count_result:PRIVATE:INT64}\"]\n8 -> 11 [label = \"t_20:{group_num:PUBLIC:INT64}\"]\n9 -> 11 [label = \"t_21:{group_id:SECRET:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 private_group_6 count_7 make_public_8 make_share_9 make_share_10 private_group_secret_sum_11 make_private_12 firstrow_13 firstrow_14 copy_15 publish_result_16]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 1, batched: false, revealGroupCount: false}},\n\t{`select plain_int_0 from alice.tbl_1 where plain_int_0 in (2, 5, 15) and plain_int_1 not in (2, 5, 15);`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_21,},],attr:[sql:select tbl_1.plain_int_0 from alice.tbl_1 where (tbl_1.plain_int_0=2 or tbl_1.plain_int_0=5 or tbl_1.plain_int_0=15) and (not(tbl_1.plain_int_1=2 or tbl_1.plain_int_1=5 or tbl_1.plain_int_1=15));,table_refs:[alice.tbl_1],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_21,},],out:[Out:{t_22,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_21:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*), bob.gb_pl_en_int_0, carol.gb_en_pl_int_0, min(bob.ag_pl_en_int_0), max(carol.agg_en_pl_int_0) from alice.tbl_3 as alice join bob.tbl_3 as bob on alice.pl_jn_cp_int_0 = bob.jn_pl_cp_int_0 join carol.tbl_3 as carol on bob.cp_pl_jn_int_0 = carol.cp_jn_pl_int_0 group by bob.gb_pl_en_int_0, carol.gb_en_pl_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select alice.pl_jn_cp_int_0 from alice.tbl_3 as alice;,table_refs:[alice.tbl_3],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,t_3,t_4,t_5,},],attr:[sql:select 'bob'.'cp_pl_jn_int_0','bob'.'jn_pl_cp_int_0','bob'.'ag_pl_en_int_0','bob'.'gb_pl_en_int_0' from 'bob'.'tbl_3' as 'bob';,table_refs:[bob.tbl_3],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{},RightJoinIndex:{t_29,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,t_4,t_5,},RowsIndexFilter:{t_29,},],out:[Out:{t_6,t_7,t_8,},],attr:[],party:[bob,]}\"]\n4 [label=\"run_sql:{in:[],out:[Out:{t_9,t_10,t_11,},],attr:[sql:select carol.cp_jn_pl_int_0,carol.gb_en_pl_int_0,carol.agg_en_pl_int_0 from carol.tbl_3 as carol;,table_refs:[carol.tbl_3],],party:[carol,]}\"]\n5 [label=\"psi_join:{in:[Left:{t_6,},Right:{t_9,},],out:[LeftJoinIndex:{t_30,},RightJoinIndex:{t_31,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n6 [label=\"filter_by_index:{in:[Data:{t_7,t_8,},RowsIndexFilter:{t_30,},],out:[Out:{t_12,t_13,},],attr:[],party:[bob,]}\"]\n7 [label=\"filter_by_index:{in:[Data:{t_10,t_11,},RowsIndexFilter:{t_31,},],out:[Out:{t_14,t_15,},],attr:[],party:[carol,]}\"]\n8 [label=\"make_share:{in:[In:{t_13,},],out:[Out:{t_32,},],attr:[],party:[alice,bob,carol,]}\"]\n9 [label=\"make_share:{in:[In:{t_14,},],out:[Out:{t_33,},],attr:[],party:[alice,bob,carol,]}\"]\n10 [label=\"make_share:{in:[In:{t_12,},],out:[Out:{t_34,},],attr:[],party:[alice,bob,carol,]}\"]\n11 [label=\"make_share:{in:[In:{t_15,},],out:[Out:{t_35,},],attr:[],party:[alice,bob,carol,]}\"]\n12 [label=\"sort:{in:[In:{t_32,t_33,t_34,t_35,t_32,t_33,},Key:{t_32,t_33,},],out:[Out:{t_36,t_37,t_38,t_39,t_40,t_41,},],attr:[reverse:[false false],],party:[alice,bob,carol,]}\"]\n13 [label=\"oblivious_group_mark:{in:[Key:{t_36,t_37,},],out:[Group:{t_42,},],attr:[],party:[alice,bob,carol,]}\"]\n14 [label=\"count:{in:[Group:{t_42,},In:{t_42,},],out:[Out:{t_43,},],attr:[],party:[alice,bob,carol,]}\"]\n15 [label=\"min:{in:[Group:{t_42,},In:{t_38,},],out:[Out:{t_44,},],attr:[],party:[alice,bob,carol,]}\"]\n16 [label=\"max:{in:[Group:{t_42,},In:{t_39,},],out:[Out:{t_45,},],attr:[],party:[alice,bob,carol,]}\"]\n17 [label=\"shuffle:{in:[In:{t_43,t_44,t_45,t_40,t_41,t_42,},],out:[Out:{t_46,t_47,t_48,t_49,t_50,t_51,},],attr:[],party:[alice,bob,carol,]}\"]\n18 [label=\"make_public:{in:[In:{t_51,},],out:[Out:{t_52,},],attr:[],party:[alice,bob,carol,]}\"]\n19 [label=\"filter:{in:[Filter:{t_52,},In:{t_46,t_47,t_48,t_49,t_50,},],out:[Out:{t_16,t_17,t_18,t_19,t_20,},],attr:[],party:[alice,bob,carol,]}\"]\n20 [label=\"constant:{in:[],out:[Out:{t_21,},],attr:[scalar:4,to_status:1,],party:[alice,bob,carol,]}\"]\n21 [label=\"broadcast_to:{in:[In:{t_21,},ShapeRefTensor:{t_16,},],out:[Out:{t_22,},],attr:[],party:[alice,bob,carol,]}\"]\n22 [label=\"GreaterEqual:{in:[Left:{t_16,},Right:{t_22,},],out:[Out:{t_23,},],attr:[],party:[alice,bob,carol,]}\"]\n23 [label=\"make_public:{in:[In:{t_23,},],out:[Out:{t_53,},],attr:[],party:[alice,bob,carol,]}\"]\n24 [label=\"filter:{in:[Filter:{t_53,},In:{t_16,t_17,t_18,t_19,t_20,},],out:[Out:{t_24,t_25,t_26,t_27,t_28,},],attr:[],party:[alice,bob,carol,]}\"]\n25 [label=\"make_private:{in:[In:{t_24,},],out:[Out:{t_54,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n26 [label=\"make_private:{in:[In:{t_27,},],out:[Out:{t_55,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n27 [label=\"make_private:{in:[In:{t_28,},],out:[Out:{t_56,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n28 [label=\"make_private:{in:[In:{t_25,},],out:[Out:{t_57,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n29 [label=\"make_private:{in:[In:{t_26,},],out:[Out:{t_58,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n30 [label=\"publish_result:{in:[In:{t_54,t_55,t_56,t_57,t_58,},],out:[Out:{t_59,t_60,t_61,t_62,t_63,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{pl_jn_cp_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{jn_pl_cp_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_2:{cp_pl_jn_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_4:{ag_pl_en_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_5:{gb_pl_en_int_0:PRIVATE:INT64}\"]\n10 -> 12 [label = \"t_34:{ag_pl_en_int_0:SECRET:INT64}\"]\n11 -> 12 [label = \"t_35:{agg_en_pl_int_0:SECRET:INT64}\"]\n12 -> 13 [label = \"t_36:{gb_pl_en_int_0:SECRET:INT64}\"]\n12 -> 13 [label = \"t_37:{gb_en_pl_int_0:SECRET:INT64}\"]\n12 -> 15 [label = \"t_38:{ag_pl_en_int_0:SECRET:INT64}\"]\n12 -> 16 [label = \"t_39:{agg_en_pl_int_0:SECRET:INT64}\"]\n12 -> 17 [label = \"t_40:{gb_pl_en_int_0:SECRET:INT64}\"]\n12 -> 17 [label = \"t_41:{gb_en_pl_int_0:SECRET:INT64}\"]\n13 -> 14 [label = \"t_42:{group_mark:SECRET:BOOL}\"]\n13 -> 14 [label = \"t_42:{group_mark:SECRET:BOOL}\"]\n13 -> 15 [label = \"t_42:{group_mark:SECRET:BOOL}\"]\n13 -> 16 [label = \"t_42:{group_mark:SECRET:BOOL}\"]\n13 -> 17 [label = \"t_42:{group_mark:SECRET:BOOL}\"]\n14 -> 17 [label = \"t_43:{aggregated_group_simple_count:SECRET:INT64}\"]\n15 -> 17 [label = \"t_44:{ag_pl_en_int_0_min:SECRET:INT64}\"]\n16 -> 17 [label = \"t_45:{agg_en_pl_int_0_max:SECRET:INT64}\"]\n17 -> 18 [label = \"t_51:{group_mark:SECRET:BOOL}\"]\n17 -> 19 [label = \"t_46:{aggregated_group_simple_count:SECRET:INT64}\"]\n17 -> 19 [label = \"t_47:{ag_pl_en_int_0_min:SECRET:INT64}\"]\n17 -> 19 [label = \"t_48:{agg_en_pl_int_0_max:SECRET:INT64}\"]\n17 -> 19 [label = \"t_49:{gb_pl_en_int_0:SECRET:INT64}\"]\n17 -> 19 [label = \"t_50:{gb_en_pl_int_0:SECRET:INT64}\"]\n18 -> 19 [label = \"t_52:{group_mark:PUBLIC:BOOL}\"]\n19 -> 21 [label = \"t_16:{simple_count_result:SECRET:INT64}\"]\n19 -> 22 [label = \"t_16:{simple_count_result:SECRET:INT64}\"]\n19 -> 24 [label = \"t_16:{simple_count_result:SECRET:INT64}\"]\n19 -> 24 [label = \"t_17:{ag_pl_en_int_0_min:SECRET:INT64}\"]\n19 -> 24 [label = \"t_18:{agg_en_pl_int_0_max:SECRET:INT64}\"]\n19 -> 24 [label = \"t_19:{gb_pl_en_int_0_firstrow:SECRET:INT64}\"]\n19 -> 24 [label = \"t_20:{gb_en_pl_int_0_firstrow:SECRET:INT64}\"]\n2 -> 3 [label = \"t_29:{right_index:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_21:{constant_data:PUBLIC:INT64}\"]\n21 -> 22 [label = \"t_22:{constant_data:PUBLIC:INT64}\"]\n22 -> 23 [label = \"t_23:{ge_out:SECRET:BOOL}\"]\n23 -> 24 [label = \"t_53:{ge_out:PUBLIC:BOOL}\"]\n24 -> 25 [label = \"t_24:{simple_count_result:SECRET:INT64}\"]\n24 -> 26 [label = \"t_27:{gb_pl_en_int_0_firstrow:SECRET:INT64}\"]\n24 -> 27 [label = \"t_28:{gb_en_pl_int_0_firstrow:SECRET:INT64}\"]\n24 -> 28 [label = \"t_25:{ag_pl_en_int_0_min:SECRET:INT64}\"]\n24 -> 29 [label = \"t_26:{agg_en_pl_int_0_max:SECRET:INT64}\"]\n25 -> 30 [label = \"t_54:{simple_count_result:PRIVATE:INT64}\"]\n26 -> 30 [label = \"t_55:{gb_pl_en_int_0_firstrow:PRIVATE:INT64}\"]\n27 -> 30 [label = \"t_56:{gb_en_pl_int_0_firstrow:PRIVATE:INT64}\"]\n28 -> 30 [label = \"t_57:{ag_pl_en_int_0_min:PRIVATE:INT64}\"]\n29 -> 30 [label = \"t_58:{agg_en_pl_int_0_max:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_6:{cp_pl_jn_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_7:{ag_pl_en_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_8:{gb_pl_en_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_9:{cp_jn_pl_int_0:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_10:{gb_en_pl_int_0:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_11:{agg_en_pl_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_30:{left_index:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_31:{right_index:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_12:{ag_pl_en_int_0:PRIVATE:INT64}\"]\n6 -> 8 [label = \"t_13:{gb_pl_en_int_0:PRIVATE:INT64}\"]\n7 -> 11 [label = \"t_15:{agg_en_pl_int_0:PRIVATE:INT64}\"]\n7 -> 9 [label = \"t_14:{gb_en_pl_int_0:PRIVATE:INT64}\"]\n8 -> 12 [label = \"t_32:{gb_pl_en_int_0:SECRET:INT64}\"]\n8 -> 12 [label = \"t_32:{gb_pl_en_int_0:SECRET:INT64}\"]\n8 -> 12 [label = \"t_32:{gb_pl_en_int_0:SECRET:INT64}\"]\n9 -> 12 [label = \"t_33:{gb_en_pl_int_0:SECRET:INT64}\"]\n9 -> 12 [label = \"t_33:{gb_en_pl_int_0:SECRET:INT64}\"]\n9 -> 12 [label = \"t_33:{gb_en_pl_int_0:SECRET:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 run_sql_4 psi_join_5 filter_by_index_6 filter_by_index_7 make_share_8 make_share_9 make_share_10 make_share_11 sort_12 oblivious_group_mark_13 count_14 min_15 max_16 shuffle_17 make_public_18 filter_19 constant_20 broadcast_to_21 GreaterEqual_22 make_public_23 filter_24 make_private_25 make_private_26 make_private_27 make_private_28 make_private_29 publish_result_30]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: true}},\n\t{`select bob.cp_pl_jn_int_0 > carol.cp_jn_pl_int_0, bob.cp_pl_jn_int_1 > carol.cp_jn_pl_int_1 from alice.tbl_3 as alice join bob.tbl_3 as bob on alice.pl_jn_cp_int_0 = bob.jn_pl_cp_int_0 join carol.tbl_3 as carol on bob.cp_pl_jn_int_0 = carol.cp_jn_pl_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select alice.pl_jn_cp_int_0 from alice.tbl_3 as alice;,table_refs:[alice.tbl_3],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,t_3,t_4,},],attr:[sql:select 'bob'.'cp_pl_jn_int_0','bob'.'cp_pl_jn_int_1','bob'.'jn_pl_cp_int_0' from 'bob'.'tbl_3' as 'bob';,table_refs:[bob.tbl_3],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_4,},],out:[LeftJoinIndex:{},RightJoinIndex:{t_15,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,t_3,},RowsIndexFilter:{t_15,},],out:[Out:{t_5,t_6,},],attr:[],party:[bob,]}\"]\n4 [label=\"run_sql:{in:[],out:[Out:{t_7,t_8,},],attr:[sql:select carol.cp_jn_pl_int_0,carol.cp_jn_pl_int_1 from carol.tbl_3 as carol;,table_refs:[carol.tbl_3],],party:[carol,]}\"]\n5 [label=\"psi_join:{in:[Left:{t_5,},Right:{t_7,},],out:[LeftJoinIndex:{t_16,},RightJoinIndex:{t_17,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n6 [label=\"filter_by_index:{in:[Data:{t_5,t_6,},RowsIndexFilter:{t_16,},],out:[Out:{t_9,t_10,},],attr:[],party:[bob,]}\"]\n7 [label=\"filter_by_index:{in:[Data:{t_7,t_8,},RowsIndexFilter:{t_17,},],out:[Out:{t_11,t_12,},],attr:[],party:[carol,]}\"]\n8 [label=\"copy:{in:[In:{t_11,},],out:[Out:{t_18,},],attr:[input_party_codes:carol,output_party_codes:bob,],party:[carol,bob,]}\"]\n9 [label=\"Greater:{in:[Left:{t_9,},Right:{t_18,},],out:[Out:{t_13,},],attr:[],party:[bob,]}\"]\n10 [label=\"make_share:{in:[In:{t_10,},],out:[Out:{t_19,},],attr:[],party:[alice,bob,carol,]}\"]\n11 [label=\"make_share:{in:[In:{t_12,},],out:[Out:{t_20,},],attr:[],party:[alice,bob,carol,]}\"]\n12 [label=\"Greater:{in:[Left:{t_19,},Right:{t_20,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,carol,]}\"]\n13 [label=\"copy:{in:[In:{t_13,},],out:[Out:{t_21,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n14 [label=\"make_private:{in:[In:{t_14,},],out:[Out:{t_22,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n15 [label=\"publish_result:{in:[In:{t_21,t_22,},],out:[Out:{t_23,t_24,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{pl_jn_cp_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_4:{jn_pl_cp_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_2:{cp_pl_jn_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_3:{cp_pl_jn_int_1:PRIVATE:INT64}\"]\n10 -> 12 [label = \"t_19:{cp_pl_jn_int_1:SECRET:INT64}\"]\n11 -> 12 [label = \"t_20:{cp_jn_pl_int_1:SECRET:INT64}\"]\n12 -> 14 [label = \"t_14:{gt_out:SECRET:BOOL}\"]\n13 -> 15 [label = \"t_21:{gt_out:PRIVATE:BOOL}\"]\n14 -> 15 [label = \"t_22:{gt_out:PRIVATE:BOOL}\"]\n2 -> 3 [label = \"t_15:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_5:{cp_pl_jn_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_5:{cp_pl_jn_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_6:{cp_pl_jn_int_1:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_7:{cp_jn_pl_int_0:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_7:{cp_jn_pl_int_0:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_8:{cp_jn_pl_int_1:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_16:{left_index:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_17:{right_index:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_10:{cp_pl_jn_int_1:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_9:{cp_pl_jn_int_0:PRIVATE:INT64}\"]\n7 -> 11 [label = \"t_12:{cp_jn_pl_int_1:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_11:{cp_jn_pl_int_0:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_18:{cp_jn_pl_int_0:PRIVATE:INT64}\"]\n9 -> 13 [label = \"t_13:{gt_out:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 run_sql_4 psi_join_5 filter_by_index_6 filter_by_index_7 copy_8 Greater_9 make_share_10 make_share_11 Greater_12 copy_13 make_private_14 publish_result_15]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select bob.cp_pl_jn_int_0 > carol.cp_jn_pl_int_0 from alice.tbl_3 as alice join bob.tbl_3 as bob on alice.pl_jn_cp_int_0 = bob.jn_pl_cp_int_0 join carol.tbl_3 as carol on bob.cp_pl_jn_int_0 = carol.cp_jn_pl_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select alice.pl_jn_cp_int_0 from alice.tbl_3 as alice;,table_refs:[alice.tbl_3],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,t_3,},],attr:[sql:select 'bob'.'cp_pl_jn_int_0','bob'.'jn_pl_cp_int_0' from 'bob'.'tbl_3' as 'bob';,table_refs:[bob.tbl_3],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{},RightJoinIndex:{t_9,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_9,},],out:[Out:{t_4,},],attr:[],party:[bob,]}\"]\n4 [label=\"run_sql:{in:[],out:[Out:{t_5,},],attr:[sql:select carol.cp_jn_pl_int_0 from carol.tbl_3 as carol;,table_refs:[carol.tbl_3],],party:[carol,]}\"]\n5 [label=\"psi_join:{in:[Left:{t_4,},Right:{t_5,},],out:[LeftJoinIndex:{t_10,},RightJoinIndex:{t_11,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n6 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_10,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n7 [label=\"filter_by_index:{in:[Data:{t_5,},RowsIndexFilter:{t_11,},],out:[Out:{t_7,},],attr:[],party:[carol,]}\"]\n8 [label=\"copy:{in:[In:{t_7,},],out:[Out:{t_12,},],attr:[input_party_codes:carol,output_party_codes:bob,],party:[carol,bob,]}\"]\n9 [label=\"Greater:{in:[Left:{t_6,},Right:{t_12,},],out:[Out:{t_8,},],attr:[],party:[bob,]}\"]\n10 [label=\"copy:{in:[In:{t_8,},],out:[Out:{t_13,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n11 [label=\"publish_result:{in:[In:{t_13,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{pl_jn_cp_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{jn_pl_cp_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_2:{cp_pl_jn_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_13:{gt_out:PRIVATE:BOOL}\"]\n2 -> 3 [label = \"t_9:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_4:{cp_pl_jn_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_4:{cp_pl_jn_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_5:{cp_jn_pl_int_0:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_5:{cp_jn_pl_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_10:{left_index:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_11:{right_index:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_6:{cp_pl_jn_int_0:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_7:{cp_jn_pl_int_0:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_12:{cp_jn_pl_int_0:PRIVATE:INT64}\"]\n9 -> 10 [label = \"t_8:{gt_out:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 run_sql_4 psi_join_5 filter_by_index_6 filter_by_index_7 copy_8 Greater_9 copy_10 publish_result_11]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select if(ta.plain_int_0, tb.plain_int_0, ta.plain_int_0) as res,if(ta.compare_int_0 > tb.compare_int_0, ta.compare_int_0, tb.compare_int_0) > ta.compare_int_1 as res1, if(ta.plain_int_0, ta.compare_int_0, tb.compare_int_0) > ta.compare_int_1 as res1, if(ta.compare_int_0 > tb.compare_int_1, ta.plain_string_0, tb.plain_string_0) as res2 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,t_3,t_4,t_5,},],attr:[sql:select ta.plain_int_0,ta.join_int_0,ta.compare_int_0,ta.plain_string_0,ta.compare_int_1 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_6,t_7,t_8,t_9,t_10,},],attr:[sql:select 'tb'.'plain_int_0','tb'.'join_int_0','tb'.'compare_int_0','tb'.'plain_string_0','tb'.'compare_int_1' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_7,},],out:[LeftJoinIndex:{t_27,},RightJoinIndex:{t_28,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_3,t_4,t_5,},RowsIndexFilter:{t_27,},],out:[Out:{t_11,t_12,t_13,t_14,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_6,t_8,t_9,t_10,},RowsIndexFilter:{t_28,},],out:[Out:{t_15,t_16,t_17,t_18,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_15,},],out:[Out:{t_29,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"if:{in:[Condition:{t_11,},ValueIfFalse:{t_11,},ValueIfTrue:{t_29,},],out:[Out:{t_19,},],attr:[],party:[alice,]}\"]\n7 [label=\"make_share:{in:[In:{t_12,},],out:[Out:{t_30,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"make_share:{in:[In:{t_16,},],out:[Out:{t_31,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"Greater:{in:[Left:{t_30,},Right:{t_31,},],out:[Out:{t_20,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"if:{in:[Condition:{t_20,},ValueIfFalse:{t_31,},ValueIfTrue:{t_30,},],out:[Out:{t_21,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"make_share:{in:[In:{t_14,},],out:[Out:{t_32,},],attr:[],party:[alice,bob,]}\"]\n12 [label=\"Greater:{in:[Left:{t_21,},Right:{t_32,},],out:[Out:{t_22,},],attr:[],party:[alice,bob,]}\"]\n13 [label=\"make_public:{in:[In:{t_11,},],out:[Out:{t_33,},],attr:[],party:[alice,bob,]}\"]\n14 [label=\"if:{in:[Condition:{t_33,},ValueIfFalse:{t_31,},ValueIfTrue:{t_30,},],out:[Out:{t_23,},],attr:[],party:[alice,bob,]}\"]\n15 [label=\"Greater:{in:[Left:{t_23,},Right:{t_32,},],out:[Out:{t_24,},],attr:[],party:[alice,bob,]}\"]\n16 [label=\"make_share:{in:[In:{t_18,},],out:[Out:{t_34,},],attr:[],party:[alice,bob,]}\"]\n17 [label=\"Greater:{in:[Left:{t_30,},Right:{t_34,},],out:[Out:{t_25,},],attr:[],party:[alice,bob,]}\"]\n18 [label=\"make_public:{in:[In:{t_13,},],out:[Out:{t_35,},],attr:[],party:[alice,bob,]}\"]\n19 [label=\"make_public:{in:[In:{t_17,},],out:[Out:{t_36,},],attr:[],party:[alice,bob,]}\"]\n20 [label=\"if:{in:[Condition:{t_25,},ValueIfFalse:{t_36,},ValueIfTrue:{t_35,},],out:[Out:{t_26,},],attr:[],party:[alice,bob,]}\"]\n21 [label=\"make_private:{in:[In:{t_22,},],out:[Out:{t_37,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n22 [label=\"make_private:{in:[In:{t_24,},],out:[Out:{t_38,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n23 [label=\"make_public:{in:[In:{t_26,},],out:[Out:{t_39,},],attr:[],party:[alice,bob,]}\"]\n24 [label=\"make_private:{in:[In:{t_39,},],out:[Out:{t_40,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n25 [label=\"publish_result:{in:[In:{t_19,t_37,t_38,t_40,},],out:[Out:{t_41,t_42,t_43,t_44,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{compare_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_4:{plain_string_0:PRIVATE:STRING}\"]\n0 -> 3 [label = \"t_5:{compare_int_1:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_7:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_10:{compare_int_1:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_6:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_8:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_9:{plain_string_0:PRIVATE:STRING}\"]\n10 -> 12 [label = \"t_21:{if_out:SECRET:INT64}\"]\n11 -> 12 [label = \"t_32:{compare_int_1:SECRET:INT64}\"]\n11 -> 15 [label = \"t_32:{compare_int_1:SECRET:INT64}\"]\n12 -> 21 [label = \"t_22:{gt_out:SECRET:BOOL}\"]\n13 -> 14 [label = \"t_33:{plain_int_0:PUBLIC:INT64}\"]\n14 -> 15 [label = \"t_23:{if_out:SECRET:INT64}\"]\n15 -> 22 [label = \"t_24:{gt_out:SECRET:BOOL}\"]\n16 -> 17 [label = \"t_34:{compare_int_1:SECRET:INT64}\"]\n17 -> 20 [label = \"t_25:{gt_out:SECRET:BOOL}\"]\n18 -> 20 [label = \"t_35:{plain_string_0:PUBLIC:STRING}\"]\n19 -> 20 [label = \"t_36:{plain_string_0:PUBLIC:STRING}\"]\n2 -> 3 [label = \"t_27:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_28:{right_index:PRIVATE:INT64}\"]\n20 -> 23 [label = \"t_26:{if_out:SECRET:STRING}\"]\n21 -> 25 [label = \"t_37:{gt_out:PRIVATE:BOOL}\"]\n22 -> 25 [label = \"t_38:{gt_out:PRIVATE:BOOL}\"]\n23 -> 24 [label = \"t_39:{if_out:PUBLIC:STRING}\"]\n24 -> 25 [label = \"t_40:{if_out:PRIVATE:STRING}\"]\n3 -> 11 [label = \"t_14:{compare_int_1:PRIVATE:INT64}\"]\n3 -> 13 [label = \"t_11:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 18 [label = \"t_13:{plain_string_0:PRIVATE:STRING}\"]\n3 -> 6 [label = \"t_11:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_11:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_12:{compare_int_0:PRIVATE:INT64}\"]\n4 -> 16 [label = \"t_18:{compare_int_1:PRIVATE:INT64}\"]\n4 -> 19 [label = \"t_17:{plain_string_0:PRIVATE:STRING}\"]\n4 -> 5 [label = \"t_15:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 8 [label = \"t_16:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_29:{plain_int_0:PRIVATE:INT64}\"]\n6 -> 25 [label = \"t_19:{if_out:PRIVATE:INT64}\"]\n7 -> 10 [label = \"t_30:{compare_int_0:SECRET:INT64}\"]\n7 -> 14 [label = \"t_30:{compare_int_0:SECRET:INT64}\"]\n7 -> 17 [label = \"t_30:{compare_int_0:SECRET:INT64}\"]\n7 -> 9 [label = \"t_30:{compare_int_0:SECRET:INT64}\"]\n8 -> 10 [label = \"t_31:{compare_int_0:SECRET:INT64}\"]\n8 -> 14 [label = \"t_31:{compare_int_0:SECRET:INT64}\"]\n8 -> 9 [label = \"t_31:{compare_int_0:SECRET:INT64}\"]\n9 -> 10 [label = \"t_20:{gt_out:SECRET:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 if_6 make_share_7 make_share_8 Greater_9 if_10 make_share_11 Greater_12 make_public_13 if_14 Greater_15 make_share_16 Greater_17 make_public_18 make_public_19 if_20 make_private_21 make_private_22 make_public_23 make_private_24 publish_result_25]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select key1, key2, count(*) as c, count(distinct bob_encrypt) as cd, sum(bob_aggregate) as sb, max(carol_aggregate) as sc, min(carol_aggregate) as min_ca, avg(carol_aggregate) as avg_ca from (select bob.plain_int_0 as bob_encrypt, bob.plain_int_0 as bob_aggregate, carol.plain_int_0 as carol_aggregate, alice.plain_int_0 as alice_join, bob.plain_int_0 as bob_join, carol.plain_int_0 as carol_join, alice.plain_int_0 + bob.plain_int_0 as key1, carol.plain_int_0 + bob.plain_int_0 as key2 from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol) as tt where alice_join = bob_join and bob_join = carol_join group by key1, key2;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select alice.plain_int_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'bob'.'plain_int_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_30,},RightJoinIndex:{t_31,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_30,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_31,},],out:[Out:{t_4,},],attr:[],party:[bob,]}\"]\n5 [label=\"run_sql:{in:[],out:[Out:{t_5,},],attr:[sql:select carol.plain_int_0 from carol.tbl_0 as carol;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n6 [label=\"psi_join:{in:[Left:{t_4,},Right:{t_5,},],out:[LeftJoinIndex:{t_32,},RightJoinIndex:{t_33,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n7 [label=\"copy:{in:[In:{t_32,},],out:[Out:{t_34,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter_by_index:{in:[Data:{t_3,},RowsIndexFilter:{t_34,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n9 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_32,},],out:[Out:{t_7,},],attr:[],party:[bob,]}\"]\n10 [label=\"filter_by_index:{in:[Data:{t_5,},RowsIndexFilter:{t_33,},],out:[Out:{t_8,},],attr:[],party:[carol,]}\"]\n11 [label=\"copy:{in:[In:{t_7,},],out:[Out:{t_35,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n12 [label=\"Add:{in:[Left:{t_6,},Right:{t_35,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n13 [label=\"copy:{in:[In:{t_8,},],out:[Out:{t_36,},],attr:[input_party_codes:carol,output_party_codes:alice,],party:[carol,alice,]}\"]\n14 [label=\"Add:{in:[Left:{t_36,},Right:{t_35,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n15 [label=\"private_group:{in:[Key:{t_9,t_10,},],out:[GroupId:{t_37,},GroupNum:{t_38,},],attr:[],party:[alice,]}\"]\n16 [label=\"count:{in:[GroupId:{t_37,},GroupNum:{t_38,},In:{t_37,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n17 [label=\"count_distinct:{in:[GroupId:{t_37,},GroupNum:{t_38,},In:{t_35,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n18 [label=\"sum:{in:[GroupId:{t_37,},GroupNum:{t_38,},In:{t_35,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n19 [label=\"max:{in:[GroupId:{t_37,},GroupNum:{t_38,},In:{t_36,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n20 [label=\"min:{in:[GroupId:{t_37,},GroupNum:{t_38,},In:{t_36,},],out:[Out:{t_15,},],attr:[],party:[alice,]}\"]\n21 [label=\"avg:{in:[GroupId:{t_37,},GroupNum:{t_38,},In:{t_36,},],out:[Out:{t_16,},],attr:[],party:[alice,]}\"]\n22 [label=\"firstrow:{in:[GroupId:{t_37,},GroupNum:{t_38,},In:{t_9,},],out:[Out:{t_17,},],attr:[],party:[alice,]}\"]\n23 [label=\"firstrow:{in:[GroupId:{t_37,},GroupNum:{t_38,},In:{t_10,},],out:[Out:{t_18,},],attr:[],party:[alice,]}\"]\n24 [label=\"constant:{in:[],out:[Out:{t_19,},],attr:[scalar:4,to_status:1,],party:[alice,bob,carol,]}\"]\n25 [label=\"broadcast_to:{in:[In:{t_19,},ShapeRefTensor:{t_11,},],out:[Out:{t_20,},],attr:[],party:[alice,]}\"]\n26 [label=\"GreaterEqual:{in:[Left:{t_11,},Right:{t_20,},],out:[Out:{t_21,},],attr:[],party:[alice,]}\"]\n27 [label=\"filter:{in:[Filter:{t_21,},In:{t_11,t_12,t_13,t_14,t_15,t_16,t_17,t_18,},],out:[Out:{t_22,t_23,t_24,t_25,t_26,t_27,t_28,t_29,},],attr:[],party:[alice,]}\"]\n28 [label=\"publish_result:{in:[In:{t_28,t_29,t_22,t_23,t_24,t_25,t_26,t_27,},],out:[Out:{t_39,t_40,t_41,t_42,t_43,t_44,t_45,t_46,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n10 -> 13 [label = \"t_8:{plain_int_0:PRIVATE:INT64}\"]\n11 -> 12 [label = \"t_35:{plain_int_0:PRIVATE:INT64}\"]\n11 -> 14 [label = \"t_35:{plain_int_0:PRIVATE:INT64}\"]\n11 -> 17 [label = \"t_35:{plain_int_0:PRIVATE:INT64}\"]\n11 -> 18 [label = \"t_35:{plain_int_0:PRIVATE:INT64}\"]\n12 -> 15 [label = \"t_9:{plus_out:PRIVATE:INT64}\"]\n12 -> 22 [label = \"t_9:{plus_out:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_36:{plain_int_0:PRIVATE:INT64}\"]\n13 -> 19 [label = \"t_36:{plain_int_0:PRIVATE:INT64}\"]\n13 -> 20 [label = \"t_36:{plain_int_0:PRIVATE:INT64}\"]\n13 -> 21 [label = \"t_36:{plain_int_0:PRIVATE:INT64}\"]\n14 -> 15 [label = \"t_10:{plus_out:PRIVATE:INT64}\"]\n14 -> 23 [label = \"t_10:{plus_out:PRIVATE:INT64}\"]\n15 -> 16 [label = \"t_37:{group_id:PRIVATE:INT64}\"]\n15 -> 16 [label = \"t_37:{group_id:PRIVATE:INT64}\"]\n15 -> 16 [label = \"t_38:{group_num:PRIVATE:INT64}\"]\n15 -> 17 [label = \"t_37:{group_id:PRIVATE:INT64}\"]\n15 -> 17 [label = \"t_38:{group_num:PRIVATE:INT64}\"]\n15 -> 18 [label = \"t_37:{group_id:PRIVATE:INT64}\"]\n15 -> 18 [label = \"t_38:{group_num:PRIVATE:INT64}\"]\n15 -> 19 [label = \"t_37:{group_id:PRIVATE:INT64}\"]\n15 -> 19 [label = \"t_38:{group_num:PRIVATE:INT64}\"]\n15 -> 20 [label = \"t_37:{group_id:PRIVATE:INT64}\"]\n15 -> 20 [label = \"t_38:{group_num:PRIVATE:INT64}\"]\n15 -> 21 [label = \"t_37:{group_id:PRIVATE:INT64}\"]\n15 -> 21 [label = \"t_38:{group_num:PRIVATE:INT64}\"]\n15 -> 22 [label = \"t_37:{group_id:PRIVATE:INT64}\"]\n15 -> 22 [label = \"t_38:{group_num:PRIVATE:INT64}\"]\n15 -> 23 [label = \"t_37:{group_id:PRIVATE:INT64}\"]\n15 -> 23 [label = \"t_38:{group_num:PRIVATE:INT64}\"]\n16 -> 25 [label = \"t_11:{simple_count_result:PRIVATE:INT64}\"]\n16 -> 26 [label = \"t_11:{simple_count_result:PRIVATE:INT64}\"]\n16 -> 27 [label = \"t_11:{simple_count_result:PRIVATE:INT64}\"]\n17 -> 27 [label = \"t_12:{plain_int_0_count:PRIVATE:INT64}\"]\n18 -> 27 [label = \"t_13:{plain_int_0_sum:PRIVATE:INT64}\"]\n19 -> 27 [label = \"t_14:{plain_int_0_max:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_30:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_31:{right_index:PRIVATE:INT64}\"]\n20 -> 27 [label = \"t_15:{plain_int_0_min:PRIVATE:INT64}\"]\n21 -> 27 [label = \"t_16:{plain_int_0_avg:PRIVATE:FLOAT64}\"]\n22 -> 27 [label = \"t_17:{plus_out_firstrow:PRIVATE:INT64}\"]\n23 -> 27 [label = \"t_18:{plus_out_firstrow:PRIVATE:INT64}\"]\n24 -> 25 [label = \"t_19:{constant_data:PUBLIC:INT64}\"]\n25 -> 26 [label = \"t_20:{constant_data:PRIVATE:INT64}\"]\n26 -> 27 [label = \"t_21:{ge_out:PRIVATE:BOOL}\"]\n27 -> 28 [label = \"t_22:{simple_count_result:PRIVATE:INT64}\"]\n27 -> 28 [label = \"t_23:{plain_int_0_count:PRIVATE:INT64}\"]\n27 -> 28 [label = \"t_24:{plain_int_0_sum:PRIVATE:INT64}\"]\n27 -> 28 [label = \"t_25:{plain_int_0_max:PRIVATE:INT64}\"]\n27 -> 28 [label = \"t_26:{plain_int_0_min:PRIVATE:INT64}\"]\n27 -> 28 [label = \"t_27:{plain_int_0_avg:PRIVATE:FLOAT64}\"]\n27 -> 28 [label = \"t_28:{plus_out_firstrow:PRIVATE:INT64}\"]\n27 -> 28 [label = \"t_29:{plus_out_firstrow:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_33:{right_index:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_32:{left_index:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_32:{left_index:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_34:{left_index:PRIVATE:INT64}\"]\n8 -> 12 [label = \"t_6:{plain_int_0:PRIVATE:INT64}\"]\n9 -> 11 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 run_sql_5 psi_join_6 copy_7 filter_by_index_8 filter_by_index_9 filter_by_index_10 copy_11 Add_12 copy_13 Add_14 private_group_15 count_16 count_distinct_17 sum_18 max_19 min_20 avg_21 firstrow_22 firstrow_23 constant_24 broadcast_to_25 GreaterEqual_26 filter_27 publish_result_28]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*) from (select ta.groupby_string_0 from alice.tbl_0 as ta union select tb.groupby_string_0 from bob.tbl_0 as tb union select tc.groupby_string_0 from carol.tbl_0 as tc) as uu`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select any_value(1) as expr_365,any_value(ta.groupby_string_0) as expr_361 from alice.tbl_0 as ta group by ta.groupby_string_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_7,t_8,},],attr:[sql:select 1 as 'expr_365','tb'.'groupby_string_0' from 'bob'.'tbl_0' as 'tb' group by 'tb'.'groupby_string_0';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"run_sql:{in:[],out:[Out:{t_11,t_12,},],attr:[sql:select 1 as expr_365,tc.groupby_string_0 from carol.tbl_0 as tc group by tc.groupby_string_0;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n3 [label=\"make_share:{in:[In:{t_3,},],out:[Out:{t_17,},],attr:[],party:[alice,bob,carol,]}\"]\n4 [label=\"make_share:{in:[In:{t_7,},],out:[Out:{t_18,},],attr:[],party:[alice,bob,carol,]}\"]\n5 [label=\"make_share:{in:[In:{t_11,},],out:[Out:{t_19,},],attr:[],party:[alice,bob,carol,]}\"]\n6 [label=\"concat:{in:[In:{t_17,t_18,t_19,},],out:[Out:{t_13,},],attr:[axis:0,],party:[alice,bob,carol,]}\"]\n7 [label=\"make_share:{in:[In:{t_4,},],out:[Out:{t_20,},],attr:[],party:[alice,bob,carol,]}\"]\n8 [label=\"make_share:{in:[In:{t_8,},],out:[Out:{t_21,},],attr:[],party:[alice,bob,carol,]}\"]\n9 [label=\"make_share:{in:[In:{t_12,},],out:[Out:{t_22,},],attr:[],party:[alice,bob,carol,]}\"]\n10 [label=\"concat:{in:[In:{t_20,t_21,t_22,},],out:[Out:{t_14,},],attr:[axis:0,],party:[alice,bob,carol,]}\"]\n11 [label=\"sort:{in:[In:{t_14,t_13,},Key:{t_14,},],out:[Out:{t_23,t_24,},],attr:[reverse:[false],],party:[alice,bob,carol,]}\"]\n12 [label=\"oblivious_group_mark:{in:[Key:{t_23,},],out:[Group:{t_25,},],attr:[],party:[alice,bob,carol,]}\"]\n13 [label=\"shuffle:{in:[In:{t_24,t_25,},],out:[Out:{t_26,t_27,},],attr:[],party:[alice,bob,carol,]}\"]\n14 [label=\"make_public:{in:[In:{t_27,},],out:[Out:{t_28,},],attr:[],party:[alice,bob,carol,]}\"]\n15 [label=\"filter:{in:[Filter:{t_28,},In:{t_26,},],out:[Out:{t_15,},],attr:[],party:[alice,bob,carol,]}\"]\n16 [label=\"shape:{in:[In:{t_15,},],out:[Out:{t_16,},],attr:[axis:0,],party:[alice,]}\"]\n17 [label=\"publish_result:{in:[In:{t_16,},],out:[Out:{t_29,},],attr:[],party:[alice,]}\"]\n0 -> 3 [label = \"t_3:{constant_data_firstrow:PRIVATE:BOOL}\"]\n0 -> 7 [label = \"t_4:{groupby_string_0_firstrow:PRIVATE:STRING}\"]\n1 -> 4 [label = \"t_7:{constant_data_firstrow:PRIVATE:BOOL}\"]\n1 -> 8 [label = \"t_8:{groupby_string_0_firstrow:PRIVATE:STRING}\"]\n10 -> 11 [label = \"t_14:{groupby_string_0_firstrow:SECRET:STRING}\"]\n10 -> 11 [label = \"t_14:{groupby_string_0_firstrow:SECRET:STRING}\"]\n11 -> 12 [label = \"t_23:{groupby_string_0_firstrow:SECRET:STRING}\"]\n11 -> 13 [label = \"t_24:{constant_data_firstrow:SECRET:BOOL}\"]\n12 -> 13 [label = \"t_25:{group_mark:SECRET:BOOL}\"]\n13 -> 14 [label = \"t_27:{group_mark:SECRET:BOOL}\"]\n13 -> 15 [label = \"t_26:{constant_data_firstrow:SECRET:BOOL}\"]\n14 -> 15 [label = \"t_28:{group_mark:PUBLIC:BOOL}\"]\n15 -> 16 [label = \"t_15:{constant_data_firstrow_firstrow:SECRET:BOOL}\"]\n16 -> 17 [label = \"t_16:{constant_data_firstrow_firstrow_count:PRIVATE:INT64}\"]\n2 -> 5 [label = \"t_11:{constant_data_firstrow:PRIVATE:BOOL}\"]\n2 -> 9 [label = \"t_12:{groupby_string_0_firstrow:PRIVATE:STRING}\"]\n3 -> 6 [label = \"t_17:{constant_data_firstrow:SECRET:BOOL}\"]\n4 -> 6 [label = \"t_18:{constant_data_firstrow:SECRET:BOOL}\"]\n5 -> 6 [label = \"t_19:{constant_data_firstrow:SECRET:BOOL}\"]\n6 -> 11 [label = \"t_13:{constant_data_firstrow:SECRET:BOOL}\"]\n7 -> 10 [label = \"t_20:{groupby_string_0_firstrow:SECRET:STRING}\"]\n8 -> 10 [label = \"t_21:{groupby_string_0_firstrow:SECRET:STRING}\"]\n9 -> 10 [label = \"t_22:{groupby_string_0_firstrow:SECRET:STRING}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 run_sql_2 make_share_3 make_share_4 make_share_5 concat_6 make_share_7 make_share_8 make_share_9 concat_10 sort_11 oblivious_group_mark_12 shuffle_13 make_public_14 filter_15 shape_16 publish_result_17]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select alice.encrypt_float_1 from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.plain_int_0 = bob.join_int_0 and bob.join_int_1 = carol.join_int_1;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select alice.plain_int_0,alice.encrypt_float_1 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'bob'.'join_int_0','bob'.'join_int_1' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{t_10,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_9,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_10,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"run_sql:{in:[],out:[Out:{t_7,},],attr:[sql:select carol.join_int_1 from carol.tbl_0 as carol;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n6 [label=\"psi_join:{in:[Left:{t_6,},Right:{t_7,},],out:[LeftJoinIndex:{t_11,},RightJoinIndex:{},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n7 [label=\"copy:{in:[In:{t_11,},],out:[Out:{t_12,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter_by_index:{in:[Data:{t_5,},RowsIndexFilter:{t_12,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n9 [label=\"publish_result:{in:[In:{t_8,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{encrypt_float_1:PRIVATE:FLOAT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{join_int_1:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_10:{right_index:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_5:{encrypt_float_1:PRIVATE:FLOAT64}\"]\n4 -> 6 [label = \"t_6:{join_int_1:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_7:{join_int_1:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_11:{left_index:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_12:{left_index:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_8:{encrypt_float_1:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 run_sql_5 psi_join_6 copy_7 filter_by_index_8 publish_result_9]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*) as c, count(distinct bob.encrypt_int_0) as cd, sum(bob.aggregate_int_0) as sb, sum(carol.aggregate_int_0) as sc from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0 group by alice.groupby_int_0 + bob.groupby_int_0, carol.groupby_int_0 + bob.groupby_int_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select alice.join_int_0,alice.groupby_int_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,t_5,t_6,},],attr:[sql:select 'bob'.'join_int_0','bob'.'groupby_int_0','bob'.'aggregate_int_0','bob'.'encrypt_int_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_34,},RightJoinIndex:{t_35,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_34,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_3,t_4,t_5,t_6,},RowsIndexFilter:{t_35,},],out:[Out:{t_8,t_9,t_10,t_11,},],attr:[],party:[bob,]}\"]\n5 [label=\"run_sql:{in:[],out:[Out:{t_12,t_13,t_14,},],attr:[sql:select carol.join_int_0,carol.groupby_int_0,carol.aggregate_int_0 from carol.tbl_0 as carol;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n6 [label=\"psi_join:{in:[Left:{t_8,},Right:{t_12,},],out:[LeftJoinIndex:{t_36,},RightJoinIndex:{t_37,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n7 [label=\"copy:{in:[In:{t_36,},],out:[Out:{t_38,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter_by_index:{in:[Data:{t_7,},RowsIndexFilter:{t_38,},],out:[Out:{t_15,},],attr:[],party:[alice,]}\"]\n9 [label=\"filter_by_index:{in:[Data:{t_9,t_10,t_11,},RowsIndexFilter:{t_36,},],out:[Out:{t_16,t_17,t_18,},],attr:[],party:[bob,]}\"]\n10 [label=\"filter_by_index:{in:[Data:{t_13,t_14,},RowsIndexFilter:{t_37,},],out:[Out:{t_19,t_20,},],attr:[],party:[carol,]}\"]\n11 [label=\"make_share:{in:[In:{t_15,},],out:[Out:{t_39,},],attr:[],party:[alice,bob,carol,]}\"]\n12 [label=\"make_share:{in:[In:{t_16,},],out:[Out:{t_40,},],attr:[],party:[alice,bob,carol,]}\"]\n13 [label=\"Add:{in:[Left:{t_39,},Right:{t_40,},],out:[Out:{t_21,},],attr:[],party:[alice,bob,carol,]}\"]\n14 [label=\"make_share:{in:[In:{t_19,},],out:[Out:{t_41,},],attr:[],party:[alice,bob,carol,]}\"]\n15 [label=\"Add:{in:[Left:{t_41,},Right:{t_40,},],out:[Out:{t_22,},],attr:[],party:[alice,bob,carol,]}\"]\n16 [label=\"make_share:{in:[In:{t_18,},],out:[Out:{t_42,},],attr:[],party:[alice,bob,carol,]}\"]\n17 [label=\"make_share:{in:[In:{t_17,},],out:[Out:{t_43,},],attr:[],party:[alice,bob,carol,]}\"]\n18 [label=\"make_share:{in:[In:{t_20,},],out:[Out:{t_44,},],attr:[],party:[alice,bob,carol,]}\"]\n19 [label=\"sort:{in:[In:{t_21,t_22,t_42,t_43,t_44,},Key:{t_21,t_22,},],out:[Out:{t_45,t_46,t_47,t_48,t_49,},],attr:[reverse:[false false],],party:[alice,bob,carol,]}\"]\n20 [label=\"oblivious_group_mark:{in:[Key:{t_45,t_46,},],out:[Group:{t_50,},],attr:[],party:[alice,bob,carol,]}\"]\n21 [label=\"count:{in:[Group:{t_50,},In:{t_50,},],out:[Out:{t_51,},],attr:[],party:[alice,bob,carol,]}\"]\n22 [label=\"sort:{in:[In:{t_47,},Key:{t_45,t_46,t_47,},],out:[Out:{t_53,},],attr:[reverse:[false false false],],party:[alice,bob,carol,]}\"]\n23 [label=\"oblivious_group_mark:{in:[Key:{t_53,},],out:[Group:{t_54,},],attr:[],party:[alice,bob,carol,]}\"]\n24 [label=\"LogicalOr:{in:[Left:{t_50,},Right:{t_54,},],out:[Out:{t_55,},],attr:[],party:[alice,bob,carol,]}\"]\n25 [label=\"sum:{in:[Group:{t_50,},In:{t_55,},],out:[Out:{t_52,},],attr:[],party:[alice,bob,carol,]}\"]\n26 [label=\"sum:{in:[Group:{t_50,},In:{t_48,},],out:[Out:{t_56,},],attr:[],party:[alice,bob,carol,]}\"]\n27 [label=\"sum:{in:[Group:{t_50,},In:{t_49,},],out:[Out:{t_57,},],attr:[],party:[alice,bob,carol,]}\"]\n28 [label=\"shuffle:{in:[In:{t_51,t_52,t_56,t_57,t_50,},],out:[Out:{t_58,t_59,t_60,t_61,t_62,},],attr:[],party:[alice,bob,carol,]}\"]\n29 [label=\"make_public:{in:[In:{t_62,},],out:[Out:{t_63,},],attr:[],party:[alice,bob,carol,]}\"]\n30 [label=\"filter:{in:[Filter:{t_63,},In:{t_58,t_59,t_60,t_61,},],out:[Out:{t_23,t_24,t_25,t_26,},],attr:[],party:[alice,bob,carol,]}\"]\n31 [label=\"constant:{in:[],out:[Out:{t_27,},],attr:[scalar:4,to_status:1,],party:[alice,bob,carol,]}\"]\n32 [label=\"broadcast_to:{in:[In:{t_27,},ShapeRefTensor:{t_23,},],out:[Out:{t_28,},],attr:[],party:[alice,bob,carol,]}\"]\n33 [label=\"GreaterEqual:{in:[Left:{t_23,},Right:{t_28,},],out:[Out:{t_29,},],attr:[],party:[alice,bob,carol,]}\"]\n34 [label=\"make_public:{in:[In:{t_29,},],out:[Out:{t_64,},],attr:[],party:[alice,bob,carol,]}\"]\n35 [label=\"filter:{in:[Filter:{t_64,},In:{t_23,t_24,t_25,t_26,},],out:[Out:{t_30,t_31,t_32,t_33,},],attr:[],party:[alice,bob,carol,]}\"]\n36 [label=\"make_private:{in:[In:{t_30,},],out:[Out:{t_65,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n37 [label=\"make_private:{in:[In:{t_31,},],out:[Out:{t_66,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n38 [label=\"make_private:{in:[In:{t_32,},],out:[Out:{t_67,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n39 [label=\"make_private:{in:[In:{t_33,},],out:[Out:{t_68,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n40 [label=\"publish_result:{in:[In:{t_65,t_66,t_67,t_68,},],out:[Out:{t_69,t_70,t_71,t_72,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{groupby_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{groupby_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_5:{aggregate_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_6:{encrypt_int_0:PRIVATE:INT64}\"]\n10 -> 14 [label = \"t_19:{groupby_int_0:PRIVATE:INT64}\"]\n10 -> 18 [label = \"t_20:{aggregate_int_0:PRIVATE:INT64}\"]\n11 -> 13 [label = \"t_39:{groupby_int_0:SECRET:INT64}\"]\n12 -> 13 [label = \"t_40:{groupby_int_0:SECRET:INT64}\"]\n12 -> 15 [label = \"t_40:{groupby_int_0:SECRET:INT64}\"]\n13 -> 19 [label = \"t_21:{plus_out:SECRET:INT64}\"]\n13 -> 19 [label = \"t_21:{plus_out:SECRET:INT64}\"]\n14 -> 15 [label = \"t_41:{groupby_int_0:SECRET:INT64}\"]\n15 -> 19 [label = \"t_22:{plus_out:SECRET:INT64}\"]\n15 -> 19 [label = \"t_22:{plus_out:SECRET:INT64}\"]\n16 -> 19 [label = \"t_42:{encrypt_int_0:SECRET:INT64}\"]\n17 -> 19 [label = \"t_43:{aggregate_int_0:SECRET:INT64}\"]\n18 -> 19 [label = \"t_44:{aggregate_int_0:SECRET:INT64}\"]\n19 -> 20 [label = \"t_45:{plus_out:SECRET:INT64}\"]\n19 -> 20 [label = \"t_46:{plus_out:SECRET:INT64}\"]\n19 -> 22 [label = \"t_45:{plus_out:SECRET:INT64}\"]\n19 -> 22 [label = \"t_46:{plus_out:SECRET:INT64}\"]\n19 -> 22 [label = \"t_47:{encrypt_int_0:SECRET:INT64}\"]\n19 -> 22 [label = \"t_47:{encrypt_int_0:SECRET:INT64}\"]\n19 -> 26 [label = \"t_48:{aggregate_int_0:SECRET:INT64}\"]\n19 -> 27 [label = \"t_49:{aggregate_int_0:SECRET:INT64}\"]\n2 -> 3 [label = \"t_34:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_35:{right_index:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_50:{group_mark:SECRET:BOOL}\"]\n20 -> 21 [label = \"t_50:{group_mark:SECRET:BOOL}\"]\n20 -> 24 [label = \"t_50:{group_mark:SECRET:BOOL}\"]\n20 -> 25 [label = \"t_50:{group_mark:SECRET:BOOL}\"]\n20 -> 26 [label = \"t_50:{group_mark:SECRET:BOOL}\"]\n20 -> 27 [label = \"t_50:{group_mark:SECRET:BOOL}\"]\n20 -> 28 [label = \"t_50:{group_mark:SECRET:BOOL}\"]\n21 -> 28 [label = \"t_51:{aggregated_group_simple_count:SECRET:INT64}\"]\n22 -> 23 [label = \"t_53:{encrypt_int_0:SECRET:INT64}\"]\n23 -> 24 [label = \"t_54:{group_mark_distinct:SECRET:BOOL}\"]\n24 -> 25 [label = \"t_55:{group_mark_full:SECRET:BOOL}\"]\n25 -> 28 [label = \"t_52:{encrypt_int_0_count:SECRET:INT64}\"]\n26 -> 28 [label = \"t_56:{aggregate_int_0_sum:SECRET:INT64}\"]\n27 -> 28 [label = \"t_57:{aggregate_int_0_sum:SECRET:INT64}\"]\n28 -> 29 [label = \"t_62:{group_mark:SECRET:BOOL}\"]\n28 -> 30 [label = \"t_58:{aggregated_group_simple_count:SECRET:INT64}\"]\n28 -> 30 [label = \"t_59:{encrypt_int_0_count:SECRET:INT64}\"]\n28 -> 30 [label = \"t_60:{aggregate_int_0_sum:SECRET:INT64}\"]\n28 -> 30 [label = \"t_61:{aggregate_int_0_sum:SECRET:INT64}\"]\n29 -> 30 [label = \"t_63:{group_mark:PUBLIC:BOOL}\"]\n3 -> 8 [label = \"t_7:{groupby_int_0:PRIVATE:INT64}\"]\n30 -> 32 [label = \"t_23:{simple_count_result:SECRET:INT64}\"]\n30 -> 33 [label = \"t_23:{simple_count_result:SECRET:INT64}\"]\n30 -> 35 [label = \"t_23:{simple_count_result:SECRET:INT64}\"]\n30 -> 35 [label = \"t_24:{encrypt_int_0_count:SECRET:INT64}\"]\n30 -> 35 [label = \"t_25:{aggregate_int_0_sum:SECRET:INT64}\"]\n30 -> 35 [label = \"t_26:{aggregate_int_0_sum:SECRET:INT64}\"]\n31 -> 32 [label = \"t_27:{constant_data:PUBLIC:INT64}\"]\n32 -> 33 [label = \"t_28:{constant_data:PUBLIC:INT64}\"]\n33 -> 34 [label = \"t_29:{ge_out:SECRET:BOOL}\"]\n34 -> 35 [label = \"t_64:{ge_out:PUBLIC:BOOL}\"]\n35 -> 36 [label = \"t_30:{simple_count_result:SECRET:INT64}\"]\n35 -> 37 [label = \"t_31:{encrypt_int_0_count:SECRET:INT64}\"]\n35 -> 38 [label = \"t_32:{aggregate_int_0_sum:SECRET:INT64}\"]\n35 -> 39 [label = \"t_33:{aggregate_int_0_sum:SECRET:INT64}\"]\n36 -> 40 [label = \"t_65:{simple_count_result:PRIVATE:INT64}\"]\n37 -> 40 [label = \"t_66:{encrypt_int_0_count:PRIVATE:INT64}\"]\n38 -> 40 [label = \"t_67:{aggregate_int_0_sum:PRIVATE:INT64}\"]\n39 -> 40 [label = \"t_68:{aggregate_int_0_sum:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_8:{join_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_10:{aggregate_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_11:{encrypt_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_9:{groupby_int_0:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_13:{groupby_int_0:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_14:{aggregate_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_12:{join_int_0:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_37:{right_index:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_36:{left_index:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_36:{left_index:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_38:{left_index:PRIVATE:INT64}\"]\n8 -> 11 [label = \"t_15:{groupby_int_0:PRIVATE:INT64}\"]\n9 -> 12 [label = \"t_16:{groupby_int_0:PRIVATE:INT64}\"]\n9 -> 16 [label = \"t_18:{encrypt_int_0:PRIVATE:INT64}\"]\n9 -> 17 [label = \"t_17:{aggregate_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 run_sql_5 psi_join_6 copy_7 filter_by_index_8 filter_by_index_9 filter_by_index_10 make_share_11 make_share_12 Add_13 make_share_14 Add_15 make_share_16 make_share_17 make_share_18 sort_19 oblivious_group_mark_20 count_21 sort_22 oblivious_group_mark_23 LogicalOr_24 sum_25 sum_26 sum_27 shuffle_28 make_public_29 filter_30 constant_31 broadcast_to_32 GreaterEqual_33 make_public_34 filter_35 make_private_36 make_private_37 make_private_38 make_private_39 publish_result_40]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: true}},\n\t{`select plain_string_0 in (select plain_int_0 from alice.tbl_1) as da from alice.tbl_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select tbl_0.plain_string_0 in (select tbl_1.plain_int_0 from alice.tbl_1) as da from alice.tbl_0;,table_refs:[alice.tbl_0 alice.tbl_1],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_3,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_3:{Column#241:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select plain_string_0 from alice.tbl_0 where plain_string_0 in (select plain_int_0 from alice.tbl_1)`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select tbl_0.plain_string_0 from alice.tbl_0 where exists (select tbl_1.plain_int_0 from alice.tbl_1 where tbl_0.plain_string_0=tbl_1.plain_int_0);,table_refs:[alice.tbl_0 alice.tbl_1],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_3,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_3:{plain_string_0:PRIVATE:STRING}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*) as c, count(distinct bob.encrypt_int_0) as cd, sum(bob.aggregate_int_0) as sb, sum(carol.aggregate_int_0) as sc from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0 group by alice.groupby_int_0, bob.groupby_int_0, carol.groupby_int_0, carol.groupby_string_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select alice.join_int_0,alice.groupby_int_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,t_5,t_6,},],attr:[sql:select 'bob'.'join_int_0','bob'.'groupby_int_0','bob'.'aggregate_int_0','bob'.'encrypt_int_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_34,},RightJoinIndex:{t_35,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_34,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_3,t_4,t_5,t_6,},RowsIndexFilter:{t_35,},],out:[Out:{t_8,t_9,t_10,t_11,},],attr:[],party:[bob,]}\"]\n5 [label=\"run_sql:{in:[],out:[Out:{t_12,t_13,t_14,t_15,},],attr:[sql:select carol.join_int_0,carol.groupby_int_0,carol.aggregate_int_0,carol.groupby_string_0 from carol.tbl_0 as carol;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n6 [label=\"psi_join:{in:[Left:{t_8,},Right:{t_12,},],out:[LeftJoinIndex:{t_36,},RightJoinIndex:{t_37,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n7 [label=\"copy:{in:[In:{t_36,},],out:[Out:{t_38,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter_by_index:{in:[Data:{t_7,},RowsIndexFilter:{t_38,},],out:[Out:{t_16,},],attr:[],party:[alice,]}\"]\n9 [label=\"filter_by_index:{in:[Data:{t_9,t_10,t_11,},RowsIndexFilter:{t_36,},],out:[Out:{t_17,t_18,t_19,},],attr:[],party:[bob,]}\"]\n10 [label=\"filter_by_index:{in:[Data:{t_13,t_14,t_15,},RowsIndexFilter:{t_37,},],out:[Out:{t_20,t_21,t_22,},],attr:[],party:[carol,]}\"]\n11 [label=\"make_share:{in:[In:{t_16,},],out:[Out:{t_39,},],attr:[],party:[alice,bob,carol,]}\"]\n12 [label=\"make_share:{in:[In:{t_17,},],out:[Out:{t_40,},],attr:[],party:[alice,bob,carol,]}\"]\n13 [label=\"make_share:{in:[In:{t_20,},],out:[Out:{t_41,},],attr:[],party:[alice,bob,carol,]}\"]\n14 [label=\"make_share:{in:[In:{t_22,},],out:[Out:{t_42,},],attr:[],party:[alice,bob,carol,]}\"]\n15 [label=\"make_share:{in:[In:{t_19,},],out:[Out:{t_43,},],attr:[],party:[alice,bob,carol,]}\"]\n16 [label=\"make_share:{in:[In:{t_18,},],out:[Out:{t_44,},],attr:[],party:[alice,bob,carol,]}\"]\n17 [label=\"make_share:{in:[In:{t_21,},],out:[Out:{t_45,},],attr:[],party:[alice,bob,carol,]}\"]\n18 [label=\"sort:{in:[In:{t_39,t_40,t_41,t_42,t_43,t_44,t_45,},Key:{t_39,t_40,t_41,t_42,},],out:[Out:{t_46,t_47,t_48,t_49,t_50,t_51,t_52,},],attr:[reverse:[false false false false],],party:[alice,bob,carol,]}\"]\n19 [label=\"oblivious_group_mark:{in:[Key:{t_46,t_47,t_48,t_49,},],out:[Group:{t_53,},],attr:[],party:[alice,bob,carol,]}\"]\n20 [label=\"count:{in:[Group:{t_53,},In:{t_53,},],out:[Out:{t_54,},],attr:[],party:[alice,bob,carol,]}\"]\n21 [label=\"sort:{in:[In:{t_50,},Key:{t_46,t_47,t_48,t_49,t_50,},],out:[Out:{t_56,},],attr:[reverse:[false false false false false],],party:[alice,bob,carol,]}\"]\n22 [label=\"oblivious_group_mark:{in:[Key:{t_56,},],out:[Group:{t_57,},],attr:[],party:[alice,bob,carol,]}\"]\n23 [label=\"LogicalOr:{in:[Left:{t_53,},Right:{t_57,},],out:[Out:{t_58,},],attr:[],party:[alice,bob,carol,]}\"]\n24 [label=\"sum:{in:[Group:{t_53,},In:{t_58,},],out:[Out:{t_55,},],attr:[],party:[alice,bob,carol,]}\"]\n25 [label=\"sum:{in:[Group:{t_53,},In:{t_51,},],out:[Out:{t_59,},],attr:[],party:[alice,bob,carol,]}\"]\n26 [label=\"sum:{in:[Group:{t_53,},In:{t_52,},],out:[Out:{t_60,},],attr:[],party:[alice,bob,carol,]}\"]\n27 [label=\"shuffle:{in:[In:{t_54,t_55,t_59,t_60,t_53,},],out:[Out:{t_61,t_62,t_63,t_64,t_65,},],attr:[],party:[alice,bob,carol,]}\"]\n28 [label=\"make_public:{in:[In:{t_65,},],out:[Out:{t_66,},],attr:[],party:[alice,bob,carol,]}\"]\n29 [label=\"filter:{in:[Filter:{t_66,},In:{t_61,t_62,t_63,t_64,},],out:[Out:{t_23,t_24,t_25,t_26,},],attr:[],party:[alice,bob,carol,]}\"]\n30 [label=\"constant:{in:[],out:[Out:{t_27,},],attr:[scalar:4,to_status:1,],party:[alice,bob,carol,]}\"]\n31 [label=\"broadcast_to:{in:[In:{t_27,},ShapeRefTensor:{t_23,},],out:[Out:{t_28,},],attr:[],party:[alice,bob,carol,]}\"]\n32 [label=\"GreaterEqual:{in:[Left:{t_23,},Right:{t_28,},],out:[Out:{t_29,},],attr:[],party:[alice,bob,carol,]}\"]\n33 [label=\"make_public:{in:[In:{t_29,},],out:[Out:{t_67,},],attr:[],party:[alice,bob,carol,]}\"]\n34 [label=\"filter:{in:[Filter:{t_67,},In:{t_23,t_24,t_25,t_26,},],out:[Out:{t_30,t_31,t_32,t_33,},],attr:[],party:[alice,bob,carol,]}\"]\n35 [label=\"make_private:{in:[In:{t_30,},],out:[Out:{t_68,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n36 [label=\"make_private:{in:[In:{t_31,},],out:[Out:{t_69,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n37 [label=\"make_private:{in:[In:{t_32,},],out:[Out:{t_70,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n38 [label=\"make_private:{in:[In:{t_33,},],out:[Out:{t_71,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n39 [label=\"publish_result:{in:[In:{t_68,t_69,t_70,t_71,},],out:[Out:{t_72,t_73,t_74,t_75,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{groupby_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{groupby_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_5:{aggregate_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_6:{encrypt_int_0:PRIVATE:INT64}\"]\n10 -> 13 [label = \"t_20:{groupby_int_0:PRIVATE:INT64}\"]\n10 -> 14 [label = \"t_22:{groupby_string_0:PRIVATE:STRING}\"]\n10 -> 17 [label = \"t_21:{aggregate_int_0:PRIVATE:INT64}\"]\n11 -> 18 [label = \"t_39:{groupby_int_0:SECRET:INT64}\"]\n11 -> 18 [label = \"t_39:{groupby_int_0:SECRET:INT64}\"]\n12 -> 18 [label = \"t_40:{groupby_int_0:SECRET:INT64}\"]\n12 -> 18 [label = \"t_40:{groupby_int_0:SECRET:INT64}\"]\n13 -> 18 [label = \"t_41:{groupby_int_0:SECRET:INT64}\"]\n13 -> 18 [label = \"t_41:{groupby_int_0:SECRET:INT64}\"]\n14 -> 18 [label = \"t_42:{groupby_string_0:SECRET:STRING}\"]\n14 -> 18 [label = \"t_42:{groupby_string_0:SECRET:STRING}\"]\n15 -> 18 [label = \"t_43:{encrypt_int_0:SECRET:INT64}\"]\n16 -> 18 [label = \"t_44:{aggregate_int_0:SECRET:INT64}\"]\n17 -> 18 [label = \"t_45:{aggregate_int_0:SECRET:INT64}\"]\n18 -> 19 [label = \"t_46:{groupby_int_0:SECRET:INT64}\"]\n18 -> 19 [label = \"t_47:{groupby_int_0:SECRET:INT64}\"]\n18 -> 19 [label = \"t_48:{groupby_int_0:SECRET:INT64}\"]\n18 -> 19 [label = \"t_49:{groupby_string_0:SECRET:STRING}\"]\n18 -> 21 [label = \"t_46:{groupby_int_0:SECRET:INT64}\"]\n18 -> 21 [label = \"t_47:{groupby_int_0:SECRET:INT64}\"]\n18 -> 21 [label = \"t_48:{groupby_int_0:SECRET:INT64}\"]\n18 -> 21 [label = \"t_49:{groupby_string_0:SECRET:STRING}\"]\n18 -> 21 [label = \"t_50:{encrypt_int_0:SECRET:INT64}\"]\n18 -> 21 [label = \"t_50:{encrypt_int_0:SECRET:INT64}\"]\n18 -> 25 [label = \"t_51:{aggregate_int_0:SECRET:INT64}\"]\n18 -> 26 [label = \"t_52:{aggregate_int_0:SECRET:INT64}\"]\n19 -> 20 [label = \"t_53:{group_mark:SECRET:BOOL}\"]\n19 -> 20 [label = \"t_53:{group_mark:SECRET:BOOL}\"]\n19 -> 23 [label = \"t_53:{group_mark:SECRET:BOOL}\"]\n19 -> 24 [label = \"t_53:{group_mark:SECRET:BOOL}\"]\n19 -> 25 [label = \"t_53:{group_mark:SECRET:BOOL}\"]\n19 -> 26 [label = \"t_53:{group_mark:SECRET:BOOL}\"]\n19 -> 27 [label = \"t_53:{group_mark:SECRET:BOOL}\"]\n2 -> 3 [label = \"t_34:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_35:{right_index:PRIVATE:INT64}\"]\n20 -> 27 [label = \"t_54:{aggregated_group_simple_count:SECRET:INT64}\"]\n21 -> 22 [label = \"t_56:{encrypt_int_0:SECRET:INT64}\"]\n22 -> 23 [label = \"t_57:{group_mark_distinct:SECRET:BOOL}\"]\n23 -> 24 [label = \"t_58:{group_mark_full:SECRET:BOOL}\"]\n24 -> 27 [label = \"t_55:{encrypt_int_0_count:SECRET:INT64}\"]\n25 -> 27 [label = \"t_59:{aggregate_int_0_sum:SECRET:INT64}\"]\n26 -> 27 [label = \"t_60:{aggregate_int_0_sum:SECRET:INT64}\"]\n27 -> 28 [label = \"t_65:{group_mark:SECRET:BOOL}\"]\n27 -> 29 [label = \"t_61:{aggregated_group_simple_count:SECRET:INT64}\"]\n27 -> 29 [label = \"t_62:{encrypt_int_0_count:SECRET:INT64}\"]\n27 -> 29 [label = \"t_63:{aggregate_int_0_sum:SECRET:INT64}\"]\n27 -> 29 [label = \"t_64:{aggregate_int_0_sum:SECRET:INT64}\"]\n28 -> 29 [label = \"t_66:{group_mark:PUBLIC:BOOL}\"]\n29 -> 31 [label = \"t_23:{simple_count_result:SECRET:INT64}\"]\n29 -> 32 [label = \"t_23:{simple_count_result:SECRET:INT64}\"]\n29 -> 34 [label = \"t_23:{simple_count_result:SECRET:INT64}\"]\n29 -> 34 [label = \"t_24:{encrypt_int_0_count:SECRET:INT64}\"]\n29 -> 34 [label = \"t_25:{aggregate_int_0_sum:SECRET:INT64}\"]\n29 -> 34 [label = \"t_26:{aggregate_int_0_sum:SECRET:INT64}\"]\n3 -> 8 [label = \"t_7:{groupby_int_0:PRIVATE:INT64}\"]\n30 -> 31 [label = \"t_27:{constant_data:PUBLIC:INT64}\"]\n31 -> 32 [label = \"t_28:{constant_data:PUBLIC:INT64}\"]\n32 -> 33 [label = \"t_29:{ge_out:SECRET:BOOL}\"]\n33 -> 34 [label = \"t_67:{ge_out:PUBLIC:BOOL}\"]\n34 -> 35 [label = \"t_30:{simple_count_result:SECRET:INT64}\"]\n34 -> 36 [label = \"t_31:{encrypt_int_0_count:SECRET:INT64}\"]\n34 -> 37 [label = \"t_32:{aggregate_int_0_sum:SECRET:INT64}\"]\n34 -> 38 [label = \"t_33:{aggregate_int_0_sum:SECRET:INT64}\"]\n35 -> 39 [label = \"t_68:{simple_count_result:PRIVATE:INT64}\"]\n36 -> 39 [label = \"t_69:{encrypt_int_0_count:PRIVATE:INT64}\"]\n37 -> 39 [label = \"t_70:{aggregate_int_0_sum:PRIVATE:INT64}\"]\n38 -> 39 [label = \"t_71:{aggregate_int_0_sum:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_8:{join_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_10:{aggregate_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_11:{encrypt_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_9:{groupby_int_0:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_13:{groupby_int_0:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_14:{aggregate_int_0:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_15:{groupby_string_0:PRIVATE:STRING}\"]\n5 -> 6 [label = \"t_12:{join_int_0:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_37:{right_index:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_36:{left_index:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_36:{left_index:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_38:{left_index:PRIVATE:INT64}\"]\n8 -> 11 [label = \"t_16:{groupby_int_0:PRIVATE:INT64}\"]\n9 -> 12 [label = \"t_17:{groupby_int_0:PRIVATE:INT64}\"]\n9 -> 15 [label = \"t_19:{encrypt_int_0:PRIVATE:INT64}\"]\n9 -> 16 [label = \"t_18:{aggregate_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 run_sql_5 psi_join_6 copy_7 filter_by_index_8 filter_by_index_9 filter_by_index_10 make_share_11 make_share_12 make_share_13 make_share_14 make_share_15 make_share_16 make_share_17 sort_18 oblivious_group_mark_19 count_20 sort_21 oblivious_group_mark_22 LogicalOr_23 sum_24 sum_25 sum_26 shuffle_27 make_public_28 filter_29 constant_30 broadcast_to_31 GreaterEqual_32 make_public_33 filter_34 make_private_35 make_private_36 make_private_37 make_private_38 publish_result_39]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*) as c, count(distinct bob.encrypt_int_0) as cd, sum(bob.aggregate_int_0) as sb, sum(carol.aggregate_int_0) as sc from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0 group by alice.groupby_int_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select alice.join_int_0,alice.groupby_int_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,t_5,},],attr:[sql:select 'bob'.'join_int_0','bob'.'aggregate_int_0','bob'.'encrypt_int_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_27,},RightJoinIndex:{t_28,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_27,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_3,t_4,t_5,},RowsIndexFilter:{t_28,},],out:[Out:{t_7,t_8,t_9,},],attr:[],party:[bob,]}\"]\n5 [label=\"run_sql:{in:[],out:[Out:{t_10,t_11,},],attr:[sql:select carol.join_int_0,carol.aggregate_int_0 from carol.tbl_0 as carol;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n6 [label=\"psi_join:{in:[Left:{t_7,},Right:{t_10,},],out:[LeftJoinIndex:{t_29,},RightJoinIndex:{t_30,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n7 [label=\"copy:{in:[In:{t_29,},],out:[Out:{t_31,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter_by_index:{in:[Data:{t_6,},RowsIndexFilter:{t_31,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n9 [label=\"filter_by_index:{in:[Data:{t_8,t_9,},RowsIndexFilter:{t_29,},],out:[Out:{t_13,t_14,},],attr:[],party:[bob,]}\"]\n10 [label=\"filter_by_index:{in:[Data:{t_11,},RowsIndexFilter:{t_30,},],out:[Out:{t_15,},],attr:[],party:[carol,]}\"]\n11 [label=\"make_share:{in:[In:{t_12,},],out:[Out:{t_32,},],attr:[],party:[alice,bob,carol,]}\"]\n12 [label=\"make_share:{in:[In:{t_14,},],out:[Out:{t_33,},],attr:[],party:[alice,bob,carol,]}\"]\n13 [label=\"make_share:{in:[In:{t_13,},],out:[Out:{t_34,},],attr:[],party:[alice,bob,carol,]}\"]\n14 [label=\"make_share:{in:[In:{t_15,},],out:[Out:{t_35,},],attr:[],party:[alice,bob,carol,]}\"]\n15 [label=\"sort:{in:[In:{t_32,t_33,t_34,t_35,},Key:{t_32,},],out:[Out:{t_36,t_37,t_38,t_39,},],attr:[reverse:[false],],party:[alice,bob,carol,]}\"]\n16 [label=\"oblivious_group_mark:{in:[Key:{t_36,},],out:[Group:{t_40,},],attr:[],party:[alice,bob,carol,]}\"]\n17 [label=\"count:{in:[Group:{t_40,},In:{t_40,},],out:[Out:{t_41,},],attr:[],party:[alice,bob,carol,]}\"]\n18 [label=\"sort:{in:[In:{t_37,},Key:{t_36,t_37,},],out:[Out:{t_43,},],attr:[reverse:[false false],],party:[alice,bob,carol,]}\"]\n19 [label=\"oblivious_group_mark:{in:[Key:{t_43,},],out:[Group:{t_44,},],attr:[],party:[alice,bob,carol,]}\"]\n20 [label=\"LogicalOr:{in:[Left:{t_40,},Right:{t_44,},],out:[Out:{t_45,},],attr:[],party:[alice,bob,carol,]}\"]\n21 [label=\"sum:{in:[Group:{t_40,},In:{t_45,},],out:[Out:{t_42,},],attr:[],party:[alice,bob,carol,]}\"]\n22 [label=\"sum:{in:[Group:{t_40,},In:{t_38,},],out:[Out:{t_46,},],attr:[],party:[alice,bob,carol,]}\"]\n23 [label=\"sum:{in:[Group:{t_40,},In:{t_39,},],out:[Out:{t_47,},],attr:[],party:[alice,bob,carol,]}\"]\n24 [label=\"shuffle:{in:[In:{t_41,t_42,t_46,t_47,t_40,},],out:[Out:{t_48,t_49,t_50,t_51,t_52,},],attr:[],party:[alice,bob,carol,]}\"]\n25 [label=\"make_public:{in:[In:{t_52,},],out:[Out:{t_53,},],attr:[],party:[alice,bob,carol,]}\"]\n26 [label=\"filter:{in:[Filter:{t_53,},In:{t_48,t_49,t_50,t_51,},],out:[Out:{t_16,t_17,t_18,t_19,},],attr:[],party:[alice,bob,carol,]}\"]\n27 [label=\"constant:{in:[],out:[Out:{t_20,},],attr:[scalar:4,to_status:1,],party:[alice,bob,carol,]}\"]\n28 [label=\"broadcast_to:{in:[In:{t_20,},ShapeRefTensor:{t_16,},],out:[Out:{t_21,},],attr:[],party:[alice,bob,carol,]}\"]\n29 [label=\"make_private:{in:[In:{t_16,},],out:[Out:{t_54,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n30 [label=\"make_private:{in:[In:{t_21,},],out:[Out:{t_55,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n31 [label=\"GreaterEqual:{in:[Left:{t_54,},Right:{t_55,},],out:[Out:{t_22,},],attr:[],party:[alice,]}\"]\n32 [label=\"make_private:{in:[In:{t_17,},],out:[Out:{t_56,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n33 [label=\"filter:{in:[Filter:{t_22,},In:{t_54,t_56,},],out:[Out:{t_23,t_24,},],attr:[],party:[alice,]}\"]\n34 [label=\"make_public:{in:[In:{t_22,},],out:[Out:{t_57,},],attr:[],party:[alice,bob,carol,]}\"]\n35 [label=\"filter:{in:[Filter:{t_57,},In:{t_18,t_19,},],out:[Out:{t_25,t_26,},],attr:[],party:[alice,bob,carol,]}\"]\n36 [label=\"make_private:{in:[In:{t_25,},],out:[Out:{t_58,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n37 [label=\"make_private:{in:[In:{t_26,},],out:[Out:{t_59,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n38 [label=\"publish_result:{in:[In:{t_23,t_24,t_58,t_59,},],out:[Out:{t_60,t_61,t_62,t_63,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{groupby_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{aggregate_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_5:{encrypt_int_0:PRIVATE:INT64}\"]\n10 -> 14 [label = \"t_15:{aggregate_int_0:PRIVATE:INT64}\"]\n11 -> 15 [label = \"t_32:{groupby_int_0:SECRET:INT64}\"]\n11 -> 15 [label = \"t_32:{groupby_int_0:SECRET:INT64}\"]\n12 -> 15 [label = \"t_33:{encrypt_int_0:SECRET:INT64}\"]\n13 -> 15 [label = \"t_34:{aggregate_int_0:SECRET:INT64}\"]\n14 -> 15 [label = \"t_35:{aggregate_int_0:SECRET:INT64}\"]\n15 -> 16 [label = \"t_36:{groupby_int_0:SECRET:INT64}\"]\n15 -> 18 [label = \"t_36:{groupby_int_0:SECRET:INT64}\"]\n15 -> 18 [label = \"t_37:{encrypt_int_0:SECRET:INT64}\"]\n15 -> 18 [label = \"t_37:{encrypt_int_0:SECRET:INT64}\"]\n15 -> 22 [label = \"t_38:{aggregate_int_0:SECRET:INT64}\"]\n15 -> 23 [label = \"t_39:{aggregate_int_0:SECRET:INT64}\"]\n16 -> 17 [label = \"t_40:{group_mark:SECRET:BOOL}\"]\n16 -> 17 [label = \"t_40:{group_mark:SECRET:BOOL}\"]\n16 -> 20 [label = \"t_40:{group_mark:SECRET:BOOL}\"]\n16 -> 21 [label = \"t_40:{group_mark:SECRET:BOOL}\"]\n16 -> 22 [label = \"t_40:{group_mark:SECRET:BOOL}\"]\n16 -> 23 [label = \"t_40:{group_mark:SECRET:BOOL}\"]\n16 -> 24 [label = \"t_40:{group_mark:SECRET:BOOL}\"]\n17 -> 24 [label = \"t_41:{aggregated_group_simple_count:SECRET:INT64}\"]\n18 -> 19 [label = \"t_43:{encrypt_int_0:SECRET:INT64}\"]\n19 -> 20 [label = \"t_44:{group_mark_distinct:SECRET:BOOL}\"]\n2 -> 3 [label = \"t_27:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_28:{right_index:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_45:{group_mark_full:SECRET:BOOL}\"]\n21 -> 24 [label = \"t_42:{encrypt_int_0_count:SECRET:INT64}\"]\n22 -> 24 [label = \"t_46:{aggregate_int_0_sum:SECRET:INT64}\"]\n23 -> 24 [label = \"t_47:{aggregate_int_0_sum:SECRET:INT64}\"]\n24 -> 25 [label = \"t_52:{group_mark:SECRET:BOOL}\"]\n24 -> 26 [label = \"t_48:{aggregated_group_simple_count:SECRET:INT64}\"]\n24 -> 26 [label = \"t_49:{encrypt_int_0_count:SECRET:INT64}\"]\n24 -> 26 [label = \"t_50:{aggregate_int_0_sum:SECRET:INT64}\"]\n24 -> 26 [label = \"t_51:{aggregate_int_0_sum:SECRET:INT64}\"]\n25 -> 26 [label = \"t_53:{group_mark:PUBLIC:BOOL}\"]\n26 -> 28 [label = \"t_16:{simple_count_result:SECRET:INT64}\"]\n26 -> 29 [label = \"t_16:{simple_count_result:SECRET:INT64}\"]\n26 -> 32 [label = \"t_17:{encrypt_int_0_count:SECRET:INT64}\"]\n26 -> 35 [label = \"t_18:{aggregate_int_0_sum:SECRET:INT64}\"]\n26 -> 35 [label = \"t_19:{aggregate_int_0_sum:SECRET:INT64}\"]\n27 -> 28 [label = \"t_20:{constant_data:PUBLIC:INT64}\"]\n28 -> 30 [label = \"t_21:{constant_data:PUBLIC:INT64}\"]\n29 -> 31 [label = \"t_54:{simple_count_result:PRIVATE:INT64}\"]\n29 -> 33 [label = \"t_54:{simple_count_result:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_6:{groupby_int_0:PRIVATE:INT64}\"]\n30 -> 31 [label = \"t_55:{constant_data:PRIVATE:INT64}\"]\n31 -> 33 [label = \"t_22:{ge_out:PRIVATE:BOOL}\"]\n31 -> 34 [label = \"t_22:{ge_out:PRIVATE:BOOL}\"]\n32 -> 33 [label = \"t_56:{encrypt_int_0_count:PRIVATE:INT64}\"]\n33 -> 38 [label = \"t_23:{simple_count_result:PRIVATE:INT64}\"]\n33 -> 38 [label = \"t_24:{encrypt_int_0_count:PRIVATE:INT64}\"]\n34 -> 35 [label = \"t_57:{ge_out:PUBLIC:BOOL}\"]\n35 -> 36 [label = \"t_25:{aggregate_int_0_sum:SECRET:INT64}\"]\n35 -> 37 [label = \"t_26:{aggregate_int_0_sum:SECRET:INT64}\"]\n36 -> 38 [label = \"t_58:{aggregate_int_0_sum:PRIVATE:INT64}\"]\n37 -> 38 [label = \"t_59:{aggregate_int_0_sum:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_7:{join_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_8:{aggregate_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_9:{encrypt_int_0:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_11:{aggregate_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_10:{join_int_0:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_30:{right_index:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_29:{left_index:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_29:{left_index:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_31:{left_index:PRIVATE:INT64}\"]\n8 -> 11 [label = \"t_12:{groupby_int_0:PRIVATE:INT64}\"]\n9 -> 12 [label = \"t_14:{encrypt_int_0:PRIVATE:INT64}\"]\n9 -> 13 [label = \"t_13:{aggregate_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 run_sql_5 psi_join_6 copy_7 filter_by_index_8 filter_by_index_9 filter_by_index_10 make_share_11 make_share_12 make_share_13 make_share_14 sort_15 oblivious_group_mark_16 count_17 sort_18 oblivious_group_mark_19 LogicalOr_20 sum_21 sum_22 sum_23 shuffle_24 make_public_25 filter_26 constant_27 broadcast_to_28 make_private_29 make_private_30 GreaterEqual_31 make_private_32 filter_33 make_public_34 filter_35 make_private_36 make_private_37 publish_result_38]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select (alice.join_int_0 + bob.compare_int_0 + carol.compare_int_0) <> 0 as reduce_res from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select alice.join_int_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,t_3,},],attr:[sql:select 'bob'.'join_int_0','bob'.'compare_int_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_17,},RightJoinIndex:{t_18,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_17,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_2,t_3,},RowsIndexFilter:{t_18,},],out:[Out:{t_5,t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"run_sql:{in:[],out:[Out:{t_7,t_8,},],attr:[sql:select carol.join_int_0,carol.compare_int_0 from carol.tbl_0 as carol;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n6 [label=\"psi_join:{in:[Left:{t_5,},Right:{t_7,},],out:[LeftJoinIndex:{t_19,},RightJoinIndex:{t_20,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n7 [label=\"copy:{in:[In:{t_19,},],out:[Out:{t_21,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_21,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n9 [label=\"filter_by_index:{in:[Data:{t_6,},RowsIndexFilter:{t_19,},],out:[Out:{t_10,},],attr:[],party:[bob,]}\"]\n10 [label=\"filter_by_index:{in:[Data:{t_8,},RowsIndexFilter:{t_20,},],out:[Out:{t_11,},],attr:[],party:[carol,]}\"]\n11 [label=\"copy:{in:[In:{t_9,},],out:[Out:{t_22,},],attr:[input_party_codes:alice,output_party_codes:bob,],party:[alice,bob,]}\"]\n12 [label=\"Add:{in:[Left:{t_22,},Right:{t_10,},],out:[Out:{t_12,},],attr:[],party:[bob,]}\"]\n13 [label=\"make_share:{in:[In:{t_12,},],out:[Out:{t_23,},],attr:[],party:[alice,bob,carol,]}\"]\n14 [label=\"make_share:{in:[In:{t_11,},],out:[Out:{t_24,},],attr:[],party:[alice,bob,carol,]}\"]\n15 [label=\"Add:{in:[Left:{t_23,},Right:{t_24,},],out:[Out:{t_13,},],attr:[],party:[alice,bob,carol,]}\"]\n16 [label=\"constant:{in:[],out:[Out:{t_14,},],attr:[scalar:0,to_status:1,],party:[alice,bob,carol,]}\"]\n17 [label=\"broadcast_to:{in:[In:{t_14,},ShapeRefTensor:{t_13,},],out:[Out:{t_15,},],attr:[],party:[alice,bob,carol,]}\"]\n18 [label=\"NotEqual:{in:[Left:{t_13,},Right:{t_15,},],out:[Out:{t_16,},],attr:[],party:[alice,bob,carol,]}\"]\n19 [label=\"make_private:{in:[In:{t_16,},],out:[Out:{t_25,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n20 [label=\"publish_result:{in:[In:{t_25,},],out:[Out:{t_26,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{compare_int_0:PRIVATE:INT64}\"]\n10 -> 14 [label = \"t_11:{compare_int_0:PRIVATE:INT64}\"]\n11 -> 12 [label = \"t_22:{join_int_0:PRIVATE:INT64}\"]\n12 -> 13 [label = \"t_12:{plus_out:PRIVATE:INT64}\"]\n13 -> 15 [label = \"t_23:{plus_out:SECRET:INT64}\"]\n14 -> 15 [label = \"t_24:{compare_int_0:SECRET:INT64}\"]\n15 -> 17 [label = \"t_13:{plus_out:SECRET:INT64}\"]\n15 -> 18 [label = \"t_13:{plus_out:SECRET:INT64}\"]\n16 -> 17 [label = \"t_14:{constant_data:PUBLIC:INT64}\"]\n17 -> 18 [label = \"t_15:{constant_data:PUBLIC:INT64}\"]\n18 -> 19 [label = \"t_16:{ne_out:SECRET:BOOL}\"]\n19 -> 20 [label = \"t_25:{ne_out:PRIVATE:BOOL}\"]\n2 -> 3 [label = \"t_17:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_18:{right_index:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_8:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_7:{join_int_0:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_20:{right_index:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_19:{left_index:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_19:{left_index:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_21:{left_index:PRIVATE:INT64}\"]\n8 -> 11 [label = \"t_9:{join_int_0:PRIVATE:INT64}\"]\n9 -> 12 [label = \"t_10:{compare_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 run_sql_5 psi_join_6 copy_7 filter_by_index_8 filter_by_index_9 filter_by_index_10 copy_11 Add_12 make_share_13 make_share_14 Add_15 constant_16 broadcast_to_17 NotEqual_18 make_private_19 publish_result_20]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select alice.plain_int_0 + bob.join_int_0 + carol.join_int_0 as add_res, alice.plain_int_0 - bob.join_int_0 - carol.join_int_0 as minus_res, alice.plain_int_0 * bob.join_int_0 * carol.join_int_0 as multi_res, alice.plain_int_0 / bob.join_int_0 / carol.join_int_0 as div_res from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select alice.plain_int_0,alice.join_int_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'bob'.'join_int_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_19,},RightJoinIndex:{t_20,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_19,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_3,},RowsIndexFilter:{t_20,},],out:[Out:{t_5,},],attr:[],party:[bob,]}\"]\n5 [label=\"run_sql:{in:[],out:[Out:{t_6,},],attr:[sql:select carol.join_int_0 from carol.tbl_0 as carol;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n6 [label=\"psi_join:{in:[Left:{t_5,},Right:{t_6,},],out:[LeftJoinIndex:{t_21,},RightJoinIndex:{t_22,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n7 [label=\"copy:{in:[In:{t_21,},],out:[Out:{t_23,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_23,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n9 [label=\"filter_by_index:{in:[Data:{t_5,},RowsIndexFilter:{t_21,},],out:[Out:{t_8,},],attr:[],party:[bob,]}\"]\n10 [label=\"filter_by_index:{in:[Data:{t_6,},RowsIndexFilter:{t_22,},],out:[Out:{t_9,},],attr:[],party:[carol,]}\"]\n11 [label=\"copy:{in:[In:{t_8,},],out:[Out:{t_24,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n12 [label=\"Add:{in:[Left:{t_7,},Right:{t_24,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n13 [label=\"copy:{in:[In:{t_9,},],out:[Out:{t_25,},],attr:[input_party_codes:carol,output_party_codes:alice,],party:[carol,alice,]}\"]\n14 [label=\"Add:{in:[Left:{t_10,},Right:{t_25,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n15 [label=\"Minus:{in:[Left:{t_7,},Right:{t_24,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n16 [label=\"Minus:{in:[Left:{t_12,},Right:{t_25,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n17 [label=\"Mul:{in:[Left:{t_7,},Right:{t_24,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n18 [label=\"Mul:{in:[Left:{t_14,},Right:{t_25,},],out:[Out:{t_15,},],attr:[],party:[alice,]}\"]\n19 [label=\"Cast:{in:[In:{t_7,},],out:[Out:{t_16,},],attr:[],party:[alice,]}\"]\n20 [label=\"Div:{in:[Left:{t_16,},Right:{t_24,},],out:[Out:{t_17,},],attr:[],party:[alice,]}\"]\n21 [label=\"Div:{in:[Left:{t_17,},Right:{t_25,},],out:[Out:{t_18,},],attr:[],party:[alice,]}\"]\n22 [label=\"publish_result:{in:[In:{t_11,t_13,t_15,t_18,},],out:[Out:{t_26,t_27,t_28,t_29,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n10 -> 13 [label = \"t_9:{join_int_0:PRIVATE:INT64}\"]\n11 -> 12 [label = \"t_24:{join_int_0:PRIVATE:INT64}\"]\n11 -> 15 [label = \"t_24:{join_int_0:PRIVATE:INT64}\"]\n11 -> 17 [label = \"t_24:{join_int_0:PRIVATE:INT64}\"]\n11 -> 20 [label = \"t_24:{join_int_0:PRIVATE:INT64}\"]\n12 -> 14 [label = \"t_10:{plus_out:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_25:{join_int_0:PRIVATE:INT64}\"]\n13 -> 16 [label = \"t_25:{join_int_0:PRIVATE:INT64}\"]\n13 -> 18 [label = \"t_25:{join_int_0:PRIVATE:INT64}\"]\n13 -> 21 [label = \"t_25:{join_int_0:PRIVATE:INT64}\"]\n14 -> 22 [label = \"t_11:{plus_out:PRIVATE:INT64}\"]\n15 -> 16 [label = \"t_12:{minus_out:PRIVATE:INT64}\"]\n16 -> 22 [label = \"t_13:{minus_out:PRIVATE:INT64}\"]\n17 -> 18 [label = \"t_14:{mul_out:PRIVATE:INT64}\"]\n18 -> 22 [label = \"t_15:{mul_out:PRIVATE:INT64}\"]\n19 -> 20 [label = \"t_16:{plain_int_0:PRIVATE:FLOAT64}\"]\n2 -> 3 [label = \"t_19:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_20:{right_index:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_17:{div_out:PRIVATE:FLOAT64}\"]\n21 -> 22 [label = \"t_18:{div_out:PRIVATE:FLOAT64}\"]\n3 -> 8 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_6:{join_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_6:{join_int_0:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_22:{right_index:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_21:{left_index:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_21:{left_index:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_23:{left_index:PRIVATE:INT64}\"]\n8 -> 12 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 15 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 17 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 19 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n9 -> 11 [label = \"t_8:{join_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 run_sql_5 psi_join_6 copy_7 filter_by_index_8 filter_by_index_9 filter_by_index_10 copy_11 Add_12 copy_13 Add_14 Minus_15 Minus_16 Mul_17 Mul_18 Cast_19 Div_20 Div_21 publish_result_22]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select concat(plain_string_0, plain_string_1) as tt from alice.tbl_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select concat(tbl_0.plain_string_0, tbl_0.plain_string_1) as tt from alice.tbl_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_3,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_3:{concat_out:PRIVATE:STRING}\"]\n}`, ``, testConf{groupThreshold: 4, batched: true, revealGroupCount: false}},\n\t{`select count(*) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(*) > 3`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_11,},],attr:[sql:select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>3) and (count(1)>=4);,table_refs:[alice.tbl_1 alice.tbl_2],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_11,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_11:{simple_count_result:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 group by tbl_1.plain_float_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_9,},],attr:[sql:select any_value(tbl_1.plain_float_0) as expr_9 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(1)>=4;,table_refs:[alice.tbl_1 alice.tbl_2],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_9,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_9:{plain_float_0_firstrow:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select plain_int_0 from alice.tbl_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select tbl_0.plain_int_0 from alice.tbl_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_1,},],out:[Out:{t_2,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*) as c, sum(plain_int_0) as b, max(plain_int_0) as a, min(plain_int_0) as d from alice.tbl_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_2,t_3,t_4,t_5,},],attr:[sql:select count(1) as c,sum(tbl_0.plain_int_0) as b,max(tbl_0.plain_int_0) as a,min(tbl_0.plain_int_0) as d from alice.tbl_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_2,t_3,t_4,t_5,},],out:[Out:{t_6,t_7,t_8,t_9,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_2:{plain_int_0_count:PRIVATE:INT64}\"]\n0 -> 1 [label = \"t_3:{plain_int_0_sum:PRIVATE:INT64}\"]\n0 -> 1 [label = \"t_4:{plain_int_0_max:PRIVATE:INT64}\"]\n0 -> 1 [label = \"t_5:{plain_int_0_min:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select plain_int_0 from alice.tbl_0 into outfile '/tmp/output.txt' fields terminated BY ','`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select tbl_0.plain_int_0 from alice.tbl_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"dump_file:{in:[In:{t_1,},],out:[Out:{t_2,},],attr:[field_deliminator:,,file_path:/tmp/output.txt,line_terminator:\n,quoting_style:0,],party:[alice,]}\"]\n0 -> 1 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 dump_file_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select plain_int_0 from alice.tbl_0 into outfile party_code 'alice' '/tmp/output.txt' columns terminated BY '|' optionally enclosed BY '\"' lines terminated BY 'end of line';`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select tbl_0.plain_int_0 from alice.tbl_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"dump_file:{in:[In:{t_1,},],out:[Out:{t_2,},],attr:[field_deliminator:|,file_path:/tmp/output.txt,line_terminator:end of line,quoting_style:1,],party:[alice,]}\"]\n0 -> 1 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 dump_file_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select plain_int_0 from alice.tbl_0 into outfile party_code 'alice' '/tmp/output_alice.txt' party_code 'bob' '/tmp/output_bob.txt' party_code 'carol' '/tmp/output_carol.txt';`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select tbl_0.plain_int_0 from alice.tbl_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"dump_file:{in:[In:{t_1,},],out:[Out:{t_2,},],attr:[field_deliminator:\t,file_path:/tmp/output_alice.txt,line_terminator:\n,quoting_style:0,],party:[alice,]}\"]\n2 [label=\"copy:{in:[In:{t_1,},],out:[Out:{t_3,},],attr:[input_party_codes:alice,output_party_codes:bob,],party:[alice,bob,]}\"]\n3 [label=\"dump_file:{in:[In:{t_3,},],out:[Out:{t_4,},],attr:[field_deliminator:\t,file_path:/tmp/output_bob.txt,line_terminator:\n,quoting_style:0,],party:[bob,]}\"]\n4 [label=\"copy:{in:[In:{t_1,},],out:[Out:{t_5,},],attr:[input_party_codes:alice,output_party_codes:carol,],party:[alice,carol,]}\"]\n5 [label=\"dump_file:{in:[In:{t_5,},],out:[Out:{t_6,},],attr:[field_deliminator:\t,file_path:/tmp/output_carol.txt,line_terminator:\n,quoting_style:0,],party:[carol,]}\"]\n0 -> 1 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 4 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 dump_file_1 copy_2 dump_file_3 copy_4 dump_file_5]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select plain_int_0 from alice.tbl_0 into outfile party_code 'bob' '/tmp/output_bob.txt' party_code 'carol' '/tmp/output_carol.txt' fields terminated BY ',';`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select tbl_0.plain_int_0 from alice.tbl_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"copy:{in:[In:{t_1,},],out:[Out:{t_2,},],attr:[input_party_codes:alice,output_party_codes:bob,],party:[alice,bob,]}\"]\n2 [label=\"dump_file:{in:[In:{t_2,},],out:[Out:{t_3,},],attr:[field_deliminator:,,file_path:/tmp/output_bob.txt,line_terminator:\n,quoting_style:0,],party:[bob,]}\"]\n3 [label=\"copy:{in:[In:{t_1,},],out:[Out:{t_4,},],attr:[input_party_codes:alice,output_party_codes:carol,],party:[alice,carol,]}\"]\n4 [label=\"dump_file:{in:[In:{t_4,},],out:[Out:{t_5,},],attr:[field_deliminator:,,file_path:/tmp/output_carol.txt,line_terminator:\n,quoting_style:0,],party:[carol,]}\"]\n0 -> 1 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 copy_1 dump_file_2 copy_3 dump_file_4]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select plain_int_0 from bob.tbl_0 into outfile party_code 'alice' '/tmp/output_alice.txt' party_code 'carol' '/tmp/output_carol.txt' fields terminated BY ',';`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select 'tbl_0'.'plain_int_0' from 'bob'.'tbl_0';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n1 [label=\"copy:{in:[In:{t_1,},],out:[Out:{t_2,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n2 [label=\"dump_file:{in:[In:{t_2,},],out:[Out:{t_3,},],attr:[field_deliminator:,,file_path:/tmp/output_alice.txt,line_terminator:\n,quoting_style:0,],party:[alice,]}\"]\n3 [label=\"copy:{in:[In:{t_2,},],out:[Out:{t_4,},],attr:[input_party_codes:alice,output_party_codes:carol,],party:[alice,carol,]}\"]\n4 [label=\"dump_file:{in:[In:{t_4,},],out:[Out:{t_5,},],attr:[field_deliminator:,,file_path:/tmp/output_carol.txt,line_terminator:\n,quoting_style:0,],party:[carol,]}\"]\n0 -> 1 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 copy_1 dump_file_2 copy_3 dump_file_4]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select plain_int_0 from bob.tbl_0 into outfile party_code 'carol' '/tmp/output_carol.txt' fields terminated BY ',';`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select 'tbl_0'.'plain_int_0' from 'bob'.'tbl_0';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n1 [label=\"copy:{in:[In:{t_1,},],out:[Out:{t_2,},],attr:[input_party_codes:bob,output_party_codes:carol,],party:[bob,carol,]}\"]\n2 [label=\"dump_file:{in:[In:{t_2,},],out:[Out:{t_3,},],attr:[field_deliminator:,,file_path:/tmp/output_carol.txt,line_terminator:\n,quoting_style:0,],party:[carol,]}\"]\n0 -> 1 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 copy_1 dump_file_2]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.join_int_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0 into outfile party_code 'alice' '/tmp/output_alice.txt' party_code 'bob' '/tmp/output_bob.txt' fields terminated BY ','`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_4,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_4,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"dump_file:{in:[In:{t_3,},],out:[Out:{t_5,},],attr:[field_deliminator:,,file_path:/tmp/output_alice.txt,line_terminator:\n,quoting_style:0,],party:[alice,]}\"]\n5 [label=\"copy:{in:[In:{t_3,},],out:[Out:{t_6,},],attr:[input_party_codes:alice,output_party_codes:bob,],party:[alice,bob,]}\"]\n6 [label=\"dump_file:{in:[In:{t_6,},],out:[Out:{t_7,},],attr:[field_deliminator:,,file_path:/tmp/output_bob.txt,line_terminator:\n,quoting_style:0,],party:[bob,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_4:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_6:{join_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 dump_file_4 copy_5 dump_file_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select (ta.compare_int_0 + tb.compare_int_0) > 0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0 into outfile party_code 'alice' '/tmp/output.txt' fields terminated BY ','`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.compare_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'join_int_0','tb'.'compare_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_11,},RightJoinIndex:{t_12,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_11,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_12,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_13,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"Add:{in:[Left:{t_13,},Right:{t_14,},],out:[Out:{t_7,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"constant:{in:[],out:[Out:{t_8,},],attr:[scalar:0,to_status:1,],party:[alice,bob,]}\"]\n9 [label=\"broadcast_to:{in:[In:{t_8,},ShapeRefTensor:{t_7,},],out:[Out:{t_9,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"Greater:{in:[Left:{t_7,},Right:{t_9,},],out:[Out:{t_10,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"make_private:{in:[In:{t_10,},],out:[Out:{t_15,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n12 [label=\"dump_file:{in:[In:{t_15,},],out:[Out:{t_16,},],attr:[field_deliminator:,,file_path:/tmp/output.txt,line_terminator:\n,quoting_style:0,],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{compare_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_10:{gt_out:SECRET:BOOL}\"]\n11 -> 12 [label = \"t_15:{gt_out:PRIVATE:BOOL}\"]\n2 -> 3 [label = \"t_11:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_12:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_5:{compare_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_13:{compare_int_0:SECRET:INT64}\"]\n6 -> 7 [label = \"t_14:{compare_int_0:SECRET:INT64}\"]\n7 -> 10 [label = \"t_7:{plus_out:SECRET:INT64}\"]\n7 -> 9 [label = \"t_7:{plus_out:SECRET:INT64}\"]\n8 -> 9 [label = \"t_8:{constant_data:PUBLIC:INT64}\"]\n9 -> 10 [label = \"t_9:{constant_data:PUBLIC:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 Add_7 constant_8 broadcast_to_9 Greater_10 make_private_11 dump_file_12]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select (ta.compare_int_0 + tb.compare_int_0) > 0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0 into outfile party_code 'alice' '/tmp/output_alice.txt' party_code 'bob' '/tmp/output_bob.txt' fields terminated BY ','`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.compare_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'join_int_0','tb'.'compare_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_11,},RightJoinIndex:{t_12,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_11,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_12,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_13,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"Add:{in:[Left:{t_13,},Right:{t_14,},],out:[Out:{t_7,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"constant:{in:[],out:[Out:{t_8,},],attr:[scalar:0,to_status:1,],party:[alice,bob,]}\"]\n9 [label=\"broadcast_to:{in:[In:{t_8,},ShapeRefTensor:{t_7,},],out:[Out:{t_9,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"Greater:{in:[Left:{t_7,},Right:{t_9,},],out:[Out:{t_10,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"make_private:{in:[In:{t_10,},],out:[Out:{t_15,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n12 [label=\"dump_file:{in:[In:{t_15,},],out:[Out:{t_16,},],attr:[field_deliminator:,,file_path:/tmp/output_alice.txt,line_terminator:\n,quoting_style:0,],party:[alice,]}\"]\n13 [label=\"copy:{in:[In:{t_15,},],out:[Out:{t_17,},],attr:[input_party_codes:alice,output_party_codes:bob,],party:[alice,bob,]}\"]\n14 [label=\"dump_file:{in:[In:{t_17,},],out:[Out:{t_18,},],attr:[field_deliminator:,,file_path:/tmp/output_bob.txt,line_terminator:\n,quoting_style:0,],party:[bob,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{compare_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_10:{gt_out:SECRET:BOOL}\"]\n11 -> 12 [label = \"t_15:{gt_out:PRIVATE:BOOL}\"]\n11 -> 13 [label = \"t_15:{gt_out:PRIVATE:BOOL}\"]\n13 -> 14 [label = \"t_17:{gt_out:PRIVATE:BOOL}\"]\n2 -> 3 [label = \"t_11:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_12:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_5:{compare_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_13:{compare_int_0:SECRET:INT64}\"]\n6 -> 7 [label = \"t_14:{compare_int_0:SECRET:INT64}\"]\n7 -> 10 [label = \"t_7:{plus_out:SECRET:INT64}\"]\n7 -> 9 [label = \"t_7:{plus_out:SECRET:INT64}\"]\n8 -> 9 [label = \"t_8:{constant_data:PUBLIC:INT64}\"]\n9 -> 10 [label = \"t_9:{constant_data:PUBLIC:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 Add_7 constant_8 broadcast_to_9 Greater_10 make_private_11 dump_file_12 copy_13 dump_file_14]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`insert into testdb.test_table (ci, cl) select a.plain_int_0, b.plain_string_0 from alice.tbl_0 a join bob.tbl_0  b on a.join_int_0=b.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select a.plain_int_0,a.join_int_0 from alice.tbl_0 as a;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'b'.'join_int_0','b'.'plain_string_0' from 'bob'.'tbl_0' as 'b';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_7,},RightJoinIndex:{t_8,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_7,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_8,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_6,},],out:[Out:{t_9,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"insert_table:{in:[In:{t_5,t_9,},],out:[Out:{t_10,t_11,},],attr:[column_names:[ci cl],table_name:testdb.test_table,],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{plain_string_0:PRIVATE:STRING}\"]\n2 -> 3 [label = \"t_7:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_8:{right_index:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_6:{plain_string_0:PRIVATE:STRING}\"]\n5 -> 6 [label = \"t_9:{plain_string_0:PRIVATE:STRING}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 insert_table_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`insert into test_table (ci, cl) select a.plain_int_0, b.plain_string_0 from alice.tbl_0 a join bob.tbl_0  b on a.join_int_0=b.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select a.plain_int_0,a.join_int_0 from alice.tbl_0 as a;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'b'.'join_int_0','b'.'plain_string_0' from 'bob'.'tbl_0' as 'b';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_7,},RightJoinIndex:{t_8,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_7,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_8,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_6,},],out:[Out:{t_9,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"insert_table:{in:[In:{t_5,t_9,},],out:[Out:{t_10,t_11,},],attr:[column_names:[ci cl],table_name:test_table,],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{plain_string_0:PRIVATE:STRING}\"]\n2 -> 3 [label = \"t_7:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_8:{right_index:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_6:{plain_string_0:PRIVATE:STRING}\"]\n5 -> 6 [label = \"t_9:{plain_string_0:PRIVATE:STRING}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 insert_table_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0, count(*) as c, sum(ta.plain_int_0) as b, max(ta.plain_int_0) as a, min(ta.plain_int_0) as d from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 group by ta.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_17,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_17,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"private_group:{in:[Key:{t_3,},],out:[GroupId:{t_18,},GroupNum:{t_19,},],attr:[],party:[alice,]}\"]\n5 [label=\"count:{in:[GroupId:{t_18,},GroupNum:{t_19,},In:{t_18,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n6 [label=\"sum:{in:[GroupId:{t_18,},GroupNum:{t_19,},In:{t_3,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n7 [label=\"max:{in:[GroupId:{t_18,},GroupNum:{t_19,},In:{t_3,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n8 [label=\"min:{in:[GroupId:{t_18,},GroupNum:{t_19,},In:{t_3,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n9 [label=\"firstrow:{in:[GroupId:{t_18,},GroupNum:{t_19,},In:{t_3,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n10 [label=\"constant:{in:[],out:[Out:{t_9,},],attr:[scalar:4,to_status:1,],party:[alice,bob,]}\"]\n11 [label=\"broadcast_to:{in:[In:{t_9,},ShapeRefTensor:{t_4,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n12 [label=\"GreaterEqual:{in:[Left:{t_4,},Right:{t_10,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n13 [label=\"filter:{in:[Filter:{t_11,},In:{t_4,t_5,t_6,t_7,t_8,},],out:[Out:{t_12,t_13,t_14,t_15,t_16,},],attr:[],party:[alice,]}\"]\n14 [label=\"publish_result:{in:[In:{t_16,t_12,t_13,t_14,t_15,},],out:[Out:{t_20,t_21,t_22,t_23,t_24,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_9:{constant_data:PUBLIC:INT64}\"]\n11 -> 12 [label = \"t_10:{constant_data:PRIVATE:INT64}\"]\n12 -> 13 [label = \"t_11:{ge_out:PRIVATE:BOOL}\"]\n13 -> 14 [label = \"t_12:{simple_count_result:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_13:{plain_int_0_sum:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_14:{plain_int_0_max:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_15:{plain_int_0_min:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_16:{plain_int_0_firstrow:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_17:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 9 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_19:{group_num:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_19:{group_num:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_19:{group_num:PRIVATE:INT64}\"]\n4 -> 8 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n4 -> 8 [label = \"t_19:{group_num:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_18:{group_id:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_19:{group_num:PRIVATE:INT64}\"]\n5 -> 11 [label = \"t_4:{simple_count_result:PRIVATE:INT64}\"]\n5 -> 12 [label = \"t_4:{simple_count_result:PRIVATE:INT64}\"]\n5 -> 13 [label = \"t_4:{simple_count_result:PRIVATE:INT64}\"]\n6 -> 13 [label = \"t_5:{plain_int_0_sum:PRIVATE:INT64}\"]\n7 -> 13 [label = \"t_6:{plain_int_0_max:PRIVATE:INT64}\"]\n8 -> 13 [label = \"t_7:{plain_int_0_min:PRIVATE:INT64}\"]\n9 -> 13 [label = \"t_8:{plain_int_0_firstrow:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 private_group_4 count_5 sum_6 max_7 min_8 firstrow_9 constant_10 broadcast_to_11 GreaterEqual_12 filter_13 publish_result_14]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.groupby_int_0, count(distinct(ta.compare_int_0)), sum(ta.compare_int_0) as b, max(ta.compare_int_0) as a, min(ta.compare_int_0) as d from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 group by ta.groupby_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,t_3,},],attr:[sql:select ta.plain_int_0,ta.groupby_int_0,ta.compare_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"bucket:{in:[In:{t_1,t_2,t_3,},Key:{t_1,},],out:[Out:{t_22,t_23,t_24,},],attr:[input_party_codes:[alice],],party:[alice,]}\"]\n3 [label=\"bucket:{in:[In:{t_4,},Key:{t_4,},],out:[Out:{t_25,},],attr:[input_party_codes:[bob],],party:[bob,]}\"]\n4 [label=\"psi_join:{in:[Left:{t_22,},Right:{t_25,},],out:[LeftJoinIndex:{t_26,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n5 [label=\"filter_by_index:{in:[Data:{t_23,t_24,},RowsIndexFilter:{t_26,},],out:[Out:{t_5,t_6,},],attr:[],party:[alice,]}\"]\n6 [label=\"private_group:{in:[Key:{t_5,},],out:[GroupId:{t_27,},GroupNum:{t_28,},],attr:[],party:[alice,]}\"]\n7 [label=\"count:{in:[GroupId:{t_27,},GroupNum:{t_28,},In:{t_27,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n8 [label=\"count_distinct:{in:[GroupId:{t_27,},GroupNum:{t_28,},In:{t_6,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n9 [label=\"sum:{in:[GroupId:{t_27,},GroupNum:{t_28,},In:{t_6,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n10 [label=\"max:{in:[GroupId:{t_27,},GroupNum:{t_28,},In:{t_6,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n11 [label=\"min:{in:[GroupId:{t_27,},GroupNum:{t_28,},In:{t_6,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n12 [label=\"firstrow:{in:[GroupId:{t_27,},GroupNum:{t_28,},In:{t_5,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n13 [label=\"constant:{in:[],out:[Out:{t_13,},],attr:[scalar:4,to_status:1,],party:[alice,bob,]}\"]\n14 [label=\"broadcast_to:{in:[In:{t_13,},ShapeRefTensor:{t_12,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n15 [label=\"GreaterEqual:{in:[Left:{t_12,},Right:{t_14,},],out:[Out:{t_15,},],attr:[],party:[alice,]}\"]\n16 [label=\"filter:{in:[Filter:{t_15,},In:{t_7,t_8,t_9,t_10,t_11,t_12,},],out:[Out:{t_16,t_17,t_18,t_19,t_20,t_21,},],attr:[],party:[alice,]}\"]\n17 [label=\"publish_result:{in:[In:{t_20,t_16,t_17,t_18,t_19,},],out:[Out:{t_29,t_30,t_31,t_32,t_33,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 2 [label = \"t_2:{groupby_int_0:PRIVATE:INT64}\"]\n0 -> 2 [label = \"t_3:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n10 -> 16 [label = \"t_9:{compare_int_0_max:PRIVATE:INT64}\"]\n11 -> 16 [label = \"t_10:{compare_int_0_min:PRIVATE:INT64}\"]\n12 -> 16 [label = \"t_11:{groupby_int_0_firstrow:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_13:{constant_data:PUBLIC:INT64}\"]\n14 -> 15 [label = \"t_14:{constant_data:PRIVATE:INT64}\"]\n15 -> 16 [label = \"t_15:{ge_out:PRIVATE:BOOL}\"]\n16 -> 17 [label = \"t_16:{compare_int_0_count:PRIVATE:INT64}\"]\n16 -> 17 [label = \"t_17:{compare_int_0_sum:PRIVATE:INT64}\"]\n16 -> 17 [label = \"t_18:{compare_int_0_max:PRIVATE:INT64}\"]\n16 -> 17 [label = \"t_19:{compare_int_0_min:PRIVATE:INT64}\"]\n16 -> 17 [label = \"t_20:{groupby_int_0_firstrow:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_22:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 5 [label = \"t_23:{groupby_int_0:PRIVATE:INT64}\"]\n2 -> 5 [label = \"t_24:{compare_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_25:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_26:{left_index:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 11 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 12 [label = \"t_5:{groupby_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_5:{groupby_int_0:PRIVATE:INT64}\"]\n5 -> 8 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 9 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_27:{group_id:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_28:{group_num:PRIVATE:INT64}\"]\n6 -> 11 [label = \"t_27:{group_id:PRIVATE:INT64}\"]\n6 -> 11 [label = \"t_28:{group_num:PRIVATE:INT64}\"]\n6 -> 12 [label = \"t_27:{group_id:PRIVATE:INT64}\"]\n6 -> 12 [label = \"t_28:{group_num:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_27:{group_id:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_27:{group_id:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_28:{group_num:PRIVATE:INT64}\"]\n6 -> 8 [label = \"t_27:{group_id:PRIVATE:INT64}\"]\n6 -> 8 [label = \"t_28:{group_num:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_27:{group_id:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_28:{group_num:PRIVATE:INT64}\"]\n7 -> 14 [label = \"t_12:{simple_count_result:PRIVATE:INT64}\"]\n7 -> 15 [label = \"t_12:{simple_count_result:PRIVATE:INT64}\"]\n7 -> 16 [label = \"t_12:{simple_count_result:PRIVATE:INT64}\"]\n8 -> 16 [label = \"t_7:{compare_int_0_count:PRIVATE:INT64}\"]\n9 -> 16 [label = \"t_8:{compare_int_0_sum:PRIVATE:INT64}\"]\n}`, `Batched pipeline with 1 nodes`, testConf{groupThreshold: 4, batched: true, revealGroupCount: false}},\n\t{`select count(distinct(ta.compare_int_0)), sum(ta.compare_int_0) as b, max(ta.compare_int_0) as a, min(ta.compare_int_0) as d from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.compare_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_9,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"unique:{in:[Key:{t_4,},],out:[UniqueKey:{t_10,},],attr:[],party:[alice,]}\"]\n5 [label=\"reduce[count]:{in:[In:{t_10,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n6 [label=\"reduce[sum]:{in:[In:{t_4,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n7 [label=\"reduce[max]:{in:[In:{t_4,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n8 [label=\"reduce[min]:{in:[In:{t_4,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n9 [label=\"publish_result:{in:[In:{t_5,t_6,t_7,t_8,},],out:[Out:{t_11,t_12,t_13,t_14,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_4:{compare_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_4:{compare_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_4:{compare_int_0:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_4:{compare_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_10:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 9 [label = \"t_5:{compare_int_0_count:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_6:{compare_int_0_sum:PRIVATE:INT64}\"]\n7 -> 9 [label = \"t_7:{compare_int_0_max:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_8:{compare_int_0_min:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 unique_4 reduce[count]_5 reduce[sum]_6 reduce[max]_7 reduce[min]_8 publish_result_9]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_4,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_4,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"publish_result:{in:[In:{t_3,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_4:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 publish_result_4]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0 from alice.tbl_0 as ta left join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_5,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:1,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_5,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"publish_result:{in:[In:{t_4,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_5:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 publish_result_4]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0 from alice.tbl_0 as ta left join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0 left join carol.tbl_0 as tc on tb.join_int_1 = tc.join_int_1`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'join_int_0','tb'.'join_int_1' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_3,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{t_10,},],attr:[input_party_codes:[alice bob],join_type:1,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_9,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_10,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"run_sql:{in:[],out:[Out:{t_7,},],attr:[sql:select tc.join_int_1 from carol.tbl_0 as tc;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n6 [label=\"psi_join:{in:[Left:{t_6,},Right:{t_7,},],out:[LeftJoinIndex:{t_11,},RightJoinIndex:{},],attr:[input_party_codes:[bob carol],join_type:1,psi_algorithm:0,],party:[bob,carol,]}\"]\n7 [label=\"copy:{in:[In:{t_11,},],out:[Out:{t_12,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter_by_index:{in:[Data:{t_5,},RowsIndexFilter:{t_12,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n9 [label=\"publish_result:{in:[In:{t_8,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{join_int_1:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_10:{right_index:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_6:{join_int_1:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_7:{join_int_1:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_11:{left_index:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_12:{left_index:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_8:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 run_sql_5 psi_join_6 copy_7 filter_by_index_8 publish_result_9]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select max(ta.aggregate_float_0 + ta.aggregate_float_0) from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.aggregate_float_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_7,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_7,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"Add:{in:[Left:{t_4,},Right:{t_4,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n5 [label=\"reduce[max]:{in:[In:{t_5,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n6 [label=\"publish_result:{in:[In:{t_6,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{aggregate_float_0:PRIVATE:FLOAT64}\"]\n1 -> 2 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_7:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_4:{aggregate_float_0:PRIVATE:FLOAT64}\"]\n3 -> 4 [label = \"t_4:{aggregate_float_0:PRIVATE:FLOAT64}\"]\n4 -> 5 [label = \"t_5:{plus_out:PRIVATE:FLOAT64}\"]\n5 -> 6 [label = \"t_6:{plus_out_max:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 Add_4 reduce[max]_5 publish_result_6]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*) as c, sum(ta.plain_int_0) as b, max(ta.plain_int_0) as a, min(ta.plain_int_0) as d, avg(ta.plain_int_0) as f from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_9,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"shape:{in:[In:{t_3,},],out:[Out:{t_4,},],attr:[axis:0,],party:[alice,]}\"]\n5 [label=\"reduce[sum]:{in:[In:{t_3,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n6 [label=\"reduce[max]:{in:[In:{t_3,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n7 [label=\"reduce[min]:{in:[In:{t_3,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n8 [label=\"reduce[avg]:{in:[In:{t_3,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n9 [label=\"publish_result:{in:[In:{t_4,t_5,t_6,t_7,t_8,},],out:[Out:{t_10,t_11,t_12,t_13,t_14,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_4:{plain_int_0_count:PRIVATE:INT64}\"]\n5 -> 9 [label = \"t_5:{plain_int_0_sum:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_6:{plain_int_0_max:PRIVATE:INT64}\"]\n7 -> 9 [label = \"t_7:{plain_int_0_min:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_8:{plain_int_0_avg:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 shape_4 reduce[sum]_5 reduce[max]_6 reduce[min]_7 reduce[avg]_8 publish_result_9]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 where ta.plain_int_1 > tb.plain_int_1`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.plain_int_1 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'plain_int_0','tb'.'plain_int_1' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_10,},RightJoinIndex:{t_11,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_10,},],out:[Out:{t_5,t_6,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_11,},],out:[Out:{t_7,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_7,},],out:[Out:{t_12,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"Greater:{in:[Left:{t_6,},Right:{t_12,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n7 [label=\"filter:{in:[Filter:{t_8,},In:{t_5,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n8 [label=\"publish_result:{in:[In:{t_9,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{plain_int_1:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{plain_int_1:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_10:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_11:{right_index:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_6:{plain_int_1:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_7:{plain_int_1:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_12:{plain_int_1:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_8:{gt_out:PRIVATE:BOOL}\"]\n7 -> 8 [label = \"t_9:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 Greater_6 filter_7 publish_result_8]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0 * tb.plain_int_0 as t1, ta.plain_int_0 + tb.plain_int_0 as t2, ta.plain_int_0 - tb.plain_int_0 as t3, ta.plain_int_0 / tb.plain_int_0 as t1 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 where ta.plain_int_1 > tb.plain_int_1`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.plain_int_1 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'plain_int_0','tb'.'plain_int_1' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_17,},RightJoinIndex:{t_18,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_17,},],out:[Out:{t_5,t_6,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_3,t_4,},RowsIndexFilter:{t_18,},],out:[Out:{t_7,t_8,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_8,},],out:[Out:{t_19,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"Greater:{in:[Left:{t_6,},Right:{t_19,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n7 [label=\"copy:{in:[In:{t_7,},],out:[Out:{t_20,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter:{in:[Filter:{t_9,},In:{t_5,t_20,},],out:[Out:{t_10,t_11,},],attr:[],party:[alice,]}\"]\n9 [label=\"Mul:{in:[Left:{t_10,},Right:{t_11,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n10 [label=\"Add:{in:[Left:{t_10,},Right:{t_11,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n11 [label=\"Minus:{in:[Left:{t_10,},Right:{t_11,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n12 [label=\"Cast:{in:[In:{t_10,},],out:[Out:{t_15,},],attr:[],party:[alice,]}\"]\n13 [label=\"Div:{in:[Left:{t_15,},Right:{t_11,},],out:[Out:{t_16,},],attr:[],party:[alice,]}\"]\n14 [label=\"publish_result:{in:[In:{t_12,t_13,t_14,t_16,},],out:[Out:{t_21,t_22,t_23,t_24,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{plain_int_1:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{plain_int_1:PRIVATE:INT64}\"]\n10 -> 14 [label = \"t_13:{plus_out:PRIVATE:INT64}\"]\n11 -> 14 [label = \"t_14:{minus_out:PRIVATE:INT64}\"]\n12 -> 13 [label = \"t_15:{plain_int_0:PRIVATE:FLOAT64}\"]\n13 -> 14 [label = \"t_16:{div_out:PRIVATE:FLOAT64}\"]\n2 -> 3 [label = \"t_17:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_18:{right_index:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_6:{plain_int_1:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_8:{plain_int_1:PRIVATE:INT64}\"]\n4 -> 7 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_19:{plain_int_1:PRIVATE:INT64}\"]\n6 -> 8 [label = \"t_9:{gt_out:PRIVATE:BOOL}\"]\n7 -> 8 [label = \"t_20:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 10 [label = \"t_10:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 10 [label = \"t_11:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 11 [label = \"t_10:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 11 [label = \"t_11:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 12 [label = \"t_10:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 13 [label = \"t_11:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_10:{plain_int_0:PRIVATE:INT64}\"]\n8 -> 9 [label = \"t_11:{plain_int_0:PRIVATE:INT64}\"]\n9 -> 14 [label = \"t_12:{mul_out:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 Greater_6 copy_7 filter_8 Mul_9 Add_10 Minus_11 Cast_12 Div_13 publish_result_14]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0 where ta.plain_int_1 > tb.plain_int_1 and ta.compare_int_0 < tb.compare_int_0 and ta.compare_int_1 <> tb.compare_int_1 and ta.compare_int_2 >= tb.compare_int_2 and ta.compare_float_0 <= tb.compare_float_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,t_3,t_4,t_5,t_6,},],attr:[sql:select ta.plain_int_0,ta.compare_int_0,ta.compare_float_0,ta.plain_int_1,ta.compare_int_1,ta.compare_int_2 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_7,t_8,t_9,t_10,t_11,t_12,},],attr:[sql:select 'tb'.'plain_int_0','tb'.'compare_int_0','tb'.'compare_float_0','tb'.'plain_int_1','tb'.'compare_int_1','tb'.'compare_int_2' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_7,},],out:[LeftJoinIndex:{t_34,},RightJoinIndex:{t_35,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,t_3,t_4,t_5,t_6,},RowsIndexFilter:{t_34,},],out:[Out:{t_13,t_14,t_15,t_16,t_17,t_18,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_8,t_9,t_10,t_11,t_12,},RowsIndexFilter:{t_35,},],out:[Out:{t_19,t_20,t_21,t_22,t_23,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_21,},],out:[Out:{t_36,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"Greater:{in:[Left:{t_16,},Right:{t_36,},],out:[Out:{t_24,},],attr:[],party:[alice,]}\"]\n7 [label=\"make_share:{in:[In:{t_14,},],out:[Out:{t_37,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"make_share:{in:[In:{t_19,},],out:[Out:{t_38,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"Less:{in:[Left:{t_37,},Right:{t_38,},],out:[Out:{t_25,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"make_share:{in:[In:{t_17,},],out:[Out:{t_39,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"make_share:{in:[In:{t_22,},],out:[Out:{t_40,},],attr:[],party:[alice,bob,]}\"]\n12 [label=\"NotEqual:{in:[Left:{t_39,},Right:{t_40,},],out:[Out:{t_26,},],attr:[],party:[alice,bob,]}\"]\n13 [label=\"make_share:{in:[In:{t_18,},],out:[Out:{t_41,},],attr:[],party:[alice,bob,]}\"]\n14 [label=\"make_share:{in:[In:{t_23,},],out:[Out:{t_42,},],attr:[],party:[alice,bob,]}\"]\n15 [label=\"GreaterEqual:{in:[Left:{t_41,},Right:{t_42,},],out:[Out:{t_27,},],attr:[],party:[alice,bob,]}\"]\n16 [label=\"make_share:{in:[In:{t_15,},],out:[Out:{t_43,},],attr:[],party:[alice,bob,]}\"]\n17 [label=\"make_share:{in:[In:{t_20,},],out:[Out:{t_44,},],attr:[],party:[alice,bob,]}\"]\n18 [label=\"LessEqual:{in:[Left:{t_43,},Right:{t_44,},],out:[Out:{t_28,},],attr:[],party:[alice,bob,]}\"]\n19 [label=\"make_public:{in:[In:{t_24,},],out:[Out:{t_45,},],attr:[],party:[alice,bob,]}\"]\n20 [label=\"LogicalAnd:{in:[Left:{t_45,},Right:{t_25,},],out:[Out:{t_29,},],attr:[],party:[alice,bob,]}\"]\n21 [label=\"LogicalAnd:{in:[Left:{t_29,},Right:{t_26,},],out:[Out:{t_30,},],attr:[],party:[alice,bob,]}\"]\n22 [label=\"LogicalAnd:{in:[Left:{t_30,},Right:{t_27,},],out:[Out:{t_31,},],attr:[],party:[alice,bob,]}\"]\n23 [label=\"LogicalAnd:{in:[Left:{t_31,},Right:{t_28,},],out:[Out:{t_32,},],attr:[],party:[alice,bob,]}\"]\n24 [label=\"make_private:{in:[In:{t_32,},],out:[Out:{t_46,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n25 [label=\"filter:{in:[Filter:{t_46,},In:{t_13,},],out:[Out:{t_33,},],attr:[],party:[alice,]}\"]\n26 [label=\"publish_result:{in:[In:{t_33,},],out:[Out:{t_47,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{compare_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{compare_float_0:PRIVATE:FLOAT64}\"]\n0 -> 3 [label = \"t_4:{plain_int_1:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_5:{compare_int_1:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_6:{compare_int_2:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_10:{plain_int_1:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_11:{compare_int_1:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_12:{compare_int_2:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_8:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_9:{compare_float_0:PRIVATE:FLOAT64}\"]\n10 -> 12 [label = \"t_39:{compare_int_1:SECRET:INT64}\"]\n11 -> 12 [label = \"t_40:{compare_int_1:SECRET:INT64}\"]\n12 -> 21 [label = \"t_26:{ne_out:SECRET:BOOL}\"]\n13 -> 15 [label = \"t_41:{compare_int_2:SECRET:INT64}\"]\n14 -> 15 [label = \"t_42:{compare_int_2:SECRET:INT64}\"]\n15 -> 22 [label = \"t_27:{ge_out:SECRET:BOOL}\"]\n16 -> 18 [label = \"t_43:{compare_float_0:SECRET:FLOAT64}\"]\n17 -> 18 [label = \"t_44:{compare_float_0:SECRET:FLOAT64}\"]\n18 -> 23 [label = \"t_28:{le_out:SECRET:BOOL}\"]\n19 -> 20 [label = \"t_45:{gt_out:PUBLIC:BOOL}\"]\n2 -> 3 [label = \"t_34:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_35:{right_index:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_29:{and_out:SECRET:BOOL}\"]\n21 -> 22 [label = \"t_30:{and_out:SECRET:BOOL}\"]\n22 -> 23 [label = \"t_31:{and_out:SECRET:BOOL}\"]\n23 -> 24 [label = \"t_32:{and_out:SECRET:BOOL}\"]\n24 -> 25 [label = \"t_46:{and_out:PRIVATE:BOOL}\"]\n25 -> 26 [label = \"t_33:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 10 [label = \"t_17:{compare_int_1:PRIVATE:INT64}\"]\n3 -> 13 [label = \"t_18:{compare_int_2:PRIVATE:INT64}\"]\n3 -> 16 [label = \"t_15:{compare_float_0:PRIVATE:FLOAT64}\"]\n3 -> 25 [label = \"t_13:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_16:{plain_int_1:PRIVATE:INT64}\"]\n3 -> 7 [label = \"t_14:{compare_int_0:PRIVATE:INT64}\"]\n4 -> 11 [label = \"t_22:{compare_int_1:PRIVATE:INT64}\"]\n4 -> 14 [label = \"t_23:{compare_int_2:PRIVATE:INT64}\"]\n4 -> 17 [label = \"t_20:{compare_float_0:PRIVATE:FLOAT64}\"]\n4 -> 5 [label = \"t_21:{plain_int_1:PRIVATE:INT64}\"]\n4 -> 8 [label = \"t_19:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_36:{plain_int_1:PRIVATE:INT64}\"]\n6 -> 19 [label = \"t_24:{gt_out:PRIVATE:BOOL}\"]\n7 -> 9 [label = \"t_37:{compare_int_0:SECRET:INT64}\"]\n8 -> 9 [label = \"t_38:{compare_int_0:SECRET:INT64}\"]\n9 -> 20 [label = \"t_25:{lt_out:SECRET:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 Greater_6 make_share_7 make_share_8 Less_9 make_share_10 make_share_11 NotEqual_12 make_share_13 make_share_14 GreaterEqual_15 make_share_16 make_share_17 LessEqual_18 make_public_19 LogicalAnd_20 LogicalAnd_21 LogicalAnd_22 LogicalAnd_23 make_private_24 filter_25 publish_result_26]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.join_int_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_4,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_4,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"publish_result:{in:[In:{t_3,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_4:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 publish_result_4]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.join_int_0 + 1 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.join_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'join_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_7,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_7,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"constant:{in:[],out:[Out:{t_4,},],attr:[scalar:1,to_status:1,],party:[alice,bob,]}\"]\n5 [label=\"broadcast_to:{in:[In:{t_4,},ShapeRefTensor:{t_3,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n6 [label=\"Add:{in:[Left:{t_3,},Right:{t_5,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n7 [label=\"publish_result:{in:[In:{t_6,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_7:{left_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_4:{constant_data:PUBLIC:INT64}\"]\n5 -> 6 [label = \"t_5:{constant_data:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_6:{plus_out:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 constant_4 broadcast_to_5 Add_6 publish_result_7]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.join_int_0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.join_int_0 = tb.join_int_0 where ta.compare_int_0 > tb.compare_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.join_int_0,ta.compare_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'join_int_0','tb'.'compare_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_10,},RightJoinIndex:{t_11,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_10,},],out:[Out:{t_5,t_6,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_11,},],out:[Out:{t_7,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_12,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_7,},],out:[Out:{t_13,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"Greater:{in:[Left:{t_12,},Right:{t_13,},],out:[Out:{t_8,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"make_private:{in:[In:{t_8,},],out:[Out:{t_14,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n9 [label=\"filter:{in:[Filter:{t_14,},In:{t_5,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n10 [label=\"publish_result:{in:[In:{t_9,},],out:[Out:{t_15,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{compare_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_10:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_11:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n3 -> 9 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_7:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_12:{compare_int_0:SECRET:INT64}\"]\n6 -> 7 [label = \"t_13:{compare_int_0:SECRET:INT64}\"]\n7 -> 8 [label = \"t_8:{gt_out:SECRET:BOOL}\"]\n8 -> 9 [label = \"t_14:{gt_out:PRIVATE:BOOL}\"]\n9 -> 10 [label = \"t_9:{join_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 Greater_7 make_private_8 filter_9 publish_result_10]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0 in (1,2,3) from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_15,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_15,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"constant:{in:[],out:[Out:{t_4,},],attr:[scalar:1,to_status:1,],party:[alice,bob,]}\"]\n5 [label=\"broadcast_to:{in:[In:{t_4,},ShapeRefTensor:{t_3,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n6 [label=\"Equal:{in:[Left:{t_3,},Right:{t_5,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n7 [label=\"constant:{in:[],out:[Out:{t_7,},],attr:[scalar:2,to_status:1,],party:[alice,bob,]}\"]\n8 [label=\"broadcast_to:{in:[In:{t_7,},ShapeRefTensor:{t_3,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n9 [label=\"Equal:{in:[Left:{t_3,},Right:{t_8,},],out:[Out:{t_9,},],attr:[],party:[alice,]}\"]\n10 [label=\"constant:{in:[],out:[Out:{t_10,},],attr:[scalar:3,to_status:1,],party:[alice,bob,]}\"]\n11 [label=\"broadcast_to:{in:[In:{t_10,},ShapeRefTensor:{t_3,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n12 [label=\"Equal:{in:[Left:{t_3,},Right:{t_11,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n13 [label=\"LogicalOr:{in:[Left:{t_9,},Right:{t_12,},],out:[Out:{t_13,},],attr:[],party:[alice,]}\"]\n14 [label=\"LogicalOr:{in:[Left:{t_6,},Right:{t_13,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n15 [label=\"publish_result:{in:[In:{t_14,},],out:[Out:{t_16,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_10:{constant_data:PUBLIC:INT64}\"]\n11 -> 12 [label = \"t_11:{constant_data:PRIVATE:INT64}\"]\n12 -> 13 [label = \"t_12:{eq_out:PRIVATE:BOOL}\"]\n13 -> 14 [label = \"t_13:{or_out:PRIVATE:BOOL}\"]\n14 -> 15 [label = \"t_14:{or_out:PRIVATE:BOOL}\"]\n2 -> 3 [label = \"t_15:{left_index:PRIVATE:INT64}\"]\n3 -> 11 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 12 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 9 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_4:{constant_data:PUBLIC:INT64}\"]\n5 -> 6 [label = \"t_5:{constant_data:PRIVATE:INT64}\"]\n6 -> 14 [label = \"t_6:{eq_out:PRIVATE:BOOL}\"]\n7 -> 8 [label = \"t_7:{constant_data:PUBLIC:INT64}\"]\n8 -> 9 [label = \"t_8:{constant_data:PRIVATE:INT64}\"]\n9 -> 13 [label = \"t_9:{eq_out:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 constant_4 broadcast_to_5 Equal_6 constant_7 broadcast_to_8 Equal_9 constant_10 broadcast_to_11 Equal_12 LogicalOr_13 LogicalOr_14 publish_result_15]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.plain_int_0 in (select tb.plain_int_0 from bob.tbl_0 as tb) from alice.tbl_0 as ta`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"copy:{in:[In:{t_2,},],out:[Out:{t_4,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n3 [label=\"in:{in:[Left:{t_1,},Right:{t_4,},],out:[Out:{t_3,},],attr:[in_type:2,input_party_codes:[alice alice],psi_algorithm:0,reveal_to:[alice],],party:[alice,]}\"]\n4 [label=\"publish_result:{in:[In:{t_3,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_3:{in_result:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 copy_2 in_3 publish_result_4]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.compare_int_0 in (select tb.compare_int_0 from bob.tbl_0 as tb) from alice.tbl_0 as ta`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.compare_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'compare_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"in:{in:[Left:{t_1,},Right:{t_2,},],out:[Out:{t_3,},],attr:[in_type:0,input_party_codes:[alice bob],psi_algorithm:0,reveal_to:[alice],],party:[alice,bob,]}\"]\n3 [label=\"publish_result:{in:[In:{t_3,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{compare_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_3:{in_result:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 in_2 publish_result_3]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.compare_int_0 from alice.tbl_0 as ta where ta.compare_int_0 in (select tb.compare_int_0 from bob.tbl_0 as tb)`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.compare_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'compare_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"in:{in:[Left:{t_1,},Right:{t_2,},],out:[Out:{t_3,},],attr:[in_type:0,input_party_codes:[alice bob],psi_algorithm:0,reveal_to:[alice],],party:[alice,bob,]}\"]\n3 [label=\"filter:{in:[Filter:{t_3,},In:{t_1,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n4 [label=\"publish_result:{in:[In:{t_4,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{compare_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{compare_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_3:{in_result:PRIVATE:BOOL}\"]\n3 -> 4 [label = \"t_4:{compare_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 in_2 filter_3 publish_result_4]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.compare_int_0 from alice.tbl_0 as ta where ta.compare_int_0 not in (select tb.compare_int_0 from bob.tbl_0 as tb)`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.compare_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'compare_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"in:{in:[Left:{t_1,},Right:{t_2,},],out:[Out:{t_3,},],attr:[in_type:0,input_party_codes:[alice bob],psi_algorithm:0,reveal_to:[alice],],party:[alice,bob,]}\"]\n3 [label=\"make_share:{in:[In:{t_3,},],out:[Out:{t_6,},],attr:[],party:[alice,bob,]}\"]\n4 [label=\"Not:{in:[In:{t_6,},],out:[Out:{t_4,},],attr:[],party:[alice,bob,]}\"]\n5 [label=\"make_private:{in:[In:{t_4,},],out:[Out:{t_7,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n6 [label=\"filter:{in:[Filter:{t_7,},In:{t_1,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n7 [label=\"publish_result:{in:[In:{t_5,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{compare_int_0:PRIVATE:INT64}\"]\n0 -> 6 [label = \"t_1:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{compare_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_3:{in_result:PRIVATE:BOOL}\"]\n3 -> 4 [label = \"t_6:{in_result:SECRET:BOOL}\"]\n4 -> 5 [label = \"t_4:{not_out:SECRET:BOOL}\"]\n5 -> 6 [label = \"t_7:{not_out:PRIVATE:BOOL}\"]\n6 -> 7 [label = \"t_5:{compare_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 in_2 make_share_3 Not_4 make_private_5 filter_6 publish_result_7]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select not(ta.plain_int_0 > tb.plain_int_0) from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.plain_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select 'tb'.'plain_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_2,},],out:[LeftJoinIndex:{t_7,},RightJoinIndex:{t_8,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_7,},],out:[Out:{t_3,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_8,},],out:[Out:{t_4,},],attr:[],party:[bob,]}\"]\n5 [label=\"copy:{in:[In:{t_4,},],out:[Out:{t_9,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n6 [label=\"Greater:{in:[Left:{t_3,},Right:{t_9,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n7 [label=\"Not:{in:[In:{t_5,},],out:[Out:{t_6,},],attr:[],party:[alice,]}\"]\n8 [label=\"publish_result:{in:[In:{t_6,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_7:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_8:{right_index:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_9:{plain_int_0:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_5:{gt_out:PRIVATE:BOOL}\"]\n7 -> 8 [label = \"t_6:{not_out:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 copy_5 Greater_6 Not_7 publish_result_8]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select not(ta.compare_int_0 > tb.compare_int_0) from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.compare_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'plain_int_0','tb'.'compare_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{t_10,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_9,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_10,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_11,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_12,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"Greater:{in:[Left:{t_11,},Right:{t_12,},],out:[Out:{t_7,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"make_private:{in:[In:{t_7,},],out:[Out:{t_13,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n9 [label=\"Not:{in:[In:{t_13,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n10 [label=\"publish_result:{in:[In:{t_8,},],out:[Out:{t_14,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{compare_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_10:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_5:{compare_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_11:{compare_int_0:SECRET:INT64}\"]\n6 -> 7 [label = \"t_12:{compare_int_0:SECRET:INT64}\"]\n7 -> 8 [label = \"t_7:{gt_out:SECRET:BOOL}\"]\n8 -> 9 [label = \"t_13:{gt_out:PRIVATE:BOOL}\"]\n9 -> 10 [label = \"t_8:{not_out:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 Greater_7 make_private_8 Not_9 publish_result_10]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select (ta.compare_int_0 + tb.compare_int_0 - 3) > 0 from alice.tbl_0 as ta join bob.tbl_0 as tb on ta.plain_int_0 = tb.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select ta.plain_int_0,ta.compare_int_0 from alice.tbl_0 as ta;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'tb'.'plain_int_0','tb'.'compare_int_0' from 'bob'.'tbl_0' as 'tb';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_14,},RightJoinIndex:{t_15,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_14,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_15,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_16,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_17,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"Add:{in:[Left:{t_16,},Right:{t_17,},],out:[Out:{t_7,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"constant:{in:[],out:[Out:{t_8,},],attr:[scalar:3,to_status:1,],party:[alice,bob,]}\"]\n9 [label=\"broadcast_to:{in:[In:{t_8,},ShapeRefTensor:{t_7,},],out:[Out:{t_9,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"Minus:{in:[Left:{t_7,},Right:{t_9,},],out:[Out:{t_10,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"constant:{in:[],out:[Out:{t_11,},],attr:[scalar:0,to_status:1,],party:[alice,bob,]}\"]\n12 [label=\"broadcast_to:{in:[In:{t_11,},ShapeRefTensor:{t_10,},],out:[Out:{t_12,},],attr:[],party:[alice,bob,]}\"]\n13 [label=\"Greater:{in:[Left:{t_10,},Right:{t_12,},],out:[Out:{t_13,},],attr:[],party:[alice,bob,]}\"]\n14 [label=\"make_private:{in:[In:{t_13,},],out:[Out:{t_18,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n15 [label=\"publish_result:{in:[In:{t_18,},],out:[Out:{t_19,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{compare_int_0:PRIVATE:INT64}\"]\n10 -> 12 [label = \"t_10:{minus_out:SECRET:INT64}\"]\n10 -> 13 [label = \"t_10:{minus_out:SECRET:INT64}\"]\n11 -> 12 [label = \"t_11:{constant_data:PUBLIC:INT64}\"]\n12 -> 13 [label = \"t_12:{constant_data:PUBLIC:INT64}\"]\n13 -> 14 [label = \"t_13:{gt_out:SECRET:BOOL}\"]\n14 -> 15 [label = \"t_18:{gt_out:PRIVATE:BOOL}\"]\n2 -> 3 [label = \"t_14:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_15:{right_index:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_5:{compare_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_16:{compare_int_0:SECRET:INT64}\"]\n6 -> 7 [label = \"t_17:{compare_int_0:SECRET:INT64}\"]\n7 -> 10 [label = \"t_7:{plus_out:SECRET:INT64}\"]\n7 -> 9 [label = \"t_7:{plus_out:SECRET:INT64}\"]\n8 -> 9 [label = \"t_8:{constant_data:PUBLIC:INT64}\"]\n9 -> 10 [label = \"t_9:{constant_data:PUBLIC:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 Add_7 constant_8 broadcast_to_9 Minus_10 constant_11 broadcast_to_12 Greater_13 make_private_14 publish_result_15]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select distinct groupby_int_0 from (select ta.groupby_int_0 from alice.tbl_0 as ta union all select tb.groupby_int_0 from bob.tbl_0 as tb) as tt`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select any_value(ta.groupby_int_0) as expr_242 from alice.tbl_0 as ta group by ta.groupby_int_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,},],attr:[sql:select 'tb'.'groupby_int_0' from 'bob'.'tbl_0' as 'tb' group by 'tb'.'groupby_int_0';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"make_share:{in:[In:{t_2,},],out:[Out:{t_7,},],attr:[],party:[alice,bob,]}\"]\n3 [label=\"make_share:{in:[In:{t_4,},],out:[Out:{t_8,},],attr:[],party:[alice,bob,]}\"]\n4 [label=\"concat:{in:[In:{t_7,t_8,},],out:[Out:{t_5,},],attr:[axis:0,],party:[alice,bob,]}\"]\n5 [label=\"sort:{in:[In:{t_5,t_5,},Key:{t_5,},],out:[Out:{t_9,t_10,},],attr:[reverse:[false],],party:[alice,bob,]}\"]\n6 [label=\"oblivious_group_mark:{in:[Key:{t_9,},],out:[Group:{t_11,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"shuffle:{in:[In:{t_10,t_11,},],out:[Out:{t_12,t_13,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"make_public:{in:[In:{t_13,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"filter:{in:[Filter:{t_14,},In:{t_12,},],out:[Out:{t_6,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"make_private:{in:[In:{t_6,},],out:[Out:{t_15,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n11 [label=\"publish_result:{in:[In:{t_15,},],out:[Out:{t_16,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{groupby_int_0_firstrow:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_4:{groupby_int_0_firstrow:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_15:{groupby_int_0_firstrow_firstrow:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_7:{groupby_int_0_firstrow:SECRET:INT64}\"]\n3 -> 4 [label = \"t_8:{groupby_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_5:{groupby_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_5:{groupby_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_5:{groupby_int_0_firstrow:SECRET:INT64}\"]\n5 -> 6 [label = \"t_9:{groupby_int_0_firstrow:SECRET:INT64}\"]\n5 -> 7 [label = \"t_10:{groupby_int_0_firstrow:SECRET:INT64}\"]\n6 -> 7 [label = \"t_11:{group_mark:SECRET:BOOL}\"]\n7 -> 8 [label = \"t_13:{group_mark:SECRET:BOOL}\"]\n7 -> 9 [label = \"t_12:{groupby_int_0_firstrow:SECRET:INT64}\"]\n8 -> 9 [label = \"t_14:{group_mark:PUBLIC:BOOL}\"]\n9 -> 10 [label = \"t_6:{groupby_int_0_firstrow_firstrow:SECRET:INT64}\"]\n}`, ``, testConf{groupThreshold: 4, batched: true, revealGroupCount: false}},\n\t{`select ta.groupby_int_0 from alice.tbl_0 as ta union select tb.groupby_int_0 from bob.tbl_0 as tb`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_2,},],attr:[sql:select any_value(ta.groupby_int_0) as expr_242 from alice.tbl_0 as ta group by ta.groupby_int_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,},],attr:[sql:select 'tb'.'groupby_int_0' from 'bob'.'tbl_0' as 'tb' group by 'tb'.'groupby_int_0';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"make_share:{in:[In:{t_2,},],out:[Out:{t_7,},],attr:[],party:[alice,bob,]}\"]\n3 [label=\"make_share:{in:[In:{t_4,},],out:[Out:{t_8,},],attr:[],party:[alice,bob,]}\"]\n4 [label=\"concat:{in:[In:{t_7,t_8,},],out:[Out:{t_5,},],attr:[axis:0,],party:[alice,bob,]}\"]\n5 [label=\"sort:{in:[In:{t_5,t_5,},Key:{t_5,},],out:[Out:{t_9,t_10,},],attr:[reverse:[false],],party:[alice,bob,]}\"]\n6 [label=\"oblivious_group_mark:{in:[Key:{t_9,},],out:[Group:{t_11,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"shuffle:{in:[In:{t_10,t_11,},],out:[Out:{t_12,t_13,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"make_public:{in:[In:{t_13,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"filter:{in:[Filter:{t_14,},In:{t_12,},],out:[Out:{t_6,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"make_private:{in:[In:{t_6,},],out:[Out:{t_15,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n11 [label=\"publish_result:{in:[In:{t_15,},],out:[Out:{t_16,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{groupby_int_0_firstrow:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_4:{groupby_int_0_firstrow:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_15:{groupby_int_0_firstrow_firstrow:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_7:{groupby_int_0_firstrow:SECRET:INT64}\"]\n3 -> 4 [label = \"t_8:{groupby_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_5:{groupby_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_5:{groupby_int_0_firstrow:SECRET:INT64}\"]\n4 -> 5 [label = \"t_5:{groupby_int_0_firstrow:SECRET:INT64}\"]\n5 -> 6 [label = \"t_9:{groupby_int_0_firstrow:SECRET:INT64}\"]\n5 -> 7 [label = \"t_10:{groupby_int_0_firstrow:SECRET:INT64}\"]\n6 -> 7 [label = \"t_11:{group_mark:SECRET:BOOL}\"]\n7 -> 8 [label = \"t_13:{group_mark:SECRET:BOOL}\"]\n7 -> 9 [label = \"t_12:{groupby_int_0_firstrow:SECRET:INT64}\"]\n8 -> 9 [label = \"t_14:{group_mark:PUBLIC:BOOL}\"]\n9 -> 10 [label = \"t_6:{groupby_int_0_firstrow_firstrow:SECRET:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 make_share_2 make_share_3 concat_4 sort_5 oblivious_group_mark_6 shuffle_7 make_public_8 filter_9 make_private_10 publish_result_11]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select plain_float_0 from (select plain_float_0 from alice.tbl_1 union all select plain_float_0 from alice.tbl_2) as tt group by plain_float_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_13,},],attr:[sql:select any_value(tt.expr_243) as plain_float_0 from ((select any_value(tbl_1.plain_float_0) as expr_243,count(1) as expr_244 from alice.tbl_1 group by tbl_1.plain_float_0) union all (select any_value(tbl_2.plain_float_0) as expr_243,count(1) as expr_244 from alice.tbl_2 group by tbl_2.plain_float_0)) as tt group by tt.expr_243 having count(tt.expr_244)>=4;,table_refs:[alice.tbl_1 alice.tbl_2],],party:[alice,]}\"]\n1 [label=\"publish_result:{in:[In:{t_13,},],out:[Out:{t_15,},],attr:[],party:[alice,]}\"]\n0 -> 1 [label = \"t_13:{plain_float_0_firstrow_firstrow:PRIVATE:FLOAT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 publish_result_1]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*), max(aggregate_int_0) from (select aggregate_int_0, groupby_int_0 from alice.tbl_0 union all select aggregate_int_0, groupby_int_0 from bob.tbl_1 union all select aggregate_int_0, groupby_int_0 from carol.tbl_2) as u`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_2,t_3,},],attr:[sql:select count(1) as expr_365,max(tbl_0.aggregate_int_0) as expr_366 from alice.tbl_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_5,t_6,},],attr:[sql:select count(1) as 'expr_365',max('tbl_1'.'aggregate_int_0') as 'expr_366' from 'bob'.'tbl_1';,table_refs:[bob.tbl_1],],party:[bob,]}\"]\n2 [label=\"run_sql:{in:[],out:[Out:{t_8,t_9,},],attr:[sql:select count(1) as expr_365,max(tbl_2.aggregate_int_0) as expr_366 from carol.tbl_2;,table_refs:[carol.tbl_2],],party:[carol,]}\"]\n3 [label=\"make_share:{in:[In:{t_2,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,carol,]}\"]\n4 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_15,},],attr:[],party:[alice,bob,carol,]}\"]\n5 [label=\"make_share:{in:[In:{t_8,},],out:[Out:{t_16,},],attr:[],party:[alice,bob,carol,]}\"]\n6 [label=\"concat:{in:[In:{t_14,t_15,t_16,},],out:[Out:{t_10,},],attr:[axis:0,],party:[alice,bob,carol,]}\"]\n7 [label=\"make_share:{in:[In:{t_3,},],out:[Out:{t_17,},],attr:[],party:[alice,bob,carol,]}\"]\n8 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_18,},],attr:[],party:[alice,bob,carol,]}\"]\n9 [label=\"make_share:{in:[In:{t_9,},],out:[Out:{t_19,},],attr:[],party:[alice,bob,carol,]}\"]\n10 [label=\"concat:{in:[In:{t_17,t_18,t_19,},],out:[Out:{t_11,},],attr:[axis:0,],party:[alice,bob,carol,]}\"]\n11 [label=\"make_private:{in:[In:{t_10,},],out:[Out:{t_20,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n12 [label=\"reduce[sum]:{in:[In:{t_20,},],out:[Out:{t_12,},],attr:[],party:[alice,]}\"]\n13 [label=\"reduce[max]:{in:[In:{t_11,},],out:[Out:{t_13,},],attr:[],party:[alice,bob,carol,]}\"]\n14 [label=\"make_private:{in:[In:{t_13,},],out:[Out:{t_21,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n15 [label=\"publish_result:{in:[In:{t_12,t_21,},],out:[Out:{t_22,t_23,},],attr:[],party:[alice,]}\"]\n0 -> 3 [label = \"t_2:{aggregate_int_0_count:PRIVATE:INT64}\"]\n0 -> 7 [label = \"t_3:{aggregate_int_0_max:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_5:{aggregate_int_0_count:PRIVATE:INT64}\"]\n1 -> 8 [label = \"t_6:{aggregate_int_0_max:PRIVATE:INT64}\"]\n10 -> 13 [label = \"t_11:{aggregate_int_0_max:SECRET:INT64}\"]\n11 -> 12 [label = \"t_20:{aggregate_int_0_count:PRIVATE:INT64}\"]\n12 -> 15 [label = \"t_12:{aggregate_int_0_count_count:PRIVATE:INT64}\"]\n13 -> 14 [label = \"t_13:{aggregate_int_0_max_max:SECRET:INT64}\"]\n14 -> 15 [label = \"t_21:{aggregate_int_0_max_max:PRIVATE:INT64}\"]\n2 -> 5 [label = \"t_8:{aggregate_int_0_count:PRIVATE:INT64}\"]\n2 -> 9 [label = \"t_9:{aggregate_int_0_max:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_14:{aggregate_int_0_count:SECRET:INT64}\"]\n4 -> 6 [label = \"t_15:{aggregate_int_0_count:SECRET:INT64}\"]\n5 -> 6 [label = \"t_16:{aggregate_int_0_count:SECRET:INT64}\"]\n6 -> 11 [label = \"t_10:{aggregate_int_0_count:SECRET:INT64}\"]\n7 -> 10 [label = \"t_17:{aggregate_int_0_max:SECRET:INT64}\"]\n8 -> 10 [label = \"t_18:{aggregate_int_0_max:SECRET:INT64}\"]\n9 -> 10 [label = \"t_19:{aggregate_int_0_max:SECRET:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 run_sql_2 make_share_3 make_share_4 make_share_5 concat_6 make_share_7 make_share_8 make_share_9 concat_10 make_private_11 reduce[sum]_12 reduce[max]_13 make_private_14 publish_result_15]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*), max(aggregate_int_0) from (select aggregate_int_0, groupby_int_0 from alice.tbl_0 union all select aggregate_int_0, groupby_int_0 from bob.tbl_1 union all select aggregate_int_0, groupby_int_0 from carol.tbl_2) as u group by groupby_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,t_5,},],attr:[sql:select count(1) as expr_365,max(tbl_0.aggregate_int_0) as expr_366,any_value(tbl_0.groupby_int_0) as expr_362 from alice.tbl_0 group by tbl_0.groupby_int_0;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_8,t_9,t_10,},],attr:[sql:select count(1) as 'expr_365',max('tbl_1'.'aggregate_int_0') as 'expr_366','tbl_1'.'groupby_int_0' from 'bob'.'tbl_1' group by 'tbl_1'.'groupby_int_0';,table_refs:[bob.tbl_1],],party:[bob,]}\"]\n2 [label=\"run_sql:{in:[],out:[Out:{t_13,t_14,t_15,},],attr:[sql:select count(1) as expr_365,max(tbl_2.aggregate_int_0) as expr_366,tbl_2.groupby_int_0 from carol.tbl_2 group by tbl_2.groupby_int_0;,table_refs:[carol.tbl_2],],party:[carol,]}\"]\n3 [label=\"make_share:{in:[In:{t_3,},],out:[Out:{t_26,},],attr:[],party:[alice,bob,carol,]}\"]\n4 [label=\"make_share:{in:[In:{t_8,},],out:[Out:{t_27,},],attr:[],party:[alice,bob,carol,]}\"]\n5 [label=\"make_share:{in:[In:{t_13,},],out:[Out:{t_28,},],attr:[],party:[alice,bob,carol,]}\"]\n6 [label=\"concat:{in:[In:{t_26,t_27,t_28,},],out:[Out:{t_16,},],attr:[axis:0,],party:[alice,bob,carol,]}\"]\n7 [label=\"make_share:{in:[In:{t_4,},],out:[Out:{t_29,},],attr:[],party:[alice,bob,carol,]}\"]\n8 [label=\"make_share:{in:[In:{t_9,},],out:[Out:{t_30,},],attr:[],party:[alice,bob,carol,]}\"]\n9 [label=\"make_share:{in:[In:{t_14,},],out:[Out:{t_31,},],attr:[],party:[alice,bob,carol,]}\"]\n10 [label=\"concat:{in:[In:{t_29,t_30,t_31,},],out:[Out:{t_17,},],attr:[axis:0,],party:[alice,bob,carol,]}\"]\n11 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_32,},],attr:[],party:[alice,bob,carol,]}\"]\n12 [label=\"make_share:{in:[In:{t_10,},],out:[Out:{t_33,},],attr:[],party:[alice,bob,carol,]}\"]\n13 [label=\"make_share:{in:[In:{t_15,},],out:[Out:{t_34,},],attr:[],party:[alice,bob,carol,]}\"]\n14 [label=\"concat:{in:[In:{t_32,t_33,t_34,},],out:[Out:{t_18,},],attr:[axis:0,],party:[alice,bob,carol,]}\"]\n15 [label=\"sort:{in:[In:{t_18,t_16,t_17,},Key:{t_18,},],out:[Out:{t_35,t_36,t_37,},],attr:[reverse:[false],],party:[alice,bob,carol,]}\"]\n16 [label=\"oblivious_group_mark:{in:[Key:{t_35,},],out:[Group:{t_38,},],attr:[],party:[alice,bob,carol,]}\"]\n17 [label=\"sum:{in:[Group:{t_38,},In:{t_36,},],out:[Out:{t_39,},],attr:[],party:[alice,bob,carol,]}\"]\n18 [label=\"max:{in:[Group:{t_38,},In:{t_37,},],out:[Out:{t_40,},],attr:[],party:[alice,bob,carol,]}\"]\n19 [label=\"shuffle:{in:[In:{t_39,t_40,t_38,},],out:[Out:{t_41,t_42,t_43,},],attr:[],party:[alice,bob,carol,]}\"]\n20 [label=\"make_public:{in:[In:{t_43,},],out:[Out:{t_44,},],attr:[],party:[alice,bob,carol,]}\"]\n21 [label=\"filter:{in:[Filter:{t_44,},In:{t_41,t_42,},],out:[Out:{t_19,t_20,},],attr:[],party:[alice,bob,carol,]}\"]\n22 [label=\"constant:{in:[],out:[Out:{t_21,},],attr:[scalar:4,to_status:1,],party:[alice,bob,carol,]}\"]\n23 [label=\"broadcast_to:{in:[In:{t_21,},ShapeRefTensor:{t_19,},],out:[Out:{t_22,},],attr:[],party:[alice,bob,carol,]}\"]\n24 [label=\"GreaterEqual:{in:[Left:{t_19,},Right:{t_22,},],out:[Out:{t_23,},],attr:[],party:[alice,bob,carol,]}\"]\n25 [label=\"make_public:{in:[In:{t_23,},],out:[Out:{t_45,},],attr:[],party:[alice,bob,carol,]}\"]\n26 [label=\"filter:{in:[Filter:{t_45,},In:{t_19,t_20,},],out:[Out:{t_24,t_25,},],attr:[],party:[alice,bob,carol,]}\"]\n27 [label=\"make_private:{in:[In:{t_24,},],out:[Out:{t_46,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n28 [label=\"make_private:{in:[In:{t_25,},],out:[Out:{t_47,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n29 [label=\"publish_result:{in:[In:{t_46,t_47,},],out:[Out:{t_48,t_49,},],attr:[],party:[alice,]}\"]\n0 -> 11 [label = \"t_5:{groupby_int_0_firstrow:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{simple_count_result:PRIVATE:INT64}\"]\n0 -> 7 [label = \"t_4:{aggregate_int_0_max:PRIVATE:INT64}\"]\n1 -> 12 [label = \"t_10:{groupby_int_0_firstrow:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_8:{simple_count_result:PRIVATE:INT64}\"]\n1 -> 8 [label = \"t_9:{aggregate_int_0_max:PRIVATE:INT64}\"]\n10 -> 15 [label = \"t_17:{aggregate_int_0_max:SECRET:INT64}\"]\n11 -> 14 [label = \"t_32:{groupby_int_0_firstrow:SECRET:INT64}\"]\n12 -> 14 [label = \"t_33:{groupby_int_0_firstrow:SECRET:INT64}\"]\n13 -> 14 [label = \"t_34:{groupby_int_0_firstrow:SECRET:INT64}\"]\n14 -> 15 [label = \"t_18:{groupby_int_0_firstrow:SECRET:INT64}\"]\n14 -> 15 [label = \"t_18:{groupby_int_0_firstrow:SECRET:INT64}\"]\n15 -> 16 [label = \"t_35:{groupby_int_0_firstrow:SECRET:INT64}\"]\n15 -> 17 [label = \"t_36:{simple_count_result:SECRET:INT64}\"]\n15 -> 18 [label = \"t_37:{aggregate_int_0_max:SECRET:INT64}\"]\n16 -> 17 [label = \"t_38:{group_mark:SECRET:BOOL}\"]\n16 -> 18 [label = \"t_38:{group_mark:SECRET:BOOL}\"]\n16 -> 19 [label = \"t_38:{group_mark:SECRET:BOOL}\"]\n17 -> 19 [label = \"t_39:{simple_count_result_count:SECRET:INT64}\"]\n18 -> 19 [label = \"t_40:{aggregate_int_0_max_max:SECRET:INT64}\"]\n19 -> 20 [label = \"t_43:{group_mark:SECRET:BOOL}\"]\n19 -> 21 [label = \"t_41:{simple_count_result_count:SECRET:INT64}\"]\n19 -> 21 [label = \"t_42:{aggregate_int_0_max_max:SECRET:INT64}\"]\n2 -> 13 [label = \"t_15:{groupby_int_0_firstrow:PRIVATE:INT64}\"]\n2 -> 5 [label = \"t_13:{simple_count_result:PRIVATE:INT64}\"]\n2 -> 9 [label = \"t_14:{aggregate_int_0_max:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_44:{group_mark:PUBLIC:BOOL}\"]\n21 -> 23 [label = \"t_19:{simple_count_result_count:SECRET:INT64}\"]\n21 -> 24 [label = \"t_19:{simple_count_result_count:SECRET:INT64}\"]\n21 -> 26 [label = \"t_19:{simple_count_result_count:SECRET:INT64}\"]\n21 -> 26 [label = \"t_20:{aggregate_int_0_max_max:SECRET:INT64}\"]\n22 -> 23 [label = \"t_21:{constant_data:PUBLIC:INT64}\"]\n23 -> 24 [label = \"t_22:{constant_data:PUBLIC:INT64}\"]\n24 -> 25 [label = \"t_23:{ge_out:SECRET:BOOL}\"]\n25 -> 26 [label = \"t_45:{ge_out:PUBLIC:BOOL}\"]\n26 -> 27 [label = \"t_24:{simple_count_result_count:SECRET:INT64}\"]\n26 -> 28 [label = \"t_25:{aggregate_int_0_max_max:SECRET:INT64}\"]\n27 -> 29 [label = \"t_46:{simple_count_result_count:PRIVATE:INT64}\"]\n28 -> 29 [label = \"t_47:{aggregate_int_0_max_max:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_26:{simple_count_result:SECRET:INT64}\"]\n4 -> 6 [label = \"t_27:{simple_count_result:SECRET:INT64}\"]\n5 -> 6 [label = \"t_28:{simple_count_result:SECRET:INT64}\"]\n6 -> 15 [label = \"t_16:{simple_count_result:SECRET:INT64}\"]\n7 -> 10 [label = \"t_29:{aggregate_int_0_max:SECRET:INT64}\"]\n8 -> 10 [label = \"t_30:{aggregate_int_0_max:SECRET:INT64}\"]\n9 -> 10 [label = \"t_31:{aggregate_int_0_max:SECRET:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 run_sql_2 make_share_3 make_share_4 make_share_5 concat_6 make_share_7 make_share_8 make_share_9 concat_10 make_share_11 make_share_12 make_share_13 concat_14 sort_15 oblivious_group_mark_16 sum_17 max_18 shuffle_19 make_public_20 filter_21 constant_22 broadcast_to_23 GreaterEqual_24 make_public_25 filter_26 make_private_27 make_private_28 publish_result_29]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select alice.plain_int_0 from alice.tbl_0 as alice join bob.tbl_0 as bob on alice.join_int_0 = bob.join_int_0 where alice.compare_int_0 Div bob.compare_int_0 > bob.compare_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,t_3,},],attr:[sql:select alice.plain_int_0,alice.join_int_0,alice.compare_int_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,t_5,},],attr:[sql:select 'bob'.'join_int_0','bob'.'compare_int_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_4,},],out:[LeftJoinIndex:{t_12,},RightJoinIndex:{t_13,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_3,},RowsIndexFilter:{t_12,},],out:[Out:{t_6,t_7,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_5,},RowsIndexFilter:{t_13,},],out:[Out:{t_8,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_7,},],out:[Out:{t_14,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_8,},],out:[Out:{t_15,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"IntDiv:{in:[Left:{t_14,},Right:{t_15,},],out:[Out:{t_9,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"Greater:{in:[Left:{t_9,},Right:{t_15,},],out:[Out:{t_10,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"make_private:{in:[In:{t_10,},],out:[Out:{t_16,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n10 [label=\"filter:{in:[Filter:{t_16,},In:{t_6,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n11 [label=\"publish_result:{in:[In:{t_11,},],out:[Out:{t_17,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_5:{compare_int_0:PRIVATE:INT64}\"]\n10 -> 11 [label = \"t_11:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_12:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_13:{right_index:PRIVATE:INT64}\"]\n3 -> 10 [label = \"t_6:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_7:{compare_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_8:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_14:{compare_int_0:SECRET:INT64}\"]\n6 -> 7 [label = \"t_15:{compare_int_0:SECRET:INT64}\"]\n6 -> 8 [label = \"t_15:{compare_int_0:SECRET:INT64}\"]\n7 -> 8 [label = \"t_9:{intdiv_out:SECRET:INT64}\"]\n8 -> 9 [label = \"t_10:{gt_out:SECRET:BOOL}\"]\n9 -> 10 [label = \"t_16:{gt_out:PRIVATE:BOOL}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 IntDiv_7 Greater_8 make_private_9 filter_10 publish_result_11]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select alice.groupby_string_0,bob.groupby_string_0, count(*) as cnt from alice.tbl_0 as alice join bob.tbl_0 as bob where alice.join_int_0=bob.join_int_0 group by alice.groupby_string_0, bob.groupby_string_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,},],attr:[sql:select alice.join_int_0,alice.groupby_string_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_3,t_4,},],attr:[sql:select 'bob'.'join_int_0','bob'.'groupby_string_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_3,},],out:[LeftJoinIndex:{t_16,},RightJoinIndex:{t_17,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_2,},RowsIndexFilter:{t_16,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,},RowsIndexFilter:{t_17,},],out:[Out:{t_6,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_5,},],out:[Out:{t_18,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_6,},],out:[Out:{t_19,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"sort:{in:[In:{t_18,t_19,t_18,t_19,},Key:{t_18,t_19,},],out:[Out:{t_20,t_21,t_22,t_23,},],attr:[reverse:[false false],],party:[alice,bob,]}\"]\n8 [label=\"oblivious_group_mark:{in:[Key:{t_20,t_21,},],out:[Group:{t_24,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"count:{in:[Group:{t_24,},In:{t_24,},],out:[Out:{t_25,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"shuffle:{in:[In:{t_25,t_22,t_23,t_24,},],out:[Out:{t_26,t_27,t_28,t_29,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"make_public:{in:[In:{t_29,},],out:[Out:{t_30,},],attr:[],party:[alice,bob,]}\"]\n12 [label=\"filter:{in:[Filter:{t_30,},In:{t_26,t_27,t_28,},],out:[Out:{t_7,t_8,t_9,},],attr:[],party:[alice,bob,]}\"]\n13 [label=\"constant:{in:[],out:[Out:{t_10,},],attr:[scalar:4,to_status:1,],party:[alice,bob,]}\"]\n14 [label=\"broadcast_to:{in:[In:{t_10,},ShapeRefTensor:{t_7,},],out:[Out:{t_11,},],attr:[],party:[alice,bob,]}\"]\n15 [label=\"GreaterEqual:{in:[Left:{t_7,},Right:{t_11,},],out:[Out:{t_12,},],attr:[],party:[alice,bob,]}\"]\n16 [label=\"make_public:{in:[In:{t_12,},],out:[Out:{t_31,},],attr:[],party:[alice,bob,]}\"]\n17 [label=\"filter:{in:[Filter:{t_31,},In:{t_7,t_8,t_9,},],out:[Out:{t_13,t_14,t_15,},],attr:[],party:[alice,bob,]}\"]\n18 [label=\"make_public:{in:[In:{t_14,},],out:[Out:{t_32,},],attr:[],party:[alice,bob,]}\"]\n19 [label=\"make_private:{in:[In:{t_32,},],out:[Out:{t_33,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n20 [label=\"make_public:{in:[In:{t_15,},],out:[Out:{t_34,},],attr:[],party:[alice,bob,]}\"]\n21 [label=\"make_private:{in:[In:{t_34,},],out:[Out:{t_35,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n22 [label=\"make_private:{in:[In:{t_13,},],out:[Out:{t_36,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n23 [label=\"publish_result:{in:[In:{t_33,t_35,t_36,},],out:[Out:{t_37,t_38,t_39,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{groupby_string_0:PRIVATE:STRING}\"]\n1 -> 2 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{groupby_string_0:PRIVATE:STRING}\"]\n10 -> 11 [label = \"t_29:{group_mark:SECRET:BOOL}\"]\n10 -> 12 [label = \"t_26:{aggregated_group_simple_count:SECRET:INT64}\"]\n10 -> 12 [label = \"t_27:{groupby_string_0:SECRET:STRING}\"]\n10 -> 12 [label = \"t_28:{groupby_string_0:SECRET:STRING}\"]\n11 -> 12 [label = \"t_30:{group_mark:PUBLIC:BOOL}\"]\n12 -> 14 [label = \"t_7:{simple_count_result:SECRET:INT64}\"]\n12 -> 15 [label = \"t_7:{simple_count_result:SECRET:INT64}\"]\n12 -> 17 [label = \"t_7:{simple_count_result:SECRET:INT64}\"]\n12 -> 17 [label = \"t_8:{groupby_string_0_firstrow:SECRET:STRING}\"]\n12 -> 17 [label = \"t_9:{groupby_string_0_firstrow:SECRET:STRING}\"]\n13 -> 14 [label = \"t_10:{constant_data:PUBLIC:INT64}\"]\n14 -> 15 [label = \"t_11:{constant_data:PUBLIC:INT64}\"]\n15 -> 16 [label = \"t_12:{ge_out:SECRET:BOOL}\"]\n16 -> 17 [label = \"t_31:{ge_out:PUBLIC:BOOL}\"]\n17 -> 18 [label = \"t_14:{groupby_string_0_firstrow:SECRET:STRING}\"]\n17 -> 20 [label = \"t_15:{groupby_string_0_firstrow:SECRET:STRING}\"]\n17 -> 22 [label = \"t_13:{simple_count_result:SECRET:INT64}\"]\n18 -> 19 [label = \"t_32:{groupby_string_0_firstrow:PUBLIC:STRING}\"]\n19 -> 23 [label = \"t_33:{groupby_string_0_firstrow:PRIVATE:STRING}\"]\n2 -> 3 [label = \"t_16:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_17:{right_index:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_34:{groupby_string_0_firstrow:PUBLIC:STRING}\"]\n21 -> 23 [label = \"t_35:{groupby_string_0_firstrow:PRIVATE:STRING}\"]\n22 -> 23 [label = \"t_36:{simple_count_result:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_5:{groupby_string_0:PRIVATE:STRING}\"]\n4 -> 6 [label = \"t_6:{groupby_string_0:PRIVATE:STRING}\"]\n5 -> 7 [label = \"t_18:{groupby_string_0:SECRET:STRING}\"]\n5 -> 7 [label = \"t_18:{groupby_string_0:SECRET:STRING}\"]\n5 -> 7 [label = \"t_18:{groupby_string_0:SECRET:STRING}\"]\n6 -> 7 [label = \"t_19:{groupby_string_0:SECRET:STRING}\"]\n6 -> 7 [label = \"t_19:{groupby_string_0:SECRET:STRING}\"]\n6 -> 7 [label = \"t_19:{groupby_string_0:SECRET:STRING}\"]\n7 -> 10 [label = \"t_22:{groupby_string_0:SECRET:STRING}\"]\n7 -> 10 [label = \"t_23:{groupby_string_0:SECRET:STRING}\"]\n7 -> 8 [label = \"t_20:{groupby_string_0:SECRET:STRING}\"]\n7 -> 8 [label = \"t_21:{groupby_string_0:SECRET:STRING}\"]\n8 -> 10 [label = \"t_24:{group_mark:SECRET:BOOL}\"]\n8 -> 9 [label = \"t_24:{group_mark:SECRET:BOOL}\"]\n8 -> 9 [label = \"t_24:{group_mark:SECRET:BOOL}\"]\n9 -> 10 [label = \"t_25:{aggregated_group_simple_count:SECRET:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 make_share_5 make_share_6 sort_7 oblivious_group_mark_8 count_9 shuffle_10 make_public_11 filter_12 constant_13 broadcast_to_14 GreaterEqual_15 make_public_16 filter_17 make_public_18 make_private_19 make_public_20 make_private_21 make_private_22 publish_result_23]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select case when alice.compare_int_0 > bob.compare_int_0 then alice.plain_int_0 else bob.plain_int_0 end as case_when1, case when bob.compare_int_0 > carol.compare_int_0 then 1 else 0 end as case_when2 from alice.tbl_0 as alice, bob.tbl_0 as bob, carol.tbl_0 as carol where alice.join_int_0 = bob.join_int_0 and bob.join_int_0 = carol.join_int_0;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,t_3,},],attr:[sql:select alice.plain_int_0,alice.join_int_0,alice.compare_int_0 from alice.tbl_0 as alice;,table_refs:[alice.tbl_0],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,t_5,t_6,},],attr:[sql:select 'bob'.'plain_int_0','bob'.'join_int_0','bob'.'compare_int_0' from 'bob'.'tbl_0' as 'bob';,table_refs:[bob.tbl_0],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_2,},Right:{t_5,},],out:[LeftJoinIndex:{t_27,},RightJoinIndex:{t_28,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_3,},RowsIndexFilter:{t_27,},],out:[Out:{t_7,t_8,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,t_5,t_6,},RowsIndexFilter:{t_28,},],out:[Out:{t_9,t_10,t_11,},],attr:[],party:[bob,]}\"]\n5 [label=\"run_sql:{in:[],out:[Out:{t_12,t_13,},],attr:[sql:select carol.join_int_0,carol.compare_int_0 from carol.tbl_0 as carol;,table_refs:[carol.tbl_0],],party:[carol,]}\"]\n6 [label=\"psi_join:{in:[Left:{t_10,},Right:{t_12,},],out:[LeftJoinIndex:{t_29,},RightJoinIndex:{t_30,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n7 [label=\"copy:{in:[In:{t_29,},],out:[Out:{t_31,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter_by_index:{in:[Data:{t_7,t_8,},RowsIndexFilter:{t_31,},],out:[Out:{t_14,t_15,},],attr:[],party:[alice,]}\"]\n9 [label=\"filter_by_index:{in:[Data:{t_9,t_11,},RowsIndexFilter:{t_29,},],out:[Out:{t_16,t_17,},],attr:[],party:[bob,]}\"]\n10 [label=\"filter_by_index:{in:[Data:{t_13,},RowsIndexFilter:{t_30,},],out:[Out:{t_18,},],attr:[],party:[carol,]}\"]\n11 [label=\"make_share:{in:[In:{t_15,},],out:[Out:{t_32,},],attr:[],party:[alice,bob,carol,]}\"]\n12 [label=\"make_share:{in:[In:{t_17,},],out:[Out:{t_33,},],attr:[],party:[alice,bob,carol,]}\"]\n13 [label=\"Greater:{in:[Left:{t_32,},Right:{t_33,},],out:[Out:{t_19,},],attr:[],party:[alice,bob,carol,]}\"]\n14 [label=\"make_public:{in:[In:{t_14,},],out:[Out:{t_34,},],attr:[],party:[alice,bob,carol,]}\"]\n15 [label=\"make_public:{in:[In:{t_16,},],out:[Out:{t_35,},],attr:[],party:[alice,bob,carol,]}\"]\n16 [label=\"case_when:{in:[Condition:{t_19,},Value:{t_34,},ValueElse:{t_35,},],out:[Out:{t_20,},],attr:[],party:[alice,bob,carol,]}\"]\n17 [label=\"make_share:{in:[In:{t_18,},],out:[Out:{t_36,},],attr:[],party:[alice,bob,carol,]}\"]\n18 [label=\"Greater:{in:[Left:{t_33,},Right:{t_36,},],out:[Out:{t_21,},],attr:[],party:[alice,bob,carol,]}\"]\n19 [label=\"constant:{in:[],out:[Out:{t_22,},],attr:[scalar:1,to_status:1,],party:[alice,bob,carol,]}\"]\n20 [label=\"constant:{in:[],out:[Out:{t_23,},],attr:[scalar:0,to_status:1,],party:[alice,bob,carol,]}\"]\n21 [label=\"broadcast_to:{in:[In:{t_22,t_23,},ShapeRefTensor:{t_21,},],out:[Out:{t_24,t_25,},],attr:[],party:[alice,bob,carol,]}\"]\n22 [label=\"case_when:{in:[Condition:{t_21,},Value:{t_24,},ValueElse:{t_25,},],out:[Out:{t_26,},],attr:[],party:[alice,bob,carol,]}\"]\n23 [label=\"make_private:{in:[In:{t_20,},],out:[Out:{t_37,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n24 [label=\"make_private:{in:[In:{t_26,},],out:[Out:{t_38,},],attr:[reveal_to:alice,],party:[alice,bob,carol,]}\"]\n25 [label=\"publish_result:{in:[In:{t_37,t_38,},],out:[Out:{t_39,t_40,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_2:{join_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{compare_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_5:{join_int_0:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_6:{compare_int_0:PRIVATE:INT64}\"]\n10 -> 17 [label = \"t_18:{compare_int_0:PRIVATE:INT64}\"]\n11 -> 13 [label = \"t_32:{compare_int_0:SECRET:INT64}\"]\n12 -> 13 [label = \"t_33:{compare_int_0:SECRET:INT64}\"]\n12 -> 18 [label = \"t_33:{compare_int_0:SECRET:INT64}\"]\n13 -> 16 [label = \"t_19:{gt_out:SECRET:BOOL}\"]\n14 -> 16 [label = \"t_34:{plain_int_0:PUBLIC:INT64}\"]\n15 -> 16 [label = \"t_35:{plain_int_0:PUBLIC:INT64}\"]\n16 -> 23 [label = \"t_20:{case_out:SECRET:INT64}\"]\n17 -> 18 [label = \"t_36:{compare_int_0:SECRET:INT64}\"]\n18 -> 21 [label = \"t_21:{gt_out:SECRET:BOOL}\"]\n18 -> 22 [label = \"t_21:{gt_out:SECRET:BOOL}\"]\n19 -> 21 [label = \"t_22:{constant_data:PUBLIC:INT64}\"]\n2 -> 3 [label = \"t_27:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_28:{right_index:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_23:{constant_data:PUBLIC:INT64}\"]\n21 -> 22 [label = \"t_24:{constant_data:PUBLIC:INT64}\"]\n21 -> 22 [label = \"t_25:{constant_data:PUBLIC:INT64}\"]\n22 -> 24 [label = \"t_26:{case_out:SECRET:INT64}\"]\n23 -> 25 [label = \"t_37:{case_out:PRIVATE:INT64}\"]\n24 -> 25 [label = \"t_38:{case_out:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_8:{compare_int_0:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_10:{join_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_11:{compare_int_0:PRIVATE:INT64}\"]\n4 -> 9 [label = \"t_9:{plain_int_0:PRIVATE:INT64}\"]\n5 -> 10 [label = \"t_13:{compare_int_0:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_12:{join_int_0:PRIVATE:INT64}\"]\n6 -> 10 [label = \"t_30:{right_index:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_29:{left_index:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_29:{left_index:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_31:{left_index:PRIVATE:INT64}\"]\n8 -> 11 [label = \"t_15:{compare_int_0:PRIVATE:INT64}\"]\n8 -> 14 [label = \"t_14:{plain_int_0:PRIVATE:INT64}\"]\n9 -> 12 [label = \"t_17:{compare_int_0:PRIVATE:INT64}\"]\n9 -> 15 [label = \"t_16:{plain_int_0:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 run_sql_5 psi_join_6 copy_7 filter_by_index_8 filter_by_index_9 filter_by_index_10 make_share_11 make_share_12 Greater_13 make_public_14 make_public_15 case_when_16 make_share_17 Greater_18 constant_19 constant_20 broadcast_to_21 case_when_22 make_private_23 make_private_24 publish_result_25]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select alice.groupby_int_0, alice.GROUPBY_int_1, bob.join_string_0, bob.JOIN_STRING_0, carol.COMPARE_float_0 > 0, carol.compare_float_1 > 0 from alice.UPPER_table as alice, bob.UPPER_table as bob, carol.UPPER_table as carol where alice.join_string_0 = bob.JOIN_string_0 and bob.join_string_1 = carol.JOIN_string_1;`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,t_2,t_3,},],attr:[sql:select alice.GROUPBY_int_0,alice.groupby_int_1,alice.JOIN_string_0 from alice.UPPER_table as alice;,table_refs:[alice.UPPER_table],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,t_5,},],attr:[sql:select 'bob'.'JOIN_string_0','bob'.'join_string_1' from 'bob'.'UPPER_table' as 'bob';,table_refs:[bob.UPPER_table],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_3,},Right:{t_4,},],out:[LeftJoinIndex:{t_24,},RightJoinIndex:{t_25,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,t_2,},RowsIndexFilter:{t_24,},],out:[Out:{t_6,t_7,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,t_5,},RowsIndexFilter:{t_25,},],out:[Out:{t_8,t_9,},],attr:[],party:[bob,]}\"]\n5 [label=\"run_sql:{in:[],out:[Out:{t_10,t_11,t_12,},],attr:[sql:select carol.join_string_1,carol.COMPARE_float_0,carol.compare_float_1 from carol.UPPER_table as carol;,table_refs:[carol.UPPER_table],],party:[carol,]}\"]\n6 [label=\"psi_join:{in:[Left:{t_9,},Right:{t_10,},],out:[LeftJoinIndex:{t_26,},RightJoinIndex:{t_27,},],attr:[input_party_codes:[bob carol],join_type:0,psi_algorithm:0,],party:[bob,carol,]}\"]\n7 [label=\"copy:{in:[In:{t_26,},],out:[Out:{t_28,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"filter_by_index:{in:[Data:{t_6,t_7,},RowsIndexFilter:{t_28,},],out:[Out:{t_13,t_14,},],attr:[],party:[alice,]}\"]\n9 [label=\"filter_by_index:{in:[Data:{t_8,},RowsIndexFilter:{t_26,},],out:[Out:{t_15,},],attr:[],party:[bob,]}\"]\n10 [label=\"filter_by_index:{in:[Data:{t_11,t_12,},RowsIndexFilter:{t_27,},],out:[Out:{t_16,t_17,},],attr:[],party:[carol,]}\"]\n11 [label=\"constant:{in:[],out:[Out:{t_18,},],attr:[scalar:0,to_status:1,],party:[alice,bob,carol,]}\"]\n12 [label=\"broadcast_to:{in:[In:{t_18,},ShapeRefTensor:{t_16,},],out:[Out:{t_19,},],attr:[],party:[carol,]}\"]\n13 [label=\"Greater:{in:[Left:{t_16,},Right:{t_19,},],out:[Out:{t_20,},],attr:[],party:[carol,]}\"]\n14 [label=\"constant:{in:[],out:[Out:{t_21,},],attr:[scalar:0,to_status:1,],party:[alice,bob,carol,]}\"]\n15 [label=\"broadcast_to:{in:[In:{t_21,},ShapeRefTensor:{t_17,},],out:[Out:{t_22,},],attr:[],party:[carol,]}\"]\n16 [label=\"Greater:{in:[Left:{t_17,},Right:{t_22,},],out:[Out:{t_23,},],attr:[],party:[carol,]}\"]\n17 [label=\"copy:{in:[In:{t_15,},],out:[Out:{t_29,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n18 [label=\"copy:{in:[In:{t_20,},],out:[Out:{t_30,},],attr:[input_party_codes:carol,output_party_codes:alice,],party:[carol,alice,]}\"]\n19 [label=\"copy:{in:[In:{t_23,},],out:[Out:{t_31,},],attr:[input_party_codes:carol,output_party_codes:alice,],party:[carol,alice,]}\"]\n20 [label=\"publish_result:{in:[In:{t_13,t_14,t_29,t_29,t_30,t_31,},],out:[Out:{t_32,t_33,t_34,t_35,t_36,t_37,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_3:{JOIN_string_0:PRIVATE:STRING}\"]\n0 -> 3 [label = \"t_1:{GROUPBY_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{groupby_int_1:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_4:{JOIN_string_0:PRIVATE:STRING}\"]\n1 -> 4 [label = \"t_4:{JOIN_string_0:PRIVATE:STRING}\"]\n1 -> 4 [label = \"t_5:{join_string_1:PRIVATE:STRING}\"]\n10 -> 12 [label = \"t_16:{COMPARE_float_0:PRIVATE:FLOAT64}\"]\n10 -> 13 [label = \"t_16:{COMPARE_float_0:PRIVATE:FLOAT64}\"]\n10 -> 15 [label = \"t_17:{compare_float_1:PRIVATE:FLOAT64}\"]\n10 -> 16 [label = \"t_17:{compare_float_1:PRIVATE:FLOAT64}\"]\n11 -> 12 [label = \"t_18:{constant_data:PUBLIC:INT64}\"]\n12 -> 13 [label = \"t_19:{constant_data:PRIVATE:INT64}\"]\n13 -> 18 [label = \"t_20:{gt_out:PRIVATE:BOOL}\"]\n14 -> 15 [label = \"t_21:{constant_data:PUBLIC:INT64}\"]\n15 -> 16 [label = \"t_22:{constant_data:PRIVATE:INT64}\"]\n16 -> 19 [label = \"t_23:{gt_out:PRIVATE:BOOL}\"]\n17 -> 20 [label = \"t_29:{JOIN_string_0:PRIVATE:STRING}\"]\n17 -> 20 [label = \"t_29:{JOIN_string_0:PRIVATE:STRING}\"]\n18 -> 20 [label = \"t_30:{gt_out:PRIVATE:BOOL}\"]\n19 -> 20 [label = \"t_31:{gt_out:PRIVATE:BOOL}\"]\n2 -> 3 [label = \"t_24:{left_index:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_25:{right_index:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_6:{GROUPBY_int_0:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_7:{groupby_int_1:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_9:{join_string_1:PRIVATE:STRING}\"]\n4 -> 9 [label = \"t_8:{JOIN_string_0:PRIVATE:STRING}\"]\n5 -> 10 [label = \"t_11:{COMPARE_float_0:PRIVATE:FLOAT64}\"]\n5 -> 10 [label = \"t_12:{compare_float_1:PRIVATE:FLOAT64}\"]\n5 -> 6 [label = \"t_10:{join_string_1:PRIVATE:STRING}\"]\n6 -> 10 [label = \"t_27:{right_index:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_26:{left_index:PRIVATE:INT64}\"]\n6 -> 9 [label = \"t_26:{left_index:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_28:{left_index:PRIVATE:INT64}\"]\n8 -> 20 [label = \"t_13:{GROUPBY_int_0:PRIVATE:INT64}\"]\n8 -> 20 [label = \"t_14:{groupby_int_1:PRIVATE:INT64}\"]\n9 -> 17 [label = \"t_15:{JOIN_string_0:PRIVATE:STRING}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 filter_by_index_4 run_sql_5 psi_join_6 copy_7 filter_by_index_8 filter_by_index_9 filter_by_index_10 constant_11 broadcast_to_12 Greater_13 constant_14 broadcast_to_15 Greater_16 copy_17 copy_18 copy_19 publish_result_20]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select ta.join_int_0, tb.plain_int_0 from alice.tbl_1 as ta inner join bob.tbl_1 as tb on ta.join_int_0=tb.join_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select ta.join_int_0 from alice.tbl_1 as ta;,table_refs:[alice.tbl_1],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_2,t_3,},],attr:[sql:select 'tb'.'plain_int_0','tb'.'join_int_0' from 'bob'.'tbl_1' as 'tb';,table_refs:[bob.tbl_1],],party:[bob,]}\"]\n2 [label=\"bucket:{in:[In:{t_1,},Key:{t_1,},],out:[Out:{t_6,},],attr:[input_party_codes:[alice],],party:[alice,]}\"]\n3 [label=\"bucket:{in:[In:{t_3,t_2,},Key:{t_3,},],out:[Out:{t_7,t_8,},],attr:[input_party_codes:[bob],],party:[bob,]}\"]\n4 [label=\"psi_join:{in:[Left:{t_6,},Right:{t_7,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{t_10,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n5 [label=\"filter_by_index:{in:[Data:{t_6,},RowsIndexFilter:{t_9,},],out:[Out:{t_4,},],attr:[],party:[alice,]}\"]\n6 [label=\"filter_by_index:{in:[Data:{t_8,},RowsIndexFilter:{t_10,},],out:[Out:{t_5,},],attr:[],party:[bob,]}\"]\n7 [label=\"copy:{in:[In:{t_5,},],out:[Out:{t_11,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"publish_result:{in:[In:{t_4,t_11,},],out:[Out:{t_12,t_13,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n0 -> 2 [label = \"t_1:{join_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_2:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_3:{join_int_0:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_6:{join_int_0:PRIVATE:INT64}\"]\n2 -> 5 [label = \"t_6:{join_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_7:{join_int_0:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_8:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_10:{right_index:PRIVATE:INT64}\"]\n5 -> 8 [label = \"t_4:{join_int_0:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_11:{plain_int_0:PRIVATE:INT64}\"]\n}`, `Batched pipeline with 3 nodes`, testConf{groupThreshold: 4, batched: true, revealGroupCount: false}},\n\t{`select count(*) from alice.tbl_1 as t1 join bob.tbl_1 as t3 join bob.tbl_2 as t4 where t1.plain_int_0 = t3.plain_int_0 and t3.plain_int_0 = t4.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select t1.plain_int_0 from alice.tbl_1 as t1;,table_refs:[alice.tbl_1],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_4,},],attr:[sql:select 't3'.'plain_int_0' from 'bob'.'tbl_1' as 't3' join 'bob'.'tbl_2' as 't4' on 't3'.'plain_int_0'='t4'.'plain_int_0';,table_refs:[bob.tbl_1 bob.tbl_2],],party:[bob,]}\"]\n2 [label=\"bucket:{in:[In:{t_1,},Key:{t_1,},],out:[Out:{t_7,},],attr:[input_party_codes:[alice],],party:[alice,]}\"]\n3 [label=\"bucket:{in:[In:{t_4,},Key:{t_4,},],out:[Out:{t_8,},],attr:[input_party_codes:[bob],],party:[bob,]}\"]\n4 [label=\"psi_join:{in:[Left:{t_7,},Right:{t_8,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n5 [label=\"filter_by_index:{in:[Data:{t_7,},RowsIndexFilter:{t_9,},],out:[Out:{t_5,},],attr:[],party:[alice,]}\"]\n6 [label=\"shape:{in:[In:{t_5,},],out:[Out:{t_6,},],attr:[axis:0,],party:[alice,]}\"]\n7 [label=\"publish_result:{in:[In:{t_6,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_4:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 5 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_8:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n5 -> 6 [label = \"t_5:{plain_int_0:PRIVATE:INT64}\"]\n6 -> 7 [label = \"t_6:{plain_int_0_count:PRIVATE:INT64}\"]\n}`, `Batched pipeline with 1 nodes`, testConf{groupThreshold: 4, batched: true, revealGroupCount: false}},\n\t{`select count(*) from alice.tbl_1 as t1 join bob.tbl_1 as t2 join alice.tbl_2 as t3 join bob.tbl_2 as t4 where t1.plain_int_0 = t3.plain_int_0 and t2.plain_int_0 = t4.plain_int_0 and t2.plain_int_0 = t3.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select t3.plain_int_0 from alice.tbl_1 as t1 join alice.tbl_2 as t3 on t1.plain_int_0=t3.plain_int_0;,table_refs:[alice.tbl_1 alice.tbl_2],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_6,},],attr:[sql:select 't2'.'plain_int_0' from 'bob'.'tbl_1' as 't2' join 'bob'.'tbl_2' as 't4' on 't2'.'plain_int_0'='t4'.'plain_int_0';,table_refs:[bob.tbl_1 bob.tbl_2],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_3,},Right:{t_6,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_3,},RowsIndexFilter:{t_9,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n4 [label=\"shape:{in:[In:{t_7,},],out:[Out:{t_8,},],attr:[axis:0,],party:[alice,]}\"]\n5 [label=\"publish_result:{in:[In:{t_8,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_6:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_8:{plain_int_0_count:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 shape_4 publish_result_5]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*) from alice.tbl_1 as t1 join alice.tbl_2 as t2 join bob.tbl_1 as t3 join bob.tbl_2 as t4 where t1.plain_int_0 = t2.plain_int_0 and t2.plain_int_0 = t3.plain_int_0 and t3.plain_int_0 = t4.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_3,},],attr:[sql:select t2.plain_int_0 from alice.tbl_1 as t1 join alice.tbl_2 as t2 on t1.plain_int_0=t2.plain_int_0;,table_refs:[alice.tbl_1 alice.tbl_2],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_6,},],attr:[sql:select 't3'.'plain_int_0' from 'bob'.'tbl_1' as 't3' join 'bob'.'tbl_2' as 't4' on 't3'.'plain_int_0'='t4'.'plain_int_0';,table_refs:[bob.tbl_1 bob.tbl_2],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_3,},Right:{t_6,},],out:[LeftJoinIndex:{t_9,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_3,},RowsIndexFilter:{t_9,},],out:[Out:{t_7,},],attr:[],party:[alice,]}\"]\n4 [label=\"shape:{in:[In:{t_7,},],out:[Out:{t_8,},],attr:[axis:0,],party:[alice,]}\"]\n5 [label=\"publish_result:{in:[In:{t_8,},],out:[Out:{t_10,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_6:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_9:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_8:{plain_int_0_count:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 shape_4 publish_result_5]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*) from alice.tbl_1 as t1 join bob.tbl_0 as t2 join bob.tbl_1 as t3 join bob.tbl_2 as t4 where t1.plain_int_0 = t2.plain_int_0 and t2.plain_int_0 = t3.plain_int_0 and t3.plain_int_0 = t4.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select t1.plain_int_0 from alice.tbl_1 as t1;,table_refs:[alice.tbl_1],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_7,},],attr:[sql:select 't2'.'plain_int_0' from (select 't2'.'plain_int_0','t3'.'plain_int_0' from ('bob'.'tbl_0' as 't2' join 'bob'.'tbl_1' as 't3' on 't2'.'plain_int_0'='t3'.'plain_int_0')) as 't2' join 'bob'.'tbl_2' as 't4' on 't2'.'plain_int_0'='t4'.'plain_int_0';,table_refs:[bob.tbl_0 bob.tbl_1 bob.tbl_2],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_7,},],out:[LeftJoinIndex:{t_10,},RightJoinIndex:{},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_1,},RowsIndexFilter:{t_10,},],out:[Out:{t_8,},],attr:[],party:[alice,]}\"]\n4 [label=\"shape:{in:[In:{t_8,},],out:[Out:{t_9,},],attr:[axis:0,],party:[alice,]}\"]\n5 [label=\"publish_result:{in:[In:{t_9,},],out:[Out:{t_11,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_7:{plain_int_0:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_10:{left_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_8:{plain_int_0:PRIVATE:INT64}\"]\n4 -> 5 [label = \"t_9:{plain_int_0_count:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 shape_4 publish_result_5]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n\t{`select count(*), sum(add_res) from alice.tbl_1 as t1, (select plain_int_0, plain_int_0+1 as add_res from bob.tbl_0) as t2, bob.tbl_1 as t3, bob.tbl_2 as t4 where t1.plain_int_0 = t2.plain_int_0 and t2.plain_int_0 = t3.plain_int_0 and t3.plain_int_0 = t4.plain_int_0`, `digraph G {\n0 [label=\"run_sql:{in:[],out:[Out:{t_1,},],attr:[sql:select t1.plain_int_0 from alice.tbl_1 as t1;,table_refs:[alice.tbl_1],],party:[alice,]}\"]\n1 [label=\"run_sql:{in:[],out:[Out:{t_10,t_11,},],attr:[sql:select 't2'.'plain_int_0','t2'.'add_res' from (select 't2'.'plain_int_0','t2'.'add_res','t3'.'plain_int_0' from ((select 'tbl_0'.'plain_int_0','tbl_0'.'plain_int_0'+1 as 'add_res' from 'bob'.'tbl_0') as 't2' join 'bob'.'tbl_1' as 't3' on 't2'.'plain_int_0'='t3'.'plain_int_0')) as 't2' join 'bob'.'tbl_2' as 't4' on 't2'.'plain_int_0'='t4'.'plain_int_0';,table_refs:[bob.tbl_0 bob.tbl_1 bob.tbl_2],],party:[bob,]}\"]\n2 [label=\"psi_join:{in:[Left:{t_1,},Right:{t_10,},],out:[LeftJoinIndex:{},RightJoinIndex:{t_15,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_11,},RowsIndexFilter:{t_15,},],out:[Out:{t_12,},],attr:[],party:[bob,]}\"]\n4 [label=\"shape:{in:[In:{t_12,},],out:[Out:{t_13,},],attr:[axis:0,],party:[bob,]}\"]\n5 [label=\"reduce[sum]:{in:[In:{t_12,},],out:[Out:{t_14,},],attr:[],party:[bob,]}\"]\n6 [label=\"copy:{in:[In:{t_13,},],out:[Out:{t_16,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n7 [label=\"copy:{in:[In:{t_14,},],out:[Out:{t_17,},],attr:[input_party_codes:bob,output_party_codes:alice,],party:[bob,alice,]}\"]\n8 [label=\"publish_result:{in:[In:{t_16,t_17,},],out:[Out:{t_18,t_19,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_1:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_10:{plain_int_0:PRIVATE:INT64}\"]\n1 -> 3 [label = \"t_11:{plus_out:PRIVATE:INT64}\"]\n2 -> 3 [label = \"t_15:{right_index:PRIVATE:INT64}\"]\n3 -> 4 [label = \"t_12:{plus_out:PRIVATE:INT64}\"]\n3 -> 5 [label = \"t_12:{plus_out:PRIVATE:INT64}\"]\n4 -> 6 [label = \"t_13:{plus_out_count:PRIVATE:INT64}\"]\n5 -> 7 [label = \"t_14:{plus_out_sum:PRIVATE:INT64}\"]\n6 -> 8 [label = \"t_16:{plus_out_count:PRIVATE:INT64}\"]\n7 -> 8 [label = \"t_17:{plus_out_sum:PRIVATE:INT64}\"]\n}`, `\npipeline 0 {\nBatched: false\nnode: [run_sql_0 run_sql_1 psi_join_2 filter_by_index_3 shape_4 reduce[sum]_5 copy_6 copy_7 publish_result_8]\nInputs: []\nOutputs: []\n}\n`, testConf{groupThreshold: 4, batched: false, revealGroupCount: false}},\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/update_column_security.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc (n *OperatorDataSource) InitCSR(csr ColumnSecurityRelaxation, applicableColNames []string) error {\n\t// Convert applicableColNames to lowercase and store in map for O(1) lookup\n\tapplicableColMap := make(map[string]struct{}, len(applicableColNames))\n\tfor _, name := range applicableColNames {\n\t\tapplicableColMap[strings.ToLower(name)] = struct{}{}\n\t}\n\n\tfor idx, originName := range n.originNames {\n\t\tif _, exists := applicableColMap[strings.ToLower(originName)]; exists {\n\t\t\tcsr.MakeApplicable(n.outputs[idx])\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorDataSource) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\t// Nothing to do here\n\treturn nil\n}\n\nfunc (n *OperatorRunSQL) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\t// Nothing to do here\n\treturn nil\n}\n\nfunc (n *OperatorConstant) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\t// Nothing to do here\n\treturn nil\n}\n\nfunc (n *OperatorEQJoin) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\t// TODO question shold we consider keys' column security relaxation or not\n\tfor idx, payload := range n.leftPayloads {\n\t\tif csr.ApplicableTo(payload, tvc) {\n\t\t\tcsr.MakeApplicable(n.leftOutputs[idx])\n\t\t}\n\t}\n\tfor idx, payload := range n.rightPayloads {\n\t\tif csr.ApplicableTo(payload, tvc) {\n\t\t\tcsr.MakeApplicable(n.rightOutputs[idx])\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorCrossJoin) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\tfor idx, input := range n.leftInputs {\n\t\tif csr.ApplicableTo(input, tvc) {\n\t\t\tcsr.MakeApplicable(n.leftOutputs[idx])\n\t\t}\n\t}\n\tfor idx, input := range n.rightInputs {\n\t\tif csr.ApplicableTo(input, tvc) {\n\t\t\tcsr.MakeApplicable(n.rightOutputs[idx])\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorLimit) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\tfor idx, input := range n.inputs {\n\t\tif csr.ApplicableTo(input, tvc) {\n\t\t\tcsr.MakeApplicable(n.outputs[idx])\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorFilter) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\tif !csr.ApplicableTo(n.mask, tvc) {\n\t\treturn nil\n\t}\n\tfor idx, input := range n.inputs {\n\t\tif csr.ApplicableTo(input, tvc) {\n\t\t\tcsr.MakeApplicable(n.outputs[idx])\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorBroadcastTo) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\tif !csr.ApplicableTo(n.shapeRef, tvc) {\n\t\treturn nil\n\t}\n\tfor idx, input := range n.scalars {\n\t\tif csr.ApplicableTo(input, tvc) {\n\t\t\tcsr.MakeApplicable(n.outputs[idx])\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorConcat) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\tif csr.AllApplicable(n.inputs, tvc) {\n\t\tcsr.MakeApplicable(n.output)\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorSort) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\t// questtion: should we consider sort keys' column security relaxation here?\n\tif !csr.AllApplicable(n.sortKeys, tvc) {\n\t\treturn nil\n\t}\n\tfor idx, input := range n.payloads {\n\t\tif csr.ApplicableTo(input, tvc) {\n\t\t\tcsr.MakeApplicable(n.outputs[idx])\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorReduce) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\tif csr.ApplicableTo(n.input, tvc) {\n\t\tcsr.MakeApplicable(n.output)\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorGroupAgg) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\tif !csr.AllApplicable(n.groupKeys, tvc) {\n\t\treturn nil\n\t}\n\n\tfor idx, input := range n.aggArgs {\n\t\tif csr.ApplicableTo(input, tvc) {\n\t\t\tcsr.MakeApplicable(n.argFuncOutputs[idx])\n\t\t}\n\t}\n\tfor _, output := range n.simpleCountOutputs {\n\t\tcsr.MakeApplicable(output)\n\t}\n\n\treturn nil\n}\n\nfunc (n *OperatorWindow) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\tif !csr.AllApplicable(n.partitionKeys, tvc) {\n\t\treturn nil\n\t}\n\tif !csr.AllApplicable(n.orderKeys, tvc) {\n\t\treturn nil\n\t}\n\tcsr.MakeApplicable(n.funcOutput)\n\tfor idx, input := range n.payloads {\n\t\tif csr.ApplicableTo(input, tvc) {\n\t\t\tcsr.MakeApplicable(n.payloadOutputs[idx])\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorIn) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\tif !csr.ApplicableTo(n.left, tvc) || !csr.ApplicableTo(n.right, tvc) {\n\t\treturn nil\n\t}\n\tcsr.MakeApplicable(n.output)\n\treturn nil\n}\n\nfunc (n *OperatorFunction) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\tif !csr.AllApplicable(n.inputs, tvc) {\n\t\treturn nil\n\t}\n\tcsr.MakeApplicable(n.output)\n\treturn nil\n}\n\nfunc (n *OperatorResult) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\treturn fmt.Errorf(\"OperatorResult's InferCSR should not be called\")\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/update_column_security_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestInferCSRDataSource(t *testing.T) {\n\t// Setup test data\n\tnode := &OperatorDataSource{\n\t\toriginNames: []string{\"col1\", \"col2\", \"col3\"},\n\t\toutputs: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t\t{ID: 3},\n\t\t},\n\t}\n\n\t// Test case 1: No applicable columns\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\tapplicableColNames := []string{\"col4\", \"col5\"}\n\terr := node.InitCSR(csr, applicableColNames)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.outputs[0], nil))\n\tassert.False(t, csr.ApplicableTo(node.outputs[1], nil))\n\tassert.False(t, csr.ApplicableTo(node.outputs[2], nil))\n\n\t// Test case 2: Some applicable columns\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\tapplicableColNames = []string{\"col1\", \"col3\"}\n\terr = node.InitCSR(csr, applicableColNames)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.outputs[0], nil))  // col1\n\tassert.False(t, csr.ApplicableTo(node.outputs[1], nil)) // col2\n\tassert.True(t, csr.ApplicableTo(node.outputs[2], nil))  // col3\n\n\t// Test case 3: Case insensitive matching\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\tapplicableColNames = []string{\"COL1\", \"Col2\"}\n\terr = node.InitCSR(csr, applicableColNames)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.outputs[0], nil))  // col1\n\tassert.True(t, csr.ApplicableTo(node.outputs[1], nil))  // col2\n\tassert.False(t, csr.ApplicableTo(node.outputs[2], nil)) // col3\n}\n\nfunc TestInferCSREQJoin(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorEQJoin{\n\t\t// join keys' CSR attributes do not affect the output tensors' CSR attributes\n\t\tleftPayloads: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t},\n\t\trightPayloads: []*TensorMeta{\n\t\t\t{ID: 3},\n\t\t\t{ID: 4},\n\t\t},\n\t\tleftOutputs: []*TensorMeta{\n\t\t\t{ID: 10},\n\t\t\t{ID: 11},\n\t\t},\n\t\trightOutputs: []*TensorMeta{\n\t\t\t{ID: 12},\n\t\t\t{ID: 13},\n\t\t},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, false)\n\tmockTVC.SetTensorPublic(3, true)\n\tmockTVC.SetTensorPublic(4, false)\n\n\t// Test case 1: CSR always apply\n\tcsr := NewColumnSecurityRelaxationBase(true)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.leftOutputs[0], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.leftOutputs[1], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.rightOutputs[0], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.rightOutputs[1], mockTVC))\n\n\t// Test case 2: Selective relaxation based on tensor visibility\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.leftOutputs[0], mockTVC))   // leftPayloads[0] is public\n\tassert.False(t, csr.ApplicableTo(node.leftOutputs[1], mockTVC))  // leftPayloads[1] is not public\n\tassert.True(t, csr.ApplicableTo(node.rightOutputs[0], mockTVC))  // rightPayloads[0] is public\n\tassert.False(t, csr.ApplicableTo(node.rightOutputs[1], mockTVC)) // rightPayloads[1] is not public\n\n\t// Test case 3: Make applicable tensors\n\tcsr.MakeApplicable(node.leftPayloads[1])\n\tcsr.MakeApplicable(node.rightPayloads[1])\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.leftOutputs[0], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.leftOutputs[1], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.rightOutputs[0], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.rightOutputs[1], mockTVC))\n}\n\nfunc TestInferCSRCrossJoin(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorCrossJoin{\n\t\tleftInputs: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t},\n\t\trightInputs: []*TensorMeta{\n\t\t\t{ID: 3},\n\t\t\t{ID: 4},\n\t\t},\n\t\tleftOutputs: []*TensorMeta{\n\t\t\t{ID: 10},\n\t\t\t{ID: 11},\n\t\t},\n\t\trightOutputs: []*TensorMeta{\n\t\t\t{ID: 12},\n\t\t\t{ID: 13},\n\t\t},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, false)\n\tmockTVC.SetTensorPublic(3, true)\n\tmockTVC.SetTensorPublic(4, false)\n\n\t// Test case 1: CSR always apply\n\tcsr := NewColumnSecurityRelaxationBase(true)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.leftOutputs[0], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.leftOutputs[1], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.rightOutputs[0], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.rightOutputs[1], mockTVC))\n\n\t// Test case 2: Selective relaxation\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.leftOutputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.leftOutputs[1], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.rightOutputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.rightOutputs[1], mockTVC))\n}\n\nfunc TestInferCSRLimit(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorLimit{\n\t\tinputs: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t},\n\t\toutputs: []*TensorMeta{\n\t\t\t{ID: 10},\n\t\t\t{ID: 11},\n\t\t},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, false)\n\n\t// Test case 1: CSR always apply\n\tcsr := NewColumnSecurityRelaxationBase(true)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.outputs[0], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.outputs[1], mockTVC))\n\n\t// Test case 2: Selective relaxation\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.outputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.outputs[1], mockTVC))\n}\n\nfunc TestInferCSRFilter(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorFilter{\n\t\tmask: &TensorMeta{ID: 0},\n\t\tinputs: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t},\n\t\toutputs: []*TensorMeta{\n\t\t\t{ID: 10},\n\t\t\t{ID: 11},\n\t\t},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(0, true)  // mask is public\n\tmockTVC.SetTensorPublic(1, true)  // input 1 is public\n\tmockTVC.SetTensorPublic(2, false) // input 2 is not public\n\n\t// Test case 1: CSR always apply\n\tcsr := NewColumnSecurityRelaxationBase(true)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.outputs[0], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.outputs[1], mockTVC))\n\n\t// Test case 2: Selective relaxation\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.outputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.outputs[1], mockTVC))\n\n\t// Test case 3: Mask not applicable\n\tmockTVC.SetTensorPublic(0, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.outputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.outputs[1], mockTVC))\n}\n\nfunc TestInferCSRBroadcastTo(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorBroadcastTo{\n\t\tshapeRef: &TensorMeta{ID: 0},\n\t\tscalars: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t},\n\t\toutputs: []*TensorMeta{\n\t\t\t{ID: 10},\n\t\t\t{ID: 11},\n\t\t},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(0, true)  // shapeRef is public\n\tmockTVC.SetTensorPublic(1, true)  // scalar 1 is public\n\tmockTVC.SetTensorPublic(2, false) // scalar 2 is not public\n\n\t// Test case 1: CSR always apply\n\tcsr := NewColumnSecurityRelaxationBase(true)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.outputs[0], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.outputs[1], mockTVC))\n\n\t// Test case 2: Selective relaxation\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.outputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.outputs[1], mockTVC))\n\n\t// Test case 3: ShapeRef not applicable\n\tmockTVC.SetTensorPublic(0, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.outputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.outputs[1], mockTVC))\n}\n\nfunc TestInferCSRConcat(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorConcat{\n\t\tinputs: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t\t{ID: 3},\n\t\t},\n\t\toutput: &TensorMeta{ID: 10},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, true)\n\tmockTVC.SetTensorPublic(3, true)\n\n\t// Test case 1: All inputs are public\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 2: Not all inputs are public\n\tmockTVC.SetTensorPublic(3, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 3: Make applicable\n\tcsr.MakeApplicable(node.inputs[2])\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 4: Empty inputs\n\temptyNode := &OperatorConcat{\n\t\tinputs: []*TensorMeta{},\n\t\toutput: &TensorMeta{ID: 20},\n\t}\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = emptyNode.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(emptyNode.output, mockTVC))\n}\n\nfunc TestInferCSRSort(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorSort{\n\t\tsortKeys: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t},\n\t\tpayloads: []*TensorMeta{\n\t\t\t{ID: 3},\n\t\t\t{ID: 4},\n\t\t},\n\t\toutputs: []*TensorMeta{\n\t\t\t{ID: 10},\n\t\t\t{ID: 11},\n\t\t},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, true)\n\tmockTVC.SetTensorPublic(3, true)\n\tmockTVC.SetTensorPublic(4, false)\n\n\t// Test case 1: All sort keys are public\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.outputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.outputs[1], mockTVC))\n\n\t// Test case 2: Not all sort keys are public\n\tmockTVC.SetTensorPublic(2, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.outputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.outputs[1], mockTVC))\n}\n\nfunc TestInferCSRReduce(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorReduce{\n\t\tinput:  &TensorMeta{ID: 1},\n\t\toutput: &TensorMeta{ID: 10},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(1, true)\n\n\t// Test case 1: Input is public\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 2: Input is not public\n\tmockTVC.SetTensorPublic(1, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 3: Make applicable\n\tcsr.MakeApplicable(node.input)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.output, mockTVC))\n}\n\nfunc TestInferCSRGroupAgg(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorGroupAgg{\n\t\tgroupKeys: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t},\n\t\taggArgs: []*TensorMeta{\n\t\t\t{ID: 3},\n\t\t\t{ID: 4},\n\t\t},\n\t\tsimpleCountOutputs: []*TensorMeta{\n\t\t\t{ID: 20},\n\t\t\t{ID: 21},\n\t\t},\n\t\targFuncOutputs: []*TensorMeta{\n\t\t\t{ID: 10},\n\t\t\t{ID: 11},\n\t\t},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, true)\n\tmockTVC.SetTensorPublic(3, true)\n\tmockTVC.SetTensorPublic(4, false)\n\n\t// Test case 1: All group keys are public\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.argFuncOutputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.argFuncOutputs[1], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.simpleCountOutputs[0], mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.simpleCountOutputs[1], mockTVC))\n\n\t// Test case 2: Not all group keys are public\n\tmockTVC.SetTensorPublic(2, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.argFuncOutputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.argFuncOutputs[1], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.simpleCountOutputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.simpleCountOutputs[1], mockTVC))\n}\n\nfunc TestInferCSRRankWindow(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorWindow{\n\t\tpartitionKeys: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t},\n\t\torderKeys: []*TensorMeta{\n\t\t\t{ID: 2},\n\t\t},\n\t\tpayloads: []*TensorMeta{\n\t\t\t{ID: 3},\n\t\t\t{ID: 4},\n\t\t},\n\t\tfuncOutput: &TensorMeta{ID: 0},\n\t\tpayloadOutputs: []*TensorMeta{\n\t\t\t{ID: 10},\n\t\t\t{ID: 11},\n\t\t},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, true)\n\tmockTVC.SetTensorPublic(3, true)\n\tmockTVC.SetTensorPublic(4, false)\n\n\t// Test case 1: All partition and order keys are public\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.funcOutput, mockTVC))\n\tassert.True(t, csr.ApplicableTo(node.payloadOutputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.payloadOutputs[1], mockTVC))\n\n\t// Test case 2: Not all partition keys are public\n\tmockTVC.SetTensorPublic(1, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.funcOutput, mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.payloadOutputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.payloadOutputs[1], mockTVC))\n\n\t// Test case 3: Not all order keys are public\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.funcOutput, mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.payloadOutputs[0], mockTVC))\n\tassert.False(t, csr.ApplicableTo(node.payloadOutputs[1], mockTVC))\n}\n\nfunc TestInferCSRIn(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorIn{\n\t\tleft:   &TensorMeta{ID: 1},\n\t\tright:  &TensorMeta{ID: 2},\n\t\toutput: &TensorMeta{ID: 10},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, true)\n\n\t// Test case 1: Both inputs are public\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 2: Left input not public\n\tmockTVC.SetTensorPublic(1, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 3: Right input not public\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 4: Make applicable\n\tcsr.MakeApplicable(node.left)\n\tcsr.MakeApplicable(node.right)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.output, mockTVC))\n}\n\nfunc TestInferCSRFunction(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Setup test data\n\tnode := &OperatorFunction{\n\t\tinputs: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t\t{ID: 3},\n\t\t},\n\t\toutput: &TensorMeta{ID: 10},\n\t}\n\n\t// Set tensor visibility\n\tmockTVC.SetTensorPublic(1, true)\n\tmockTVC.SetTensorPublic(2, true)\n\tmockTVC.SetTensorPublic(3, true)\n\n\t// Test case 1: All inputs are public\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\terr := node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 2: Not all inputs are public\n\tmockTVC.SetTensorPublic(3, false)\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 3: Make applicable\n\tcsr.MakeApplicable(node.inputs[2])\n\terr = node.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(node.output, mockTVC))\n\n\t// Test case 4: Empty inputs\n\temptyNode := &OperatorFunction{\n\t\tinputs: []*TensorMeta{},\n\t\toutput: &TensorMeta{ID: 20},\n\t}\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = emptyNode.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(emptyNode.output, mockTVC))\n}\n\nfunc TestInferCSRTrivial(t *testing.T) {\n\topDataSource := &OperatorDataSource{}\n\terr := opDataSource.InferCSR(nil, nil)\n\tassert.NoError(t, err)\n\n\topRunSQL := &OperatorRunSQL{}\n\terr = opRunSQL.InferCSR(nil, nil)\n\tassert.NoError(t, err)\n\n\topConstant := &OperatorConstant{}\n\terr = opConstant.InferCSR(nil, nil)\n\tassert.NoError(t, err)\n\n\topResult := &OperatorResult{}\n\terr = opResult.InferCSR(nil, nil)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"OperatorResult's InferCSR should not be called\")\n}\n\nfunc TestInferCSRRegressionEdgeCases(t *testing.T) {\n\tmockTVC := NewMockTensorVisibilityChecker()\n\n\t// Test case 1: Empty applicableColNames for DataSource\n\tnode := &OperatorDataSource{\n\t\toriginNames: []string{\"col1\", \"col2\"},\n\t\toutputs: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t},\n\t}\n\tcsr := NewColumnSecurityRelaxationBase(false)\n\terr := node.InitCSR(csr, []string{})\n\tassert.NoError(t, err)\n\tassert.False(t, csr.ApplicableTo(node.outputs[0], nil))\n\tassert.False(t, csr.ApplicableTo(node.outputs[1], nil))\n\n\t// Test case 2: Empty tensors for other nodes\n\temptyNode := &OperatorLimit{\n\t\tinputs:  []*TensorMeta{},\n\t\toutputs: []*TensorMeta{},\n\t}\n\terr = emptyNode.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\n\t// Test case 3: Nil tensors handling\n\tnilNode := &OperatorReduce{\n\t\tinput:  nil,\n\t\toutput: nil,\n\t}\n\terr = nilNode.InferCSR(csr, mockTVC)\n\tassert.NoError(t, err)\n\n\t// Test case 4: Case sensitivity edge case\n\tcaseNode := &OperatorDataSource{\n\t\toriginNames: []string{\"Col1\", \"COL2\", \"col3\"},\n\t\toutputs: []*TensorMeta{\n\t\t\t{ID: 1},\n\t\t\t{ID: 2},\n\t\t\t{ID: 3},\n\t\t},\n\t}\n\tcsr = NewColumnSecurityRelaxationBase(false)\n\terr = caseNode.InitCSR(csr, []string{\"COL1\", \"col2\", \"COL3\"})\n\tassert.NoError(t, err)\n\tassert.True(t, csr.ApplicableTo(caseNode.outputs[0], nil)) // Col1 matches COL1\n\tassert.True(t, csr.ApplicableTo(caseNode.outputs[1], nil)) // COL2 matches col2\n\tassert.True(t, csr.ApplicableTo(caseNode.outputs[2], nil)) // col3 matches COL3\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/util/priority_queue.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage util\n\nimport \"container/heap\"\n\n// PriorityQueueItem represents an item in the priority queue\ntype PriorityQueueItem[T any] struct {\n\tvalue    T\n\tpriority int\n}\n\n// PriorityQueue implements a priority queue using a max-heap\n// Duplicates are not allowed and we use a map to track existing values\ntype PriorityQueue[T comparable] struct {\n\titems []*PriorityQueueItem[T]\n\t// existing is used to track existing values for O(1) duplicate checking\n\texisting map[T]struct{}\n\t// priorityFunc is used to calculate priority for items\n\tpriorityFunc func(T) int\n}\n\n// NewPriorityQueue creates a new priority queue with a priority function\nfunc NewPriorityQueue[T comparable](priorityFunc func(T) int) *PriorityQueue[T] {\n\tpq := &PriorityQueue[T]{\n\t\texisting:     make(map[T]struct{}),\n\t\tpriorityFunc: priorityFunc,\n\t}\n\theap.Init(pq)\n\treturn pq\n}\n\n// Len returns the number of items in the priority queue\n// for sort.Interface\nfunc (pq *PriorityQueue[T]) Len() int {\n\treturn len(pq.items)\n}\n\n// Less compares the priority of two items\n// for sort.Interface\nfunc (pq *PriorityQueue[T]) Less(i, j int) bool {\n\treturn pq.items[i].priority > pq.items[j].priority\n}\n\n// Swap swaps two items in the priority queue\n// for sort.Interface\nfunc (pq *PriorityQueue[T]) Swap(i, j int) {\n\tpq.items[i], pq.items[j] = pq.items[j], pq.items[i]\n}\n\n// Push adds an item to the priority queue\n// for heap.Interface\nfunc (pq *PriorityQueue[T]) Push(x any) {\n\titem := x.(*PriorityQueueItem[T])\n\tpq.items = append(pq.items, item)\n}\n\n// Pop removes and returns the item with the highest priority\n// for heap.Interface\nfunc (pq *PriorityQueue[T]) Pop() any {\n\told := pq.items\n\tn := len(old)\n\titem := old[n-1]\n\told[n-1] = nil\n\tpq.items = old[0 : n-1]\n\treturn item\n}\n\n// Enqueue adds a new item to the priority queue with the given value\nfunc (pq *PriorityQueue[T]) Enqueue(value T) {\n\t// Check for duplicates using map\n\tif _, exists := pq.existing[value]; exists {\n\t\treturn\n\t}\n\n\titem := &PriorityQueueItem[T]{\n\t\tvalue:    value,\n\t\tpriority: pq.priorityFunc(value),\n\t}\n\theap.Push(pq, item)\n\tpq.existing[value] = struct{}{}\n}\n\n// Dequeue removes and returns the item with the highest priority\nfunc (pq *PriorityQueue[T]) Dequeue() (T, bool) {\n\tif pq.Len() == 0 {\n\t\tvar zero T\n\t\treturn zero, false\n\t}\n\titem := heap.Pop(pq).(*PriorityQueueItem[T])\n\tdelete(pq.existing, item.value)\n\treturn item.value, true\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/util/priority_queue_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage util\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestPriorityQueue(t *testing.T) {\n\t// Test with integer values\n\tpq := NewPriorityQueue(func(x int) int {\n\t\treturn x // Use the value itself as priority\n\t})\n\n\t// Test empty queue\n\tval, ok := pq.Dequeue()\n\tassert.False(t, ok)\n\tassert.Equal(t, 0, val)\n\n\t// Test enqueue and dequeue\n\tpq.Enqueue(3)\n\tpq.Enqueue(1)\n\tpq.Enqueue(4)\n\tpq.Enqueue(2)\n\n\t// Test dequeue order (should be in descending order)\n\tval, ok = pq.Dequeue()\n\tassert.True(t, ok)\n\tassert.Equal(t, 4, val)\n\n\tval, ok = pq.Dequeue()\n\tassert.True(t, ok)\n\tassert.Equal(t, 3, val)\n\n\tval, ok = pq.Dequeue()\n\tassert.True(t, ok)\n\tassert.Equal(t, 2, val)\n\n\tval, ok = pq.Dequeue()\n\tassert.True(t, ok)\n\tassert.Equal(t, 1, val)\n\n\t// Test empty queue after dequeue\n\tval, ok = pq.Dequeue()\n\tassert.False(t, ok)\n\tassert.Equal(t, 0, val)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/visibility_analysis_pass.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n)\n\n// VisibilityAnalysisPass handles visibility analysis and computation\ntype VisibilityAnalysisPass struct{}\n\n// NewVisibilityAnalysisPass creates a new visibility analysis pass\nfunc NewVisibilityAnalysisPass() *VisibilityAnalysisPass {\n\treturn &VisibilityAnalysisPass{}\n}\n\n// Name returns the pass name\nfunc (p *VisibilityAnalysisPass) Name() string {\n\treturn \"VisibilityAnalysisPass\"\n}\n\n// Run performs visibility analysis and computation\nfunc (p *VisibilityAnalysisPass) Run(c *CompileContext) error {\n\t// 1. Ensure involved parties are available\n\t// They should have been set in OperatorGraphPass\n\tif len(c.InvolvedParties) == 0 {\n\t\treturn fmt.Errorf(\"involved parties not found - ensure OperatorGraphPass runs before VisibilityAnalysisPass\")\n\t}\n\tlogrus.Debugf(\"involved parties: %v\", c.InvolvedParties)\n\n\t// 2. Build visibility table and security relaxation manager\n\tvt := NewVisibilityTable(c.InvolvedParties)\n\tglobalSecurityRelaxation := convertGlobalSecurityRelaxation(c.Request.GetSecurityConfig().GetGlobalRelaxation())\n\tsourceSecurityRelaxation := convertColumnSecurityRelaxation(c.Request.GetSecurityConfig().GetColumnRelaxationList())\n\tsrm := NewSecurityRelaxationManager(globalSecurityRelaxation, sourceSecurityRelaxation)\n\tc.VisibilityTable = vt\n\tc.SecurityRelaxationManager = srm\n\n\t// 3. Create specified visibility from column visibility list\n\t// TODO: support specified column visibility\n\tspecifiedVis := map[int]*VisibleParties{}\n\n\t// 4. Get original visibility from column visibility list\n\toriginalVis, err := buildOriginalVisibility(c.Request.GetSecurityConfig().GetColumnVisibilityList())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build original visibility: %v\", err)\n\t}\n\n\t// 5. Solve visibility\n\tenableReverseInference := c.Request.GetSecurityConfig().GetReverseInferenceConf().GetEnableReverseInference()\n\tvisibilitySolver := NewVisibilitySolver(vt, srm, originalVis, specifiedVis, enableReverseInference)\n\tlogrus.Debugf(\"%v\", visibilitySolver.originalVisibility)\n\terr = visibilitySolver.Solve(c.OperatorGraph)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to solve visibility: %v\", err)\n\t}\n\n\tlogrus.Debugf(\"TensorMetas: %s\", c.TensorMetaManager.DumpTensorMetas(vt))\n\n\treturn nil\n}\n\n// Helper functions moved from compiler.go\n\nfunc convertGlobalSecurityRelaxation(global *v1.GlobalSecurityRelaxation) *GlobalSecurityRelaxation {\n\tif global == nil {\n\t\treturn &GlobalSecurityRelaxation{}\n\t}\n\n\treturn &GlobalSecurityRelaxation{\n\t\tRevealGroupCount:   global.GetRevealGroupCount(),\n\t\tRevealGroupMark:    global.GetRevealGroupMark(),\n\t\tRevealKeyAfterJoin: global.GetRevealKeyAfterJoin(),\n\t\tRevealFilterMask:   global.GetRevealFilterMask(),\n\t}\n}\n\nfunc convertColumnSecurityRelaxation(relaxationList []*v1.ColumnSecurityRelaxation) map[string][]string {\n\tsourceSecurityRelaxation := make(map[string][]string)\n\n\tfor _, relaxation := range relaxationList {\n\t\tfullName := strings.ToLower(toFullQualifiedColumnName(\n\t\t\trelaxation.GetDatabase(),\n\t\t\trelaxation.GetTable(),\n\t\t\trelaxation.GetColumn(),\n\t\t))\n\n\t\tif relaxation.GetRevealKeyAfterJoin() {\n\t\t\tsourceSecurityRelaxation[RevealKeyAfterJoin] = append(sourceSecurityRelaxation[RevealKeyAfterJoin], fullName)\n\t\t}\n\n\t\tif relaxation.GetRevealFilterMask() {\n\t\t\tsourceSecurityRelaxation[RevealFilterMask] = append(sourceSecurityRelaxation[RevealFilterMask], fullName)\n\t\t}\n\t}\n\n\treturn sourceSecurityRelaxation\n}\n\nfunc buildOriginalVisibility(columnVisibilities []*v1.ColumnVisibility) (map[string]*VisibleParties, error) {\n\toriginalVis := make(map[string]*VisibleParties)\n\n\t// Build a map from column full name to visible parties\n\tfor _, colVis := range columnVisibilities {\n\t\tfullName := strings.ToLower(toFullQualifiedColumnName(\n\t\t\tcolVis.GetDatabase(),\n\t\t\tcolVis.GetTable(),\n\t\t\tcolVis.GetColumn(),\n\t\t))\n\t\tif _, exist := originalVis[fullName]; exist {\n\t\t\treturn nil, fmt.Errorf(\"column %s is duplicated in column visibility list\", fullName)\n\t\t}\n\t\tparties := make([]string, 0, len(colVis.GetVisibleParties()))\n\t\tfor _, party := range colVis.GetVisibleParties() {\n\t\t\tparties = append(parties, party.GetCode())\n\t\t}\n\t\toriginalVis[fullName] = NewVisibleParties(parties)\n\t}\n\n\treturn originalVis, nil\n}\n\nfunc toFullQualifiedColumnName(dbName, tblName, colName string) string {\n\tif len(dbName) == 0 && len(tblName) == 0 {\n\t\treturn colName\n\t}\n\tif len(dbName) == 0 {\n\t\treturn fmt.Sprintf(\"%s.%s\", tblName, colName)\n\t}\n\treturn fmt.Sprintf(\"%s.%s.%s\", dbName, tblName, colName)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/visibility_basic_inference.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\nfunc (n *OperatorDataSource) InitVis(vr VisibilityRegistry, initialVisibility map[string]*VisibleParties) error {\n\tfor idx, output := range n.outputs {\n\t\tvr.UpdateVisibility(output, NewVisibleParties([]string{n.sourceParty}))\n\t\toriVis, ok := initialVisibility[strings.ToLower(n.originNames[idx])]\n\t\tif ok {\n\t\t\tvr.UpdateVisibility(output, oriVis)\n\t\t}\n\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorDataSource) InferVis(vr VisibilityRegistry) error {\n\t// Nothing to do here\n\treturn nil\n}\n\nfunc (n *OperatorRunSQL) InferVis(vr VisibilityRegistry) error {\n\t// Nothing to do here\n\treturn nil\n}\n\nfunc (n *OperatorEQJoin) InferVis(vr VisibilityRegistry) error {\n\tkeysVP := VPIntersection(vr.CommonVisibleParties(n.leftKeys), vr.CommonVisibleParties(n.rightKeys))\n\n\tfor idx := range n.leftPayloads {\n\t\toutputVP := VPIntersection(keysVP, vr.TensorVisibleParties(n.leftPayloads[idx]))\n\t\tvr.UpdateVisibility(n.leftOutputs[idx], outputVP)\n\t}\n\tfor idx := range n.rightPayloads {\n\t\toutputVP := VPIntersection(keysVP, vr.TensorVisibleParties(n.rightPayloads[idx]))\n\t\tvr.UpdateVisibility(n.rightOutputs[idx], outputVP)\n\t}\n\n\treturn nil\n}\n\nfunc (n *OperatorCrossJoin) InferVis(vr VisibilityRegistry) error {\n\tfor idx := range n.leftInputs {\n\t\tvr.UpdateVisibility(n.leftOutputs[idx], vr.TensorVisibleParties(n.leftInputs[idx]))\n\t}\n\tfor idx := range n.rightInputs {\n\t\tvr.UpdateVisibility(n.rightOutputs[idx], vr.TensorVisibleParties(n.rightInputs[idx]))\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorLimit) InferVis(vr VisibilityRegistry) error {\n\tfor idx := range n.inputs {\n\t\tvr.UpdateVisibility(n.outputs[idx], vr.TensorVisibleParties(n.inputs[idx]))\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorFilter) InferVis(vr VisibilityRegistry) error {\n\tfilterVP := vr.TensorVisibleParties(n.mask)\n\tfor idx, input := range n.inputs {\n\t\toutputVP := VPIntersection(vr.TensorVisibleParties(input), filterVP)\n\t\tvr.UpdateVisibility(n.outputs[idx], outputVP)\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorBroadcastTo) InferVis(vr VisibilityRegistry) error {\n\t// TODO question: should we consider the shape ref's visibility here?\n\tfor idx, input := range n.scalars {\n\t\tvr.UpdateVisibility(n.outputs[idx], vr.TensorVisibleParties(input))\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorConcat) InferVis(vr VisibilityRegistry) error {\n\tinputsVP := vr.CommonVisibleParties(n.inputs)\n\tvr.UpdateVisibility(n.output, inputsVP)\n\treturn nil\n}\n\nfunc (n *OperatorSort) InferVis(vr VisibilityRegistry) error {\n\trankVP := vr.CommonVisibleParties(n.sortKeys)\n\n\tfor idx, input := range n.payloads {\n\t\toutputVP := VPIntersection(vr.TensorVisibleParties(input), rankVP)\n\t\tvr.UpdateVisibility(n.outputs[idx], outputVP)\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorReduce) InferVis(vr VisibilityRegistry) error {\n\tswitch n.aggFunc.Name {\n\tcase ast.AggFuncCount:\n\t\tvr.UpdateVisibility(n.output, vr.PublicVisibility())\n\tcase ast.AggFuncFirstRow, ast.AggFuncSum, ast.AggFuncAvg, ast.AggFuncMax, ast.AggFuncMin, ast.AggPercentileDisc:\n\t\tvr.UpdateVisibility(n.output, vr.TensorVisibleParties(n.input))\n\tdefault:\n\t\treturn fmt.Errorf(\"OperatorReduce InferVis: unsupported agg func %s\", n.aggFunc.Name)\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorGroupAgg) InferVis(vr VisibilityRegistry) error {\n\tkeysVP := vr.CommonVisibleParties(n.groupKeys)\n\n\tfor idx, aggFunc := range n.aggFuncsWithArg {\n\t\tswitch aggFunc.Name {\n\t\tcase ast.AggFuncCount:\n\t\t\tvr.UpdateVisibility(n.argFuncOutputs[idx], keysVP)\n\t\tcase ast.AggFuncFirstRow, ast.AggFuncSum, ast.AggFuncAvg, ast.AggFuncMax, ast.AggFuncMin, ast.AggPercentileDisc:\n\t\t\toutputVP := VPIntersection(vr.TensorVisibleParties(n.aggArgs[idx]), keysVP)\n\t\t\tvr.UpdateVisibility(n.argFuncOutputs[idx], outputVP)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"OperatorGroupAgg InferVis: unsupported agg func %s\", aggFunc.Name)\n\t\t}\n\t}\n\tfor idx := range n.simpleCountOutputs {\n\t\tvr.UpdateVisibility(n.simpleCountOutputs[idx], keysVP)\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorWindow) InferVis(vr VisibilityRegistry) error {\n\tkeysVP := vr.CommonVisibleParties(n.orderKeys)\n\n\tvr.UpdateVisibility(n.funcOutput, keysVP)\n\tfor idx, input := range n.payloads {\n\t\t// FIXME should we consider keysVP here?\n\t\tvr.UpdateVisibility(n.payloadOutputs[idx], vr.TensorVisibleParties(input))\n\t}\n\treturn nil\n}\n\nfunc (n *OperatorIn) InferVis(vr VisibilityRegistry) error {\n\toutVP := VPIntersection(vr.TensorVisibleParties(n.left), vr.TensorVisibleParties(n.right))\n\tvr.UpdateVisibility(n.output, outVP)\n\treturn nil\n}\n\nfunc (n *OperatorFunction) InferVis(vr VisibilityRegistry) error {\n\tvr.UpdateVisibility(n.output, vr.CommonVisibleParties(n.inputs))\n\treturn nil\n}\n\nfunc (n *OperatorConstant) InferVis(vr VisibilityRegistry) error {\n\toutVP := vr.PublicVisibility()\n\tvr.UpdateVisibility(n.output, outVP)\n\treturn nil\n}\n\nfunc (n *OperatorResult) InferVis(vr VisibilityRegistry) error {\n\treturn fmt.Errorf(\"OperatorResult's InferVis should not be called\")\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/visibility_basic_inference_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\nfunc createTestTensor(id int) *TensorMeta {\n\treturn &TensorMeta{ID: id}\n}\n\nfunc TestInitDataourceVisibility(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Test case 1: Basic initialization\n\tt1 := createTestTensor(1)\n\tt2 := createTestTensor(2)\n\tnode := &OperatorDataSource{\n\t\toutputs:     []*TensorMeta{t1, t2},\n\t\tsourceParty: \"alice\",\n\t\toriginNames: []string{\"col1\", \"col2\"},\n\t}\n\n\toriginalVisibility := map[string]*VisibleParties{\n\t\t\"col1\": NewVisibleParties([]string{\"alice\", \"bob\"}),\n\t\t\"col2\": NewVisibleParties([]string{\"carol\"}),\n\t}\n\n\terr := node.InitVis(vt, originalVisibility)\n\tassert.NoError(t, err)\n\n\t// Check visibility for first output\n\tvp1 := vt.TensorVisibleParties(t1)\n\t// vp1 contains \"alice\" and \"bob\" because they'are provided by the original visibility\n\tassert.True(t, vp1.Contains(\"alice\"))\n\tassert.True(t, vp1.Contains(\"bob\"))\n\tassert.False(t, vp1.Contains(\"carol\"))\n\n\t// Check visibility for second output\n\tvp2 := vt.TensorVisibleParties(t2)\n\t// vp2 contains \"carol\" because it's provided by the original visibility\n\tassert.True(t, vp2.Contains(\"carol\"))\n\t// vp2 contains \"alice\" because it's the source party\n\tassert.True(t, vp2.Contains(\"alice\"))\n\tassert.False(t, vp2.Contains(\"bob\"))\n\n\t// Test case 2: No original visibility\n\tvt2 := NewVisibilityTable(parties)\n\tt3 := createTestTensor(3)\n\tnode2 := &OperatorDataSource{\n\t\toutputs:     []*TensorMeta{t3},\n\t\tsourceParty: \"bob\",\n\t\toriginNames: []string{\"col3\"},\n\t}\n\n\terr = node2.InitVis(vt2, map[string]*VisibleParties{})\n\tassert.NoError(t, err)\n\n\tvp3 := vt2.TensorVisibleParties(t3)\n\tassert.True(t, vp3.Contains(\"bob\"))\n\tassert.False(t, vp3.Contains(\"alice\"))\n\tassert.False(t, vp3.Contains(\"carol\"))\n\n\t// Test case 3: Case insensitive original visibility\n\tvt3 := NewVisibilityTable(parties)\n\tt4 := createTestTensor(4)\n\tnode3 := &OperatorDataSource{\n\t\toutputs:     []*TensorMeta{t4},\n\t\tsourceParty: \"carol\",\n\t\toriginNames: []string{\"COL1\"},\n\t}\n\n\toriginalVisibility3 := map[string]*VisibleParties{\n\t\t\"col1\": NewVisibleParties([]string{\"alice\", \"carol\"}),\n\t}\n\n\terr = node3.InitVis(vt3, originalVisibility3)\n\tassert.NoError(t, err)\n\n\tvp4 := vt3.TensorVisibleParties(t4)\n\tassert.True(t, vp4.Contains(\"alice\"))\n\tassert.True(t, vp4.Contains(\"carol\"))\n\tassert.False(t, vp4.Contains(\"bob\"))\n}\n\nfunc TestOperatorEQJoinInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Setup tensors\n\tleftKey1 := createTestTensor(1)\n\tleftKey2 := createTestTensor(2)\n\trightKey1 := createTestTensor(3)\n\trightKey2 := createTestTensor(4)\n\tleftPayload1 := createTestTensor(5)\n\tleftPayload2 := createTestTensor(6)\n\trightPayload1 := createTestTensor(7)\n\trightPayload2 := createTestTensor(8)\n\tleftOutput1 := createTestTensor(9)\n\tleftOutput2 := createTestTensor(10)\n\trightOutput1 := createTestTensor(11)\n\trightOutput2 := createTestTensor(12)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(leftKey1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(leftKey2, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(rightKey1, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\tvt.UpdateVisibility(rightKey2, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\tvt.UpdateVisibility(leftPayload1, NewVisibleParties([]string{\"alice\"}))\n\tvt.UpdateVisibility(leftPayload2, NewVisibleParties([]string{\"bob\"}))\n\tvt.UpdateVisibility(rightPayload1, NewVisibleParties([]string{\"carol\"}))\n\tvt.UpdateVisibility(rightPayload2, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\n\tnode := &OperatorEQJoin{\n\t\tleftKeys:      []*TensorMeta{leftKey1, leftKey2},\n\t\trightKeys:     []*TensorMeta{rightKey1, rightKey2},\n\t\tleftPayloads:  []*TensorMeta{leftPayload1, leftPayload2},\n\t\trightPayloads: []*TensorMeta{rightPayload1, rightPayload2},\n\t\tleftOutputs:   []*TensorMeta{leftOutput1, leftOutput2},\n\t\trightOutputs:  []*TensorMeta{rightOutput1, rightOutput2},\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check left outputs visibility (intersection of keys and payloads)\n\t// keys visibility: {\"bob\"} (intersection of {\"alice\", \"bob\"} and {\"bob\", \"carol\"})\n\t// leftOutput1: intersection of {\"bob\"} and {\"alice\"} = empty\n\tassert.True(t, vt.TensorVisibleParties(leftOutput1).IsEmpty())\n\n\t// leftOutput2: intersection of {\"bob\"} and {\"bob\"} = {\"bob\"}\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(leftOutput2).GetParties())\n\n\t// Check right outputs visibility\n\t// rightOutput1: intersection of {\"bob\"} and {\"carol\"} = empty\n\tassert.True(t, vt.TensorVisibleParties(rightOutput1).IsEmpty())\n\n\t// rightOutput2: intersection of {\"bob\"} and {\"bob\", \"carol\"} = {\"bob\"}\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(rightOutput2).GetParties())\n}\n\nfunc TestOperatorCrossJoinInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Setup tensors\n\tleftInput1 := createTestTensor(1)\n\tleftInput2 := createTestTensor(2)\n\trightInput1 := createTestTensor(3)\n\trightInput2 := createTestTensor(4)\n\tleftOutput1 := createTestTensor(5)\n\tleftOutput2 := createTestTensor(6)\n\trightOutput1 := createTestTensor(7)\n\trightOutput2 := createTestTensor(8)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(leftInput1, NewVisibleParties([]string{\"alice\"}))\n\tvt.UpdateVisibility(leftInput2, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(rightInput1, NewVisibleParties([]string{\"bob\"}))\n\tvt.UpdateVisibility(rightInput2, NewVisibleParties([]string{\"carol\"}))\n\n\tnode := &OperatorCrossJoin{\n\t\tleftInputs:   []*TensorMeta{leftInput1, leftInput2},\n\t\trightInputs:  []*TensorMeta{rightInput1, rightInput2},\n\t\tleftOutputs:  []*TensorMeta{leftOutput1, leftOutput2},\n\t\trightOutputs: []*TensorMeta{rightOutput1, rightOutput2},\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check left outputs: should have same visibility as left inputs\n\tassert.Equal(t, []string{\"alice\"}, vt.TensorVisibleParties(leftOutput1).GetParties())\n\tassert.Equal(t, []string{\"alice\", \"bob\"}, vt.TensorVisibleParties(leftOutput2).GetParties())\n\n\t// Check right outputs: should have same visibility as right inputs\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(rightOutput1).GetParties())\n\tassert.Equal(t, []string{\"carol\"}, vt.TensorVisibleParties(rightOutput2).GetParties())\n}\n\nfunc TestOperatorLimitInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Setup tensors\n\tinput1 := createTestTensor(1)\n\tinput2 := createTestTensor(2)\n\toutput1 := createTestTensor(3)\n\toutput2 := createTestTensor(4)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(input1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(input2, NewVisibleParties([]string{\"carol\"}))\n\n\tnode := &OperatorLimit{\n\t\tinputs:  []*TensorMeta{input1, input2},\n\t\toutputs: []*TensorMeta{output1, output2},\n\t\toffset:  10,\n\t\tcount:   100,\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check outputs: should have same visibility as inputs\n\tassert.Equal(t, []string{\"alice\", \"bob\"}, vt.TensorVisibleParties(output1).GetParties())\n\tassert.Equal(t, []string{\"carol\"}, vt.TensorVisibleParties(output2).GetParties())\n}\n\nfunc TestOperatorFilterInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Setup tensors\n\tmask := createTestTensor(1)\n\tinput1 := createTestTensor(2)\n\tinput2 := createTestTensor(3)\n\toutput1 := createTestTensor(4)\n\toutput2 := createTestTensor(5)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(mask, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(input1, NewVisibleParties([]string{\"alice\", \"carol\"}))\n\tvt.UpdateVisibility(input2, NewVisibleParties([]string{\"bob\"}))\n\n\tnode := &OperatorFilter{\n\t\tmask:    mask,\n\t\tinputs:  []*TensorMeta{input1, input2},\n\t\toutputs: []*TensorMeta{output1, output2},\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check outputs: should be intersection of mask visibility and input visibility\n\t// output1: {\"alice\", \"bob\"} ∩ {\"alice\", \"carol\"} = {\"alice\"}\n\tassert.Equal(t, []string{\"alice\"}, vt.TensorVisibleParties(output1).GetParties())\n\n\t// output2: {\"alice\", \"bob\"} ∩ {\"bob\"} = {\"bob\"}\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(output2).GetParties())\n}\n\nfunc TestOperatorBroadcastToInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Setup tensors\n\tshapeRef := createTestTensor(1)\n\tscalar1 := createTestTensor(2)\n\tscalar2 := createTestTensor(3)\n\toutput1 := createTestTensor(4)\n\toutput2 := createTestTensor(5)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(shapeRef, NewVisibleParties([]string{\"alice\"})) // shapeRef visibility not used\n\tvt.UpdateVisibility(scalar1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(scalar2, NewVisibleParties([]string{\"carol\"}))\n\n\tnode := &OperatorBroadcastTo{\n\t\tshapeRef: shapeRef,\n\t\tscalars:  []*TensorMeta{scalar1, scalar2},\n\t\toutputs:  []*TensorMeta{output1, output2},\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check outputs: should have same visibility as scalars\n\tassert.Equal(t, []string{\"alice\", \"bob\"}, vt.TensorVisibleParties(output1).GetParties())\n\tassert.Equal(t, []string{\"carol\"}, vt.TensorVisibleParties(output2).GetParties())\n}\n\nfunc TestOperatorConcatInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Setup tensors\n\tinput1 := createTestTensor(1)\n\tinput2 := createTestTensor(2)\n\tinput3 := createTestTensor(3)\n\toutput := createTestTensor(4)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(input1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(input2, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\tvt.UpdateVisibility(input3, NewVisibleParties([]string{\"bob\"}))\n\n\tnode := &OperatorConcat{\n\t\tinputs: []*TensorMeta{input1, input2, input3},\n\t\toutput: output,\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check output: should be intersection of all inputs\n\t// {\"alice\", \"bob\"} ∩ {\"bob\", \"carol\"} ∩ {\"bob\"} = {\"bob\"}\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(output).GetParties())\n}\n\nfunc TestOperatorSortInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Setup tensors\n\tsortKey1 := createTestTensor(1)\n\tsortKey2 := createTestTensor(2)\n\tpayload1 := createTestTensor(3)\n\tpayload2 := createTestTensor(4)\n\toutput1 := createTestTensor(5)\n\toutput2 := createTestTensor(6)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(sortKey1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(sortKey2, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\tvt.UpdateVisibility(payload1, NewVisibleParties([]string{\"alice\", \"carol\"}))\n\tvt.UpdateVisibility(payload2, NewVisibleParties([]string{\"bob\"}))\n\n\tnode := &OperatorSort{\n\t\tsortKeys:   []*TensorMeta{sortKey1, sortKey2},\n\t\tpayloads:   []*TensorMeta{payload1, payload2},\n\t\toutputs:    []*TensorMeta{output1, output2},\n\t\tdescending: slices.Repeat([]bool{false}, 2),\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check outputs: should be intersection of rank visibility and payload visibility\n\t// rank visibility: {\"bob\"} (intersection of {\"alice\", \"bob\"} and {\"bob\", \"carol\"})\n\t// output1: {\"bob\"} ∩ {\"alice\", \"carol\"} = empty\n\tassert.True(t, vt.TensorVisibleParties(output1).IsEmpty())\n\n\t// output2: {\"bob\"} ∩ {\"bob\"} = {\"bob\"}\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(output2).GetParties())\n}\n\nfunc TestOperatorReduceInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Test case 1: COUNT function should be public\n\tinput1 := createTestTensor(1)\n\toutput1 := createTestTensor(2)\n\tvt.UpdateVisibility(input1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\n\tcountFunc := &aggregation.AggFuncDesc{}\n\tcountFunc.Name = ast.AggFuncCount\n\tnode1 := &OperatorReduce{\n\t\tinput:   input1,\n\t\toutput:  output1,\n\t\taggFunc: countFunc,\n\t}\n\n\terr := node1.InferVis(vt)\n\tassert.NoError(t, err)\n\tassert.True(t, vt.VisibilityPublic(vt.TensorVisibleParties(output1)))\n\n\t// Test case 2: SUM function should have same visibility as input\n\tinput2 := createTestTensor(3)\n\toutput2 := createTestTensor(4)\n\tvt.UpdateVisibility(input2, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\n\tsumFunc := &aggregation.AggFuncDesc{}\n\tsumFunc.Name = ast.AggFuncSum\n\tnode2 := &OperatorReduce{\n\t\tinput:   input2,\n\t\toutput:  output2,\n\t\taggFunc: sumFunc,\n\t}\n\n\terr = node2.InferVis(vt)\n\tassert.NoError(t, err)\n\tassert.Equal(t, []string{\"alice\", \"bob\"}, vt.TensorVisibleParties(output2).GetParties())\n\n\t// Test case 3: AVG function should have same visibility as input\n\tinput3 := createTestTensor(5)\n\toutput3 := createTestTensor(6)\n\tvt.UpdateVisibility(input3, NewVisibleParties([]string{\"carol\"}))\n\n\tavgFunc := &aggregation.AggFuncDesc{}\n\tavgFunc.Name = ast.AggFuncAvg\n\tnode3 := &OperatorReduce{\n\t\tinput:   input3,\n\t\toutput:  output3,\n\t\taggFunc: avgFunc,\n\t}\n\n\terr = node3.InferVis(vt)\n\tassert.NoError(t, err)\n\tassert.Equal(t, []string{\"carol\"}, vt.TensorVisibleParties(output3).GetParties())\n\n\t// Test case 4: Unsupported function should return error\n\tinput4 := createTestTensor(7)\n\toutput4 := createTestTensor(8)\n\tunsupportedFunc := &aggregation.AggFuncDesc{}\n\tunsupportedFunc.Name = \"unsupported\"\n\tnode4 := &OperatorReduce{\n\t\tinput:   input4,\n\t\toutput:  output4,\n\t\taggFunc: unsupportedFunc,\n\t}\n\n\terr = node4.InferVis(vt)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"unsupported agg func\")\n}\n\nfunc TestOperatorGroupAggInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Setup tensors\n\tgroupKey1 := createTestTensor(1)\n\tgroupKey2 := createTestTensor(2)\n\tpayload1 := createTestTensor(3)\n\tpayload2 := createTestTensor(4)\n\tpayload3 := createTestTensor(5)\n\toutput1 := createTestTensor(6)\n\toutput2 := createTestTensor(7)\n\toutput3 := createTestTensor(8)\n\tsimpleCountOutput := createTestTensor(9)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(groupKey1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(groupKey2, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\tvt.UpdateVisibility(payload1, NewVisibleParties([]string{\"alice\", \"carol\"}))\n\tvt.UpdateVisibility(payload2, NewVisibleParties([]string{\"bob\"}))\n\tvt.UpdateVisibility(payload3, NewVisibleParties([]string{\"carol\"}))\n\n\t// Test case 1: COUNT function should have keys visibility\n\tcountFunc := &aggregation.AggFuncDesc{}\n\tcountFunc.Name = ast.AggFuncCount\n\n\t// Test case 2: SUM function should have intersection of keys and payload\n\tsumFunc := &aggregation.AggFuncDesc{}\n\tsumFunc.Name = ast.AggFuncSum\n\n\tnode := &OperatorGroupAgg{\n\t\tgroupKeys:          []*TensorMeta{groupKey1, groupKey2},\n\t\taggArgs:            []*TensorMeta{payload1, payload2, payload3},\n\t\targFuncOutputs:     []*TensorMeta{output1, output2, output3},\n\t\tsimpleCountOutputs: []*TensorMeta{simpleCountOutput},\n\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{\n\t\t\tcountFunc,\n\t\t\tsumFunc,\n\t\t\tsumFunc,\n\t\t},\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check keys visibility: {\"bob\"} (intersection of {\"alice\", \"bob\"} and {\"bob\", \"carol\"})\n\tkeysVisibility := NewVisibleParties([]string{\"bob\"})\n\n\t// output1 (COUNT): should have keys visibility\n\tassert.Equal(t, keysVisibility.GetParties(), vt.TensorVisibleParties(output1).GetParties())\n\n\t// output2 (SUM): intersection of keys and payload2 = {\"bob\"} ∩ {\"bob\"} = {\"bob\"}\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(output2).GetParties())\n\n\t// output3 (SUM): intersection of keys and payload3 = {\"bob\"} ∩ {\"carol\"} = empty\n\tassert.True(t, vt.TensorVisibleParties(output3).IsEmpty())\n\n\t// simpleCountOutput: should have keys visibility\n\tassert.Equal(t, keysVisibility.GetParties(), vt.TensorVisibleParties(simpleCountOutput).GetParties())\n\n\t// Test case 4: Unsupported function should return error\n\tnode2 := &OperatorGroupAgg{\n\t\tgroupKeys:          []*TensorMeta{groupKey1},\n\t\taggArgs:            []*TensorMeta{payload1},\n\t\targFuncOutputs:     []*TensorMeta{createTestTensor(10)},\n\t\tsimpleCountOutputs: []*TensorMeta{},\n\t\taggFuncsWithArg: []*aggregation.AggFuncDesc{\n\t\t\tfunc() *aggregation.AggFuncDesc {\n\t\t\t\tagg := &aggregation.AggFuncDesc{}\n\t\t\t\tagg.Name = \"unsupported\"\n\t\t\t\treturn agg\n\t\t\t}(),\n\t\t},\n\t}\n\n\terr = node2.InferVis(vt)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"unsupported agg func\")\n}\n\nfunc TestOperatorRankWindowInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Setup tensors\n\torderKey1 := createTestTensor(1)\n\torderKey2 := createTestTensor(2)\n\tpayload1 := createTestTensor(3)\n\tpayload2 := createTestTensor(4)\n\toutput1 := createTestTensor(5)\n\toutput2 := createTestTensor(6)\n\trank := createTestTensor(7)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(orderKey1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(orderKey2, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\tvt.UpdateVisibility(payload1, NewVisibleParties([]string{\"alice\", \"carol\"}))\n\tvt.UpdateVisibility(payload2, NewVisibleParties([]string{\"bob\"}))\n\n\tnode := &OperatorWindow{\n\t\torderKeys:      []*TensorMeta{orderKey1, orderKey2},\n\t\tpayloads:       []*TensorMeta{payload1, payload2},\n\t\tpayloadOutputs: []*TensorMeta{output1, output2},\n\t\tfuncOutput:     rank,\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check rank visibility: should be intersection of order keys\n\t// {\"alice\", \"bob\"} ∩ {\"bob\", \"carol\"} = {\"bob\"}\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(rank).GetParties())\n\n\t// Check outputs: should have same visibility as payloads (FIXME: should this consider keys?)\n\tassert.Equal(t, []string{\"alice\", \"carol\"}, vt.TensorVisibleParties(output1).GetParties())\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(output2).GetParties())\n}\n\nfunc TestOperatorInInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Setup tensors\n\tleft := createTestTensor(1)\n\tright := createTestTensor(2)\n\toutput := createTestTensor(3)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(left, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(right, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\n\tnode := &OperatorIn{\n\t\tleft:   left,\n\t\tright:  right,\n\t\toutput: output,\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check output: should be intersection of left and right\n\t// {\"alice\", \"bob\"} ∩ {\"bob\", \"carol\"} = {\"bob\"}\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(output).GetParties())\n}\n\nfunc TestOperatorFunctionInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Test case 1: Multiple inputs\n\tinput1 := createTestTensor(1)\n\tinput2 := createTestTensor(2)\n\tinput3 := createTestTensor(3)\n\toutput := createTestTensor(4)\n\n\t// Set initial visibility\n\tvt.UpdateVisibility(input1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvt.UpdateVisibility(input2, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\tvt.UpdateVisibility(input3, NewVisibleParties([]string{\"bob\"}))\n\n\tnode := &OperatorFunction{\n\t\tinputs: []*TensorMeta{input1, input2, input3},\n\t\toutput: output,\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check output: should be intersection of all inputs\n\t// {\"alice\", \"bob\"} ∩ {\"bob\", \"carol\"} ∩ {\"bob\"} = {\"bob\"}\n\tassert.Equal(t, []string{\"bob\"}, vt.TensorVisibleParties(output).GetParties())\n\n\t// Test case 2: Single input\n\tinput4 := createTestTensor(5)\n\toutput2 := createTestTensor(6)\n\tvt.UpdateVisibility(input4, NewVisibleParties([]string{\"alice\"}))\n\n\tnode2 := &OperatorFunction{\n\t\tinputs: []*TensorMeta{input4},\n\t\toutput: output2,\n\t}\n\n\terr = node2.InferVis(vt)\n\tassert.NoError(t, err)\n\tassert.Equal(t, []string{\"alice\"}, vt.TensorVisibleParties(output2).GetParties())\n\n\t// Test case 3: No inputs (edge case)\n\toutput3 := createTestTensor(7)\n\tnode3 := &OperatorFunction{\n\t\tinputs: []*TensorMeta{},\n\t\toutput: output3,\n\t}\n\n\terr = node3.InferVis(vt)\n\tassert.NoError(t, err)\n\tassert.True(t, vt.VisibilityPublic(vt.TensorVisibleParties(output3))) // Should be public when no inputs\n}\n\nfunc TestOperatorConstantInferVis(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\toutput := createTestTensor(1)\n\n\tnode := &OperatorConstant{\n\t\toutput: output,\n\t\tvalue:  nil, // value doesn't affect visibility\n\t}\n\n\terr := node.InferVis(vt)\n\tassert.NoError(t, err)\n\n\t// Check output: should always be public\n\tassert.True(t, vt.VisibilityPublic(vt.TensorVisibleParties(output)))\n}\n\nfunc TestTrivialInferVis(t *testing.T) {\n\topDatasource := &OperatorDataSource{}\n\terr := opDatasource.InferVis(nil)\n\tassert.NoError(t, err)\n\n\topRunSQL := &OperatorRunSQL{}\n\terr = opRunSQL.InferVis(nil)\n\tassert.NoError(t, err)\n\n\topResult := &OperatorResult{}\n\terr = opResult.InferVis(nil)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"OperatorResult's InferVis should not be called\")\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/visibility_inference_with_relaxation.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n)\n\nfunc (n *OperatorFunction) ApplyRevealFilterMask(vr VisibilityRegistry, csr *ColumnSecurityRelaxationBase, consumerTracker *TensorConsumerTracker) error {\n\tif !csr.ApplicableTo(n.output, vr) {\n\t\treturn nil\n\t}\n\n\t_, isCompare := isCompareAstFuncMap[n.funcName]\n\t_, isLogical := isLogicalAstFuncMap[n.funcName]\n\tif !isCompare && !isLogical {\n\t\treturn nil\n\t}\n\n\tif !consumerTracker.UsedAsFilterMask(n.output) {\n\t\treturn nil\n\t}\n\n\tvr.UpdateVisibility(n.output, vr.PublicVisibility())\n\treturn nil\n}\n\nfunc (n *OperatorIn) ApplyRevealFilterMask(vr VisibilityRegistry, csr *ColumnSecurityRelaxationBase, consumerTracker *TensorConsumerTracker) error {\n\tif !csr.ApplicableTo(n.left, vr) || !csr.ApplicableTo(n.right, vr) {\n\t\treturn nil\n\t}\n\n\tif !consumerTracker.UsedAsFilterMask(n.output) {\n\t\treturn nil\n\t}\n\n\tvr.UpdateVisibility(n.output, vr.PublicVisibility())\n\treturn nil\n}\n\nfunc (n *OperatorEQJoin) ApplyRevealKeyAfterJoin(vr VisibilityRegistry, csr *ColumnSecurityRelaxationBase) error {\n\t// TODO question: should we allow partially applicable?\n\tif !csr.AllApplicable(n.leftKeys, vr) || !csr.AllApplicable(n.rightKeys, vr) {\n\t\treturn nil\n\t}\n\n\tif n.joinType == core.InnerJoin || n.joinType == core.RightOuterJoin {\n\t\tfor _, input := range n.leftKeys {\n\t\t\tvr.UpdateVisibility(input, vr.PublicVisibility())\n\t\t}\n\t}\n\n\tif n.joinType == core.InnerJoin || n.joinType == core.LeftOuterJoin {\n\t\tfor _, input := range n.rightKeys {\n\t\t\tvr.UpdateVisibility(input, vr.PublicVisibility())\n\t\t}\n\t}\n\n\tif len(n.leftPayloads) != len(n.leftOutputs) {\n\t\treturn fmt.Errorf(\"payloads and outputs num not match in left side\")\n\t}\n\tif len(n.rightPayloads) != len(n.rightOutputs) {\n\t\treturn fmt.Errorf(\"payloads and outputs num not match in right side\")\n\t}\n\n\tfor idx := range n.leftPayloads {\n\t\tvr.UpdateVisibility(n.leftOutputs[idx], vr.TensorVisibleParties(n.leftPayloads[idx]))\n\t}\n\tfor idx := range n.rightPayloads {\n\t\tvr.UpdateVisibility(n.rightOutputs[idx], vr.TensorVisibleParties(n.rightPayloads[idx]))\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/visibility_registry.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// VisibilityRegistry defines the contract for managing tensor visibility across parties\n// in the SCQL compiler. It tracks which parties can see which tensors during query execution.\ntype VisibilityRegistry interface {\n\t// TensorVisibleParties returns the visible parties for a given tensor\n\tTensorVisibleParties(tensor *TensorMeta) *VisibleParties\n\n\t// CommonVisibleParties returns the intersection of visible parties across multiple tensors\n\t// Returns empty VisibleParties if input slice is empty\n\tCommonVisibleParties(tensors []*TensorMeta) *VisibleParties\n\n\t// UpdateVisibility updates the visible parties for a tensor by merging with increment\n\t// Silently ignores nil tensor or nil increment\n\tUpdateVisibility(tensor *TensorMeta, increment *VisibleParties)\n\n\t// PublicVisibility returns a VisibleParties containing all parties (has public visibility)\n\tPublicVisibility() *VisibleParties\n\n\t// IsTensorPublic returns true if the tensor is visible to all parties\n\tIsTensorPublic(tensor *TensorMeta) bool\n}\n\ntype VisibilityTable struct {\n\ttensorsVisibility map[int]*VisibleParties\n\tallParties        []string\n}\n\n// NewVisibilityTable creates a new VisibilityTable with the given parties as public visibility\nfunc NewVisibilityTable(parties []string) *VisibilityTable {\n\treturn &VisibilityTable{\n\t\ttensorsVisibility: make(map[int]*VisibleParties),\n\t\tallParties:        parties,\n\t}\n}\n\nfunc (vt *VisibilityTable) TensorVisibleParties(tensor *TensorMeta) *VisibleParties {\n\tif tensor == nil {\n\t\treturn nil\n\t}\n\tif v, ok := vt.tensorsVisibility[tensor.ID]; ok {\n\t\treturn v\n\t}\n\treturn NewVisibleParties(nil)\n}\n\nfunc (vt *VisibilityTable) UpdateVisibility(tensor *TensorMeta, increment *VisibleParties) {\n\tif tensor == nil || increment == nil {\n\t\treturn\n\t}\n\tvp := vt.TensorVisibleParties(tensor)\n\tvp.UpdateWith(increment)\n\tvt.tensorsVisibility[tensor.ID] = vp\n}\n\n// CommonVisibleParties returns the intersection of visible parties across multiple tensors\n// Returns public VisibleParties if input slice is empty\nfunc (vt *VisibilityTable) CommonVisibleParties(tensors []*TensorMeta) *VisibleParties {\n\tif len(tensors) == 0 {\n\t\treturn vt.PublicVisibility()\n\t}\n\tvis := vt.TensorVisibleParties(tensors[0])\n\tfor _, tensor := range tensors[1:] {\n\t\tvis = VPIntersection(vis, vt.TensorVisibleParties(tensor))\n\t}\n\treturn vis\n}\n\n// PublicVisibility returns a VisibleParties containing all parties (public visibility)\nfunc (vt *VisibilityTable) PublicVisibility() *VisibleParties {\n\treturn NewVisibleParties(vt.allParties)\n}\n\n// VisibilityPublic returns true if the given visibility covers all parties\nfunc (vt *VisibilityTable) VisibilityPublic(vis *VisibleParties) bool {\n\tfor _, party := range vt.allParties {\n\t\tif !vis.Contains(party) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// TryUpdateVisibility attempts to update visibility only if increment adds new parties\n// Returns true if the visibility was actually modified, false if no changes were needed\n// because the tensor already covers all parties in the increment\nfunc (vt *VisibilityTable) TryUpdateVisibility(tensor *TensorMeta, increment *VisibleParties) bool {\n\tvp := vt.TensorVisibleParties(tensor)\n\tif vp.Covers(increment) {\n\t\treturn false\n\t}\n\tvt.UpdateVisibility(tensor, increment)\n\treturn true\n}\n\n// TensorRegistered returns true if the tensor has been registered with visibility information\nfunc (vs *VisibilityTable) TensorRegistered(tensor *TensorMeta) bool {\n\tif tensor == nil {\n\t\treturn false\n\t}\n\t_, ok := vs.tensorsVisibility[tensor.ID]\n\treturn ok\n}\n\nfunc (vt *VisibilityTable) DumpVisibility() string {\n\tvar sb strings.Builder\n\tfmt.Fprintf(&sb, \"Tensor Visibility:\\n\")\n\tfor tensorID, VP := range vt.tensorsVisibility {\n\t\tfmt.Fprintf(&sb, \"t_%d: \\tVisibleParties[%s]\\n\", tensorID, VP.parties)\n\t}\n\treturn sb.String()\n}\n\n// choosePlacement determines the optimal placement for a tensor meta based on visibility and constraints\n//\n// Parameters:\n// - tensor: the meta of the tensor to place\n// - tm: tensor manager for checking existing placements\n// - allowPublic: whether public placement is allowed\n// - allowPrivate: whether private placement is allowed\n// - secretFine: whether secret placement is considered as good as other placements\n//\n// Decision priority:\n// 1. Empty visibility → secret placement\n// 2. Existing placement (to avoid unnecessary conversion)\n// 3. Public placement if tensor is visible to all parties\n// 4. Private placement for single party visibility\n// 5. Secret placement as fallback\nfunc (vt *VisibilityTable) choosePlacement(tensor *TensorMeta, tm *TensorManager, allowPublic, allowPrivate, secretFine bool) tensorPlacement {\n\tvp := vt.TensorVisibleParties(tensor)\n\tif vp.IsEmpty() {\n\t\treturn &secretPlacement{}\n\t}\n\t// check existing placment to avoid conversion\n\tif allowPublic && tm.hasPlacedTensor(tensor, &publicPlacement{}) {\n\t\treturn &publicPlacement{}\n\t}\n\tif allowPrivate {\n\t\tfor _, party := range vp.GetParties() {\n\t\t\tplacement := &privatePlacement{partyCode: party}\n\t\t\tif tm.hasPlacedTensor(tensor, placement) {\n\t\t\t\treturn placement\n\t\t\t}\n\t\t}\n\t}\n\tif secretFine && tm.hasPlacedTensor(tensor, &secretPlacement{}) {\n\t\treturn &secretPlacement{}\n\t}\n\tif vt.VisibilityPublic(vp) && allowPublic {\n\t\treturn &publicPlacement{}\n\t}\n\tif allowPrivate && !vp.IsEmpty() {\n\t\treturn &privatePlacement{partyCode: vp.GetOneParty()}\n\t}\n\treturn &secretPlacement{}\n}\n\n// IsTensorPublic returns true if the tensor is visible to all parties\nfunc (vt *VisibilityTable) IsTensorPublic(tensor *TensorMeta) bool {\n\tvp := vt.TensorVisibleParties(tensor)\n\treturn vt.VisibilityPublic(vp)\n}\n\n// TensorVisibleTo returns true if the tensor is visible to the specified party\nfunc (vt *VisibilityTable) TensorVisibleTo(tensor *TensorMeta, party string) bool {\n\tvp := vt.TensorVisibleParties(tensor)\n\treturn vp.Contains(party)\n}\n\n// UpdateTensorsVisibilityLike increase given tensors‘ visibility according to another registry.\n// This is useful for synchronizing the VisibilityTable with a temporary OverlayVisibilityTable.\nfunc (vt *VisibilityTable) UpdateTensorsVisibilityLike(vr VisibilityRegistry, tensors []*TensorMeta) {\n\tfor _, tensor := range tensors {\n\t\tvt.UpdateVisibility(tensor, vr.TensorVisibleParties(tensor))\n\t}\n}\n\n// OverlayVisibilityTable implements a decorator pattern for VisibilityRegistry\n// It provides a layered visibility system where overlay changes take precedence over base table\n// This allows temporary visibility modifications without affecting the underlying base table\n// This is useful for complex visibility inference scenarios\n//\n// Usage pattern:\n// - Base table contains permanent visibility assignments\n// - Overlay contains temporary/modified visibility for specific tensors\n// - Lookup order: overlay → base table (with cloning to prevent mutation)\ntype OverlayVisibilityTable struct {\n\toverlayVisibility map[int]*VisibleParties\n\tbaseTable         *VisibilityTable\n}\n\nfunc (ovt *OverlayVisibilityTable) TensorVisibleParties(tensor *TensorMeta) *VisibleParties {\n\tif tensor == nil {\n\t\treturn NewVisibleParties(nil)\n\t}\n\tif v, ok := ovt.overlayVisibility[tensor.ID]; ok {\n\t\treturn v\n\t}\n\treturn ovt.baseTable.TensorVisibleParties(tensor).Clone()\n}\n\nfunc (ovt *OverlayVisibilityTable) CommonVisibleParties(tensors []*TensorMeta) *VisibleParties {\n\tif len(tensors) == 0 {\n\t\treturn ovt.PublicVisibility()\n\t}\n\tvis := ovt.TensorVisibleParties(tensors[0])\n\tfor _, tensor := range tensors[1:] {\n\t\tvis = VPIntersection(vis, ovt.TensorVisibleParties(tensor))\n\t}\n\treturn vis\n}\n\nfunc (ovt *OverlayVisibilityTable) UpdateVisibility(tensor *TensorMeta, increment *VisibleParties) {\n\tif tensor == nil || increment == nil {\n\t\treturn\n\t}\n\tvp := ovt.TensorVisibleParties(tensor)\n\tvp.UpdateWith(increment)\n\tovt.overlayVisibility[tensor.ID] = vp\n}\n\nfunc (ovt *OverlayVisibilityTable) PublicVisibility() *VisibleParties {\n\treturn ovt.baseTable.PublicVisibility()\n}\n\nfunc (ovt *OverlayVisibilityTable) IsTensorPublic(tensor *TensorMeta) bool {\n\tvis := ovt.TensorVisibleParties(tensor)\n\treturn ovt.baseTable.VisibilityPublic(vis)\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/visibility_registry_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestNewVisibilityTable(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\tassert.NotNil(t, vt)\n\tassert.Equal(t, parties, vt.allParties)\n\tassert.NotNil(t, vt.tensorsVisibility)\n\tassert.Empty(t, vt.tensorsVisibility)\n}\n\nfunc TestVisibilityTableTensorVisibleParties(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\n\ttensor := &TensorMeta{ID: 1}\n\n\t// Test non-existent tensor returns empty VisibleParties\n\tvis := vt.TensorVisibleParties(tensor)\n\tassert.NotNil(t, vis)\n\tassert.True(t, vis.IsEmpty())\n\n\t// Test after adding visibility\n\tvt.UpdateVisibility(tensor, NewVisibleParties([]string{\"alice\"}))\n\tvis = vt.TensorVisibleParties(tensor)\n\tassert.Equal(t, []string{\"alice\"}, vis.GetParties())\n}\n\nfunc TestVisibilityTableTensorsVisibleParties(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\ttensor1 := &TensorMeta{ID: 1}\n\ttensor2 := &TensorMeta{ID: 2}\n\ttensor3 := &TensorMeta{ID: 3}\n\n\t// Test empty slice\n\tvis := vt.CommonVisibleParties([]*TensorMeta{})\n\tassert.True(t, vt.VisibilityPublic(vis))\n\n\t// Test single tensor\n\tvt.UpdateVisibility(tensor1, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tvis = vt.CommonVisibleParties([]*TensorMeta{tensor1})\n\tassert.Equal(t, []string{\"alice\", \"bob\"}, vis.GetParties())\n\n\t// Test multiple tensors with intersection\n\tvt.UpdateVisibility(tensor2, NewVisibleParties([]string{\"bob\", \"carol\"}))\n\tvt.UpdateVisibility(tensor3, NewVisibleParties([]string{\"bob\"}))\n\n\tvis = vt.CommonVisibleParties([]*TensorMeta{tensor1, tensor2, tensor3})\n\tassert.Equal(t, []string{\"bob\"}, vis.GetParties())\n}\n\nfunc TestVisibilityTableUpdateVisibility(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\n\ttensor := &TensorMeta{ID: 1}\n\n\t// Test basic update\n\tvt.UpdateVisibility(tensor, NewVisibleParties([]string{\"alice\"}))\n\tvis := vt.TensorVisibleParties(tensor)\n\tassert.Equal(t, []string{\"alice\"}, vis.GetParties())\n\n\t// Test update with increment (merge)\n\tvt.UpdateVisibility(tensor, NewVisibleParties([]string{\"bob\"}))\n\tvis = vt.TensorVisibleParties(tensor)\n\tassert.ElementsMatch(t, []string{\"alice\", \"bob\"}, vis.GetParties())\n\n\t// Test nil tensor (should not panic)\n\tvt.UpdateVisibility(nil, NewVisibleParties([]string{\"alice\"}))\n\n\t// Test nil increment (should not panic)\n\tvt.UpdateVisibility(tensor, nil)\n\n\t// Verify no changes after nil inputs\n\tvis = vt.TensorVisibleParties(tensor)\n\tassert.ElementsMatch(t, []string{\"alice\", \"bob\"}, vis.GetParties())\n}\n\nfunc TestVisibilityTablePublicVisibility(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\tpublic := vt.PublicVisibility()\n\tassert.ElementsMatch(t, parties, public.GetParties())\n}\n\nfunc TestVisibilityTableIsTensorPublic(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\ttensor := &TensorMeta{ID: 1}\n\n\t// Test non-public tensor\n\tvt.UpdateVisibility(tensor, NewVisibleParties([]string{\"alice\"}))\n\tassert.False(t, vt.IsTensorPublic(tensor))\n\n\t// Test public tensor\n\tvt.UpdateVisibility(tensor, NewVisibleParties(parties))\n\tassert.True(t, vt.IsTensorPublic(tensor))\n\n\t// Test empty visibility\n\temptyTensor := &TensorMeta{ID: 2}\n\tassert.False(t, vt.IsTensorPublic(emptyTensor))\n}\n\nfunc TestVisibilityTableTryUpdateVisibility(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\n\ttensor := &TensorMeta{ID: 1}\n\n\t// Test first update (should return true)\n\tupdated := vt.TryUpdateVisibility(tensor, NewVisibleParties([]string{\"alice\"}))\n\tassert.True(t, updated)\n\tassert.Equal(t, []string{\"alice\"}, vt.TensorVisibleParties(tensor).GetParties())\n\n\t// Test redundant update (should return false)\n\tupdated = vt.TryUpdateVisibility(tensor, NewVisibleParties([]string{\"alice\"}))\n\tassert.False(t, updated)\n\tassert.Equal(t, []string{\"alice\"}, vt.TensorVisibleParties(tensor).GetParties())\n\n\t// Test update with new party (should return true)\n\tupdated = vt.TryUpdateVisibility(tensor, NewVisibleParties([]string{\"bob\"}))\n\tassert.True(t, updated)\n\tassert.ElementsMatch(t, []string{\"alice\", \"bob\"}, vt.TensorVisibleParties(tensor).GetParties())\n}\n\nfunc TestVisibilityTableVisibilityPublic(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Test public visibility\n\tpublic := NewVisibleParties(parties)\n\tassert.True(t, vt.VisibilityPublic(public))\n\n\t// Test partial visibility\n\tpartial := NewVisibleParties([]string{\"alice\", \"bob\"})\n\tassert.False(t, vt.VisibilityPublic(partial))\n\n\t// Test empty visibility\n\tempty := NewVisibleParties([]string{})\n\tassert.False(t, vt.VisibilityPublic(empty))\n\n\t// Test nil visibility\n\tassert.False(t, vt.VisibilityPublic(nil))\n}\n\nfunc TestVisibilityTableTensorRegistered(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\n\ttensor := &TensorMeta{ID: 1}\n\n\t// Test unregistered tensor\n\tassert.False(t, vt.TensorRegistered(tensor))\n\n\t// Test registered tensor\n\tvt.UpdateVisibility(tensor, NewVisibleParties([]string{\"alice\"}))\n\tassert.True(t, vt.TensorRegistered(tensor))\n}\n\nfunc TestVisibilityTableTensorVisibleTo(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tvt := NewVisibilityTable(parties)\n\n\ttensor := &TensorMeta{ID: 1}\n\tvt.UpdateVisibility(tensor, NewVisibleParties([]string{\"alice\", \"bob\"}))\n\tassert.True(t, vt.TensorVisibleTo(tensor, \"alice\"))\n\tassert.True(t, vt.TensorVisibleTo(tensor, \"bob\"))\n\tassert.False(t, vt.TensorVisibleTo(tensor, \"carol\"))\n}\n\nfunc TestOverlayVisibilityTableBasic(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\"}\n\tbase := NewVisibilityTable(parties)\n\n\t// Create overlay\n\toverlay := &OverlayVisibilityTable{\n\t\toverlayVisibility: make(map[int]*VisibleParties),\n\t\tbaseTable:         base,\n\t}\n\n\ttensor := &TensorMeta{ID: 1}\n\n\t// Test falls back to base table\n\tbase.UpdateVisibility(tensor, NewVisibleParties([]string{\"alice\"}))\n\tvis := overlay.TensorVisibleParties(tensor)\n\tassert.Equal(t, []string{\"alice\"}, vis.GetParties())\n\n\t// Test update with OverlayVibilityTable\n\toverlay.UpdateVisibility(tensor, NewVisibleParties([]string{\"bob\"}))\n\tvis = overlay.TensorVisibleParties(tensor)\n\tassert.Equal(t, []string{\"alice\", \"bob\"}, vis.GetParties())\n\n\t// Base table unchanged\n\tvis = base.TensorVisibleParties(tensor)\n\tassert.Equal(t, []string{\"alice\"}, vis.GetParties())\n}\n\nfunc TestOverlayVisibilityTablePublicVisibility(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\"}\n\tbase := NewVisibilityTable(parties)\n\n\toverlay := &OverlayVisibilityTable{\n\t\toverlayVisibility: make(map[int]*VisibleParties),\n\t\tbaseTable:         base,\n\t}\n\n\t// Public visibility comes from base table\n\tpublic := overlay.PublicVisibility()\n\tassert.ElementsMatch(t, parties, public.GetParties())\n}\n\nfunc TestOverlayVisibilityTableIsTensorPublic(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tbase := NewVisibilityTable(parties)\n\n\toverlay := &OverlayVisibilityTable{\n\t\toverlayVisibility: make(map[int]*VisibleParties),\n\t\tbaseTable:         base,\n\t}\n\n\ttensor := &TensorMeta{ID: 1}\n\n\t// Test with overlay visibility\n\toverlay.UpdateVisibility(tensor, NewVisibleParties(parties))\n\tassert.True(t, overlay.IsTensorPublic(tensor))\n\n\t// Test with base table visibility\n\toverlay.overlayVisibility = make(map[int]*VisibleParties) // clear overlay\n\tbase.UpdateVisibility(tensor, NewVisibleParties(parties))\n\tassert.True(t, overlay.IsTensorPublic(tensor))\n}\n\nfunc TestUpdateTensorsVisibilityLike(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\"}\n\tsource := NewVisibilityTable(parties)\n\ttarget := NewVisibilityTable(parties)\n\n\ttensors := []*TensorMeta{\n\t\t{ID: 1},\n\t\t{ID: 2},\n\t\t{ID: 3},\n\t}\n\n\t// Set up source visibility\n\tsource.UpdateVisibility(tensors[0], NewVisibleParties([]string{\"alice\"}))\n\tsource.UpdateVisibility(tensors[1], NewVisibleParties([]string{\"bob\"}))\n\tsource.UpdateVisibility(tensors[2], NewVisibleParties([]string{\"alice\", \"bob\"}))\n\n\t// Set up target visibility\n\ttarget.UpdateVisibility(tensors[1], NewVisibleParties([]string{\"alice\"}))\n\n\t// Increase visibility\n\ttarget.UpdateTensorsVisibilityLike(source, tensors)\n\n\t// Check updated visibility\n\tassert.Equal(t, []string{\"alice\"}, target.TensorVisibleParties(tensors[0]).GetParties())\n\tassert.Equal(t, []string{\"alice\", \"bob\"}, target.TensorVisibleParties(tensors[1]).GetParties())\n\tassert.Equal(t, []string{\"alice\", \"bob\"}, target.TensorVisibleParties(tensors[2]).GetParties())\n\n}\n\nfunc TestEdgeCases(t *testing.T) {\n\tparties := []string{\"alice\", \"bob\"}\n\tvt := NewVisibilityTable(parties)\n\n\t// Test nil tensor inputs\n\tvt.UpdateVisibility(nil, NewVisibleParties([]string{\"alice\"})) // Should not panic\n\tassert.False(t, vt.IsTensorPublic(nil))                        // Should not panic\n\n\t// Test empty parties\n\temptyVT := NewVisibilityTable([]string{})\n\temptyPublic := emptyVT.PublicVisibility()\n\tassert.True(t, emptyPublic.IsEmpty())\n\n\t// Test with nil VisibleParties\n\tvt.UpdateVisibility(&TensorMeta{ID: 1}, nil) // Should not panic\n\tvis := vt.TensorVisibleParties(&TensorMeta{ID: 1})\n\tassert.True(t, vis.IsEmpty())\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/visibility_solver.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/compiler/util\"\n)\n\ntype VisibilitySolver struct {\n\tvt                 *VisibilityTable // keep track of tensor visibility\n\tsrm                *SecurityRelaxationManager\n\toriginalVisibility map[string]*VisibleParties // original visibility for tensor get from data source\n\tspecifiedVis       map[int]*VisibleParties    // tensor visibility specified by user\n\tproducerTracker    *TensorProducerTracker\n\tconsumerTracker    *TensorConsumerTracker\n\treverseInfer       bool // whether to enable reverse inference\n}\n\nfunc NewVisibilitySolver(vt *VisibilityTable, srm *SecurityRelaxationManager, origVis map[string]*VisibleParties, specifiedVis map[int]*VisibleParties, reverseInfer bool) *VisibilitySolver {\n\treturn &VisibilitySolver{\n\t\tvt:                 vt,\n\t\tsrm:                srm,\n\t\toriginalVisibility: origVis,\n\t\tspecifiedVis:       specifiedVis,\n\t\treverseInfer:       reverseInfer,\n\t}\n}\n\nfunc (vs *VisibilitySolver) Solve(operatorGraph *OperatorGraph) error {\n\tvs.producerTracker = operatorGraph.producerTracker\n\tvs.consumerTracker = operatorGraph.consumerTracker\n\n\tif err := vs.revealResult(operatorGraph); err != nil {\n\t\treturn err\n\t}\n\n\tnodeNum := len(operatorGraph.operators)\n\n\t// Create priority queues with priority functions\n\tpqf := util.NewPriorityQueue(func(node Operator) int {\n\t\treturn nodeNum - node.ID()\n\t})\n\tpqr := util.NewPriorityQueue(func(node Operator) int {\n\t\treturn node.ID()\n\t})\n\n\tfor _, node := range operatorGraph.operators[:len(operatorGraph.operators)-1] {\n\t\tpqf.Enqueue(node)\n\t}\n\n\tfor pqf.Len() > 0 || pqr.Len() > 0 {\n\t\tif pqr.Len() > 0 {\n\t\t\t// Always do reverse inference first rather than forward inference when pqr is not empty\n\t\t\tnode, _ := pqr.Dequeue()\n\t\t\tupdatedTensors, err := node.ReverseInfer(vs)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, tensor := range updatedTensors {\n\t\t\t\tsourceNode, err := operatorGraph.producerTracker.GetProducer(tensor)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tpqr.Enqueue(sourceNode)\n\t\t\t}\n\n\t\t\t// forward infer again\n\t\t\t// We can skip this step for most operators because updatedTensors will be empty for them\n\t\t\t// But this requires us to carefully inspect the reverse inference logic for each operator\n\t\t\t// Furthermore, the reverse inference logic maybe updated in the future.\n\t\t\t// So just always Infer again to make life easier.\n\t\t\tupdatedTensors, err = node.Infer(vs, false)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// Forward infer again if input tensor's visibility updated\n\t\t\tif len(updatedTensors) > 0 {\n\t\t\t\tpqf.Enqueue(node)\n\t\t\t}\n\t\t} else {\n\t\t\tnode, _ := pqf.Dequeue()\n\t\t\tupdatedTensors, err := node.Infer(vs, true)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfor _, tensor := range updatedTensors {\n\t\t\t\tuserNodes := operatorGraph.consumerTracker.GetConsumers(tensor)\n\t\t\t\tfor _, userNode := range userNodes {\n\t\t\t\t\tpqf.Enqueue(userNode)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if tensor's visibility updated not because of the forward inference,\n\t\t\t// then we need to perform reverse inference on that tensor's source node\n\t\t\tupdated := false\n\t\t\tfor _, tensor := range GetNodeOutputs(node) {\n\t\t\t\tif vis, ok := vs.specifiedVis[tensor.ID]; ok {\n\t\t\t\t\tupdated = vs.vt.TryUpdateVisibility(tensor, vis) || updated\n\t\t\t\t}\n\t\t\t}\n\t\t\tif updated && vs.reverseInfer {\n\t\t\t\tpqr.Enqueue(node)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (vs *VisibilitySolver) revealResult(operatorGraph *OperatorGraph) error {\n\tif len(operatorGraph.operators) == 0 {\n\t\treturn fmt.Errorf(\"revealResult: empty operator graph\")\n\t}\n\n\tresultNode, ok := operatorGraph.operators[len(operatorGraph.operators)-1].(*OperatorResult)\n\tif !ok {\n\t\treturn fmt.Errorf(\"revealResult: expect result node, but got %T\", operatorGraph.operators[len(operatorGraph.operators)-1])\n\t}\n\n\tif resultNode.intoOpt == nil {\n\t\tfor _, tensor := range GetNodeInputs(resultNode) {\n\t\t\tif vs.reverseInfer {\n\t\t\t\tvs.specifiedVis[tensor.ID] = NewVisibleParties([]string{resultNode.issuerPartyCode})\n\t\t\t} else {\n\t\t\t\tvs.vt.UpdateVisibility(tensor, NewVisibleParties([]string{resultNode.issuerPartyCode}))\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\n\tfor _, partyFile := range resultNode.intoOpt.Opt.PartyFiles {\n\t\tvisIncreament := NewVisibleParties([]string{partyFile.PartyCode})\n\t\tif len(partyFile.FieldList) == 0 {\n\t\t\tfor _, tensor := range GetNodeInputs(resultNode) {\n\t\t\t\tif vs.reverseInfer {\n\t\t\t\t\tvs.vt.UpdateVisibility(tensor, visIncreament)\n\t\t\t\t\tvs.specifiedVis[tensor.ID] = vs.vt.TensorVisibleParties(tensor)\n\t\t\t\t} else {\n\t\t\t\t\tvs.vt.UpdateVisibility(tensor, visIncreament)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor idx, col := range resultNode.intoOpt.PartyColumns[partyFile.PartyCode] {\n\t\t\t\ttensor, ok := resultNode.resultTable[col.UniqueID]\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"revealResult: result tensor %d not found\", idx)\n\t\t\t\t}\n\t\t\t\tif vs.reverseInfer {\n\t\t\t\t\tvs.specifiedVis[tensor.ID] = visIncreament\n\t\t\t\t} else {\n\t\t\t\t\tvs.vt.UpdateVisibility(tensor, visIncreament)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (vs *VisibilitySolver) handleRunSQL(n *OperatorRunSQL) error {\n\tfor _, node := range n.subGraphNodes {\n\t\t_, err := node.Infer(vs, false)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (vs *VisibilitySolver) NewOverlayVisibilityTable() *OverlayVisibilityTable {\n\treturn &OverlayVisibilityTable{\n\t\toverlayVisibility: make(map[int]*VisibleParties),\n\t\tbaseTable:         vs.vt,\n\t}\n}\n\nfunc (vs *VisibilitySolver) outputVisSnapshot(node Operator) map[int]*VisibleParties {\n\tsnapshot := make(map[int]*VisibleParties)\n\tfor _, tensor := range GetNodeOutputs(node) {\n\t\tsnapshot[tensor.ID] = vs.vt.TensorVisibleParties(tensor).Clone()\n\t}\n\treturn snapshot\n}\n\nfunc (vs *VisibilitySolver) getUpdatedTensors(node Operator, snapshot map[int]*VisibleParties) []*TensorMeta {\n\tupdatedTensors := make([]*TensorMeta, 0)\n\tfor _, tensor := range GetNodeOutputs(node) {\n\t\toriginVis, ok := snapshot[tensor.ID]\n\t\tif !ok {\n\t\t\tupdatedTensors = append(updatedTensors, tensor)\n\t\t\tcontinue\n\t\t}\n\t\tupdatedVis := vs.vt.TensorVisibleParties(tensor)\n\t\tif !originVis.Covers(updatedVis) {\n\t\t\tupdatedTensors = append(updatedTensors, tensor)\n\t\t}\n\t}\n\treturn updatedTensors\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/visibility_solver_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n)\n\ntype mockOperator struct {\n\tbaseOperator\n\tinputs         []*TensorMeta\n\toutputs        []*TensorMeta\n\tinferErr       error\n\treverseErr     error\n\tupdated        []*TensorMeta\n\treverseUpdated []*TensorMeta\n}\n\nfunc (m *mockOperator) InferVis(vr VisibilityRegistry) error {\n\treturn nil\n}\nfunc (m *mockOperator) InferCSR(csr ColumnSecurityRelaxation, tvc TensorVisibilityChecker) error {\n\treturn nil\n}\nfunc (m *mockOperator) Infer(vs *VisibilitySolver, applySecurityRelaxation bool) ([]*TensorMeta, error) {\n\tfor _, tensor := range m.updated {\n\t\tvs.vt.UpdateVisibility(tensor, vs.vt.PublicVisibility())\n\t}\n\treturn m.updated, m.inferErr\n}\nfunc (m *mockOperator) ReverseInfer(vs *VisibilitySolver) ([]*TensorMeta, error) {\n\tfor _, tensor := range m.reverseUpdated {\n\t\tvs.vt.UpdateVisibility(tensor, vs.vt.PublicVisibility())\n\t}\n\treturn m.reverseUpdated, m.reverseErr\n}\nfunc (m *mockOperator) Inputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\"input\": m.inputs}\n}\nfunc (m *mockOperator) Outputs() map[string][]*TensorMeta {\n\treturn map[string][]*TensorMeta{\"output\": m.outputs}\n}\nfunc (m *mockOperator) Attrs() map[string]any { return nil }\nfunc (m *mockOperator) String() string        { return \"\" }\n\nfunc TestVisibilitySolverSolve(t *testing.T) {\n\n\ttests := []struct {\n\t\tname    string\n\t\tsetup   func() (*OperatorGraph, *VisibilityTable)\n\t\treverse bool\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname: \"empty graph\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilityTable) {\n\t\t\t\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\t\t\t\tgraph := &OperatorGraph{}\n\t\t\t\treturn graph, vt\n\t\t\t},\n\t\t\treverse: false,\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"forward only\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilityTable) {\n\t\t\t\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\n\t\t\t\tproducerTracker := &TensorProducerTracker{}\n\t\t\t\tconsumerTracker := &TensorConsumerTracker{}\n\n\t\t\t\ttensor1 := &TensorMeta{ID: 1}\n\t\t\t\tvt.UpdateVisibility(tensor1, NewVisibleParties([]string{\"bob\"}))\n\n\t\t\t\top1 := &mockOperator{outputs: []*TensorMeta{tensor1}}\n\t\t\t\tproducerTracker.SetProducer(tensor1, op1)\n\t\t\t\top1.updated = []*TensorMeta{tensor1}\n\n\t\t\t\top2 := &OperatorResult{issuerPartyCode: \"alice\", resultTensors: []*TensorMeta{tensor1}}\n\t\t\t\tconsumerTracker.AddConsumer(tensor1, op2)\n\n\t\t\t\tgraph := &OperatorGraph{\n\t\t\t\t\toperators:       []Operator{op1, op2},\n\t\t\t\t\tproducerTracker: producerTracker,\n\t\t\t\t\tconsumerTracker: consumerTracker,\n\t\t\t\t}\n\t\t\t\treturn graph, vt\n\t\t\t},\n\t\t\treverse: false,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"reverse enabled\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilityTable) {\n\t\t\t\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\n\t\t\t\tproducerTracker := &TensorProducerTracker{}\n\t\t\t\tconsumerTracker := &TensorConsumerTracker{}\n\n\t\t\t\ttensor1 := &TensorMeta{ID: 1}\n\t\t\t\ttensor2 := &TensorMeta{ID: 2}\n\t\t\t\ttensor3 := &TensorMeta{ID: 3}\n\n\t\t\t\t// Configure visibility for all tensors\n\t\t\t\tvt.UpdateVisibility(tensor1, NewVisibleParties([]string{\"alice\"}))\n\t\t\t\tvt.UpdateVisibility(tensor2, NewVisibleParties([]string{\"bob\"}))\n\n\t\t\t\top1 := &mockOperator{outputs: []*TensorMeta{tensor1, tensor2}}\n\t\t\t\tproducerTracker.SetProducer(tensor1, op1)\n\t\t\t\tproducerTracker.SetProducer(tensor2, op1)\n\n\t\t\t\top2 := &mockOperator{inputs: []*TensorMeta{tensor1, tensor2}, outputs: []*TensorMeta{tensor3}}\n\t\t\t\tproducerTracker.SetProducer(tensor3, op2)\n\t\t\t\tconsumerTracker.AddConsumer(tensor1, op2)\n\t\t\t\tconsumerTracker.AddConsumer(tensor2, op2)\n\t\t\t\top2.reverseUpdated = []*TensorMeta{tensor1}\n\n\t\t\t\top3 := &OperatorResult{issuerPartyCode: \"alice\", resultTensors: []*TensorMeta{tensor3}}\n\t\t\t\tconsumerTracker.AddConsumer(tensor3, op3)\n\n\t\t\t\tgraph := &OperatorGraph{\n\t\t\t\t\toperators:       []Operator{op1, op2, op3},\n\t\t\t\t\tproducerTracker: producerTracker,\n\t\t\t\t\tconsumerTracker: consumerTracker,\n\t\t\t\t}\n\t\t\t\treturn graph, vt\n\t\t\t},\n\t\t\treverse: true,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"infer error\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilityTable) {\n\t\t\t\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\n\t\t\t\tproducerTracker := &TensorProducerTracker{}\n\t\t\t\tconsumerTracker := &TensorConsumerTracker{}\n\n\t\t\t\ttensor1 := &TensorMeta{ID: 1}\n\t\t\t\ttensor2 := &TensorMeta{ID: 2}\n\n\t\t\t\tvt.UpdateVisibility(tensor1, NewVisibleParties([]string{\"alice\"}))\n\n\t\t\t\top1 := &mockOperator{outputs: []*TensorMeta{tensor1}}\n\t\t\t\tproducerTracker.SetProducer(tensor1, op1)\n\n\t\t\t\top2 := &mockOperator{\n\t\t\t\t\tinputs:   []*TensorMeta{tensor1},\n\t\t\t\t\toutputs:  []*TensorMeta{tensor2},\n\t\t\t\t\tinferErr: fmt.Errorf(\"infer error\"),\n\t\t\t\t}\n\t\t\t\tproducerTracker.SetProducer(tensor2, op2)\n\t\t\t\tconsumerTracker.AddConsumer(tensor1, op2)\n\n\t\t\t\top3 := &OperatorResult{issuerPartyCode: \"alice\", resultTensors: []*TensorMeta{tensor2}}\n\t\t\t\tconsumerTracker.AddConsumer(tensor2, op3)\n\n\t\t\t\tgraph := &OperatorGraph{\n\t\t\t\t\toperators:       []Operator{op1, op2, op3},\n\t\t\t\t\tproducerTracker: producerTracker,\n\t\t\t\t\tconsumerTracker: consumerTracker,\n\t\t\t\t}\n\t\t\t\treturn graph, vt\n\t\t\t},\n\t\t\treverse: false,\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"reverse error\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilityTable) {\n\t\t\t\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\n\t\t\t\tproducerTracker := &TensorProducerTracker{}\n\t\t\t\tconsumerTracker := &TensorConsumerTracker{}\n\n\t\t\t\ttensor1 := &TensorMeta{ID: 1}\n\t\t\t\ttensor2 := &TensorMeta{ID: 2}\n\t\t\t\ttensor3 := &TensorMeta{ID: 3}\n\n\t\t\t\tvt.UpdateVisibility(tensor1, NewVisibleParties([]string{\"alice\"}))\n\t\t\t\tvt.UpdateVisibility(tensor2, NewVisibleParties([]string{\"bob\"}))\n\n\t\t\t\top1 := &mockOperator{outputs: []*TensorMeta{tensor1, tensor2}}\n\t\t\t\tproducerTracker.SetProducer(tensor1, op1)\n\t\t\t\tproducerTracker.SetProducer(tensor2, op1)\n\n\t\t\t\top2 := &mockOperator{\n\t\t\t\t\tinputs:     []*TensorMeta{tensor1, tensor2},\n\t\t\t\t\toutputs:    []*TensorMeta{tensor3},\n\t\t\t\t\treverseErr: fmt.Errorf(\"reverse error\"),\n\t\t\t\t}\n\t\t\t\tproducerTracker.SetProducer(tensor3, op2)\n\t\t\t\tconsumerTracker.AddConsumer(tensor1, op2)\n\t\t\t\tconsumerTracker.AddConsumer(tensor2, op2)\n\n\t\t\t\top3 := &OperatorResult{issuerPartyCode: \"alice\", resultTensors: []*TensorMeta{tensor3}}\n\t\t\t\tconsumerTracker.AddConsumer(tensor3, op3)\n\n\t\t\t\tgraph := &OperatorGraph{\n\t\t\t\t\toperators:       []Operator{op1, op2, op3},\n\t\t\t\t\tproducerTracker: producerTracker,\n\t\t\t\t\tconsumerTracker: consumerTracker,\n\t\t\t\t}\n\t\t\t\treturn graph, vt\n\t\t\t},\n\t\t\treverse: true,\n\t\t\twantErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgraph, vt := tt.setup()\n\n\t\t\tsrm := NewSecurityRelaxationManager(&GlobalSecurityRelaxation{}, map[string][]string{})\n\t\t\tvs := NewVisibilitySolver(vt, srm, nil, make(map[int]*VisibleParties), tt.reverse)\n\n\t\t\terr := vs.Solve(graph)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"Solve() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestRevealResult(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\tsetup   func() (*OperatorGraph, *VisibilitySolver)\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname: \"empty graph\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilitySolver) {\n\t\t\t\tgraph := &OperatorGraph{operators: []Operator{}}\n\t\t\t\tvs := NewVisibilitySolver(NewVisibilityTable([]string{\"alice\"}), nil, nil, nil, false)\n\t\t\t\treturn graph, vs\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid last node\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilitySolver) {\n\t\t\t\tgraph := &OperatorGraph{operators: []Operator{&mockOperator{}}}\n\t\t\t\tvs := NewVisibilitySolver(NewVisibilityTable([]string{\"alice\"}), nil, nil, nil, false)\n\t\t\t\treturn graph, vs\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"result node with nil intoOpt\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilitySolver) {\n\t\t\t\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\t\t\t\tresultNode := &OperatorResult{\n\t\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t\t\tresultTensors:   []*TensorMeta{{ID: 1}},\n\t\t\t\t}\n\t\t\t\tgraph := &OperatorGraph{operators: []Operator{resultNode}}\n\t\t\t\tvs := NewVisibilitySolver(vt, nil, nil, make(map[int]*VisibleParties), false)\n\t\t\t\treturn graph, vs\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"result node with intoOpt and empty field list\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilitySolver) {\n\t\t\t\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\t\t\t\tresultNode := &OperatorResult{\n\t\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t\t\tresultTensors:   []*TensorMeta{{ID: 1}},\n\t\t\t\t\tintoOpt: &core.IntoOpt{\n\t\t\t\t\t\tOpt: &ast.SelectIntoOption{\n\t\t\t\t\t\t\tTp: ast.SelectIntoDumpfile,\n\t\t\t\t\t\t\tPartyFiles: []*ast.PartyFile{\n\t\t\t\t\t\t\t\t{PartyCode: \"alice\", FieldList: []*ast.SelectField{}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPartyColumns: map[string][]*expression.Column{\n\t\t\t\t\t\t\t\"alice\": {},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tgraph := &OperatorGraph{operators: []Operator{resultNode}}\n\t\t\t\tvs := NewVisibilitySolver(vt, nil, nil, make(map[int]*VisibleParties), false)\n\t\t\t\treturn graph, vs\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"result node with intoOpt and field list\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilitySolver) {\n\t\t\t\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\t\t\t\ttensor := &TensorMeta{ID: 1}\n\t\t\t\tcol := &expression.Column{UniqueID: 1}\n\t\t\t\tresultNode := &OperatorResult{\n\t\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t\t\tresultTensors:   []*TensorMeta{tensor},\n\t\t\t\t\tresultTable:     map[int64]*TensorMeta{1: tensor},\n\t\t\t\t\tintoOpt: &core.IntoOpt{\n\t\t\t\t\t\tOpt: &ast.SelectIntoOption{\n\t\t\t\t\t\t\tTp: ast.SelectIntoDumpfile,\n\t\t\t\t\t\t\tPartyFiles: []*ast.PartyFile{\n\t\t\t\t\t\t\t\t{PartyCode: \"alice\", FieldList: []*ast.SelectField{\n\t\t\t\t\t\t\t\t\t{Expr: &ast.ColumnNameExpr{Name: &ast.ColumnName{Name: model.NewCIStr(\"col1\")}}},\n\t\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPartyColumns: map[string][]*expression.Column{\n\t\t\t\t\t\t\t\"alice\": {col},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tgraph := &OperatorGraph{operators: []Operator{resultNode}}\n\t\t\t\tvs := NewVisibilitySolver(vt, nil, nil, make(map[int]*VisibleParties), false)\n\t\t\t\treturn graph, vs\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"result node with missing column\",\n\t\t\tsetup: func() (*OperatorGraph, *VisibilitySolver) {\n\t\t\t\tvt := NewVisibilityTable([]string{\"alice\", \"bob\"})\n\t\t\t\tcol := &expression.Column{UniqueID: 2} // Different from tensor ID\n\t\t\t\tresultNode := &OperatorResult{\n\t\t\t\t\tissuerPartyCode: \"alice\",\n\t\t\t\t\tresultTensors:   []*TensorMeta{{ID: 1}},\n\t\t\t\t\tresultTable:     map[int64]*TensorMeta{}, // Empty table\n\t\t\t\t\tintoOpt: &core.IntoOpt{\n\t\t\t\t\t\tOpt: &ast.SelectIntoOption{\n\t\t\t\t\t\t\tTp: ast.SelectIntoDumpfile,\n\t\t\t\t\t\t\tPartyFiles: []*ast.PartyFile{\n\t\t\t\t\t\t\t\t{PartyCode: \"alice\", FieldList: []*ast.SelectField{{Expr: &ast.ColumnNameExpr{Name: &ast.ColumnName{Name: model.NewCIStr(\"col1\")}}}}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPartyColumns: map[string][]*expression.Column{\n\t\t\t\t\t\t\t\"alice\": {col}, // Column not in resultTable\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tgraph := &OperatorGraph{operators: []Operator{resultNode}}\n\t\t\t\tvs := NewVisibilitySolver(vt, nil, nil, make(map[int]*VisibleParties), false)\n\t\t\t\treturn graph, vs\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgraph, vs := tt.setup()\n\t\t\terr := vs.revealResult(graph)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"revealResult() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/visible_parties.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"slices\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n)\n\ntype VisibleParties struct {\n\tparties []string\n}\n\nfunc NewVisibleParties(parties []string) *VisibleParties {\n\treturn &VisibleParties{\n\t\tparties: sliceutil.SliceDeDup(parties),\n\t}\n}\n\nfunc (vp *VisibleParties) String() string {\n\tif vp == nil {\n\t\treturn \"\"\n\t}\n\treturn strings.Join(vp.parties, \",\")\n}\n\nfunc (vp *VisibleParties) Clone() *VisibleParties {\n\tif vp == nil {\n\t\treturn nil\n\t}\n\treturn &VisibleParties{\n\t\tparties: append([]string{}, vp.parties...),\n\t}\n}\n\nfunc (vp *VisibleParties) Contains(party string) bool {\n\tif vp == nil {\n\t\treturn false\n\t}\n\treturn slices.Contains(vp.parties, party)\n}\n\n// Covers returns true if this VisibleParties contains all parties present in other.\n// Returns false if other contains any party not present in this instance.\n// Returns false if either VisibleParties is nil.\nfunc (vp *VisibleParties) Covers(other *VisibleParties) bool {\n\tif vp == nil || other == nil {\n\t\treturn false\n\t}\n\tfor _, party := range other.parties {\n\t\tif !vp.Contains(party) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (vp *VisibleParties) IsEmpty() bool {\n\tif vp == nil {\n\t\treturn true\n\t}\n\treturn len(vp.parties) == 0\n}\n\nfunc (vp *VisibleParties) GetParties() []string {\n\tif vp == nil {\n\t\treturn nil\n\t}\n\treturn append([]string{}, vp.parties...)\n}\n\n// GetOneParty returns the first party from the list, or empty string if no parties exist.\n// The order is not guaranteed unless the list has been sorted.\nfunc (vp *VisibleParties) GetOneParty() string {\n\tif vp == nil || len(vp.parties) == 0 {\n\t\treturn \"\"\n\t}\n\treturn vp.parties[0]\n}\n\n// AddParty adds a party to the list if it doesn't already exist.\nfunc (vp *VisibleParties) AddParty(party string) {\n\tif vp == nil {\n\t\treturn\n\t}\n\tif !slices.Contains(vp.parties, party) {\n\t\tvp.parties = append(vp.parties, party)\n\t}\n}\n\n// UpdateWith merges all parties from increment into thisVisibleParties.\n// Duplicate parties are filtered out and the final list is sorted alphabetically.\nfunc (vp *VisibleParties) UpdateWith(increment *VisibleParties) {\n\tif vp == nil || increment == nil {\n\t\treturn\n\t}\n\tfor _, party := range increment.parties {\n\t\tvp.AddParty(party)\n\t}\n\tsort.Strings(vp.parties)\n}\n\nfunc (vp *VisibleParties) CopyFrom(ref *VisibleParties) {\n\tif vp == nil {\n\t\treturn\n\t}\n\tif ref == nil {\n\t\tvp.parties = nil\n\t\treturn\n\t}\n\tvp.parties = append([]string{}, ref.parties...)\n}\n\nfunc VPIntersection(a, b *VisibleParties) *VisibleParties {\n\tif a == nil || b == nil {\n\t\treturn NewVisibleParties(nil)\n\t}\n\treturn NewVisibleParties(sliceutil.Intersection(a.parties, b.parties))\n}\n"
  },
  {
    "path": "pkg/interpreter/compiler/visible_parties_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestNewVisibleParties(t *testing.T) {\n\t// Test with duplicates\n\tparties := NewVisibleParties([]string{\"alice\", \"bob\", \"alice\", \"carol\"})\n\tassert.Equal(t, []string{\"alice\", \"bob\", \"carol\"}, parties.GetParties())\n\tassert.Len(t, parties.GetParties(), 3)\n\n\t// Test with empty slice\n\tempty := NewVisibleParties([]string{})\n\tassert.Empty(t, empty.GetParties())\n\n\t// Test with nil slice\n\tnilSlice := NewVisibleParties(nil)\n\tassert.Empty(t, nilSlice.GetParties())\n}\n\nfunc TestVisiblePartiesContains(t *testing.T) {\n\tparties := NewVisibleParties([]string{\"alice\", \"bob\"})\n\tassert.True(t, parties.Contains(\"alice\"))\n\tassert.True(t, parties.Contains(\"bob\"))\n\tassert.False(t, parties.Contains(\"carol\"))\n}\n\nfunc TestVisiblePartiesCovers(t *testing.T) {\n\taliceBob := NewVisibleParties([]string{\"alice\", \"bob\"})\n\talice := NewVisibleParties([]string{\"alice\"})\n\tbobCarol := NewVisibleParties([]string{\"bob\", \"carol\"})\n\n\tassert.True(t, aliceBob.Covers(alice))\n\tassert.False(t, alice.Covers(aliceBob))\n\tassert.False(t, aliceBob.Covers(bobCarol))\n}\n\nfunc TestVisiblePartiesIsEmpty(t *testing.T) {\n\tempty := NewVisibleParties([]string{})\n\tnonEmpty := NewVisibleParties([]string{\"alice\"})\n\n\tassert.True(t, empty.IsEmpty())\n\tassert.False(t, nonEmpty.IsEmpty())\n}\n\nfunc TestVisiblePartiesGetOneParty(t *testing.T) {\n\tparties := NewVisibleParties([]string{\"alice\", \"bob\"})\n\tempty := NewVisibleParties([]string{})\n\n\tassert.Equal(t, \"alice\", parties.GetOneParty())\n\tassert.Equal(t, \"\", empty.GetOneParty())\n}\n\nfunc TestVisiblePartiesAddParty(t *testing.T) {\n\tparties := NewVisibleParties([]string{\"alice\"})\n\tparties.AddParty(\"bob\")\n\tparties.AddParty(\"alice\") // duplicate\n\n\tassert.Equal(t, []string{\"alice\", \"bob\"}, parties.GetParties())\n}\n\nfunc TestVisiblePartiesUpdateWith(t *testing.T) {\n\tbase := NewVisibleParties([]string{\"alice\"})\n\tincrement := NewVisibleParties([]string{\"bob\", \"alice\", \"carol\"})\n\n\tbase.UpdateWith(increment)\n\tassert.Equal(t, []string{\"alice\", \"bob\", \"carol\"}, base.GetParties())\n}\n\nfunc TestVisiblePartiesCopyFrom(t *testing.T) {\n\tsource := NewVisibleParties([]string{\"alice\", \"bob\"})\n\tdest := NewVisibleParties([]string{\"carol\"})\n\n\tdest.CopyFrom(source)\n\tassert.Equal(t, []string{\"alice\", \"bob\"}, dest.GetParties())\n\tassert.NotSame(t, source.GetParties(), dest.GetParties()) // ensure deep copy\n}\n\nfunc TestVisiblePartiesClone(t *testing.T) {\n\toriginal := NewVisibleParties([]string{\"alice\", \"bob\"})\n\tcloned := original.Clone()\n\n\tassert.Equal(t, original.GetParties(), cloned.GetParties())\n\tassert.NotSame(t, original.GetParties(), cloned.GetParties()) // ensure deep copy\n\n\t// Modify original to ensure independence\n\toriginal.AddParty(\"carol\")\n\tassert.Len(t, cloned.GetParties(), 2)\n}\n\nfunc TestVPIntersection(t *testing.T) {\n\ta := NewVisibleParties([]string{\"alice\", \"bob\", \"carol\"})\n\tb := NewVisibleParties([]string{\"bob\", \"carol\", \"dave\"})\n\n\tresult := VPIntersection(a, b)\n\tassert.Equal(t, []string{\"bob\", \"carol\"}, result.GetParties())\n}\n\n// Test nil handling\nfunc TestVisiblePartiesNilHandling(t *testing.T) {\n\tvar nilVP *VisibleParties\n\n\t// Test nil receiver\n\tassert.True(t, nilVP.IsEmpty())\n\tassert.Nil(t, nilVP.GetParties())\n\tassert.Equal(t, \"\", nilVP.GetOneParty())\n\tassert.False(t, nilVP.Contains(\"alice\"))\n\tassert.False(t, nilVP.Covers(NewVisibleParties([]string{\"alice\"})))\n\n\t// Test nil parameters\n\tvp := NewVisibleParties([]string{\"alice\"})\n\tassert.False(t, vp.Covers(nil))\n\tvp.UpdateWith(nil)\n\tassert.Equal(t, []string{\"alice\"}, vp.GetParties())\n\n\t// Test VPIntersection with nil\n\tassert.NotNil(t, VPIntersection(nil, nil))\n\tassert.True(t, VPIntersection(nil, nil).IsEmpty())\n\tassert.True(t, VPIntersection(vp, nil).IsEmpty())\n\tassert.True(t, VPIntersection(nil, vp).IsEmpty())\n\n\t// Test CopyFrom with nil\n\tvp.CopyFrom(nil)\n\tassert.Empty(t, vp.GetParties())\n\n\t// Test Clone with nil\n\tassert.Nil(t, nilVP.Clone())\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/attribute.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// Attribute is the in-memory data structure of proto.Attribute\ntype Attribute struct {\n\tTensorValue *Tensor\n}\n\n// ToString dumps a debug string of the attribute\nfunc (attr *Attribute) ToString() string {\n\tvar builder strings.Builder\n\tfmt.Fprint(&builder, attr.GetAttrValue())\n\treturn builder.String()\n}\n\nfunc (attr *Attribute) SetStrings(v []string) {\n\tattr.TensorValue = &Tensor{\n\t\tStringS: v,\n\t\tDType:   NewPrimitiveDataType(proto.PrimitiveDataType_STRING),\n\t\tShape:   []int{len(v)},\n\t}\n}\n\nfunc (attr *Attribute) GetStrings() ([]string, error) {\n\tif attr.TensorValue == nil || len(attr.TensorValue.StringS) == 0 {\n\t\treturn nil, fmt.Errorf(\"getString: invalid attribute %v\", attr)\n\t}\n\treturn attr.TensorValue.StringS, nil\n}\n\nfunc (attr *Attribute) SetString(v string) {\n\tattr.TensorValue = &Tensor{\n\t\tStringS: []string{v},\n\t\tDType:   NewPrimitiveDataType(proto.PrimitiveDataType_STRING),\n\t}\n}\n\nfunc (attr *Attribute) SetInt(v int) {\n\tattr.TensorValue = &Tensor{\n\t\tInt32S: []int32{int32(v)},\n\t\tDType:  NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t}\n}\n\nfunc (attr *Attribute) SetInt64(v int64) {\n\tattr.TensorValue = &Tensor{\n\t\tInt64S: []int64{v},\n\t\tDType:  NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t}\n}\n\nfunc (attr *Attribute) SetFloat(v float32) {\n\tattr.TensorValue = &Tensor{\n\t\tFloatS: []float32{v},\n\t\tDType:  NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT32),\n\t}\n}\n\nfunc (attr *Attribute) SetDouble(v float64) {\n\tattr.TensorValue = &Tensor{\n\t\tDoubleS: []float64{v},\n\t\tDType:   NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64),\n\t}\n}\n\nfunc (attr *Attribute) SetBool(v bool) {\n\tattr.TensorValue = &Tensor{\n\t\tBooleanS: []bool{v},\n\t\tDType:    NewPrimitiveDataType(proto.PrimitiveDataType_BOOL),\n\t}\n}\n\nfunc (attr *Attribute) SetBools(v []bool) {\n\tattr.TensorValue = &Tensor{\n\t\tBooleanS: v,\n\t\tDType:    NewPrimitiveDataType(proto.PrimitiveDataType_BOOL),\n\t\tShape:    []int{len(v)},\n\t}\n}\n\n// GetAttrValue returns attr value\nfunc (attr *Attribute) GetAttrValue() interface{} {\n\tif attr.TensorValue == nil {\n\t\treturn nil\n\t}\n\tif attr.TensorValue.StringS != nil {\n\t\tif len(attr.TensorValue.Shape) == 0 && len(attr.TensorValue.StringS) == 1 {\n\t\t\treturn attr.TensorValue.StringS[0]\n\t\t}\n\t\treturn attr.TensorValue.StringS\n\t}\n\tif attr.TensorValue.BooleanS != nil {\n\t\tif len(attr.TensorValue.Shape) == 0 && len(attr.TensorValue.BooleanS) == 1 {\n\t\t\treturn attr.TensorValue.BooleanS[0]\n\t\t}\n\t\treturn attr.TensorValue.BooleanS\n\t}\n\tif attr.TensorValue.Int32S != nil {\n\t\tif len(attr.TensorValue.Shape) == 0 && len(attr.TensorValue.Int32S) == 1 {\n\t\t\treturn attr.TensorValue.Int32S[0]\n\t\t}\n\t\treturn attr.TensorValue.Int32S\n\t}\n\tif attr.TensorValue.Int64S != nil {\n\t\tif len(attr.TensorValue.Shape) == 0 && len(attr.TensorValue.Int64S) == 1 {\n\t\t\treturn attr.TensorValue.Int64S[0]\n\t\t}\n\t\treturn attr.TensorValue.Int64S\n\t}\n\tif attr.TensorValue.FloatS != nil {\n\t\tif len(attr.TensorValue.Shape) == 0 && len(attr.TensorValue.FloatS) == 1 {\n\t\t\treturn attr.TensorValue.FloatS[0]\n\t\t}\n\t\treturn attr.TensorValue.FloatS\n\t}\n\tif attr.TensorValue.DoubleS != nil {\n\t\tif len(attr.TensorValue.Shape) == 0 && len(attr.TensorValue.DoubleS) == 1 {\n\t\t\treturn attr.TensorValue.DoubleS[0]\n\t\t}\n\t\treturn attr.TensorValue.DoubleS\n\t}\n\treturn nil\n}\n\nfunc (attr *Attribute) ToProto() *proto.AttributeValue {\n\treturn &proto.AttributeValue{\n\t\tValue: &proto.AttributeValue_T{\n\t\t\tT: attr.TensorValue.ToProto()},\n\t}\n}\n\n// NewStringAttr creates an Attribute with a string value\nfunc NewStringAttr(v string) *Attribute {\n\treturn &Attribute{\n\t\tTensorValue: &Tensor{\n\t\t\tStringS: []string{v},\n\t\t\tDType:   NewPrimitiveDataType(proto.PrimitiveDataType_STRING),\n\t\t},\n\t}\n}\n\n// NewStringsAttr creates an Attribute with a string slice\nfunc NewStringsAttr(v []string) *Attribute {\n\treturn &Attribute{\n\t\tTensorValue: &Tensor{\n\t\t\tStringS: v,\n\t\t\tDType:   NewPrimitiveDataType(proto.PrimitiveDataType_STRING),\n\t\t\tShape:   []int{len(v)},\n\t\t},\n\t}\n}\n\n// NewInt64Attr creates an Attribute with an int64 value\nfunc NewInt64Attr(v int64) *Attribute {\n\treturn &Attribute{\n\t\tTensorValue: &Tensor{\n\t\t\tInt64S: []int64{v},\n\t\t\tDType:  NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t\t},\n\t}\n}\n\n// NewInt32Attr creates an Attribute with an int32 value\nfunc NewInt32Attr(v int32) *Attribute {\n\treturn &Attribute{\n\t\tTensorValue: &Tensor{\n\t\t\tInt32S: []int32{v},\n\t\t\tDType:  NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t\t},\n\t}\n}\n\n// NewFloatAttr creates an Attribute with a float32 value\nfunc NewFloatAttr(v float32) *Attribute {\n\treturn &Attribute{\n\t\tTensorValue: &Tensor{\n\t\t\tFloatS: []float32{v},\n\t\t\tDType:  NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT32),\n\t\t},\n\t}\n}\n\n// NewDoubleAttr creates an Attribute with a float64 value\nfunc NewDoubleAttr(v float64) *Attribute {\n\treturn &Attribute{\n\t\tTensorValue: &Tensor{\n\t\t\tDoubleS: []float64{v},\n\t\t\tDType:   NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64),\n\t\t},\n\t}\n}\n\n// NewBoolAttr creates an Attribute with a boolean value\nfunc NewBoolAttr(v bool) *Attribute {\n\treturn &Attribute{\n\t\tTensorValue: &Tensor{\n\t\t\tBooleanS: []bool{v},\n\t\t\tDType:    NewPrimitiveDataType(proto.PrimitiveDataType_BOOL),\n\t\t},\n\t}\n}\n\n// NewBoolsAttr creates an Attribute with a boolean slice\nfunc NewBoolsAttr(v []bool) *Attribute {\n\treturn &Attribute{\n\t\tTensorValue: &Tensor{\n\t\t\tBooleanS: v,\n\t\t\tDType:    NewPrimitiveDataType(proto.PrimitiveDataType_BOOL),\n\t\t\tShape:    []int{len(v)},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/attribute_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\nfunc TestAttribute(t *testing.T) {\n\ta := assert.New(t)\n\t{\n\t\tattr := &Attribute{}\n\t\tattr.SetString(\"alice\")\n\t\tr1 := attr.GetAttrValue()\n\t\ta.Equal(\"alice\", r1)\n\t}\n\n\t{\n\t\tattr := &Attribute{}\n\t\tattr.SetStrings([]string{\"alice\", \"bob\"})\n\t\tr1 := attr.GetAttrValue()\n\t\ta.Equal([]string{\"alice\", \"bob\"}, r1)\n\t}\n\n\t{\n\t\tattr := &Attribute{}\n\t\tattr.SetBool(true)\n\t\tr1 := attr.GetAttrValue()\n\t\ta.Equal(true, r1)\n\t}\n\n\t{\n\t\tattr := &Attribute{}\n\t\tattr.SetInt(1)\n\t\tpb2 := &proto.AttributeValue_T{\n\t\t\tT: attr.TensorValue.ToProto(),\n\t\t}\n\t\ta.NotNil(pb2)\n\t\ta.Equal(int32(1), attr.GetAttrValue())\n\t}\n\n\t{\n\t\tattr := &Attribute{}\n\t\tattr.SetFloat(1.0)\n\t\tpb2 := &proto.AttributeValue_T{\n\t\t\tT: attr.TensorValue.ToProto(),\n\t\t}\n\t\ta.NotNil(pb2)\n\t\ta.Equal(float32(1.0), attr.GetAttrValue())\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/constant.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\ntype TensorStatus int32\n\nconst (\n\tUnknownStatus TensorStatus = TensorStatus(scql.TensorStatus_TENSORSTATUS_UNKNOWN)\n\tPrivateStatus TensorStatus = TensorStatus(scql.TensorStatus_TENSORSTATUS_PRIVATE)\n\tSecretStatus  TensorStatus = TensorStatus(scql.TensorStatus_TENSORSTATUS_SECRET)\n\tCipherStatus  TensorStatus = TensorStatus(scql.TensorStatus_TENSORSTATUS_CIPHER)\n\tPublicStatus  TensorStatus = TensorStatus(scql.TensorStatus_TENSORSTATUS_PUBLIC)\n)\n\n// input tensors key\nconst (\n\tLeft         string = \"Left\"\n\tRight        string = \"Right\"\n\tCondition    string = \"Condition\"\n\tValueIfTrue  string = \"ValueIfTrue\"\n\tValueIfFalse string = \"ValueIfFalse\"\n\tValue        string = \"Value\"\n\tValueElse    string = \"ValueElse\"\n\tIn           string = \"In\"\n\tOut          string = \"Out\"\n)\n\nconst (\n\tInnerJoin      = 0\n\tLeftOuterJoin  = 1\n\tRightOuterJoin = 2\n)\n\nconst (\n\tPsiIn  = 0\n\tEcdhIn = 1\n\tOprfIn = 2\n)\n"
  },
  {
    "path": "pkg/interpreter/graph/data_type.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/types\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\ntype DataType struct {\n\tDType proto.PrimitiveDataType\n\tScale int32\n\tWidth int32\n}\n\nfunc NewPrimitiveDataType(dtype proto.PrimitiveDataType) *DataType {\n\treturn &DataType{\n\t\tDType: dtype,\n\t\tScale: 0,\n\t\tWidth: 0,\n\t}\n}\nfunc NewDataType(dtype proto.PrimitiveDataType, width, scale int32) *DataType {\n\treturn &DataType{\n\t\tDType: dtype,\n\t\tScale: scale,\n\t\tWidth: width,\n\t}\n}\n\nfunc (dType *DataType) Equal(otherType *DataType) bool {\n\treturn dType.DType == otherType.DType && dType.Scale == otherType.Scale && dType.Width == otherType.Width\n}\n\nfunc (dType *DataType) String() string {\n\tif dType.DType == proto.PrimitiveDataType_DECIMAL {\n\t\treturn fmt.Sprintf(\"%s(%d,%d)\", proto.PrimitiveDataType_name[int32(dType.DType)], dType.Width, dType.Scale)\n\t}\n\treturn proto.PrimitiveDataType_name[int32(dType.DType)]\n}\n\nfunc (dType *DataType) Clone() *DataType {\n\treturn &DataType{\n\t\tDType: dType.DType,\n\t\tScale: dType.Scale,\n\t\tWidth: dType.Width,\n\t}\n}\n\n// for now, support data type: bool/int/float/double/string\nfunc ConvertDataType(typ *types.FieldType) (*DataType, error) {\n\tswitch typ.Tp {\n\tcase mysql.TypeLonglong:\n\t\tif mysql.HasIsBooleanFlag(typ.Flag) {\n\t\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_BOOL), nil\n\t\t}\n\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_INT64), nil\n\tcase mysql.TypeLong, mysql.TypeDuration:\n\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_INT64), nil\n\tcase mysql.TypeString, mysql.TypeVarchar, mysql.TypeVarString:\n\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_STRING), nil\n\tcase mysql.TypeTiny:\n\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_BOOL), nil\n\tcase mysql.TypeFloat:\n\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT32), nil\n\tcase mysql.TypeDouble, mysql.TypeNewDecimal:\n\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64), nil\n\tcase mysql.TypeDatetime, mysql.TypeDate, mysql.TypeYear:\n\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_DATETIME), nil\n\tcase mysql.TypeTimestamp:\n\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_TIMESTAMP), nil\n\t}\n\treturn NewPrimitiveDataType(proto.PrimitiveDataType_PrimitiveDataType_UNDEFINED), fmt.Errorf(\"ConvertDataType doesn't support type %v\", typ.Tp)\n}\n\nvar numericTypes = map[proto.PrimitiveDataType]bool{\n\tproto.PrimitiveDataType_INT8:    true,\n\tproto.PrimitiveDataType_INT16:   true,\n\tproto.PrimitiveDataType_INT32:   true,\n\tproto.PrimitiveDataType_INT64:   true,\n\tproto.PrimitiveDataType_FLOAT32: true,\n\tproto.PrimitiveDataType_FLOAT64: true,\n\tproto.PrimitiveDataType_DECIMAL: true,\n}\nvar integerTypes = map[proto.PrimitiveDataType]bool{\n\tproto.PrimitiveDataType_INT8:  true,\n\tproto.PrimitiveDataType_INT16: true,\n\tproto.PrimitiveDataType_INT32: true,\n\tproto.PrimitiveDataType_INT64: true,\n}\nvar dataTypeIndexMap = map[proto.PrimitiveDataType]int{\n\tproto.PrimitiveDataType_INT8:    0,\n\tproto.PrimitiveDataType_INT16:   1,\n\tproto.PrimitiveDataType_INT32:   2,\n\tproto.PrimitiveDataType_INT64:   3,\n\tproto.PrimitiveDataType_FLOAT32: 4,\n\tproto.PrimitiveDataType_FLOAT64: 5,\n}\n\nfunc (dType *DataType) IsStringType() bool {\n\treturn dType.DType == proto.PrimitiveDataType_STRING\n}\n\nfunc (dType *DataType) IsNumericType() bool {\n\t_, ok := numericTypes[dType.DType]\n\treturn ok\n}\n\nfunc (dType *DataType) IsBoolType() bool {\n\treturn dType.DType == proto.PrimitiveDataType_BOOL\n}\n\nfunc (dType *DataType) IsFloatOrDoubleType() bool {\n\treturn dType.DType == proto.PrimitiveDataType_FLOAT32 || dType.DType == proto.PrimitiveDataType_FLOAT64\n}\n\nfunc (dType *DataType) IsIntegerType() bool {\n\t_, ok := integerTypes[dType.DType]\n\treturn ok\n}\n\nfunc (dType *DataType) IsTimeType() bool {\n\treturn dType.DType == proto.PrimitiveDataType_TIMESTAMP || dType.DType == proto.PrimitiveDataType_DATETIME\n}\n\n// GetWiderType returns the wider type between two numeric types\n// TODO(xiaoyuan): currently only consider INT and FLOAT types, need to reconsider DECIMAL type later\nfunc GetWiderType(dtype1, dtype2 *DataType) (*DataType, error) {\n\tif !dtype1.IsNumericType() {\n\t\treturn nil, fmt.Errorf(\"%v is not numeric type\", dtype1.String())\n\t}\n\tif !dtype2.IsNumericType() {\n\t\treturn nil, fmt.Errorf(\"%v is not numeric type\", dtype2.String())\n\t}\n\n\t// Handle DECIMAL type\n\tif dtype1.DType == proto.PrimitiveDataType_DECIMAL && dtype2.DType == proto.PrimitiveDataType_DECIMAL {\n\t\t// Both are DECIMAL, return the wider one\n\t\twidth := dtype1.Width\n\t\tif dtype2.Width > width {\n\t\t\twidth = dtype2.Width\n\t\t}\n\t\tscale := dtype1.Scale\n\t\tif dtype2.Scale > scale {\n\t\t\tscale = dtype2.Scale\n\t\t}\n\t\treturn NewDataType(proto.PrimitiveDataType_DECIMAL, width, scale), nil\n\t}\n\t// TODO: fix scale and width handling for mixed DECIMAL and other numeric types\n\tif dtype1.DType == proto.PrimitiveDataType_DECIMAL {\n\t\t// One is DECIMAL, the other is another numeric type\n\t\tif dtype2.IsIntegerType() {\n\t\t\t// DECIMAL and integer type, return DECIMAL\n\t\t\treturn dtype1.Clone(), nil\n\t\t} else if dtype2.IsFloatOrDoubleType() {\n\t\t\t// DECIMAL and float type, return float type (wider)\n\t\t\treturn dtype2.Clone(), nil\n\t\t}\n\t}\n\n\tif dtype2.DType == proto.PrimitiveDataType_DECIMAL {\n\t\t// Same as above, symmetric handling\n\t\tif dtype1.IsIntegerType() {\n\t\t\treturn dtype2.Clone(), nil\n\t\t} else if dtype1.IsFloatOrDoubleType() {\n\t\t\treturn dtype1.Clone(), nil\n\t\t}\n\t}\n\n\t// Handle integer types\n\tif dtype1.IsIntegerType() && dtype2.IsIntegerType() {\n\t\tif dataTypeIndexMap[dtype1.DType] > dataTypeIndexMap[dtype2.DType] {\n\t\t\treturn dtype1.Clone(), nil\n\t\t} else {\n\t\t\treturn dtype2.Clone(), nil\n\t\t}\n\t}\n\n\t// Handle float types\n\tif dtype1.IsFloatOrDoubleType() && dtype2.IsFloatOrDoubleType() {\n\t\tif dataTypeIndexMap[dtype1.DType] > dataTypeIndexMap[dtype2.DType] {\n\t\t\treturn dtype1.Clone(), nil\n\t\t} else {\n\t\t\treturn dtype2.Clone(), nil\n\t\t}\n\t}\n\n\t// Handle mixed integer and float types\n\tif (dtype1.IsIntegerType() && dtype2.IsFloatOrDoubleType()) || (dtype1.IsFloatOrDoubleType() && dtype2.IsIntegerType()) {\n\t\tif dtype1.DType == proto.PrimitiveDataType_FLOAT64 || dtype2.DType == proto.PrimitiveDataType_FLOAT64 {\n\t\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64), nil\n\t\t}\n\t\tif dtype1.DType == proto.PrimitiveDataType_INT64 || dtype2.DType == proto.PrimitiveDataType_INT64 {\n\t\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64), nil\n\t\t}\n\t\treturn NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT32), nil\n\t}\n\n\treturn nil, fmt.Errorf(\"unsupported type combination: %v and %v\", dtype1.String(), dtype2.String())\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/engine_info.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n)\n\ntype EnginesInfo struct {\n\tpartyInfo     *PartyInfo\n\tpartyToTables map[string][]core.DbTable\n\ttableToParty  map[core.DbTable]string\n\ttableToRefs   map[core.DbTable]core.DbTable\n\t// Adds a party-level map layer in refToUris to prevent overwriting when refTblName is duplicated across parties.\n\t// e.g. {\"carol\": {\"project001.UPPER_table\": \"domain_id_for_carol_UPPER_table\"}, \"alice\": {\"project001.UPPER_table\": \"domain_id_for_alice_UPPER_table\"}}\n\trefToUris map[string]map[string]string\n}\n\nfunc (h *EnginesInfo) GetPartyInfo() *PartyInfo {\n\treturn h.partyInfo\n}\n\nfunc (h *EnginesInfo) GetParties() []string {\n\treturn h.partyInfo.GetParties()\n}\n\nfunc (h *EnginesInfo) GetUrlByParty(party string) (string, error) {\n\treturn h.partyInfo.GetUrlByParty(party)\n}\n\nfunc (h *EnginesInfo) GetCredentialByParty(party string) (string, error) {\n\treturn h.partyInfo.GetCredentialByParty(party)\n}\n\nfunc (h *EnginesInfo) GetTablesByParty(party string) []core.DbTable {\n\t// if party don't exist in partyInfo just return nil slice\n\treturn h.partyToTables[party]\n}\n\nfunc (h *EnginesInfo) GetPartyByTable(t core.DbTable) string {\n\treturn h.tableToParty[t]\n}\n\nfunc (h *EnginesInfo) GetRefTableName(tableName string) (core.DbTable, error) {\n\tdt, err := core.NewDbTableFromString(tableName)\n\tif err != nil {\n\t\treturn core.DbTable{}, err\n\t}\n\treturn h.tableToRefs[dt], nil\n}\n\nfunc (h *EnginesInfo) GetDbTableMap() map[core.DbTable]core.DbTable {\n\treturn h.tableToRefs\n}\n\nfunc (h *EnginesInfo) String() string {\n\treturn fmt.Sprintf(\"engine infos party info: %+v, tables: %+v\", h.partyInfo, h.partyToTables)\n}\n\nfunc (h *EnginesInfo) UpdateTableToRefs(tableToRefs map[core.DbTable]core.DbTable) {\n\tfor table, ref := range tableToRefs {\n\t\th.tableToRefs[table] = ref\n\t}\n}\n\nfunc (h *EnginesInfo) UpdateRefToUris(refs map[string]map[string]string) {\n\tfor party, refToUris := range refs {\n\t\tif h.refToUris[party] == nil {\n\t\t\th.refToUris[party] = make(map[string]string)\n\t\t}\n\t\tfor ref, uri := range refToUris {\n\t\t\th.refToUris[party][ref] = uri\n\t\t}\n\t}\n}\n\nfunc (h *EnginesInfo) GetUris(party string, refs []string) []string {\n\tvar result []string\n\tfor _, ref := range refs {\n\t\tif id, ok := h.refToUris[party][ref]; ok {\n\t\t\tresult = append(result, id)\n\t\t} else {\n\t\t\tresult = append(result, ref)\n\t\t}\n\t}\n\treturn result\n}\n\nfunc NewEnginesInfo(p *PartyInfo, party2Tables map[string][]core.DbTable) *EnginesInfo {\n\ttable2Party := make(map[core.DbTable]string)\n\tfor p, tables := range party2Tables {\n\t\tfor _, dt := range tables {\n\t\t\ttable2Party[dt] = p\n\t\t}\n\t}\n\treturn &EnginesInfo{\n\t\tpartyInfo:     p,\n\t\tpartyToTables: party2Tables,\n\t\ttableToParty:  table2Party,\n\t\ttableToRefs:   make(map[core.DbTable]core.DbTable),\n\t\trefToUris:     make(map[string]map[string]string),\n\t}\n}\n\ntype Participant struct {\n\tPartyCode string\n\tEndpoints []string\n\tToken     string\n\tPubKey    string\n}\n\ntype PartyInfo struct {\n\tparticipants []*Participant\n}\n\nfunc NewPartyInfo(parties []*Participant) *PartyInfo {\n\treturn &PartyInfo{\n\t\tparticipants: parties,\n\t}\n}\n\nfunc (p *PartyInfo) GetParticipants() []*Participant {\n\treturn p.participants\n}\n\nfunc (pi *PartyInfo) GetParties() []string {\n\tpartyCodes := make([]string, 0, len(pi.participants))\n\tfor _, p := range pi.participants {\n\t\tpartyCodes = append(partyCodes, p.PartyCode)\n\t}\n\treturn partyCodes\n}\n\nfunc (pi *PartyInfo) GetCredentialByParty(party string) (credential string, err error) {\n\tfor _, p := range pi.participants {\n\t\tif p.PartyCode == party {\n\t\t\treturn p.Token, nil\n\t\t}\n\t}\n\treturn \"\", fmt.Errorf(\"no party named %s\", party)\n}\n\nfunc (pi *PartyInfo) GetCredentials() []string {\n\tcredentials := make([]string, 0, len(pi.participants))\n\tfor _, p := range pi.participants {\n\t\tcredentials = append(credentials, p.Token)\n\t}\n\treturn credentials\n}\n\nfunc (pi *PartyInfo) GetUrlByParty(party string) (url string, err error) {\n\tfor _, p := range pi.participants {\n\t\tif p.PartyCode == party {\n\t\t\treturn p.Endpoints[0], nil\n\t\t}\n\t}\n\treturn \"\", fmt.Errorf(\"no party named %s\", party)\n}\n\nfunc (pi *PartyInfo) GetUrls() []string {\n\turls := make([]string, 0, len(pi.participants))\n\tfor _, p := range pi.participants {\n\t\turls = append(urls, p.Endpoints[0])\n\t}\n\treturn urls\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/engine_info_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n)\n\nfunc TestPartyInfos(t *testing.T) {\n\tr := require.New(t)\n\tpartyInfo := NewPartyInfo([]*Participant{\n\t\t{\n\t\t\tPartyCode: \"alice\",\n\t\t\tEndpoints: []string{\"alice.com\"},\n\t\t\tToken:     \"alice_credential\",\n\t\t},\n\t\t{\n\t\t\tPartyCode: \"bob\",\n\t\t\tEndpoints: []string{\"bob.com\"},\n\t\t\tToken:     \"bob_credential\",\n\t\t},\n\t})\n\tr.Equal([]string{\"alice\", \"bob\"}, partyInfo.GetParties())\n\tr.Equal([]string{\"alice.com\", \"bob.com\"}, partyInfo.GetUrls())\n\turl, err := partyInfo.GetUrlByParty(\"alice\")\n\tr.NoError(err)\n\tr.Equal(\"alice.com\", url)\n\turl, err = partyInfo.GetUrlByParty(\"bob\")\n\tr.NoError(err)\n\tr.Equal(\"bob.com\", url)\n\t_, err = partyInfo.GetUrlByParty(\"jojo\")\n\tr.Error(err)\n}\n\nfunc TestEnginesInfo(t *testing.T) {\n\tr := require.New(t)\n\tmockPartyA := &MockPartyAndTableInfos{\n\t\tparty:     \"alice\",\n\t\ttables:    []string{\"dba.ta\", \"dba.tb\"},\n\t\trefTables: []string{\"dbar.tar\", \"dbar.tbr\"},\n\t}\n\tmockPartyB := &MockPartyAndTableInfos{\n\t\tparty:     \"bob\",\n\t\ttables:    []string{\"dbb.ta\", \"dbb.tb\"},\n\t\trefTables: []string{\"dbbr.tar\", \"dbbr.tbr\"},\n\t}\n\tmockEnginesInfo, err := MockEnginesInfo([]*MockPartyAndTableInfos{mockPartyA, mockPartyB})\n\tr.NoError(err)\n\tr.Equal([]string{\"alice\", \"bob\"}, mockEnginesInfo.GetParties())\n\turl, err := mockEnginesInfo.GetUrlByParty(\"alice\")\n\tr.NoError(err)\n\tr.Equal(\"alice.com\", url)\n\turl, err = mockEnginesInfo.GetUrlByParty(\"bob\")\n\tr.NoError(err)\n\tr.Equal(\"bob.com\", url)\n\ttb, err := mockEnginesInfo.GetRefTableName(\"dba.ta\")\n\tr.NoError(err)\n\tr.Equal(core.NewDbTable(\"dbar\", \"tar\"), tb)\n\ttb, err = mockEnginesInfo.GetRefTableName(\"dbb.tb\")\n\tr.NoError(err)\n\tr.Equal(core.NewDbTable(\"dbbr\", \"tbr\"), tb)\n\tr.Equal(2, len(mockEnginesInfo.GetTablesByParty(\"alice\")))\n\tr.Equal(2, len(mockEnginesInfo.GetTablesByParty(\"bob\")))\n\tr.Equal(\"alice\", mockEnginesInfo.GetPartyByTable(core.NewDbTable(\"dbar\", \"tar\")))\n\tr.Equal(\"bob\", mockEnginesInfo.GetPartyByTable(core.NewDbTable(\"dbbr\", \"tbr\")))\n}\n\ntype MockPartyAndTableInfos struct {\n\tparty     string\n\ttables    []string\n\trefTables []string\n}\n\nfunc MockEnginesInfo(mockInfos []*MockPartyAndTableInfos) (*EnginesInfo, error) {\n\tif len(mockInfos) != 2 {\n\t\treturn nil, fmt.Errorf(\"unsupported party number %d\", len(mockInfos))\n\t}\n\tvar participants []*Participant\n\tfor _, info := range mockInfos {\n\t\tparticipants = append(participants, &Participant{\n\t\t\tPartyCode: info.party,\n\t\t\tEndpoints: []string{fmt.Sprintf(\"%s.com\", info.party)},\n\t\t\tToken:     fmt.Sprintf(\"%s_credential\", info.party),\n\t\t})\n\t}\n\tpartyInfo := NewPartyInfo(participants)\n\ttableNum := len(mockInfos[0].tables)\n\tparty2Tables := make(map[string][]core.DbTable)\n\tmockRefTables := make([]core.DbTable, 0)\n\tmockTables := make([]core.DbTable, 0)\n\tfor _, info := range mockInfos {\n\t\tfor _, qualifiedTable := range info.refTables {\n\t\t\tdt, err := core.NewDbTableFromString(qualifiedTable)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tmockRefTables = append(mockRefTables, dt)\n\t\t}\n\t\tfor _, refQualifiedTable := range info.tables {\n\t\t\tdt, err := core.NewDbTableFromString(refQualifiedTable)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tmockTables = append(mockTables, dt)\n\t\t}\n\t}\n\tparty2Tables[mockInfos[0].party] = mockRefTables[:tableNum]\n\tparty2Tables[mockInfos[1].party] = mockRefTables[tableNum:]\n\tmockEnginesInfo := NewEnginesInfo(partyInfo, party2Tables)\n\ttableToRefs := make(map[core.DbTable]core.DbTable)\n\tfor i, tbl := range mockRefTables {\n\t\ttableToRefs[mockTables[i]] = tbl\n\t}\n\n\tmockEnginesInfo.UpdateTableToRefs(tableToRefs)\n\treturn mockEnginesInfo, nil\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/execution_node.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// ExecutionNode struct\ntype ExecutionNode struct {\n\tID         int\n\tName       string\n\tOpType     string\n\tInputs     map[string][]*Tensor\n\tOutputs    map[string][]*Tensor\n\tAttributes map[string]*Attribute\n\n\tEdges map[*Edge]bool // Out Edges\n\t// party codes of participants\n\tParties []string\n}\n\n// ToString dumps a debug string of the execution node\nfunc (node *ExecutionNode) ToString() string {\n\tvar builder strings.Builder\n\tfmt.Fprintf(&builder, \"%s:{\", node.Name)\n\n\tfmt.Fprint(&builder, \"in:[\")\n\tvar inputs []string\n\tfor input := range node.Inputs {\n\t\tinputs = append(inputs, input)\n\t}\n\tsort.Strings(inputs)\n\tfor _, input := range inputs {\n\t\tfmt.Fprintf(&builder, \"%s:{\", input)\n\t\tfor _, argument := range node.Inputs[input] {\n\t\t\tfmt.Fprintf(&builder, \"t_%d,\", argument.ID)\n\t\t}\n\t\tfmt.Fprint(&builder, \"},\")\n\t}\n\tfmt.Fprint(&builder, \"],\")\n\n\tfmt.Fprint(&builder, \"out:[\")\n\tvar outputs []string\n\tfor output := range node.Outputs {\n\t\toutputs = append(outputs, output)\n\t}\n\tsort.Strings(outputs)\n\tfor _, output := range outputs {\n\t\tfmt.Fprintf(&builder, \"%s:{\", output)\n\t\tfor _, argument := range node.Outputs[output] {\n\t\t\tfmt.Fprintf(&builder, \"t_%d,\", argument.ID)\n\t\t}\n\t\tfmt.Fprint(&builder, \"},\")\n\t}\n\tfmt.Fprint(&builder, \"],\")\n\n\tfmt.Fprint(&builder, \"attr:[\")\n\tvar keys []string\n\tfor k := range node.Attributes {\n\t\tkeys = append(keys, k)\n\t}\n\tsort.Strings(keys)\n\tfor _, k := range keys {\n\t\tif k == operator.FuncOptAttr {\n\t\t\t// avoid print serialized options\n\t\t\tcontinue\n\t\t}\n\t\tfmt.Fprintf(&builder, \"%s:%s,\", k, node.Attributes[k].ToString())\n\t}\n\tfmt.Fprint(&builder, \"],\")\n\n\tfmt.Fprint(&builder, \"party:[\")\n\tfor _, p := range node.Parties {\n\t\tfmt.Fprintf(&builder, \"%s,\", p)\n\t}\n\tfmt.Fprint(&builder, \"]\")\n\tfmt.Fprint(&builder, \"}\")\n\treturn builder.String()\n}\n\n// ToBriefString dumps a brief string of the execution node\nfunc (node *ExecutionNode) ToBriefString() string {\n\tvar builder strings.Builder\n\tfmt.Fprintf(&builder, \"%s\", node.Name)\n\tfmt.Fprint(&builder, \"\\\\l[\")\n\tfor _, p := range node.Parties {\n\t\tfmt.Fprintf(&builder, \"%s,\", p)\n\t}\n\tfmt.Fprint(&builder, \"]\")\n\treturn builder.String()\n}\n\nfunc (node *ExecutionNode) GetAttrStrings(name string) ([]string, error) {\n\tif attr, ok := node.Attributes[name]; ok {\n\t\treturn attr.GetStrings()\n\t}\n\treturn nil, fmt.Errorf(\"getAttrStrings: attribute %s doesn't exists\", name)\n}\n\n// ToProto serializes in-memory execution node to proto\nfunc (node *ExecutionNode) ToProto() *proto.ExecNode {\n\tpb := &proto.ExecNode{\n\t\tNodeName: fmt.Sprintf(\"%s.%v\", node.Name, node.ID),\n\t\tOpType:   node.OpType,\n\t}\n\n\tif len(node.Inputs) > 0 {\n\t\tpb.Inputs = make(map[string]*proto.TensorList)\n\t\tfor k, inputs := range node.Inputs {\n\n\t\t\tpb.Inputs[k] = &proto.TensorList{\n\t\t\t\tTensors: make([]*proto.Tensor, 0),\n\t\t\t}\n\t\t\tfor _, i := range inputs {\n\t\t\t\tpb.Inputs[k].Tensors = append(pb.Inputs[k].Tensors, i.ToProto())\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(node.Outputs) > 0 {\n\t\tpb.Outputs = make(map[string]*proto.TensorList)\n\t\tfor k, outputs := range node.Outputs {\n\t\t\tpb.Outputs[k] = &proto.TensorList{\n\t\t\t\tTensors: make([]*proto.Tensor, 0),\n\t\t\t}\n\t\t\tfor _, o := range outputs {\n\t\t\t\tpb.Outputs[k].Tensors = append(pb.Outputs[k].Tensors, o.ToProto())\n\t\t\t}\n\t\t}\n\t}\n\tif len(node.Attributes) > 0 {\n\t\tpb.Attributes = make(map[string]*proto.AttributeValue)\n\t\tfor k, attr := range node.Attributes {\n\t\t\tpb.Attributes[k] = attr.ToProto()\n\t\t}\n\t}\n\treturn pb\n}\n\nfunc (node *ExecutionNode) UpdateInput(id int, newTensor *Tensor) {\n\tfor k, inputs := range node.Inputs {\n\t\tvar ids []int\n\t\tfor i, input := range inputs {\n\t\t\tif input.ID == id {\n\t\t\t\tids = append(ids, i)\n\t\t\t}\n\t\t}\n\t\tfor _, i := range ids {\n\t\t\tnode.Inputs[k][i] = newTensor\n\t\t}\n\t}\n}\n\nfunc (node *ExecutionNode) UpdateOutput(id int, newTensor *Tensor) {\n\tfor k, outputs := range node.Outputs {\n\t\tvar ids []int\n\t\tfor i, input := range outputs {\n\t\t\tif input.ID == id {\n\t\t\t\tids = append(ids, i)\n\t\t\t}\n\t\t}\n\t\tfor _, i := range ids {\n\t\t\tnode.Outputs[k][i] = newTensor\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/graph.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// Edge struct of a dag\ntype Edge struct {\n\tFrom  *ExecutionNode\n\tTo    *ExecutionNode\n\tValue *Tensor\n}\n\ntype Pipeline struct {\n\tBatched bool\n\t// tensors created by upstream pipeline but used in current pipeline\n\tInputTensors []*Tensor\n\t// tensors created by current pipeline but used in downstream pipeline\n\tOutputTensors []*Tensor\n\tNodes         map[*ExecutionNode]bool\n}\n\n// Graph struct\ntype Graph struct {\n\tPipelines   []*Pipeline\n\tNodeCnt     int\n\tOutputNames []string\n\tPartyInfo   *PartyInfo\n}\n\nfunc (graph *Graph) GetParties() []string {\n\treturn graph.PartyInfo.GetParties()\n}\n\nfunc (graph *Graph) GetUrlByParty(party string) (string, error) {\n\treturn graph.PartyInfo.GetUrlByParty(party)\n}\n\nfunc (graph *Graph) UpdateTensorRefNum() {\n\tfor _, pipeline := range graph.Pipelines {\n\t\tfor node := range pipeline.Nodes {\n\t\t\tfor _, ts := range node.Inputs {\n\t\t\t\tfor _, t := range ts {\n\t\t\t\t\tt.RefNum += 1\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// TopologicalSort of the dag\nfunc (graph *Graph) TopologicalSort() ([][]*ExecutionNode, error) {\n\tvar outputs [][]*ExecutionNode\n\tfor _, pipeline := range graph.Pipelines {\n\t\tvar nodes []*ExecutionNode\n\t\tvar queue []*ExecutionNode\n\n\t\tindegrees := make(map[*ExecutionNode]int)\n\t\tfor node := range pipeline.Nodes {\n\t\t\tindegrees[node] = 0\n\t\t}\n\n\t\tfor node := range pipeline.Nodes {\n\t\t\tfor edge := range node.Edges {\n\t\t\t\tif _, ok := indegrees[edge.To]; ok {\n\t\t\t\t\tindegrees[edge.To]++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor k, v := range indegrees {\n\t\t\tif v == 0 {\n\t\t\t\tqueue = append(queue, k)\n\t\t\t}\n\t\t}\n\n\t\t// NOTE(yang.y): sort nodes in the first queue to enforce determinism\n\t\tsort.Slice(queue, func(i, j int) bool { return queue[i].ID < queue[j].ID })\n\n\t\tcount := 0\n\t\tfor count = 0; len(queue) != 0; count++ {\n\t\t\tcur := queue[0]\n\t\t\tnodes = append(nodes, cur)\n\t\t\tqueue = queue[1:]\n\n\t\t\ttoAppend := []*ExecutionNode{}\n\t\t\tfor v := range cur.Edges {\n\t\t\t\tindegrees[v.To] = indegrees[v.To] - 1\n\t\t\t\tif indegrees[v.To] == 0 {\n\t\t\t\t\ttoAppend = append(toAppend, v.To)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// NOTE(yang.y): sort nodes to be appended to enforce determinism\n\t\t\tsort.Slice(toAppend, func(i, j int) bool { return toAppend[i].ID < toAppend[j].ID })\n\t\t\tqueue = append(queue, toAppend...)\n\t\t}\n\t\tif count != len(pipeline.Nodes) {\n\t\t\t// circle in DAG!\n\t\t\treturn nil, fmt.Errorf(\"topological sort fail: maybe circle in graph\")\n\t\t}\n\t\toutputs = append(outputs, nodes)\n\t}\n\n\treturn outputs, nil\n}\n\n// DumpGraphvizBase is a helper function to dump graphviz with custom labeler\nfunc (graph *Graph) DumpGraphvizBase(nodeLabeler func(*ExecutionNode) string, edgeValueLabeler func(*Tensor) string) string {\n\tvar builder strings.Builder\n\tfmt.Fprintln(&builder, \"digraph G {\")\n\tconvertToSingleQuote := func(s string) string {\n\t\treturn strings.ReplaceAll(s, \"\\\"\", \"'\")\n\t}\n\n\tnodes := []*ExecutionNode{}\n\tfor _, pipeline := range graph.Pipelines {\n\t\tfor n := range pipeline.Nodes {\n\t\t\tnodes = append(nodes, n)\n\t\t}\n\t}\n\tsort.Slice(nodes, func(i, j int) bool { return nodes[i].ID < nodes[j].ID })\n\n\tfor _, node := range nodes {\n\t\tfmt.Fprintf(&builder, \"%d [label=\\\"%s\\\"]\\n\", node.ID, convertToSingleQuote(nodeLabeler(node)))\n\t}\n\n\tvar all []string\n\tfor _, node := range nodes {\n\t\tfor edge := range node.Edges {\n\t\t\tall = append(all, fmt.Sprintf(\"%d -> %d [label = \\\"%s\\\"]\\n\", edge.From.ID,\n\t\t\t\tedge.To.ID, convertToSingleQuote(edgeValueLabeler(edge.Value))))\n\t\t}\n\t}\n\tsort.Strings(all)\n\tfmt.Fprint(&builder, strings.Join(all, \"\"))\n\tfmt.Fprint(&builder, \"}\")\n\treturn builder.String()\n}\n\n// DumpGraphviz dumps a graph viz for visualization\nfunc (graph *Graph) DumpGraphviz() string {\n\treturn graph.DumpGraphvizBase(\n\t\tfunc(node *ExecutionNode) string { return node.ToString() },\n\t\tfunc(edgeValue *Tensor) string { return edgeValue.ToString() },\n\t)\n}\n\n// DumpBriefGraphviz dumps a brief graph viz for visualization\nfunc (graph *Graph) DumpBriefGraphviz() string {\n\treturn graph.DumpGraphvizBase(\n\t\tfunc(node *ExecutionNode) string { return node.ToBriefString() },\n\t\tfunc(edgeValue *Tensor) string { return edgeValue.ToBriefString() },\n\t)\n}\n\n// DumpBriefPipeline dumps pipeline to string\nfunc (graph *Graph) DumpBriefPipeline() string {\n\tvar builder strings.Builder\n\tfmt.Fprintln(&builder)\n\tfor i, pipeline := range graph.Pipelines {\n\t\tfmt.Fprintf(&builder, \"pipeline %d {\\n\", i)\n\t\tfmt.Fprintf(&builder, \"Batched: %v\\n\", pipeline.Batched)\n\t\tnodes := []*ExecutionNode{}\n\t\tfor n := range pipeline.Nodes {\n\t\t\tnodes = append(nodes, n)\n\t\t}\n\t\tsort.Slice(nodes, func(i, j int) bool { return nodes[i].ID < nodes[j].ID })\n\t\tvar nodeNames []string\n\t\tfor _, node := range nodes {\n\t\t\tnodeNames = append(nodeNames, fmt.Sprintf(\"%s_%d\", node.Name, node.ID))\n\t\t}\n\t\tfmt.Fprintf(&builder, \"node: %+v\\n\", nodeNames)\n\t\tvar inputTensorIDs []string\n\t\tvar outputTensorIDs []string\n\t\tfor _, t := range pipeline.InputTensors {\n\t\t\tinputTensorIDs = append(inputTensorIDs, fmt.Sprintf(\"t_%d\", t.ID))\n\t\t}\n\t\tfor _, t := range pipeline.OutputTensors {\n\t\t\toutputTensorIDs = append(outputTensorIDs, fmt.Sprintf(\"t_%d\", t.ID))\n\t\t}\n\t\tslices.Sort(inputTensorIDs)\n\t\tslices.Sort(outputTensorIDs)\n\t\tfmt.Fprintf(&builder, \"Inputs: %+v\\n\", inputTensorIDs)\n\t\tfmt.Fprintf(&builder, \"Outputs: %+v\\n\", outputTensorIDs)\n\t\tfmt.Fprint(&builder, \"}\\n\")\n\t}\n\treturn builder.String()\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/graph_mapper.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\tproto \"google.golang.org/protobuf/proto\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\t\"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\nconst workerNumLevel1 = 8\nconst workerNumLevel2 = 16\n\ntype ParallelJobs struct {\n\t// map from worker id to node ids\n\tJobs map[int][]int\n\t// sync among parties. Sometimes, the DAGs of Alice and Bob\n\t// are unbalanced. There is no need to call sync parties when\n\t// only one party execute its own subDAG.\n\tNeedCallBarrierAfterJobs bool\n\tNeedSyncSymbolBeforeJobs bool\n}\n\ntype PipelineJobs struct {\n\tBatched       bool\n\tInputTensors  []*Tensor\n\tOutputTensors []*Tensor\n\tJobs          []*ParallelJobs\n}\n\ntype SchedulePolicy struct {\n\tWorkerNumber int\n\tPipelineJobs []*PipelineJobs\n}\n\ntype ExecutionPlan struct {\n\tNodes  map[int]*ExecutionNode\n\tPolicy *SchedulePolicy\n}\n\nfunc NewExecutionPlan(workerNum, pipelinesNum int) *ExecutionPlan {\n\tplan := &ExecutionPlan{\n\t\tNodes: make(map[int]*ExecutionNode),\n\t\tPolicy: &SchedulePolicy{\n\t\t\tWorkerNumber: workerNum,\n\t\t\tPipelineJobs: make([]*PipelineJobs, pipelinesNum),\n\t\t},\n\t}\n\tfor i := range pipelinesNum {\n\t\tplan.Policy.PipelineJobs[i] = &PipelineJobs{}\n\t}\n\treturn plan\n}\n\nfunc (b *ExecutionPlan) DumpString() string {\n\tvar builder strings.Builder\n\tfmt.Fprintf(&builder, \"SchedulePolicy: {\\n\")\n\tfor _, p := range b.Policy.PipelineJobs {\n\t\tfmt.Fprintf(&builder, \"  Pipeline {\\n\")\n\t\tfor _, j := range p.Jobs {\n\t\t\tfmt.Fprintf(&builder, \"    SubDAG {\\n\")\n\t\t\tvar keys []int\n\t\t\tfor k := range j.Jobs {\n\t\t\t\tkeys = append(keys, k)\n\t\t\t}\n\t\t\tsort.Ints(keys)\n\t\t\tfor _, k := range keys {\n\t\t\t\tfmt.Fprintf(&builder, \"      Worker %d, nodes: %v\\n\", k, j.Jobs[k])\n\t\t\t}\n\t\t\tfmt.Fprintf(&builder, \"      CallBarrierAfterJobs: %v\\n\", j.NeedCallBarrierAfterJobs)\n\t\t\tfmt.Fprintf(&builder, \"      SyncSymbolBeforeJobs: %v\\n\", j.NeedSyncSymbolBeforeJobs)\n\t\t\tfmt.Fprintf(&builder, \"    }\\n\")\n\t\t}\n\t\tfmt.Fprintf(&builder, \"  }\\n\")\n\t}\n\tfmt.Fprintf(&builder, \"}\")\n\treturn builder.String()\n}\n\ntype GraphMapper struct {\n\tgraph     *Graph\n\tpipelines []*PartitionedPipeline\n\n\tsyncedTensorMap map[string]bool\n\n\tCodes map[string]*ExecutionPlan // key is party code, value is execution plan\n}\n\nfunc NewGraphMapper(input *Graph, pipelines []*PartitionedPipeline) *GraphMapper {\n\treturn &GraphMapper{\n\t\tgraph:           input,\n\t\tpipelines:       pipelines,\n\t\tCodes:           make(map[string]*ExecutionPlan),\n\t\tsyncedTensorMap: make(map[string]bool),\n\t}\n}\n\nfunc (m *GraphMapper) InferenceWorkerNumber() int {\n\tworkerNum := 1\n\tfor _, pipeline := range m.pipelines {\n\t\tfor _, subDAG := range pipeline.SubDAGs {\n\t\t\tif len(subDAG.Nodes) > workerNum {\n\t\t\t\tworkerNum = len(subDAG.Nodes)\n\t\t\t}\n\t\t}\n\t}\n\tif workerNum <= workerNumLevel1 {\n\t\treturn workerNum\n\t}\n\tif workerNum > workerNumLevel2 {\n\t\treturn workerNumLevel1\n\t}\n\treturn workerNum / 2\n}\n\nfunc (m *GraphMapper) inferenceNeedCallBarrier(pipelineIndex, jobIndex int) {\n\tvar partyCodes []string\n\tfor k, v := range m.Codes {\n\t\tif len(v.Policy.PipelineJobs[pipelineIndex].Jobs[jobIndex].Jobs) != 0 {\n\t\t\tpartyCodes = append(partyCodes, k)\n\t\t}\n\n\t}\n\tif len(partyCodes) > 1 {\n\t\tfor _, v := range m.Codes {\n\t\t\tv.Policy.PipelineJobs[pipelineIndex].Jobs[jobIndex].NeedCallBarrierAfterJobs = true\n\t\t}\n\t}\n}\n\nvar needSyncSymbolOps = map[string]bool{\n\toperator.OpNameReplicate: true,\n\toperator.OpNameMakeShare: true,\n}\n\nfunc needSyncSymbol(node *ExecutionNode) bool {\n\t_, ok := needSyncSymbolOps[node.OpType]\n\treturn ok\n}\n\nfunc (m *GraphMapper) IsInputsSynced(node *ExecutionNode) bool {\n\tfor _, tensors := range node.Inputs {\n\t\tfor _, tensor := range tensors {\n\t\t\tif !m.syncedTensorMap[tensor.UniqueName()] {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\n// SyncedTensorMap keep info which tensors have been synced, this func update SyncedTensorMap\n// after sync op\nfunc (m *GraphMapper) UpdateSyncedTensorMap(inputs map[string][]*Tensor) {\n\tfor _, tensors := range inputs {\n\t\tfor _, tensor := range tensors {\n\t\t\tif ok := m.syncedTensorMap[tensor.UniqueName()]; !ok {\n\t\t\t\tm.syncedTensorMap[tensor.UniqueName()] = false\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (m *GraphMapper) inferenceNeedSyncSymbol(pipelineIndex, jobIndex int) {\n\tfor _, v := range m.Codes {\n\t\tjobs := v.Policy.PipelineJobs[pipelineIndex].Jobs[jobIndex].Jobs\n\t\tfor _, ids := range jobs {\n\t\t\tfor _, id := range ids {\n\t\t\t\tif needSyncSymbol(v.Nodes[id]) && !m.IsInputsSynced(v.Nodes[id]) {\n\t\t\t\t\tv.Policy.PipelineJobs[pipelineIndex].Jobs[jobIndex].NeedSyncSymbolBeforeJobs = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// if synced in this subdag, set current SyncedTensorMap all true\n\tfor _, v := range m.Codes {\n\t\tif v.Policy.PipelineJobs[pipelineIndex].Jobs[jobIndex].NeedSyncSymbolBeforeJobs {\n\t\t\t// set current to true\n\t\t\tfor key := range m.syncedTensorMap {\n\t\t\t\tm.syncedTensorMap[key] = true\n\t\t\t}\n\t\t}\n\t\tbreak\n\n\t}\n\t// put outputs in this subdag to SyncedTensorMap\n\tfor _, v := range m.Codes {\n\t\tjobs := v.Policy.PipelineJobs[pipelineIndex].Jobs[jobIndex].Jobs\n\t\tfor _, ids := range jobs {\n\t\t\tfor _, id := range ids {\n\t\t\t\t// update SyncedTensorMap with outputs\n\t\t\t\tm.UpdateSyncedTensorMap(v.Nodes[id].Outputs)\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nfunc (m *GraphMapper) Map() {\n\tfor i, pipeline := range m.pipelines {\n\t\tfor j, subDAG := range pipeline.SubDAGs {\n\t\t\tpartyCodeToParallelJobs := make(map[string]*ParallelJobs)\n\t\t\tfor _, partyCode := range m.graph.PartyInfo.GetParties() {\n\t\t\t\tpartyCodeToParallelJobs[partyCode] = &ParallelJobs{\n\t\t\t\t\tJobs: make(map[int][]int),\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsortedNodes := make([]*ExecutionNode, 0)\n\t\t\tsinglePartyNodes := make([]*ExecutionNode, 0)\n\t\t\tfor node := range subDAG.Nodes {\n\t\t\t\tif len(node.Parties) == 1 {\n\t\t\t\t\tsinglePartyNodes = append(singlePartyNodes, node)\n\t\t\t\t} else {\n\t\t\t\t\tsortedNodes = append(sortedNodes, node)\n\t\t\t\t}\n\t\t\t}\n\t\t\tsort.Slice(sortedNodes, func(i, j int) bool { return sortedNodes[i].ID < sortedNodes[j].ID })\n\t\t\tsort.Slice(singlePartyNodes, func(i, j int) bool { return singlePartyNodes[i].ID < singlePartyNodes[j].ID })\n\t\t\tsortedNodes = append(sortedNodes, singlePartyNodes...)\n\n\t\t\tfor i, node := range sortedNodes {\n\t\t\t\tnodes := splitExecutionNode(node)\n\t\t\t\tfor k, v := range nodes {\n\t\t\t\t\t_, ok := m.Codes[k]\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\tm.Codes[k] = NewExecutionPlan(m.InferenceWorkerNumber(), len(m.pipelines))\n\t\t\t\t\t}\n\t\t\t\t\tm.Codes[k].Nodes[v.ID] = v\n\t\t\t\t\tworkerID := i % m.Codes[k].Policy.WorkerNumber\n\t\t\t\t\t_, ok = partyCodeToParallelJobs[k].Jobs[workerID]\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\tpartyCodeToParallelJobs[k].Jobs[workerID] = make([]int, 0)\n\t\t\t\t\t}\n\t\t\t\t\tpartyCodeToParallelJobs[k].Jobs[workerID] = append(partyCodeToParallelJobs[k].Jobs[workerID], v.ID)\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor k, v := range partyCodeToParallelJobs {\n\t\t\t\t_, ok := m.Codes[k]\n\t\t\t\tif !ok {\n\t\t\t\t\tm.Codes[k] = NewExecutionPlan(m.InferenceWorkerNumber(), len(m.pipelines))\n\t\t\t\t}\n\t\t\t\tm.Codes[k].Policy.PipelineJobs[i].Jobs = append(m.Codes[k].Policy.PipelineJobs[i].Jobs, v)\n\t\t\t}\n\t\t\tfor _, code := range m.Codes {\n\t\t\t\tcode.Policy.PipelineJobs[i].Batched = pipeline.Batched\n\t\t\t}\n\t\t\tm.inferenceNeedCallBarrier(i, j)\n\t\t\tm.inferenceNeedSyncSymbol(i, j)\n\t\t}\n\t\tif pipeline.Batched {\n\t\t\t// TODO: support share tensors\n\t\t\tfor _, t := range pipeline.InputTensors {\n\t\t\t\tm.Codes[t.OwnerPartyCode].Policy.PipelineJobs[i].InputTensors = append(m.Codes[t.OwnerPartyCode].Policy.PipelineJobs[i].InputTensors, t)\n\t\t\t}\n\t\t\tfor _, t := range pipeline.OutputTensors {\n\t\t\t\tm.Codes[t.OwnerPartyCode].Policy.PipelineJobs[i].OutputTensors = append(m.Codes[t.OwnerPartyCode].Policy.PipelineJobs[i].OutputTensors, t)\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nfunc (m *GraphMapper) CodeGen(params *scql.JobStartParams) map[string]*scql.RunExecutionPlanRequest {\n\tresult := make(map[string]*scql.RunExecutionPlanRequest)\n\tfor partyCode, plan := range m.Codes {\n\t\tjobStartParams, ok := proto.Clone(params).(*scql.JobStartParams)\n\t\tif !ok {\n\t\t\treturn nil\n\t\t}\n\t\tpb := &scql.RunExecutionPlanRequest{\n\t\t\tJobParams: jobStartParams,\n\t\t\tGraph: &scql.SubGraph{\n\t\t\t\tNodes: make(map[string]*scql.ExecNode),\n\t\t\t\tPolicy: &scql.SchedulingPolicy{\n\t\t\t\t\tWorkerNum: int32(plan.Policy.WorkerNumber),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tpb.JobParams.PartyCode = partyCode\n\t\tfor k, v := range plan.Nodes {\n\t\t\tpb.Graph.Nodes[strconv.Itoa(k)] = v.ToProto()\n\t\t}\n\t\tfor _, pipelineJobs := range plan.Policy.PipelineJobs {\n\t\t\tpipeline := scql.Pipeline{Subdags: make([]*scql.SubDAG, 0)}\n\t\t\tfor _, job := range pipelineJobs.Jobs {\n\t\t\t\tsubdag := &scql.SubDAG{\n\t\t\t\t\tJobs:                     make([]*scql.SubDAG_Job, 0),\n\t\t\t\t\tNeedCallBarrierAfterJobs: job.NeedCallBarrierAfterJobs,\n\t\t\t\t}\n\t\t\t\tfor k, v := range job.Jobs {\n\t\t\t\t\tvar ids []string\n\t\t\t\t\tfor _, id := range v {\n\t\t\t\t\t\tids = append(ids, strconv.Itoa(id))\n\t\t\t\t\t}\n\t\t\t\t\tj := &scql.SubDAG_Job{\n\t\t\t\t\t\tWorkerId: int32(k),\n\t\t\t\t\t\tNodeIds:  ids,\n\t\t\t\t\t}\n\t\t\t\t\tsubdag.Jobs = append(subdag.Jobs, j)\n\t\t\t\t}\n\t\t\t\tpipeline.Subdags = append(pipeline.Subdags, subdag)\n\t\t\t}\n\t\t\tpb.Graph.Policy.Pipelines = append(pb.Graph.Policy.Pipelines, &pipeline)\n\t\t}\n\t\tresult[partyCode] = pb\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/graph_mapper_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// Helper to create test party info\nfunc createTestPartyInfoForMapper(parties ...string) *PartyInfo {\n\tparticipants := make([]*Participant, 0, len(parties))\n\tfor _, party := range parties {\n\t\tparticipants = append(participants, &Participant{\n\t\t\tPartyCode: party,\n\t\t\tEndpoints: []string{party + \".net\"},\n\t\t\tToken:     party + \"_credential\",\n\t\t})\n\t}\n\treturn NewPartyInfo(participants)\n}\n\n// Helper to create test graph with nodes\nfunc createTestGraphForMapper(parties []string) *Graph {\n\t// Create tensors\n\ttensors := make([]*Tensor, 0, len(parties)*3)\n\tfor i, party := range parties {\n\t\tfor j := 0; j < 3; j++ {\n\t\t\ttensor := &Tensor{\n\t\t\t\tID:             i*3 + j,\n\t\t\t\tName:           fmt.Sprintf(\"t%d%d\", i, j),\n\t\t\t\tDType:          NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t\t\t\tRefNum:         0,\n\t\t\t\tOwnerPartyCode: party,\n\t\t\t}\n\t\t\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\t\t\ttensors = append(tensors, tensor)\n\t\t}\n\t}\n\n\t// Create execution nodes\n\tnodes := make([]*ExecutionNode, 0)\n\n\t// RunSQL nodes for each party\n\tfor i, party := range parties {\n\t\tnode := &ExecutionNode{\n\t\t\tID:         i,\n\t\t\tName:       \"RunSQLOp\" + party,\n\t\t\tOpType:     operator.OpNameRunSQL,\n\t\t\tInputs:     make(map[string][]*Tensor),\n\t\t\tOutputs:    make(map[string][]*Tensor),\n\t\t\tAttributes: make(map[string]*Attribute),\n\t\t\tEdges:      make(map[*Edge]bool),\n\t\t\tParties:    []string{party},\n\t\t}\n\t\tnode.Outputs[\"output\"] = tensors[i*3 : i*3+3]\n\t\tnodes = append(nodes, node)\n\t}\n\n\t// MakeShare nodes\n\tmakeShareNodes := make([]*ExecutionNode, 0)\n\tfor i := range tensors {\n\t\tnode := &ExecutionNode{\n\t\t\tID:         len(parties) + i,\n\t\t\tName:       fmt.Sprintf(\"make_share_%d_%d\", i/3, i%3),\n\t\t\tOpType:     operator.OpNameMakeShare,\n\t\t\tInputs:     make(map[string][]*Tensor),\n\t\t\tOutputs:    make(map[string][]*Tensor),\n\t\t\tAttributes: make(map[string]*Attribute),\n\t\t\tEdges:      make(map[*Edge]bool),\n\t\t\tParties:    parties,\n\t\t}\n\t\tnode.Inputs[\"input\"] = []*Tensor{tensors[i]}\n\t\tmakeShareNodes = append(makeShareNodes, node)\n\t}\n\tnodes = append(nodes, makeShareNodes...)\n\n\t// Concat nodes\n\tconcatNodes := make([]*ExecutionNode, 0)\n\tfor i := 0; i < len(parties); i++ {\n\t\tnode := &ExecutionNode{\n\t\t\tID:         len(parties) + len(tensors) + i,\n\t\t\tName:       \"concat_\" + parties[i],\n\t\t\tOpType:     operator.OpNameConcat,\n\t\t\tInputs:     make(map[string][]*Tensor),\n\t\t\tOutputs:    make(map[string][]*Tensor),\n\t\t\tAttributes: make(map[string]*Attribute),\n\t\t\tEdges:      make(map[*Edge]bool),\n\t\t\tParties:    parties,\n\t\t}\n\t\t// Each concat node takes 3 make_share outputs\n\t\tstartIdx := i * 3\n\t\tinputs := make([]*Tensor, 3)\n\t\tfor j := 0; j < 3; j++ {\n\t\t\t// Create output tensors for make_share nodes\n\t\t\toutputTensor := &Tensor{\n\t\t\t\tID:     len(tensors) + startIdx + j,\n\t\t\t\tName:   fmt.Sprintf(\"shared_%d%d\", i, j),\n\t\t\t\tDType:  NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t\t\t\tRefNum: 0,\n\t\t\t}\n\t\t\toutputTensor.SetStatus(proto.TensorStatus_TENSORSTATUS_SECRET)\n\t\t\tinputs[j] = outputTensor\n\t\t}\n\t\tnode.Inputs[\"In\"] = inputs\n\t\tconcatNodes = append(concatNodes, node)\n\t}\n\tnodes = append(nodes, concatNodes...)\n\n\t// Create graph\n\tpartyInfo := createTestPartyInfoForMapper(parties...)\n\tpipeline := &Pipeline{\n\t\tBatched:       false,\n\t\tInputTensors:  []*Tensor{},\n\t\tOutputTensors: []*Tensor{},\n\t\tNodes:         make(map[*ExecutionNode]bool),\n\t}\n\tfor _, node := range nodes {\n\t\tpipeline.Nodes[node] = true\n\t}\n\n\tg := &Graph{\n\t\tPipelines:   []*Pipeline{pipeline},\n\t\tNodeCnt:     len(nodes),\n\t\tOutputNames: []string{},\n\t\tPartyInfo:   partyInfo,\n\t}\n\n\treturn g\n}\n\nfunc TestMapSimple(t *testing.T) {\n\ta := require.New(t)\n\n\t// Create test graph\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tgraph := createTestGraphForMapper(parties)\n\n\t// Create partitioner and partition\n\tp := NewGraphPartitioner(graph)\n\tp.NaivePartition()\n\n\t// Create mapper and map\n\tm := NewGraphMapper(p.Graph, p.Pipelines)\n\tm.Map()\n\n\t// Verify all parties have execution plans\n\ta.Equal(len(parties), len(m.Codes))\n\tfor _, party := range parties {\n\t\ta.Contains(m.Codes, party)\n\t\ta.NotNil(m.Codes[party])\n\t\ta.NotNil(m.Codes[party].Policy)\n\t}\n\n\t// NaivePartition should result in 1 worker\n\tfor _, party := range parties {\n\t\ta.Equal(1, m.Codes[party].Policy.WorkerNumber)\n\t}\n\n\t// Verify make_share nodes exist in all parties\n\t// Find the first make_share node\n\tvar makeShareNodeID int\n\tvar found bool\n\tfor id, node := range m.Codes[\"alice\"].Nodes {\n\t\tif node.OpType == operator.OpNameMakeShare {\n\t\t\tmakeShareNodeID = id\n\t\t\tfound = true\n\t\t\tbreak\n\t\t}\n\t}\n\ta.True(found, \"MakeShare node not found in alice's plan\")\n\n\t// Verify the same make_share node exists in all parties\n\tfor _, party := range parties {\n\t\tnode, exists := m.Codes[party].Nodes[makeShareNodeID]\n\t\ta.True(exists, \"MakeShare node not found in %s's plan\", party)\n\t\ta.Equal(operator.OpNameMakeShare, node.OpType)\n\t}\n}\n\nfunc TestMapSimpleStreaming(t *testing.T) {\n\ta := require.New(t)\n\n\t// Create test graph\n\tparties := []string{\"alice\", \"bob\", \"carol\"}\n\tgraph := createTestGraphForMapper(parties)\n\n\t// Mark the pipeline as batched\n\tfor _, pipeline := range graph.Pipelines {\n\t\tpipeline.Batched = true\n\t}\n\n\t// Create partitioner and partition\n\tp := NewGraphPartitioner(graph)\n\tp.NaivePartition()\n\n\t// Create mapper and map\n\tm := NewGraphMapper(p.Graph, p.Pipelines)\n\tm.Map()\n\n\t// Verify all parties have execution plans\n\ta.Equal(len(parties), len(m.Codes))\n\tfor _, party := range parties {\n\t\ta.Contains(m.Codes, party)\n\t\ta.NotNil(m.Codes[party])\n\t\ta.NotNil(m.Codes[party].Policy)\n\t}\n\n\t// NaivePartition should result in 1 worker\n\tfor _, party := range parties {\n\t\ta.Equal(1, m.Codes[party].Policy.WorkerNumber)\n\t}\n\n\t// Verify we have both batched and non-batched pipeline jobs\n\ta.GreaterOrEqual(len(m.Codes[\"alice\"].Policy.PipelineJobs), 1)\n\n\t// The first pipeline should be batched\n\ta.True(m.Codes[\"alice\"].Policy.PipelineJobs[0].Batched)\n}\n\nfunc TestInferenceWorkerNumber(t *testing.T) {\n\ta := require.New(t)\n\n\t// Test empty graph\n\temptyGraph := &Graph{\n\t\tPipelines: []*Pipeline{},\n\t\tPartyInfo: createTestPartyInfoForMapper(\"alice\", \"bob\"),\n\t}\n\tm := NewGraphMapper(emptyGraph, []*PartitionedPipeline{})\n\ta.Equal(1, m.InferenceWorkerNumber())\n\n\t// Test graph with single node per subdag\n\tsingleNodeGraph := &Graph{\n\t\tPipelines: []*Pipeline{\n\t\t\t{\n\t\t\t\tNodes: map[*ExecutionNode]bool{\n\t\t\t\t\t{ID: 0}: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tPartyInfo: createTestPartyInfoForMapper(\"alice\", \"bob\"),\n\t}\n\tpipelines := []*PartitionedPipeline{\n\t\t{\n\t\t\tSubDAGs: []*WorkerSubDAG{\n\t\t\t\t{\n\t\t\t\t\tNodes: map[*ExecutionNode]bool{\n\t\t\t\t\t\t{ID: 0}: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tm = NewGraphMapper(singleNodeGraph, pipelines)\n\ta.Equal(1, m.InferenceWorkerNumber())\n\n\t// Test graph with many nodes (testing the level thresholds)\n\tmanyNodesMap := make(map[*ExecutionNode]bool)\n\tmanyNodes := make([]*ExecutionNode, 0, 20)\n\tfor i := range 20 {\n\t\tnode := &ExecutionNode{ID: i}\n\t\tmanyNodes = append(manyNodes, node)\n\t\tmanyNodesMap[node] = true\n\t}\n\tmanyNodeGraph := &Graph{\n\t\tPipelines: []*Pipeline{\n\t\t\t{\n\t\t\t\tNodes: manyNodesMap,\n\t\t\t},\n\t\t},\n\t\tPartyInfo: createTestPartyInfoForMapper(\"alice\", \"bob\"),\n\t}\n\tpipelines = []*PartitionedPipeline{\n\t\t{\n\t\t\tSubDAGs: []*WorkerSubDAG{\n\t\t\t\t{Nodes: manyNodesMap},\n\t\t\t},\n\t\t},\n\t}\n\tm = NewGraphMapper(manyNodeGraph, pipelines)\n\t// With 20 nodes, should return workerNumLevel1 = 8 (since it's > level2)\n\ta.Equal(8, m.InferenceWorkerNumber())\n\n\t// Test graph with nodes between level1 and level2\n\tbetweenLevelNodesMap := make(map[*ExecutionNode]bool)\n\tbetweenLevelNodes := make([]*ExecutionNode, 0, 10)\n\tfor i := range 10 {\n\t\tnode := &ExecutionNode{ID: i + 20}\n\t\tbetweenLevelNodes = append(betweenLevelNodes, node)\n\t\tbetweenLevelNodesMap[node] = true\n\t}\n\tbetweenLevelNodeGraph := &Graph{\n\t\tPipelines: []*Pipeline{\n\t\t\t{\n\t\t\t\tNodes: betweenLevelNodesMap,\n\t\t\t},\n\t\t},\n\t\tPartyInfo: createTestPartyInfoForMapper(\"alice\", \"bob\"),\n\t}\n\tbetweenLevelPipelines := []*PartitionedPipeline{\n\t\t{\n\t\t\tSubDAGs: []*WorkerSubDAG{\n\t\t\t\t{Nodes: betweenLevelNodesMap},\n\t\t\t},\n\t\t},\n\t}\n\tm = NewGraphMapper(betweenLevelNodeGraph, betweenLevelPipelines)\n\t// With 10 nodes, should return workerNum/2 = 5 (since it's between level1 and level2)\n\ta.Equal(5, m.InferenceWorkerNumber())\n}\n\nfunc TestNeedSyncSymbol(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\topType   string\n\t\texpected bool\n\t}{\n\t\t{\"Replicate\", operator.OpNameReplicate, true},\n\t\t{\"MakeShare\", operator.OpNameMakeShare, true},\n\t\t{\"Other\", \"OtherOperation\", false},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tnode := &ExecutionNode{\n\t\t\t\tOpType: tt.opType,\n\t\t\t}\n\t\t\tresult := needSyncSymbol(node)\n\t\t\tassert.Equal(t, tt.expected, result)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/graph_optimizer.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\t\"github.com/secretflow/scql/pkg/util/stringutil\"\n)\n\nvar (\n\t_ optimizeGraphRule = &optConstantCast{}\n)\n\ntype optimizeGraphRule interface {\n\toptimize(*Graph) error\n}\n\ntype GraphOptimizer struct {\n\trules []optimizeGraphRule\n}\n\nfunc NewGraphOptimizer() *GraphOptimizer {\n\trules := []optimizeGraphRule{&optConstantCast{}}\n\treturn &GraphOptimizer{rules: rules}\n}\n\nfunc (g *GraphOptimizer) Optimize(graph *Graph) error {\n\tfor _, rule := range g.rules {\n\t\tif err := rule.optimize(graph); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\ntype optConstantCast struct {\n}\n\nfunc (rule optConstantCast) optimize(graph *Graph) error {\n\tfor _, pipeline := range graph.Pipelines {\n\t\tfor node := range pipeline.Nodes {\n\t\t\tif node.OpType != \"Constant\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// find broadcast node\n\t\t\tvar broadCastNode *ExecutionNode\n\t\t\t// only support constant -> broadcast -> cast single path\n\t\t\tif len(node.Edges) != 1 {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tfor edge := range node.Edges {\n\t\t\t\tif edge.To.OpType == \"BroadcastTo\" {\n\t\t\t\t\tbroadCastNode = edge.To\n\t\t\t\t}\n\t\t\t}\n\t\t\tif broadCastNode == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// find cast node\n\t\t\tvar castNode *ExecutionNode\n\t\t\tif len(broadCastNode.Edges) != 1 {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tfor edge := range broadCastNode.Edges {\n\t\t\t\tif edge.To.OpType == \"Cast\" {\n\t\t\t\t\tcastNode = edge.To\n\t\t\t\t}\n\t\t\t}\n\t\t\tif castNode == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// check whether cast is valid\n\t\t\toriginType := node.Outputs[\"Out\"][0].DType\n\t\t\tcastType := castNode.Outputs[\"Out\"][0].DType\n\t\t\tif !isValidCast(originType, castType) {\n\t\t\t\treturn fmt.Errorf(\"GraphOptimizer: invalid cast from %v to %v\", originType, castType)\n\t\t\t}\n\n\t\t\t// cast value\n\t\t\tscalarAttr := node.Attributes[\"scalar\"]\n\t\t\terr := castValue(scalarAttr, originType, castType)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"GraphOptimizer: failed to cast value: %v\", err)\n\t\t\t}\n\n\t\t\t// change tensor type\n\t\t\tif castType.IsTimeType() {\n\t\t\t\tnode.Outputs[\"Out\"][0].DType = NewPrimitiveDataType(proto.PrimitiveDataType_INT64)\n\t\t\t\tbroadCastNode.Outputs[\"Out\"][0].DType = NewPrimitiveDataType(proto.PrimitiveDataType_INT64)\n\t\t\t} else {\n\t\t\t\tnode.Outputs[\"Out\"][0].DType = castType\n\t\t\t\tbroadCastNode.Outputs[\"Out\"][0].DType = castType\n\t\t\t}\n\n\t\t\t// rearrange edges\n\t\t\tfor edge := range broadCastNode.Edges {\n\t\t\t\tdelete(broadCastNode.Edges, edge)\n\t\t\t}\n\t\t\tcastNodeOutTs := castNode.Outputs[\"Out\"][0]\n\t\t\tfor edge := range castNode.Edges {\n\t\t\t\tedge.From = broadCastNode\n\t\t\t\tedge.Value = broadCastNode.Outputs[\"Out\"][0]\n\t\t\t\tbroadCastNode.Edges[edge] = true\n\n\t\t\t\tfor _, input := range edge.To.Inputs {\n\t\t\t\t\tfor i := range input {\n\t\t\t\t\t\tif input[i].ID == castNodeOutTs.ID {\n\t\t\t\t\t\t\tinput[i] = edge.Value\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// remove castNode\n\t\t\tdelete(pipeline.Nodes, castNode)\n\t\t}\n\t}\n\treturn nil\n}\n\n// TODO: support decimal\nfunc isValidCast(originType, castType *DataType) bool {\n\tvalidCasts := map[proto.PrimitiveDataType]map[proto.PrimitiveDataType]bool{\n\t\tproto.PrimitiveDataType_STRING: {\n\t\t\tproto.PrimitiveDataType_INT64:     true,\n\t\t\tproto.PrimitiveDataType_FLOAT64:   true,\n\t\t\tproto.PrimitiveDataType_DATETIME:  true,\n\t\t\tproto.PrimitiveDataType_TIMESTAMP: true,\n\t\t},\n\t\tproto.PrimitiveDataType_INT32: {\n\t\t\tproto.PrimitiveDataType_FLOAT32: true,\n\t\t\tproto.PrimitiveDataType_FLOAT64: true,\n\t\t\tproto.PrimitiveDataType_STRING:  true,\n\t\t},\n\t\tproto.PrimitiveDataType_INT64: {\n\t\t\tproto.PrimitiveDataType_FLOAT32: true,\n\t\t\tproto.PrimitiveDataType_FLOAT64: true,\n\t\t\tproto.PrimitiveDataType_STRING:  true,\n\t\t},\n\t\tproto.PrimitiveDataType_FLOAT32: {\n\t\t\tproto.PrimitiveDataType_INT64:  true,\n\t\t\tproto.PrimitiveDataType_STRING: true,\n\t\t},\n\t\tproto.PrimitiveDataType_FLOAT64: {\n\t\t\tproto.PrimitiveDataType_INT64:  true,\n\t\t\tproto.PrimitiveDataType_STRING: true,\n\t\t},\n\t\tproto.PrimitiveDataType_BOOL: {\n\t\t\tproto.PrimitiveDataType_INT32:  true,\n\t\t\tproto.PrimitiveDataType_STRING: true,\n\t\t},\n\t}\n\n\tif validCastMap, ok := validCasts[originType.DType]; ok {\n\t\treturn validCastMap[castType.DType]\n\t}\n\n\treturn originType == castType\n}\n\n// TODO: support decimal\nfunc castValue(scalarAttr *Attribute, originType, castType *DataType) error {\n\tif scalarAttr == nil {\n\t\treturn fmt.Errorf(\"constant node doesn't have scalar attribute\")\n\t}\n\n\toriginalValue := scalarAttr.GetAttrValue()\n\tif originalValue == nil {\n\t\treturn fmt.Errorf(\"constant node doesn't have value\")\n\t}\n\n\tswitch originType.DType {\n\tcase proto.PrimitiveDataType_STRING:\n\t\tstrVal, ok := originalValue.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"expected string value\")\n\t\t}\n\t\tswitch castType.DType {\n\t\tcase proto.PrimitiveDataType_INT64:\n\t\t\tcastValue, err := strconv.ParseInt(strVal, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tscalarAttr.SetInt64(castValue)\n\t\t\treturn nil\n\t\tcase proto.PrimitiveDataType_FLOAT64:\n\t\t\tcastValue, err := strconv.ParseFloat(strVal, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tscalarAttr.SetDouble(castValue)\n\t\t\treturn nil\n\t\tcase proto.PrimitiveDataType_DATETIME: // return int64 value\n\t\t\tif stringutil.IsDateString(strVal) {\n\t\t\t\tunixSec, err := stringutil.StringToUnixSec(strVal)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to parse datetime constant %q: %v\", strVal, err)\n\t\t\t\t}\n\t\t\t\tscalarAttr.SetInt64(unixSec)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"datetime constant format should be 'YYYY-MM-DD hh:mm:ss', but got %s\", strVal)\n\t\tcase proto.PrimitiveDataType_TIMESTAMP:\n\t\t\tunixSec, err := stringutil.StringToUnixSecWithTimezone(strVal)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to parse timestamp constant %q: %v\", strVal, err)\n\t\t\t}\n\t\t\tscalarAttr.SetInt64(unixSec)\n\t\t\treturn nil\n\t\t}\n\tcase proto.PrimitiveDataType_INT32, proto.PrimitiveDataType_INT64:\n\t\tintVal, ok := originalValue.(int64)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"expected int64 value\")\n\t\t}\n\t\tswitch castType.DType {\n\t\tcase proto.PrimitiveDataType_FLOAT64:\n\t\t\tscalarAttr.SetDouble(float64(intVal))\n\t\t\treturn nil\n\t\tcase proto.PrimitiveDataType_STRING:\n\t\t\tscalarAttr.SetString(strconv.FormatInt(intVal, 10))\n\t\t\treturn nil\n\t\t}\n\tcase proto.PrimitiveDataType_FLOAT32, proto.PrimitiveDataType_FLOAT64:\n\t\tfloatVal, ok := originalValue.(float64)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"expected float64 value\")\n\t\t}\n\t\tswitch castType.DType {\n\t\tcase proto.PrimitiveDataType_INT64:\n\t\t\tscalarAttr.SetInt64(int64(floatVal))\n\t\t\treturn nil\n\t\tcase proto.PrimitiveDataType_STRING:\n\t\t\tscalarAttr.SetString(fmt.Sprintf(\"%f\", floatVal))\n\t\t\treturn nil\n\t\t}\n\tcase proto.PrimitiveDataType_BOOL:\n\t\tboolVal, ok := originalValue.(bool)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"expected bool value\")\n\t\t}\n\t\tswitch castType.DType {\n\t\tcase proto.PrimitiveDataType_INT32:\n\t\t\tif boolVal {\n\t\t\t\tscalarAttr.SetInt(1)\n\t\t\t\treturn nil\n\t\t\t} else {\n\t\t\t\tscalarAttr.SetInt(0)\n\t\t\t\treturn nil\n\t\t\t}\n\t\tcase proto.PrimitiveDataType_STRING:\n\t\t\tscalarAttr.SetString(strconv.FormatBool(boolVal))\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn fmt.Errorf(\"invalid cast from %v to %v\", originType, castType)\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/graph_optimizer_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/operator\"\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// createConstantNode creates a constant node with the given value and type\nfunc createConstantNode(id int, value any, dtype *DataType) *ExecutionNode {\n\tattr := &Attribute{}\n\tswitch v := value.(type) {\n\tcase string:\n\t\tattr.SetString(v)\n\tcase int64:\n\t\tattr.SetInt64(v)\n\tcase float64:\n\t\tattr.SetDouble(v)\n\t}\n\n\ttensor := createTestTensor(id, \"constant_out\", 0)\n\ttensor.DType = dtype\n\n\tnode := createTestExecutionNode(id, \"constant\", nil, []*Tensor{tensor})\n\tnode.OpType = operator.OpNameConstant\n\tnode.Attributes[\"scalar\"] = attr\n\tnode.Outputs = make(map[string][]*Tensor)\n\tnode.Outputs[\"Out\"] = []*Tensor{tensor}\n\treturn node\n}\n\n// createBroadcastNode creates a BroadcastTo node\nfunc createBroadcastNode(id int, input *Tensor) *ExecutionNode {\n\toutput := createTestTensor(id+100, \"broadcast_out\", 0) // Use different ID for output\n\toutput.DType = input.DType\n\n\tnode := createTestExecutionNode(id, \"broadcast\", []*Tensor{input}, []*Tensor{output})\n\tnode.OpType = operator.OpNameBroadcastTo\n\tnode.Outputs = make(map[string][]*Tensor)\n\tnode.Outputs[\"Out\"] = []*Tensor{output}\n\treturn node\n}\n\n// createCastNode creates a Cast node\nfunc createCastNode(id int, input *Tensor, targetType *DataType) *ExecutionNode {\n\toutput := createTestTensor(id+200, \"cast_out\", 0) // Use different ID for output\n\toutput.DType = targetType\n\n\tnode := createTestExecutionNode(id, \"cast\", []*Tensor{input}, []*Tensor{output})\n\tnode.OpType = operator.OpNameCast\n\tnode.Outputs = make(map[string][]*Tensor)\n\tnode.Outputs[\"Out\"] = []*Tensor{output}\n\treturn node\n}\n\nfunc testConstantCastOptimization(t *testing.T, originValue interface{},\n\toriginType, castType *DataType, expectedValue interface{}) {\n\tr := require.New(t)\n\n\t// Create the graph: Constant -> Broadcast -> Cast\n\tconstNode := createConstantNode(1, originValue, originType)\n\tbroadcastNode := createBroadcastNode(2, constNode.Outputs[\"Out\"][0])\n\tcastNode := createCastNode(3, broadcastNode.Outputs[\"Out\"][0], castType)\n\n\t// Add edges\n\tcreateTestEdge(constNode, broadcastNode, constNode.Outputs[\"Out\"][0])\n\tcreateTestEdge(broadcastNode, castNode, broadcastNode.Outputs[\"Out\"][0])\n\n\t// Create pipeline and graph\n\tpipeline := createTestPipeline([]*ExecutionNode{constNode, broadcastNode, castNode}, false)\n\tgraph := createTestGraph([]*Pipeline{pipeline})\n\n\t// Verify initial state\n\tpipelineNodes, err := graph.TopologicalSort()\n\tr.NoError(err)\n\tr.Len(pipelineNodes, 1)\n\tr.Len(pipelineNodes[0], 3) // const, broadcast, cast\n\n\t// Apply optimization\n\toptimizer := NewGraphOptimizer()\n\terr = optimizer.Optimize(graph)\n\tr.NoError(err)\n\n\t// Verify optimization result\n\tpipelineNodes, err = graph.TopologicalSort()\n\tr.NoError(err)\n\tr.Len(pipelineNodes, 1)\n\tr.Len(pipelineNodes[0], 2) // cast node removed\n\n\t// Find constant node and verify cast was applied\n\tvar optimizedConst *ExecutionNode\n\tfor _, node := range pipelineNodes[0] {\n\t\tif node.Name == \"constant\" {\n\t\t\toptimizedConst = node\n\t\t\tbreak\n\t\t}\n\t}\n\tr.NotNil(optimizedConst)\n\n\t// Verify the value was cast correctly\n\tscalarAttr := optimizedConst.Attributes[\"scalar\"]\n\tr.NotNil(scalarAttr)\n\tr.Equal(expectedValue, scalarAttr.GetAttrValue())\n\n\t// Verify tensor type was updated\n\toutputTensor := optimizedConst.Outputs[\"Out\"][0]\n\tif castType.IsTimeType() {\n\t\tr.Equal(proto.PrimitiveDataType_INT64, outputTensor.DType.DType)\n\t} else {\n\t\tr.True(castType.Equal(outputTensor.DType))\n\t}\n}\n\nfunc TestOptConstantCast(t *testing.T) {\n\tt.Run(\"StringToDatetime\", func(t *testing.T) {\n\t\ttestConstantCastOptimization(t, \"2025-05-08\", NewPrimitiveDataType(proto.PrimitiveDataType_STRING),\n\t\t\tNewPrimitiveDataType(proto.PrimitiveDataType_DATETIME), int64(1746662400))\n\t})\n\n\tt.Run(\"Int64ToFloat64\", func(t *testing.T) {\n\t\ttestConstantCastOptimization(t, int64(12), NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t\t\tNewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64), float64(12))\n\t})\n\n\tt.Run(\"Float64ToInt64\", func(t *testing.T) {\n\t\ttestConstantCastOptimization(t, float64(12.2), NewPrimitiveDataType(proto.PrimitiveDataType_FLOAT64),\n\t\t\tNewPrimitiveDataType(proto.PrimitiveDataType_INT64), int64(12))\n\t})\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/graph_partitioner.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype WorkerSubDAG struct {\n\tNodes map[*ExecutionNode]bool\n}\n\n// String returns a string representation of the WorkerSubDAG\nfunc (s *WorkerSubDAG) String() string {\n\tvar sb strings.Builder\n\tsb.WriteString(\"WorkerSubDAG{\\n\")\n\tsb.WriteString(fmt.Sprintf(\"  Nodes: %d,\\n\", len(s.Nodes)))\n\tsb.WriteString(\"  ExecutionNodes: [\\n\")\n\n\tfor node := range s.Nodes {\n\t\tsb.WriteString(\"    \")\n\t\tsb.WriteString(node.ToString())\n\t\tsb.WriteString(\",\\n\")\n\t}\n\n\tsb.WriteString(\"  ]\\n}\")\n\treturn sb.String()\n}\n\ntype PartitionedPipeline struct {\n\tBatched       bool\n\tInputTensors  []*Tensor\n\tOutputTensors []*Tensor\n\tSubDAGs       []*WorkerSubDAG\n}\n\n// String returns a string representation of the PartitionedPipeline\nfunc (p *PartitionedPipeline) String() string {\n\tvar sb strings.Builder\n\tsb.WriteString(\"PartitionedPipeline{\\n\")\n\tsb.WriteString(fmt.Sprintf(\"  Batched: %t,\\n\", p.Batched))\n\n\tif p.Batched {\n\t\tsb.WriteString(fmt.Sprintf(\"  InputTensors: %d,\\n\", len(p.InputTensors)))\n\t\tsb.WriteString(fmt.Sprintf(\"  OutputTensors: %d,\\n\", len(p.OutputTensors)))\n\t}\n\n\t// Add SubDAGs details\n\tsb.WriteString(\"  SubDAGs: [\\n\")\n\tfor _, subDAG := range p.SubDAGs {\n\t\t// Indent SubDAG content\n\t\tsubDAGStr := subDAG.String()\n\t\tlines := strings.Split(subDAGStr, \"\\n\")\n\t\tfor _, line := range lines {\n\t\t\tif line != \"\" {\n\t\t\t\tsb.WriteString(\"    \")\n\t\t\t\tsb.WriteString(line)\n\t\t\t\tsb.WriteString(\"\\n\")\n\t\t\t}\n\t\t}\n\t\tsb.WriteString(\",\\n\")\n\t}\n\tsb.WriteString(\"  ]\\n}\")\n\treturn sb.String()\n}\n\ntype GraphPartitioner struct {\n\tGraph     *Graph\n\tPipelines []*PartitionedPipeline\n}\n\nfunc NewGraphPartitioner(input *Graph) *GraphPartitioner {\n\treturn &GraphPartitioner{\n\t\tGraph: input,\n\t}\n}\n\n// NaivePartition a graph by topological sort order\nfunc (p *GraphPartitioner) NaivePartition() error {\n\tp.Graph.UpdateTensorRefNum()\n\tpipelineNodes, err := p.Graph.TopologicalSort()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor i, nodes := range pipelineNodes {\n\t\tpipeline := &PartitionedPipeline{Batched: p.Graph.Pipelines[i].Batched}\n\t\tif pipeline.Batched {\n\t\t\tpipeline.InputTensors = p.Graph.Pipelines[i].InputTensors\n\t\t\tpipeline.OutputTensors = p.Graph.Pipelines[i].OutputTensors\n\t\t}\n\t\tfor _, node := range nodes {\n\t\t\tsubDAG := &WorkerSubDAG{\n\t\t\t\tNodes: make(map[*ExecutionNode]bool),\n\t\t\t}\n\t\t\tsubDAG.Nodes[node] = true\n\t\t\tpipeline.SubDAGs = append(pipeline.SubDAGs, subDAG)\n\t\t}\n\t\tp.Pipelines = append(p.Pipelines, pipeline)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/graph_splitter.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"sort\"\n)\n\n// PartySubDAG struct\ntype PartySubDAG struct {\n\tNodes     []*ExecutionNode\n\tPartyCode string\n}\n\nfunc splitExecutionNode(node *ExecutionNode) map[string]*ExecutionNode {\n\tresult := make(map[string]*ExecutionNode)\n\tfor _, party := range node.Parties {\n\t\tresult[party] = &ExecutionNode{\n\t\t\tID:         node.ID,\n\t\t\tName:       node.Name,\n\t\t\tOpType:     node.OpType,\n\t\t\tInputs:     node.Inputs,\n\t\t\tOutputs:    node.Outputs,\n\t\t\tAttributes: node.Attributes,\n\t\t}\n\t}\n\treturn result\n}\n\n// Split a subDAG into several party subDAGs\nfunc Split(subDag *WorkerSubDAG) (map[string]*PartySubDAG, error) {\n\tpartyNodes := make([]*ExecutionNode, 0)\n\tsinglePartyNodes := make([]*ExecutionNode, 0)\n\tfor node := range subDag.Nodes {\n\t\tif len(node.Parties) == 1 {\n\t\t\tsinglePartyNodes = append(singlePartyNodes, node)\n\t\t} else {\n\t\t\tpartyNodes = append(partyNodes, node)\n\t\t}\n\t}\n\tsort.Slice(partyNodes, func(i, j int) bool { return partyNodes[i].Name < partyNodes[j].Name })\n\tsort.Slice(singlePartyNodes, func(i, j int) bool { return singlePartyNodes[i].Name < singlePartyNodes[j].Name })\n\tpartyNodes = append(partyNodes, singlePartyNodes...)\n\n\tresult := make(map[string]*PartySubDAG)\n\tfor _, node := range partyNodes {\n\t\tnodes := splitExecutionNode(node)\n\t\tfor party, n := range nodes {\n\t\t\t_, ok := result[party]\n\t\t\tif !ok {\n\t\t\t\tresult[party] = &PartySubDAG{\n\t\t\t\t\tNodes:     make([]*ExecutionNode, 0),\n\t\t\t\t\tPartyCode: party,\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult[party].Nodes = append(result[party].Nodes, n)\n\t\t}\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/graph_splitter_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// Helper to create test tensor with owner\nfunc createTestTensorWithOwner(id int, name, owner string) *Tensor {\n\ttensor := &Tensor{\n\t\tID:     id,\n\t\tName:   name,\n\t\tDType:  NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t\tRefNum: 0,\n\t}\n\ttensor.SetStatus(proto.TensorStatus_TENSORSTATUS_PRIVATE)\n\ttensor.OwnerPartyCode = owner\n\treturn tensor\n}\n\n// Helper to create test execution node\nfunc createTestExecutionNodeForSplitter(id int, name string, parties []string, inputs, outputs []*Tensor) *ExecutionNode {\n\tnode := &ExecutionNode{\n\t\tID:         id,\n\t\tName:       name,\n\t\tOpType:     \"TestOp\",\n\t\tInputs:     make(map[string][]*Tensor),\n\t\tOutputs:    make(map[string][]*Tensor),\n\t\tAttributes: make(map[string]*Attribute),\n\t\tEdges:      make(map[*Edge]bool),\n\t\tParties:    parties,\n\t}\n\n\tif len(inputs) > 0 {\n\t\tnode.Inputs[\"input\"] = inputs\n\t}\n\tif len(outputs) > 0 {\n\t\tnode.Outputs[\"output\"] = outputs\n\t}\n\n\treturn node\n}\n\n// Helper to create test SubDAG\nfunc createTestSubDAG(nodes []*ExecutionNode) *WorkerSubDAG {\n\tnodeMap := make(map[*ExecutionNode]bool)\n\tfor _, node := range nodes {\n\t\tnodeMap[node] = true\n\t}\n\treturn &WorkerSubDAG{\n\t\tNodes: nodeMap,\n\t}\n}\n\nfunc TestSplitSimple(t *testing.T) {\n\tr := require.New(t)\n\n\t// Create test tensors\n\tt0 := createTestTensorWithOwner(0, \"t0\", \"alice\")\n\tt1 := createTestTensorWithOwner(1, \"t1\", \"bob\")\n\tt2 := createTestTensorWithOwner(2, \"t2\", \"carol\")\n\n\t// Create execution nodes\n\trunSQLNode1 := createTestExecutionNodeForSplitter(0, \"RunSQLOp1\", []string{\"alice\"}, nil, []*Tensor{t0})\n\trunSQLNode2 := createTestExecutionNodeForSplitter(1, \"RunSQLOp2\", []string{\"bob\"}, nil, []*Tensor{t1})\n\trunSQLNode3 := createTestExecutionNodeForSplitter(2, \"RunSQLOp3\", []string{\"carol\"}, nil, []*Tensor{t2})\n\n\tjoinNode1 := createTestExecutionNodeForSplitter(3, \"join\", []string{\"alice\", \"bob\"},\n\t\t[]*Tensor{t0, t1}, []*Tensor{t0})\n\tjoinNode2 := createTestExecutionNodeForSplitter(4, \"join\", []string{\"alice\", \"carol\"},\n\t\t[]*Tensor{t0, t2}, []*Tensor{t0})\n\n\tfilterNode1 := createTestExecutionNodeForSplitter(5, \"filter\", []string{\"alice\"},\n\t\t[]*Tensor{t0}, []*Tensor{t0})\n\tfilterNode2 := createTestExecutionNodeForSplitter(6, \"filter\", []string{\"bob\"},\n\t\t[]*Tensor{t1}, []*Tensor{t1})\n\tfilterNode3 := createTestExecutionNodeForSplitter(7, \"filter\", []string{\"carol\"},\n\t\t[]*Tensor{t2}, []*Tensor{t2})\n\n\tcopyNode := createTestExecutionNodeForSplitter(8, \"copy\", []string{\"alice\", \"bob\"},\n\t\t[]*Tensor{t0}, []*Tensor{t0})\n\n\t// Create test graph with nodes\n\tnodes := []*ExecutionNode{\n\t\trunSQLNode1, runSQLNode2, runSQLNode3,\n\t\tjoinNode1, joinNode2,\n\t\tfilterNode1, filterNode2, filterNode3,\n\t\tcopyNode,\n\t}\n\n\t// Create SubDAG\n\tsubDag := createTestSubDAG(nodes)\n\n\t// Split the SubDAG\n\tpartySubDAGs, err := Split(subDag)\n\tr.NoError(err)\n\n\t// Verify results\n\t// alice: should have 5 nodes (2 single-party nodes + 2 multi-party nodes + 1 copy)\n\tr.Equal(5, len(partySubDAGs[\"alice\"].Nodes))\n\n\t// bob: should have 4 nodes (1 single-party node + 2 multi-party nodes + 1 copy)\n\tr.Equal(4, len(partySubDAGs[\"bob\"].Nodes))\n\n\t// carol: should have 3 nodes (1 single-party node + 2 multi-party nodes)\n\tr.Equal(3, len(partySubDAGs[\"carol\"].Nodes))\n\n\t// Verify node names in each party's subDAG\n\taliceNames := make([]string, 0)\n\tfor _, node := range partySubDAGs[\"alice\"].Nodes {\n\t\taliceNames = append(aliceNames, node.Name)\n\t}\n\tr.Contains(aliceNames, \"RunSQLOp1\")\n\tr.Contains(aliceNames, \"join\")\n\tr.Contains(aliceNames, \"filter\")\n\tr.Contains(aliceNames, \"copy\")\n\n\tbobNames := make([]string, 0)\n\tfor _, node := range partySubDAGs[\"bob\"].Nodes {\n\t\tbobNames = append(bobNames, node.Name)\n\t}\n\tr.Contains(bobNames, \"RunSQLOp2\")\n\tr.Contains(bobNames, \"join\")\n\tr.Contains(bobNames, \"filter\")\n\tr.Contains(bobNames, \"copy\")\n\n\tcarolNames := make([]string, 0)\n\tfor _, node := range partySubDAGs[\"carol\"].Nodes {\n\t\tcarolNames = append(carolNames, node.Name)\n\t}\n\tr.Contains(carolNames, \"RunSQLOp3\")\n\tr.Contains(carolNames, \"join\")\n\tr.Contains(carolNames, \"filter\")\n}\n\nfunc TestSplitEmptySubDAG(t *testing.T) {\n\tr := require.New(t)\n\n\t// Create empty SubDAG\n\tsubDag := createTestSubDAG([]*ExecutionNode{})\n\n\t// Split the SubDAG\n\tpartySubDAGs, err := Split(subDag)\n\tr.NoError(err)\n\tr.Equal(0, len(partySubDAGs))\n}\n\nfunc TestSplitSinglePartyNodes(t *testing.T) {\n\tr := require.New(t)\n\n\t// Create test tensors\n\tt0 := createTestTensorWithOwner(0, \"t0\", \"alice\")\n\tt1 := createTestTensorWithOwner(1, \"t1\", \"bob\")\n\n\t// Create single-party nodes only\n\taliceNode := createTestExecutionNodeForSplitter(0, \"AliceOp\", []string{\"alice\"}, nil, []*Tensor{t0})\n\tbobNode := createTestExecutionNodeForSplitter(1, \"BobOp\", []string{\"bob\"}, nil, []*Tensor{t1})\n\n\tnodes := []*ExecutionNode{aliceNode, bobNode}\n\tsubDag := createTestSubDAG(nodes)\n\n\t// Split the SubDAG\n\tpartySubDAGs, err := Split(subDag)\n\tr.NoError(err)\n\n\t// Verify each party has only their own node\n\tr.Equal(1, len(partySubDAGs[\"alice\"].Nodes))\n\tr.Equal(\"AliceOp\", partySubDAGs[\"alice\"].Nodes[0].Name)\n\n\tr.Equal(1, len(partySubDAGs[\"bob\"].Nodes))\n\tr.Equal(\"BobOp\", partySubDAGs[\"bob\"].Nodes[0].Name)\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/graph_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// Helper to create test tensors\nfunc createTestTensor(id int, name string, refNum int32) *Tensor {\n\treturn &Tensor{\n\t\tID:     id,\n\t\tName:   name,\n\t\tDType:  NewPrimitiveDataType(proto.PrimitiveDataType_INT64),\n\t\tstatus: proto.TensorStatus_TENSORSTATUS_PRIVATE,\n\t\tRefNum: refNum,\n\t}\n}\n\n// Helper to create test execution nodes\nfunc createTestExecutionNode(id int, name string, inputs, outputs []*Tensor) *ExecutionNode {\n\tnode := &ExecutionNode{\n\t\tID:         id,\n\t\tName:       name,\n\t\tOpType:     \"TestOp\",\n\t\tInputs:     make(map[string][]*Tensor),\n\t\tOutputs:    make(map[string][]*Tensor),\n\t\tAttributes: make(map[string]*Attribute),\n\t\tEdges:      make(map[*Edge]bool),\n\t\tParties:    []string{\"alice\", \"bob\"},\n\t}\n\n\tif len(inputs) > 0 {\n\t\tnode.Inputs[\"input\"] = inputs\n\t}\n\tif len(outputs) > 0 {\n\t\tnode.Outputs[\"output\"] = outputs\n\t}\n\n\treturn node\n}\n\n// Helper to create test edges\nfunc createTestEdge(from, to *ExecutionNode, value *Tensor) *Edge {\n\tedge := &Edge{\n\t\tFrom:  from,\n\t\tTo:    to,\n\t\tValue: value,\n\t}\n\tfrom.Edges[edge] = true\n\treturn edge\n}\n\n// Helper to create test pipeline\nfunc createTestPipeline(nodes []*ExecutionNode, batched bool) *Pipeline {\n\tnodeMap := make(map[*ExecutionNode]bool)\n\tfor _, node := range nodes {\n\t\tnodeMap[node] = true\n\t}\n\n\treturn &Pipeline{\n\t\tBatched:       batched,\n\t\tInputTensors:  []*Tensor{},\n\t\tOutputTensors: []*Tensor{},\n\t\tNodes:         nodeMap,\n\t}\n}\n\n// Helper to create test graph with party info\nfunc createTestGraph(pipelines []*Pipeline) *Graph {\n\tpartyInfo := NewPartyInfo([]*Participant{\n\t\t{PartyCode: \"alice\", Endpoints: []string{\"alice.com\"}, Token: \"token\"},\n\t\t{PartyCode: \"bob\", Endpoints: []string{\"bob.com\"}, Token: \"token\"},\n\t})\n\n\treturn &Graph{\n\t\tPipelines:   pipelines,\n\t\tNodeCnt:     0,\n\t\tOutputNames: []string{},\n\t\tPartyInfo:   partyInfo,\n\t}\n}\n\nfunc TestGraphUpdateTensorRefNum(t *testing.T) {\n\tr := require.New(t)\n\n\t// Test basic reference counting\n\tt1 := createTestTensor(1, \"t1\", 0)\n\tt2 := createTestTensor(2, \"t2\", 0)\n\tt3 := createTestTensor(3, \"t3\", 0)\n\n\tnodeA := createTestExecutionNode(1, \"A\", nil, []*Tensor{t1})\n\tnodeB := createTestExecutionNode(2, \"B\", []*Tensor{t1}, []*Tensor{t2})\n\tnodeC := createTestExecutionNode(3, \"C\", []*Tensor{t1, t2}, []*Tensor{t3})\n\n\tpipeline := createTestPipeline([]*ExecutionNode{nodeA, nodeB, nodeC}, false)\n\tgraph := createTestGraph([]*Pipeline{pipeline})\n\n\t// Verify initial RefNum\n\tr.Equal(int32(0), t1.RefNum)\n\tr.Equal(int32(0), t2.RefNum)\n\tr.Equal(int32(0), t3.RefNum)\n\n\t// Update reference numbers\n\tgraph.UpdateTensorRefNum()\n\n\t// t1 is input to B and C = 2 references\n\t// t2 is input to C = 1 reference\n\t// t3 has no consumers = 0 reference\n\tr.Equal(int32(2), t1.RefNum)\n\tr.Equal(int32(1), t2.RefNum)\n\tr.Equal(int32(0), t3.RefNum)\n}\n\nfunc TestGraphUpdateTensorRefNumMultiplePipelines(t *testing.T) {\n\tr := require.New(t)\n\n\t// Create two pipelines with shared tensors\n\tt1 := createTestTensor(1, \"t1\", 0)\n\tt2 := createTestTensor(2, \"t2\", 0)\n\n\t// Pipeline 1\n\tnodeA1 := createTestExecutionNode(1, \"A1\", nil, []*Tensor{t1})\n\tnodeB1 := createTestExecutionNode(2, \"B1\", []*Tensor{t1}, []*Tensor{t2})\n\tpipeline1 := createTestPipeline([]*ExecutionNode{nodeA1, nodeB1}, false)\n\n\t// Pipeline 2\n\tnodeA2 := createTestExecutionNode(3, \"A2\", []*Tensor{t1}, []*Tensor{t2})\n\tpipeline2 := createTestPipeline([]*ExecutionNode{nodeA2}, false)\n\n\tgraph := createTestGraph([]*Pipeline{pipeline1, pipeline2})\n\n\t// Update reference numbers\n\tgraph.UpdateTensorRefNum()\n\n\t// t1 is input to B1 and A2 = 2 references\n\t// t2 has no consumers = 0 reference\n\tr.Equal(int32(2), t1.RefNum)\n\tr.Equal(int32(0), t2.RefNum)\n}\n\nfunc TestGraphTopologicalSort(t *testing.T) {\n\tt.Run(\"Linear\", func(t *testing.T) {\n\t\tr := require.New(t)\n\n\t\t// Create A -> B -> C\n\t\tt1 := createTestTensor(1, \"t1\", 0)\n\t\tt2 := createTestTensor(2, \"t2\", 0)\n\t\tt3 := createTestTensor(3, \"t3\", 0)\n\n\t\tnodeA := createTestExecutionNode(1, \"A\", nil, []*Tensor{t1})\n\t\tnodeB := createTestExecutionNode(2, \"B\", []*Tensor{t1}, []*Tensor{t2})\n\t\tnodeC := createTestExecutionNode(3, \"C\", []*Tensor{t2}, []*Tensor{t3})\n\n\t\tcreateTestEdge(nodeA, nodeB, t1)\n\t\tcreateTestEdge(nodeB, nodeC, t2)\n\n\t\tpipeline := createTestPipeline([]*ExecutionNode{nodeA, nodeB, nodeC}, false)\n\t\tgraph := createTestGraph([]*Pipeline{pipeline})\n\n\t\tresult, err := graph.TopologicalSort()\n\t\tr.NoError(err)\n\t\tr.Len(result, 1)\n\t\tr.Equal([]*ExecutionNode{nodeA, nodeB, nodeC}, result[0])\n\t})\n\n\tt.Run(\"Diamond\", func(t *testing.T) {\n\t\tr := require.New(t)\n\n\t\t// Create diamond shape: A -> [B, C] -> D\n\t\tt1 := createTestTensor(1, \"t1\", 0)\n\t\tt2 := createTestTensor(2, \"t2\", 0)\n\t\tt3 := createTestTensor(3, \"t3\", 0)\n\t\tt4 := createTestTensor(4, \"t4\", 0)\n\n\t\tnodeA := createTestExecutionNode(1, \"A\", nil, []*Tensor{t1})\n\t\tnodeB := createTestExecutionNode(2, \"B\", []*Tensor{t1}, []*Tensor{t2})\n\t\tnodeC := createTestExecutionNode(3, \"C\", []*Tensor{t1}, []*Tensor{t3})\n\t\tnodeD := createTestExecutionNode(4, \"D\", []*Tensor{t2, t3}, []*Tensor{t4})\n\n\t\tcreateTestEdge(nodeA, nodeB, t1)\n\t\tcreateTestEdge(nodeA, nodeC, t1)\n\t\tcreateTestEdge(nodeB, nodeD, t2)\n\t\tcreateTestEdge(nodeC, nodeD, t3)\n\n\t\tpipeline := createTestPipeline([]*ExecutionNode{nodeA, nodeB, nodeC, nodeD}, false)\n\t\tgraph := createTestGraph([]*Pipeline{pipeline})\n\n\t\tresult, err := graph.TopologicalSort()\n\t\tr.NoError(err)\n\t\tr.Len(result, 1)\n\n\t\t// Verify A is first, D is last, B and C in between (sorted by ID)\n\t\tr.Equal(nodeA, result[0][0])\n\t\tr.Equal(nodeD, result[0][3])\n\t\tr.Equal(nodeB, result[0][1])\n\t\tr.Equal(nodeC, result[0][2])\n\t})\n\n\tt.Run(\"Cycle\", func(t *testing.T) {\n\t\tr := require.New(t)\n\n\t\t// Create A -> B -> C -> A (cycle)\n\t\tt1 := createTestTensor(1, \"t1\", 0)\n\t\tt2 := createTestTensor(2, \"t2\", 0)\n\t\tt3 := createTestTensor(3, \"t3\", 0)\n\n\t\tnodeA := createTestExecutionNode(1, \"A\", []*Tensor{t3}, []*Tensor{t1})\n\t\tnodeB := createTestExecutionNode(2, \"B\", []*Tensor{t1}, []*Tensor{t2})\n\t\tnodeC := createTestExecutionNode(3, \"C\", []*Tensor{t2}, []*Tensor{t3})\n\n\t\tcreateTestEdge(nodeA, nodeB, t1)\n\t\tcreateTestEdge(nodeB, nodeC, t2)\n\t\tcreateTestEdge(nodeC, nodeA, t3)\n\n\t\tpipeline := createTestPipeline([]*ExecutionNode{nodeA, nodeB, nodeC}, false)\n\t\tgraph := createTestGraph([]*Pipeline{pipeline})\n\n\t\tresult, err := graph.TopologicalSort()\n\t\tr.Error(err)\n\t\tr.Contains(err.Error(), \"topological sort fail: maybe circle in graph\")\n\t\tr.Nil(result)\n\t})\n\n\tt.Run(\"SelfLoop\", func(t *testing.T) {\n\t\tr := require.New(t)\n\n\t\t// Create node A with self-loop\n\t\tt1 := createTestTensor(1, \"t1\", 0)\n\t\tnodeA := createTestExecutionNode(1, \"A\", []*Tensor{t1}, []*Tensor{t1})\n\t\tcreateTestEdge(nodeA, nodeA, t1)\n\n\t\tpipeline := createTestPipeline([]*ExecutionNode{nodeA}, false)\n\t\tgraph := createTestGraph([]*Pipeline{pipeline})\n\n\t\tresult, err := graph.TopologicalSort()\n\t\tr.Error(err)\n\t\tr.Contains(err.Error(), \"topological sort fail: maybe circle in graph\")\n\t\tr.Nil(result)\n\t})\n\n\tt.Run(\"IndependentNodes\", func(t *testing.T) {\n\t\tr := require.New(t)\n\n\t\t// Create nodes A, B, C with no dependencies\n\t\tt1 := createTestTensor(1, \"t1\", 0)\n\t\tt2 := createTestTensor(2, \"t2\", 0)\n\t\tt3 := createTestTensor(3, \"t3\", 0)\n\n\t\tnodeA := createTestExecutionNode(3, \"A\", nil, []*Tensor{t1}) // Higher ID\n\t\tnodeB := createTestExecutionNode(1, \"B\", nil, []*Tensor{t2}) // Lower ID\n\t\tnodeC := createTestExecutionNode(2, \"C\", nil, []*Tensor{t3}) // Middle ID\n\n\t\tpipeline := createTestPipeline([]*ExecutionNode{nodeA, nodeB, nodeC}, false)\n\t\tgraph := createTestGraph([]*Pipeline{pipeline})\n\n\t\tresult, err := graph.TopologicalSort()\n\t\tr.NoError(err)\n\t\tr.Len(result, 1)\n\n\t\t// Should be sorted by ID for determinism: B(1), C(2), A(3)\n\t\tr.Equal([]*ExecutionNode{nodeB, nodeC, nodeA}, result[0])\n\t})\n\n\tt.Run(\"EmptyGraph\", func(t *testing.T) {\n\t\tr := require.New(t)\n\n\t\tgraph := createTestGraph([]*Pipeline{})\n\n\t\tresult, err := graph.TopologicalSort()\n\t\tr.NoError(err)\n\t\tr.Len(result, 0)\n\t})\n\n\tt.Run(\"EmptyPipeline\", func(t *testing.T) {\n\t\tr := require.New(t)\n\n\t\temptyPipeline := createTestPipeline([]*ExecutionNode{}, false)\n\t\tgraph := createTestGraph([]*Pipeline{emptyPipeline})\n\n\t\tresult, err := graph.TopologicalSort()\n\t\tr.NoError(err)\n\t\tr.Len(result, 1)\n\t\tr.Len(result[0], 0)\n\t})\n\n\tt.Run(\"MultiplePipelines\", func(t *testing.T) {\n\t\tr := require.New(t)\n\n\t\t// Pipeline 1: A -> B\n\t\tt1 := createTestTensor(1, \"t1\", 0)\n\t\tt2 := createTestTensor(2, \"t2\", 0)\n\t\tnodeA := createTestExecutionNode(1, \"A\", nil, []*Tensor{t1})\n\t\tnodeB := createTestExecutionNode(2, \"B\", []*Tensor{t1}, []*Tensor{t2})\n\t\tcreateTestEdge(nodeA, nodeB, t1)\n\t\tpipeline1 := createTestPipeline([]*ExecutionNode{nodeA, nodeB}, false)\n\n\t\t// Pipeline 2: C -> D\n\t\tt3 := createTestTensor(3, \"t3\", 0)\n\t\tt4 := createTestTensor(4, \"t4\", 0)\n\t\tnodeC := createTestExecutionNode(1, \"C\", nil, []*Tensor{t3})\n\t\tnodeD := createTestExecutionNode(2, \"D\", []*Tensor{t3}, []*Tensor{t4})\n\t\tcreateTestEdge(nodeC, nodeD, t3)\n\t\tpipeline2 := createTestPipeline([]*ExecutionNode{nodeC, nodeD}, false)\n\n\t\tgraph := createTestGraph([]*Pipeline{pipeline1, pipeline2})\n\n\t\tresult, err := graph.TopologicalSort()\n\t\tr.NoError(err)\n\t\tr.Len(result, 2)\n\t\tr.Equal([]*ExecutionNode{nodeA, nodeB}, result[0])\n\t\tr.Equal([]*ExecutionNode{nodeC, nodeD}, result[1])\n\t})\n}\n\nfunc TestGraphPartyInfo(t *testing.T) {\n\tr := require.New(t)\n\n\tgraph := &Graph{\n\t\tPartyInfo: NewPartyInfo([]*Participant{\n\t\t\t{PartyCode: \"alice\", Endpoints: []string{\"alice.com\"}, Token: \"token\"},\n\t\t\t{PartyCode: \"bob\", Endpoints: []string{\"bob.com\"}, Token: \"token\"},\n\t\t}),\n\t}\n\n\t// Test GetParties\n\tparties := graph.GetParties()\n\tr.Equal([]string{\"alice\", \"bob\"}, parties)\n\n\t// Test GetUrlByParty\n\turl, err := graph.GetUrlByParty(\"alice\")\n\tr.NoError(err)\n\tr.Equal(\"alice.com\", url)\n\n\t// Test error case\n\t_, err = graph.GetUrlByParty(\"nonexistent\")\n\tr.Error(err)\n\tr.Contains(err.Error(), \"no party named nonexistent\")\n}\n"
  },
  {
    "path": "pkg/interpreter/graph/tensor.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage graph\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// Tensor struct\ntype Tensor struct {\n\tID     int\n\tName   string\n\tOption proto.TensorOptions\n\tDType  *DataType\n\tstatus proto.TensorStatus\n\tShape  []int\n\t// TODO add more data types\n\tStringS  []string\n\tFloatS   []float32\n\tDoubleS  []float64\n\tInt32S   []int32\n\tInt64S   []int64\n\tBooleanS []bool\n\t// `OwnerPartyCode` make sense only when tensor is in private status\n\tOwnerPartyCode string\n\t// used to record parties who convert string into secret, they may need to participate revealing secret string later.\n\tSecretStringOwners []string\n\n\t// `IsConstScalar` is true when the tensor's data is constant scalar,\n\t// or the result of expression which only contains constant scalar.\n\tIsConstScalar bool\n\n\tRefNum int32\n}\n\n// ToString dumps a debug string of the tensor\nfunc (t *Tensor) ToString() string {\n\treturn t.ToBriefString()\n}\n\nfunc (t *Tensor) String() string {\n\tvar builder strings.Builder\n\tfmt.Fprintf(&builder, \"t_%d\", t.ID)\n\treturn builder.String()\n}\n\nfunc (t Tensor) Status() proto.TensorStatus {\n\treturn t.status\n}\n\nfunc (t *Tensor) SetStatus(s proto.TensorStatus) {\n\tt.status = s\n}\n\n// ToBriefString dumps a brief string of the tensor\nfunc (t *Tensor) ToBriefString() string {\n\tvar builder strings.Builder\n\tfmt.Fprintf(&builder, \"t_%d:{\", t.ID)\n\tfmt.Fprintf(&builder, \"%s:%s:%s}\",\n\t\tshortName(t.Name),\n\t\tShortStatus(proto.TensorStatus_name[int32(t.Status())]),\n\t\tt.DType.String(),\n\t)\n\treturn builder.String()\n}\n\nfunc shortName(name string) string {\n\ts := strings.Split(name, \".\")\n\treturn s[len(s)-1]\n}\n\nfunc ShortStatus(status string) string {\n\ts := strings.Split(status, \"_\")\n\treturn s[len(s)-1]\n}\n\n// NewTensor creates a tensor instance\nfunc NewTensor(id int, name string) *Tensor {\n\treturn &Tensor{\n\t\tID:   id,\n\t\tName: name,\n\t}\n}\n\nfunc (t *Tensor) UniqueName() string {\n\treturn fmt.Sprintf(\"%s.%d\", t.Name, t.ID)\n}\n\nfunc TensorNameFromUniqueName(uniqName string) string {\n\tss := strings.Split(uniqName, \".\")\n\treturn strings.Join(ss[:len(ss)-1], \".\")\n}\n\nfunc NewTensorFromProto(pb *proto.Tensor) *Tensor {\n\tt := &Tensor{\n\t\tName:   pb.Name,\n\t\tOption: pb.Option,\n\t\tDType:  NewDataType(pb.ElemType, pb.Width, pb.Scale),\n\t\tRefNum: pb.RefNum,\n\t}\n\n\tif pb.Annotation != nil {\n\t\tt.SetStatus(pb.Annotation.Status)\n\t}\n\n\tswitch pb.ElemType {\n\tcase proto.PrimitiveDataType_BOOL:\n\t\tdst := make([]bool, len(pb.BoolData))\n\t\tcopy(dst, pb.BoolData)\n\t\tt.BooleanS = dst\n\tcase proto.PrimitiveDataType_STRING:\n\t\tdst := make([]string, len(pb.StringData))\n\t\tcopy(dst, pb.StringData)\n\t\tt.StringS = dst\n\tcase proto.PrimitiveDataType_INT8, proto.PrimitiveDataType_INT16, proto.PrimitiveDataType_INT32:\n\t\tdst := make([]int32, len(pb.Int32Data))\n\t\tcopy(dst, pb.Int32Data)\n\t\tt.Int32S = dst\n\tcase proto.PrimitiveDataType_INT64:\n\t\tdst := make([]int64, len(pb.Int64Data))\n\t\tcopy(dst, pb.Int64Data)\n\t\tt.Int64S = dst\n\tcase proto.PrimitiveDataType_FLOAT32:\n\t\tdst := make([]float32, len(pb.FloatData))\n\t\tcopy(dst, pb.FloatData)\n\t\tt.FloatS = dst\n\tcase proto.PrimitiveDataType_FLOAT64:\n\t\tdst := make([]float64, len(pb.DoubleData))\n\t\tcopy(dst, pb.DoubleData)\n\t\tt.DoubleS = dst\n\t}\n\n\tif x := pb.Shape; x != nil {\n\t\tvar shape []int\n\t\tfor _, s := range x.Dim {\n\t\t\tshape = append(shape, int(s.GetDimValue()))\n\t\t}\n\t\tt.Shape = shape\n\t}\n\n\treturn t\n}\n\n// ToProto serializes in-memory tensor to proto\nfunc (t *Tensor) ToProto() *proto.Tensor {\n\tpb := &proto.Tensor{\n\t\tName:     t.UniqueName(),\n\t\tOption:   t.Option,\n\t\tElemType: t.DType.DType,\n\t\tWidth:    t.DType.Width,\n\t\tScale:    t.DType.Scale,\n\t\tRefNum:   t.RefNum,\n\t}\n\tif t.Status() != proto.TensorStatus_TENSORSTATUS_UNKNOWN {\n\t\tpb.Annotation = &proto.TensorAnnotation{\n\t\t\tStatus: t.Status()}\n\t}\n\n\tif len(t.Shape) > 0 {\n\t\tpb.Shape = &proto.TensorShape{\n\t\t\tDim: []*proto.TensorShape_Dimension{},\n\t\t}\n\t\tfor _, s := range t.Shape {\n\t\t\tdim := &proto.TensorShape_Dimension{\n\t\t\t\tValue: &proto.TensorShape_Dimension_DimValue{DimValue: int64(s)},\n\t\t\t}\n\t\t\tpb.Shape.Dim = append(pb.Shape.Dim, dim)\n\t\t}\n\t}\n\n\tif t.StringS != nil {\n\t\tpb.StringData = t.StringS\n\t}\n\n\tif t.FloatS != nil {\n\t\tpb.FloatData = t.FloatS\n\t}\n\n\tif t.DoubleS != nil {\n\t\tpb.DoubleData = t.DoubleS\n\t}\n\n\tif t.Int32S != nil {\n\t\tpb.Int32Data = t.Int32S\n\t}\n\n\tif t.Int64S != nil {\n\t\tpb.Int64Data = t.Int64S\n\t}\n\n\tif t.BooleanS != nil {\n\t\tpb.BoolData = t.BooleanS\n\t}\n\treturn pb\n}\n"
  },
  {
    "path": "pkg/interpreter/operator/constant.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage operator\n\nimport \"github.com/secretflow/scql/pkg/parser/ast\"\n\nconst (\n\tOpNameConstant      string = \"Constant\"\n\tOpNameMakePrivate   string = \"MakePrivate\"\n\tOpNameMakeShare     string = \"MakeShare\"\n\tOpNameMakePublic    string = \"MakePublic\"\n\tOpNameFilterByIndex string = \"FilterByIndex\"\n\tOpNameBucket        string = \"Bucket\"\n\tOpNameJoin          string = \"Join\"\n\tOpNameSecretJoin    string = \"SecretJoin\"\n\tOpNameRunSQL        string = \"RunSQL\"\n\tOpNamePublish       string = \"Publish\"\n\tOpNameDumpFile      string = \"DumpFile\"\n\tOpNameInsertTable   string = \"InsertTable\"\n\tOpNameCopy          string = \"Copy\"\n\tOpNameFilter        string = \"Filter\"\n\tOpNameGreatest      string = \"Greatest\"\n\tOpNameLeast         string = \"Least\"\n\tOpNameIn            string = \"In\"\n\tOpNameReplicate     string = \"Replicate\"\n\tOpNameBroadcastTo   string = \"BroadcastTo\"\n\tOpNameCast          string = \"Cast\"\n\tOpNameLimit         string = \"Limit\"\n\tOpNameIsNull        string = \"IsNull\"\n\tOpNameArrowFunc     string = \"ArrowFunc\"\n\t// binary ops\n\tOpNameLess         string = \"Less\"\n\tOpNameLessEqual    string = \"LessEqual\"\n\tOpNameGreater      string = \"Greater\"\n\tOpNameGreaterEqual string = \"GreaterEqual\"\n\tOpNameEqual        string = \"Equal\"\n\tOpNameNotEqual     string = \"NotEqual\"\n\tOpNameLogicalAnd   string = \"LogicalAnd\"\n\tOpNameLogicalOr    string = \"LogicalOr\"\n\tOpNamePow          string = \"Pow\"\n\t// arithmetic ops\n\tOpNameAdd    string = \"Add\"\n\tOpNameMinus  string = \"Minus\"\n\tOpNameMul    string = \"Mul\"\n\tOpNameDiv    string = \"Div\"\n\tOpNameIntDiv string = \"IntDiv\"\n\tOpNameMod    string = \"Mod\"\n\tOpNameNot    string = \"Not\"\n\tOpNameSin    string = \"Sin\"\n\tOpNameCos    string = \"Cos\"\n\tOpNameACos   string = \"ACos\"\n\tOpNameASin   string = \"ASin\"\n\tOpNameTan    string = \"Tan\"\n\tOpNameCot    string = \"Cot\"\n\tOpNameATan   string = \"ATan\"\n\tOpNameATan2  string = \"ATan2\"\n\t// OpNameACot   string = \"ACot\"\n\t// agg\n\tOpNameReduceSum string = \"ReduceSum\"\n\tOpNameReduceMax string = \"ReduceMax\"\n\tOpNameReduceMin string = \"ReduceMin\"\n\t// OpNameReduceMedian string = \"ReduceMedian\"\n\tOpNameReduceAvg            string = \"ReduceAvg\"\n\tOpNameReduceCount          string = \"ReduceCount\"\n\tOpNameReducePercentileDisc string = \"ReducePercentileDisc\"\n\n\t// private group by\n\tOpNameGroup               string = \"Group\"\n\tOpNameGroupSum            string = \"GroupSum\"\n\tOpNameGroupCount          string = \"GroupCount\"\n\tOpNameGroupCountDistinct  string = \"GroupCountDistinct\"\n\tOpNameGroupAvg            string = \"GroupAvg\"\n\tOpNameGroupMin            string = \"GroupMin\"\n\tOpNameGroupMax            string = \"GroupMax\"\n\tOpNameGroupFirstOf        string = \"GroupFirstOf\"\n\tOpNameGroupSecretSum      string = \"GroupSecretSum\"\n\tOpNameGroupSecretAvg      string = \"GroupSecretAvg\"\n\tOpNameGroupPercentileDisc string = \"GroupPercentileDisc\"\n\n\tOpNameUnique                  string = \"Unique\"\n\tOpNameShape                   string = \"Shape\"\n\tOpNameSort                    string = \"Sort\"\n\tOpNameObliviousGroupMark      string = \"ObliviousGroupMark\"\n\tOpNameObliviousGroupCount     string = \"ObliviousGroupCount\"\n\tOpNameObliviousGroupSum       string = \"ObliviousGroupSum\"\n\tOpNameObliviousGroupMax       string = \"ObliviousGroupMax\"\n\tOpNameObliviousGroupMin       string = \"ObliviousGroupMin\"\n\tOpNameObliviousGroupAvg       string = \"ObliviousGroupAvg\"\n\tOpNameObliviousPercentRank    string = \"ObliviousPercentRank\"\n\tOpNameObliviousPercentileDisc string = \"ObliviousPercentileDisc\"\n\tOpNameObliviousRank           string = \"ObliviousRank\"\n\tOpNameShuffle                 string = \"Shuffle\"\n\t// union all\n\tOpNameConcat string = \"Concat\"\n\t// condition ops\n\tOpNameCaseWhen string = \"CaseWhen\"\n\tOpNameIf       string = \"If\"\n\tOpNameIfNull   string = \"IfNull\"\n\tOpNameCoalesce string = \"Coalesce\"\n\n\tOpNameRowNumber   string = \"RowNumber\"\n\tOpNamePercentRank string = \"PercentRank\"\n\tOpNameRank        string = \"Rank\"\n\tOpNameAbs         string = \"Abs\"\n\tOpNameCeil        string = \"Ceil\"\n\tOpNameFloor       string = \"Floor\"\n\tOpNameRound       string = \"Round\"\n\tOpNameDegrees     string = \"Degrees\"\n\tOpNameRadians     string = \"Radians\"\n\tOpNameLn          string = \"Ln\"\n\tOpNameLog10       string = \"Log10\"\n\tOpNameLog2        string = \"Log2\"\n\tOpNameSqrt        string = \"Sqrt\"\n\tOpNameExp         string = \"Exp\"\n)\n\nconst (\n\t// RevealToAttr, used by MakePrivateOp, PSI_In\n\tRevealToAttr = `reveal_to`\n\t// InputPartyCodesAttr, used by PSI_In/Join/Replicate/Copy\n\tInputPartyCodesAttr = `input_party_codes`\n\t// used by Copy\n\tOutputPartyCodesAttr = `output_party_codes`\n\t// used by Limit\n\tLimitCountAttr  = \"count\"\n\tLimitOffsetAttr = \"offset\"\n\t// used by WriteTable\n\tTableNameAttr   = `table_name`\n\tColumnNamesAttr = `column_names`\n\t// AlgorithmAttr\n\tPsiAlgorithmAttr     = `psi_algorithm`\n\tInTypeAttr           = `in_type`\n\tJoinTypeAttr         = `join_type`\n\tSqlAttr              = `sql`\n\tTableRefsAttr        = `table_refs`\n\tScalarAttr           = `scalar`\n\tToStatusAttr         = `to_status`\n\tFilePathAttr         = `file_path`\n\tFieldDeliminatorAttr = `field_deliminator`\n\tQuotingStyleAttr     = `quoting_style`\n\tLineTerminatorAttr   = `line_terminator`\n\tAxisAttr             = `axis`\n\tReverseAttr          = `reverse`\n\tPercentAttr          = `percent`\n\n\tFuncNameAttr    = `func_name`\n\tFuncOptAttr     = `func_options`\n\tFuncOptTypeAttr = `func_opt_type`\n)\n\nvar ReduceAggOp = map[string]string{\n\tast.AggFuncSum: OpNameReduceSum,\n\tast.AggFuncMax: OpNameReduceMax,\n\tast.AggFuncMin: OpNameReduceMin,\n\t// ast.AggFuncMedian: OpNameReduceMedian,\n\tast.AggFuncAvg:        OpNameReduceAvg,\n\tast.AggFuncCount:      OpNameReduceCount,\n\tast.AggPercentileDisc: OpNameReducePercentileDisc,\n}\n\nvar ObliviousGroupAggOp = map[string]string{\n\tast.AggFuncSum:            OpNameObliviousGroupSum,\n\tast.AggFuncMax:            OpNameObliviousGroupMax,\n\tast.AggFuncMin:            OpNameObliviousGroupMin,\n\tast.AggFuncAvg:            OpNameObliviousGroupAvg,\n\tast.AggFuncCount:          OpNameObliviousGroupCount,\n\tast.WindowFuncPercentRank: OpNameObliviousPercentRank,\n\tast.AggPercentileDisc:     OpNameObliviousPercentileDisc,\n\tast.WindowFuncRank:        OpNameObliviousRank,\n}\n\nvar GroupAggOp = map[string]string{\n\tast.AggFuncSum:        OpNameGroupSum,\n\tast.AggFuncMax:        OpNameGroupMax,\n\tast.AggFuncMin:        OpNameGroupMin,\n\tast.AggFuncAvg:        OpNameGroupAvg,\n\tast.AggFuncCount:      OpNameGroupCount,\n\tast.AggFuncFirstRow:   OpNameGroupFirstOf,\n\tast.AggPercentileDisc: OpNameGroupPercentileDisc,\n}\n\nvar GroupSecretAggOp = map[string]string{\n\tast.AggFuncSum: OpNameGroupSecretSum,\n\tast.AggFuncAvg: OpNameGroupSecretAvg,\n}\n\nconst (\n\tPsiIn = 0\n\t// SecretShareIn = 1\n\tLocalIn = 2\n)\n"
  },
  {
    "path": "pkg/interpreter/operator/operator_checker.go",
    "content": "// Copyright 2026 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage operator\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\tpb \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\ntype statusConstraint interface {\n\tStatus() pb.TensorStatus\n}\n\n// CheckParamStatusConstraint check parameter status constraint strictly\nfunc CheckParamStatusConstraint[T statusConstraint](op *OperatorDef, inputs map[string][]T, outputs map[string][]T) error {\n\topDef := op.GetOperatorDefProto()\n\tif len(opDef.InputParams) != len(inputs) {\n\t\treturn fmt.Errorf(\"CheckParamStatusConstraint: op %v len(opDef.InputParams):%v != len(inputs):%v\",\n\t\t\topDef.Name, len(opDef.InputParams), len(inputs))\n\t}\n\tif len(opDef.OutputParams) != len(outputs) {\n\t\treturn fmt.Errorf(\"CheckParamStatusConstraint: op %v len(opDef.OutputParams):%v != len(outputs):%v\",\n\t\t\topDef.Name, len(opDef.OutputParams), len(outputs))\n\t}\n\n\tconstraintNameToStatus := map[string]pb.TensorStatus{}\n\tif err := checkParamStatusConstraintInternal(constraintNameToStatus, inputs, opDef.InputParams, opDef.ParamStatusConstraints); err != nil {\n\t\treturn fmt.Errorf(\"opName %s %v\", opDef.Name, err)\n\t}\n\tif err := checkParamStatusConstraintInternal(constraintNameToStatus, outputs, opDef.OutputParams, opDef.ParamStatusConstraints); err != nil {\n\t\treturn fmt.Errorf(\"opName %s %v\", opDef.Name, err)\n\t}\n\treturn nil\n}\n\nfunc checkParamStatusConstraintInternal[T statusConstraint](constraintNameToStatus map[string]pb.TensorStatus,\n\targs map[string][]T, params []*pb.FormalParameter,\n\tparamStatusConstraint map[string]*pb.TensorStatusList) error {\n\tfor _, param := range params {\n\t\targuments, ok := args[param.ParamName]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"can't find param:%v in arguments\", param.ParamName)\n\t\t}\n\n\t\tif len(arguments) == 0 && param.Option == pb.FormalParameterOptions_FORMALPARAMETEROPTIONS_OPTIONAL {\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(arguments) == 0 {\n\t\t\treturn fmt.Errorf(\"param:%v must contains at least one argument\", param.ParamName)\n\t\t}\n\n\t\texpectedStatus, ok := constraintNameToStatus[param.ParameterStatusConstraintName]\n\t\tif !ok {\n\t\t\tstatusConstraint, ok := paramStatusConstraint[param.ParameterStatusConstraintName]\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"CheckParamStatusConstraint: can't find constraint for param:%v, constraintName:%v\",\n\t\t\t\t\tparam.ParamName, param.ParameterStatusConstraintName)\n\t\t\t}\n\n\t\t\tif !slices.Contains(statusConstraint.Status, args[param.ParamName][0].Status()) {\n\t\t\t\treturn fmt.Errorf(\"CheckParamStatusConstraint: invalid status for param[%v] actual:%v, expected:%v\", param.ParamName, args[param.ParamName][0].Status(), statusConstraint)\n\t\t\t}\n\t\t\tconstraintNameToStatus[param.ParameterStatusConstraintName] = args[param.ParamName][0].Status()\n\t\t} else {\n\t\t\tif args[param.ParamName][0].Status() != expectedStatus {\n\t\t\t\treturn fmt.Errorf(\"param status mismatch, actual:%v, expected:%v\", args[param.ParamName][0].Status(), expectedStatus)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/interpreter/operator/operator_def.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage operator\n\nimport (\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\ntype StreamingOpType int\n\n// This is by design\nconst (\n\tSinkOp StreamingOpType = iota\n\tStreamingOp\n)\n\n// OperatorDef defines the signature of an operator\ntype OperatorDef struct {\n\tproto.OperatorDef\n\terr             error\n\topStreamingType StreamingOpType\n}\n\n// SetName sets name of an operator def\nfunc (op *OperatorDef) SetName(name string) {\n\top.Name = name\n}\n\nfunc (op *OperatorDef) GetName() string {\n\treturn op.Name\n}\n\nfunc (op *OperatorDef) SetStreamingType(typ StreamingOpType) {\n\top.opStreamingType = typ\n}\n\nfunc (op *OperatorDef) GetStreamingType() StreamingOpType {\n\treturn op.opStreamingType\n}\n\n// SetDefinition adds detailed definition of the operator\nfunc (op *OperatorDef) SetDefinition(comment string) {\n\top.Definition = comment\n}\n\n// AddInput adds an input parameter\nfunc (op *OperatorDef) AddInput(name string, doc string, option proto.FormalParameterOptions, statusConstraintName string) {\n\tif op.err != nil {\n\t\treturn\n\t}\n\tinputs := op.InputParams\n\tif inputs == nil {\n\t\top.InputParams = make([]*proto.FormalParameter, 0)\n\t}\n\tparam := &proto.FormalParameter{}\n\tparam.ParamName = name\n\tparam.Option = option\n\tparam.Definition = doc\n\tparam.ParameterStatusConstraintName = statusConstraintName\n\top.InputParams = append(op.InputParams, param)\n}\n\n// AddOutput adds an output parameter\nfunc (op *OperatorDef) AddOutput(name string, doc string, option proto.FormalParameterOptions, statusConstraintName string) {\n\tif op.err != nil {\n\t\treturn\n\t}\n\toutputs := op.OutputParams\n\tif outputs == nil {\n\t\top.OutputParams = make([]*proto.FormalParameter, 0)\n\t}\n\tparam := &proto.FormalParameter{}\n\tparam.ParamName = name\n\tparam.Option = option\n\tparam.Definition = doc\n\tparam.ParameterStatusConstraintName = statusConstraintName\n\top.OutputParams = append(op.OutputParams, param)\n}\n\n// AddAttribute adds an attribute name\nfunc (op *OperatorDef) AddAttribute(name string, definition string) {\n\tif op.err != nil {\n\t\treturn\n\t}\n\top.AttributeParams = append(op.AttributeParams, &proto.FormalAttribute{Name: name, Definition: definition})\n}\n\n// AddDefaultAttributeValue adds default value for attr\nfunc (op *OperatorDef) AddDefaultAttributeValue(name string, attr *proto.AttributeValue) {\n\tif op.err != nil {\n\t\treturn\n\t}\n\tif op.DefaultAttributeValues == nil {\n\t\top.DefaultAttributeValues = make(map[string]*proto.AttributeValue)\n\t}\n\top.DefaultAttributeValues[name] = attr\n}\n\nfunc CreateIntAttribute(data int) *proto.AttributeValue {\n\treturn &proto.AttributeValue{\n\t\tValue: &proto.AttributeValue_T{\n\t\t\tT: &proto.Tensor{\n\t\t\t\tElemType:  proto.PrimitiveDataType_INT64,\n\t\t\t\tInt64Data: []int64{int64(data)},\n\t\t\t}},\n\t}\n}\n\nfunc CreateIntsAttribute(datas []int64) *proto.AttributeValue {\n\treturn &proto.AttributeValue{\n\t\tValue: &proto.AttributeValue_T{\n\t\t\tT: &proto.Tensor{\n\t\t\t\tElemType:  proto.PrimitiveDataType_INT64,\n\t\t\t\tInt64Data: datas,\n\t\t\t\tShape: &proto.TensorShape{\n\t\t\t\t\tDim: []*proto.TensorShape_Dimension{{\n\t\t\t\t\t\tValue: &proto.TensorShape_Dimension_DimValue{DimValue: int64(len(datas))},\n\t\t\t\t\t}},\n\t\t\t\t},\n\t\t\t}},\n\t}\n}\n\nfunc CreateFloatAttribute(data float32) *proto.AttributeValue {\n\treturn &proto.AttributeValue{\n\t\tValue: &proto.AttributeValue_T{\n\t\t\tT: &proto.Tensor{\n\t\t\t\tElemType:  proto.PrimitiveDataType_FLOAT32,\n\t\t\t\tFloatData: []float32{data},\n\t\t\t}},\n\t}\n}\n\nfunc CreateBoolAttribute(data bool) *proto.AttributeValue {\n\treturn &proto.AttributeValue{\n\t\tValue: &proto.AttributeValue_T{\n\t\t\tT: &proto.Tensor{\n\t\t\t\tElemType: proto.PrimitiveDataType_BOOL,\n\t\t\t\tBoolData: []bool{data},\n\t\t\t}},\n\t}\n}\n\nfunc CreateStringAttribute(str string) *proto.AttributeValue {\n\treturn &proto.AttributeValue{\n\t\tValue: &proto.AttributeValue_T{\n\t\t\tT: &proto.Tensor{\n\t\t\t\tElemType:   proto.PrimitiveDataType_STRING,\n\t\t\t\tStringData: []string{str},\n\t\t\t}},\n\t}\n}\n\n// Set param type constraint\nfunc (op *OperatorDef) SetParamTypeConstraint(constraintName string, status []proto.TensorStatus) {\n\tif op.err != nil {\n\t\treturn\n\t}\n\tif op.ParamStatusConstraints == nil {\n\t\top.ParamStatusConstraints = make(map[string]*proto.TensorStatusList)\n\t}\n\top.ParamStatusConstraints[constraintName] = &proto.TensorStatusList{\n\t\tStatus: status,\n\t}\n}\n\nfunc (op *OperatorDef) GetDefaultAttribute() map[string]*proto.AttributeValue {\n\treturn op.DefaultAttributeValues\n}\n\nfunc (op *OperatorDef) GetOperatorDefProto() *proto.OperatorDef {\n\treturn &op.OperatorDef\n}\n"
  },
  {
    "path": "pkg/interpreter/operator/operator_def_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage operator\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\nfunc TestOperatorDef(t *testing.T) {\n\tvar opDef OperatorDef\n\topDef.SetName(\"RunSQL\")\n\topDef.AddInput(\"X\", \"\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, \"T\")\n\topDef.AddInput(\"X1\", \"\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, \"T\")\n\topDef.SetParamTypeConstraint(\"T\", []proto.TensorStatus{proto.TensorStatus_TENSORSTATUS_PRIVATE})\n\tassert.Nil(t, opDef.err)\n\tassert.Equal(t, 2, len(opDef.InputParams))\n\tassert.Equal(t, 0, len(opDef.OutputParams))\n\tassert.Equal(t, 1, len(opDef.ParamStatusConstraints))\n\n\topDef1 := &OperatorDef{}\n\topDef1.SetName(\"RunSQL\")\n\topDef1.AddInput(\"X\", \"\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, \"T\")\n\topDef1.AddInput(\"X1\", \"\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, \"T\")\n\topDef1.AddOutput(\"X2\", \"\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, \"T\")\n\tassert.Nil(t, opDef1.err)\n\tassert.Equal(t, 1, len(opDef1.OutputParams))\n\tassert.Equal(t, 0, len(opDef1.ParamStatusConstraints))\n\n\topDef2 := &OperatorDef{}\n\topDef2.SetName(\"Less\")\n\topDef2.AddInput(\"Left\", \"\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, \"T\")\n\topDef2.AddInput(\"Right\", \"\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, \"T\")\n\topDef1.SetParamTypeConstraint(\"T\", []proto.TensorStatus{proto.TensorStatus_TENSORSTATUS_PUBLIC})\n\tassert.Nil(t, opDef2.err)\n\n\topDef3 := &OperatorDef{}\n\topDef3.SetName(\"Great\")\n\topDef3.AddOutput(\"Out\", \"\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, \"T\")\n\topDef1.SetParamTypeConstraint(\"T\", []proto.TensorStatus{proto.TensorStatus_TENSORSTATUS_SECRET})\n\tassert.Nil(t, opDef3.err)\n\topDef3.AddOutput(\"O\", \"\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, \"T\")\n\tassert.Nil(t, opDef3.err)\n}\n"
  },
  {
    "path": "pkg/interpreter/operator/operator_registration.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage operator\n\nimport (\n\t\"fmt\"\n\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\nconst (\n\tversion = 1\n)\n\nvar AllOpDef []*OperatorDef\n\nvar BinaryOps = []string{\n\tOpNameLess,\n\tOpNameLessEqual,\n\tOpNameGreater,\n\tOpNameGreaterEqual,\n\tOpNameEqual,\n\tOpNameNotEqual,\n\tOpNameLogicalAnd,\n\tOpNameLogicalOr,\n\tOpNameAdd,\n\tOpNameMinus,\n\tOpNameMul,\n\tOpNameDiv,\n\tOpNameIntDiv,\n\tOpNameMod,\n\tOpNameATan2,\n\tOpNamePow,\n}\n\nvar UnaryOps = []string{\n\tOpNameNot,\n}\n\nfunc check(err error) {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc registerAllOpDef() {\n\tconst (\n\t\tT  = \"T\"\n\t\tT1 = \"T1\"\n\t\tT2 = \"T2\"\n\t\tT3 = \"T3\"\n\t)\n\n\tvar statusPrivate = []proto.TensorStatus{proto.TensorStatus_TENSORSTATUS_PRIVATE}\n\tvar statusSecret = []proto.TensorStatus{proto.TensorStatus_TENSORSTATUS_SECRET}\n\tvar statusPublic = []proto.TensorStatus{proto.TensorStatus_TENSORSTATUS_PUBLIC}\n\tvar statusPrivateOrPublic = []proto.TensorStatus{proto.TensorStatus_TENSORSTATUS_PUBLIC, proto.TensorStatus_TENSORSTATUS_PRIVATE}\n\tvar statusPrivateOrSecret = []proto.TensorStatus{proto.TensorStatus_TENSORSTATUS_PRIVATE, proto.TensorStatus_TENSORSTATUS_SECRET}\n\tvar statusSecretOrPublic = []proto.TensorStatus{proto.TensorStatus_TENSORSTATUS_SECRET, proto.TensorStatus_TENSORSTATUS_PUBLIC}\n\tvar statusPrivateOrSecretOrPublic = []proto.TensorStatus{proto.TensorStatus_TENSORSTATUS_PUBLIC, proto.TensorStatus_TENSORSTATUS_PRIVATE, proto.TensorStatus_TENSORSTATUS_SECRET}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameRunSQL)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddOutput(\"Out\", \"Result tensors of the SQL statement.\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddAttribute(SqlAttr, \"SQL statement\")\n\t\topDef.AddAttribute(TableRefsAttr, \"tables referenced by query\")\n\t\topDef.SetDefinition(\"Definition: Run a SQL statement and return a list of tensors in private status\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNamePublish)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Tensors to be published.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Published name of input tensors. Tensors are in TensorOption VALUE.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetDefinition(\"Definition: This operator publishes the DAG results.\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\tfor _, opName := range BinaryOps {\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(opName)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"Left\", \"First operand.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddInput(\"Right\", \"Second operand.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T1)\n\t\topDef.AddOutput(\"Out\", \"Output Tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T2)\n\t\topDef.SetDefinition(fmt.Sprintf(\"Definition: Out = Left `%s` Right\", opName))\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T1, statusPrivateOrSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T2, statusPrivateOrSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameMakePublic)\n\t\t// make public is not a sink op, but for now, we don't support concat share tensors\n\t\t// TODO: fix sink op type\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"Input tensors.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T1)\n\t\topDef.AddOutput(\"Out\", \"Output tensors.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T2)\n\t\topDef.SetDefinition(\"Definition: Convert In tensor from share/private status to public status.\")\n\t\topDef.SetParamTypeConstraint(T1, statusPrivateOrSecret)\n\t\topDef.SetParamTypeConstraint(T2, statusPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameMakePrivate)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"Input tensors.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T1)\n\t\topDef.AddOutput(\"Out\", \"Output tensors.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T2)\n\t\topDef.AddAttribute(RevealToAttr, \"List of parties to see the private data. If it is revealed to one party only, the other party also needs to run the op, but does not have an output. Only the reveal_to party gets the output.\")\n\t\topDef.SetDefinition(\"Definition: Convert In tensor from share status to private status.\")\n\t\topDef.SetParamTypeConstraint(T1, statusSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T2, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameMakeShare)\n\t\t// make share is not a sink op, but for now, we don't support concat share tensors\n\t\t// TODO: fix sink op type\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"Input tensors.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T1)\n\t\topDef.AddOutput(\"Out\", \"Output tensors.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T2)\n\t\topDef.SetDefinition(\"Definition: Convert In tensor from private status to share status.\")\n\t\topDef.SetParamTypeConstraint(T1, statusPrivate)\n\t\topDef.SetParamTypeConstraint(T2, statusSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameJoin)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"Left\", \"Left vector(shape [M][1])\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T1)\n\t\topDef.AddInput(\"Right\", \"Right vector(shape [N][1])\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T1)\n\t\topDef.AddOutput(\"LeftJoinIndex\", \"Joined rows index for left vector(shape [K][1])\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_OPTIONAL, T2)\n\t\topDef.AddOutput(\"RightJoinIndex\", \"Joined rows index for right vector(shape [K][1])\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_OPTIONAL, T2)\n\t\topDef.AddAttribute(InputPartyCodesAttr, \"List of parties the inputs belong to([PartyCodeLeft, PartyCodeRight]).\")\n\t\topDef.AddAttribute(JoinTypeAttr, \"Int64. 0: inner join; 1: left join; 2: right join;\")\n\t\topDef.AddDefaultAttributeValue(JoinTypeAttr, CreateIntAttribute(0))\n\t\topDef.AddAttribute(PsiAlgorithmAttr, \"Choose PSI join algorithm, Int64. 0: Auto; 1: Ecdh; 2: Oprf;\")\n\t\topDef.AddDefaultAttributeValue(PsiAlgorithmAttr, CreateIntAttribute(0))\n\t\topDef.SetDefinition(`Definition: Create Join Index based on EQ-Join, return result's corresponding rows index in the original input.\nExample:\n` + \"\\n```python\" + `\n// inner join example\nLeft = {4,4,3,2,1} // shape:[M=5]\nRight = {1,3,4,5} // shape: [N=4]\njoin_type = 0\nLeftJoinIndex = {4,2,0,1}  // shape:[K=4], rows after applied filter eq-join-list={1,3,4,4}\nRightJoinIndex = {0,1,2,2} // shape:[K=4], rows after applied filter eq-join-list={1,3,4,4}\n\n// Left join example\nLeft = {4,4,3,2,1} // shape:[M=5]\nRight = {1,3,4,5} // shape: [N=4]\njoin_type = 1\nLeftJoinIndex = {4,2,0,1,3}  // shape:[K=5], rows after applied filter eq-join-list={1,3,4,4,2}\nRightJoinIndex = {0,1,2,2,null} // shape:[K=5], rows after applied filter eq-join-list={1,3,4,4,null}\n\n// Right join example\nLeft = {4,4,3,2,1} // shape:[M=5]\nRight = {1,3,4,5} // shape: [N=4]\njoin_type = 2\nLeftJoinIndex = {4,2,0,1,null}  // shape:[K=5], rows after applied filter eq-join-list={1,3,4,4,null}\nRightJoinIndex = {0,1,2,2,3} // shape:[K=5], rows after applied filter eq-join-list={1,3,4,4,5}\n\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T1, statusPrivate)\n\t\topDef.SetParamTypeConstraint(T2, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameFilterByIndex)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"RowsIndexFilter\", \"Rows index filter vector(shape [K][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddInput(\"Data\", \"Input data tensor(shape [M][N]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Output data tensor(shape [X][N]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetDefinition(`Definition: Filter by rows index.\nExample:\n` + \"\\n```python\" + `\nRowsIndexFilter = {3,1,0}\nData = [{\"a\", \"b\", \"c\", \"d\"}, {0, 1, 2, 3}]\nOut = [{\"d\", \"b\", \"a\"}, {3, 1, 0}]\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameCopy)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"source tensor\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T1)\n\t\topDef.AddOutput(\"Out\", \"target tensor\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T1)\n\t\topDef.AddAttribute(InputPartyCodesAttr, \"Input tensor `In` belongs to\")\n\t\topDef.AddAttribute(OutputPartyCodesAttr, \"Output tensor `Out` belongs to\")\n\t\topDef.SetDefinition(`Definition: Copy source tensor \"In\" to new tensor \"Out\" on target party`)\n\t\topDef.SetParamTypeConstraint(T1, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameFilter)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"Filter\", \"Filter tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T1)\n\t\topDef.AddInput(\"In\", \"Tensors to be filtered.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Output tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetDefinition(`Definition: Given a boolean tensor Filter (its shape is [M]), and a number of tensors In\n(variadic, each tensor's shape must be [M]), for i in [0, M-1], keep the In tensors' element if and only if Filter[i]\nis True, output the filter result tensors Out (variadic). Example:\n` + \"\\n```python\" + `\nFilter = {True, False, False, True, False}\nIn = {a, b, c, d, e}\nOut = {a, d}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T1, statusPrivateOrPublic)\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameConstant)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddOutput(\"Out\", \"output tensor(shape [M]) from constant.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddAttribute(ScalarAttr, \"scalar attribute(with shape [M])\")\n\t\topDef.SetDefinition(`Definition: Make constant from attribute.\nExample:\n` + \"\\n```python\" + `\nscalar = [{\"a\", \"b\", \"c\"}]\nOut = [{\"a\", \"b\", \"c\"}]\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameDumpFile)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Tensors to be dumped.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Tensors have been dumped.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetDefinition(`Definition: Dump the input tensor. Note: This op will change the affected rows in the session`)\n\t\topDef.AddAttribute(FilePathAttr, \"String. Absolute file path to dump the tensors.\")\n\t\topDef.AddAttribute(FieldDeliminatorAttr, \"String. Column deliminator, e.g. `\\\\t`\")\n\t\topDef.AddDefaultAttributeValue(FieldDeliminatorAttr, CreateStringAttribute(\"\\\\t\"))\n\t\topDef.AddAttribute(QuotingStyleAttr, \"Int64. Strategies for using quotes, 0: do not use quotes; 1: use quotes for strings; 2: use quotes for all valid data\")\n\t\topDef.AddDefaultAttributeValue(QuotingStyleAttr, CreateIntAttribute(0))\n\t\topDef.AddAttribute(LineTerminatorAttr, \"String. Line terminator, e.g. `\\\\n`\")\n\t\topDef.AddDefaultAttributeValue(LineTerminatorAttr, CreateStringAttribute(\"\\\\n\"))\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameInsertTable)\n\t\topDef.AddInput(\"In\", \"Tensors to be inserted to DB table.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Tensors have been inserted to DB table.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetDefinition(`Definition: Insert the input tensor to existing table in Database. Note: This op will change the affected rows in the session`)\n\t\topDef.AddAttribute(TableNameAttr, \"String. table to insert the tensors.\")\n\t\topDef.AddAttribute(ColumnNamesAttr, \"String array. column names of table.\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameIn)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"Left\", \"First operand.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddInput(\"Right\", \"Second operand.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T1)\n\t\topDef.AddOutput(\"Out\", \"Output Tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddAttribute(InTypeAttr, \"Int64. 0: PSI In, 1: Share In, 2: Local In\")\n\t\topDef.AddDefaultAttributeValue(InTypeAttr, CreateIntAttribute(PsiIn))\n\t\topDef.AddAttribute(PsiAlgorithmAttr, \"Int64. PSI Algorithm for In. 0: Auto, 1: Ecdh, 2: Oprf;\")\n\t\topDef.AddDefaultAttributeValue(PsiAlgorithmAttr, CreateIntAttribute(0))\n\t\topDef.AddAttribute(InputPartyCodesAttr, \"List of parties the inputs belong to. This attribute is required if algorithm = PSI.\")\n\t\topDef.AddAttribute(RevealToAttr, \"A party can see the result. This attribute is required if algorithm = PSI.\")\n\t\topDef.SetDefinition(`Definition: Given an input tensor Left (its shape is [M]), and another input tensor Right (its shape is [N]),\ncheck whether Left's element exists in Right's elements and output a boolean tensor Out (its shape is [M]). Left and Right must be the same type.\nExample:\n` + \"\\n```python\" + `\nLeft = {a, b, c, d}\nRight = {b, d, e, f, g, h}\nOut = {False, True, False, True}\n` + \"```\\n\")\n\t\t// for psi in, status must be private\n\t\t// support share/local in later\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\topDef.SetParamTypeConstraint(T1, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\t// Following definition of reduce_sum in\n\t\t// - TensorFlow: https://www.tensorflow.org/api_docs/python/tf/math/reduce_sum\n\t\t// - ONNX: https://github.com/onnx/onnx/blob/master/docs/Operators.md#ReduceSum\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameReduceSum)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Tensor to be summed (shape [M]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"The summed Tensor (shape [1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Given an input tensor In, return the sum of input tensor's elements.\nExample:\n` + \"\\n```python\" + `\nIn = {1, 2, 3, 4, 5, 6}\nOut = {21}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameReduceCount)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Tensor to be counted (shape [M]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"The counted Tensor (shape [1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Given an input tensor In, return the count of input tensor's elements.\nExample:\n` + \"\\n```python\" + `\nIn = {1, 2, 3, 4, 5, 6}\nOut = {6}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\t// Following definition of reduce_max in\n\t\t// - TensorFlow: https://www.tensorflow.org/api_docs/python/tf/math/reduce_max\n\t\t// - ONNX: https://github.com/onnx/onnx/blob/master/docs/Operators.md#reducemax\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameReduceMax)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Tensor to be maxed (shape [M]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"The maxed Tensor (shape [1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Given a input tensor In, return the max of input tensor's elements.\nExample:\n` + \"\\n```python\" + `\nIn = {1, 2, 3, 4, 5, 6}\nOut = {6}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\t// Following definition of reduce_min in\n\t\t// - TensorFlow: https://www.tensorflow.org/api_docs/python/tf/math/reduce_min\n\t\t// - ONNX: https://github.com/onnx/onnx/blob/master/docs/Operators.md#reducemin\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameReduceMin)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Tensor to be mined (shape [M]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"The mined Tensor (shape [1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Given a input tensor In, return the min of input tensor's elements.\nExample:\n` + \"\\n```python\" + `\nIn = {1, 2, 3, 4, 5, 6}\nOut = {1}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameReduceAvg)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Tensor to be reduced (shape [M]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"The average Tensor (shape [1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Given a input tensor In, return the average of input tensor's elements.\nExample:\n` + \"\\n```python\" + `\nIn = {1, 2, 3, 4, 5}\nOut = {3}\n\nIn = {1, 2, 3, 4}\nOut = {2.5}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameReducePercentileDisc)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Tensor to be reduced (shape [M]).\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"The value of given percentile position(shape [1]).\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Given a input tensor In, return the value of given percentile position.\nExample:\n` + \"\\n```python\" + `\nIn = {1, 2, 3, 4, 5}\npercent = 0.5 // the position is ceil(percent * length) - 1, which is 2 here\nOut = {3}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecret)\n\t\topDef.AddAttribute(\"percent\", \"Float. The percentile to calculate the range of which is [0, 1], 0 means the min one, 1 means the max one.\")\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameShape)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Input Tensors\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Shape Tensors\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T1)\n\t\topDef.AddAttribute(AxisAttr, \"Int64. Specific dimension of the shape.\")\n\t\topDef.AddDefaultAttributeValue(AxisAttr, CreateIntAttribute(-1))\n\t\topDef.SetDefinition(`Definition: Given tensors In, return shapes of each tensor. Axis starts from 0. If axis is set, dimensions of each shape are returned. If axis is not set(default -1), shapes are returned.\nExample:\n` + \"\\n```python\" + `\nIn = { {1, 2}, {2, 3}, {4, 3, 3} } # {1, 2} here is a column vector\nOut = { {2, 1}, {2, 1}, {3, 1} }\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T1, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameUnique)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"Key\", \"Input key tensors(shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"UniqueKey\", \"Output unique key tensor(shape [K][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Unique of Key tensor.\nExample:\n` + \"\\n```python\" + `\nKey = {\"a\", \"b\", \"a\", \"d\"}\nUniqueKey = {\"a\", \"b\", \"d\"}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameSort)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"Key\", \"Sort Key(shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddInput(\"In\", \"Sort Value(shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Sorted Value(shape [M][1])\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddAttribute(ReverseAttr, \"Bool. If True, the sorted tensor in descending order.\")\n\t\topDef.AddDefaultAttributeValue(ReverseAttr, CreateBoolAttribute(false))\n\t\topDef.SetDefinition(\"Definition: sort `In` using `Key`.\" + `\nExample:\n` + \"\\n```python\" + `\nKey = {3, 1, 2, 4}\nIn = [{3, 1, 2, 4}, {1, 2, 3, 4}, {9, 8, 7, 6}]\nOut = [{1, 2, 3, 4}, {2, 3, 1, 4}, {8, 7, 9, 6}]\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameObliviousGroupMark)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"Key\", \"Pre-sorted group keys (shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Group\",\n\t\t\t\"End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(\"Definition: generate end of group indicator `Group` based on `Key`. The operator calculates Group[i] = not_eq(Key[i+1], Key[i]).\" + `\nExample:\n` + \"\\n```python\" + `\nKey = [{0, 0, 0, 1}, {0, 1, 1, 1}]\nGroup = {1, 0, 1, 1}\n\nKey = [{0, 0, 1, 2, 2}]\nGroup = {0, 1, 1, 0, 1}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\ttype tmpl struct {\n\t\t\topName    string\n\t\t\taggResult string\n\t\t}\n\t\tfor _, t := range []tmpl{\n\t\t\t{opName: OpNameObliviousGroupSum, aggResult: `[{1, 3, 5, 9, 0}, {9, 8, 15, 21, 5}]`},\n\t\t\t{opName: OpNameObliviousGroupCount, aggResult: `[{1, 1, 2, 3, 1}, {1, 1, 2, 3, 1}]`},\n\t\t\t{opName: OpNameObliviousGroupMax, aggResult: `[{1, 3, 3, 4, 0}, {9, 8, 8, 8, 5}]`},\n\t\t\t{opName: OpNameObliviousGroupMin, aggResult: `[{1, 3, 2, 2, 0}, {9, 8, 7, 6, 5}]`},\n\t\t\t{opName: OpNameObliviousGroupAvg, aggResult: `[{1, 3, 2.5, 3, 0}, {9, 8, 7.5, 7, 5}]`},\n\t\t\t{opName: OpNameObliviousPercentRank, aggResult: `[{1, 0.3333, 0.6666, 1, 1, 1}, {1, 0.3333, 0.6666, 1, 1, 1}]`},\n\t\t\t{opName: OpNameObliviousRank, aggResult: `[{2, 2, 1, 3, 1}, {3, 2, 1, 2, 1}]`},\n\t\t} {\n\t\t\topDef := &OperatorDef{}\n\t\t\topDef.SetName(t.opName)\n\t\t\topDef.SetStreamingType(SinkOp)\n\t\t\topDef.AddInput(\"Group\",\n\t\t\t\t\"End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\",\n\t\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.AddInput(\"In\", \"Values to be aggregated (shape [M][1]).\",\n\t\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.AddOutput(\"Out\", \"Partially aggregated values (shape [M][1]).\",\n\t\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.SetDefinition(\"Definition: partially aggregate `In` according to end of group indicator.\" + fmt.Sprintf(`\nExample:\n`+\"\\n```python\"+`\nGroup = {1, 0, 0, 1, 1}\nIn = [{1, 3, 2, 4, 0}, {9, 8, 7, 6, 5}]\nOut = %s\n`, t.aggResult) + \"```\\n\")\n\t\t\topDef.SetParamTypeConstraint(T, statusSecret)\n\t\t\tcheck(opDef.err)\n\t\t\tAllOpDef = append(AllOpDef, opDef)\n\t\t}\n\n\t\t{\n\t\t\topDef := &OperatorDef{}\n\t\t\topDef.SetName(OpNameObliviousPercentileDisc)\n\t\t\topDef.SetStreamingType(SinkOp)\n\t\t\topDef.AddInput(\"Group\",\n\t\t\t\t\"End of group indicator(shape [M][1]). Element 1 means the row is the last element of the group, 0 is not.\",\n\t\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.AddInput(\"In\", \"Values to be aggregated (shape [M][1]).\",\n\t\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.AddOutput(\"Out\", \"Partially aggregated values (shape [M][1]).\",\n\t\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.SetParamTypeConstraint(T, statusSecret)\n\t\t\topDef.AddAttribute(\"percent\", \"Float. The percentile to calculate the range of which is [0, 1], 0 means the min one, 1 means the max one.\")\n\t\t\topDef.SetDefinition(\"Definition: find the value of given percentile of `In` for each group.\" + fmt.Sprintf(`\nExample:\n`+\"\\n```python\"+`\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\nthe percent is 0.5, the index of each group is = upper_bound(0.5 * group_size) - 1\nOut = [{0, 1, 4}, {7, 6, 5}]`+\"\\n```\\n\"))\n\t\t\tcheck(opDef.err)\n\t\t\tAllOpDef = append(AllOpDef, opDef)\n\t\t}\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameShuffle)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Input Value(shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Output Value(shape [M][1])\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetDefinition(\"Definition: Shuffle `In`.\" + `\nExample:\n` + \"\\n```python\" + `\nIn = [{1, 2, 3, 4}, {9, 8, 7, 6}]\nOut = [{4, 3, 2, 1}, {6, 7, 8, 9}]\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameBroadcastTo)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"Input tensor\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddInput(\"ShapeRefTensor\", \"Shape reference tensor\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T1)\n\t\topDef.AddOutput(\"Out\", \"Result tensor\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T2)\n\t\topDef.SetDefinition(\"Definition: Broadcast Input tensor `In` to the same shape as `ShapeRefTensor`.\\nExample:\\n```Python\" + `\nIn = [1]\nShapeRefTensor = [a, b, c]\n# ShapeRefTensor's shape is (3, 1), broadcast In to shape (3, 1)\nOut = BroadcastTo(In, ShapeRefTensor) = [1, 1, 1]\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPublic)\n\t\topDef.SetParamTypeConstraint(T1, statusPrivateOrSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T2, statusPrivateOrPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\tfor _, opName := range UnaryOps {\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(opName)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"Input tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"Output tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(fmt.Sprintf(\"Definition:  Out = %s In\", opName))\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameConcat)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Tensors to be concat.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Concated Tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddAttribute(\"axis\", \"Int64. Dimension along which to concatenate.\")\n\t\topDef.AddDefaultAttributeValue(\"axis\", CreateIntAttribute(0))\n\t\topDef.SetDefinition(`Definition: Given a number of tensors In (variadic, each tensor's shape must be the same in every dimension except for the axis), concat the In tensors along the axis.\nExample:\n` + \"\\n```python\" + `\nIn = { {1, 2}, {2, 3, 4}, {3, 4, 5, 6} }\nOut = {1, 2, 2, 3, 4, 3, 4, 5, 6}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameGroup)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"Key\", \"input key tensors(shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"GroupId\", \"group id vector(shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"GroupNum\", \"number of groups vector(shape [1][1])\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Assign a group id(start from 0) for each input element.\nExample:\n` + \"\\n```python\" + `\nKey = [{\"a\", \"c\", \"a\", \"d\"}, {0, 2, 0, 3}]\nGroupId = {0, 1, 0, 2}\nGroupNum = {3}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameIf)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"Condition\", \"Condition tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddInput(\"ValueIfTrue\", \"Value if true tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T1)\n\t\topDef.AddInput(\"ValueIfFalse\", \"Value if false tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T2)\n\t\topDef.AddOutput(\"Out\", \"Result tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T3)\n\t\topDef.SetDefinition(`The IF operator returns a value if a condition is TRUE, or another value if a condition is FALSE.\nExample:\n` + \"\\n```python\" + `\nCondition = [true, false, true, true]\nValueIfTrue = [0, 0, 0, 0]\nValueIfFalse = [1, 1, 1, 1]\nOut = [0, 1, 0, 0]\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T1, statusPrivateOrSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T2, statusPrivateOrSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T3, statusPrivateOrSecretOrPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameCaseWhen)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"Condition\", \"Condition tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddInput(\"Value\", \"Value if condition tensor is true and all previous conditions are false.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T1)\n\t\topDef.AddInput(\"ValueElse\", \"Value if all condition tensors are false.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T2)\n\t\topDef.AddOutput(\"Out\", \"Result tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T3)\n\t\topDef.SetDefinition(`The CaseWhen operator goes through conditions and returns a value when the first condition is met (like an if-then-else statement)\n\nExample:\n` + \"\\n```python\" + `\nCondition = [[true, false, false, false], [true, true, false, false]]\nValue = [[0, 0, 0, 0], [1, 1, 1, 1]]\nValueElse = [2, 2, 2, 2]\nOut = [0, 1, 2, 2]\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T1, statusPrivateOrSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T2, statusPrivateOrSecretOrPublic)\n\t\topDef.SetParamTypeConstraint(T3, statusPrivateOrSecretOrPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\ttype tmpl struct {\n\t\t\topName    string\n\t\t\taggResult string\n\t\t}\n\t\tfor _, t := range []tmpl{\n\t\t\t{opName: OpNameGroupFirstOf, aggResult: `[{0, 1, 4}, {9, 8, 5}]`},\n\t\t\t{opName: OpNameGroupCount, aggResult: `[{2, 2, 1}, {2, 2, 1}]`},\n\t\t\t{opName: OpNameGroupCountDistinct, aggResult: `[{2, 2, 1}, {2, 2, 1}]`},\n\t\t\t{opName: OpNameGroupSum, aggResult: `[{2, 4, 4}, {16, 14, 5}]`},\n\t\t\t{opName: OpNameGroupAvg, aggResult: `[{1, 2, 4}, {8, 7, 5}]`},\n\t\t\t{opName: OpNameGroupMin, aggResult: `[{0, 1, 4}, {7, 6, 5}]`},\n\t\t\t{opName: OpNameGroupMax, aggResult: `[{2, 3, 4}, {9, 8, 5}]`},\n\t\t} {\n\t\t\topDef := &OperatorDef{}\n\t\t\topDef.SetName(t.opName)\n\t\t\topDef.SetStreamingType(SinkOp)\n\t\t\topDef.AddInput(\"GroupId\", \"Input group id vector(shape [M][1]).\",\n\t\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.AddInput(\"GroupNum\", \"Input number of groups vector(shape [1][1]).\",\n\t\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.AddInput(\"In\", \"Input data tensor(shape [M][1]).\",\n\t\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.AddOutput(\"Out\", \"Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\",\n\t\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.SetDefinition(\"Definition: Aggregate `In` for each group.\" + fmt.Sprintf(`\nExample:\n`+\"\\n```python\"+`\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\nOut = %s\n`, t.aggResult) + \"```\\n\")\n\t\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\t\tcheck(opDef.err)\n\t\t\tAllOpDef = append(AllOpDef, opDef)\n\t\t}\n\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameGroupPercentileDisc)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"GroupId\", \"Input group id vector(shape [M][1]).\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddInput(\"GroupNum\", \"Input number of groups vector(shape [1][1]).\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddInput(\"In\", \"Input data tensor(shape [M][1]).\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\topDef.AddAttribute(\"percent\", \"Float. The percentile to calculate the range of which is [0, 1], 0 means the min one, 1 means the max one.\")\n\t\topDef.SetDefinition(\"Definition: find the value of given percentile of `In` for each group.\" + fmt.Sprintf(`\nExample:\n`+\"\\n```python\"+`\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = [{0, 1, 2, 3, 4}, {9, 8, 7, 6, 5}]\npercent = 0.5 //the percent is 0.5, the index of each group is = ceil(0.5 * group_size) - 1\nOut = [{0, 1, 4}, {7, 6, 5}]`+\"\\n```\\n\"))\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameGroupSecretSum)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"GroupId\", \"Input group id vector(shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddInput(\"GroupNum\", \"Input number of groups vector(shape [1][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T1)\n\t\topDef.AddInput(\"In\", \"Input data tensor(shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Calculate secret SUM for each group.\nExample:\n` + \"\\n```python\" + `\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = {0, 1, 2, 3, 4}\nOut = {2, 4, 4}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusSecret)\n\t\topDef.SetParamTypeConstraint(T1, statusPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameGroupSecretAvg)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"GroupId\", \"Input group id vector(shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddInput(\"GroupNum\", \"Input number of groups vector(shape [1][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T1)\n\t\topDef.AddInput(\"In\", \"Input data tensor(shape [M][1]).\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"Output data tensors(shape [K][1], K equals to number of groups), Out[i] is the agg result for i-th group.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Calculate secret AVG for each group.\nExample:\n` + \"\\n```python\" + `\nGroupId = {0, 1, 0, 1, 2}\nGroupNum = {3}\nIn = {0, 1, 2, 3, 4}\nOut = {1, 2, 4}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusSecret)\n\t\topDef.SetParamTypeConstraint(T1, statusPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameCast)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"Input tensor.\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"Output tensor.\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Cast Input tensor's data type to Output tensor's.`)\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameLimit)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"In\", \"Tensors to be limited.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"Output tensor.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetDefinition(`Limit return part of data, the amount of data depends on limit attr, the offset of data depends on offset attr.\nExample:\n` + \"\\n```python\" + `\noffset = 1\ncount = 2\nIn = {a, b, c, d, e}\nOut = {b, c}\n` + \"```\\n\")\n\t\topDef.AddAttribute(LimitOffsetAttr, \"offset in limit\")\n\t\topDef.AddAttribute(LimitCountAttr, \"count in limit\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameIsNull)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"Input tensor.\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"Output tensor.\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: Test if Input tensor's data contains NULL.\nExample:\n` + \"\\n```python\" + `\nIn = {0, 1, NULL}\nOut = {false, false, true}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameIfNull)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"Expr\", \"The expression to test whether is NULL\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddInput(\"AltValue\", \"The value to return if Expr is NULL\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.AddOutput(\"Out\", \"Result\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\topDef.SetDefinition(`Definition: If Expr is NULL, return AltValue. Otherwise, return Expr.\nExample:\n` + \"\\n```python\" + `\nExpr = {0, 1, NULL}\nAltValue = {10, 10, 10}\nOut = {0, 1, 10}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\n\t\t{\n\t\t\topDef := &OperatorDef{}\n\t\t\topDef.SetName(OpNameCoalesce)\n\t\t\topDef.SetStreamingType(StreamingOp)\n\t\t\topDef.AddInput(\"Exprs\", \"The expressions to coalesce\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.AddOutput(\"Out\", \"Result\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.SetDefinition(`Definition: Coalesce returns the first value of Exprs that is not NULL. NULL is returned only if Exprs are all NULL.\nExample:\n` + \"\\n```python\" + `\nExprs[0] = {0, NULL, NULL}\nExprs[1] = {0, 1, NULL}\nOut = {0, 1, NULL}\n` + \"```\\n\")\n\t\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\t\tcheck(opDef.err)\n\t\t\tAllOpDef = append(AllOpDef, opDef)\n\t\t}\n\n\t\t{\n\t\t\topDef := &OperatorDef{}\n\t\t\topDef.SetName(OpNameBucket)\n\t\t\topDef.SetStreamingType(SinkOp)\n\t\t\topDef.AddInput(\"Key\", \"Join Key Tensors\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.AddInput(\"In\", \"Input Tensors\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.AddOutput(\"Out\", \"Result\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.AddAttribute(InputPartyCodesAttr, \"List of parties the inputs belong to([PartyCodeLeft, PartyCodeRight]).\")\n\t\t\topDef.SetDefinition(`Definition: Put the data into buckets based on the hash value of the join key.`)\n\t\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\t\tcheck(opDef.err)\n\t\t\tAllOpDef = append(AllOpDef, opDef)\n\t\t}\n\n\t}\n\t{\n\t\ttrigonoOp := map[string]string{\n\t\t\tOpNameCos:  \"cosine\",\n\t\t\tOpNameSin:  \"sine\",\n\t\t\tOpNameTan:  \"tangent\",\n\t\t\tOpNameCot:  \"cotangent\",\n\t\t\tOpNameACos: \"arc cosine\",\n\t\t\tOpNameASin: \"arc sine\",\n\t\t\tOpNameATan: \"arc tangent\",\n\t\t}\n\n\t\tfor op, description := range trigonoOp {\n\t\t\topDef := &OperatorDef{}\n\t\t\topDef.SetName(op)\n\t\t\topDef.SetStreamingType(StreamingOp)\n\t\t\topDef.AddInput(\"In\", fmt.Sprintf(\"the expression pass to %s function\", description), proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.AddOutput(\"Out\", \"Result\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.SetDefinition(fmt.Sprintf(\"Definition: return the value of %s function\", description))\n\t\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\t\tcheck(opDef.err)\n\t\t\tAllOpDef = append(AllOpDef, opDef)\n\t\t}\n\t}\n\n\t{\n\t\twindowOp := map[string]string{\n\t\t\tOpNameRowNumber:   \"row number\",\n\t\t\tOpNamePercentRank: \"percent rank\",\n\t\t\tOpNameRank:        \"rank\",\n\t\t}\n\n\t\tfor op, decription := range windowOp {\n\t\t\topDef := &OperatorDef{}\n\t\t\topDef.SetName(op)\n\t\t\topDef.SetStreamingType(SinkOp)\n\t\t\topDef.AddInput(\"Key\", \"the tensors which used for sorting in partition, e.g. [2,0,4,2,3,7]\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\t\topDef.AddInput(\"PartitionId\", \"the partitioned id, e.g. [0,0,0,1,1,1], the first 3 in a group and the others are in another group\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.AddInput(\"PartitionNum\", \"the partitioned num, e.g. [2]\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.AddOutput(\"Out\", fmt.Sprintf(\"%s output\", decription), proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.SetDefinition(fmt.Sprintf(\"Definition: return the %s in each partition\", decription))\n\t\t\topDef.AddAttribute(ReverseAttr, `string array consists of \"0\" and \"1\", \"0\" means this input tensor sort by ascending, \"1\" means this tensor sort by descending.\n\t\te.g. [\"0\",\"1\"] means the first input key sort by ascending, the second sort by descending`)\n\t\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\t\tcheck(opDef.err)\n\t\t\tAllOpDef = append(AllOpDef, opDef)\n\t\t}\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameSecretJoin)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"LeftKey\", \"Left keys for join\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddInput(\"RightKey\", \"Right keys for join\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddInput(\"Left\", \"Left payloads for join\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_OPTIONAL, T)\n\t\topDef.AddInput(\"Right\", \"Right payloads for join\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_OPTIONAL, T)\n\t\topDef.AddOutput(\"LeftOutput\", \"Left payloads after join\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_OPTIONAL, T)\n\t\topDef.AddOutput(\"RightOutput\", \"Right payloads after join\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_OPTIONAL, T)\n\t\topDef.SetDefinition(`Definition: inner join the left and right payloads based on the left and right keys.\nExample:\n` + \"\\n```python\" + `\nLeftKey = {{1,2,1,3,5}} // shape:[5*1]\nRightKey = {{1,2,1,2}}  // shape:[4*1]\nLeft = {{0,1,2,3,4}}\nRight = {{0,1,2,3}}\nLeftOutput = {0,0,2,2,1,1}\nRightOutput = {0,2,0,2,1,3}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusSecret)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\tunaryNumericOps := map[string]bool{\n\t\t\tOpNameAbs:     true,\n\t\t\tOpNameCeil:    true,\n\t\t\tOpNameFloor:   true,\n\t\t\tOpNameRound:   true,\n\t\t\tOpNameRadians: true,\n\t\t\tOpNameDegrees: true,\n\t\t\tOpNameLn:      true,\n\t\t\tOpNameLog10:   true,\n\t\t\tOpNameLog2:    true,\n\t\t\tOpNameSqrt:    true,\n\t\t\tOpNameExp:     true,\n\t\t}\n\n\t\tfor op := range unaryNumericOps {\n\t\t\topDef := &OperatorDef{}\n\t\t\topDef.SetName(op)\n\t\t\topDef.SetStreamingType(SinkOp)\n\t\t\topDef.AddInput(\"In\", fmt.Sprintf(\"the expression pass to %s function\", op), proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.AddOutput(\"Out\", \"Result\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE, T)\n\t\t\topDef.SetDefinition(fmt.Sprintf(\"Definition: return the value of %s function\", op))\n\t\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\t\tcheck(opDef.err)\n\t\t\tAllOpDef = append(AllOpDef, opDef)\n\t\t}\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameGreatest)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"expressions passed for getting greatest value\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"greatest value\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetDefinition(`return the greatest value in the given expressions.`)\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameLeast)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"expressions passed for getting least value\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"Out\", \"least value\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetDefinition(`return the least value in the given expressions.`)\n\t\topDef.SetParamTypeConstraint(T, statusPrivateOrSecretOrPublic)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameArrowFunc)\n\t\topDef.SetStreamingType(StreamingOp)\n\t\topDef.AddInput(\"In\", \"Input tensors.\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddAttribute(FuncNameAttr, \"the name of arrow function, e.g: add/ifnull/...\")\n\t\topDef.AddOutput(\"Out\", \"Output tensors.\", proto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.SetDefinition(`Definition: Call arrow functions to finish calculation.\nExample:\n` + \"\\n```python\" + `\nIn = {{0, 1, NULL}}\nfunc_name = \"ifnull\"\nOut = {{false, false, true}}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n\n\t{\n\t\topDef := &OperatorDef{}\n\t\topDef.SetName(OpNameReplicate)\n\t\topDef.SetStreamingType(SinkOp)\n\t\topDef.AddInput(\"Left\", \"Left tensors to be replicated.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddInput(\"Right\", \"Right tensors to be replicated.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"LeftOut\", \"Left Output tensors.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddOutput(\"RightOut\", \"Right Output tensors.\",\n\t\t\tproto.FormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC, T)\n\t\topDef.AddAttribute(InputPartyCodesAttr, \"List of parties the inputs belong to([PartyCodeLeft, PartyCodeRight])\")\n\t\topDef.SetDefinition(`Replicate the Left with a given scale (rows of Right[0]) in interleaving way, when sending to the left party.\nAnd replicate the Right with a given scale (rows of Left[0]) in non-interleaving way, when sending to the right party.\nOutput the replication result Out. Example:\n` + \"\\n```python\" + `\nLeft = {a, b, c, d} # i.e. scale = 4\nRight = {0, 1, 2} # i.e. scale = 3\nsending to the interleaving party:\n  LeftOut = {a, b, c, d, a, b, c, d, a, b, c, d}\nthe other party:\n  RightOut = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2}\n` + \"```\\n\")\n\t\topDef.SetParamTypeConstraint(T, statusPrivate)\n\t\tcheck(opDef.err)\n\t\tAllOpDef = append(AllOpDef, opDef)\n\t}\n}\n\nfunc GetAllOpDef() ([]*proto.OperatorDef, int) {\n\trval := make([]*proto.OperatorDef, 0)\n\tfor _, op := range AllOpDef {\n\t\trval = append(rval, op.GetOperatorDefProto())\n\t}\n\treturn rval, version\n}\n\nfunc init() {\n\tregisterAllOpDef()\n}\n\nfunc FindOpDef(opType string) (*OperatorDef, error) {\n\tfor _, op := range AllOpDef {\n\t\tif opType == op.GetName() {\n\t\t\treturn op, nil\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"findOpDef: failed to find opType %v\", opType)\n}\n"
  },
  {
    "path": "pkg/interpreter/sc/scql_compiler.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage sc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\t\"github.com/secretflow/scql/pkg/interpreter/compiler\"\n\tpb \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n\t\"github.com/secretflow/scql/pkg/proto-gen/spu\"\n\t\"github.com/secretflow/scql/pkg/util/message\"\n)\n\ntype ColumnSlice []Column\n\ntype CompileResult struct {\n\tOperatorGraph string\n\tMarshaledPlan []byte\n}\n\ntype Catalog struct {\n\tTableEntries []*TableEntry\n}\n\nfunc (catalog *Catalog) AddTableEntry(table *TableEntry) {\n\tcatalog.TableEntries = append(catalog.TableEntries, table)\n}\n\ntype TableEntry struct {\n\tName        string\n\tDb          string\n\tDbType      string\n\tOwner       string\n\tRefTable    string\n\tRefTableUri string\n\tColumns     []*Column\n}\n\ntype Column struct {\n\tName string\n\tType string\n}\n\ntype CompileInputs struct {\n\tQuery   string\n\tIssuer  string\n\tDb      string // TODO: remove this field\n\tCatalog *Catalog\n}\n\nfunc (te *TableEntry) AddColumn(col *Column) {\n\tte.Columns = append(te.Columns, col)\n}\n\nfunc Compile(inputs *CompileInputs) (CompileResult, error) {\n\tcompileResult := CompileResult{}\n\n\treq, err := createCompileRequest(inputs)\n\tif err != nil {\n\t\treturn compileResult, err\n\t}\n\n\tgoResult, err := compiler.DetailedCompile(context.Background(), req)\n\tif err != nil {\n\t\treturn compileResult, err\n\t}\n\n\tcompileResult.OperatorGraph = goResult.OperatorGraph.String()\n\n\tcompileResult.MarshaledPlan, err = message.ProtoMarshal(goResult.ExecutionPlan)\n\tif err != nil {\n\t\treturn compileResult, err\n\t}\n\n\treturn compileResult, nil\n}\n\nfunc createCompileRequest(inputs *CompileInputs) (*v1.CompileSQLRequest, error) {\n\treturn &v1.CompileSQLRequest{\n\t\tQuery: inputs.Query,\n\t\tDb:    inputs.Db,\n\t\tIssuer: &pb.PartyId{\n\t\t\tCode: inputs.Issuer,\n\t\t},\n\t\tCatalog:        createCatalog(inputs.Catalog),\n\t\tCompileOpts:    crateCompileOptions(),\n\t\tIssueTime:      timestamppb.New(time.Now()),\n\t\tSecurityConfig: createSecurityConfig(),\n\t\tAdditionalInfo: &v1.AdditionalInfoSpec{\n\t\t\tNeedOperatorGraph: true,\n\t\t},\n\t}, nil\n}\n\nfunc createCatalog(catalog *Catalog) *pb.Catalog {\n\tcatalogPb := &pb.Catalog{}\n\n\tfor _, table := range catalog.TableEntries {\n\t\ttableEntry := &pb.TableEntry{\n\t\t\tTableName:   fmt.Sprintf(\"%s.%s\", table.Db, table.Name),\n\t\t\tRefTable:    table.RefTable,\n\t\t\tRefTableUri: table.RefTableUri,\n\t\t\tDbType:      table.DbType,\n\t\t\tOwner:       &pb.PartyId{Code: table.Owner},\n\t\t}\n\t\tfor _, column := range table.Columns {\n\t\t\tcol := &pb.TableEntry_Column{\n\t\t\t\tName: column.Name,\n\t\t\t\tType: column.Type,\n\t\t\t}\n\t\t\ttableEntry.Columns = append(tableEntry.Columns, col)\n\t\t}\n\t\tcatalogPb.Tables = append(catalogPb.Tables, tableEntry)\n\t}\n\n\treturn catalogPb\n}\n\nfunc crateCompileOptions() *v1.CompileOptions {\n\treturn &v1.CompileOptions{\n\t\tSpuConf: &spu.RuntimeConfig{\n\t\t\tProtocol:                                spu.ProtocolKind_SEMI2K,\n\t\t\tField:                                   spu.FieldType_FM128,\n\t\t\tExperimentalEnableColocatedOptimization: true,\n\t\t},\n\t\tBatched:          false,\n\t\tPsiAlgorithmType: pb.PsiAlgorithmType_AUTO,\n\t}\n}\n\nfunc createSecurityConfig() *v1.CompilerSecurityConfig {\n\tconfig := &v1.CompilerSecurityConfig{\n\t\tGlobalRelaxation: &v1.GlobalSecurityRelaxation{\n\t\t\tRevealGroupCount:   true,\n\t\t\tRevealGroupMark:    true,\n\t\t\tRevealKeyAfterJoin: true,\n\t\t\tRevealFilterMask:   true,\n\t\t},\n\t\tColumnRelaxationList: nil,\n\t\tReverseInferenceConf: &v1.ReverseInferenceConfig{\n\t\t\tEnableReverseInference: true,\n\t\t},\n\t}\n\n\treturn config\n}\n"
  },
  {
    "path": "pkg/parser/.gitignore",
    "content": "bin/\ny.go\n*.output\n.idea/\ncoverage.txt\n"
  },
  {
    "path": "pkg/parser/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "pkg/parser/Makefile",
    "content": ".PHONY: all parser clean\n\nall: fmt parser\n\ntest: fmt parser\n\tsh test.sh\n\nparser: parser.go hintparser.go\n\n%arser.go: prefix = $(@:parser.go=)\n%arser.go: %arser.y bin/goyacc\n\t@echo \"bin/goyacc -o $@ -p yy$(prefix) -t $(prefix)Parser $<\"\n\t@bin/goyacc -o $@ -p yy$(prefix) -t $(prefix)Parser $< || ( rm -f $@ && echo 'Please check y.output for more information' && exit 1 )\n\t@rm -f y.output\n\n%arser_golden.y: %arser.y\n\t@bin/goyacc -fmt -fmtout $@ $<\n\t@(git diff --no-index --exit-code $< $@ && rm $@) || (mv $@ $< && >&2 echo \"formatted $<\" && exit 1)\n\nbin/goyacc: goyacc/main.go goyacc/format_yacc.go\n\tGO111MODULE=on go build -o bin/goyacc goyacc/main.go goyacc/format_yacc.go\n\nfmt: bin/goyacc parser_golden.y hintparser_golden.y\n\t@echo \"gofmt (simplify)\"\n\t@gofmt -s -l -w . 2>&1 | awk '{print} END{if(NR>0) {exit 1}}'\n\nclean:\n\tgo clean -i ./...\n\trm -rf *.out\n\trm -f parser.go hintparser.go\n"
  },
  {
    "path": "pkg/parser/README.md",
    "content": "# Parser\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/pingcap/parser)](https://goreportcard.com/report/github.com/pingcap/parser) [![CircleCI Status](https://circleci.com/gh/pingcap/parser.svg?style=shield)](https://circleci.com/gh/pingcap/parser) [![GoDoc](https://godoc.org/github.com/pingcap/parser?status.svg)](https://godoc.org/github.com/pingcap/parser)\n[![codecov](https://codecov.io/gh/pingcap/parser/branch/master/graph/badge.svg)](https://codecov.io/gh/pingcap/parser)\n\nTiDB SQL Parser\n\n## How to use it\n\n```go\nimport (\n \"fmt\"\n \"github.com/pingcap/parser\"\n _ \"github.com/pingcap/tidb/types/parser_driver\"\n)\n\n// This example show how to parse a text sql into ast.\nfunc example() {\n\n // 0. make sure import parser_driver implemented by TiDB(user also can implement own driver by self).\n // and add `import _ \"github.com/pingcap/tidb/types/parser_driver\"` in the head of file.\n\n // 1. Create a parser. The parser is NOT goroutine safe and should\n // not be shared among multiple goroutines. However, parser is also\n // heavy, so each goroutine should reuse its own local instance if\n // possible.\n p := parser.New()\n\n // 2. Parse a text SQL into AST([]ast.StmtNode).\n stmtNodes, _, err := p.Parse(\"select * from tbl where id = 1\", \"\", \"\")\n\n // 3. Use AST to do cool things.\n fmt.Println(stmtNodes[0], err)\n}\n```\n\nSee [https://godoc.org/github.com/pingcap/parser](https://godoc.org/github.com/pingcap/parser)\n\n## How to update parser for TiDB\n\nAssuming that you want to file a PR (pull request) to TiDB, and your PR includes a change in the parser, follow these steps to update the parser in TiDB.\n\n### Step 1: Make changes in your parser repository\n\nFork this repository to your own account and commit the changes to your repository.\n\n> **Note:**\n>\n> - Don't forget to run `make test` before you commit!\n> - Make sure `parser.go` is updated.\n\nSuppose the forked repository is `https://github.com/your-repo/parser`.\n\n### Step 2: Make your parser changes take effect in TiDB and run CI\n\n1. In your TiDB repository, execute the `replace` instruction to make your parser changes take effect:\n\n    ```bash\n    GO111MODULE=on go mod edit -replace github.com/pingcap/parser=github.com/your-repo/parser@your-branch\n    ```\n\n2. `make dev` to run CI in TiDB.\n\n3. File a PR to TiDB.\n\n### Step 3: Merge the PR about the parser to this repository\n\nFile a PR to this repository. **Link the related PR in TiDB in your PR description or comment.**\n\nThis PR will be reviewed, and if everything goes well, it will be merged.\n\n### Step 4: Update TiDB to use the latest parser\n\nIn your TiDB pull request, modify the `go.mod` file manually or use this command:\n\n```bash\nGO111MODULE=on go get -u github.com/pingcap/parser@master\n```\n\nMake sure the `replace` instruction is changed back to the `require` instruction and the version is the latest.\n"
  },
  {
    "path": "pkg/parser/ast/advisor.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport (\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n)\n\nvar _ StmtNode = &IndexAdviseStmt{}\n\n// IndexAdviseStmt is used to advise indexes\ntype IndexAdviseStmt struct {\n\tstmtNode\n\n\tIsLocal     bool\n\tPath        string\n\tMaxMinutes  uint64\n\tMaxIndexNum *MaxIndexNumClause\n\tLinesInfo   *LinesClause\n}\n\n// Restore implements Node Accept interface.\nfunc (n *IndexAdviseStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"INDEX ADVISE \")\n\tif n.IsLocal {\n\t\tctx.WriteKeyWord(\"LOCAL \")\n\t}\n\tctx.WriteKeyWord(\"INFILE \")\n\tctx.WriteString(n.Path)\n\tif n.MaxMinutes != UnspecifiedSize {\n\t\tctx.WriteKeyWord(\" MAX_MINUTES \")\n\t\tctx.WritePlainf(\"%d\", n.MaxMinutes)\n\t}\n\tif n.MaxIndexNum != nil {\n\t\tn.MaxIndexNum.Restore(ctx)\n\t}\n\tn.LinesInfo.Restore(ctx)\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *IndexAdviseStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*IndexAdviseStmt)\n\treturn v.Leave(n)\n}\n\n// MaxIndexNumClause represents 'maximum number of indexes' clause in index advise statement.\ntype MaxIndexNumClause struct {\n\tPerTable uint64\n\tPerDB    uint64\n}\n\n// Restore for max index num clause\nfunc (n *MaxIndexNumClause) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\" MAX_IDXNUM\")\n\tif n.PerTable != UnspecifiedSize {\n\t\tctx.WriteKeyWord(\" PER_TABLE \")\n\t\tctx.WritePlainf(\"%d\", n.PerTable)\n\t}\n\tif n.PerDB != UnspecifiedSize {\n\t\tctx.WriteKeyWord(\" PER_DB \")\n\t\tctx.WritePlainf(\"%d\", n.PerDB)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/parser/ast/ast.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package ast is the abstract syntax tree parsed from a SQL statement by parser.\n// It can be analysed and transformed by optimizer.\npackage ast\n\nimport (\n\t\"io\"\n\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/types\"\n)\n\n// Node is the basic element of the AST.\n// Interfaces embed Node should have 'Node' name suffix.\ntype Node interface {\n\t// Restore returns the sql text from ast tree\n\tRestore(ctx *RestoreCtx) error\n\t// Accept accepts Visitor to visit itself.\n\t// The returned node should replace original node.\n\t// ok returns false to stop visiting.\n\t//\n\t// Implementation of this method should first call visitor.Enter,\n\t// assign the returned node to its method receiver, if skipChildren returns true,\n\t// children should be skipped. Otherwise, call its children in particular order that\n\t// later elements depends on former elements. Finally, return visitor.Leave.\n\tAccept(v Visitor) (node Node, ok bool)\n\t// Text returns the original text of the element.\n\tText() string\n\t// SetText sets original text to the Node.\n\tSetText(text string)\n}\n\n// Flags indicates whether an expression contains certain types of expression.\nconst (\n\tFlagConstant       uint64 = 0\n\tFlagHasParamMarker uint64 = 1 << iota\n\tFlagHasFunc\n\tFlagHasReference\n\tFlagHasAggregateFunc\n\tFlagHasSubquery\n\tFlagHasVariable\n\tFlagHasDefault\n\tFlagPreEvaluated\n\tFlagHasWindowFunc\n)\n\n// ExprNode is a node that can be evaluated.\n// Name of implementations should have 'Expr' suffix.\ntype ExprNode interface {\n\t// Node is embedded in ExprNode.\n\tNode\n\t// SetType sets evaluation type to the expression.\n\tSetType(tp *types.FieldType)\n\t// GetType gets the evaluation type of the expression.\n\tGetType() *types.FieldType\n\t// SetFlag sets flag to the expression.\n\t// Flag indicates whether the expression contains\n\t// parameter marker, reference, aggregate function...\n\tSetFlag(flag uint64)\n\t// GetFlag returns the flag of the expression.\n\tGetFlag() uint64\n\n\t// Format formats the AST into a writer.\n\tFormat(w io.Writer)\n}\n\n// OptBinary is used for parser.\ntype OptBinary struct {\n\tIsBinary bool\n\tCharset  string\n}\n\n// FuncNode represents function call expression node.\ntype FuncNode interface {\n\tExprNode\n\tfunctionExpression()\n}\n\n// StmtNode represents statement node.\n// Name of implementations should have 'Stmt' suffix.\ntype StmtNode interface {\n\tNode\n\tstatement()\n}\n\n// DDLNode represents DDL statement node.\ntype DDLNode interface {\n\tStmtNode\n\tddlStatement()\n}\n\n// DMLNode represents DML statement node.\ntype DMLNode interface {\n\tStmtNode\n\tdmlStatement()\n}\n\n// ResultField represents a result field which can be a column from a table,\n// or an expression in select field. It is a generated property during\n// binding process. ResultField is the key element to evaluate a ColumnNameExpr.\n// After resolving process, every ColumnNameExpr will be resolved to a ResultField.\n// During execution, every row retrieved from table will set the row value to\n// ResultFields of that table, so ColumnNameExpr resolved to that ResultField can be\n// easily evaluated.\ntype ResultField struct {\n\tColumn       *model.ColumnInfo\n\tColumnAsName model.CIStr\n\tTable        *model.TableInfo\n\tTableAsName  model.CIStr\n\tDBName       model.CIStr\n\n\t// Expr represents the expression for the result field. If it is generated from a select field, it would\n\t// be the expression of that select field, otherwise the type would be ValueExpr and value\n\t// will be set for every retrieved row.\n\tExpr      ExprNode\n\tTableName *TableName\n\t// Referenced indicates the result field has been referenced or not.\n\t// If not, we don't need to get the values.\n\tReferenced bool\n}\n\n// ResultSetNode interface has a ResultFields property, represents a Node that returns result set.\n// Implementations include SelectStmt, SubqueryExpr, TableSource, TableName and Join.\ntype ResultSetNode interface {\n\tNode\n}\n\n// SensitiveStmtNode overloads StmtNode and provides a SecureText method.\ntype SensitiveStmtNode interface {\n\tStmtNode\n\t// SecureText is different from Text that it hide password information.\n\tSecureText() string\n}\n\n// Visitor visits a Node.\ntype Visitor interface {\n\t// Enter is called before children nodes are visited.\n\t// The returned node must be the same type as the input node n.\n\t// skipChildren returns true means children nodes should be skipped,\n\t// this is useful when work is done in Enter and there is no need to visit children.\n\tEnter(n Node) (node Node, skipChildren bool)\n\t// Leave is called after children nodes have been visited.\n\t// The returned node's type can be different from the input node if it is a ExprNode,\n\t// Non-expression node must be the same type as the input node n.\n\t// ok returns false to stop visiting.\n\tLeave(n Node) (node Node, ok bool)\n}\n"
  },
  {
    "path": "pkg/parser/ast/base.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport \"github.com/secretflow/scql/pkg/parser/types\"\n\n// node is the struct implements node interface except for Accept method.\n// Node implementations should embed it in.\ntype node struct {\n\ttext string\n}\n\n// SetText implements Node interface.\nfunc (n *node) SetText(text string) {\n\tn.text = text\n}\n\n// Text implements Node interface.\nfunc (n *node) Text() string {\n\treturn n.text\n}\n\n// stmtNode implements StmtNode interface.\n// Statement implementations should embed it in.\ntype stmtNode struct {\n\tnode\n}\n\n// statement implements StmtNode interface.\nfunc (sn *stmtNode) statement() {}\n\n// ddlNode implements DDLNode interface.\n// DDL implementations should embed it in.\ntype ddlNode struct {\n\tstmtNode\n}\n\n// ddlStatement implements DDLNode interface.\nfunc (dn *ddlNode) ddlStatement() {}\n\n// dmlNode is the struct implements DMLNode interface.\n// DML implementations should embed it in.\ntype dmlNode struct {\n\tstmtNode\n}\n\n// dmlStatement implements DMLNode interface.\nfunc (dn *dmlNode) dmlStatement() {}\n\n// exprNode is the struct implements Expression interface.\n// Expression implementations should embed it in.\ntype exprNode struct {\n\tnode\n\tType types.FieldType\n\tflag uint64\n}\n\n// TexprNode is exported for parser driver.\ntype TexprNode = exprNode\n\n// SetType implements ExprNode interface.\nfunc (en *exprNode) SetType(tp *types.FieldType) {\n\ten.Type = *tp\n}\n\n// GetType implements ExprNode interface.\nfunc (en *exprNode) GetType() *types.FieldType {\n\treturn &en.Type\n}\n\n// SetFlag implements ExprNode interface.\nfunc (en *exprNode) SetFlag(flag uint64) {\n\ten.flag = flag\n}\n\n// GetFlag implements ExprNode interface.\nfunc (en *exprNode) GetFlag() uint64 {\n\treturn en.flag\n}\n\ntype funcNode struct {\n\texprNode\n}\n\n// functionExpression implements FunctionNode interface.\nfunc (fn *funcNode) functionExpression() {}\n\ntype resultSetNode struct {\n\tresultFields []*ResultField\n}\n"
  },
  {
    "path": "pkg/parser/ast/ddl.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/auth\"\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\t\"github.com/secretflow/scql/pkg/parser/types\"\n)\n\nvar (\n\t_ DDLNode = &AlterTableStmt{}\n\t_ DDLNode = &CreateDatabaseStmt{}\n\t_ DDLNode = &CreateIndexStmt{}\n\t_ DDLNode = &CreateTableStmt{}\n\t_ DDLNode = &CreateViewStmt{}\n\t_ DDLNode = &CreateSequenceStmt{}\n\t_ DDLNode = &DropDatabaseStmt{}\n\t_ DDLNode = &DropIndexStmt{}\n\t_ DDLNode = &DropTableStmt{}\n\t_ DDLNode = &DropSequenceStmt{}\n\t_ DDLNode = &RenameTableStmt{}\n\t_ DDLNode = &TruncateTableStmt{}\n\t_ DDLNode = &RepairTableStmt{}\n\n\t_ Node = &AlterTableSpec{}\n\t_ Node = &ColumnDef{}\n\t_ Node = &ColumnOption{}\n\t_ Node = &ColumnPosition{}\n\t_ Node = &Constraint{}\n\t_ Node = &IndexPartSpecification{}\n\t_ Node = &ReferenceDef{}\n)\n\n// CharsetOpt is used for parsing charset option from SQL.\ntype CharsetOpt struct {\n\tChs string\n\tCol string\n}\n\n// DatabaseOptionType is the type for database options.\ntype DatabaseOptionType int\n\n// Database option types.\nconst (\n\tDatabaseOptionNone DatabaseOptionType = iota\n\tDatabaseOptionCharset\n\tDatabaseOptionCollate\n\tDatabaseOptionEncryption\n)\n\n// DatabaseOption represents database option.\ntype DatabaseOption struct {\n\tTp    DatabaseOptionType\n\tValue string\n}\n\n// Restore implements Node interface.\nfunc (n *DatabaseOption) Restore(ctx *RestoreCtx) error {\n\tswitch n.Tp {\n\tcase DatabaseOptionCharset:\n\t\tctx.WriteKeyWord(\"CHARACTER SET\")\n\t\tctx.WritePlain(\" = \")\n\t\tctx.WritePlain(n.Value)\n\tcase DatabaseOptionCollate:\n\t\tctx.WriteKeyWord(\"COLLATE\")\n\t\tctx.WritePlain(\" = \")\n\t\tctx.WritePlain(n.Value)\n\tcase DatabaseOptionEncryption:\n\t\tctx.WriteKeyWord(\"ENCRYPTION\")\n\t\tctx.WritePlain(\" = \")\n\t\tctx.WriteString(n.Value)\n\tdefault:\n\t\treturn errors.Errorf(\"invalid DatabaseOptionType: %d\", n.Tp)\n\t}\n\treturn nil\n}\n\n// CreateDatabaseStmt is a statement to create a database.\n// See https://dev.mysql.com/doc/refman/5.7/en/create-database.html\ntype CreateDatabaseStmt struct {\n\tddlNode\n\n\tIfNotExists bool\n\tName        string\n\tOptions     []*DatabaseOption\n}\n\n// Restore implements Node interface.\nfunc (n *CreateDatabaseStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"CREATE DATABASE \")\n\tif n.IfNotExists {\n\t\tctx.WriteKeyWord(\"IF NOT EXISTS \")\n\t}\n\tctx.WriteName(n.Name)\n\tfor i, option := range n.Options {\n\t\tctx.WritePlain(\" \")\n\t\terr := option.Restore(ctx)\n\t\tif err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing CreateDatabaseStmt DatabaseOption: [%v]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *CreateDatabaseStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*CreateDatabaseStmt)\n\treturn v.Leave(n)\n}\n\n// AlterDatabaseStmt is a statement to change the structure of a database.\n// See https://dev.mysql.com/doc/refman/5.7/en/alter-database.html\ntype AlterDatabaseStmt struct {\n\tddlNode\n\n\tName                 string\n\tAlterDefaultDatabase bool\n\tOptions              []*DatabaseOption\n}\n\n// Restore implements Node interface.\nfunc (n *AlterDatabaseStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"ALTER DATABASE\")\n\tif !n.AlterDefaultDatabase {\n\t\tctx.WritePlain(\" \")\n\t\tctx.WriteName(n.Name)\n\t}\n\tfor i, option := range n.Options {\n\t\tctx.WritePlain(\" \")\n\t\terr := option.Restore(ctx)\n\t\tif err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing AlterDatabaseStmt DatabaseOption: [%v]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *AlterDatabaseStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*AlterDatabaseStmt)\n\treturn v.Leave(n)\n}\n\n// DropDatabaseStmt is a statement to drop a database and all tables in the database.\n// See https://dev.mysql.com/doc/refman/5.7/en/drop-database.html\ntype DropDatabaseStmt struct {\n\tddlNode\n\n\tIfExists bool\n\tName     string\n}\n\n// Restore implements Node interface.\nfunc (n *DropDatabaseStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"DROP DATABASE \")\n\tif n.IfExists {\n\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t}\n\tctx.WriteName(n.Name)\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DropDatabaseStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DropDatabaseStmt)\n\treturn v.Leave(n)\n}\n\n// IndexPartSpecifications is used for parsing index column name or index expression from SQL.\ntype IndexPartSpecification struct {\n\tnode\n\n\tColumn *ColumnName\n\tLength int\n\tExpr   ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *IndexPartSpecification) Restore(ctx *RestoreCtx) error {\n\tif n.Expr != nil {\n\t\tctx.WritePlain(\"(\")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing IndexPartSpecifications\")\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t\treturn nil\n\t}\n\tif err := n.Column.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while splicing IndexPartSpecifications\")\n\t}\n\tif n.Length > 0 {\n\t\tctx.WritePlainf(\"(%d)\", n.Length)\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *IndexPartSpecification) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*IndexPartSpecification)\n\tif n.Expr != nil {\n\t\tnode, ok := n.Expr.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Expr = node.(ExprNode)\n\t\treturn v.Leave(n)\n\t}\n\tnode, ok := n.Column.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Column = node.(*ColumnName)\n\treturn v.Leave(n)\n}\n\n// MatchType is the type for reference match type.\ntype MatchType int\n\n// match type\nconst (\n\tMatchNone MatchType = iota\n\tMatchFull\n\tMatchPartial\n\tMatchSimple\n)\n\n// ReferenceDef is used for parsing foreign key reference option from SQL.\n// See http://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html\ntype ReferenceDef struct {\n\tnode\n\n\tTable                   *TableName\n\tIndexPartSpecifications []*IndexPartSpecification\n\tOnDelete                *OnDeleteOpt\n\tOnUpdate                *OnUpdateOpt\n\tMatch                   MatchType\n}\n\n// Restore implements Node interface.\nfunc (n *ReferenceDef) Restore(ctx *RestoreCtx) error {\n\tif n.Table != nil {\n\t\tctx.WriteKeyWord(\"REFERENCES \")\n\t\tif err := n.Table.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing ReferenceDef\")\n\t\t}\n\t}\n\n\tif n.IndexPartSpecifications != nil {\n\t\tctx.WritePlain(\"(\")\n\t\tfor i, indexColNames := range n.IndexPartSpecifications {\n\t\t\tif i > 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tif err := indexColNames.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing IndexPartSpecifications: [%v]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\n\tif n.Match != MatchNone {\n\t\tctx.WriteKeyWord(\" MATCH \")\n\t\tswitch n.Match {\n\t\tcase MatchFull:\n\t\t\tctx.WriteKeyWord(\"FULL\")\n\t\tcase MatchPartial:\n\t\t\tctx.WriteKeyWord(\"PARTIAL\")\n\t\tcase MatchSimple:\n\t\t\tctx.WriteKeyWord(\"SIMPLE\")\n\t\t}\n\t}\n\tif n.OnDelete.ReferOpt != ReferOptionNoOption {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.OnDelete.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing OnDelete\")\n\t\t}\n\t}\n\tif n.OnUpdate.ReferOpt != ReferOptionNoOption {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.OnUpdate.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing OnUpdate\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ReferenceDef) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ReferenceDef)\n\tnode, ok := n.Table.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Table = node.(*TableName)\n\tfor i, val := range n.IndexPartSpecifications {\n\t\tnode, ok = val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.IndexPartSpecifications[i] = node.(*IndexPartSpecification)\n\t}\n\tonDelete, ok := n.OnDelete.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.OnDelete = onDelete.(*OnDeleteOpt)\n\tonUpdate, ok := n.OnUpdate.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.OnUpdate = onUpdate.(*OnUpdateOpt)\n\treturn v.Leave(n)\n}\n\n// ReferOptionType is the type for refer options.\ntype ReferOptionType int\n\n// Refer option types.\nconst (\n\tReferOptionNoOption ReferOptionType = iota\n\tReferOptionRestrict\n\tReferOptionCascade\n\tReferOptionSetNull\n\tReferOptionNoAction\n\tReferOptionSetDefault\n)\n\n// String implements fmt.Stringer interface.\nfunc (r ReferOptionType) String() string {\n\tswitch r {\n\tcase ReferOptionRestrict:\n\t\treturn \"RESTRICT\"\n\tcase ReferOptionCascade:\n\t\treturn \"CASCADE\"\n\tcase ReferOptionSetNull:\n\t\treturn \"SET NULL\"\n\tcase ReferOptionNoAction:\n\t\treturn \"NO ACTION\"\n\tcase ReferOptionSetDefault:\n\t\treturn \"SET DEFAULT\"\n\t}\n\treturn \"\"\n}\n\n// OnDeleteOpt is used for optional on delete clause.\ntype OnDeleteOpt struct {\n\tnode\n\tReferOpt ReferOptionType\n}\n\n// Restore implements Node interface.\nfunc (n *OnDeleteOpt) Restore(ctx *RestoreCtx) error {\n\tif n.ReferOpt != ReferOptionNoOption {\n\t\tctx.WriteKeyWord(\"ON DELETE \")\n\t\tctx.WriteKeyWord(n.ReferOpt.String())\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *OnDeleteOpt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*OnDeleteOpt)\n\treturn v.Leave(n)\n}\n\n// OnUpdateOpt is used for optional on update clause.\ntype OnUpdateOpt struct {\n\tnode\n\tReferOpt ReferOptionType\n}\n\n// Restore implements Node interface.\nfunc (n *OnUpdateOpt) Restore(ctx *RestoreCtx) error {\n\tif n.ReferOpt != ReferOptionNoOption {\n\t\tctx.WriteKeyWord(\"ON UPDATE \")\n\t\tctx.WriteKeyWord(n.ReferOpt.String())\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *OnUpdateOpt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*OnUpdateOpt)\n\treturn v.Leave(n)\n}\n\n// ColumnOptionType is the type for ColumnOption.\ntype ColumnOptionType int\n\n// ColumnOption types.\nconst (\n\tColumnOptionNoOption ColumnOptionType = iota\n\tColumnOptionPrimaryKey\n\tColumnOptionNotNull\n\tColumnOptionAutoIncrement\n\tColumnOptionDefaultValue\n\tColumnOptionUniqKey\n\tColumnOptionNull\n\tColumnOptionOnUpdate // For Timestamp and Datetime only.\n\tColumnOptionFulltext\n\tColumnOptionComment\n\tColumnOptionGenerated\n\tColumnOptionReference\n\tColumnOptionCollate\n\tColumnOptionCheck\n\tColumnOptionColumnFormat\n\tColumnOptionStorage\n\tColumnOptionAutoRandom\n)\n\nvar (\n\tinvalidOptionForGeneratedColumn = map[ColumnOptionType]struct{}{\n\t\tColumnOptionAutoIncrement: {},\n\t\tColumnOptionOnUpdate:      {},\n\t\tColumnOptionDefaultValue:  {},\n\t}\n)\n\n// ColumnOption is used for parsing column constraint info from SQL.\ntype ColumnOption struct {\n\tnode\n\n\tTp ColumnOptionType\n\t// Expr is used for ColumnOptionDefaultValue/ColumnOptionOnUpdateColumnOptionGenerated.\n\t// For ColumnOptionDefaultValue or ColumnOptionOnUpdate, it's the target value.\n\t// For ColumnOptionGenerated, it's the target expression.\n\tExpr ExprNode\n\t// Stored is only for ColumnOptionGenerated, default is false.\n\tStored bool\n\t// Refer is used for foreign key.\n\tRefer               *ReferenceDef\n\tStrValue            string\n\tAutoRandomBitLength int\n\t// Enforced is only for Check, default is true.\n\tEnforced bool\n}\n\n// Restore implements Node interface.\nfunc (n *ColumnOption) Restore(ctx *RestoreCtx) error {\n\tswitch n.Tp {\n\tcase ColumnOptionNoOption:\n\t\treturn nil\n\tcase ColumnOptionPrimaryKey:\n\t\tctx.WriteKeyWord(\"PRIMARY KEY\")\n\tcase ColumnOptionNotNull:\n\t\tctx.WriteKeyWord(\"NOT NULL\")\n\tcase ColumnOptionAutoIncrement:\n\t\tctx.WriteKeyWord(\"AUTO_INCREMENT\")\n\tcase ColumnOptionDefaultValue:\n\t\tctx.WriteKeyWord(\"DEFAULT \")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing ColumnOption DefaultValue Expr\")\n\t\t}\n\tcase ColumnOptionUniqKey:\n\t\tctx.WriteKeyWord(\"UNIQUE KEY\")\n\tcase ColumnOptionNull:\n\t\tctx.WriteKeyWord(\"NULL\")\n\tcase ColumnOptionOnUpdate:\n\t\tctx.WriteKeyWord(\"ON UPDATE \")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing ColumnOption ON UPDATE Expr\")\n\t\t}\n\tcase ColumnOptionFulltext:\n\t\treturn errors.New(\"TiDB Parser ignore the `ColumnOptionFulltext` type now\")\n\tcase ColumnOptionComment:\n\t\tctx.WriteKeyWord(\"COMMENT \")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing ColumnOption COMMENT Expr\")\n\t\t}\n\tcase ColumnOptionGenerated:\n\t\tctx.WriteKeyWord(\"GENERATED ALWAYS AS\")\n\t\tctx.WritePlain(\"(\")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing ColumnOption GENERATED ALWAYS Expr\")\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t\tif n.Stored {\n\t\t\tctx.WriteKeyWord(\" STORED\")\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\" VIRTUAL\")\n\t\t}\n\tcase ColumnOptionReference:\n\t\tif err := n.Refer.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing ColumnOption ReferenceDef\")\n\t\t}\n\tcase ColumnOptionCollate:\n\t\tif n.StrValue == \"\" {\n\t\t\treturn errors.New(\"Empty ColumnOption COLLATE\")\n\t\t}\n\t\tctx.WriteKeyWord(\"COLLATE \")\n\t\tctx.WritePlain(n.StrValue)\n\tcase ColumnOptionCheck:\n\t\tctx.WriteKeyWord(\"CHECK\")\n\t\tctx.WritePlain(\"(\")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Trace(err)\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t\tif n.Enforced {\n\t\t\tctx.WriteKeyWord(\" ENFORCED\")\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\" NOT ENFORCED\")\n\t\t}\n\tcase ColumnOptionColumnFormat:\n\t\tctx.WriteKeyWord(\"COLUMN_FORMAT \")\n\t\tctx.WriteKeyWord(n.StrValue)\n\tcase ColumnOptionStorage:\n\t\tctx.WriteKeyWord(\"STORAGE \")\n\t\tctx.WriteKeyWord(n.StrValue)\n\tcase ColumnOptionAutoRandom:\n\t\tctx.WriteKeyWord(\"AUTO_RANDOM\")\n\t\tif n.AutoRandomBitLength != types.UnspecifiedLength {\n\t\t\tctx.WritePlainf(\"(%d)\", n.AutoRandomBitLength)\n\t\t}\n\tdefault:\n\t\treturn errors.New(\"An error occurred while splicing ColumnOption\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ColumnOption) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ColumnOption)\n\tif n.Expr != nil {\n\t\tnode, ok := n.Expr.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Expr = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// IndexVisibility is the option for index visibility.\ntype IndexVisibility int\n\n// IndexVisibility options.\nconst (\n\tIndexVisibilityDefault IndexVisibility = iota\n\tIndexVisibilityVisible\n\tIndexVisibilityInvisible\n)\n\n// IndexOption is the index options.\n//\n//\t  KEY_BLOCK_SIZE [=] value\n//\t| index_type\n//\t| WITH PARSER parser_name\n//\t| COMMENT 'string'\n//\n// See http://dev.mysql.com/doc/refman/5.7/en/create-table.html\ntype IndexOption struct {\n\tnode\n\n\tKeyBlockSize uint64\n\tTp           model.IndexType\n\tComment      string\n\tParserName   model.CIStr\n\tVisibility   IndexVisibility\n}\n\n// Restore implements Node interface.\nfunc (n *IndexOption) Restore(ctx *RestoreCtx) error {\n\thasPrevOption := false\n\tif n.KeyBlockSize > 0 {\n\t\tctx.WriteKeyWord(\"KEY_BLOCK_SIZE\")\n\t\tctx.WritePlainf(\"=%d\", n.KeyBlockSize)\n\t\thasPrevOption = true\n\t}\n\n\tif n.Tp != model.IndexTypeInvalid {\n\t\tif hasPrevOption {\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tctx.WriteKeyWord(\"USING \")\n\t\tctx.WritePlain(n.Tp.String())\n\t\thasPrevOption = true\n\t}\n\n\tif len(n.ParserName.O) > 0 {\n\t\tif hasPrevOption {\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tctx.WriteKeyWord(\"WITH PARSER \")\n\t\tctx.WriteName(n.ParserName.O)\n\t\thasPrevOption = true\n\t}\n\n\tif n.Comment != \"\" {\n\t\tif hasPrevOption {\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tctx.WriteKeyWord(\"COMMENT \")\n\t\tctx.WriteString(n.Comment)\n\t\thasPrevOption = true\n\t}\n\n\tif n.Visibility != IndexVisibilityDefault {\n\t\tif hasPrevOption {\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tswitch n.Visibility {\n\t\tcase IndexVisibilityVisible:\n\t\t\tctx.WriteKeyWord(\"VISIBLE\")\n\t\tcase IndexVisibilityInvisible:\n\t\t\tctx.WriteKeyWord(\"INVISIBLE\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *IndexOption) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*IndexOption)\n\treturn v.Leave(n)\n}\n\n// ConstraintType is the type for Constraint.\ntype ConstraintType int\n\n// ConstraintTypes\nconst (\n\tConstraintNoConstraint ConstraintType = iota\n\tConstraintPrimaryKey\n\tConstraintKey\n\tConstraintIndex\n\tConstraintUniq\n\tConstraintUniqKey\n\tConstraintUniqIndex\n\tConstraintForeignKey\n\tConstraintFulltext\n\tConstraintCheck\n)\n\n// Constraint is constraint for table definition.\ntype Constraint struct {\n\tnode\n\n\t// only supported by MariaDB 10.0.2+ (ADD {INDEX|KEY}, ADD FOREIGN KEY),\n\t// see https://mariadb.com/kb/en/library/alter-table/\n\tIfNotExists bool\n\n\tTp   ConstraintType\n\tName string\n\n\tKeys []*IndexPartSpecification // Used for PRIMARY KEY, UNIQUE, ......\n\n\tRefer *ReferenceDef // Used for foreign key.\n\n\tOption *IndexOption // Index Options\n\n\tExpr ExprNode // Used for Check\n\n\tEnforced bool // Used for Check\n}\n\n// Restore implements Node interface.\nfunc (n *Constraint) Restore(ctx *RestoreCtx) error {\n\tswitch n.Tp {\n\tcase ConstraintNoConstraint:\n\t\treturn nil\n\tcase ConstraintPrimaryKey:\n\t\tctx.WriteKeyWord(\"PRIMARY KEY\")\n\tcase ConstraintKey:\n\t\tctx.WriteKeyWord(\"KEY\")\n\t\tif n.IfNotExists {\n\t\t\tctx.WriteKeyWord(\" IF NOT EXISTS\")\n\t\t}\n\tcase ConstraintIndex:\n\t\tctx.WriteKeyWord(\"INDEX\")\n\t\tif n.IfNotExists {\n\t\t\tctx.WriteKeyWord(\" IF NOT EXISTS\")\n\t\t}\n\tcase ConstraintUniq:\n\t\tctx.WriteKeyWord(\"UNIQUE\")\n\tcase ConstraintUniqKey:\n\t\tctx.WriteKeyWord(\"UNIQUE KEY\")\n\tcase ConstraintUniqIndex:\n\t\tctx.WriteKeyWord(\"UNIQUE INDEX\")\n\tcase ConstraintFulltext:\n\t\tctx.WriteKeyWord(\"FULLTEXT\")\n\tcase ConstraintCheck:\n\t\tif n.Name != \"\" {\n\t\t\tctx.WriteKeyWord(\"CONSTRAINT \")\n\t\t\tctx.WriteName(n.Name)\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tctx.WriteKeyWord(\"CHECK\")\n\t\tctx.WritePlain(\"(\")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Trace(err)\n\t\t}\n\t\tctx.WritePlain(\") \")\n\t\tif n.Enforced {\n\t\t\tctx.WriteKeyWord(\"ENFORCED\")\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\"NOT ENFORCED\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tif n.Tp == ConstraintForeignKey {\n\t\tctx.WriteKeyWord(\"CONSTRAINT \")\n\t\tif n.Name != \"\" {\n\t\t\tctx.WriteName(n.Name)\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tctx.WriteKeyWord(\"FOREIGN KEY \")\n\t\tif n.IfNotExists {\n\t\t\tctx.WriteKeyWord(\"IF NOT EXISTS \")\n\t\t}\n\t} else if n.Name != \"\" {\n\t\tctx.WritePlain(\" \")\n\t\tctx.WriteName(n.Name)\n\t}\n\n\tctx.WritePlain(\"(\")\n\tfor i, keys := range n.Keys {\n\t\tif i > 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := keys.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing Constraint Keys: [%v]\", i)\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\n\tif n.Refer != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Refer.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing Constraint Refer\")\n\t\t}\n\t}\n\n\tif n.Option != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Option.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing Constraint Option\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *Constraint) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*Constraint)\n\tfor i, val := range n.Keys {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Keys[i] = node.(*IndexPartSpecification)\n\t}\n\tif n.Refer != nil {\n\t\tnode, ok := n.Refer.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Refer = node.(*ReferenceDef)\n\t}\n\tif n.Option != nil {\n\t\tnode, ok := n.Option.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Option = node.(*IndexOption)\n\t}\n\treturn v.Leave(n)\n}\n\n// ColumnDef is used for parsing column definition from SQL.\ntype ColumnDef struct {\n\tnode\n\n\tName    *ColumnName\n\tType    string\n\tOptions []*ColumnOption\n}\n\n// Restore implements Node interface.\nfunc (n *ColumnDef) Restore(ctx *RestoreCtx) error {\n\tif err := n.Name.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while splicing ColumnDef Name\")\n\t}\n\n\tif len(n.Type) > 0 {\n\t\tctx.WritePlain(\" \")\n\t\tctx.WriteKeyWord(n.Type)\n\t}\n\n\tfor i, options := range n.Options {\n\t\tctx.WritePlain(\" \")\n\t\tif err := options.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing ColumnDef ColumnOption: [%v]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ColumnDef) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ColumnDef)\n\tnode, ok := n.Name.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Name = node.(*ColumnName)\n\tfor i, val := range n.Options {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Options[i] = node.(*ColumnOption)\n\t}\n\treturn v.Leave(n)\n}\n\n// Validate checks if a column definition is legal.\n// For example, generated column definitions that contain such\n// column options as `ON UPDATE`, `AUTO_INCREMENT`, `DEFAULT`\n// are illegal.\nfunc (n *ColumnDef) Validate() bool {\n\tgeneratedCol := false\n\tillegalOpt4gc := false\n\tfor _, opt := range n.Options {\n\t\tif opt.Tp == ColumnOptionGenerated {\n\t\t\tgeneratedCol = true\n\t\t}\n\t\t_, found := invalidOptionForGeneratedColumn[opt.Tp]\n\t\tillegalOpt4gc = illegalOpt4gc || found\n\t}\n\treturn !(generatedCol && illegalOpt4gc)\n}\n\n// CreateTableStmt is a statement to create a table.\n// See https://dev.mysql.com/doc/refman/5.7/en/create-table.html\ntype CreateTableStmt struct {\n\tddlNode\n\n\tIfNotExists bool\n\tIsTemporary bool\n\tTable       *TableName\n\tReferTable  *TableName\n\tCols        []*ColumnDef\n\tConstraints []*Constraint\n\tOptions     []*TableOption\n\tPartition   *PartitionOptions\n\tOnDuplicate OnDuplicateKeyHandlingType\n\tSelect      ResultSetNode\n}\n\n// Restore implements Node interface.\nfunc (n *CreateTableStmt) Restore(ctx *RestoreCtx) error {\n\tif n.IsTemporary {\n\t\tctx.WriteKeyWord(\"CREATE TEMPORARY TABLE \")\n\t} else {\n\t\tctx.WriteKeyWord(\"CREATE TABLE \")\n\t}\n\tif n.IfNotExists {\n\t\tctx.WriteKeyWord(\"IF NOT EXISTS \")\n\t}\n\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while splicing CreateTableStmt Table\")\n\t}\n\tctx.WritePlain(\" \")\n\tif n.ReferTable != nil {\n\t\tctx.WriteKeyWord(\"LIKE \")\n\t\tif err := n.ReferTable.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing CreateTableStmt ReferTable\")\n\t\t}\n\t}\n\tlenCols := len(n.Cols)\n\tlenConstraints := len(n.Constraints)\n\tif lenCols+lenConstraints > 0 {\n\t\tctx.WritePlain(\"(\")\n\t\tfor i, col := range n.Cols {\n\t\t\tif i > 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := col.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing CreateTableStmt ColumnDef: [%v]\", i)\n\t\t\t}\n\t\t}\n\t\tfor i, constraint := range n.Constraints {\n\t\t\tif i > 0 || lenCols >= 1 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := constraint.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing CreateTableStmt Constraints: [%v]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\n\tfor i, option := range n.Options {\n\t\tctx.WritePlain(\" \")\n\t\tif err := option.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing CreateTableStmt TableOption: [%v]\", i)\n\t\t}\n\t}\n\n\tif n.Partition != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Partition.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing CreateTableStmt Partition\")\n\t\t}\n\t}\n\n\tif n.Select != nil {\n\t\tswitch n.OnDuplicate {\n\t\tcase OnDuplicateKeyHandlingError:\n\t\t\tctx.WriteKeyWord(\" AS \")\n\t\tcase OnDuplicateKeyHandlingIgnore:\n\t\t\tctx.WriteKeyWord(\" IGNORE AS \")\n\t\tcase OnDuplicateKeyHandlingReplace:\n\t\t\tctx.WriteKeyWord(\" REPLACE AS \")\n\t\t}\n\n\t\tif err := n.Select.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing CreateTableStmt Select\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *CreateTableStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*CreateTableStmt)\n\tnode, ok := n.Table.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Table = node.(*TableName)\n\tif n.ReferTable != nil {\n\t\tnode, ok = n.ReferTable.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.ReferTable = node.(*TableName)\n\t}\n\tfor i, val := range n.Cols {\n\t\tnode, ok = val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Cols[i] = node.(*ColumnDef)\n\t}\n\tfor i, val := range n.Constraints {\n\t\tnode, ok = val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Constraints[i] = node.(*Constraint)\n\t}\n\tif n.Select != nil {\n\t\tnode, ok := n.Select.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Select = node.(ResultSetNode)\n\t}\n\tif n.Partition != nil {\n\t\tnode, ok := n.Partition.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Partition = node.(*PartitionOptions)\n\t}\n\n\treturn v.Leave(n)\n}\n\n// DropTableStmt is a statement to drop one or more tables.\n// See https://dev.mysql.com/doc/refman/5.7/en/drop-table.html\ntype DropTableStmt struct {\n\tddlNode\n\n\tIfExists    bool\n\tTables      []*TableName\n\tIsView      bool\n\tIsTemporary bool // make sense ONLY if/when IsView == false\n}\n\n// Restore implements Node interface.\nfunc (n *DropTableStmt) Restore(ctx *RestoreCtx) error {\n\tif n.IsView {\n\t\tctx.WriteKeyWord(\"DROP VIEW \")\n\t} else {\n\t\tif n.IsTemporary {\n\t\t\tctx.WriteKeyWord(\"DROP TEMPORARY TABLE \")\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\"DROP TABLE \")\n\t\t}\n\t}\n\tif n.IfExists {\n\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t}\n\n\tfor index, table := range n.Tables {\n\t\tif index != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := table.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore DropTableStmt.Tables \"+fmt.Sprint(index))\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DropTableStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DropTableStmt)\n\tfor i, val := range n.Tables {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Tables[i] = node.(*TableName)\n\t}\n\treturn v.Leave(n)\n}\n\n// DropSequenceStmt is a statement to drop a Sequence.\ntype DropSequenceStmt struct {\n\tddlNode\n\n\tIfExists    bool\n\tSequences   []*TableName\n\tIsTemporary bool\n}\n\n// Restore implements Node interface.\nfunc (n *DropSequenceStmt) Restore(ctx *RestoreCtx) error {\n\tif n.IsTemporary {\n\t\tctx.WriteKeyWord(\"DROP TEMPORARY SEQUENCE \")\n\t} else {\n\t\tctx.WriteKeyWord(\"DROP SEQUENCE \")\n\t}\n\tif n.IfExists {\n\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t}\n\tfor i, sequence := range n.Sequences {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := sequence.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore DropSequenceStmt.Sequences[%d]\", i)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DropSequenceStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DropSequenceStmt)\n\tfor i, val := range n.Sequences {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Sequences[i] = node.(*TableName)\n\t}\n\treturn v.Leave(n)\n}\n\n// RenameTableStmt is a statement to rename a table.\n// See http://dev.mysql.com/doc/refman/5.7/en/rename-table.html\ntype RenameTableStmt struct {\n\tddlNode\n\n\tOldTable *TableName\n\tNewTable *TableName\n\n\t// TableToTables is only useful for syncer which depends heavily on tidb parser to do some dirty work for now.\n\t// TODO: Refactor this when you are going to add full support for multiple schema changes.\n\tTableToTables []*TableToTable\n}\n\n// Restore implements Node interface.\nfunc (n *RenameTableStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"RENAME TABLE \")\n\tfor index, table2table := range n.TableToTables {\n\t\tif index != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := table2table.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore RenameTableStmt.TableToTables\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *RenameTableStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*RenameTableStmt)\n\tnode, ok := n.OldTable.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.OldTable = node.(*TableName)\n\tnode, ok = n.NewTable.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.NewTable = node.(*TableName)\n\n\tfor i, t := range n.TableToTables {\n\t\tnode, ok := t.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.TableToTables[i] = node.(*TableToTable)\n\t}\n\n\treturn v.Leave(n)\n}\n\n// TableToTable represents renaming old table to new table used in RenameTableStmt.\ntype TableToTable struct {\n\tnode\n\tOldTable *TableName\n\tNewTable *TableName\n}\n\n// Restore implements Node interface.\nfunc (n *TableToTable) Restore(ctx *RestoreCtx) error {\n\tif err := n.OldTable.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore TableToTable.OldTable\")\n\t}\n\tctx.WriteKeyWord(\" TO \")\n\tif err := n.NewTable.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore TableToTable.NewTable\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *TableToTable) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*TableToTable)\n\tnode, ok := n.OldTable.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.OldTable = node.(*TableName)\n\tnode, ok = n.NewTable.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.NewTable = node.(*TableName)\n\treturn v.Leave(n)\n}\n\n// CreateViewStmt is a statement to create a View.\n// See https://dev.mysql.com/doc/refman/5.7/en/create-view.html\ntype CreateViewStmt struct {\n\tddlNode\n\n\tOrReplace   bool\n\tViewName    *TableName\n\tCols        []model.CIStr\n\tSelect      StmtNode\n\tSchemaCols  []model.CIStr\n\tAlgorithm   model.ViewAlgorithm\n\tDefiner     *auth.UserIdentity\n\tSecurity    model.ViewSecurity\n\tCheckOption model.ViewCheckOption\n}\n\n// Restore implements Node interface.\nfunc (n *CreateViewStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"CREATE \")\n\tif n.OrReplace {\n\t\tctx.WriteKeyWord(\"OR REPLACE \")\n\t}\n\tctx.WriteKeyWord(\"ALGORITHM\")\n\tctx.WritePlain(\" = \")\n\tctx.WriteKeyWord(n.Algorithm.String())\n\tctx.WriteKeyWord(\" DEFINER\")\n\tctx.WritePlain(\" = \")\n\n\t// todo Use n.Definer.Restore(ctx) to replace this part\n\tif n.Definer.CurrentUser {\n\t\tctx.WriteKeyWord(\"current_user\")\n\t} else {\n\t\tctx.WriteName(n.Definer.Username)\n\t\tif n.Definer.Hostname != \"\" {\n\t\t\tctx.WritePlain(\"@\")\n\t\t\tctx.WriteName(n.Definer.Hostname)\n\t\t}\n\t}\n\n\tctx.WriteKeyWord(\" SQL SECURITY \")\n\tctx.WriteKeyWord(n.Security.String())\n\tctx.WriteKeyWord(\" VIEW \")\n\n\tif err := n.ViewName.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while create CreateViewStmt.ViewName\")\n\t}\n\n\tfor i, col := range n.Cols {\n\t\tif i == 0 {\n\t\t\tctx.WritePlain(\" (\")\n\t\t} else {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t\tctx.WriteName(col.O)\n\t\tif i == len(n.Cols)-1 {\n\t\t\tctx.WritePlain(\")\")\n\t\t}\n\t}\n\n\tctx.WriteKeyWord(\" AS \")\n\n\tif err := n.Select.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while create CreateViewStmt.Select\")\n\t}\n\n\tif n.CheckOption != model.CheckOptionCascaded {\n\t\tctx.WriteKeyWord(\" WITH \")\n\t\tctx.WriteKeyWord(n.CheckOption.String())\n\t\tctx.WriteKeyWord(\" CHECK OPTION\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *CreateViewStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*CreateViewStmt)\n\tnode, ok := n.ViewName.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.ViewName = node.(*TableName)\n\tselnode, ok := n.Select.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Select = selnode.(StmtNode)\n\treturn v.Leave(n)\n}\n\n// CreateSequenceStmt is a statement to create a Sequence.\ntype CreateSequenceStmt struct {\n\tddlNode\n\n\t// TODO : support or replace if need : care for it will conflict on temporaryOpt.\n\tOrReplace   bool\n\tIsTemporary bool\n\tIfNotExists bool\n\tName        *TableName\n\tSeqOptions  []*SequenceOption\n\tTblOptions  []*TableOption\n}\n\n// Restore implements Node interface.\nfunc (n *CreateSequenceStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"CREATE \")\n\tif n.OrReplace {\n\t\tctx.WriteKeyWord(\"OR REPLACE \")\n\t}\n\tif n.IsTemporary {\n\t\tctx.WriteKeyWord(\"TEMPORARY \")\n\t}\n\tctx.WriteKeyWord(\"SEQUENCE \")\n\tif n.IfNotExists {\n\t\tctx.WriteKeyWord(\"IF NOT EXISTS \")\n\t}\n\tif err := n.Name.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while create CreateSequenceStmt.Name\")\n\t}\n\tfor i, option := range n.SeqOptions {\n\t\tctx.WritePlain(\" \")\n\t\tif err := option.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing CreateSequenceStmt SequenceOption: [%v]\", i)\n\t\t}\n\t}\n\tfor i, option := range n.TblOptions {\n\t\tctx.WritePlain(\" \")\n\t\tif err := option.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing CreateSequenceStmt TableOption: [%v]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *CreateSequenceStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*CreateSequenceStmt)\n\tnode, ok := n.Name.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Name = node.(*TableName)\n\treturn v.Leave(n)\n}\n\n// IndexLockAndAlgorithm stores the algorithm option and the lock option.\ntype IndexLockAndAlgorithm struct {\n\tnode\n\n\tLockTp      LockType\n\tAlgorithmTp AlgorithmType\n}\n\n// Restore implements Node interface.\nfunc (n *IndexLockAndAlgorithm) Restore(ctx *RestoreCtx) error {\n\thasPrevOption := false\n\tif n.AlgorithmTp != AlgorithmTypeDefault {\n\t\tctx.WriteKeyWord(\"ALGORITHM\")\n\t\tctx.WritePlain(\" = \")\n\t\tctx.WriteKeyWord(n.AlgorithmTp.String())\n\t\thasPrevOption = true\n\t}\n\n\tif n.LockTp != LockTypeDefault {\n\t\tif hasPrevOption {\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tctx.WriteKeyWord(\"LOCK\")\n\t\tctx.WritePlain(\" = \")\n\t\tctx.WriteKeyWord(n.LockTp.String())\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *IndexLockAndAlgorithm) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*IndexLockAndAlgorithm)\n\treturn v.Leave(n)\n}\n\n// IndexKeyType is the type for index key.\ntype IndexKeyType int\n\n// Index key types.\nconst (\n\tIndexKeyTypeNone IndexKeyType = iota\n\tIndexKeyTypeUnique\n\tIndexKeyTypeSpatial\n\tIndexKeyTypeFullText\n)\n\n// CreateIndexStmt is a statement to create an index.\n// See https://dev.mysql.com/doc/refman/5.7/en/create-index.html\ntype CreateIndexStmt struct {\n\tddlNode\n\n\t// only supported by MariaDB 10.0.2+,\n\t// see https://mariadb.com/kb/en/library/create-index/\n\tIfNotExists bool\n\n\tIndexName               string\n\tTable                   *TableName\n\tIndexPartSpecifications []*IndexPartSpecification\n\tIndexOption             *IndexOption\n\tKeyType                 IndexKeyType\n\tLockAlg                 *IndexLockAndAlgorithm\n}\n\n// Restore implements Node interface.\nfunc (n *CreateIndexStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"CREATE \")\n\tswitch n.KeyType {\n\tcase IndexKeyTypeUnique:\n\t\tctx.WriteKeyWord(\"UNIQUE \")\n\tcase IndexKeyTypeSpatial:\n\t\tctx.WriteKeyWord(\"SPATIAL \")\n\tcase IndexKeyTypeFullText:\n\t\tctx.WriteKeyWord(\"FULLTEXT \")\n\t}\n\tctx.WriteKeyWord(\"INDEX \")\n\tif n.IfNotExists {\n\t\tctx.WriteKeyWord(\"IF NOT EXISTS \")\n\t}\n\tctx.WriteName(n.IndexName)\n\tctx.WriteKeyWord(\" ON \")\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore CreateIndexStmt.Table\")\n\t}\n\n\tctx.WritePlain(\" (\")\n\tfor i, indexColName := range n.IndexPartSpecifications {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := indexColName.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore CreateIndexStmt.IndexPartSpecifications: [%v]\", i)\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\n\tif n.IndexOption.Tp != model.IndexTypeInvalid || n.IndexOption.KeyBlockSize > 0 || n.IndexOption.Comment != \"\" || len(n.IndexOption.ParserName.O) > 0 || n.IndexOption.Visibility != IndexVisibilityDefault {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.IndexOption.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore CreateIndexStmt.IndexOption\")\n\t\t}\n\t}\n\n\tif n.LockAlg != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.LockAlg.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore CreateIndexStmt.LockAlg\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *CreateIndexStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*CreateIndexStmt)\n\tnode, ok := n.Table.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Table = node.(*TableName)\n\tfor i, val := range n.IndexPartSpecifications {\n\t\tnode, ok = val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.IndexPartSpecifications[i] = node.(*IndexPartSpecification)\n\t}\n\tif n.IndexOption != nil {\n\t\tnode, ok := n.IndexOption.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.IndexOption = node.(*IndexOption)\n\t}\n\tif n.LockAlg != nil {\n\t\tnode, ok := n.LockAlg.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.LockAlg = node.(*IndexLockAndAlgorithm)\n\t}\n\treturn v.Leave(n)\n}\n\n// DropIndexStmt is a statement to drop the index.\n// See https://dev.mysql.com/doc/refman/5.7/en/drop-index.html\ntype DropIndexStmt struct {\n\tddlNode\n\n\tIfExists  bool\n\tIndexName string\n\tTable     *TableName\n\tLockAlg   *IndexLockAndAlgorithm\n}\n\n// Restore implements Node interface.\nfunc (n *DropIndexStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"DROP INDEX \")\n\tif n.IfExists {\n\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t}\n\tctx.WriteName(n.IndexName)\n\tctx.WriteKeyWord(\" ON \")\n\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while add index\")\n\t}\n\n\tif n.LockAlg != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.LockAlg.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore CreateIndexStmt.LockAlg\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DropIndexStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DropIndexStmt)\n\tnode, ok := n.Table.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Table = node.(*TableName)\n\tif n.LockAlg != nil {\n\t\tnode, ok := n.LockAlg.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.LockAlg = node.(*IndexLockAndAlgorithm)\n\t}\n\treturn v.Leave(n)\n}\n\n// LockTablesStmt is a statement to lock tables.\ntype LockTablesStmt struct {\n\tddlNode\n\n\tTableLocks []TableLock\n}\n\n// TableLock contains the table name and lock type.\ntype TableLock struct {\n\tTable *TableName\n\tType  model.TableLockType\n}\n\n// Accept implements Node Accept interface.\nfunc (n *LockTablesStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*LockTablesStmt)\n\tfor i := range n.TableLocks {\n\t\tnode, ok := n.TableLocks[i].Table.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.TableLocks[i].Table = node.(*TableName)\n\t}\n\treturn v.Leave(n)\n}\n\n// Restore implements Node interface.\nfunc (n *LockTablesStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"LOCK TABLES \")\n\tfor i, tl := range n.TableLocks {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := tl.Table.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while add index\")\n\t\t}\n\t\tctx.WriteKeyWord(\" \" + tl.Type.String())\n\t}\n\treturn nil\n}\n\n// UnlockTablesStmt is a statement to unlock tables.\ntype UnlockTablesStmt struct {\n\tddlNode\n}\n\n// Accept implements Node Accept interface.\nfunc (n *UnlockTablesStmt) Accept(v Visitor) (Node, bool) {\n\t_, _ = v.Enter(n)\n\treturn v.Leave(n)\n}\n\n// Restore implements Node interface.\nfunc (n *UnlockTablesStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"UNLOCK TABLES\")\n\treturn nil\n}\n\n// CleanupTableLockStmt is a statement to cleanup table lock.\ntype CleanupTableLockStmt struct {\n\tddlNode\n\n\tTables []*TableName\n}\n\n// Accept implements Node Accept interface.\nfunc (n *CleanupTableLockStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*CleanupTableLockStmt)\n\tfor i := range n.Tables {\n\t\tnode, ok := n.Tables[i].Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Tables[i] = node.(*TableName)\n\t}\n\treturn v.Leave(n)\n}\n\n// Restore implements Node interface.\nfunc (n *CleanupTableLockStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"ADMIN CLEANUP TABLE LOCK \")\n\tfor i, v := range n.Tables {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore CleanupTableLockStmt.Tables[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// RepairTableStmt is a statement to repair tableInfo.\ntype RepairTableStmt struct {\n\tddlNode\n\tTable      *TableName\n\tCreateStmt *CreateTableStmt\n}\n\n// Accept implements Node Accept interface.\nfunc (n *RepairTableStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*RepairTableStmt)\n\tnode, ok := n.Table.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Table = node.(*TableName)\n\tnode, ok = n.CreateStmt.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.CreateStmt = node.(*CreateTableStmt)\n\treturn v.Leave(n)\n}\n\n// Restore implements Node interface.\nfunc (n *RepairTableStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"ADMIN REPAIR TABLE \")\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotatef(err, \"An error occurred while restore RepairTableStmt.table : [%v]\", n.Table)\n\t}\n\tctx.WritePlain(\" \")\n\tif err := n.CreateStmt.Restore(ctx); err != nil {\n\t\treturn errors.Annotatef(err, \"An error occurred while restore RepairTableStmt.createStmt : [%v]\", n.CreateStmt)\n\t}\n\treturn nil\n}\n\n// TableOptionType is the type for TableOption\ntype TableOptionType int\n\n// TableOption types.\nconst (\n\tTableOptionNone TableOptionType = iota\n\tTableOptionEngine\n\tTableOptionCharset\n\tTableOptionCollate\n\tTableOptionAutoIncrement\n\tTableOptionComment\n\tTableOptionAvgRowLength\n\tTableOptionCheckSum\n\tTableOptionCompression\n\tTableOptionConnection\n\tTableOptionPassword\n\tTableOptionKeyBlockSize\n\tTableOptionMaxRows\n\tTableOptionMinRows\n\tTableOptionDelayKeyWrite\n\tTableOptionRowFormat\n\tTableOptionStatsPersistent\n\tTableOptionStatsAutoRecalc\n\tTableOptionShardRowID\n\tTableOptionPreSplitRegion\n\tTableOptionPackKeys\n\tTableOptionTablespace\n\tTableOptionNodegroup\n\tTableOptionDataDirectory\n\tTableOptionIndexDirectory\n\tTableOptionStorageMedia\n\tTableOptionStatsSamplePages\n\tTableOptionSecondaryEngine\n\tTableOptionSecondaryEngineNull\n\tTableOptionInsertMethod\n\tTableOptionTableCheckSum\n\tTableOptionUnion\n\tTableOptionEncryption\n\tTableOptionRefTable\n\tTableOptionDBType\n)\n\n// RowFormat types\nconst (\n\tRowFormatDefault uint64 = iota + 1\n\tRowFormatDynamic\n\tRowFormatFixed\n\tRowFormatCompressed\n\tRowFormatRedundant\n\tRowFormatCompact\n\tTokuDBRowFormatDefault\n\tTokuDBRowFormatFast\n\tTokuDBRowFormatSmall\n\tTokuDBRowFormatZlib\n\tTokuDBRowFormatQuickLZ\n\tTokuDBRowFormatLzma\n\tTokuDBRowFormatSnappy\n\tTokuDBRowFormatUncompressed\n)\n\n// OnDuplicateKeyHandlingType is the option that handle unique key values in 'CREATE TABLE ... SELECT' or `LOAD DATA`.\n// See https://dev.mysql.com/doc/refman/5.7/en/create-table-select.html\n// See https://dev.mysql.com/doc/refman/5.7/en/load-data.html\ntype OnDuplicateKeyHandlingType int\n\n// OnDuplicateKeyHandling types\nconst (\n\tOnDuplicateKeyHandlingError OnDuplicateKeyHandlingType = iota\n\tOnDuplicateKeyHandlingIgnore\n\tOnDuplicateKeyHandlingReplace\n)\n\nconst (\n\tTableOptionCharsetWithoutConvertTo uint64 = 0\n\tTableOptionCharsetWithConvertTo    uint64 = 1\n)\n\n// TableOption is used for parsing table option from SQL.\ntype TableOption struct {\n\tTp         TableOptionType\n\tDefault    bool\n\tStrValue   string\n\tUintValue  uint64\n\tTableNames []*TableName\n}\n\nfunc (n *TableOption) Restore(ctx *RestoreCtx) error {\n\tswitch n.Tp {\n\tcase TableOptionEngine:\n\t\tctx.WriteKeyWord(\"ENGINE \")\n\t\tctx.WritePlain(\"= \")\n\t\tif n.StrValue != \"\" {\n\t\t\tctx.WritePlain(n.StrValue)\n\t\t} else {\n\t\t\tctx.WritePlain(\"''\")\n\t\t}\n\tcase TableOptionCharset:\n\t\tif n.UintValue == TableOptionCharsetWithConvertTo {\n\t\t\tctx.WriteKeyWord(\"CONVERT TO \")\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\"DEFAULT \")\n\t\t}\n\t\tctx.WriteKeyWord(\"CHARACTER SET \")\n\t\tif n.UintValue == TableOptionCharsetWithoutConvertTo {\n\t\t\tctx.WriteKeyWord(\"= \")\n\t\t}\n\t\tif n.Default {\n\t\t\tctx.WriteKeyWord(\"DEFAULT\")\n\t\t} else {\n\t\t\tctx.WriteKeyWord(n.StrValue)\n\t\t}\n\tcase TableOptionCollate:\n\t\tctx.WriteKeyWord(\"DEFAULT COLLATE \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteKeyWord(n.StrValue)\n\tcase TableOptionAutoIncrement:\n\t\tctx.WriteKeyWord(\"AUTO_INCREMENT \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WritePlainf(\"%d\", n.UintValue)\n\tcase TableOptionComment:\n\t\tctx.WriteKeyWord(\"COMMENT \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.StrValue)\n\tcase TableOptionAvgRowLength:\n\t\tctx.WriteKeyWord(\"AVG_ROW_LENGTH \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WritePlainf(\"%d\", n.UintValue)\n\tcase TableOptionCheckSum:\n\t\tctx.WriteKeyWord(\"CHECKSUM \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WritePlainf(\"%d\", n.UintValue)\n\tcase TableOptionCompression:\n\t\tctx.WriteKeyWord(\"COMPRESSION \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.StrValue)\n\tcase TableOptionConnection:\n\t\tctx.WriteKeyWord(\"CONNECTION \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.StrValue)\n\tcase TableOptionPassword:\n\t\tctx.WriteKeyWord(\"PASSWORD \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.StrValue)\n\tcase TableOptionKeyBlockSize:\n\t\tctx.WriteKeyWord(\"KEY_BLOCK_SIZE \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WritePlainf(\"%d\", n.UintValue)\n\tcase TableOptionMaxRows:\n\t\tctx.WriteKeyWord(\"MAX_ROWS \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WritePlainf(\"%d\", n.UintValue)\n\tcase TableOptionMinRows:\n\t\tctx.WriteKeyWord(\"MIN_ROWS \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WritePlainf(\"%d\", n.UintValue)\n\tcase TableOptionDelayKeyWrite:\n\t\tctx.WriteKeyWord(\"DELAY_KEY_WRITE \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WritePlainf(\"%d\", n.UintValue)\n\tcase TableOptionRowFormat:\n\t\tctx.WriteKeyWord(\"ROW_FORMAT \")\n\t\tctx.WritePlain(\"= \")\n\t\tswitch n.UintValue {\n\t\tcase RowFormatDefault:\n\t\t\tctx.WriteKeyWord(\"DEFAULT\")\n\t\tcase RowFormatDynamic:\n\t\t\tctx.WriteKeyWord(\"DYNAMIC\")\n\t\tcase RowFormatFixed:\n\t\t\tctx.WriteKeyWord(\"FIXED\")\n\t\tcase RowFormatCompressed:\n\t\t\tctx.WriteKeyWord(\"COMPRESSED\")\n\t\tcase RowFormatRedundant:\n\t\t\tctx.WriteKeyWord(\"REDUNDANT\")\n\t\tcase RowFormatCompact:\n\t\t\tctx.WriteKeyWord(\"COMPACT\")\n\t\tcase TokuDBRowFormatDefault:\n\t\t\tctx.WriteKeyWord(\"TOKUDB_DEFAULT\")\n\t\tcase TokuDBRowFormatFast:\n\t\t\tctx.WriteKeyWord(\"TOKUDB_FAST\")\n\t\tcase TokuDBRowFormatSmall:\n\t\t\tctx.WriteKeyWord(\"TOKUDB_SMALL\")\n\t\tcase TokuDBRowFormatZlib:\n\t\t\tctx.WriteKeyWord(\"TOKUDB_ZLIB\")\n\t\tcase TokuDBRowFormatQuickLZ:\n\t\t\tctx.WriteKeyWord(\"TOKUDB_QUICKLZ\")\n\t\tcase TokuDBRowFormatLzma:\n\t\t\tctx.WriteKeyWord(\"TOKUDB_LZMA\")\n\t\tcase TokuDBRowFormatSnappy:\n\t\t\tctx.WriteKeyWord(\"TOKUDB_SNAPPY\")\n\t\tcase TokuDBRowFormatUncompressed:\n\t\t\tctx.WriteKeyWord(\"TOKUDB_UNCOMPRESSED\")\n\t\tdefault:\n\t\t\treturn errors.Errorf(\"invalid TableOption: TableOptionRowFormat: %d\", n.UintValue)\n\t\t}\n\tcase TableOptionStatsPersistent:\n\t\t// TODO: not support\n\t\tctx.WriteKeyWord(\"STATS_PERSISTENT \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteKeyWord(\"DEFAULT\")\n\t\tctx.WritePlain(\" /* TableOptionStatsPersistent is not supported */ \")\n\tcase TableOptionStatsAutoRecalc:\n\t\tctx.WriteKeyWord(\"STATS_AUTO_RECALC \")\n\t\tctx.WritePlain(\"= \")\n\t\tif n.Default {\n\t\t\tctx.WriteKeyWord(\"DEFAULT\")\n\t\t} else {\n\t\t\tctx.WritePlainf(\"%d\", n.UintValue)\n\t\t}\n\tcase TableOptionShardRowID:\n\t\tctx.WriteKeyWord(\"SHARD_ROW_ID_BITS \")\n\t\tctx.WritePlainf(\"= %d\", n.UintValue)\n\tcase TableOptionPreSplitRegion:\n\t\tctx.WriteKeyWord(\"PRE_SPLIT_REGIONS \")\n\t\tctx.WritePlainf(\"= %d\", n.UintValue)\n\tcase TableOptionPackKeys:\n\t\t// TODO: not support\n\t\tctx.WriteKeyWord(\"PACK_KEYS \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteKeyWord(\"DEFAULT\")\n\t\tctx.WritePlain(\" /* TableOptionPackKeys is not supported */ \")\n\tcase TableOptionTablespace:\n\t\tctx.WriteKeyWord(\"TABLESPACE \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteName(n.StrValue)\n\tcase TableOptionNodegroup:\n\t\tctx.WriteKeyWord(\"NODEGROUP \")\n\t\tctx.WritePlainf(\"= %d\", n.UintValue)\n\tcase TableOptionDataDirectory:\n\t\tctx.WriteKeyWord(\"DATA DIRECTORY \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.StrValue)\n\tcase TableOptionIndexDirectory:\n\t\tctx.WriteKeyWord(\"INDEX DIRECTORY \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.StrValue)\n\tcase TableOptionStorageMedia:\n\t\tctx.WriteKeyWord(\"STORAGE \")\n\t\tctx.WriteKeyWord(n.StrValue)\n\tcase TableOptionStatsSamplePages:\n\t\tctx.WriteKeyWord(\"STATS_SAMPLE_PAGES \")\n\t\tctx.WritePlain(\"= \")\n\t\tif n.Default {\n\t\t\tctx.WriteKeyWord(\"DEFAULT\")\n\t\t} else {\n\t\t\tctx.WritePlainf(\"%d\", n.UintValue)\n\t\t}\n\tcase TableOptionSecondaryEngine:\n\t\tctx.WriteKeyWord(\"SECONDARY_ENGINE \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.StrValue)\n\tcase TableOptionSecondaryEngineNull:\n\t\tctx.WriteKeyWord(\"SECONDARY_ENGINE \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteKeyWord(\"NULL\")\n\tcase TableOptionInsertMethod:\n\t\tctx.WriteKeyWord(\"INSERT_METHOD \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.StrValue)\n\tcase TableOptionTableCheckSum:\n\t\tctx.WriteKeyWord(\"TABLE_CHECKSUM \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WritePlainf(\"%d\", n.UintValue)\n\tcase TableOptionUnion:\n\t\tctx.WriteKeyWord(\"UNION \")\n\t\tctx.WritePlain(\"= (\")\n\t\tfor i, tableName := range n.TableNames {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\ttableName.Restore(ctx)\n\t\t}\n\t\tctx.WritePlain(\")\")\n\tcase TableOptionEncryption:\n\t\tctx.WriteKeyWord(\"ENCRYPTION \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.StrValue)\n\tcase TableOptionRefTable:\n\t\tctx.WriteKeyWord(\"REF_TABLE \")\n\t\tctx.WritePlain(\"= \")\n\t\ttn := n.TableNames[0]\n\t\ttn.Restore(ctx)\n\tcase TableOptionDBType:\n\t\tctx.WriteKeyWord(\"DB_TYPE \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.StrValue)\n\tdefault:\n\t\treturn errors.Errorf(\"invalid TableOption: %d\", n.Tp)\n\t}\n\treturn nil\n}\n\n// SequenceOptionType is the type for SequenceOption\ntype SequenceOptionType int\n\n// SequenceOption types.\nconst (\n\tSequenceOptionNone SequenceOptionType = iota\n\tSequenceOptionIncrementBy\n\tSequenceStartWith\n\tSequenceNoMinValue\n\tSequenceMinValue\n\tSequenceNoMaxValue\n\tSequenceMaxValue\n\tSequenceNoCache\n\tSequenceCache\n\tSequenceNoCycle\n\tSequenceCycle\n\tSequenceNoOrder\n\tSequenceOrder\n)\n\n// SequenceOption is used for parsing sequence option from SQL.\ntype SequenceOption struct {\n\tTp       SequenceOptionType\n\tIntValue int64\n}\n\nfunc (n *SequenceOption) Restore(ctx *RestoreCtx) error {\n\tswitch n.Tp {\n\tcase SequenceOptionIncrementBy:\n\t\tctx.WriteKeyWord(\"INCREMENT BY \")\n\t\tctx.WritePlainf(\"%d\", n.IntValue)\n\tcase SequenceStartWith:\n\t\tctx.WriteKeyWord(\"START WITH \")\n\t\tctx.WritePlainf(\"%d\", n.IntValue)\n\tcase SequenceNoMinValue:\n\t\tctx.WriteKeyWord(\"NO MINVALUE\")\n\tcase SequenceMinValue:\n\t\tctx.WriteKeyWord(\"MINVALUE \")\n\t\tctx.WritePlainf(\"%d\", n.IntValue)\n\tcase SequenceNoMaxValue:\n\t\tctx.WriteKeyWord(\"NO MAXVALUE\")\n\tcase SequenceMaxValue:\n\t\tctx.WriteKeyWord(\"MAXVALUE \")\n\t\tctx.WritePlainf(\"%d\", n.IntValue)\n\tcase SequenceNoCache:\n\t\tctx.WriteKeyWord(\"NOCACHE\")\n\tcase SequenceCache:\n\t\tctx.WriteKeyWord(\"CACHE \")\n\t\tctx.WritePlainf(\"%d\", n.IntValue)\n\tcase SequenceNoCycle:\n\t\tctx.WriteKeyWord(\"NOCYCLE\")\n\tcase SequenceCycle:\n\t\tctx.WriteKeyWord(\"CYCLE\")\n\tcase SequenceNoOrder:\n\t\tctx.WriteKeyWord(\"NOORDER\")\n\tcase SequenceOrder:\n\t\tctx.WriteKeyWord(\"ORDER\")\n\tdefault:\n\t\treturn errors.Errorf(\"invalid SequenceOption: %d\", n.Tp)\n\t}\n\treturn nil\n}\n\n// ColumnPositionType is the type for ColumnPosition.\ntype ColumnPositionType int\n\n// ColumnPosition Types\nconst (\n\tColumnPositionNone ColumnPositionType = iota\n\tColumnPositionFirst\n\tColumnPositionAfter\n)\n\n// ColumnPosition represent the position of the newly added column\ntype ColumnPosition struct {\n\tnode\n\t// Tp is either ColumnPositionNone, ColumnPositionFirst or ColumnPositionAfter.\n\tTp ColumnPositionType\n\t// RelativeColumn is the column the newly added column after if type is ColumnPositionAfter\n\tRelativeColumn *ColumnName\n}\n\n// Restore implements Node interface.\nfunc (n *ColumnPosition) Restore(ctx *RestoreCtx) error {\n\tswitch n.Tp {\n\tcase ColumnPositionNone:\n\t\t// do nothing\n\tcase ColumnPositionFirst:\n\t\tctx.WriteKeyWord(\"FIRST\")\n\tcase ColumnPositionAfter:\n\t\tctx.WriteKeyWord(\"AFTER \")\n\t\tif err := n.RelativeColumn.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore ColumnPosition.RelativeColumn\")\n\t\t}\n\tdefault:\n\t\treturn errors.Errorf(\"invalid ColumnPositionType: %d\", n.Tp)\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ColumnPosition) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ColumnPosition)\n\tif n.RelativeColumn != nil {\n\t\tnode, ok := n.RelativeColumn.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.RelativeColumn = node.(*ColumnName)\n\t}\n\treturn v.Leave(n)\n}\n\n// AlterTableType is the type for AlterTableSpec.\ntype AlterTableType int\n\n// AlterTable types.\nconst (\n\tAlterTableOption AlterTableType = iota + 1\n\tAlterTableAddColumns\n\tAlterTableAddConstraint\n\tAlterTableDropColumn\n\tAlterTableDropPrimaryKey\n\tAlterTableDropIndex\n\tAlterTableDropForeignKey\n\tAlterTableModifyColumn\n\tAlterTableChangeColumn\n\tAlterTableRenameColumn\n\tAlterTableRenameTable\n\tAlterTableAlterColumn\n\tAlterTableLock\n\tAlterTableAlgorithm\n\tAlterTableRenameIndex\n\tAlterTableForce\n\tAlterTableAddPartitions\n\tAlterTableCoalescePartitions\n\tAlterTableDropPartition\n\tAlterTableTruncatePartition\n\tAlterTablePartition\n\tAlterTableEnableKeys\n\tAlterTableDisableKeys\n\tAlterTableRemovePartitioning\n\tAlterTableWithValidation\n\tAlterTableWithoutValidation\n\tAlterTableSecondaryLoad\n\tAlterTableSecondaryUnload\n\tAlterTableRebuildPartition\n\tAlterTableReorganizePartition\n\tAlterTableCheckPartitions\n\tAlterTableExchangePartition\n\tAlterTableOptimizePartition\n\tAlterTableRepairPartition\n\tAlterTableImportPartitionTablespace\n\tAlterTableDiscardPartitionTablespace\n\tAlterTableAlterCheck\n\tAlterTableDropCheck\n\tAlterTableImportTablespace\n\tAlterTableDiscardTablespace\n\tAlterTableIndexInvisible\n\t// TODO: Add more actions\n\tAlterTableOrderByColumns\n\t// AlterTableSetTiFlashReplica uses to set the table TiFlash replica.\n\tAlterTableSetTiFlashReplica\n)\n\n// LockType is the type for AlterTableSpec.\n// See https://dev.mysql.com/doc/refman/5.7/en/alter-table.html#alter-table-concurrency\ntype LockType byte\n\nfunc (n LockType) String() string {\n\tswitch n {\n\tcase LockTypeNone:\n\t\treturn \"NONE\"\n\tcase LockTypeDefault:\n\t\treturn \"DEFAULT\"\n\tcase LockTypeShared:\n\t\treturn \"SHARED\"\n\tcase LockTypeExclusive:\n\t\treturn \"EXCLUSIVE\"\n\t}\n\treturn \"\"\n}\n\n// Lock Types.\nconst (\n\tLockTypeNone LockType = iota + 1\n\tLockTypeDefault\n\tLockTypeShared\n\tLockTypeExclusive\n)\n\n// AlgorithmType is the algorithm of the DDL operations.\n// See https://dev.mysql.com/doc/refman/8.0/en/alter-table.html#alter-table-performance.\ntype AlgorithmType byte\n\n// DDL algorithms.\n// For now, TiDB only supported inplace and instance algorithms. If the user specify `copy`,\n// will get an error.\nconst (\n\tAlgorithmTypeDefault AlgorithmType = iota\n\tAlgorithmTypeCopy\n\tAlgorithmTypeInplace\n\tAlgorithmTypeInstant\n)\n\nfunc (a AlgorithmType) String() string {\n\tswitch a {\n\tcase AlgorithmTypeDefault:\n\t\treturn \"DEFAULT\"\n\tcase AlgorithmTypeCopy:\n\t\treturn \"COPY\"\n\tcase AlgorithmTypeInplace:\n\t\treturn \"INPLACE\"\n\tcase AlgorithmTypeInstant:\n\t\treturn \"INSTANT\"\n\tdefault:\n\t\treturn \"DEFAULT\"\n\t}\n}\n\n// AlterTableSpec represents alter table specification.\ntype AlterTableSpec struct {\n\tnode\n\n\t// only supported by MariaDB 10.0.2+ (DROP COLUMN, CHANGE COLUMN, MODIFY COLUMN, DROP INDEX, DROP FOREIGN KEY, DROP PARTITION)\n\t// see https://mariadb.com/kb/en/library/alter-table/\n\tIfExists bool\n\n\t// only supported by MariaDB 10.0.2+ (ADD COLUMN, ADD PARTITION)\n\t// see https://mariadb.com/kb/en/library/alter-table/\n\tIfNotExists bool\n\n\tNoWriteToBinlog bool\n\tOnAllPartitions bool\n\n\tTp              AlterTableType\n\tName            string\n\tConstraint      *Constraint\n\tOptions         []*TableOption\n\tOrderByList     []*AlterOrderItem\n\tNewTable        *TableName\n\tNewColumns      []*ColumnDef\n\tNewConstraints  []*Constraint\n\tOldColumnName   *ColumnName\n\tNewColumnName   *ColumnName\n\tPosition        *ColumnPosition\n\tLockType        LockType\n\tAlgorithm       AlgorithmType\n\tComment         string\n\tFromKey         model.CIStr\n\tToKey           model.CIStr\n\tPartition       *PartitionOptions\n\tPartitionNames  []model.CIStr\n\tPartDefinitions []*PartitionDefinition\n\tWithValidation  bool\n\tNum             uint64\n\tVisibility      IndexVisibility\n\tTiFlashReplica  *TiFlashReplicaSpec\n}\n\ntype TiFlashReplicaSpec struct {\n\tCount  uint64\n\tLabels []string\n}\n\n// AlterOrderItem represents an item in order by at alter table stmt.\ntype AlterOrderItem struct {\n\tnode\n\tColumn *ColumnName\n\tDesc   bool\n}\n\n// Restore implements Node interface.\nfunc (n *AlterOrderItem) Restore(ctx *RestoreCtx) error {\n\tif err := n.Column.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore AlterOrderItem.Column\")\n\t}\n\tif n.Desc {\n\t\tctx.WriteKeyWord(\" DESC\")\n\t}\n\treturn nil\n}\n\n// Restore implements Node interface.\nfunc (n *AlterTableSpec) Restore(ctx *RestoreCtx) error {\n\tswitch n.Tp {\n\tcase AlterTableSetTiFlashReplica:\n\t\tctx.WriteKeyWord(\"SET TIFLASH REPLICA \")\n\t\tctx.WritePlainf(\"%d\", n.TiFlashReplica.Count)\n\t\tif len(n.TiFlashReplica.Labels) == 0 {\n\t\t\tbreak\n\t\t}\n\t\tctx.WriteKeyWord(\" LOCATION LABELS \")\n\t\tfor i, v := range n.TiFlashReplica.Labels {\n\t\t\tif i > 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tctx.WriteString(v)\n\t\t}\n\tcase AlterTableOption:\n\t\tswitch {\n\t\tcase len(n.Options) == 2 && n.Options[0].Tp == TableOptionCharset && n.Options[1].Tp == TableOptionCollate:\n\t\t\tif n.Options[0].UintValue == TableOptionCharsetWithConvertTo {\n\t\t\t\tctx.WriteKeyWord(\"CONVERT TO \")\n\t\t\t}\n\t\t\tctx.WriteKeyWord(\"CHARACTER SET \")\n\t\t\tif n.Options[0].Default {\n\t\t\t\tctx.WriteKeyWord(\"DEFAULT\")\n\t\t\t} else {\n\t\t\t\tctx.WriteKeyWord(n.Options[0].StrValue)\n\t\t\t}\n\t\t\tctx.WriteKeyWord(\" COLLATE \")\n\t\t\tctx.WriteKeyWord(n.Options[1].StrValue)\n\t\tcase n.Options[0].Tp == TableOptionCharset && n.Options[0].Default:\n\t\t\tif n.Options[0].UintValue == TableOptionCharsetWithConvertTo {\n\t\t\t\tctx.WriteKeyWord(\"CONVERT TO \")\n\t\t\t}\n\t\t\tctx.WriteKeyWord(\"CHARACTER SET DEFAULT\")\n\t\tdefault:\n\t\t\tfor i, opt := range n.Options {\n\t\t\t\tif i != 0 {\n\t\t\t\t\tctx.WritePlain(\", \")\n\t\t\t\t}\n\t\t\t\tif err := opt.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterTableSpec.Options[%d]\", i)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase AlterTableAddColumns:\n\t\tctx.WriteKeyWord(\"ADD COLUMN \")\n\t\tif n.IfNotExists {\n\t\t\tctx.WriteKeyWord(\"IF NOT EXISTS \")\n\t\t}\n\t\tif n.Position != nil && len(n.NewColumns) == 1 {\n\t\t\tif err := n.NewColumns[0].Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterTableSpec.NewColumns[%d]\", 0)\n\t\t\t}\n\t\t\tif n.Position.Tp != ColumnPositionNone {\n\t\t\t\tctx.WritePlain(\" \")\n\t\t\t}\n\t\t\tif err := n.Position.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.Position\")\n\t\t\t}\n\t\t} else {\n\t\t\tlenCols := len(n.NewColumns)\n\t\t\tctx.WritePlain(\"(\")\n\t\t\tfor i, col := range n.NewColumns {\n\t\t\t\tif i != 0 {\n\t\t\t\t\tctx.WritePlain(\", \")\n\t\t\t\t}\n\t\t\t\tif err := col.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterTableSpec.NewColumns[%d]\", i)\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor i, constraint := range n.NewConstraints {\n\t\t\t\tif i != 0 || lenCols >= 1 {\n\t\t\t\t\tctx.WritePlain(\", \")\n\t\t\t\t}\n\t\t\t\tif err := constraint.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterTableSpec.NewConstraints[%d]\", i)\n\t\t\t\t}\n\t\t\t}\n\t\t\tctx.WritePlain(\")\")\n\t\t}\n\tcase AlterTableAddConstraint:\n\t\tctx.WriteKeyWord(\"ADD \")\n\t\tif err := n.Constraint.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.Constraint\")\n\t\t}\n\tcase AlterTableDropColumn:\n\t\tctx.WriteKeyWord(\"DROP COLUMN \")\n\t\tif n.IfExists {\n\t\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t\t}\n\t\tif err := n.OldColumnName.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.OldColumnName\")\n\t\t}\n\t// TODO: RestrictOrCascadeOpt not support\n\tcase AlterTableDropPrimaryKey:\n\t\tctx.WriteKeyWord(\"DROP PRIMARY KEY\")\n\tcase AlterTableDropIndex:\n\t\tctx.WriteKeyWord(\"DROP INDEX \")\n\t\tif n.IfExists {\n\t\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t\t}\n\t\tctx.WriteName(n.Name)\n\tcase AlterTableDropForeignKey:\n\t\tctx.WriteKeyWord(\"DROP FOREIGN KEY \")\n\t\tif n.IfExists {\n\t\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t\t}\n\t\tctx.WriteName(n.Name)\n\tcase AlterTableModifyColumn:\n\t\tctx.WriteKeyWord(\"MODIFY COLUMN \")\n\t\tif n.IfExists {\n\t\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t\t}\n\t\tif err := n.NewColumns[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.NewColumns[0]\")\n\t\t}\n\t\tif n.Position.Tp != ColumnPositionNone {\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tif err := n.Position.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.Position\")\n\t\t}\n\tcase AlterTableChangeColumn:\n\t\tctx.WriteKeyWord(\"CHANGE COLUMN \")\n\t\tif n.IfExists {\n\t\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t\t}\n\t\tif err := n.OldColumnName.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.OldColumnName\")\n\t\t}\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.NewColumns[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.NewColumns[0]\")\n\t\t}\n\t\tif n.Position.Tp != ColumnPositionNone {\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tif err := n.Position.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.Position\")\n\t\t}\n\tcase AlterTableRenameColumn:\n\t\tctx.WriteKeyWord(\"RENAME COLUMN \")\n\t\tif err := n.OldColumnName.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.OldColumnName\")\n\t\t}\n\t\tctx.WriteKeyWord(\" TO \")\n\t\tif err := n.NewColumnName.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.NewColumnName\")\n\t\t}\n\tcase AlterTableRenameTable:\n\t\tctx.WriteKeyWord(\"RENAME AS \")\n\t\tif err := n.NewTable.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.NewTable\")\n\t\t}\n\tcase AlterTableAlterColumn:\n\t\tctx.WriteKeyWord(\"ALTER COLUMN \")\n\t\tif err := n.NewColumns[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.NewColumns[0]\")\n\t\t}\n\t\tif len(n.NewColumns[0].Options) == 1 {\n\t\t\tctx.WriteKeyWord(\"SET DEFAULT \")\n\t\t\texpr := n.NewColumns[0].Options[0].Expr\n\t\t\tif valueExpr, ok := expr.(ValueExpr); ok {\n\t\t\t\tif err := valueExpr.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.NewColumns[0].Options[0].Expr\")\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tctx.WritePlain(\"(\")\n\t\t\t\tif err := expr.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.NewColumns[0].Options[0].Expr\")\n\t\t\t\t}\n\t\t\t\tctx.WritePlain(\")\")\n\t\t\t}\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\" DROP DEFAULT\")\n\t\t}\n\tcase AlterTableLock:\n\t\tctx.WriteKeyWord(\"LOCK \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteKeyWord(n.LockType.String())\n\tcase AlterTableOrderByColumns:\n\t\tctx.WriteKeyWord(\"ORDER BY \")\n\t\tfor i, alterOrderItem := range n.OrderByList {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := alterOrderItem.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterTableSpec.OrderByList[%d]\", i)\n\t\t\t}\n\t\t}\n\tcase AlterTableAlgorithm:\n\t\tctx.WriteKeyWord(\"ALGORITHM \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteKeyWord(n.Algorithm.String())\n\tcase AlterTableRenameIndex:\n\t\tctx.WriteKeyWord(\"RENAME INDEX \")\n\t\tctx.WriteName(n.FromKey.O)\n\t\tctx.WriteKeyWord(\" TO \")\n\t\tctx.WriteName(n.ToKey.O)\n\tcase AlterTableForce:\n\t\t// TODO: not support\n\t\tctx.WriteKeyWord(\"FORCE\")\n\t\tctx.WritePlain(\" /* AlterTableForce is not supported */ \")\n\tcase AlterTableAddPartitions:\n\t\tctx.WriteKeyWord(\"ADD PARTITION\")\n\t\tif n.IfNotExists {\n\t\t\tctx.WriteKeyWord(\" IF NOT EXISTS\")\n\t\t}\n\t\tif n.NoWriteToBinlog {\n\t\t\tctx.WriteKeyWord(\" NO_WRITE_TO_BINLOG\")\n\t\t}\n\t\tif n.PartDefinitions != nil {\n\t\t\tctx.WritePlain(\" (\")\n\t\t\tfor i, def := range n.PartDefinitions {\n\t\t\t\tif i != 0 {\n\t\t\t\t\tctx.WritePlain(\", \")\n\t\t\t\t}\n\t\t\t\tif err := def.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterTableSpec.PartDefinitions[%d]\", i)\n\t\t\t\t}\n\t\t\t}\n\t\t\tctx.WritePlain(\")\")\n\t\t} else if n.Num != 0 {\n\t\t\tctx.WriteKeyWord(\" PARTITIONS \")\n\t\t\tctx.WritePlainf(\"%d\", n.Num)\n\t\t}\n\tcase AlterTableCoalescePartitions:\n\t\tctx.WriteKeyWord(\"COALESCE PARTITION \")\n\t\tif n.NoWriteToBinlog {\n\t\t\tctx.WriteKeyWord(\"NO_WRITE_TO_BINLOG \")\n\t\t}\n\t\tctx.WritePlainf(\"%d\", n.Num)\n\tcase AlterTableDropPartition:\n\t\tctx.WriteKeyWord(\"DROP PARTITION \")\n\t\tif n.IfExists {\n\t\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t\t}\n\t\tfor i, name := range n.PartitionNames {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tctx.WriteName(name.O)\n\t\t}\n\tcase AlterTableTruncatePartition:\n\t\tctx.WriteKeyWord(\"TRUNCATE PARTITION \")\n\t\tif n.OnAllPartitions {\n\t\t\tctx.WriteKeyWord(\"ALL\")\n\t\t\treturn nil\n\t\t}\n\t\tfor i, name := range n.PartitionNames {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tctx.WriteName(name.O)\n\t\t}\n\tcase AlterTableCheckPartitions:\n\t\tctx.WriteKeyWord(\"CHECK PARTITION \")\n\t\tif n.OnAllPartitions {\n\t\t\tctx.WriteKeyWord(\"ALL\")\n\t\t\treturn nil\n\t\t}\n\t\tfor i, name := range n.PartitionNames {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tctx.WriteName(name.O)\n\t\t}\n\tcase AlterTableOptimizePartition:\n\t\tctx.WriteKeyWord(\"OPTIMIZE PARTITION \")\n\t\tif n.NoWriteToBinlog {\n\t\t\tctx.WriteKeyWord(\"NO_WRITE_TO_BINLOG \")\n\t\t}\n\t\tif n.OnAllPartitions {\n\t\t\tctx.WriteKeyWord(\"ALL\")\n\t\t\treturn nil\n\t\t}\n\t\tfor i, name := range n.PartitionNames {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tctx.WriteName(name.O)\n\t\t}\n\tcase AlterTableRepairPartition:\n\t\tctx.WriteKeyWord(\"REPAIR PARTITION \")\n\t\tif n.NoWriteToBinlog {\n\t\t\tctx.WriteKeyWord(\"NO_WRITE_TO_BINLOG \")\n\t\t}\n\t\tif n.OnAllPartitions {\n\t\t\tctx.WriteKeyWord(\"ALL\")\n\t\t\treturn nil\n\t\t}\n\t\tfor i, name := range n.PartitionNames {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tctx.WriteName(name.O)\n\t\t}\n\tcase AlterTableImportPartitionTablespace:\n\t\tctx.WriteKeyWord(\"IMPORT PARTITION \")\n\t\tif n.OnAllPartitions {\n\t\t\tctx.WriteKeyWord(\"ALL\")\n\t\t} else {\n\t\t\tfor i, name := range n.PartitionNames {\n\t\t\t\tif i != 0 {\n\t\t\t\t\tctx.WritePlain(\",\")\n\t\t\t\t}\n\t\t\t\tctx.WriteName(name.O)\n\t\t\t}\n\t\t}\n\t\tctx.WriteKeyWord(\" TABLESPACE\")\n\tcase AlterTableDiscardPartitionTablespace:\n\t\tctx.WriteKeyWord(\"DISCARD PARTITION \")\n\t\tif n.OnAllPartitions {\n\t\t\tctx.WriteKeyWord(\"ALL\")\n\t\t} else {\n\t\t\tfor i, name := range n.PartitionNames {\n\t\t\t\tif i != 0 {\n\t\t\t\t\tctx.WritePlain(\",\")\n\t\t\t\t}\n\t\t\t\tctx.WriteName(name.O)\n\t\t\t}\n\t\t}\n\t\tctx.WriteKeyWord(\" TABLESPACE\")\n\tcase AlterTablePartition:\n\t\tif err := n.Partition.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableSpec.Partition\")\n\t\t}\n\tcase AlterTableEnableKeys:\n\t\tctx.WriteKeyWord(\"ENABLE KEYS\")\n\tcase AlterTableDisableKeys:\n\t\tctx.WriteKeyWord(\"DISABLE KEYS\")\n\tcase AlterTableRemovePartitioning:\n\t\tctx.WriteKeyWord(\"REMOVE PARTITIONING\")\n\tcase AlterTableWithValidation:\n\t\tctx.WriteKeyWord(\"WITH VALIDATION\")\n\tcase AlterTableWithoutValidation:\n\t\tctx.WriteKeyWord(\"WITHOUT VALIDATION\")\n\tcase AlterTableRebuildPartition:\n\t\tctx.WriteKeyWord(\"REBUILD PARTITION \")\n\t\tif n.NoWriteToBinlog {\n\t\t\tctx.WriteKeyWord(\"NO_WRITE_TO_BINLOG \")\n\t\t}\n\t\tif n.OnAllPartitions {\n\t\t\tctx.WriteKeyWord(\"ALL\")\n\t\t\treturn nil\n\t\t}\n\t\tfor i, name := range n.PartitionNames {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tctx.WriteName(name.O)\n\t\t}\n\tcase AlterTableReorganizePartition:\n\t\tctx.WriteKeyWord(\"REORGANIZE PARTITION\")\n\t\tif n.NoWriteToBinlog {\n\t\t\tctx.WriteKeyWord(\" NO_WRITE_TO_BINLOG\")\n\t\t}\n\t\tif n.OnAllPartitions {\n\t\t\treturn nil\n\t\t}\n\t\tfor i, name := range n.PartitionNames {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t} else {\n\t\t\t\tctx.WritePlain(\" \")\n\t\t\t}\n\t\t\tctx.WriteName(name.O)\n\t\t}\n\t\tctx.WriteKeyWord(\" INTO \")\n\t\tif n.PartDefinitions != nil {\n\t\t\tctx.WritePlain(\"(\")\n\t\t\tfor i, def := range n.PartDefinitions {\n\t\t\t\tif i != 0 {\n\t\t\t\t\tctx.WritePlain(\", \")\n\t\t\t\t}\n\t\t\t\tif err := def.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterTableSpec.PartDefinitions[%d]\", i)\n\t\t\t\t}\n\t\t\t}\n\t\t\tctx.WritePlain(\")\")\n\t\t}\n\tcase AlterTableExchangePartition:\n\t\tctx.WriteKeyWord(\"EXCHANGE PARTITION \")\n\t\tctx.WriteName(n.PartitionNames[0].O)\n\t\tctx.WriteKeyWord(\" WITH TABLE \")\n\t\tn.NewTable.Restore(ctx)\n\t\tif !n.WithValidation {\n\t\t\tctx.WriteKeyWord(\" WITHOUT VALIDATION\")\n\t\t}\n\tcase AlterTableSecondaryLoad:\n\t\tctx.WriteKeyWord(\"SECONDARY_LOAD\")\n\tcase AlterTableSecondaryUnload:\n\t\tctx.WriteKeyWord(\"SECONDARY_UNLOAD\")\n\tcase AlterTableAlterCheck:\n\t\tctx.WriteKeyWord(\"ALTER CHECK \")\n\t\tctx.WriteName(n.Constraint.Name)\n\t\tif n.Constraint.Enforced == false {\n\t\t\tctx.WriteKeyWord(\" NOT\")\n\t\t}\n\t\tctx.WriteKeyWord(\" ENFORCED\")\n\tcase AlterTableDropCheck:\n\t\tctx.WriteKeyWord(\"DROP CHECK \")\n\t\tctx.WriteName(n.Constraint.Name)\n\tcase AlterTableImportTablespace:\n\t\tctx.WriteKeyWord(\"IMPORT TABLESPACE\")\n\tcase AlterTableDiscardTablespace:\n\t\tctx.WriteKeyWord(\"DISCARD TABLESPACE\")\n\tcase AlterTableIndexInvisible:\n\t\tctx.WriteKeyWord(\"ALTER INDEX \")\n\t\tctx.WriteName(n.Name)\n\t\tswitch n.Visibility {\n\t\tcase IndexVisibilityVisible:\n\t\t\tctx.WriteKeyWord(\" VISIBLE\")\n\t\tcase IndexVisibilityInvisible:\n\t\t\tctx.WriteKeyWord(\" INVISIBLE\")\n\t\t}\n\tdefault:\n\t\t// TODO: not support\n\t\tctx.WritePlainf(\" /* AlterTableType(%d) is not supported */ \", n.Tp)\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *AlterTableSpec) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*AlterTableSpec)\n\tif n.Constraint != nil {\n\t\tnode, ok := n.Constraint.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Constraint = node.(*Constraint)\n\t}\n\tif n.NewTable != nil {\n\t\tnode, ok := n.NewTable.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.NewTable = node.(*TableName)\n\t}\n\tfor _, col := range n.NewColumns {\n\t\tnode, ok := col.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tcol = node.(*ColumnDef)\n\t}\n\tfor _, constraint := range n.NewConstraints {\n\t\tnode, ok := constraint.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tconstraint = node.(*Constraint)\n\t}\n\tif n.OldColumnName != nil {\n\t\tnode, ok := n.OldColumnName.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.OldColumnName = node.(*ColumnName)\n\t}\n\tif n.Position != nil {\n\t\tnode, ok := n.Position.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Position = node.(*ColumnPosition)\n\t}\n\treturn v.Leave(n)\n}\n\n// AlterTableStmt is a statement to change the structure of a table.\n// See https://dev.mysql.com/doc/refman/5.7/en/alter-table.html\ntype AlterTableStmt struct {\n\tddlNode\n\n\tTable *TableName\n\tSpecs []*AlterTableSpec\n}\n\n// Restore implements Node interface.\nfunc (n *AlterTableStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"ALTER TABLE \")\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore AlterTableStmt.Table\")\n\t}\n\tfor i, spec := range n.Specs {\n\t\tif i == 0 || spec.Tp == AlterTablePartition || spec.Tp == AlterTableRemovePartitioning || spec.Tp == AlterTableImportTablespace || spec.Tp == AlterTableDiscardTablespace {\n\t\t\tctx.WritePlain(\" \")\n\t\t} else {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := spec.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterTableStmt.Specs[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *AlterTableStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*AlterTableStmt)\n\tnode, ok := n.Table.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Table = node.(*TableName)\n\tfor i, val := range n.Specs {\n\t\tnode, ok = val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Specs[i] = node.(*AlterTableSpec)\n\t}\n\treturn v.Leave(n)\n}\n\n// TruncateTableStmt is a statement to empty a table completely.\n// See https://dev.mysql.com/doc/refman/5.7/en/truncate-table.html\ntype TruncateTableStmt struct {\n\tddlNode\n\n\tTable *TableName\n}\n\n// Restore implements Node interface.\nfunc (n *TruncateTableStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"TRUNCATE TABLE \")\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore TruncateTableStmt.Table\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *TruncateTableStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*TruncateTableStmt)\n\tnode, ok := n.Table.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Table = node.(*TableName)\n\treturn v.Leave(n)\n}\n\nvar (\n\tErrNoParts                              = terror.ClassDDL.NewStd(mysql.ErrNoParts)\n\tErrPartitionColumnList                  = terror.ClassDDL.NewStd(mysql.ErrPartitionColumnList)\n\tErrPartitionRequiresValues              = terror.ClassDDL.NewStd(mysql.ErrPartitionRequiresValues)\n\tErrPartitionsMustBeDefined              = terror.ClassDDL.NewStd(mysql.ErrPartitionsMustBeDefined)\n\tErrPartitionWrongNoPart                 = terror.ClassDDL.NewStd(mysql.ErrPartitionWrongNoPart)\n\tErrPartitionWrongNoSubpart              = terror.ClassDDL.NewStd(mysql.ErrPartitionWrongNoSubpart)\n\tErrPartitionWrongValues                 = terror.ClassDDL.NewStd(mysql.ErrPartitionWrongValues)\n\tErrRowSinglePartitionField              = terror.ClassDDL.NewStd(mysql.ErrRowSinglePartitionField)\n\tErrSubpartition                         = terror.ClassDDL.NewStd(mysql.ErrSubpartition)\n\tErrSystemVersioningWrongPartitions      = terror.ClassDDL.NewStd(mysql.ErrSystemVersioningWrongPartitions)\n\tErrTooManyValues                        = terror.ClassDDL.NewStd(mysql.ErrTooManyValues)\n\tErrWrongPartitionTypeExpectedSystemTime = terror.ClassDDL.NewStd(mysql.ErrWrongPartitionTypeExpectedSystemTime)\n)\n\ntype SubPartitionDefinition struct {\n\tName    model.CIStr\n\tOptions []*TableOption\n}\n\nfunc (spd *SubPartitionDefinition) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"SUBPARTITION \")\n\tctx.WriteName(spd.Name.O)\n\tfor i, opt := range spd.Options {\n\t\tctx.WritePlain(\" \")\n\t\tif err := opt.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore SubPartitionDefinition.Options[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\ntype PartitionDefinitionClause interface {\n\trestore(ctx *RestoreCtx) error\n\tacceptInPlace(v Visitor) bool\n\t// Validate checks if the clause is consistent with the given options.\n\t// `pt` can be 0 and `columns` can be -1 to skip checking the clause against\n\t// the partition type or number of columns in the expression list.\n\tValidate(pt model.PartitionType, columns int) error\n}\n\ntype PartitionDefinitionClauseNone struct{}\n\nfunc (n *PartitionDefinitionClauseNone) restore(ctx *RestoreCtx) error {\n\treturn nil\n}\n\nfunc (n *PartitionDefinitionClauseNone) acceptInPlace(v Visitor) bool {\n\treturn true\n}\n\nfunc (n *PartitionDefinitionClauseNone) Validate(pt model.PartitionType, columns int) error {\n\tswitch pt {\n\tcase 0:\n\tcase model.PartitionTypeRange:\n\t\treturn ErrPartitionRequiresValues.GenWithStackByArgs(\"RANGE\", \"LESS THAN\")\n\tcase model.PartitionTypeList:\n\t\treturn ErrPartitionRequiresValues.GenWithStackByArgs(\"LIST\", \"IN\")\n\tcase model.PartitionTypeSystemTime:\n\t\treturn ErrSystemVersioningWrongPartitions\n\t}\n\treturn nil\n}\n\ntype PartitionDefinitionClauseLessThan struct {\n\tExprs []ExprNode\n}\n\nfunc (n *PartitionDefinitionClauseLessThan) restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\" VALUES LESS THAN \")\n\tctx.WritePlain(\"(\")\n\tfor i, expr := range n.Exprs {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore PartitionDefinitionClauseLessThan.Exprs[%d]\", i)\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\treturn nil\n}\n\nfunc (n *PartitionDefinitionClauseLessThan) acceptInPlace(v Visitor) bool {\n\tfor i, expr := range n.Exprs {\n\t\tnewExpr, ok := expr.Accept(v)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\t\tn.Exprs[i] = newExpr.(ExprNode)\n\t}\n\treturn true\n}\n\nfunc (n *PartitionDefinitionClauseLessThan) Validate(pt model.PartitionType, columns int) error {\n\tswitch pt {\n\tcase model.PartitionTypeRange, 0:\n\tdefault:\n\t\treturn ErrPartitionWrongValues.GenWithStackByArgs(\"RANGE\", \"LESS THAN\")\n\t}\n\n\tswitch {\n\tcase columns == 0 && len(n.Exprs) != 1:\n\t\treturn ErrTooManyValues.GenWithStackByArgs(\"RANGE\")\n\tcase columns > 0 && len(n.Exprs) != columns:\n\t\treturn ErrPartitionColumnList\n\t}\n\treturn nil\n}\n\ntype PartitionDefinitionClauseIn struct {\n\tValues [][]ExprNode\n}\n\nfunc (n *PartitionDefinitionClauseIn) restore(ctx *RestoreCtx) error {\n\t// we special-case an empty list of values to mean MariaDB's \"DEFAULT\" clause.\n\tif len(n.Values) == 0 {\n\t\tctx.WriteKeyWord(\" DEFAULT\")\n\t\treturn nil\n\t}\n\n\tctx.WriteKeyWord(\" VALUES IN \")\n\tctx.WritePlain(\"(\")\n\tfor i, valList := range n.Values {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif len(valList) == 1 {\n\t\t\tif err := valList[0].Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore PartitionDefinitionClauseIn.Values[%d][0]\", i)\n\t\t\t}\n\t\t} else {\n\t\t\tctx.WritePlain(\"(\")\n\t\t\tfor j, val := range valList {\n\t\t\t\tif j != 0 {\n\t\t\t\t\tctx.WritePlain(\", \")\n\t\t\t\t}\n\t\t\t\tif err := val.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore PartitionDefinitionClauseIn.Values[%d][%d]\", i, j)\n\t\t\t\t}\n\t\t\t}\n\t\t\tctx.WritePlain(\")\")\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\treturn nil\n}\n\nfunc (n *PartitionDefinitionClauseIn) acceptInPlace(v Visitor) bool {\n\tfor _, valList := range n.Values {\n\t\tfor j, val := range valList {\n\t\t\tnewVal, ok := val.Accept(v)\n\t\t\tif !ok {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tvalList[j] = newVal.(ExprNode)\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (n *PartitionDefinitionClauseIn) Validate(pt model.PartitionType, columns int) error {\n\tswitch pt {\n\tcase model.PartitionTypeList, 0:\n\tdefault:\n\t\treturn ErrPartitionWrongValues.GenWithStackByArgs(\"LIST\", \"IN\")\n\t}\n\n\tif len(n.Values) == 0 {\n\t\treturn nil\n\t}\n\n\texpectedColCount := len(n.Values[0])\n\tfor _, val := range n.Values[1:] {\n\t\tif len(val) != expectedColCount {\n\t\t\treturn ErrPartitionColumnList\n\t\t}\n\t}\n\n\tswitch {\n\tcase columns == 0 && expectedColCount != 1:\n\t\treturn ErrRowSinglePartitionField\n\tcase columns > 0 && expectedColCount != columns:\n\t\treturn ErrPartitionColumnList\n\t}\n\treturn nil\n}\n\ntype PartitionDefinitionClauseHistory struct {\n\tCurrent bool\n}\n\nfunc (n *PartitionDefinitionClauseHistory) restore(ctx *RestoreCtx) error {\n\tif n.Current {\n\t\tctx.WriteKeyWord(\" CURRENT\")\n\t} else {\n\t\tctx.WriteKeyWord(\" HISTORY\")\n\t}\n\treturn nil\n}\n\nfunc (n *PartitionDefinitionClauseHistory) acceptInPlace(v Visitor) bool {\n\treturn true\n}\n\nfunc (n *PartitionDefinitionClauseHistory) Validate(pt model.PartitionType, columns int) error {\n\tswitch pt {\n\tcase 0, model.PartitionTypeSystemTime:\n\tdefault:\n\t\treturn ErrWrongPartitionTypeExpectedSystemTime\n\t}\n\n\treturn nil\n}\n\n// PartitionDefinition defines a single partition.\ntype PartitionDefinition struct {\n\tName    model.CIStr\n\tClause  PartitionDefinitionClause\n\tOptions []*TableOption\n\tSub     []*SubPartitionDefinition\n}\n\n// Comment returns the comment option given to this definition.\n// The second return value indicates if the comment option exists.\nfunc (n *PartitionDefinition) Comment() (string, bool) {\n\tfor _, opt := range n.Options {\n\t\tif opt.Tp == TableOptionComment {\n\t\t\treturn opt.StrValue, true\n\t\t}\n\t}\n\treturn \"\", false\n}\n\nfunc (n *PartitionDefinition) acceptInPlace(v Visitor) bool {\n\treturn n.Clause.acceptInPlace(v)\n}\n\n// Restore implements Node interface.\nfunc (n *PartitionDefinition) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"PARTITION \")\n\tctx.WriteName(n.Name.O)\n\n\tif err := n.Clause.restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore PartitionDefinition.Clause\")\n\t}\n\n\tfor i, opt := range n.Options {\n\t\tctx.WritePlain(\" \")\n\t\tif err := opt.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore PartitionDefinition.Options[%d]\", i)\n\t\t}\n\t}\n\n\tif len(n.Sub) > 0 {\n\t\tctx.WritePlain(\" (\")\n\t\tfor i, spd := range n.Sub {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := spd.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore PartitionDefinition.Sub[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\n\treturn nil\n}\n\n// PartitionMethod describes how partitions or subpartitions are constructed.\ntype PartitionMethod struct {\n\t// Tp is the type of the partition function\n\tTp model.PartitionType\n\t// Linear is a modifier to the HASH and KEY type for choosing a different\n\t// algorithm\n\tLinear bool\n\t// Expr is an expression used as argument of HASH, RANGE, LIST and\n\t// SYSTEM_TIME types\n\tExpr ExprNode\n\t// ColumnNames is a list of column names used as argument of KEY,\n\t// RANGE COLUMNS and LIST COLUMNS types\n\tColumnNames []*ColumnName\n\t// Unit is a time unit used as argument of SYSTEM_TIME type\n\tUnit TimeUnitType\n\t// Limit is a row count used as argument of the SYSTEM_TIME type\n\tLimit uint64\n\n\t// Num is the number of (sub)partitions required by the method.\n\tNum uint64\n}\n\n// Restore implements the Node interface\nfunc (n *PartitionMethod) Restore(ctx *RestoreCtx) error {\n\tif n.Linear {\n\t\tctx.WriteKeyWord(\"LINEAR \")\n\t}\n\tctx.WriteKeyWord(n.Tp.String())\n\n\tswitch {\n\tcase n.Tp == model.PartitionTypeSystemTime:\n\t\tif n.Expr != nil && n.Unit != TimeUnitInvalid {\n\t\t\tctx.WriteKeyWord(\" INTERVAL \")\n\t\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore PartitionMethod.Expr\")\n\t\t\t}\n\t\t\tctx.WritePlain(\" \")\n\t\t\tctx.WriteKeyWord(n.Unit.String())\n\t\t}\n\n\tcase n.Expr != nil:\n\t\tctx.WritePlain(\" (\")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore PartitionMethod.Expr\")\n\t\t}\n\t\tctx.WritePlain(\")\")\n\n\tdefault:\n\t\tif n.Tp == model.PartitionTypeRange || n.Tp == model.PartitionTypeList {\n\t\t\tctx.WriteKeyWord(\" COLUMNS\")\n\t\t}\n\t\tctx.WritePlain(\" (\")\n\t\tfor i, col := range n.ColumnNames {\n\t\t\tif i > 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := col.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while splicing PartitionMethod.ColumnName[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\n\tif n.Limit > 0 {\n\t\tctx.WriteKeyWord(\" LIMIT \")\n\t\tctx.WritePlainf(\"%d\", n.Limit)\n\t}\n\n\treturn nil\n}\n\n// acceptInPlace is like Node.Accept but does not allow replacing the node itself.\nfunc (n *PartitionMethod) acceptInPlace(v Visitor) bool {\n\tif n.Expr != nil {\n\t\texpr, ok := n.Expr.Accept(v)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\t\tn.Expr = expr.(ExprNode)\n\t}\n\tfor i, colName := range n.ColumnNames {\n\t\tnewColName, ok := colName.Accept(v)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\t\tn.ColumnNames[i] = newColName.(*ColumnName)\n\t}\n\treturn true\n}\n\n// PartitionOptions specifies the partition options.\ntype PartitionOptions struct {\n\tnode\n\tPartitionMethod\n\tSub         *PartitionMethod\n\tDefinitions []*PartitionDefinition\n}\n\n// Validate checks if the partition is well-formed.\nfunc (n *PartitionOptions) Validate() error {\n\t// if both a partition list and the partition numbers are specified, their values must match\n\tif n.Num != 0 && len(n.Definitions) != 0 && n.Num != uint64(len(n.Definitions)) {\n\t\treturn ErrPartitionWrongNoPart\n\t}\n\t// now check the subpartition count\n\tif len(n.Definitions) > 0 {\n\t\t// ensure the subpartition count for every partitions are the same\n\t\t// then normalize n.Num and n.Sub.Num so equality comparison works.\n\t\tn.Num = uint64(len(n.Definitions))\n\n\t\tsubDefCount := len(n.Definitions[0].Sub)\n\t\tfor _, pd := range n.Definitions[1:] {\n\t\t\tif len(pd.Sub) != subDefCount {\n\t\t\t\treturn ErrPartitionWrongNoSubpart\n\t\t\t}\n\t\t}\n\t\tif n.Sub != nil {\n\t\t\tif n.Sub.Num != 0 && subDefCount != 0 && n.Sub.Num != uint64(subDefCount) {\n\t\t\t\treturn ErrPartitionWrongNoSubpart\n\t\t\t}\n\t\t\tif subDefCount != 0 {\n\t\t\t\tn.Sub.Num = uint64(subDefCount)\n\t\t\t}\n\t\t} else if subDefCount != 0 {\n\t\t\treturn ErrSubpartition\n\t\t}\n\t}\n\n\tswitch n.Tp {\n\tcase model.PartitionTypeHash, model.PartitionTypeKey:\n\t\tif n.Num == 0 {\n\t\t\tn.Num = 1\n\t\t}\n\tcase model.PartitionTypeRange, model.PartitionTypeList:\n\t\tif len(n.Definitions) == 0 {\n\t\t\treturn ErrPartitionsMustBeDefined.GenWithStackByArgs(n.Tp)\n\t\t}\n\tcase model.PartitionTypeSystemTime:\n\t\tif len(n.Definitions) < 2 {\n\t\t\treturn ErrSystemVersioningWrongPartitions\n\t\t}\n\t}\n\n\tfor _, pd := range n.Definitions {\n\t\t// ensure the partition definition types match the methods,\n\t\t// e.g. RANGE partitions only allows VALUES LESS THAN\n\t\tif err := pd.Clause.Validate(n.Tp, len(n.ColumnNames)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (n *PartitionOptions) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"PARTITION BY \")\n\tif err := n.PartitionMethod.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore PartitionOptions.PartitionMethod\")\n\t}\n\n\tif n.Num > 0 && len(n.Definitions) == 0 {\n\t\tctx.WriteKeyWord(\" PARTITIONS \")\n\t\tctx.WritePlainf(\"%d\", n.Num)\n\t}\n\n\tif n.Sub != nil {\n\t\tctx.WriteKeyWord(\" SUBPARTITION BY \")\n\t\tif err := n.Sub.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore PartitionOptions.Sub\")\n\t\t}\n\t\tif n.Sub.Num > 0 {\n\t\t\tctx.WriteKeyWord(\" SUBPARTITIONS \")\n\t\t\tctx.WritePlainf(\"%d\", n.Sub.Num)\n\t\t}\n\t}\n\n\tif len(n.Definitions) > 0 {\n\t\tctx.WritePlain(\" (\")\n\t\tfor i, def := range n.Definitions {\n\t\t\tif i > 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := def.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore PartitionOptions.Definitions[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\n\treturn nil\n}\n\nfunc (n *PartitionOptions) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*PartitionOptions)\n\tif !n.PartitionMethod.acceptInPlace(v) {\n\t\treturn n, false\n\t}\n\tif n.Sub != nil && !n.Sub.acceptInPlace(v) {\n\t\treturn n, false\n\t}\n\tfor _, def := range n.Definitions {\n\t\tif !def.acceptInPlace(v) {\n\t\t\treturn n, false\n\t\t}\n\t}\n\treturn v.Leave(n)\n}\n\n// RecoverTableStmt is a statement to recover dropped table.\ntype RecoverTableStmt struct {\n\tddlNode\n\n\tJobID  int64\n\tTable  *TableName\n\tJobNum int64\n}\n\n// Restore implements Node interface.\nfunc (n *RecoverTableStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"RECOVER TABLE \")\n\tif n.JobID != 0 {\n\t\tctx.WriteKeyWord(\"BY JOB \")\n\t\tctx.WritePlainf(\"%d\", n.JobID)\n\t} else {\n\t\tif err := n.Table.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing RecoverTableStmt Table\")\n\t\t}\n\t\tif n.JobNum > 0 {\n\t\t\tctx.WritePlainf(\" %d\", n.JobNum)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *RecoverTableStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*RecoverTableStmt)\n\tif n.Table != nil {\n\t\tnode, ok := n.Table.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Table = node.(*TableName)\n\t}\n\treturn v.Leave(n)\n}\n\n// FlashBackTableStmt is a statement to restore a dropped/truncate table.\ntype FlashBackTableStmt struct {\n\tddlNode\n\n\tTable     *TableName\n\tTimestamp ValueExpr\n\tNewName   string\n}\n\n// Restore implements Node interface.\nfunc (n *FlashBackTableStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"FLASHBACK TABLE \")\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while splicing RecoverTableStmt Table\")\n\t}\n\tctx.WriteKeyWord(\" UNTIL TIMESTAMP \")\n\tif err := n.Timestamp.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while splicing FlashBackTableStmt Table\")\n\t}\n\tif len(n.NewName) > 0 {\n\t\tctx.WriteKeyWord(\" TO \")\n\t\tctx.WriteName(n.NewName)\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *FlashBackTableStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*FlashBackTableStmt)\n\tif n.Table != nil {\n\t\tnode, ok := n.Table.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Table = node.(*TableName)\n\t}\n\treturn v.Leave(n)\n}\n"
  },
  {
    "path": "pkg/parser/ast/ddl_test.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast_test\n\nimport (\n\t. \"github.com/pingcap/check\"\n\n\t. \"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\nvar _ = Suite(&testDDLSuite{})\n\ntype testDDLSuite struct {\n}\n\nfunc (ts *testDDLSuite) TestDDLVisitorCover(c *C) {\n\tce := &checkExpr{}\n\tconstraint := &Constraint{Keys: []*IndexPartSpecification{{Column: &ColumnName{}}, {Column: &ColumnName{}}}, Refer: &ReferenceDef{}, Option: &IndexOption{}}\n\n\talterTableSpec := &AlterTableSpec{Constraint: constraint, Options: []*TableOption{{}}, NewTable: &TableName{}, NewColumns: []*ColumnDef{{Name: &ColumnName{}}}, OldColumnName: &ColumnName{}, Position: &ColumnPosition{RelativeColumn: &ColumnName{}}}\n\n\tstmts := []struct {\n\t\tnode             Node\n\t\texpectedEnterCnt int\n\t\texpectedLeaveCnt int\n\t}{\n\t\t{&CreateDatabaseStmt{}, 0, 0},\n\t\t{&AlterDatabaseStmt{}, 0, 0},\n\t\t{&DropDatabaseStmt{}, 0, 0},\n\t\t{&DropIndexStmt{Table: &TableName{}}, 0, 0},\n\t\t{&DropTableStmt{Tables: []*TableName{{}, {}}}, 0, 0},\n\t\t{&RenameTableStmt{OldTable: &TableName{}, NewTable: &TableName{}}, 0, 0},\n\t\t{&TruncateTableStmt{Table: &TableName{}}, 0, 0},\n\n\t\t// TODO: cover children\n\t\t{&AlterTableStmt{Table: &TableName{}, Specs: []*AlterTableSpec{alterTableSpec}}, 0, 0},\n\t\t{&CreateIndexStmt{Table: &TableName{}}, 0, 0},\n\t\t{&CreateTableStmt{Table: &TableName{}, ReferTable: &TableName{}}, 0, 0},\n\t\t{&CreateViewStmt{ViewName: &TableName{}, Select: &SelectStmt{}}, 0, 0},\n\t\t{&AlterTableSpec{}, 0, 0},\n\t\t{&ColumnDef{Name: &ColumnName{}, Options: []*ColumnOption{{Expr: ce}}}, 1, 1},\n\t\t{&ColumnOption{Expr: ce}, 1, 1},\n\t\t{&ColumnPosition{RelativeColumn: &ColumnName{}}, 0, 0},\n\t\t{&Constraint{Keys: []*IndexPartSpecification{{Column: &ColumnName{}}, {Column: &ColumnName{}}}, Refer: &ReferenceDef{}, Option: &IndexOption{}}, 0, 0},\n\t\t{&IndexPartSpecification{Column: &ColumnName{}}, 0, 0},\n\t\t{&ReferenceDef{Table: &TableName{}, IndexPartSpecifications: []*IndexPartSpecification{{Column: &ColumnName{}}, {Column: &ColumnName{}}}, OnDelete: &OnDeleteOpt{}, OnUpdate: &OnUpdateOpt{}}, 0, 0},\n\t\t{&AlterTableSpec{NewConstraints: []*Constraint{constraint, constraint}}, 0, 0},\n\t\t{&AlterTableSpec{NewConstraints: []*Constraint{constraint}, NewColumns: []*ColumnDef{{Name: &ColumnName{}}}}, 0, 0},\n\t}\n\n\tfor _, v := range stmts {\n\t\tce.reset()\n\t\tv.node.Accept(checkVisitor{})\n\t\tc.Check(ce.enterCnt, Equals, v.expectedEnterCnt)\n\t\tc.Check(ce.leaveCnt, Equals, v.expectedLeaveCnt)\n\t\tv.node.Accept(visitor1{})\n\t}\n}\n\nfunc (ts *testDDLSuite) TestDDLIndexColNameRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"(a + 1)\", \"(`a`+1)\"},\n\t\t{\"(1 * 1 + (1 + 1))\", \"(1*1+(1+1))\"},\n\t\t{\"((1 * 1 + (1 + 1)))\", \"((1*1+(1+1)))\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*CreateIndexStmt).IndexPartSpecifications[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"CREATE INDEX idx ON t (%s) USING HASH\", extractNodeFunc)\n}\n\nfunc (ts *testDDLSuite) TestDDLIndexExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"world\", \"`world`\"},\n\t\t{\"world(2)\", \"`world`(2)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*CreateIndexStmt).IndexPartSpecifications[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"CREATE INDEX idx ON t (%s) USING HASH\", extractNodeFunc)\n}\n\n// func (ts *testDDLSuite) TestDDLOnDeleteRestore(c *C) {\n// \ttestCases := []NodeRestoreTestCase{\n// \t\t{\"on delete restrict\", \"ON DELETE RESTRICT\"},\n// \t\t{\"on delete CASCADE\", \"ON DELETE CASCADE\"},\n// \t\t{\"on delete SET NULL\", \"ON DELETE SET NULL\"},\n// \t\t{\"on delete no action\", \"ON DELETE NO ACTION\"},\n// \t}\n// \textractNodeFunc := func(node Node) Node {\n// \t\treturn node.(*CreateTableStmt).Constraints[1].Refer.OnDelete\n// \t}\n// \tRunNodeRestoreTest(c, testCases, \"CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) %s)\", extractNodeFunc)\n// \tRunNodeRestoreTest(c, testCases, \"CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) on update CASCADE %s)\", extractNodeFunc)\n// \tRunNodeRestoreTest(c, testCases, \"CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) %s on update CASCADE)\", extractNodeFunc)\n// }\n\n// func (ts *testDDLSuite) TestDDLOnUpdateRestore(c *C) {\n// \ttestCases := []NodeRestoreTestCase{\n// \t\t{\"ON UPDATE RESTRICT\", \"ON UPDATE RESTRICT\"},\n// \t\t{\"on update CASCADE\", \"ON UPDATE CASCADE\"},\n// \t\t{\"on update SET NULL\", \"ON UPDATE SET NULL\"},\n// \t\t{\"on update no action\", \"ON UPDATE NO ACTION\"},\n// \t}\n// \textractNodeFunc := func(node Node) Node {\n// \t\treturn node.(*CreateTableStmt).Constraints[1].Refer.OnUpdate\n// \t}\n// \tRunNodeRestoreTest(c, testCases, \"CREATE TABLE child ( id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE %s )\", extractNodeFunc)\n// \tRunNodeRestoreTest(c, testCases, \"CREATE TABLE child ( id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) %s ON DELETE CASCADE)\", extractNodeFunc)\n// \tRunNodeRestoreTest(c, testCases, \"CREATE TABLE child ( id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id)  %s )\", extractNodeFunc)\n// }\n\nfunc (ts *testDDLSuite) TestDDLIndexOption(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"key_block_size=16\", \"KEY_BLOCK_SIZE=16\"},\n\t\t{\"USING HASH\", \"USING HASH\"},\n\t\t{\"comment 'hello'\", \"COMMENT 'hello'\"},\n\t\t{\"key_block_size=16 USING HASH\", \"KEY_BLOCK_SIZE=16 USING HASH\"},\n\t\t{\"USING HASH KEY_BLOCK_SIZE=16\", \"KEY_BLOCK_SIZE=16 USING HASH\"},\n\t\t{\"USING HASH COMMENT 'foo'\", \"USING HASH COMMENT 'foo'\"},\n\t\t{\"COMMENT 'foo'\", \"COMMENT 'foo'\"},\n\t\t{\"key_block_size = 32 using hash comment 'hello'\", \"KEY_BLOCK_SIZE=32 USING HASH COMMENT 'hello'\"},\n\t\t{\"key_block_size=32 using btree comment 'hello'\", \"KEY_BLOCK_SIZE=32 USING BTREE COMMENT 'hello'\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*CreateIndexStmt).IndexOption\n\t}\n\tRunNodeRestoreTest(c, testCases, \"CREATE INDEX idx ON t (a) %s\", extractNodeFunc)\n}\n\nfunc (ts *testDDLSuite) TestTableToTableRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"t1 to t2\", \"`t1` TO `t2`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*RenameTableStmt).TableToTables[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"rename table %s\", extractNodeFunc)\n}\n\n// func (ts *testDDLSuite) TestDDLReferenceDefRestore(c *C) {\n// \ttestCases := []NodeRestoreTestCase{\n// \t\t{\"REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT\", \"REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT\"},\n// \t\t{\"REFERENCES parent(id) ON DELETE CASCADE\", \"REFERENCES `parent`(`id`) ON DELETE CASCADE\"},\n// \t\t{\"REFERENCES parent(id,hello) ON DELETE CASCADE\", \"REFERENCES `parent`(`id`, `hello`) ON DELETE CASCADE\"},\n// \t\t{\"REFERENCES parent(id,hello(12)) ON DELETE CASCADE\", \"REFERENCES `parent`(`id`, `hello`(12)) ON DELETE CASCADE\"},\n// \t\t{\"REFERENCES parent(id(8),hello(12)) ON DELETE CASCADE\", \"REFERENCES `parent`(`id`(8), `hello`(12)) ON DELETE CASCADE\"},\n// \t\t{\"REFERENCES parent(id)\", \"REFERENCES `parent`(`id`)\"},\n// \t\t{\"REFERENCES parent((id+1))\", \"REFERENCES `parent`((`id`+1))\"},\n// \t}\n// \textractNodeFunc := func(node Node) Node {\n// \t\treturn node.(*CreateTableStmt).Constraints[1].Refer\n// \t}\n// \tRunNodeRestoreTest(c, testCases, \"CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) %s)\", extractNodeFunc)\n// }\n\n// func (ts *testDDLSuite) TestDDLConstraintRestore(c *C) {\n// \ttestCases := []NodeRestoreTestCase{\n// \t\t{\"INDEX par_ind (parent_id)\", \"INDEX `par_ind`(`parent_id`)\"},\n// \t\t{\"INDEX par_ind (parent_id(6))\", \"INDEX `par_ind`(`parent_id`(6))\"},\n// \t\t{\"INDEX expr_ind ((id + parent_id))\", \"INDEX `expr_ind`((`id`+`parent_id`))\"},\n// \t\t{\"INDEX expr_ind ((lower(id)))\", \"INDEX `expr_ind`((LOWER(`id`)))\"},\n// \t\t{\"key par_ind (parent_id)\", \"INDEX `par_ind`(`parent_id`)\"},\n// \t\t{\"key expr_ind ((lower(id)))\", \"INDEX `expr_ind`((LOWER(`id`)))\"},\n// \t\t{\"unique par_ind (parent_id)\", \"UNIQUE `par_ind`(`parent_id`)\"},\n// \t\t{\"unique key par_ind (parent_id)\", \"UNIQUE `par_ind`(`parent_id`)\"},\n// \t\t{\"unique index par_ind (parent_id)\", \"UNIQUE `par_ind`(`parent_id`)\"},\n// \t\t{\"unique expr_ind ((id + parent_id))\", \"UNIQUE `expr_ind`((`id`+`parent_id`))\"},\n// \t\t{\"unique expr_ind ((lower(id)))\", \"UNIQUE `expr_ind`((LOWER(`id`)))\"},\n// \t\t{\"unique key expr_ind ((id + parent_id))\", \"UNIQUE `expr_ind`((`id`+`parent_id`))\"},\n// \t\t{\"unique key expr_ind ((lower(id)))\", \"UNIQUE `expr_ind`((LOWER(`id`)))\"},\n// \t\t{\"unique index expr_ind ((id + parent_id))\", \"UNIQUE `expr_ind`((`id`+`parent_id`))\"},\n// \t\t{\"unique index expr_ind ((lower(id)))\", \"UNIQUE `expr_ind`((LOWER(`id`)))\"},\n// \t\t{\"fulltext key full_id (parent_id)\", \"FULLTEXT `full_id`(`parent_id`)\"},\n// \t\t{\"fulltext INDEX full_id (parent_id)\", \"FULLTEXT `full_id`(`parent_id`)\"},\n// \t\t{\"fulltext INDEX full_id ((parent_id+1))\", \"FULLTEXT `full_id`((`parent_id`+1))\"},\n// \t\t{\"PRIMARY KEY (id)\", \"PRIMARY KEY(`id`)\"},\n// \t\t{\"PRIMARY KEY (id) key_block_size = 32 using hash comment 'hello'\", \"PRIMARY KEY(`id`) KEY_BLOCK_SIZE=32 USING HASH COMMENT 'hello'\"},\n// \t\t{\"PRIMARY KEY ((id+1))\", \"PRIMARY KEY((`id`+1))\"},\n// \t\t{\"CONSTRAINT FOREIGN KEY (parent_id(2),hello(4)) REFERENCES parent(id) ON DELETE CASCADE\", \"CONSTRAINT FOREIGN KEY (`parent_id`(2), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE\"},\n// \t\t{\"CONSTRAINT FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT\", \"CONSTRAINT FOREIGN KEY (`parent_id`) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT\"},\n// \t\t{\"CONSTRAINT FOREIGN KEY (parent_id(2),hello(4)) REFERENCES parent((id+1)) ON DELETE CASCADE\", \"CONSTRAINT FOREIGN KEY (`parent_id`(2), `hello`(4)) REFERENCES `parent`((`id`+1)) ON DELETE CASCADE\"},\n// \t\t{\"CONSTRAINT FOREIGN KEY (parent_id) REFERENCES parent((id+1)) ON DELETE CASCADE ON UPDATE RESTRICT\", \"CONSTRAINT FOREIGN KEY (`parent_id`) REFERENCES `parent`((`id`+1)) ON DELETE CASCADE ON UPDATE RESTRICT\"},\n// \t\t{\"CONSTRAINT fk_123 FOREIGN KEY (parent_id(2),hello(4)) REFERENCES parent(id) ON DELETE CASCADE\", \"CONSTRAINT `fk_123` FOREIGN KEY (`parent_id`(2), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE\"},\n// \t\t{\"CONSTRAINT fk_123 FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT\", \"CONSTRAINT `fk_123` FOREIGN KEY (`parent_id`) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT\"},\n// \t\t{\"CONSTRAINT fk_123 FOREIGN KEY ((parent_id+1),hello(4)) REFERENCES parent(id) ON DELETE CASCADE\", \"CONSTRAINT `fk_123` FOREIGN KEY ((`parent_id`+1), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE\"},\n// \t\t{\"CONSTRAINT fk_123 FOREIGN KEY ((parent_id+1)) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT\", \"CONSTRAINT `fk_123` FOREIGN KEY ((`parent_id`+1)) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT\"},\n// \t\t{\"FOREIGN KEY (parent_id(2),hello(4)) REFERENCES parent(id) ON DELETE CASCADE\", \"CONSTRAINT FOREIGN KEY (`parent_id`(2), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE\"},\n// \t\t{\"FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT\", \"CONSTRAINT FOREIGN KEY (`parent_id`) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT\"},\n// \t\t{\"FOREIGN KEY ((parent_id+1),hello(4)) REFERENCES parent(id) ON DELETE CASCADE\", \"CONSTRAINT FOREIGN KEY ((`parent_id`+1), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE\"},\n// \t\t{\"FOREIGN KEY ((parent_id+1)) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT\", \"CONSTRAINT FOREIGN KEY ((`parent_id`+1)) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT\"},\n// \t}\n// \textractNodeFunc := func(node Node) Node {\n// \t\treturn node.(*CreateTableStmt).Constraints[0]\n// \t}\n// \tRunNodeRestoreTest(c, testCases, \"CREATE TABLE child (id INT, parent_id INT, %s)\", extractNodeFunc)\n// }\n\nfunc (ts *testDDLSuite) TestDDLColumnOptionRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"primary key\", \"PRIMARY KEY\"},\n\t\t{\"not null\", \"NOT NULL\"},\n\t\t{\"null\", \"NULL\"},\n\t\t{\"auto_increment\", \"AUTO_INCREMENT\"},\n\t\t{\"DEFAULT 10\", \"DEFAULT 10\"},\n\t\t{\"DEFAULT '10'\", \"DEFAULT '10'\"},\n\t\t{\"DEFAULT 'hello'\", \"DEFAULT 'hello'\"},\n\t\t{\"DEFAULT 1.1\", \"DEFAULT 1.1\"},\n\t\t{\"DEFAULT NULL\", \"DEFAULT NULL\"},\n\t\t{\"DEFAULT ''\", \"DEFAULT ''\"},\n\t\t{\"DEFAULT TRUE\", \"DEFAULT TRUE\"},\n\t\t{\"DEFAULT FALSE\", \"DEFAULT FALSE\"},\n\t\t{\"UNIQUE KEY\", \"UNIQUE KEY\"},\n\t\t{\"on update CURRENT_TIMESTAMP\", \"ON UPDATE CURRENT_TIMESTAMP()\"},\n\t\t{\"comment 'hello'\", \"COMMENT 'hello'\"},\n\t\t{\"generated always as(id + 1)\", \"GENERATED ALWAYS AS(`id`+1) VIRTUAL\"},\n\t\t{\"generated always as(id + 1) virtual\", \"GENERATED ALWAYS AS(`id`+1) VIRTUAL\"},\n\t\t{\"generated always as(id + 1) stored\", \"GENERATED ALWAYS AS(`id`+1) STORED\"},\n\t\t{\"REFERENCES parent(id)\", \"REFERENCES `parent`(`id`)\"},\n\t\t{\"COLLATE utf8_bin\", \"COLLATE utf8_bin\"},\n\t\t{\"STORAGE DEFAULT\", \"STORAGE DEFAULT\"},\n\t\t{\"STORAGE DISK\", \"STORAGE DISK\"},\n\t\t{\"STORAGE MEMORY\", \"STORAGE MEMORY\"},\n\t\t{\"AUTO_RANDOM (3)\", \"AUTO_RANDOM(3)\"},\n\t\t{\"AUTO_RANDOM\", \"AUTO_RANDOM\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*CreateTableStmt).Cols[0].Options[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"CREATE TABLE child (id INT %s)\", extractNodeFunc)\n}\n\nfunc (ts *testDDLSuite) TestDDLColumnDefRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t// for type\n\t\t{\"id json\", \"`id` JSON\"},\n\t\t// {\"id time(5)\", \"`id` TIME(5)\"},\n\t\t// {\"id int(5) unsigned\", \"`id` INT(5) UNSIGNED\"},\n\t\t// {\"id int(5) UNSIGNED ZEROFILL\", \"`id` INT(5) UNSIGNED ZEROFILL\"},\n\t\t// {\"id float(12,3)\", \"`id` FLOAT(12,3)\"},\n\t\t{\"id float\", \"`id` FLOAT\"},\n\t\t// {\"id double(22,3)\", \"`id` DOUBLE(22,3)\"},\n\t\t{\"id double\", \"`id` DOUBLE\"},\n\t\t// {\"id tinyint(4)\", \"`id` TINYINT(4)\"},\n\t\t// {\"id smallint(6)\", \"`id` SMALLINT(6)\"},\n\t\t// {\"id mediumint(9)\", \"`id` MEDIUMINT(9)\"},\n\t\t// {\"id integer(11)\", \"`id` INT(11)\"},\n\t\t// {\"id bigint(20)\", \"`id` BIGINT(20)\"},\n\t\t{\"id DATE\", \"`id` DATE\"},\n\t\t{\"id DATETIME\", \"`id` DATETIME\"},\n\t\t// {\"id DECIMAL(4,2)\", \"`id` DECIMAL(4,2)\"},\n\t\t// {\"id char(1)\", \"`id` CHAR(1)\"},\n\t\t// {\"id varchar(10) BINARY\", \"`id` VARCHAR(10) BINARY\"},\n\t\t// {\"id binary(1)\", \"`id` BINARY(1)\"},\n\t\t// {\"id timestamp(2)\", \"`id` TIMESTAMP(2)\"},\n\t\t{\"id timestamp\", \"`id` TIMESTAMP\"},\n\t\t// {\"id datetime(2)\", \"`id` DATETIME(2)\"},\n\t\t{\"id date\", \"`id` DATE\"},\n\t\t{\"id year\", \"`id` YEAR\"},\n\t\t{\"id INT\", \"`id` INT\"},\n\t\t{\"id INT NULL\", \"`id` INT NULL\"},\n\t\t// {\"id enum('a','b')\", \"`id` ENUM('a','b')\"},\n\t\t// {\"id enum('''a''','''b''')\", \"`id` ENUM('''a''','''b''')\"},\n\t\t// {\"id enum('a\\\\nb','a\\\\tb','a\\\\rb')\", \"`id` ENUM('a\\nb','a\\tb','a\\rb')\"},\n\t\t// {\"id set('a','b')\", \"`id` SET('a','b')\"},\n\t\t// {\"id set('''a''','''b''')\", \"`id` SET('''a''','''b''')\"},\n\t\t// {\"id set('a\\\\nb','a''\t\\\\r\\\\nb','a\\\\rb')\", \"`id` SET('a\\nb','a''\t\\r\\nb','a\\rb')\"},\n\t\t// {`id set(\"a'\\nb\",\"a'b\\tc\")`, \"`id` SET('a''\\nb','a''b\\tc')\"},\n\t\t// {\"id TEXT CHARACTER SET UTF8 COLLATE UTF8_UNICODE_CI\", \"`id` TEXT CHARACTER SET UTF8 COLLATE utf8_unicode_ci\"},\n\t\t// {\"id text character set UTF8\", \"`id` TEXT CHARACTER SET UTF8\"},\n\t\t// {\"id text charset UTF8\", \"`id` TEXT CHARACTER SET UTF8\"},\n\t\t// {\"id varchar(50) collate UTF8MB4_CZECH_CI\", \"`id` VARCHAR(50) COLLATE utf8mb4_czech_ci\"},\n\t\t// {\"id varchar(50) collate utf8_bin\", \"`id` VARCHAR(50) COLLATE utf8_bin\"},\n\t\t// {\"id varchar(50) collate utf8_unicode_ci collate utf8mb4_bin\", \"`id` VARCHAR(50) COLLATE utf8_unicode_ci COLLATE utf8mb4_bin\"},\n\t\t// {\"c1 char(10) character set LATIN1 collate latin1_german1_ci\", \"`c1` CHAR(10) CHARACTER SET LATIN1 COLLATE latin1_german1_ci\"},\n\n\t\t// {\"id int(11) PRIMARY KEY\", \"`id` INT(11) PRIMARY KEY\"},\n\t\t// {\"id int(11) NOT NULL\", \"`id` INT(11) NOT NULL\"},\n\t\t// {\"id INT(11) NULL\", \"`id` INT(11) NULL\"},\n\t\t// {\"id INT(11) auto_increment\", \"`id` INT(11) AUTO_INCREMENT\"},\n\t\t// {\"id INT(11) DEFAULT 10\", \"`id` INT(11) DEFAULT 10\"},\n\t\t// {\"id INT(11) DEFAULT '10'\", \"`id` INT(11) DEFAULT '10'\"},\n\t\t// {\"id INT(11) DEFAULT 1.1\", \"`id` INT(11) DEFAULT 1.1\"},\n\t\t// {\"id INT(11) UNIQUE KEY\", \"`id` INT(11) UNIQUE KEY\"},\n\t\t// {\"id INT(11) COLLATE ascii_bin\", \"`id` INT(11) COLLATE ascii_bin\"},\n\t\t// {\"id INT(11) collate ascii_bin collate utf8_bin\", \"`id` INT(11) COLLATE ascii_bin COLLATE utf8_bin\"},\n\t\t// {\"id INT(11) on update CURRENT_TIMESTAMP\", \"`id` INT(11) ON UPDATE CURRENT_TIMESTAMP()\"},\n\t\t// {\"id INT(11) comment 'hello'\", \"`id` INT(11) COMMENT 'hello'\"},\n\t\t// {\"id INT(11) generated always as(id + 1)\", \"`id` INT(11) GENERATED ALWAYS AS(`id`+1) VIRTUAL\"},\n\t\t// {\"id INT(11) REFERENCES parent(id)\", \"`id` INT(11) REFERENCES `parent`(`id`)\"},\n\n\t\t{\"id bit\", \"`id` BIT\"},\n\t\t// {\"id bit(1)\", \"`id` BIT(1)\"},\n\t\t// {\"id bit(64)\", \"`id` BIT(64)\"},\n\t\t// {\"id tinyint\", \"`id` TINYINT\"},\n\t\t// {\"id tinyint(255)\", \"`id` TINYINT(255)\"},\n\t\t{\"id bool\", \"`id` BOOL\"},\n\t\t{\"id boolean\", \"`id` BOOLEAN\"},\n\t\t// {\"id smallint\", \"`id` SMALLINT\"},\n\t\t// {\"id smallint(255)\", \"`id` SMALLINT(255)\"},\n\t\t// {\"id mediumint\", \"`id` MEDIUMINT\"},\n\t\t// {\"id mediumint(255)\", \"`id` MEDIUMINT(255)\"},\n\t\t{\"id int\", \"`id` INT\"},\n\t\t// {\"id int(255)\", \"`id` INT(255)\"},\n\t\t// {\"id integer\", \"`id` INT\"},\n\t\t// {\"id integer(255)\", \"`id` INT(255)\"},\n\t\t// {\"id bigint\", \"`id` BIGINT\"},\n\t\t// {\"id bigint(255)\", \"`id` BIGINT(255)\"},\n\t\t// {\"id decimal\", \"`id` DECIMAL\"},\n\t\t// {\"id decimal(10)\", \"`id` DECIMAL(10)\"},\n\t\t// {\"id decimal(10,0)\", \"`id` DECIMAL(10,0)\"},\n\t\t// {\"id decimal(65)\", \"`id` DECIMAL(65)\"},\n\t\t// {\"id decimal(65,30)\", \"`id` DECIMAL(65,30)\"},\n\t\t// {\"id dec(10,0)\", \"`id` DECIMAL(10,0)\"},\n\t\t// {\"id numeric(10,0)\", \"`id` DECIMAL(10,0)\"},\n\t\t// {\"id float(0)\", \"`id` FLOAT\"},\n\t\t// {\"id float(24)\", \"`id` FLOAT\"},\n\t\t// {\"id float(25)\", \"`id` DOUBLE\"},\n\t\t// {\"id float(53)\", \"`id` DOUBLE\"},\n\t\t// {\"id float(7,0)\", \"`id` FLOAT(7,0)\"},\n\t\t// {\"id float(25,0)\", \"`id` FLOAT(25,0)\"},\n\t\t// {\"id double(15,0)\", \"`id` DOUBLE(15,0)\"},\n\t\t// {\"id double precision(15,0)\", \"`id` DOUBLE(15,0)\"},\n\t\t// {\"id real(15,0)\", \"`id` DOUBLE(15,0)\"},\n\t\t// {\"id year(4)\", \"`id` YEAR(4)\"},\n\t\t{\"id time\", \"`id` TIME\"},\n\t\t// {\"id char\", \"`id` CHAR\"},\n\t\t// {\"id char(0)\", \"`id` CHAR(0)\"},\n\t\t// {\"id char(255)\", \"`id` CHAR(255)\"},\n\t\t// {\"id national char(0)\", \"`id` CHAR(0)\"},\n\t\t// {\"id binary\", \"`id` BINARY\"},\n\t\t// {\"id varbinary(0)\", \"`id` VARBINARY(0)\"},\n\t\t// {\"id varbinary(65535)\", \"`id` VARBINARY(65535)\"},\n\t\t// {\"id tinyblob\", \"`id` TINYBLOB\"},\n\t\t// {\"id tinytext\", \"`id` TINYTEXT\"},\n\t\t// {\"id blob\", \"`id` BLOB\"},\n\t\t// {\"id blob(0)\", \"`id` BLOB(0)\"},\n\t\t// {\"id blob(65535)\", \"`id` BLOB(65535)\"},\n\t\t// {\"id text(0)\", \"`id` TEXT(0)\"},\n\t\t// {\"id text(65535)\", \"`id` TEXT(65535)\"},\n\t\t// {\"id mediumblob\", \"`id` MEDIUMBLOB\"},\n\t\t// {\"id mediumtext\", \"`id` MEDIUMTEXT\"},\n\t\t// {\"id longblob\", \"`id` LONGBLOB\"},\n\t\t// {\"id longtext\", \"`id` LONGTEXT\"},\n\t\t// {\"id json\", \"`id` JSON\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*CreateTableStmt).Cols[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"CREATE TABLE t (%s)\", extractNodeFunc)\n}\n\nfunc (ts *testDDLSuite) TestDDLTruncateTableStmtRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"truncate t1\", \"TRUNCATE TABLE `t1`\"},\n\t\t{\"truncate table t1\", \"TRUNCATE TABLE `t1`\"},\n\t\t{\"truncate a.t1\", \"TRUNCATE TABLE `a`.`t1`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*TruncateTableStmt)\n\t}\n\tRunNodeRestoreTest(c, testCases, \"%s\", extractNodeFunc)\n}\n\nfunc (ts *testDDLSuite) TestDDLDropTableStmtRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"drop table t1\", \"DROP TABLE `t1`\"},\n\t\t{\"drop table if exists t1\", \"DROP TABLE IF EXISTS `t1`\"},\n\t\t{\"drop temporary table t1\", \"DROP TEMPORARY TABLE `t1`\"},\n\t\t{\"drop temporary table if exists t1\", \"DROP TEMPORARY TABLE IF EXISTS `t1`\"},\n\t\t{\"DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `test`\", \"DROP TEMPORARY TABLE IF EXISTS `test`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*DropTableStmt)\n\t}\n\tRunNodeRestoreTest(c, testCases, \"%s\", extractNodeFunc)\n}\n\nfunc (ts *testDDLSuite) TestColumnPositionRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"\", \"\"},\n\t\t{\"first\", \"FIRST\"},\n\t\t{\"after b\", \"AFTER `b`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*AlterTableStmt).Specs[0].Position\n\t}\n\tRunNodeRestoreTest(c, testCases, \"alter table t add column a string %s\", extractNodeFunc)\n}\n\nfunc (ts *testDDLSuite) TestAlterTableSpecRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"ENGINE innodb\", \"ENGINE = innodb\"},\n\t\t{\"ENGINE = innodb\", \"ENGINE = innodb\"},\n\t\t{\"ENGINE = 'innodb'\", \"ENGINE = innodb\"},\n\t\t{\"ENGINE tokudb\", \"ENGINE = tokudb\"},\n\t\t{\"ENGINE = tokudb\", \"ENGINE = tokudb\"},\n\t\t{\"ENGINE = 'tokudb'\", \"ENGINE = tokudb\"},\n\t\t{\"DEFAULT CHARACTER SET utf8\", \"DEFAULT CHARACTER SET = UTF8\"},\n\t\t{\"DEFAULT CHARACTER SET = utf8\", \"DEFAULT CHARACTER SET = UTF8\"},\n\t\t{\"DEFAULT CHARSET utf8\", \"DEFAULT CHARACTER SET = UTF8\"},\n\t\t{\"DEFAULT CHARSET = utf8\", \"DEFAULT CHARACTER SET = UTF8\"},\n\t\t{\"DEFAULT COLLATE utf8_bin\", \"DEFAULT COLLATE = UTF8_BIN\"},\n\t\t{\"DEFAULT COLLATE = utf8_bin\", \"DEFAULT COLLATE = UTF8_BIN\"},\n\t\t{\"AUTO_INCREMENT 3\", \"AUTO_INCREMENT = 3\"},\n\t\t{\"AUTO_INCREMENT = 6\", \"AUTO_INCREMENT = 6\"},\n\t\t{\"COMMENT ''\", \"COMMENT = ''\"},\n\t\t{\"COMMENT 'system role'\", \"COMMENT = 'system role'\"},\n\t\t{\"COMMENT = 'system role'\", \"COMMENT = 'system role'\"},\n\t\t{\"AVG_ROW_LENGTH 12\", \"AVG_ROW_LENGTH = 12\"},\n\t\t{\"AVG_ROW_LENGTH = 6\", \"AVG_ROW_LENGTH = 6\"},\n\t\t{\"connection 'abc'\", \"CONNECTION = 'abc'\"},\n\t\t{\"CONNECTION = 'abc'\", \"CONNECTION = 'abc'\"},\n\t\t{\"checksum 1\", \"CHECKSUM = 1\"},\n\t\t{\"checksum = 0\", \"CHECKSUM = 0\"},\n\t\t{\"PASSWORD '123456'\", \"PASSWORD = '123456'\"},\n\t\t{\"PASSWORD = ''\", \"PASSWORD = ''\"},\n\t\t{\"compression 'NONE'\", \"COMPRESSION = 'NONE'\"},\n\t\t{\"compression = 'lz4'\", \"COMPRESSION = 'lz4'\"},\n\t\t{\"key_block_size 1024\", \"KEY_BLOCK_SIZE = 1024\"},\n\t\t{\"KEY_BLOCK_SIZE = 1024\", \"KEY_BLOCK_SIZE = 1024\"},\n\t\t{\"max_rows 1000\", \"MAX_ROWS = 1000\"},\n\t\t{\"max_rows = 1000\", \"MAX_ROWS = 1000\"},\n\t\t{\"min_rows 1000\", \"MIN_ROWS = 1000\"},\n\t\t{\"MIN_ROWS = 1000\", \"MIN_ROWS = 1000\"},\n\t\t{\"DELAY_KEY_WRITE 1\", \"DELAY_KEY_WRITE = 1\"},\n\t\t{\"DELAY_KEY_WRITE = 1000\", \"DELAY_KEY_WRITE = 1000\"},\n\t\t{\"ROW_FORMAT default\", \"ROW_FORMAT = DEFAULT\"},\n\t\t{\"ROW_FORMAT = default\", \"ROW_FORMAT = DEFAULT\"},\n\t\t{\"ROW_FORMAT = fixed\", \"ROW_FORMAT = FIXED\"},\n\t\t{\"ROW_FORMAT = compressed\", \"ROW_FORMAT = COMPRESSED\"},\n\t\t{\"ROW_FORMAT = compact\", \"ROW_FORMAT = COMPACT\"},\n\t\t{\"ROW_FORMAT = redundant\", \"ROW_FORMAT = REDUNDANT\"},\n\t\t{\"ROW_FORMAT = dynamic\", \"ROW_FORMAT = DYNAMIC\"},\n\t\t{\"ROW_FORMAT tokudb_default\", \"ROW_FORMAT = TOKUDB_DEFAULT\"},\n\t\t{\"ROW_FORMAT = tokudb_default\", \"ROW_FORMAT = TOKUDB_DEFAULT\"},\n\t\t{\"ROW_FORMAT = tokudb_fast\", \"ROW_FORMAT = TOKUDB_FAST\"},\n\t\t{\"ROW_FORMAT = tokudb_small\", \"ROW_FORMAT = TOKUDB_SMALL\"},\n\t\t{\"ROW_FORMAT = tokudb_zlib\", \"ROW_FORMAT = TOKUDB_ZLIB\"},\n\t\t{\"ROW_FORMAT = tokudb_quicklz\", \"ROW_FORMAT = TOKUDB_QUICKLZ\"},\n\t\t{\"ROW_FORMAT = tokudb_lzma\", \"ROW_FORMAT = TOKUDB_LZMA\"},\n\t\t{\"ROW_FORMAT = tokudb_snappy\", \"ROW_FORMAT = TOKUDB_SNAPPY\"},\n\t\t{\"ROW_FORMAT = tokudb_uncompressed\", \"ROW_FORMAT = TOKUDB_UNCOMPRESSED\"},\n\t\t{\"shard_row_id_bits 1\", \"SHARD_ROW_ID_BITS = 1\"},\n\t\t{\"shard_row_id_bits = 1\", \"SHARD_ROW_ID_BITS = 1\"},\n\t\t{\"CONVERT TO CHARACTER SET utf8\", \"CONVERT TO CHARACTER SET UTF8\"},\n\t\t{\"CONVERT TO CHARSET utf8\", \"CONVERT TO CHARACTER SET UTF8\"},\n\t\t{\"CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin\", \"CONVERT TO CHARACTER SET UTF8 COLLATE UTF8_BIN\"},\n\t\t{\"CONVERT TO CHARSET utf8 COLLATE utf8_bin\", \"CONVERT TO CHARACTER SET UTF8 COLLATE UTF8_BIN\"},\n\t\t// {\"ADD COLUMN (a SMALLINT UNSIGNED)\", \"ADD COLUMN (`a` SMALLINT UNSIGNED)\"},\n\t\t// {\"ADD COLUMN (a SMALLINT UNSIGNED, b varchar(255))\", \"ADD COLUMN (`a` SMALLINT UNSIGNED, `b` VARCHAR(255))\"},\n\t\t// {\"ADD COLUMN a SMALLINT UNSIGNED\", \"ADD COLUMN `a` SMALLINT UNSIGNED\"},\n\t\t// {\"ADD COLUMN a SMALLINT UNSIGNED FIRST\", \"ADD COLUMN `a` SMALLINT UNSIGNED FIRST\"},\n\t\t// {\"ADD COLUMN a SMALLINT UNSIGNED AFTER b\", \"ADD COLUMN `a` SMALLINT UNSIGNED AFTER `b`\"},\n\t\t// {\"ADD COLUMN name mediumtext CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci NOT NULL\", \"ADD COLUMN `name` MEDIUMTEXT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci NOT NULL\"},\n\t\t// {\"ADD CONSTRAINT INDEX par_ind (parent_id)\", \"ADD INDEX `par_ind`(`parent_id`)\"},\n\t\t// {\"ADD CONSTRAINT INDEX par_ind (parent_id(6))\", \"ADD INDEX `par_ind`(`parent_id`(6))\"},\n\t\t{\"ADD CONSTRAINT key par_ind (parent_id)\", \"ADD INDEX `par_ind`(`parent_id`)\"},\n\t\t{\"ADD CONSTRAINT unique par_ind (parent_id)\", \"ADD UNIQUE `par_ind`(`parent_id`)\"},\n\t\t{\"ADD CONSTRAINT unique key par_ind (parent_id)\", \"ADD UNIQUE `par_ind`(`parent_id`)\"},\n\t\t// {\"ADD CONSTRAINT unique index par_ind (parent_id)\", \"ADD UNIQUE `par_ind`(`parent_id`)\"},\n\t\t{\"ADD CONSTRAINT fulltext key full_id (parent_id)\", \"ADD FULLTEXT `full_id`(`parent_id`)\"},\n\t\t{\"ADD CONSTRAINT fulltext INDEX full_id (parent_id)\", \"ADD FULLTEXT `full_id`(`parent_id`)\"},\n\t\t{\"ADD CONSTRAINT PRIMARY KEY (id)\", \"ADD PRIMARY KEY(`id`)\"},\n\t\t{\"ADD CONSTRAINT PRIMARY KEY (id) key_block_size = 32 using hash comment 'hello'\", \"ADD PRIMARY KEY(`id`) KEY_BLOCK_SIZE=32 USING HASH COMMENT 'hello'\"},\n\t\t{\"ADD CONSTRAINT FOREIGN KEY (parent_id(2),hello(4)) REFERENCES parent(id) ON DELETE CASCADE\", \"ADD CONSTRAINT FOREIGN KEY (`parent_id`(2), `hello`(4)) REFERENCES `parent`(`id`) ON DELETE CASCADE\"},\n\t\t{\"ADD CONSTRAINT FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT\", \"ADD CONSTRAINT FOREIGN KEY (`parent_id`) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT\"},\n\t\t{\"ADD CONSTRAINT fk_123 FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ON UPDATE RESTRICT\", \"ADD CONSTRAINT `fk_123` FOREIGN KEY (`parent_id`) REFERENCES `parent`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT\"},\n\t\t{\"DROP COLUMN a\", \"DROP COLUMN `a`\"},\n\t\t{\"DROP COLUMN a RESTRICT\", \"DROP COLUMN `a`\"},\n\t\t{\"DROP COLUMN a CASCADE\", \"DROP COLUMN `a`\"},\n\t\t{\"DROP PRIMARY KEY\", \"DROP PRIMARY KEY\"},\n\t\t{\"drop index a\", \"DROP INDEX `a`\"},\n\t\t{\"drop key a\", \"DROP INDEX `a`\"},\n\t\t{\"drop FOREIGN key a\", \"DROP FOREIGN KEY `a`\"},\n\t\t// {\"MODIFY column a varchar(255)\", \"MODIFY COLUMN `a` VARCHAR(255)\"},\n\t\t// {\"modify COLUMN a varchar(255) FIRST\", \"MODIFY COLUMN `a` VARCHAR(255) FIRST\"},\n\t\t// {\"modify COLUMN a varchar(255) AFTER b\", \"MODIFY COLUMN `a` VARCHAR(255) AFTER `b`\"},\n\t\t// {\"change column a b VARCHAR(255)\", \"CHANGE COLUMN `a` `b` VARCHAR(255)\"},\n\t\t// {\"change COLUMN a b varchar(255) CHARACTER SET UTF8 BINARY\", \"CHANGE COLUMN `a` `b` VARCHAR(255) BINARY CHARACTER SET UTF8\"},\n\t\t// {\"CHANGE column a b varchar(255) FIRST\", \"CHANGE COLUMN `a` `b` VARCHAR(255) FIRST\"},\n\t\t// {\"change COLUMN a b varchar(255) AFTER c\", \"CHANGE COLUMN `a` `b` VARCHAR(255) AFTER `c`\"},\n\t\t{\"RENAME db1.t1\", \"RENAME AS `db1`.`t1`\"},\n\t\t{\"RENAME to db1.t1\", \"RENAME AS `db1`.`t1`\"},\n\t\t{\"RENAME as t1\", \"RENAME AS `t1`\"},\n\t\t{\"ALTER a SET DEFAULT 1\", \"ALTER COLUMN `a` SET DEFAULT 1\"},\n\t\t{\"ALTER a DROP DEFAULT\", \"ALTER COLUMN `a` DROP DEFAULT\"},\n\t\t{\"ALTER COLUMN a SET DEFAULT 1\", \"ALTER COLUMN `a` SET DEFAULT 1\"},\n\t\t{\"ALTER COLUMN a DROP DEFAULT\", \"ALTER COLUMN `a` DROP DEFAULT\"},\n\t\t{\"LOCK=NONE\", \"LOCK = NONE\"},\n\t\t{\"LOCK=DEFAULT\", \"LOCK = DEFAULT\"},\n\t\t{\"LOCK=SHARED\", \"LOCK = SHARED\"},\n\t\t{\"LOCK=EXCLUSIVE\", \"LOCK = EXCLUSIVE\"},\n\t\t{\"RENAME KEY a TO b\", \"RENAME INDEX `a` TO `b`\"},\n\t\t{\"RENAME INDEX a TO b\", \"RENAME INDEX `a` TO `b`\"},\n\t\t{\"ADD PARTITION\", \"ADD PARTITION\"},\n\t\t{\"ADD PARTITION ( PARTITION P1 VALUES LESS THAN (2010))\", \"ADD PARTITION (PARTITION `P1` VALUES LESS THAN (2010))\"},\n\t\t{\"ADD PARTITION ( PARTITION P2 VALUES LESS THAN MAXVALUE)\", \"ADD PARTITION (PARTITION `P2` VALUES LESS THAN (MAXVALUE))\"},\n\t\t{\"ADD PARTITION (\\nPARTITION P1 VALUES LESS THAN (2010),\\nPARTITION P2 VALUES LESS THAN (2015),\\nPARTITION P3 VALUES LESS THAN MAXVALUE)\", \"ADD PARTITION (PARTITION `P1` VALUES LESS THAN (2010), PARTITION `P2` VALUES LESS THAN (2015), PARTITION `P3` VALUES LESS THAN (MAXVALUE))\"},\n\t\t{\"ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT 'AP_START \\\\' AP_END')\", \"ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'AP_START '' AP_END')\"},\n\t\t{\"ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'xxx')\", \"ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'xxx')\"},\n\t\t{\"coalesce partition 3\", \"COALESCE PARTITION 3\"},\n\t\t{\"drop partition p1\", \"DROP PARTITION `p1`\"},\n\t\t{\"TRUNCATE PARTITION p0\", \"TRUNCATE PARTITION `p0`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*AlterTableStmt).Specs[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"ALTER TABLE t %s\", extractNodeFunc)\n}\n\nfunc (ts *testDDLSuite) TestAdminRepairTableRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"ADMIN REPAIR TABLE t CREATE TABLE t (a int)\", \"ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`a` INT)\"},\n\t\t{\"ADMIN REPAIR TABLE t CREATE TABLE t (a int, b int)\", \"ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`a` INT,`b` INT)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node\n\t}\n\tRunNodeRestoreTest(c, testCases, \"%s\", extractNodeFunc)\n}\n\nfunc (ts *testDDLSuite) TestSequenceRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"create sequence seq\", \"CREATE SEQUENCE `seq`\"},\n\t\t{\"create sequence if not exists seq\", \"CREATE SEQUENCE IF NOT EXISTS `seq`\"},\n\t\t{\"create temporary sequence if not exists seq\", \"CREATE TEMPORARY SEQUENCE IF NOT EXISTS `seq`\"},\n\t\t{\"create sequence if not exists seq increment 1\", \"CREATE SEQUENCE IF NOT EXISTS `seq` INCREMENT BY 1\"},\n\t\t{\"create sequence if not exists seq increment = 1\", \"CREATE SEQUENCE IF NOT EXISTS `seq` INCREMENT BY 1\"},\n\t\t{\"create sequence if not exists seq minvalue 1\", \"CREATE SEQUENCE IF NOT EXISTS `seq` MINVALUE 1\"},\n\t\t{\"create sequence if not exists seq minvalue = 1\", \"CREATE SEQUENCE IF NOT EXISTS `seq` MINVALUE 1\"},\n\t\t{\"create sequence if not exists seq nominvalue\", \"CREATE SEQUENCE IF NOT EXISTS `seq` NO MINVALUE\"},\n\t\t{\"create sequence if not exists seq no minvalue\", \"CREATE SEQUENCE IF NOT EXISTS `seq` NO MINVALUE\"},\n\t\t{\"create sequence if not exists seq maxvalue 1\", \"CREATE SEQUENCE IF NOT EXISTS `seq` MAXVALUE 1\"},\n\t\t{\"create sequence if not exists seq maxvalue = 1\", \"CREATE SEQUENCE IF NOT EXISTS `seq` MAXVALUE 1\"},\n\t\t{\"create sequence if not exists seq nomaxvalue\", \"CREATE SEQUENCE IF NOT EXISTS `seq` NO MAXVALUE\"},\n\t\t{\"create sequence if not exists seq no maxvalue\", \"CREATE SEQUENCE IF NOT EXISTS `seq` NO MAXVALUE\"},\n\t\t{\"create sequence if not exists seq start 1\", \"CREATE SEQUENCE IF NOT EXISTS `seq` START WITH 1\"},\n\t\t{\"create sequence if not exists seq start with 1\", \"CREATE SEQUENCE IF NOT EXISTS `seq` START WITH 1\"},\n\t\t{\"create sequence if not exists seq cache 1\", \"CREATE SEQUENCE IF NOT EXISTS `seq` CACHE 1\"},\n\t\t{\"create sequence if not exists seq nocache\", \"CREATE SEQUENCE IF NOT EXISTS `seq` NOCACHE\"},\n\t\t{\"create sequence if not exists seq no cache\", \"CREATE SEQUENCE IF NOT EXISTS `seq` NOCACHE\"},\n\t\t{\"create sequence if not exists seq cycle\", \"CREATE SEQUENCE IF NOT EXISTS `seq` CYCLE\"},\n\t\t{\"create sequence if not exists seq nocycle\", \"CREATE SEQUENCE IF NOT EXISTS `seq` NOCYCLE\"},\n\t\t{\"create sequence if not exists seq no cycle\", \"CREATE SEQUENCE IF NOT EXISTS `seq` NOCYCLE\"},\n\t\t{\"create sequence if not exists seq order\", \"CREATE SEQUENCE IF NOT EXISTS `seq` ORDER\"},\n\t\t{\"create sequence if not exists seq noorder\", \"CREATE SEQUENCE IF NOT EXISTS `seq` NOORDER\"},\n\t\t{\"create sequence if not exists seq no order\", \"CREATE SEQUENCE IF NOT EXISTS `seq` NOORDER\"},\n\t\t{\"create temporary sequence seq increment 1 minvalue 0 maxvalue 1000\", \"CREATE TEMPORARY SEQUENCE `seq` INCREMENT BY 1 MINVALUE 0 MAXVALUE 1000\"},\n\t\t{\"create temporary sequence seq minvalue 0 maxvalue 1000 increment 1\", \"CREATE TEMPORARY SEQUENCE `seq` MINVALUE 0 MAXVALUE 1000 INCREMENT BY 1\"},\n\t\t{\"create temporary sequence seq cache = 1 order minvalue 0 maxvalue -1000\", \"CREATE TEMPORARY SEQUENCE `seq` CACHE 1 ORDER MINVALUE 0 MAXVALUE -1000\"},\n\t\t{\"create temporary sequence seq increment -1 minvalue 0 maxvalue -1000\", \"CREATE TEMPORARY SEQUENCE `seq` INCREMENT BY -1 MINVALUE 0 MAXVALUE -1000\"},\n\t\t{\"create temporary sequence seq nocycle nocache maxvalue 1000 cache 1\", \"CREATE TEMPORARY SEQUENCE `seq` NOCYCLE NOCACHE MAXVALUE 1000 CACHE 1\"},\n\t\t{\"create temporary sequence seq increment -1 no minvalue no maxvalue cache = 1\", \"CREATE TEMPORARY SEQUENCE `seq` INCREMENT BY -1 NO MINVALUE NO MAXVALUE CACHE 1\"},\n\t\t{\"create temporary sequence if not exists seq increment 1 minvalue 0 nomaxvalue cache 100 nocycle noorder\", \"CREATE TEMPORARY SEQUENCE IF NOT EXISTS `seq` INCREMENT BY 1 MINVALUE 0 NO MAXVALUE CACHE 100 NOCYCLE NOORDER\"},\n\n\t\t// test drop sequence\n\t\t{\"drop sequence seq\", \"DROP SEQUENCE `seq`\"},\n\t\t{\"drop sequence seq, seq2\", \"DROP SEQUENCE `seq`, `seq2`\"},\n\t\t{\"drop sequence if exists seq, seq2\", \"DROP SEQUENCE IF EXISTS `seq`, `seq2`\"},\n\t\t{\"drop temporary sequence if exists seq\", \"DROP TEMPORARY SEQUENCE IF EXISTS `seq`\"},\n\t\t{\"drop temporary sequence sequence\", \"DROP TEMPORARY SEQUENCE `sequence`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node\n\t}\n\tRunNodeRestoreTest(c, testCases, \"%s\", extractNodeFunc)\n}\n"
  },
  {
    "path": "pkg/parser/ast/dml.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport (\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/auth\"\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n)\n\nvar (\n\t_ DMLNode = &DeleteStmt{}\n\t_ DMLNode = &InsertStmt{}\n\t_ DMLNode = &UnionStmt{}\n\t_ DMLNode = &UpdateStmt{}\n\t_ DMLNode = &SelectStmt{}\n\t_ DMLNode = &ShowStmt{}\n\t_ DMLNode = &LoadDataStmt{}\n\t_ DMLNode = &SplitRegionStmt{}\n\n\t_ Node = &Assignment{}\n\t_ Node = &ByItem{}\n\t_ Node = &FieldList{}\n\t_ Node = &GroupByClause{}\n\t_ Node = &HavingClause{}\n\t_ Node = &Join{}\n\t_ Node = &Limit{}\n\t_ Node = &OnCondition{}\n\t_ Node = &OrderByClause{}\n\t_ Node = &SelectField{}\n\t_ Node = &TableName{}\n\t_ Node = &TableRefsClause{}\n\t_ Node = &TableSource{}\n\t_ Node = &UnionSelectList{}\n\t_ Node = &WildCardField{}\n\t_ Node = &WindowSpec{}\n\t_ Node = &PartitionByClause{}\n\t_ Node = &FrameClause{}\n\t_ Node = &FrameBound{}\n)\n\n// JoinType is join type, including cross/left/right/full.\ntype JoinType int\n\nconst (\n\t// CrossJoin is cross join type.\n\tCrossJoin JoinType = iota + 1\n\t// LeftJoin is left Join type.\n\tLeftJoin\n\t// RightJoin is right Join type.\n\tRightJoin\n)\n\n// Join represents table join.\ntype Join struct {\n\tnode\n\tresultSetNode\n\n\t// Left table can be TableSource or JoinNode.\n\tLeft ResultSetNode\n\t// Right table can be TableSource or JoinNode or nil.\n\tRight ResultSetNode\n\t// Tp represents join type.\n\tTp JoinType\n\t// On represents join on condition.\n\tOn *OnCondition\n\t// Using represents join using clause.\n\tUsing []*ColumnName\n\t// NaturalJoin represents join is natural join.\n\tNaturalJoin bool\n\t// StraightJoin represents a straight join.\n\tStraightJoin bool\n}\n\n// Restore implements Node interface.\nfunc (n *Join) Restore(ctx *RestoreCtx) error {\n\tskipParen := false\n\tif _, ok := n.Left.(*TableSource); ok {\n\t\tif n.Right == nil {\n\t\t\tskipParen = true\n\t\t}\n\t}\n\tif !skipParen && ctx.JoinLevel != 0 {\n\t\tctx.WritePlain(\"(\")\n\t\tdefer ctx.WritePlain(\")\")\n\t}\n\tif n.Right != nil {\n\t\tctx.JoinLevel++\n\t}\n\tif err := n.Left.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore Join.Left\")\n\t}\n\tif n.Right != nil {\n\t\tctx.JoinLevel--\n\t}\n\tif n.Right == nil {\n\t\treturn nil\n\t}\n\tif n.NaturalJoin {\n\t\tctx.WriteKeyWord(\" NATURAL\")\n\t}\n\n\tif n.On == nil && len(n.Using) == 0 {\n\t\tif ctx.Dialect.ObviousCrossWhenCrossJoin() {\n\t\t\tctx.WriteKeyWord(\" CROSS\")\n\t\t}\n\t} else {\n\t\tswitch n.Tp {\n\t\tcase LeftJoin:\n\t\t\tctx.WriteKeyWord(\" LEFT\")\n\t\tcase RightJoin:\n\t\t\tctx.WriteKeyWord(\" RIGHT\")\n\t\t}\n\t}\n\n\tif n.StraightJoin {\n\t\tctx.WriteKeyWord(\" STRAIGHT_JOIN \")\n\t} else {\n\t\tctx.WriteKeyWord(\" JOIN \")\n\t}\n\tctx.JoinLevel++\n\tif err := n.Right.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore Join.Right\")\n\t}\n\tctx.JoinLevel--\n\n\tif n.On != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.On.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore Join.On\")\n\t\t}\n\t}\n\tif len(n.Using) != 0 {\n\t\tctx.WriteKeyWord(\" USING \")\n\t\tctx.WritePlain(\"(\")\n\t\tfor i, v := range n.Using {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore Join.Using\")\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *Join) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*Join)\n\tnode, ok := n.Left.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Left = node.(ResultSetNode)\n\tif n.Right != nil {\n\t\tnode, ok = n.Right.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Right = node.(ResultSetNode)\n\t}\n\tif n.On != nil {\n\t\tnode, ok = n.On.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.On = node.(*OnCondition)\n\t}\n\treturn v.Leave(n)\n}\n\n// TableName represents a table name.\ntype TableName struct {\n\tnode\n\tresultSetNode\n\n\tSchema model.CIStr\n\tName   model.CIStr\n\n\tDBInfo    *model.DBInfo\n\tTableInfo *model.TableInfo\n\n\tIndexHints     []*IndexHint\n\tPartitionNames []model.CIStr\n}\n\n// Restore implements Node interface.\nfunc (n *TableName) restoreName(ctx *RestoreCtx) {\n\tif n.Schema.String() != \"\" {\n\t\tctx.WriteName(n.Schema.String())\n\t\tctx.WritePlain(\".\")\n\t}\n\tctx.WriteName(n.Name.String())\n}\n\nfunc (n *TableName) restorePartitions(ctx *RestoreCtx) {\n\tif len(n.PartitionNames) > 0 {\n\t\tctx.WriteKeyWord(\" PARTITION\")\n\t\tctx.WritePlain(\"(\")\n\t\tfor i, v := range n.PartitionNames {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tctx.WriteName(v.String())\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n}\n\nfunc (n *TableName) restoreIndexHints(ctx *RestoreCtx) error {\n\tfor _, value := range n.IndexHints {\n\t\tctx.WritePlain(\" \")\n\t\tif err := value.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while splicing IndexHints\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (n *TableName) Restore(ctx *RestoreCtx) error {\n\tn.restoreName(ctx)\n\tn.restorePartitions(ctx)\n\treturn n.restoreIndexHints(ctx)\n}\n\n// IndexHintType is the type for index hint use, ignore or force.\ntype IndexHintType int\n\n// IndexHintUseType values.\nconst (\n\tHintUse    IndexHintType = 1\n\tHintIgnore IndexHintType = 2\n\tHintForce  IndexHintType = 3\n)\n\n// IndexHintScope is the type for index hint for join, order by or group by.\ntype IndexHintScope int\n\n// Index hint scopes.\nconst (\n\tHintForScan    IndexHintScope = 1\n\tHintForJoin    IndexHintScope = 2\n\tHintForOrderBy IndexHintScope = 3\n\tHintForGroupBy IndexHintScope = 4\n)\n\n// IndexHint represents a hint for optimizer to use/ignore/force for join/order by/group by.\ntype IndexHint struct {\n\tIndexNames []model.CIStr\n\tHintType   IndexHintType\n\tHintScope  IndexHintScope\n}\n\n// IndexHint Restore (The const field uses switch to facilitate understanding)\nfunc (n *IndexHint) Restore(ctx *RestoreCtx) error {\n\tindexHintType := \"\"\n\tswitch n.HintType {\n\tcase 1:\n\t\tindexHintType = \"USE INDEX\"\n\tcase 2:\n\t\tindexHintType = \"IGNORE INDEX\"\n\tcase 3:\n\t\tindexHintType = \"FORCE INDEX\"\n\tdefault: // Prevent accidents\n\t\treturn errors.New(\"IndexHintType has an error while matching\")\n\t}\n\n\tindexHintScope := \"\"\n\tswitch n.HintScope {\n\tcase 1:\n\t\tindexHintScope = \"\"\n\tcase 2:\n\t\tindexHintScope = \" FOR JOIN\"\n\tcase 3:\n\t\tindexHintScope = \" FOR ORDER BY\"\n\tcase 4:\n\t\tindexHintScope = \" FOR GROUP BY\"\n\tdefault: // Prevent accidents\n\t\treturn errors.New(\"IndexHintScope has an error while matching\")\n\t}\n\tctx.WriteKeyWord(indexHintType)\n\tctx.WriteKeyWord(indexHintScope)\n\tctx.WritePlain(\" (\")\n\tfor i, value := range n.IndexNames {\n\t\tif i > 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tctx.WriteName(value.O)\n\t}\n\tctx.WritePlain(\")\")\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *TableName) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*TableName)\n\treturn v.Leave(n)\n}\n\n// DeleteTableList is the tablelist used in delete statement multi-table mode.\ntype DeleteTableList struct {\n\tnode\n\tTables []*TableName\n}\n\n// Restore implements Node interface.\nfunc (n *DeleteTableList) Restore(ctx *RestoreCtx) error {\n\tfor i, t := range n.Tables {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t\tif err := t.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore DeleteTableList.Tables[%v]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DeleteTableList) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DeleteTableList)\n\tif n != nil {\n\t\tfor i, t := range n.Tables {\n\t\t\tnode, ok := t.Accept(v)\n\t\t\tif !ok {\n\t\t\t\treturn n, false\n\t\t\t}\n\t\t\tn.Tables[i] = node.(*TableName)\n\t\t}\n\t}\n\treturn v.Leave(n)\n}\n\n// OnCondition represents JOIN on condition.\ntype OnCondition struct {\n\tnode\n\n\tExpr ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *OnCondition) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"ON \")\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore OnCondition.Expr\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *OnCondition) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*OnCondition)\n\tnode, ok := n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// TableSource represents table source with a name.\ntype TableSource struct {\n\tnode\n\n\t// Source is the source of the data, can be a TableName,\n\t// a SelectStmt, a UnionStmt, or a JoinNode.\n\tSource ResultSetNode\n\n\t// AsName is the alias name of the table source.\n\tAsName model.CIStr\n}\n\n// Restore implements Node interface.\nfunc (n *TableSource) Restore(ctx *RestoreCtx) error {\n\tneedParen := false\n\tswitch n.Source.(type) {\n\tcase *SelectStmt, *UnionStmt:\n\t\tneedParen = true\n\t}\n\n\tif tn, tnCase := n.Source.(*TableName); tnCase {\n\t\tif needParen {\n\t\t\tctx.WritePlain(\"(\")\n\t\t}\n\n\t\ttn.restoreName(ctx)\n\t\ttn.restorePartitions(ctx)\n\n\t\tif asName := n.AsName.String(); asName != \"\" {\n\t\t\tctx.WriteKeyWord(\" AS \")\n\t\t\tctx.WriteName(asName)\n\t\t}\n\t\tif err := tn.restoreIndexHints(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore TableSource.Source.(*TableName).IndexHints\")\n\t\t}\n\n\t\tif needParen {\n\t\t\tctx.WritePlain(\")\")\n\t\t}\n\t} else {\n\t\tif needParen {\n\t\t\tctx.WritePlain(\"(\")\n\t\t}\n\t\tif err := n.Source.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore TableSource.Source\")\n\t\t}\n\t\tif needParen {\n\t\t\tctx.WritePlain(\")\")\n\t\t}\n\t\tif asName := n.AsName.String(); asName != \"\" {\n\t\t\tctx.WriteKeyWord(\" AS \")\n\t\t\tctx.WriteName(asName)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *TableSource) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*TableSource)\n\tnode, ok := n.Source.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Source = node.(ResultSetNode)\n\treturn v.Leave(n)\n}\n\n// SelectLockType is the lock type for SelectStmt.\ntype SelectLockType int\n\n// Select lock types.\nconst (\n\tSelectLockNone SelectLockType = iota\n\tSelectLockForUpdate\n\tSelectLockInShareMode\n\tSelectLockForUpdateNoWait\n)\n\n// String implements fmt.Stringer.\nfunc (slt SelectLockType) String() string {\n\tswitch slt {\n\tcase SelectLockNone:\n\t\treturn \"none\"\n\tcase SelectLockForUpdate:\n\t\treturn \"for update\"\n\tcase SelectLockInShareMode:\n\t\treturn \"in share mode\"\n\tcase SelectLockForUpdateNoWait:\n\t\treturn \"for update nowait\"\n\t}\n\treturn \"unsupported select lock type\"\n}\n\n// WildCardField is a special type of select field content.\ntype WildCardField struct {\n\tnode\n\n\tTable  model.CIStr\n\tSchema model.CIStr\n}\n\n// Restore implements Node interface.\nfunc (n *WildCardField) Restore(ctx *RestoreCtx) error {\n\tif schema := n.Schema.String(); schema != \"\" {\n\t\tctx.WriteName(schema)\n\t\tctx.WritePlain(\".\")\n\t}\n\tif table := n.Table.String(); table != \"\" {\n\t\tctx.WriteName(table)\n\t\tctx.WritePlain(\".\")\n\t}\n\tctx.WritePlain(\"*\")\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *WildCardField) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*WildCardField)\n\treturn v.Leave(n)\n}\n\n// SelectField represents fields in select statement.\n// There are two type of select field: wildcard\n// and expression with optional alias name.\ntype SelectField struct {\n\tnode\n\n\t// Offset is used to get original text.\n\tOffset int\n\t// WildCard is not nil, Expr will be nil.\n\tWildCard *WildCardField\n\t// Expr is not nil, WildCard will be nil.\n\tExpr ExprNode\n\t// AsName is alias name for Expr.\n\tAsName model.CIStr\n\t// Auxiliary stands for if this field is auxiliary.\n\t// When we add a Field into SelectField list which is used for having/orderby clause but the field is not in select clause,\n\t// we should set its Auxiliary to true. Then the TrimExec will trim the field.\n\tAuxiliary bool\n}\n\n// Restore implements Node interface.\nfunc (n *SelectField) Restore(ctx *RestoreCtx) error {\n\tif n.WildCard != nil {\n\t\tif err := n.WildCard.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectField.WildCard\")\n\t\t}\n\t}\n\tif n.Expr != nil {\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectField.Expr\")\n\t\t}\n\t}\n\tif asName := n.AsName.String(); asName != \"\" {\n\t\tctx.WriteKeyWord(\" AS \")\n\t\tctx.WriteName(asName)\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *SelectField) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*SelectField)\n\tif n.Expr != nil {\n\t\tnode, ok := n.Expr.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Expr = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// FieldList represents field list in select statement.\ntype FieldList struct {\n\tnode\n\n\tFields []*SelectField\n}\n\n// Restore implements Node interface.\nfunc (n *FieldList) Restore(ctx *RestoreCtx) error {\n\tfor i, v := range n.Fields {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FieldList.Fields[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *FieldList) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*FieldList)\n\tfor i, val := range n.Fields {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Fields[i] = node.(*SelectField)\n\t}\n\treturn v.Leave(n)\n}\n\n// TableRefsClause represents table references clause in dml statement.\ntype TableRefsClause struct {\n\tnode\n\n\tTableRefs *Join\n}\n\n// Restore implements Node interface.\nfunc (n *TableRefsClause) Restore(ctx *RestoreCtx) error {\n\tif err := n.TableRefs.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore TableRefsClause.TableRefs\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *TableRefsClause) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*TableRefsClause)\n\tnode, ok := n.TableRefs.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.TableRefs = node.(*Join)\n\treturn v.Leave(n)\n}\n\n// ByItem represents an item in order by or group by.\ntype ByItem struct {\n\tnode\n\n\tExpr ExprNode\n\tDesc bool\n}\n\n// Restore implements Node interface.\nfunc (n *ByItem) Restore(ctx *RestoreCtx) error {\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore ByItem.Expr\")\n\t}\n\tif n.Desc {\n\t\tctx.WriteKeyWord(\" DESC\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ByItem) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ByItem)\n\tnode, ok := n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// GroupByClause represents group by clause.\ntype GroupByClause struct {\n\tnode\n\tItems []*ByItem\n}\n\n// Restore implements Node interface.\nfunc (n *GroupByClause) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"GROUP BY \")\n\tfor i, v := range n.Items {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore GroupByClause.Items[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *GroupByClause) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*GroupByClause)\n\tfor i, val := range n.Items {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Items[i] = node.(*ByItem)\n\t}\n\treturn v.Leave(n)\n}\n\n// HavingClause represents having clause.\ntype HavingClause struct {\n\tnode\n\tExpr ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *HavingClause) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"HAVING \")\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore HavingClause.Expr\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *HavingClause) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*HavingClause)\n\tnode, ok := n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// OrderByClause represents order by clause.\ntype OrderByClause struct {\n\tnode\n\tItems    []*ByItem\n\tForUnion bool\n}\n\n// Restore implements Node interface.\nfunc (n *OrderByClause) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"ORDER BY \")\n\tfor i, item := range n.Items {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t\tif err := item.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore OrderByClause.Items[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *OrderByClause) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*OrderByClause)\n\tfor i, val := range n.Items {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Items[i] = node.(*ByItem)\n\t}\n\treturn v.Leave(n)\n}\n\n// SelectStmt represents the select query node.\n// See https://dev.mysql.com/doc/refman/5.7/en/select.html\ntype SelectStmt struct {\n\tdmlNode\n\tresultSetNode\n\n\t// SelectStmtOpts wraps around select hints and switches.\n\t*SelectStmtOpts\n\t// Distinct represents whether the select has distinct option.\n\tDistinct bool\n\t// From is the from clause of the query.\n\tFrom *TableRefsClause\n\t// Where is the where clause in select statement.\n\tWhere ExprNode\n\t// Fields is the select expression list.\n\tFields *FieldList\n\t// GroupBy is the group by expression list.\n\tGroupBy *GroupByClause\n\t// Having is the having condition.\n\tHaving *HavingClause\n\t// WindowSpecs is the window specification list.\n\tWindowSpecs []WindowSpec\n\t// OrderBy is the ordering expression list.\n\tOrderBy *OrderByClause\n\t// Limit is the limit clause.\n\tLimit *Limit\n\t// LockTp is the lock type\n\tLockTp SelectLockType\n\t// TableHints represents the table level Optimizer Hint for join type\n\tTableHints []*TableOptimizerHint\n\t// IsAfterUnionDistinct indicates whether it's a stmt after \"union distinct\".\n\tIsAfterUnionDistinct bool\n\t// IsInBraces indicates whether it's a stmt in brace.\n\tIsInBraces bool\n\t// QueryBlockOffset indicates the order of this SelectStmt if counted from left to right in the sql text.\n\tQueryBlockOffset int\n\t// SelectIntoOpt is the select-into option.\n\tSelectIntoOpt *SelectIntoOption\n}\n\n// Restore implements Node interface.\nfunc (n *SelectStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"SELECT \")\n\tif n.SelectStmtOpts != nil {\n\t\tif n.SelectStmtOpts.Priority > 0 {\n\t\t\tctx.WriteKeyWord(mysql.Priority2Str[n.SelectStmtOpts.Priority])\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\n\t\tif n.SelectStmtOpts.SQLSmallResult {\n\t\t\tctx.WriteKeyWord(\"SQL_SMALL_RESULT \")\n\t\t}\n\n\t\tif n.SelectStmtOpts.SQLBigResult {\n\t\t\tctx.WriteKeyWord(\"SQL_BIG_RESULT \")\n\t\t}\n\n\t\tif n.SelectStmtOpts.SQLBufferResult {\n\t\t\tctx.WriteKeyWord(\"SQL_BUFFER_RESULT \")\n\t\t}\n\n\t\tif !n.SelectStmtOpts.SQLCache {\n\t\t\tctx.WriteKeyWord(\"SQL_NO_CACHE \")\n\t\t}\n\t}\n\n\tif n.TableHints != nil && len(n.TableHints) != 0 {\n\t\tctx.WritePlain(\"/*+ \")\n\t\tfor i, tableHint := range n.TableHints {\n\t\t\tif err := tableHint.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore SelectStmt.TableHints[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\"*/ \")\n\t}\n\n\tif n.Distinct {\n\t\tctx.WriteKeyWord(\"DISTINCT \")\n\t}\n\tif n.SelectStmtOpts != nil && n.SelectStmtOpts.StraightJoin {\n\t\tctx.WriteKeyWord(\"STRAIGHT_JOIN \")\n\t}\n\tif n.Fields != nil {\n\t\tfor i, field := range n.Fields.Fields {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := field.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore SelectStmt.Fields[%d]\", i)\n\t\t\t}\n\t\t}\n\t}\n\n\tif n.From != nil {\n\t\tctx.WriteKeyWord(\" FROM \")\n\t\tif err := n.From.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectStmt.From\")\n\t\t}\n\t}\n\n\tif n.From == nil && n.Where != nil {\n\t\tctx.WriteKeyWord(\" FROM DUAL\")\n\t}\n\tif n.Where != nil {\n\t\tctx.WriteKeyWord(\" WHERE \")\n\t\tif err := n.Where.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectStmt.Where\")\n\t\t}\n\t}\n\n\tif n.GroupBy != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.GroupBy.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectStmt.GroupBy\")\n\t\t}\n\t}\n\n\tif n.Having != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Having.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectStmt.Having\")\n\t\t}\n\t}\n\n\tif n.WindowSpecs != nil {\n\t\tctx.WriteKeyWord(\" WINDOW \")\n\t\tfor i, windowsSpec := range n.WindowSpecs {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := windowsSpec.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore SelectStmt.WindowSpec[%d]\", i)\n\t\t\t}\n\t\t}\n\t}\n\n\tif n.OrderBy != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.OrderBy.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectStmt.OrderBy\")\n\t\t}\n\t}\n\n\tif n.Limit != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Limit.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectStmt.Limit\")\n\t\t}\n\t}\n\n\tswitch n.LockTp {\n\tcase SelectLockInShareMode:\n\t\tctx.WriteKeyWord(\" LOCK \")\n\t\tctx.WriteKeyWord(n.LockTp.String())\n\tcase SelectLockForUpdate, SelectLockForUpdateNoWait:\n\t\tctx.WritePlain(\" \")\n\t\tctx.WriteKeyWord(n.LockTp.String())\n\t}\n\n\tif n.SelectIntoOpt != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.SelectIntoOpt.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectStmt.SelectIntoOpt\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *SelectStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*SelectStmt)\n\tif n.TableHints != nil && len(n.TableHints) != 0 {\n\t\tnewHints := make([]*TableOptimizerHint, len(n.TableHints))\n\t\tfor i, hint := range n.TableHints {\n\t\t\tnode, ok := hint.Accept(v)\n\t\t\tif !ok {\n\t\t\t\treturn n, false\n\t\t\t}\n\t\t\tnewHints[i] = node.(*TableOptimizerHint)\n\t\t}\n\t\tn.TableHints = newHints\n\t}\n\n\tif n.Fields != nil {\n\t\tnode, ok := n.Fields.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Fields = node.(*FieldList)\n\t}\n\n\tif n.From != nil {\n\t\tnode, ok := n.From.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.From = node.(*TableRefsClause)\n\t}\n\n\tif n.Where != nil {\n\t\tnode, ok := n.Where.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Where = node.(ExprNode)\n\t}\n\n\tif n.GroupBy != nil {\n\t\tnode, ok := n.GroupBy.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.GroupBy = node.(*GroupByClause)\n\t}\n\n\tif n.Having != nil {\n\t\tnode, ok := n.Having.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Having = node.(*HavingClause)\n\t}\n\n\tfor i, spec := range n.WindowSpecs {\n\t\tnode, ok := spec.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.WindowSpecs[i] = *node.(*WindowSpec)\n\t}\n\n\tif n.OrderBy != nil {\n\t\tnode, ok := n.OrderBy.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.OrderBy = node.(*OrderByClause)\n\t}\n\n\tif n.Limit != nil {\n\t\tnode, ok := n.Limit.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Limit = node.(*Limit)\n\t}\n\n\treturn v.Leave(n)\n}\n\n// UnionSelectList represents the select list in a union statement.\ntype UnionSelectList struct {\n\tnode\n\n\tSelects []*SelectStmt\n}\n\n// Restore implements Node interface.\nfunc (n *UnionSelectList) Restore(ctx *RestoreCtx) error {\n\tfor i, selectStmt := range n.Selects {\n\t\tif i != 0 {\n\t\t\tctx.WriteKeyWord(\" UNION \")\n\t\t\tif !selectStmt.IsAfterUnionDistinct {\n\t\t\t\tctx.WriteKeyWord(\"ALL \")\n\t\t\t}\n\t\t}\n\t\tif selectStmt.IsInBraces {\n\t\t\tctx.WritePlain(\"(\")\n\t\t}\n\t\tif err := selectStmt.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore UnionSelectList.SelectStmt\")\n\t\t}\n\t\tif selectStmt.IsInBraces {\n\t\t\tctx.WritePlain(\")\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *UnionSelectList) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*UnionSelectList)\n\tfor i, sel := range n.Selects {\n\t\tnode, ok := sel.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Selects[i] = node.(*SelectStmt)\n\t}\n\treturn v.Leave(n)\n}\n\n// UnionStmt represents \"union statement\"\n// See https://dev.mysql.com/doc/refman/5.7/en/union.html\ntype UnionStmt struct {\n\tdmlNode\n\tresultSetNode\n\n\tSelectList *UnionSelectList\n\tOrderBy    *OrderByClause\n\tLimit      *Limit\n}\n\n// Restore implements Node interface.\nfunc (n *UnionStmt) Restore(ctx *RestoreCtx) error {\n\tif err := n.SelectList.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore UnionStmt.SelectList\")\n\t}\n\n\tif n.OrderBy != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.OrderBy.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore UnionStmt.OrderBy\")\n\t\t}\n\t}\n\n\tif n.Limit != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Limit.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore UnionStmt.Limit\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *UnionStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*UnionStmt)\n\tif n.SelectList != nil {\n\t\tnode, ok := n.SelectList.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.SelectList = node.(*UnionSelectList)\n\t}\n\tif n.OrderBy != nil {\n\t\tnode, ok := n.OrderBy.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.OrderBy = node.(*OrderByClause)\n\t}\n\tif n.Limit != nil {\n\t\tnode, ok := n.Limit.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Limit = node.(*Limit)\n\t}\n\treturn v.Leave(n)\n}\n\n// Assignment is the expression for assignment, like a = 1.\ntype Assignment struct {\n\tnode\n\t// Column is the column name to be assigned.\n\tColumn *ColumnName\n\t// Expr is the expression assigning to ColName.\n\tExpr ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *Assignment) Restore(ctx *RestoreCtx) error {\n\tif err := n.Column.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore Assignment.Column\")\n\t}\n\tctx.WritePlain(\"=\")\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore Assignment.Expr\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *Assignment) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*Assignment)\n\tnode, ok := n.Column.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Column = node.(*ColumnName)\n\tnode, ok = n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\ntype ColumnNameOrUserVar struct {\n\tColumnName *ColumnName\n\tUserVar    *VariableExpr\n}\n\n// LoadDataStmt is a statement to load data from a specified file, then insert this rows into an existing table.\n// See https://dev.mysql.com/doc/refman/5.7/en/load-data.html\ntype LoadDataStmt struct {\n\tdmlNode\n\n\tIsLocal           bool\n\tPath              string\n\tOnDuplicate       OnDuplicateKeyHandlingType\n\tTable             *TableName\n\tColumns           []*ColumnName\n\tFieldsInfo        *FieldsClause\n\tLinesInfo         *LinesClause\n\tIgnoreLines       uint64\n\tColumnAssignments []*Assignment\n\n\tColumnsAndUserVars []*ColumnNameOrUserVar\n}\n\n// Restore implements Node interface.\nfunc (n *LoadDataStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"LOAD DATA \")\n\tif n.IsLocal {\n\t\tctx.WriteKeyWord(\"LOCAL \")\n\t}\n\tctx.WriteKeyWord(\"INFILE \")\n\tctx.WriteString(n.Path)\n\tif n.OnDuplicate == OnDuplicateKeyHandlingReplace {\n\t\tctx.WriteKeyWord(\" REPLACE\")\n\t} else if n.OnDuplicate == OnDuplicateKeyHandlingIgnore {\n\t\tctx.WriteKeyWord(\" IGNORE\")\n\t}\n\tctx.WriteKeyWord(\" INTO TABLE \")\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore LoadDataStmt.Table\")\n\t}\n\tn.FieldsInfo.Restore(ctx)\n\tn.LinesInfo.Restore(ctx)\n\tif n.IgnoreLines != 0 {\n\t\tctx.WriteKeyWord(\" IGNORE \")\n\t\tctx.WritePlainf(\"%d\", n.IgnoreLines)\n\t\tctx.WriteKeyWord(\" LINES\")\n\t}\n\tif len(n.ColumnsAndUserVars) != 0 {\n\t\tctx.WritePlain(\" (\")\n\t\tfor i, c := range n.ColumnsAndUserVars {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif c.ColumnName != nil {\n\t\t\t\tif err := c.ColumnName.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore LoadDataStmt.ColumnsAndUserVars\")\n\t\t\t\t}\n\t\t\t}\n\t\t\tif c.UserVar != nil {\n\t\t\t\tif err := c.UserVar.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore LoadDataStmt.ColumnsAndUserVars\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\n\tif n.ColumnAssignments != nil {\n\t\tctx.WriteKeyWord(\" SET\")\n\t\tfor i, assign := range n.ColumnAssignments {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tctx.WritePlain(\" \")\n\t\t\tif err := assign.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore LoadDataStmt.ColumnAssignments\")\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *LoadDataStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*LoadDataStmt)\n\tif n.Table != nil {\n\t\tnode, ok := n.Table.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Table = node.(*TableName)\n\t}\n\tfor i, val := range n.Columns {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Columns[i] = node.(*ColumnName)\n\t}\n\n\tfor i, assignment := range n.ColumnAssignments {\n\t\tnode, ok := assignment.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.ColumnAssignments[i] = node.(*Assignment)\n\t}\n\treturn v.Leave(n)\n}\n\nconst (\n\tTerminated = iota\n\tEnclosed\n\tEscaped\n)\n\ntype FieldItem struct {\n\tType        int\n\tValue       string\n\tOptEnclosed bool\n}\n\n// FieldsClause represents fields references clause in load data statement.\ntype FieldsClause struct {\n\tTerminated  string\n\tEnclosed    byte\n\tEscaped     byte\n\tOptEnclosed bool\n}\n\n// Restore for FieldsClause\nfunc (n *FieldsClause) Restore(ctx *RestoreCtx) error {\n\tif n.Terminated != \"\\t\" || n.Escaped != '\\\\' {\n\t\tctx.WriteKeyWord(\" FIELDS\")\n\t\tif n.Terminated != \"\\t\" {\n\t\t\tctx.WriteKeyWord(\" TERMINATED BY \")\n\t\t\tctx.WriteString(n.Terminated)\n\t\t}\n\t\tif n.Enclosed != 0 {\n\t\t\tif n.OptEnclosed {\n\t\t\t\tctx.WriteKeyWord(\" OPTIONALLY\")\n\t\t\t}\n\t\t\tctx.WriteKeyWord(\" ENCLOSED BY \")\n\t\t\tctx.WriteString(string(n.Enclosed))\n\t\t}\n\t\tif n.Escaped != '\\\\' {\n\t\t\tctx.WriteKeyWord(\" ESCAPED BY \")\n\t\t\tif n.Escaped == 0 {\n\t\t\t\tctx.WritePlain(\"''\")\n\t\t\t} else {\n\t\t\t\tctx.WriteString(string(n.Escaped))\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// LinesClause represents lines references clause in load data statement.\ntype LinesClause struct {\n\tStarting   string\n\tTerminated string\n}\n\n// Restore for LinesClause\nfunc (n *LinesClause) Restore(ctx *RestoreCtx) error {\n\tif n.Starting != \"\" || n.Terminated != \"\\n\" {\n\t\tctx.WriteKeyWord(\" LINES\")\n\t\tif n.Starting != \"\" {\n\t\t\tctx.WriteKeyWord(\" STARTING BY \")\n\t\t\tctx.WriteString(n.Starting)\n\t\t}\n\t\tif n.Terminated != \"\\n\" {\n\t\t\tctx.WriteKeyWord(\" TERMINATED BY \")\n\t\t\tctx.WriteString(n.Terminated)\n\t\t}\n\t}\n\treturn nil\n}\n\n// InsertStmt is a statement to insert new rows into an existing table.\n// See https://dev.mysql.com/doc/refman/5.7/en/insert.html\ntype InsertStmt struct {\n\tdmlNode\n\n\tIsReplace   bool\n\tIgnoreErr   bool\n\tTable       *TableRefsClause\n\tColumns     []*ColumnName\n\tLists       [][]ExprNode\n\tSetlist     []*Assignment\n\tPriority    mysql.PriorityEnum\n\tOnDuplicate []*Assignment\n\tSelect      ResultSetNode\n}\n\n// Restore implements Node interface.\nfunc (n *InsertStmt) Restore(ctx *RestoreCtx) error {\n\tif n.IsReplace {\n\t\tctx.WriteKeyWord(\"REPLACE \")\n\t} else {\n\t\tctx.WriteKeyWord(\"INSERT \")\n\t}\n\tif n.Priority != mysql.NoPriority {\n\t\tctx.WritePlain(\" \")\n\t}\n\tif n.IgnoreErr {\n\t\tctx.WriteKeyWord(\"IGNORE \")\n\t}\n\tctx.WriteKeyWord(\"INTO \")\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore InsertStmt.Table\")\n\t}\n\tif n.Columns != nil {\n\t\tctx.WritePlain(\" (\")\n\t\tfor i, v := range n.Columns {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore InsertStmt.Columns[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\tif n.Lists != nil {\n\t\tctx.WriteKeyWord(\" VALUES \")\n\t\tfor i, row := range n.Lists {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tctx.WritePlain(\"(\")\n\t\t\tfor j, v := range row {\n\t\t\t\tif j != 0 {\n\t\t\t\t\tctx.WritePlain(\",\")\n\t\t\t\t}\n\t\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore InsertStmt.Lists[%d][%d]\", i, j)\n\t\t\t\t}\n\t\t\t}\n\t\t\tctx.WritePlain(\")\")\n\t\t}\n\t}\n\tif n.Select != nil {\n\t\tctx.WritePlain(\" \")\n\t\tswitch v := n.Select.(type) {\n\t\tcase *SelectStmt, *UnionStmt:\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore InsertStmt.Select\")\n\t\t\t}\n\t\tdefault:\n\t\t\treturn errors.Errorf(\"Incorrect type for InsertStmt.Select: %T\", v)\n\t\t}\n\t}\n\tif n.Setlist != nil {\n\t\tctx.WriteKeyWord(\" SET \")\n\t\tfor i, v := range n.Setlist {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore InsertStmt.Setlist[%d]\", i)\n\t\t\t}\n\t\t}\n\t}\n\tif n.OnDuplicate != nil {\n\t\tctx.WriteKeyWord(\" ON DUPLICATE KEY UPDATE \")\n\t\tfor i, v := range n.OnDuplicate {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore InsertStmt.OnDuplicate[%d]\", i)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *InsertStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*InsertStmt)\n\tif n.Select != nil {\n\t\tnode, ok := n.Select.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Select = node.(ResultSetNode)\n\t}\n\n\t// NOTE(jingshi): avoid preprocess inserting table, it may not exist in project\n\t// node, ok := n.Table.Accept(v)\n\t// if !ok {\n\t// \treturn n, false\n\t// }\n\t// n.Table = node.(*TableRefsClause)\n\n\tfor i, val := range n.Columns {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Columns[i] = node.(*ColumnName)\n\t}\n\tfor i, list := range n.Lists {\n\t\tfor j, val := range list {\n\t\t\tnode, ok := val.Accept(v)\n\t\t\tif !ok {\n\t\t\t\treturn n, false\n\t\t\t}\n\t\t\tn.Lists[i][j] = node.(ExprNode)\n\t\t}\n\t}\n\tfor i, val := range n.Setlist {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Setlist[i] = node.(*Assignment)\n\t}\n\tfor i, val := range n.OnDuplicate {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.OnDuplicate[i] = node.(*Assignment)\n\t}\n\treturn v.Leave(n)\n}\n\n// DeleteStmt is a statement to delete rows from table.\n// See https://dev.mysql.com/doc/refman/5.7/en/delete.html\ntype DeleteStmt struct {\n\tdmlNode\n\n\t// TableRefs is used in both single table and multiple table delete statement.\n\tTableRefs *TableRefsClause\n\t// Tables is only used in multiple table delete statement.\n\tTables       *DeleteTableList\n\tWhere        ExprNode\n\tOrder        *OrderByClause\n\tLimit        *Limit\n\tPriority     mysql.PriorityEnum\n\tIgnoreErr    bool\n\tQuick        bool\n\tIsMultiTable bool\n\tBeforeFrom   bool\n\t// TableHints represents the table level Optimizer Hint for join type.\n\tTableHints []*TableOptimizerHint\n}\n\n// Restore implements Node interface.\nfunc (n *DeleteStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"DELETE \")\n\n\tif n.TableHints != nil && len(n.TableHints) != 0 {\n\t\tctx.WritePlain(\"/*+ \")\n\t\tfor i, tableHint := range n.TableHints {\n\t\t\tif err := tableHint.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore UpdateStmt.TableHints[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\"*/ \")\n\t}\n\n\tif n.Priority != mysql.NoPriority {\n\t\tctx.WritePlain(\" \")\n\t}\n\tif n.Quick {\n\t\tctx.WriteKeyWord(\"QUICK \")\n\t}\n\tif n.IgnoreErr {\n\t\tctx.WriteKeyWord(\"IGNORE \")\n\t}\n\n\tif n.IsMultiTable { // Multiple-Table Syntax\n\t\tif n.BeforeFrom {\n\t\t\tif err := n.Tables.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore DeleteStmt.Tables\")\n\t\t\t}\n\n\t\t\tctx.WriteKeyWord(\" FROM \")\n\t\t\tif err := n.TableRefs.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore DeleteStmt.TableRefs\")\n\t\t\t}\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\"FROM \")\n\t\t\tif err := n.Tables.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore DeleteStmt.Tables\")\n\t\t\t}\n\n\t\t\tctx.WriteKeyWord(\" USING \")\n\t\t\tif err := n.TableRefs.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore DeleteStmt.TableRefs\")\n\t\t\t}\n\t\t}\n\t} else { // Single-Table Syntax\n\t\tctx.WriteKeyWord(\"FROM \")\n\n\t\tif err := n.TableRefs.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore DeleteStmt.TableRefs\")\n\t\t}\n\t}\n\n\tif n.Where != nil {\n\t\tctx.WriteKeyWord(\" WHERE \")\n\t\tif err := n.Where.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore DeleteStmt.Where\")\n\t\t}\n\t}\n\n\tif n.Order != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Order.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore DeleteStmt.Order\")\n\t\t}\n\t}\n\n\tif n.Limit != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Limit.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore DeleteStmt.Limit\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DeleteStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*DeleteStmt)\n\tnode, ok := n.TableRefs.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.TableRefs = node.(*TableRefsClause)\n\n\tif n.Tables != nil {\n\t\tnode, ok = n.Tables.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Tables = node.(*DeleteTableList)\n\t}\n\n\tif n.Where != nil {\n\t\tnode, ok = n.Where.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Where = node.(ExprNode)\n\t}\n\tif n.Order != nil {\n\t\tnode, ok = n.Order.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Order = node.(*OrderByClause)\n\t}\n\tif n.Limit != nil {\n\t\tnode, ok = n.Limit.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Limit = node.(*Limit)\n\t}\n\treturn v.Leave(n)\n}\n\n// UpdateStmt is a statement to update columns of existing rows in tables with new values.\n// See https://dev.mysql.com/doc/refman/5.7/en/update.html\ntype UpdateStmt struct {\n\tdmlNode\n\n\tTableRefs     *TableRefsClause\n\tList          []*Assignment\n\tWhere         ExprNode\n\tOrder         *OrderByClause\n\tLimit         *Limit\n\tPriority      mysql.PriorityEnum\n\tIgnoreErr     bool\n\tMultipleTable bool\n\tTableHints    []*TableOptimizerHint\n}\n\n// Restore implements Node interface.\nfunc (n *UpdateStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"UPDATE \")\n\n\tif n.TableHints != nil && len(n.TableHints) != 0 {\n\t\tctx.WritePlain(\"/*+ \")\n\t\tfor i, tableHint := range n.TableHints {\n\t\t\tif err := tableHint.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore UpdateStmt.TableHints[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\"*/ \")\n\t}\n\n\tif n.Priority != mysql.NoPriority {\n\t\tctx.WritePlain(\" \")\n\t}\n\tif n.IgnoreErr {\n\t\tctx.WriteKeyWord(\"IGNORE \")\n\t}\n\n\tif err := n.TableRefs.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occur while restore UpdateStmt.TableRefs\")\n\t}\n\n\tctx.WriteKeyWord(\" SET \")\n\tfor i, assignment := range n.List {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\n\t\tif err := assignment.Column.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occur while restore UpdateStmt.List[%d].Column\", i)\n\t\t}\n\n\t\tctx.WritePlain(\"=\")\n\n\t\tif err := assignment.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occur while restore UpdateStmt.List[%d].Expr\", i)\n\t\t}\n\t}\n\n\tif n.Where != nil {\n\t\tctx.WriteKeyWord(\" WHERE \")\n\t\tif err := n.Where.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occur while restore UpdateStmt.Where\")\n\t\t}\n\t}\n\n\tif n.Order != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Order.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occur while restore UpdateStmt.Order\")\n\t\t}\n\t}\n\n\tif n.Limit != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Limit.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occur while restore UpdateStmt.Limit\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *UpdateStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*UpdateStmt)\n\tnode, ok := n.TableRefs.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.TableRefs = node.(*TableRefsClause)\n\tfor i, val := range n.List {\n\t\tnode, ok = val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.List[i] = node.(*Assignment)\n\t}\n\tif n.Where != nil {\n\t\tnode, ok = n.Where.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Where = node.(ExprNode)\n\t}\n\tif n.Order != nil {\n\t\tnode, ok = n.Order.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Order = node.(*OrderByClause)\n\t}\n\tif n.Limit != nil {\n\t\tnode, ok = n.Limit.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Limit = node.(*Limit)\n\t}\n\treturn v.Leave(n)\n}\n\n// Limit is the limit clause.\ntype Limit struct {\n\tnode\n\n\tCount  ExprNode\n\tOffset ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *Limit) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"LIMIT \")\n\tif err := n.Count.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore Limit.Count\")\n\t}\n\tif n.Offset != nil {\n\t\tctx.WriteKeyWord(\" OFFSET \")\n\t\tif err := n.Offset.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore Limit.Offset\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *Limit) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tif n.Count != nil {\n\t\tnode, ok := n.Count.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Count = node.(ExprNode)\n\t}\n\tif n.Offset != nil {\n\t\tnode, ok := n.Offset.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Offset = node.(ExprNode)\n\t}\n\n\tn = newNode.(*Limit)\n\treturn v.Leave(n)\n}\n\n// ShowStmtType is the type for SHOW statement.\ntype ShowStmtType int\n\n// Show statement types.\nconst (\n\tShowNone = iota\n\tShowEngines\n\tShowDatabases\n\tShowTables\n\tShowTableStatus\n\tShowColumns\n\tShowWarnings\n\tShowCharset\n\tShowVariables\n\tShowStatus\n\tShowCollation\n\tShowCreateTable\n\tShowCreateView\n\tShowCreateUser\n\tShowCreateSequence\n\tShowGrants\n\tShowTriggers\n\tShowProcedureStatus\n\tShowIndex\n\tShowProcessList\n\tShowCreateDatabase\n\tShowEvents\n\tShowStatsMeta\n\tShowStatsHistograms\n\tShowStatsBuckets\n\tShowStatsHealthy\n\tShowPlugins\n\tShowProfile\n\tShowProfiles\n\tShowMasterStatus\n\tShowPrivileges\n\tShowErrors\n\tShowBindings\n\tShowPumpStatus\n\tShowDrainerStatus\n\tShowOpenTables\n\tShowAnalyzeStatus\n\tShowRegions\n\tShowBuiltins\n)\n\nconst (\n\tProfileTypeInvalid = iota\n\tProfileTypeCPU\n\tProfileTypeMemory\n\tProfileTypeBlockIo\n\tProfileTypeContextSwitch\n\tProfileTypePageFaults\n\tProfileTypeIpc\n\tProfileTypeSwaps\n\tProfileTypeSource\n\tProfileTypeAll\n)\n\n// ShowStmt is a statement to provide information about databases, tables, columns and so on.\n// See https://dev.mysql.com/doc/refman/5.7/en/show.html\ntype ShowStmt struct {\n\tdmlNode\n\tresultSetNode\n\n\tTp          ShowStmtType // Databases/Tables/Columns/....\n\tDBName      string\n\tTable       *TableName  // Used for showing columns.\n\tColumn      *ColumnName // Used for `desc table column`.\n\tIndexName   model.CIStr\n\tFlag        int // Some flag parsed from sql, such as FULL.\n\tFull        bool\n\tUser        *auth.UserIdentity   // Used for show grants/create user.\n\tRoles       []*auth.RoleIdentity // Used for show grants .. using\n\tIfNotExists bool                 // Used for `show create database if not exists`\n\tExtended    bool                 // Used for `show extended columns from ...`\n\n\t// GlobalScope is used by `show variables` and `show bindings`\n\tGlobalScope bool\n\tPattern     *PatternLikeExpr\n\tWhere       ExprNode\n\n\tShowProfileTypes []int  // Used for `SHOW PROFILE` syntax\n\tShowProfileArgs  *int64 // Used for `SHOW PROFILE` syntax\n\tShowProfileLimit *Limit // Used for `SHOW PROFILE` syntax\n}\n\n// Restore implements Node interface.\nfunc (n *ShowStmt) Restore(ctx *RestoreCtx) error {\n\trestoreOptFull := func() {\n\t\tif n.Full {\n\t\t\tctx.WriteKeyWord(\"FULL \")\n\t\t}\n\t}\n\trestoreShowDatabaseNameOpt := func() {\n\t\tif n.DBName != \"\" {\n\t\t\t// FROM OR IN\n\t\t\tctx.WriteKeyWord(\" IN \")\n\t\t\tctx.WriteName(n.DBName)\n\t\t}\n\t}\n\trestoreGlobalScope := func() {\n\t\tif n.GlobalScope {\n\t\t\tctx.WriteKeyWord(\"GLOBAL \")\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\"SESSION \")\n\t\t}\n\t}\n\trestoreShowLikeOrWhereOpt := func() error {\n\t\tif n.Pattern != nil && n.Pattern.Pattern != nil {\n\t\t\tctx.WriteKeyWord(\" LIKE \")\n\t\t\tif err := n.Pattern.Pattern.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore ShowStmt.Pattern\")\n\t\t\t}\n\t\t} else if n.Where != nil {\n\t\t\tctx.WriteKeyWord(\" WHERE \")\n\t\t\tif err := n.Where.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore ShowStmt.Where\")\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\n\tctx.WriteKeyWord(\"SHOW \")\n\tswitch n.Tp {\n\tcase ShowCreateTable:\n\t\tctx.WriteKeyWord(\"CREATE TABLE \")\n\t\tif err := n.Table.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore ShowStmt.Table\")\n\t\t}\n\tcase ShowCreateView:\n\t\tctx.WriteKeyWord(\"CREATE VIEW \")\n\t\tif err := n.Table.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore ShowStmt.VIEW\")\n\t\t}\n\tcase ShowCreateDatabase:\n\t\tctx.WriteKeyWord(\"CREATE DATABASE \")\n\t\tif n.IfNotExists {\n\t\t\tctx.WriteKeyWord(\"IF NOT EXISTS \")\n\t\t}\n\t\tctx.WriteName(n.DBName)\n\tcase ShowCreateSequence:\n\t\tctx.WriteKeyWord(\"CREATE SEQUENCE \")\n\t\tif err := n.Table.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore ShowStmt.SEQUENCE\")\n\t\t}\n\tcase ShowCreateUser:\n\t\tctx.WriteKeyWord(\"CREATE USER \")\n\t\tif err := n.User.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore ShowStmt.User\")\n\t\t}\n\tcase ShowGrants:\n\t\tctx.WriteKeyWord(\"GRANTS\")\n\t\tctx.WriteKeyWord(\" ON \")\n\t\tctx.WriteKeyWord(n.DBName)\n\t\tif n.User != nil {\n\t\t\tctx.WriteKeyWord(\" FOR \")\n\t\t\tif err := n.User.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore ShowStmt.User\")\n\t\t\t}\n\t\t}\n\t\tif n.Roles != nil {\n\t\t\tctx.WriteKeyWord(\" USING \")\n\t\t\tfor i, r := range n.Roles {\n\t\t\t\tif err := r.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore ShowStmt.User\")\n\t\t\t\t}\n\t\t\t\tif i != len(n.Roles)-1 {\n\t\t\t\t\tctx.WritePlain(\", \")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase ShowMasterStatus:\n\t\tctx.WriteKeyWord(\"MASTER STATUS\")\n\tcase ShowProcessList:\n\t\trestoreOptFull()\n\t\tctx.WriteKeyWord(\"PROCESSLIST\")\n\tcase ShowStatsMeta:\n\t\tctx.WriteKeyWord(\"STATS_META\")\n\t\tif err := restoreShowLikeOrWhereOpt(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase ShowStatsHistograms:\n\t\tctx.WriteKeyWord(\"STATS_HISTOGRAMS\")\n\t\tif err := restoreShowLikeOrWhereOpt(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase ShowStatsBuckets:\n\t\tctx.WriteKeyWord(\"STATS_BUCKETS\")\n\t\tif err := restoreShowLikeOrWhereOpt(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase ShowStatsHealthy:\n\t\tctx.WriteKeyWord(\"STATS_HEALTHY\")\n\t\tif err := restoreShowLikeOrWhereOpt(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase ShowProfiles:\n\t\tctx.WriteKeyWord(\"PROFILES\")\n\tcase ShowProfile:\n\t\tctx.WriteKeyWord(\"PROFILE\")\n\t\tif len(n.ShowProfileTypes) > 0 {\n\t\t\tfor i, tp := range n.ShowProfileTypes {\n\t\t\t\tif i != 0 {\n\t\t\t\t\tctx.WritePlain(\",\")\n\t\t\t\t}\n\t\t\t\tctx.WritePlain(\" \")\n\t\t\t\tswitch tp {\n\t\t\t\tcase ProfileTypeCPU:\n\t\t\t\t\tctx.WriteKeyWord(\"CPU\")\n\t\t\t\tcase ProfileTypeMemory:\n\t\t\t\t\tctx.WriteKeyWord(\"MEMORY\")\n\t\t\t\tcase ProfileTypeBlockIo:\n\t\t\t\t\tctx.WriteKeyWord(\"BLOCK IO\")\n\t\t\t\tcase ProfileTypeContextSwitch:\n\t\t\t\t\tctx.WriteKeyWord(\"CONTEXT SWITCHES\")\n\t\t\t\tcase ProfileTypeIpc:\n\t\t\t\t\tctx.WriteKeyWord(\"IPC\")\n\t\t\t\tcase ProfileTypePageFaults:\n\t\t\t\t\tctx.WriteKeyWord(\"PAGE FAULTS\")\n\t\t\t\tcase ProfileTypeSource:\n\t\t\t\t\tctx.WriteKeyWord(\"SOURCE\")\n\t\t\t\tcase ProfileTypeSwaps:\n\t\t\t\t\tctx.WriteKeyWord(\"SWAPS\")\n\t\t\t\tcase ProfileTypeAll:\n\t\t\t\t\tctx.WriteKeyWord(\"ALL\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif n.ShowProfileArgs != nil {\n\t\t\tctx.WriteKeyWord(\" FOR QUERY \")\n\t\t\tctx.WritePlainf(\"%d\", *n.ShowProfileArgs)\n\t\t}\n\t\tif n.ShowProfileLimit != nil {\n\t\t\tctx.WritePlain(\" \")\n\t\t\tif err := n.ShowProfileLimit.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore ShowStmt.WritePlain\")\n\t\t\t}\n\t\t}\n\n\tcase ShowPrivileges:\n\t\tctx.WriteKeyWord(\"PRIVILEGES\")\n\tcase ShowBuiltins:\n\t\tctx.WriteKeyWord(\"BUILTINS\")\n\t// ShowTargetFilterable\n\tdefault:\n\t\tswitch n.Tp {\n\t\tcase ShowEngines:\n\t\t\tctx.WriteKeyWord(\"ENGINES\")\n\t\tcase ShowDatabases:\n\t\t\tctx.WriteKeyWord(\"DATABASES\")\n\t\tcase ShowCharset:\n\t\t\tctx.WriteKeyWord(\"CHARSET\")\n\t\tcase ShowTables:\n\t\t\trestoreOptFull()\n\t\t\tctx.WriteKeyWord(\"TABLES\")\n\t\t\trestoreShowDatabaseNameOpt()\n\t\tcase ShowOpenTables:\n\t\t\tctx.WriteKeyWord(\"OPEN TABLES\")\n\t\t\trestoreShowDatabaseNameOpt()\n\t\tcase ShowTableStatus:\n\t\t\tctx.WriteKeyWord(\"TABLE STATUS\")\n\t\t\trestoreShowDatabaseNameOpt()\n\t\tcase ShowIndex:\n\t\t\t// here can be INDEX INDEXES KEYS\n\t\t\t// FROM or IN\n\t\t\tctx.WriteKeyWord(\"INDEX IN \")\n\t\t\tif err := n.Table.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while resotre ShowStmt.Table\")\n\t\t\t} // TODO: remember to check this case\n\t\tcase ShowColumns: // equivalent to SHOW FIELDS\n\t\t\tif n.Extended {\n\t\t\t\tctx.WriteKeyWord(\"EXTENDED \")\n\t\t\t}\n\t\t\trestoreOptFull()\n\t\t\tctx.WriteKeyWord(\"COLUMNS\")\n\t\t\tif n.Table != nil {\n\t\t\t\t// FROM or IN\n\t\t\t\tctx.WriteKeyWord(\" IN \")\n\t\t\t\tif err := n.Table.Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotate(err, \"An error occurred while resotre ShowStmt.Table\")\n\t\t\t\t}\n\t\t\t}\n\t\t\trestoreShowDatabaseNameOpt()\n\t\tcase ShowWarnings:\n\t\t\tctx.WriteKeyWord(\"WARNINGS\")\n\t\tcase ShowErrors:\n\t\t\tctx.WriteKeyWord(\"ERRORS\")\n\t\tcase ShowVariables:\n\t\t\trestoreGlobalScope()\n\t\t\tctx.WriteKeyWord(\"VARIABLES\")\n\t\tcase ShowStatus:\n\t\t\trestoreGlobalScope()\n\t\t\tctx.WriteKeyWord(\"STATUS\")\n\t\tcase ShowCollation:\n\t\t\tctx.WriteKeyWord(\"COLLATION\")\n\t\tcase ShowTriggers:\n\t\t\tctx.WriteKeyWord(\"TRIGGERS\")\n\t\t\trestoreShowDatabaseNameOpt()\n\t\tcase ShowProcedureStatus:\n\t\t\tctx.WriteKeyWord(\"PROCEDURE STATUS\")\n\t\tcase ShowEvents:\n\t\t\tctx.WriteKeyWord(\"EVENTS\")\n\t\t\trestoreShowDatabaseNameOpt()\n\t\tcase ShowPlugins:\n\t\t\tctx.WriteKeyWord(\"PLUGINS\")\n\t\tcase ShowBindings:\n\t\t\tif n.GlobalScope {\n\t\t\t\tctx.WriteKeyWord(\"GLOBAL \")\n\t\t\t} else {\n\t\t\t\tctx.WriteKeyWord(\"SESSION \")\n\t\t\t}\n\t\t\tctx.WriteKeyWord(\"BINDINGS\")\n\t\tcase ShowPumpStatus:\n\t\t\tctx.WriteKeyWord(\"PUMP STATUS\")\n\t\tcase ShowDrainerStatus:\n\t\t\tctx.WriteKeyWord(\"DRAINER STATUS\")\n\t\tcase ShowAnalyzeStatus:\n\t\t\tctx.WriteKeyWord(\"ANALYZE STATUS\")\n\t\tcase ShowRegions:\n\t\t\tctx.WriteKeyWord(\"TABLE \")\n\t\t\tif err := n.Table.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore SplitIndexRegionStmt.Table\")\n\t\t\t}\n\t\t\tif len(n.IndexName.L) > 0 {\n\t\t\t\tctx.WriteKeyWord(\" INDEX \")\n\t\t\t\tctx.WriteName(n.IndexName.String())\n\t\t\t}\n\t\t\tctx.WriteKeyWord(\" REGIONS\")\n\t\t\tif err := restoreShowLikeOrWhereOpt(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\tdefault:\n\t\t\treturn errors.New(\"Unknown ShowStmt type\")\n\t\t}\n\t\trestoreShowLikeOrWhereOpt()\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ShowStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ShowStmt)\n\tif n.Table != nil {\n\t\tnode, ok := n.Table.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Table = node.(*TableName)\n\t}\n\tif n.Column != nil {\n\t\tnode, ok := n.Column.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Column = node.(*ColumnName)\n\t}\n\tif n.Pattern != nil {\n\t\tnode, ok := n.Pattern.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Pattern = node.(*PatternLikeExpr)\n\t}\n\n\tswitch n.Tp {\n\tcase ShowTriggers, ShowProcedureStatus, ShowProcessList, ShowEvents:\n\t\t// We don't have any data to return for those types,\n\t\t// but visiting Where may cause resolving error, so return here to avoid error.\n\t\treturn v.Leave(n)\n\t}\n\n\tif n.Where != nil {\n\t\tnode, ok := n.Where.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Where = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// WindowSpec is the specification of a window.\ntype WindowSpec struct {\n\tnode\n\n\tName model.CIStr\n\t// Ref is the reference window of this specification. For example, in `w2 as (w1 order by a)`,\n\t// the definition of `w2` references `w1`.\n\tRef model.CIStr\n\n\tPartitionBy *PartitionByClause\n\tOrderBy     *OrderByClause\n\tFrame       *FrameClause\n\n\t// OnlyAlias will set to true of the first following case.\n\t// To make compatible with MySQL, we need to distinguish `select func over w` from `select func over (w)`.\n\tOnlyAlias bool\n}\n\n// Restore implements Node interface.\nfunc (n *WindowSpec) Restore(ctx *RestoreCtx) error {\n\tif name := n.Name.String(); name != \"\" {\n\t\tctx.WriteName(name)\n\t\tif n.OnlyAlias {\n\t\t\treturn nil\n\t\t}\n\t\tctx.WriteKeyWord(\" AS \")\n\t}\n\tctx.WritePlain(\"(\")\n\tsep := \"\"\n\tif refName := n.Ref.String(); refName != \"\" {\n\t\tctx.WriteName(refName)\n\t\tsep = \" \"\n\t}\n\tif n.PartitionBy != nil {\n\t\tctx.WritePlain(sep)\n\t\tif err := n.PartitionBy.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore WindowSpec.PartitionBy\")\n\t\t}\n\t\tsep = \" \"\n\t}\n\tif n.OrderBy != nil {\n\t\tctx.WritePlain(sep)\n\t\tif err := n.OrderBy.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore WindowSpec.OrderBy\")\n\t\t}\n\t\tsep = \" \"\n\t}\n\tif n.Frame != nil {\n\t\tctx.WritePlain(sep)\n\t\tif err := n.Frame.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore WindowSpec.Frame\")\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *WindowSpec) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*WindowSpec)\n\tif n.PartitionBy != nil {\n\t\tnode, ok := n.PartitionBy.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.PartitionBy = node.(*PartitionByClause)\n\t}\n\tif n.OrderBy != nil {\n\t\tnode, ok := n.OrderBy.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.OrderBy = node.(*OrderByClause)\n\t}\n\tif n.Frame != nil {\n\t\tnode, ok := n.Frame.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Frame = node.(*FrameClause)\n\t}\n\treturn v.Leave(n)\n}\n\ntype SelectIntoType int\n\nconst (\n\tSelectIntoOutfile SelectIntoType = iota + 1\n\tSelectIntoDumpfile\n\tSelectIntoVars\n)\n\ntype SelectIntoOption struct {\n\tnode\n\n\tTp         SelectIntoType\n\tPartyFiles []*PartyFile\n\tFieldsInfo *FieldsClause\n\tLinesInfo  *LinesClause\n}\n\n// Restore implements Node interface.\nfunc (n *SelectIntoOption) Restore(ctx *RestoreCtx) error {\n\tif n.Tp != SelectIntoOutfile {\n\t\t// only support SELECT ... INTO OUTFILE now\n\t\treturn errors.New(\"Unsupported SelectionInto type\")\n\t}\n\n\tctx.WriteKeyWord(\"INTO OUTFILE\")\n\tif n.PartyFiles != nil {\n\t\tfor i, partyFile := range n.PartyFiles {\n\t\t\tctx.WriteKeyWord(\" \")\n\t\t\tif err := partyFile.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore UpdateStmt.TableHints[%d]\", i)\n\t\t\t}\n\t\t}\n\t}\n\n\tif n.FieldsInfo != nil {\n\t\tif err := n.FieldsInfo.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectInto.FieldsInfo\")\n\t\t}\n\t}\n\tif n.LinesInfo != nil {\n\t\tif err := n.LinesInfo.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SelectInto.LinesInfo\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *SelectIntoOption) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\treturn v.Leave(n)\n}\n\ntype PartyFile struct {\n\tPartyCode string\n\tFileName  string\n\tFieldList []*SelectField\n}\n\n// Restore implements Node interface.\nfunc (n *PartyFile) Restore(ctx *RestoreCtx) error {\n\tif n.PartyCode != \"\" {\n\t\tctx.WriteKeyWord(\"PARTY_CODE \")\n\t\tctx.WriteString(n.PartyCode)\n\t\tctx.WritePlain(\" \")\n\t}\n\tctx.WriteString(n.FileName)\n\treturn nil\n}\n\n// PartitionByClause represents partition by clause.\ntype PartitionByClause struct {\n\tnode\n\n\tItems []*ByItem\n}\n\n// Restore implements Node interface.\nfunc (n *PartitionByClause) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"PARTITION BY \")\n\tfor i, v := range n.Items {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore PartitionByClause.Items[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *PartitionByClause) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*PartitionByClause)\n\tfor i, val := range n.Items {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Items[i] = node.(*ByItem)\n\t}\n\treturn v.Leave(n)\n}\n\n// FrameType is the type of window function frame.\ntype FrameType int\n\n// Window function frame types.\n// MySQL only supports `ROWS` and `RANGES`.\nconst (\n\tRows = iota\n\tRanges\n\tGroups\n)\n\n// FrameClause represents frame clause.\ntype FrameClause struct {\n\tnode\n\n\tType   FrameType\n\tExtent FrameExtent\n}\n\n// Restore implements Node interface.\nfunc (n *FrameClause) Restore(ctx *RestoreCtx) error {\n\tswitch n.Type {\n\tcase Rows:\n\t\tctx.WriteKeyWord(\"ROWS\")\n\tcase Ranges:\n\t\tctx.WriteKeyWord(\"RANGE\")\n\tdefault:\n\t\treturn errors.New(\"Unsupported window function frame type\")\n\t}\n\tctx.WriteKeyWord(\" BETWEEN \")\n\tif err := n.Extent.Start.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore FrameClause.Extent.Start\")\n\t}\n\tctx.WriteKeyWord(\" AND \")\n\tif err := n.Extent.End.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore FrameClause.Extent.End\")\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *FrameClause) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*FrameClause)\n\tnode, ok := n.Extent.Start.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Extent.Start = *node.(*FrameBound)\n\tnode, ok = n.Extent.End.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Extent.End = *node.(*FrameBound)\n\treturn v.Leave(n)\n}\n\n// FrameExtent represents frame extent.\ntype FrameExtent struct {\n\tStart FrameBound\n\tEnd   FrameBound\n}\n\n// FrameType is the type of window function frame bound.\ntype BoundType int\n\n// Frame bound types.\nconst (\n\tFollowing = iota\n\tPreceding\n\tCurrentRow\n)\n\n// FrameBound represents frame bound.\ntype FrameBound struct {\n\tnode\n\n\tType      BoundType\n\tUnBounded bool\n\tExpr      ExprNode\n\t// `Unit` is used to indicate the units in which the `Expr` should be interpreted.\n\t// For example: '2:30' MINUTE_SECOND.\n\tUnit TimeUnitType\n}\n\n// Restore implements Node interface.\nfunc (n *FrameBound) Restore(ctx *RestoreCtx) error {\n\tif n.UnBounded {\n\t\tctx.WriteKeyWord(\"UNBOUNDED\")\n\t}\n\tswitch n.Type {\n\tcase CurrentRow:\n\t\tctx.WriteKeyWord(\"CURRENT ROW\")\n\tcase Preceding, Following:\n\t\tif n.Unit != TimeUnitInvalid {\n\t\t\tctx.WriteKeyWord(\"INTERVAL \")\n\t\t}\n\t\tif n.Expr != nil {\n\t\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore FrameBound.Expr\")\n\t\t\t}\n\t\t}\n\t\tif n.Unit != TimeUnitInvalid {\n\t\t\tctx.WritePlain(\" \")\n\t\t\tctx.WriteKeyWord(n.Unit.String())\n\t\t}\n\t\tif n.Type == Preceding {\n\t\t\tctx.WriteKeyWord(\" PRECEDING\")\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\" FOLLOWING\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *FrameBound) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*FrameBound)\n\tif n.Expr != nil {\n\t\tnode, ok := n.Expr.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Expr = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\ntype SplitRegionStmt struct {\n\tdmlNode\n\n\tTable          *TableName\n\tIndexName      model.CIStr\n\tPartitionNames []model.CIStr\n\n\tSplitSyntaxOpt *SplitSyntaxOption\n\n\tSplitOpt *SplitOption\n}\n\ntype SplitOption struct {\n\tLower      []ExprNode\n\tUpper      []ExprNode\n\tNum        int64\n\tValueLists [][]ExprNode\n}\n\ntype SplitSyntaxOption struct {\n\tHasRegionFor bool\n\tHasPartition bool\n}\n\nfunc (n *SplitRegionStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"SPLIT \")\n\tif n.SplitSyntaxOpt != nil {\n\t\tif n.SplitSyntaxOpt.HasRegionFor {\n\t\t\tctx.WriteKeyWord(\"REGION FOR \")\n\t\t}\n\t\tif n.SplitSyntaxOpt.HasPartition {\n\t\t\tctx.WriteKeyWord(\"PARTITION \")\n\n\t\t}\n\t}\n\tctx.WriteKeyWord(\"TABLE \")\n\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore SplitIndexRegionStmt.Table\")\n\t}\n\tif len(n.PartitionNames) > 0 {\n\t\tctx.WriteKeyWord(\" PARTITION\")\n\t\tctx.WritePlain(\"(\")\n\t\tfor i, v := range n.PartitionNames {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tctx.WriteName(v.String())\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\n\tif len(n.IndexName.L) > 0 {\n\t\tctx.WriteKeyWord(\" INDEX \")\n\t\tctx.WriteName(n.IndexName.String())\n\t}\n\tctx.WritePlain(\" \")\n\terr := n.SplitOpt.Restore(ctx)\n\treturn err\n}\n\nfunc (n *SplitRegionStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*SplitRegionStmt)\n\tnode, ok := n.Table.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Table = node.(*TableName)\n\tfor i, val := range n.SplitOpt.Lower {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.SplitOpt.Lower[i] = node.(ExprNode)\n\t}\n\tfor i, val := range n.SplitOpt.Upper {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.SplitOpt.Upper[i] = node.(ExprNode)\n\t}\n\n\tfor i, list := range n.SplitOpt.ValueLists {\n\t\tfor j, val := range list {\n\t\t\tnode, ok := val.Accept(v)\n\t\t\tif !ok {\n\t\t\t\treturn n, false\n\t\t\t}\n\t\t\tn.SplitOpt.ValueLists[i][j] = node.(ExprNode)\n\t\t}\n\t}\n\treturn v.Leave(n)\n}\n\nfunc (n *SplitOption) Restore(ctx *RestoreCtx) error {\n\tif len(n.ValueLists) == 0 {\n\t\tctx.WriteKeyWord(\"BETWEEN \")\n\t\tctx.WritePlain(\"(\")\n\t\tfor j, v := range n.Lower {\n\t\t\tif j != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore SplitOption Lower\")\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\n\t\tctx.WriteKeyWord(\" AND \")\n\t\tctx.WritePlain(\"(\")\n\t\tfor j, v := range n.Upper {\n\t\t\tif j != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore SplitOption Upper\")\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t\tctx.WriteKeyWord(\" REGIONS\")\n\t\tctx.WritePlainf(\" %d\", n.Num)\n\t\treturn nil\n\t}\n\tctx.WriteKeyWord(\"BY \")\n\tfor i, row := range n.ValueLists {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t\tctx.WritePlain(\"(\")\n\t\tfor j, v := range row {\n\t\t\tif j != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore SplitOption.ValueLists[%d][%d]\", i, j)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\treturn nil\n}\n\ntype FulltextSearchModifier int\n\nconst (\n\tFulltextSearchModifierNaturalLanguageMode = 0\n\tFulltextSearchModifierBooleanMode         = 1\n\tFulltextSearchModifierModeMask            = 0xF\n\tFulltextSearchModifierWithQueryExpansion  = 1 << 4\n)\n\nfunc (m FulltextSearchModifier) IsBooleanMode() bool {\n\treturn m&FulltextSearchModifierModeMask == FulltextSearchModifierBooleanMode\n}\n\nfunc (m FulltextSearchModifier) IsNaturalLanguageMode() bool {\n\treturn m&FulltextSearchModifierModeMask == FulltextSearchModifierNaturalLanguageMode\n}\n\nfunc (m FulltextSearchModifier) WithQueryExpansion() bool {\n\treturn m&FulltextSearchModifierWithQueryExpansion == FulltextSearchModifierWithQueryExpansion\n}\n\ntype TimestampBound struct {\n\tMode      TimestampBoundMode\n\tTimestamp ExprNode\n}\n\ntype TimestampBoundMode int\n\nconst (\n\tTimestampBoundStrong TimestampBoundMode = iota\n\tTimestampBoundMaxStaleness\n\tTimestampBoundExactStaleness\n\tTimestampBoundReadTimestamp\n\tTimestampBoundMinReadTimestamp\n)\n"
  },
  {
    "path": "pkg/parser/ast/dml_test.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast_test\n\nimport (\n\t. \"github.com/pingcap/check\"\n\n\t. \"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\nvar _ = Suite(&testDMLSuite{})\n\ntype testDMLSuite struct {\n}\n\nfunc (ts *testDMLSuite) TestDMLVisitorCover(c *C) {\n\tce := &checkExpr{}\n\n\ttableRefsClause := &TableRefsClause{TableRefs: &Join{Left: &TableSource{Source: &TableName{}}, On: &OnCondition{Expr: ce}}}\n\n\tstmts := []struct {\n\t\tnode             Node\n\t\texpectedEnterCnt int\n\t\texpectedLeaveCnt int\n\t}{\n\t\t{&DeleteStmt{TableRefs: tableRefsClause, Tables: &DeleteTableList{}, Where: ce,\n\t\t\tOrder: &OrderByClause{}, Limit: &Limit{Count: ce, Offset: ce}}, 4, 4},\n\t\t{&ShowStmt{Table: &TableName{}, Column: &ColumnName{}, Pattern: &PatternLikeExpr{Expr: ce, Pattern: ce}, Where: ce}, 3, 3},\n\t\t{&LoadDataStmt{Table: &TableName{}, Columns: []*ColumnName{{}}, FieldsInfo: &FieldsClause{}, LinesInfo: &LinesClause{}}, 0, 0},\n\t\t{&Assignment{Column: &ColumnName{}, Expr: ce}, 1, 1},\n\t\t{&ByItem{Expr: ce}, 1, 1},\n\t\t{&GroupByClause{Items: []*ByItem{{Expr: ce}, {Expr: ce}}}, 2, 2},\n\t\t{&HavingClause{Expr: ce}, 1, 1},\n\t\t{&Join{Left: &TableSource{Source: &TableName{}}}, 0, 0},\n\t\t{&Limit{Count: ce, Offset: ce}, 2, 2},\n\t\t{&OnCondition{Expr: ce}, 1, 1},\n\t\t{&OrderByClause{Items: []*ByItem{{Expr: ce}, {Expr: ce}}}, 2, 2},\n\t\t{&SelectField{Expr: ce, WildCard: &WildCardField{}}, 1, 1},\n\t\t{&TableName{}, 0, 0},\n\t\t{tableRefsClause, 1, 1},\n\t\t{&TableSource{Source: &TableName{}}, 0, 0},\n\t\t{&WildCardField{}, 0, 0},\n\t\t{&SelectIntoOption{Tp: SelectIntoOutfile, PartyFiles: []*PartyFile{{}, {}}, FieldsInfo: &FieldsClause{}, LinesInfo: &LinesClause{}}, 0, 0},\n\n\t\t// TODO: cover childrens\n\t\t{&InsertStmt{Table: tableRefsClause}, 0, 0},\n\t\t{&UnionStmt{}, 0, 0},\n\t\t{&UpdateStmt{TableRefs: tableRefsClause}, 1, 1},\n\t\t{&SelectStmt{}, 0, 0},\n\t\t{&FieldList{}, 0, 0},\n\t\t{&UnionSelectList{}, 0, 0},\n\t\t{&WindowSpec{}, 0, 0},\n\t\t{&PartitionByClause{}, 0, 0},\n\t\t{&FrameClause{}, 0, 0},\n\t\t{&FrameBound{}, 0, 0},\n\t}\n\n\tfor _, v := range stmts {\n\t\tce.reset()\n\t\tv.node.Accept(checkVisitor{})\n\t\tc.Check(ce.enterCnt, Equals, v.expectedEnterCnt)\n\t\tc.Check(ce.leaveCnt, Equals, v.expectedLeaveCnt)\n\t\tv.node.Accept(visitor1{})\n\t}\n}\n\nfunc (tc *testDMLSuite) TestSelectIntoRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"into outfile '/tmp/output.txt'\", \"INTO OUTFILE '/tmp/output.txt'\"},\n\t\t{\"into outfile party_code 'alice' '/tmp/output.txt' fields terminated BY ','\", \"INTO OUTFILE PARTY_CODE 'alice' '/tmp/output.txt' FIELDS TERMINATED BY ','\"},\n\t\t{\"into outfile party_code 'alice' '/tmp/output_alice.txt' party_code 'bob' '/tmp/output_bob.txt' columns terminated BY '|' optionally enclosed BY '\\\"' lines terminated BY 'end of line'\", \"INTO OUTFILE PARTY_CODE 'alice' '/tmp/output_alice.txt' PARTY_CODE 'bob' '/tmp/output_bob.txt' FIELDS TERMINATED BY '|' OPTIONALLY ENCLOSED BY '\\\"' LINES TERMINATED BY 'end of line'\"},\n\t\t{\"into outfile party_code 'alice' '/tmp/output_alice.txt' party_code 'bob' '/tmp/output_bob.txt' party_code 'carol' '/tmp/output_carol.txt'\", \"INTO OUTFILE PARTY_CODE 'alice' '/tmp/output_alice.txt' PARTY_CODE 'bob' '/tmp/output_bob.txt' PARTY_CODE 'carol' '/tmp/output_carol.txt'\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).SelectIntoOpt\n\t}\n\tRunNodeRestoreTest(c, testCases, \"SELECT * FROM t1 %s;\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestTableNameRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"dbb.`tbb1`\", \"`dbb`.`tbb1`\"},\n\t\t{\"`tbb2`\", \"`tbb2`\"},\n\t\t{\"tbb3\", \"`tbb3`\"},\n\t\t{\"dbb.`hello-world`\", \"`dbb`.`hello-world`\"},\n\t\t{\"`dbb`.`hello-world`\", \"`dbb`.`hello-world`\"},\n\t\t{\"`dbb.HelloWorld`\", \"`dbb.HelloWorld`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*CreateTableStmt).Table\n\t}\n\tRunNodeRestoreTest(c, testCases, \"CREATE TABLE %s (id INT NOT NULL);\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestTableNameIndexHintsRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"t use index (hello)\", \"`t` USE INDEX (`hello`)\"},\n\t\t{\"t use index (hello, world)\", \"`t` USE INDEX (`hello`, `world`)\"},\n\t\t{\"t use index ()\", \"`t` USE INDEX ()\"},\n\t\t{\"t use key ()\", \"`t` USE INDEX ()\"},\n\t\t{\"t ignore key ()\", \"`t` IGNORE INDEX ()\"},\n\t\t{\"t force key ()\", \"`t` FORCE INDEX ()\"},\n\t\t{\"t use index for order by (idx1)\", \"`t` USE INDEX FOR ORDER BY (`idx1`)\"},\n\n\t\t{\"t use index (hello, world, yes) force key (good)\", \"`t` USE INDEX (`hello`, `world`, `yes`) FORCE INDEX (`good`)\"},\n\t\t{\"t use index (hello, world, yes) use index for order by (good)\", \"`t` USE INDEX (`hello`, `world`, `yes`) USE INDEX FOR ORDER BY (`good`)\"},\n\t\t{\"t ignore key (hello, world, yes) force key (good)\", \"`t` IGNORE INDEX (`hello`, `world`, `yes`) FORCE INDEX (`good`)\"},\n\n\t\t{\"t use index for group by (idx1) use index for order by (idx2)\", \"`t` USE INDEX FOR GROUP BY (`idx1`) USE INDEX FOR ORDER BY (`idx2`)\"},\n\t\t{\"t use index for group by (idx1) ignore key for order by (idx2)\", \"`t` USE INDEX FOR GROUP BY (`idx1`) IGNORE INDEX FOR ORDER BY (`idx2`)\"},\n\t\t{\"t use index for group by (idx1) ignore key for group by (idx2)\", \"`t` USE INDEX FOR GROUP BY (`idx1`) IGNORE INDEX FOR GROUP BY (`idx2`)\"},\n\t\t{\"t use index for order by (idx1) ignore key for group by (idx2)\", \"`t` USE INDEX FOR ORDER BY (`idx1`) IGNORE INDEX FOR GROUP BY (`idx2`)\"},\n\n\t\t{\"t use index for order by (idx1) ignore key for group by (idx2) use index (idx3)\", \"`t` USE INDEX FOR ORDER BY (`idx1`) IGNORE INDEX FOR GROUP BY (`idx2`) USE INDEX (`idx3`)\"},\n\t\t{\"t use index for order by (idx1) ignore key for group by (idx2) use index (idx3)\", \"`t` USE INDEX FOR ORDER BY (`idx1`) IGNORE INDEX FOR GROUP BY (`idx2`) USE INDEX (`idx3`)\"},\n\n\t\t{\"t use index (`foo``bar`) force index (`baz``1`, `xyz`)\", \"`t` USE INDEX (`foo``bar`) FORCE INDEX (`baz``1`, `xyz`)\"},\n\t\t{\"t force index (`foo``bar`) ignore index (`baz``1`, xyz)\", \"`t` FORCE INDEX (`foo``bar`) IGNORE INDEX (`baz``1`, `xyz`)\"},\n\t\t{\"t ignore index (`foo``bar`) force key (`baz``1`, xyz)\", \"`t` IGNORE INDEX (`foo``bar`) FORCE INDEX (`baz``1`, `xyz`)\"},\n\t\t{\"t ignore index (`foo``bar`) ignore key for group by (`baz``1`, xyz)\", \"`t` IGNORE INDEX (`foo``bar`) IGNORE INDEX FOR GROUP BY (`baz``1`, `xyz`)\"},\n\t\t{\"t ignore index (`foo``bar`) ignore key for order by (`baz``1`, xyz)\", \"`t` IGNORE INDEX (`foo``bar`) IGNORE INDEX FOR ORDER BY (`baz``1`, `xyz`)\"},\n\n\t\t{\"t use index for group by (`foo``bar`) use index for order by (`baz``1`, `xyz`)\", \"`t` USE INDEX FOR GROUP BY (`foo``bar`) USE INDEX FOR ORDER BY (`baz``1`, `xyz`)\"},\n\t\t{\"t use index for group by (`foo``bar`) ignore key for order by (`baz``1`, `xyz`)\", \"`t` USE INDEX FOR GROUP BY (`foo``bar`) IGNORE INDEX FOR ORDER BY (`baz``1`, `xyz`)\"},\n\t\t{\"t use index for group by (`foo``bar`) ignore key for group by (`baz``1`, `xyz`)\", \"`t` USE INDEX FOR GROUP BY (`foo``bar`) IGNORE INDEX FOR GROUP BY (`baz``1`, `xyz`)\"},\n\t\t{\"t use index for order by (`foo``bar`) ignore key for group by (`baz``1`, `xyz`)\", \"`t` USE INDEX FOR ORDER BY (`foo``bar`) IGNORE INDEX FOR GROUP BY (`baz``1`, `xyz`)\"},\n\n\t\t{\"t tt use index for order by (`foo``bar`) ignore key for group by (`baz``1`, `xyz`)\", \"`t` AS `tt` USE INDEX FOR ORDER BY (`foo``bar`) IGNORE INDEX FOR GROUP BY (`baz``1`, `xyz`)\"},\n\t\t{\"t as tt use index for order by (`foo``bar`) ignore key for group by (`baz``1`, `xyz`)\", \"`t` AS `tt` USE INDEX FOR ORDER BY (`foo``bar`) IGNORE INDEX FOR GROUP BY (`baz``1`, `xyz`)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).From.TableRefs.Left\n\t}\n\tRunNodeRestoreTest(c, testCases, \"SELECT * FROM %s\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestLimitRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"limit 10\", \"LIMIT 10\"},\n\t\t{\"limit 10,20\", \"LIMIT 20 OFFSET 10\"},\n\t\t{\"limit 20 offset 10\", \"LIMIT 20 OFFSET 10\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Limit\n\t}\n\tRunNodeRestoreTest(c, testCases, \"SELECT 1 %s\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestWildCardFieldRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"*\", \"*\"},\n\t\t{\"t.*\", \"`t`.*\"},\n\t\t{\"testdb.t.*\", \"`testdb`.`t`.*\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].WildCard\n\t}\n\tRunNodeRestoreTest(c, testCases, \"SELECT %s\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestSelectFieldRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"*\", \"*\"},\n\t\t{\"t.*\", \"`t`.*\"},\n\t\t{\"testdb.t.*\", \"`testdb`.`t`.*\"},\n\t\t{\"col as a\", \"`col` AS `a`\"},\n\t\t{\"col + 1 a\", \"`col`+1 AS `a`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"SELECT %s\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestFieldListRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"*\", \"*\"},\n\t\t{\"t.*\", \"`t`.*\"},\n\t\t{\"testdb.t.*\", \"`testdb`.`t`.*\"},\n\t\t{\"col as a\", \"`col` AS `a`\"},\n\t\t{\"`t`.*, s.col as a\", \"`t`.*, `s`.`col` AS `a`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields\n\t}\n\tRunNodeRestoreTest(c, testCases, \"SELECT %s\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestTableSourceRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"tbl\", \"`tbl`\"},\n\t\t{\"tbl as t\", \"`tbl` AS `t`\"},\n\t\t{\"(select * from tbl) as t\", \"(SELECT * FROM `tbl`) AS `t`\"},\n\t\t{\"(select * from a union select * from b) as t\", \"(SELECT * FROM `a` UNION SELECT * FROM `b`) AS `t`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).From.TableRefs.Left\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select * from %s\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestOnConditionRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"on t1.a=t2.a\", \"ON `t1`.`a`=`t2`.`a`\"},\n\t\t{\"on t1.a=t2.a and t1.b=t2.b\", \"ON `t1`.`a`=`t2`.`a` AND `t1`.`b`=`t2`.`b`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).From.TableRefs.On\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select * from t1 join t2 %s\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestJoinRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"t1 natural join t2\", \"`t1` NATURAL JOIN `t2`\"},\n\t\t{\"t1 natural left join t2\", \"`t1` NATURAL JOIN `t2`\"},\n\t\t{\"t1 natural right outer join t2\", \"`t1` NATURAL JOIN `t2`\"},\n\t\t{\"t1 straight_join t2\", \"`t1` STRAIGHT_JOIN `t2`\"},\n\t\t{\"t1 straight_join t2 on t1.a>t2.a\", \"`t1` STRAIGHT_JOIN `t2` ON `t1`.`a`>`t2`.`a`\"},\n\t\t{\"t1 cross join t2\", \"`t1` JOIN `t2`\"},\n\t\t{\"t1 cross join t2 on t1.a>t2.a\", \"`t1` JOIN `t2` ON `t1`.`a`>`t2`.`a`\"},\n\t\t{\"t1 inner join t2 using (b)\", \"`t1` JOIN `t2` USING (`b`)\"},\n\t\t{\"t1 join t2 using (b,c) left join t3 on t1.a>t3.a\", \"(`t1` JOIN `t2` USING (`b`,`c`)) LEFT JOIN `t3` ON `t1`.`a`>`t3`.`a`\"},\n\t\t{\"t1 natural join t2 right outer join t3 using (b,c)\", \"(`t1` NATURAL JOIN `t2`) RIGHT JOIN `t3` USING (`b`,`c`)\"},\n\t\t{\"(a al left join b bl on al.a1 > bl.b1) join (a ar right join b br on ar.a1 > br.b1)\", \"(`a` AS `al` LEFT JOIN `b` AS `bl` ON `al`.`a1`>`bl`.`b1`) JOIN (`a` AS `ar` RIGHT JOIN `b` AS `br` ON `ar`.`a1`>`br`.`b1`)\"},\n\t\t{\"a al left join b bl on al.a1 > bl.b1, a ar right join b br on ar.a1 > br.b1\", \"(`a` AS `al` LEFT JOIN `b` AS `bl` ON `al`.`a1`>`bl`.`b1`) JOIN (`a` AS `ar` RIGHT JOIN `b` AS `br` ON `ar`.`a1`>`br`.`b1`)\"},\n\t\t{\"t1, t2\", \"`t1` JOIN `t2`\"},\n\t\t{\"t1, t2, t3\", \"(`t1` JOIN `t2`) JOIN `t3`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).From.TableRefs\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select * from %s\", extractNodeFunc)\n}\n\nfunc (ts *testDMLSuite) TestTableRefsClauseRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"t\", \"`t`\"},\n\t\t{\"t1 join t2\", \"`t1` JOIN `t2`\"},\n\t\t{\"t1, t2\", \"`t1` JOIN `t2`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).From\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select * from %s\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestDeleteTableListRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"t1,t2\", \"`t1`,`t2`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*DeleteStmt).Tables\n\t}\n\tRunNodeRestoreTest(c, testCases, \"DELETE %s FROM t1, t2;\", extractNodeFunc)\n\tRunNodeRestoreTest(c, testCases, \"DELETE FROM %s USING t1, t2;\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestDeleteTableIndexHintRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"DELETE FROM t1 USE key (`fld1`) WHERE fld=1\",\n\t\t\t\"DELETE FROM `t1` USE INDEX (`fld1`) WHERE `fld`=1\"},\n\t\t{\"DELETE FROM t1 as tbl USE key (`fld1`) WHERE tbl.fld=2\",\n\t\t\t\"DELETE FROM `t1` AS `tbl` USE INDEX (`fld1`) WHERE `tbl`.`fld`=2\"},\n\t}\n\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*DeleteStmt)\n\t}\n\tRunNodeRestoreTest(c, testCases, \"%s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestByItemRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"a\", \"`a`\"},\n\t\t{\"a desc\", \"`a` DESC\"},\n\t\t{\"NULL\", \"NULL\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).OrderBy.Items[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select * from t order by %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestGroupByClauseRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"GROUP BY a,b desc\", \"GROUP BY `a`,`b` DESC\"},\n\t\t{\"GROUP BY 1 desc,b\", \"GROUP BY 1 DESC,`b`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).GroupBy\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select * from t %s\", extractNodeFunc)\n}\n\nfunc (tc *testDMLSuite) TestOrderByClauseRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"ORDER BY a\", \"ORDER BY `a`\"},\n\t\t{\"ORDER BY a,b\", \"ORDER BY `a`,`b`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).OrderBy\n\t}\n\tRunNodeRestoreTest(c, testCases, \"SELECT 1 FROM t1 %s\", extractNodeFunc)\n\n\textractNodeFromUnionStmtFunc := func(node Node) Node {\n\t\treturn node.(*UnionStmt).OrderBy\n\t}\n\tRunNodeRestoreTest(c, testCases, \"SELECT 1 FROM t1 UNION SELECT 2 FROM t2 %s\", extractNodeFromUnionStmtFunc)\n}\n\nfunc (tc *testDMLSuite) TestAssignmentRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"a=1\", \"`a`=1\"},\n\t\t{\"b=1+2\", \"`b`=1+2\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*UpdateStmt).List[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"UPDATE t1 SET %s\", extractNodeFunc)\n}\n\nfunc (ts *testDMLSuite) TestHavingClauseRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"HAVING a\", \"HAVING `a`\"},\n\t\t{\"HAVING NULL\", \"HAVING NULL\"},\n\t\t{\"HAVING a>b\", \"HAVING `a`>`b`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Having\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select 1 from t1 group by 1 %s\", extractNodeFunc)\n}\n\nfunc (ts *testDMLSuite) TestFrameBoundRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"CURRENT ROW\", \"CURRENT ROW\"},\n\t\t{\"UNBOUNDED PRECEDING\", \"UNBOUNDED PRECEDING\"},\n\t\t{\"1 PRECEDING\", \"1 PRECEDING\"},\n\t\t{\"{{param1}} PRECEDING\", \"NULL PRECEDING\"},\n\t\t{\"INTERVAL 5 DAY PRECEDING\", \"INTERVAL 5 DAY PRECEDING\"},\n\t\t{\"UNBOUNDED FOLLOWING\", \"UNBOUNDED FOLLOWING\"},\n\t\t{\"1 FOLLOWING\", \"1 FOLLOWING\"},\n\t\t{\"{{param1}} FOLLOWING\", \"NULL FOLLOWING\"},\n\t\t{\"INTERVAL '2:30' MINUTE_SECOND FOLLOWING\", \"INTERVAL '2:30' MINUTE_SECOND FOLLOWING\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn &node.(*SelectStmt).Fields.Fields[0].Expr.(*WindowFuncExpr).Spec.Frame.Extent.Start\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select avg(val) over (rows between %s and current row) from t\", extractNodeFunc)\n}\n\nfunc (ts *testDMLSuite) TestFrameClauseRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"ROWS CURRENT ROW\", \"ROWS BETWEEN CURRENT ROW AND CURRENT ROW\"},\n\t\t{\"ROWS UNBOUNDED PRECEDING\", \"ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\"},\n\t\t{\"ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING\", \"ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING\"},\n\t\t{\"RANGE BETWEEN {{param1}} PRECEDING AND {{param2}}  FOLLOWING\", \"RANGE BETWEEN NULL PRECEDING AND NULL FOLLOWING\"},\n\t\t{\"RANGE BETWEEN INTERVAL 5 DAY PRECEDING AND INTERVAL '2:30' MINUTE_SECOND FOLLOWING\", \"RANGE BETWEEN INTERVAL 5 DAY PRECEDING AND INTERVAL '2:30' MINUTE_SECOND FOLLOWING\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr.(*WindowFuncExpr).Spec.Frame\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select avg(val) over (%s) from t\", extractNodeFunc)\n}\n\nfunc (ts *testDMLSuite) TestPartitionByClauseRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"PARTITION BY a\", \"PARTITION BY `a`\"},\n\t\t{\"PARTITION BY NULL\", \"PARTITION BY NULL\"},\n\t\t{\"PARTITION BY a, b\", \"PARTITION BY `a`, `b`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr.(*WindowFuncExpr).Spec.PartitionBy\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select avg(val) over (%s rows current row) from t\", extractNodeFunc)\n}\n\nfunc (ts *testDMLSuite) TestWindowSpecRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"w as ()\", \"`w` AS ()\"},\n\t\t{\"w as (w1)\", \"`w` AS (`w1`)\"},\n\t\t{\"w as (w1 order by country)\", \"`w` AS (`w1` ORDER BY `country`)\"},\n\t\t{\"w as (partition by a order by b rows current row)\", \"`w` AS (PARTITION BY `a` ORDER BY `b` ROWS BETWEEN CURRENT ROW AND CURRENT ROW)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn &node.(*SelectStmt).WindowSpecs[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select rank() over w from t window %s\", extractNodeFunc)\n\n\ttestCases = []NodeRestoreTestCase{\n\t\t{\"w\", \"`w`\"},\n\t\t{\"()\", \"()\"},\n\t\t{\"(w)\", \"(`w`)\"},\n\t\t{\"(w PARTITION BY country)\", \"(`w` PARTITION BY `country`)\"},\n\t\t{\"(PARTITION BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)\", \"(PARTITION BY `a` ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)\"},\n\t}\n\textractNodeFunc = func(node Node) Node {\n\t\treturn &node.(*SelectStmt).Fields.Fields[0].Expr.(*WindowFuncExpr).Spec\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select rank() over %s from t window w as (order by a)\", extractNodeFunc)\n}\n\nfunc (ts *testDMLSuite) TestFulltextSearchModifier(c *C) {\n\tc.Assert(FulltextSearchModifier(FulltextSearchModifierNaturalLanguageMode).IsBooleanMode(), IsFalse)\n\tc.Assert(FulltextSearchModifier(FulltextSearchModifierNaturalLanguageMode).IsNaturalLanguageMode(), IsTrue)\n\tc.Assert(FulltextSearchModifier(FulltextSearchModifierNaturalLanguageMode).WithQueryExpansion(), IsFalse)\n}\n"
  },
  {
    "path": "pkg/parser/ast/expressions.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n)\n\nvar (\n\t_ ExprNode = &BetweenExpr{}\n\t_ ExprNode = &BinaryOperationExpr{}\n\t_ ExprNode = &CaseExpr{}\n\t_ ExprNode = &ColumnNameExpr{}\n\t_ ExprNode = &CompareSubqueryExpr{}\n\t_ ExprNode = &DefaultExpr{}\n\t_ ExprNode = &ExistsSubqueryExpr{}\n\t_ ExprNode = &IsNullExpr{}\n\t_ ExprNode = &IsTruthExpr{}\n\t_ ExprNode = &ParenthesesExpr{}\n\t_ ExprNode = &PatternInExpr{}\n\t_ ExprNode = &PatternLikeExpr{}\n\t_ ExprNode = &PatternRegexpExpr{}\n\t_ ExprNode = &PositionExpr{}\n\t_ ExprNode = &RowExpr{}\n\t_ ExprNode = &SubqueryExpr{}\n\t_ ExprNode = &UnaryOperationExpr{}\n\t_ ExprNode = &ValuesExpr{}\n\t_ ExprNode = &VariableExpr{}\n\t_ ExprNode = &MatchAgainst{}\n\n\t_ Node = &ColumnName{}\n\t_ Node = &WhenClause{}\n)\n\n// ValueExpr define a interface for ValueExpr.\ntype ValueExpr interface {\n\tExprNode\n\tSetValue(val interface{})\n\tGetValue() interface{}\n\tGetDatumString() string\n\tGetString() string\n\tGetProjectionOffset() int\n\tSetProjectionOffset(offset int)\n}\n\n// NewValueExpr creates a ValueExpr with value, and sets default field type.\nvar NewValueExpr func(interface{}) ValueExpr\n\n// NewParamMarkerExpr creates a ParamMarkerExpr.\nvar NewParamMarkerExpr func(offset int, paramName string) ParamMarkerExpr\n\n// BetweenExpr is for \"between and\" or \"not between and\" expression.\ntype BetweenExpr struct {\n\texprNode\n\t// Expr is the expression to be checked.\n\tExpr ExprNode\n\t// Left is the expression for minimal value in the range.\n\tLeft ExprNode\n\t// Right is the expression for maximum value in the range.\n\tRight ExprNode\n\t// Not is true, the expression is \"not between and\".\n\tNot bool\n}\n\n// Restore implements Node interface.\nfunc (n *BetweenExpr) Restore(ctx *RestoreCtx) error {\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore BetweenExpr.Expr\")\n\t}\n\tif n.Not {\n\t\tctx.WriteKeyWord(\" NOT BETWEEN \")\n\t} else {\n\t\tctx.WriteKeyWord(\" BETWEEN \")\n\t}\n\tif err := n.Left.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore BetweenExpr.Left\")\n\t}\n\tctx.WriteKeyWord(\" AND \")\n\tif err := n.Right.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore BetweenExpr.Right \")\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *BetweenExpr) Format(w io.Writer) {\n\tn.Expr.Format(w)\n\tif n.Not {\n\t\tfmt.Fprint(w, \" NOT BETWEEN \")\n\t} else {\n\t\tfmt.Fprint(w, \" BETWEEN \")\n\t}\n\tn.Left.Format(w)\n\tfmt.Fprint(w, \" AND \")\n\tn.Right.Format(w)\n}\n\n// Accept implements Node interface.\nfunc (n *BetweenExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*BetweenExpr)\n\tnode, ok := n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\n\tnode, ok = n.Left.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Left = node.(ExprNode)\n\n\tnode, ok = n.Right.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Right = node.(ExprNode)\n\n\treturn v.Leave(n)\n}\n\n// BinaryOperationExpr is for binary operation like `1 + 1`, `1 - 1`, etc.\ntype BinaryOperationExpr struct {\n\texprNode\n\t// Op is the operator code for BinaryOperation.\n\tOp opcode.Op\n\t// L is the left expression in BinaryOperation.\n\tL ExprNode\n\t// R is the right expression in BinaryOperation.\n\tR ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *BinaryOperationExpr) Restore(ctx *RestoreCtx) error {\n\tif err := n.L.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred when restore BinaryOperationExpr.L\")\n\t}\n\tif ctx.Flags.HasSpacesAroundBinaryOperationFlag() {\n\t\tctx.WritePlain(\" \")\n\t}\n\tif err := n.Op.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred when restore BinaryOperationExpr.Op\")\n\t}\n\tif ctx.Flags.HasSpacesAroundBinaryOperationFlag() {\n\t\tctx.WritePlain(\" \")\n\t}\n\tif err := n.R.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred when restore BinaryOperationExpr.R\")\n\t}\n\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *BinaryOperationExpr) Format(w io.Writer) {\n\tn.L.Format(w)\n\tfmt.Fprint(w, \" \")\n\tn.Op.Format(w)\n\tfmt.Fprint(w, \" \")\n\tn.R.Format(w)\n}\n\n// Accept implements Node interface.\nfunc (n *BinaryOperationExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*BinaryOperationExpr)\n\tnode, ok := n.L.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.L = node.(ExprNode)\n\n\tnode, ok = n.R.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.R = node.(ExprNode)\n\n\treturn v.Leave(n)\n}\n\n// WhenClause is the when clause in Case expression for \"when condition then result\".\ntype WhenClause struct {\n\tnode\n\t// Expr is the condition expression in WhenClause.\n\tExpr ExprNode\n\t// Result is the result expression in WhenClause.\n\tResult ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *WhenClause) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"WHEN \")\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore WhenClauses.Expr\")\n\t}\n\tctx.WriteKeyWord(\" THEN \")\n\tif err := n.Result.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore WhenClauses.Result\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *WhenClause) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*WhenClause)\n\tnode, ok := n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\n\tnode, ok = n.Result.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Result = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// CaseExpr is the case expression.\ntype CaseExpr struct {\n\texprNode\n\t// Value is the compare value expression.\n\tValue ExprNode\n\t// WhenClauses is the condition check expression.\n\tWhenClauses []*WhenClause\n\t// ElseClause is the else result expression.\n\tElseClause ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *CaseExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"CASE\")\n\tif n.Value != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Value.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore CaseExpr.Value\")\n\t\t}\n\t}\n\tfor _, clause := range n.WhenClauses {\n\t\tctx.WritePlain(\" \")\n\t\tif err := clause.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore CaseExpr.WhenClauses\")\n\t\t}\n\t}\n\tif n.ElseClause != nil {\n\t\tctx.WriteKeyWord(\" ELSE \")\n\t\tif err := n.ElseClause.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore CaseExpr.ElseClause\")\n\t\t}\n\t}\n\tctx.WriteKeyWord(\" END\")\n\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *CaseExpr) Format(w io.Writer) {\n\tfmt.Fprint(w, \"CASE\")\n\t// Because the presence of `case when` syntax, `Value` could be nil and we need check this.\n\tif n.Value != nil {\n\t\tfmt.Fprint(w, \" \")\n\t\tn.Value.Format(w)\n\t}\n\tfor _, clause := range n.WhenClauses {\n\t\tfmt.Fprint(w, \" \")\n\t\tfmt.Fprint(w, \"WHEN \")\n\t\tclause.Expr.Format(w)\n\t\tfmt.Fprint(w, \" THEN \")\n\t\tclause.Result.Format(w)\n\t}\n\tif n.ElseClause != nil {\n\t\tfmt.Fprint(w, \" ELSE \")\n\t\tn.ElseClause.Format(w)\n\t}\n\tfmt.Fprint(w, \" END\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *CaseExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*CaseExpr)\n\tif n.Value != nil {\n\t\tnode, ok := n.Value.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Value = node.(ExprNode)\n\t}\n\tfor i, val := range n.WhenClauses {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.WhenClauses[i] = node.(*WhenClause)\n\t}\n\tif n.ElseClause != nil {\n\t\tnode, ok := n.ElseClause.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.ElseClause = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// SubqueryExpr represents a subquery.\ntype SubqueryExpr struct {\n\texprNode\n\t// Query is the query SelectNode.\n\tQuery      ResultSetNode\n\tEvaluated  bool\n\tCorrelated bool\n\tMultiRows  bool\n\tExists     bool\n}\n\n// Restore implements Node interface.\nfunc (n *SubqueryExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WritePlain(\"(\")\n\tif err := n.Query.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore SubqueryExpr.Query\")\n\t}\n\tctx.WritePlain(\")\")\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *SubqueryExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *SubqueryExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*SubqueryExpr)\n\tnode, ok := n.Query.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Query = node.(ResultSetNode)\n\treturn v.Leave(n)\n}\n\n// CompareSubqueryExpr is the expression for \"expr cmp (select ...)\".\n// See https://dev.mysql.com/doc/refman/5.7/en/comparisons-using-subqueries.html\n// See https://dev.mysql.com/doc/refman/5.7/en/any-in-some-subqueries.html\n// See https://dev.mysql.com/doc/refman/5.7/en/all-subqueries.html\ntype CompareSubqueryExpr struct {\n\texprNode\n\t// L is the left expression\n\tL ExprNode\n\t// Op is the comparison opcode.\n\tOp opcode.Op\n\t// R is the subquery for right expression, may be rewritten to other type of expression.\n\tR ExprNode\n\t// All is true, we should compare all records in subquery.\n\tAll bool\n}\n\n// Restore implements Node interface.\nfunc (n *CompareSubqueryExpr) Restore(ctx *RestoreCtx) error {\n\tif err := n.L.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore CompareSubqueryExpr.L\")\n\t}\n\tif err := n.Op.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore CompareSubqueryExpr.Op\")\n\t}\n\tif n.All {\n\t\tctx.WriteKeyWord(\"ALL \")\n\t} else {\n\t\tctx.WriteKeyWord(\"ANY \")\n\t}\n\tif err := n.R.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore CompareSubqueryExpr.R\")\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *CompareSubqueryExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *CompareSubqueryExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*CompareSubqueryExpr)\n\tnode, ok := n.L.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.L = node.(ExprNode)\n\tnode, ok = n.R.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.R = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// ColumnName represents column name.\ntype ColumnName struct {\n\tnode\n\tSchema model.CIStr\n\tTable  model.CIStr\n\tName   model.CIStr\n}\n\n// Restore implements Node interface.\nfunc (n *ColumnName) Restore(ctx *RestoreCtx) error {\n\tif n.Schema.O != \"\" && !ctx.Dialect.SkipSchemaInColName() {\n\t\tctx.WriteName(n.Schema.O)\n\t\tctx.WritePlain(\".\")\n\t}\n\tif n.Table.O != \"\" {\n\t\tctx.WriteName(n.Table.O)\n\t\tctx.WritePlain(\".\")\n\t}\n\tctx.WriteName(n.Name.O)\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ColumnName) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ColumnName)\n\treturn v.Leave(n)\n}\n\n// String implements Stringer interface.\nfunc (n *ColumnName) String() string {\n\tresult := n.Name.L\n\tif n.Table.L != \"\" {\n\t\tresult = n.Table.L + \".\" + result\n\t}\n\tif n.Schema.L != \"\" {\n\t\tresult = n.Schema.L + \".\" + result\n\t}\n\treturn result\n}\n\n// OrigColName returns the full original column name.\nfunc (n *ColumnName) OrigColName() (ret string) {\n\tret = n.Name.O\n\tif n.Table.O == \"\" {\n\t\treturn\n\t}\n\tret = n.Table.O + \".\" + ret\n\tif n.Schema.O == \"\" {\n\t\treturn\n\t}\n\tret = n.Schema.O + \".\" + ret\n\treturn\n}\n\n// ColumnNameExpr represents a column name expression.\ntype ColumnNameExpr struct {\n\texprNode\n\n\t// Name is the referenced column name.\n\tName *ColumnName\n\n\t// Refer is the result field the column name refers to.\n\t// The value of Refer.Expr is used as the value of the expression.\n\tRefer *ResultField\n}\n\n// Restore implements Node interface.\nfunc (n *ColumnNameExpr) Restore(ctx *RestoreCtx) error {\n\tif err := n.Name.Restore(ctx); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *ColumnNameExpr) Format(w io.Writer) {\n\tname := strings.Replace(n.Name.String(), \".\", \"`.`\", -1)\n\tfmt.Fprintf(w, \"`%s`\", name)\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ColumnNameExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ColumnNameExpr)\n\tnode, ok := n.Name.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Name = node.(*ColumnName)\n\treturn v.Leave(n)\n}\n\n// DefaultExpr is the default expression using default value for a column.\ntype DefaultExpr struct {\n\texprNode\n\t// Name is the column name.\n\tName *ColumnName\n}\n\n// Restore implements Node interface.\nfunc (n *DefaultExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"DEFAULT\")\n\tif n.Name != nil {\n\t\tctx.WritePlain(\"(\")\n\t\tif err := n.Name.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore DefaultExpr.Name\")\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *DefaultExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DefaultExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DefaultExpr)\n\tif n.Name != nil {\n\t\tnode, ok := n.Name.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Name = node.(*ColumnName)\n\t}\n\treturn v.Leave(n)\n}\n\n// ExistsSubqueryExpr is the expression for \"exists (select ...)\".\n// See https://dev.mysql.com/doc/refman/5.7/en/exists-and-not-exists-subqueries.html\ntype ExistsSubqueryExpr struct {\n\texprNode\n\t// Sel is the subquery, may be rewritten to other type of expression.\n\tSel ExprNode\n\t// Not is true, the expression is \"not exists\".\n\tNot bool\n}\n\n// Restore implements Node interface.\nfunc (n *ExistsSubqueryExpr) Restore(ctx *RestoreCtx) error {\n\tif n.Not {\n\t\tctx.WriteKeyWord(\"NOT EXISTS \")\n\t} else {\n\t\tctx.WriteKeyWord(\"EXISTS \")\n\t}\n\tif err := n.Sel.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore ExistsSubqueryExpr.Sel\")\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *ExistsSubqueryExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ExistsSubqueryExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ExistsSubqueryExpr)\n\tnode, ok := n.Sel.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Sel = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// PatternInExpr is the expression for in operator, like \"expr in (1, 2, 3)\" or \"expr in (select c from t)\".\ntype PatternInExpr struct {\n\texprNode\n\t// Expr is the value expression to be compared.\n\tExpr ExprNode\n\t// List is the list expression in compare list.\n\tList []ExprNode\n\t// Not is true, the expression is \"not in\".\n\tNot bool\n\t// Sel is the subquery, may be rewritten to other type of expression.\n\tSel ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *PatternInExpr) Restore(ctx *RestoreCtx) error {\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore PatternInExpr.Expr\")\n\t}\n\tif n.Not {\n\t\tctx.WriteKeyWord(\" NOT IN \")\n\t} else {\n\t\tctx.WriteKeyWord(\" IN \")\n\t}\n\tif n.Sel != nil {\n\t\tif err := n.Sel.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore PatternInExpr.Sel\")\n\t\t}\n\t} else {\n\t\tctx.WritePlain(\"(\")\n\t\tfor i, expr := range n.List {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := expr.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore PatternInExpr.List[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *PatternInExpr) Format(w io.Writer) {\n\tn.Expr.Format(w)\n\tif n.Not {\n\t\tfmt.Fprint(w, \" NOT IN (\")\n\t} else {\n\t\tfmt.Fprint(w, \" IN (\")\n\t}\n\tfor i, expr := range n.List {\n\t\tif i != 0 {\n\t\t\tfmt.Fprint(w, \",\")\n\t\t}\n\t\texpr.Format(w)\n\t}\n\tfmt.Fprint(w, \")\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *PatternInExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*PatternInExpr)\n\tnode, ok := n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\tfor i, val := range n.List {\n\t\tnode, ok = val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.List[i] = node.(ExprNode)\n\t}\n\tif n.Sel != nil {\n\t\tnode, ok = n.Sel.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Sel = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// IsNullExpr is the expression for null check.\ntype IsNullExpr struct {\n\texprNode\n\t// Expr is the expression to be checked.\n\tExpr ExprNode\n\t// Not is true, the expression is \"is not null\".\n\tNot bool\n}\n\n// Restore implements Node interface.\nfunc (n *IsNullExpr) Restore(ctx *RestoreCtx) error {\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\tif n.Not {\n\t\tctx.WriteKeyWord(\" IS NOT NULL\")\n\t} else {\n\t\tctx.WriteKeyWord(\" IS NULL\")\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *IsNullExpr) Format(w io.Writer) {\n\tn.Expr.Format(w)\n\tif n.Not {\n\t\tfmt.Fprint(w, \" IS NOT NULL\")\n\t\treturn\n\t}\n\tfmt.Fprint(w, \" IS NULL\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *IsNullExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*IsNullExpr)\n\tnode, ok := n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// IsTruthExpr is the expression for true/false check.\ntype IsTruthExpr struct {\n\texprNode\n\t// Expr is the expression to be checked.\n\tExpr ExprNode\n\t// Not is true, the expression is \"is not true/false\".\n\tNot bool\n\t// True indicates checking true or false.\n\tTrue int64\n}\n\n// Restore implements Node interface.\nfunc (n *IsTruthExpr) Restore(ctx *RestoreCtx) error {\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\tif n.Not {\n\t\tctx.WriteKeyWord(\" IS NOT\")\n\t} else {\n\t\tctx.WriteKeyWord(\" IS\")\n\t}\n\tif n.True > 0 {\n\t\tctx.WriteKeyWord(\" TRUE\")\n\t} else {\n\t\tctx.WriteKeyWord(\" FALSE\")\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *IsTruthExpr) Format(w io.Writer) {\n\tn.Expr.Format(w)\n\tif n.Not {\n\t\tfmt.Fprint(w, \" IS NOT\")\n\t} else {\n\t\tfmt.Fprint(w, \" IS\")\n\t}\n\tif n.True > 0 {\n\t\tfmt.Fprint(w, \" TRUE\")\n\t} else {\n\t\tfmt.Fprint(w, \" FALSE\")\n\t}\n}\n\n// Accept implements Node Accept interface.\nfunc (n *IsTruthExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*IsTruthExpr)\n\tnode, ok := n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// PatternLikeExpr is the expression for like operator, e.g, expr like \"%123%\"\ntype PatternLikeExpr struct {\n\texprNode\n\t// Expr is the expression to be checked.\n\tExpr ExprNode\n\t// Pattern is the like expression.\n\tPattern ExprNode\n\t// Not is true, the expression is \"not like\".\n\tNot bool\n\n\tEscape byte\n\n\tPatChars []byte\n\tPatTypes []byte\n}\n\n// Restore implements Node interface.\nfunc (n *PatternLikeExpr) Restore(ctx *RestoreCtx) error {\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore PatternLikeExpr.Expr\")\n\t}\n\n\tif n.Not {\n\t\tctx.WriteKeyWord(\" NOT LIKE \")\n\t} else {\n\t\tctx.WriteKeyWord(\" LIKE \")\n\t}\n\n\tif err := n.Pattern.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore PatternLikeExpr.Pattern\")\n\t}\n\n\tescape := string(n.Escape)\n\tif escape != \"\\\\\" {\n\t\tctx.WriteKeyWord(\" ESCAPE \")\n\t\tctx.WriteString(escape)\n\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *PatternLikeExpr) Format(w io.Writer) {\n\tn.Expr.Format(w)\n\tif n.Not {\n\t\tfmt.Fprint(w, \" NOT LIKE \")\n\t} else {\n\t\tfmt.Fprint(w, \" LIKE \")\n\t}\n\tn.Pattern.Format(w)\n\tif n.Escape != '\\\\' {\n\t\tfmt.Fprint(w, \" ESCAPE \")\n\t\tfmt.Fprintf(w, \"'%c'\", n.Escape)\n\t}\n}\n\n// Accept implements Node Accept interface.\nfunc (n *PatternLikeExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*PatternLikeExpr)\n\tif n.Expr != nil {\n\t\tnode, ok := n.Expr.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Expr = node.(ExprNode)\n\t}\n\tif n.Pattern != nil {\n\t\tnode, ok := n.Pattern.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Pattern = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// ParamMarkerExpr expression holds a place for another expression.\n// Used in parsing prepare statement.\ntype ParamMarkerExpr interface {\n\tValueExpr\n\tSetOrder(int)\n}\n\n// ParenthesesExpr is the parentheses expression.\ntype ParenthesesExpr struct {\n\texprNode\n\t// Expr is the expression in parentheses.\n\tExpr ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *ParenthesesExpr) Restore(ctx *RestoreCtx) error {\n\tif _, ok := n.Expr.(*ParenthesesExpr); ok {\n\t\t// to avoid ((expr)), ((expr)) is unacceptable for explorer\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred when restore ParenthesesExpr.Expr\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tctx.WritePlain(\"(\")\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred when restore ParenthesesExpr.Expr\")\n\t}\n\tctx.WritePlain(\")\")\n\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *ParenthesesExpr) Format(w io.Writer) {\n\tfmt.Fprint(w, \"(\")\n\tn.Expr.Format(w)\n\tfmt.Fprint(w, \")\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ParenthesesExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ParenthesesExpr)\n\tif n.Expr != nil {\n\t\tnode, ok := n.Expr.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Expr = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// PositionExpr is the expression for order by and group by position.\n// MySQL use position expression started from 1, it looks a little confused inner.\n// maybe later we will use 0 at first.\ntype PositionExpr struct {\n\texprNode\n\t// N is the position, started from 1 now.\n\tN int\n\t// P is the parameterized position.\n\tP ExprNode\n\t// Refer is the result field the position refers to.\n\tRefer *ResultField\n}\n\n// Restore implements Node interface.\nfunc (n *PositionExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WritePlainf(\"%d\", n.N)\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *PositionExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *PositionExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*PositionExpr)\n\tif n.P != nil {\n\t\tnode, ok := n.P.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.P = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// PatternRegexpExpr is the pattern expression for pattern match.\ntype PatternRegexpExpr struct {\n\texprNode\n\t// Expr is the expression to be checked.\n\tExpr ExprNode\n\t// Pattern is the expression for pattern.\n\tPattern ExprNode\n\t// Not is true, the expression is \"not rlike\",\n\tNot bool\n\n\t// Re is the compiled regexp.\n\tRe *regexp.Regexp\n\t// Sexpr is the string for Expr expression.\n\tSexpr *string\n}\n\n// Restore implements Node interface.\nfunc (n *PatternRegexpExpr) Restore(ctx *RestoreCtx) error {\n\tif err := n.Expr.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore PatternRegexpExpr.Expr\")\n\t}\n\n\tif n.Not {\n\t\tctx.WriteKeyWord(\" NOT REGEXP \")\n\t} else {\n\t\tctx.WriteKeyWord(\" REGEXP \")\n\t}\n\n\tif err := n.Pattern.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore PatternRegexpExpr.Pattern\")\n\t}\n\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *PatternRegexpExpr) Format(w io.Writer) {\n\tn.Expr.Format(w)\n\tif n.Not {\n\t\tfmt.Fprint(w, \" NOT REGEXP \")\n\t} else {\n\t\tfmt.Fprint(w, \" REGEXP \")\n\t}\n\tn.Pattern.Format(w)\n}\n\n// Accept implements Node Accept interface.\nfunc (n *PatternRegexpExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*PatternRegexpExpr)\n\tnode, ok := n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\tnode, ok = n.Pattern.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Pattern = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// RowExpr is the expression for row constructor.\n// See https://dev.mysql.com/doc/refman/5.7/en/row-subqueries.html\ntype RowExpr struct {\n\texprNode\n\n\tValues []ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *RowExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"ROW\")\n\tctx.WritePlain(\"(\")\n\tfor i, v := range n.Values {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred when restore RowExpr.Values[%v]\", i)\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *RowExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *RowExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*RowExpr)\n\tfor i, val := range n.Values {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Values[i] = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// UnaryOperationExpr is the expression for unary operator.\ntype UnaryOperationExpr struct {\n\texprNode\n\t// Op is the operator opcode.\n\tOp opcode.Op\n\t// V is the unary expression.\n\tV ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *UnaryOperationExpr) Restore(ctx *RestoreCtx) error {\n\tif err := n.Op.Restore(ctx); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\tif err := n.V.Restore(ctx); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *UnaryOperationExpr) Format(w io.Writer) {\n\tn.Op.Format(w)\n\tn.V.Format(w)\n}\n\n// Accept implements Node Accept interface.\nfunc (n *UnaryOperationExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*UnaryOperationExpr)\n\tnode, ok := n.V.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.V = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// ValuesExpr is the expression used in INSERT VALUES.\ntype ValuesExpr struct {\n\texprNode\n\t// Column is column name.\n\tColumn *ColumnNameExpr\n}\n\n// Restore implements Node interface.\nfunc (n *ValuesExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"VALUES\")\n\tctx.WritePlain(\"(\")\n\tif err := n.Column.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore ValuesExpr.Column\")\n\t}\n\tctx.WritePlain(\")\")\n\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *ValuesExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ValuesExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ValuesExpr)\n\tnode, ok := n.Column.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\t// `node` may be *ast.ValueExpr, to avoid panic, we write `ok` but do not use\n\t// it.\n\tn.Column, ok = node.(*ColumnNameExpr)\n\treturn v.Leave(n)\n}\n\n// VariableExpr is the expression for variable.\ntype VariableExpr struct {\n\texprNode\n\t// Name is the variable name.\n\tName string\n\t// IsGlobal indicates whether this variable is global.\n\tIsGlobal bool\n\t// IsSystem indicates whether this variable is a system variable in current session.\n\tIsSystem bool\n\t// ExplicitScope indicates whether this variable scope is set explicitly.\n\tExplicitScope bool\n\t// Value is the variable value.\n\tValue ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *VariableExpr) Restore(ctx *RestoreCtx) error {\n\tif n.IsSystem {\n\t\tctx.WritePlain(\"@@\")\n\t\tif n.ExplicitScope {\n\t\t\tif n.IsGlobal {\n\t\t\t\tctx.WriteKeyWord(\"GLOBAL\")\n\t\t\t} else {\n\t\t\t\tctx.WriteKeyWord(\"SESSION\")\n\t\t\t}\n\t\t\tctx.WritePlain(\".\")\n\t\t}\n\t} else {\n\t\tctx.WritePlain(\"@\")\n\t}\n\tctx.WriteName(n.Name)\n\n\tif n.Value != nil {\n\t\tctx.WritePlain(\":=\")\n\t\tif err := n.Value.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore VariableExpr.Value\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *VariableExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *VariableExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*VariableExpr)\n\tif n.Value == nil {\n\t\treturn v.Leave(n)\n\t}\n\n\tnode, ok := n.Value.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Value = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// MaxValueExpr is the expression for \"maxvalue\" used in partition.\ntype MaxValueExpr struct {\n\texprNode\n}\n\n// Restore implements Node interface.\nfunc (n *MaxValueExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"MAXVALUE\")\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *MaxValueExpr) Format(w io.Writer) {\n\tfmt.Fprint(w, \"MAXVALUE\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *MaxValueExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// MatchAgainst is the expression for matching against fulltext index.\ntype MatchAgainst struct {\n\texprNode\n\t// ColumnNames are the columns to match.\n\tColumnNames []*ColumnName\n\t// Against\n\tAgainst ExprNode\n\t// Modifier\n\tModifier FulltextSearchModifier\n}\n\nfunc (n *MatchAgainst) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"MATCH\")\n\tctx.WritePlain(\" (\")\n\tfor i, v := range n.ColumnNames {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore MatchAgainst.ColumnNames[%d]\", i)\n\t\t}\n\t}\n\tctx.WritePlain(\") \")\n\tctx.WriteKeyWord(\"AGAINST\")\n\tctx.WritePlain(\" (\")\n\tif err := n.Against.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore MatchAgainst.Against\")\n\t}\n\tif n.Modifier.IsBooleanMode() {\n\t\tctx.WritePlain(\" IN BOOLEAN MODE\")\n\t\tif n.Modifier.WithQueryExpansion() {\n\t\t\treturn errors.New(\"BOOLEAN MODE doesn't support QUERY EXPANSION\")\n\t\t}\n\t} else if n.Modifier.WithQueryExpansion() {\n\t\tctx.WritePlain(\" WITH QUERY EXPANSION\")\n\t}\n\tctx.WritePlain(\")\")\n\treturn nil\n}\n\nfunc (n *MatchAgainst) Format(w io.Writer) {\n\tfmt.Fprint(w, \"MATCH(\")\n\tfor i, v := range n.ColumnNames {\n\t\tif i != 0 {\n\t\t\tfmt.Fprintf(w, \",%s\", v.String())\n\t\t} else {\n\t\t\tfmt.Fprint(w, v.String())\n\t\t}\n\t}\n\tfmt.Fprint(w, \") AGAINST(\")\n\tn.Against.Format(w)\n\tif n.Modifier.IsBooleanMode() {\n\t\tfmt.Fprint(w, \" IN BOOLEAN MODE\")\n\t} else if n.Modifier.WithQueryExpansion() {\n\t\tfmt.Fprint(w, \" WITH QUERY EXPANSION\")\n\t}\n\tfmt.Fprint(w, \")\")\n}\n\nfunc (n *MatchAgainst) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*MatchAgainst)\n\tfor i, colName := range n.ColumnNames {\n\t\tnewColName, ok := colName.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.ColumnNames[i] = newColName.(*ColumnName)\n\t}\n\tnewAgainst, ok := n.Against.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Against = newAgainst.(ExprNode)\n\treturn v.Leave(n)\n}\n"
  },
  {
    "path": "pkg/parser/ast/expressions_test.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast_test\n\nimport (\n\t. \"github.com/pingcap/check\"\n\n\t. \"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n)\n\nvar _ = Suite(&testExpressionsSuite{})\n\ntype testExpressionsSuite struct {\n}\n\ntype checkVisitor struct{}\n\nfunc (v checkVisitor) Enter(in Node) (Node, bool) {\n\tif e, ok := in.(*checkExpr); ok {\n\t\te.enterCnt++\n\t\treturn in, true\n\t}\n\treturn in, false\n}\n\nfunc (v checkVisitor) Leave(in Node) (Node, bool) {\n\tif e, ok := in.(*checkExpr); ok {\n\t\te.leaveCnt++\n\t}\n\treturn in, true\n}\n\ntype checkExpr struct {\n\tValueExpr\n\n\tenterCnt int\n\tleaveCnt int\n}\n\nfunc (n *checkExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*checkExpr)\n\treturn v.Leave(n)\n}\n\nfunc (n *checkExpr) reset() {\n\tn.enterCnt = 0\n\tn.leaveCnt = 0\n}\n\nfunc (tc *testExpressionsSuite) TestExpresionsVisitorCover(c *C) {\n\tce := &checkExpr{}\n\tstmts :=\n\t\t[]struct {\n\t\t\tnode             Node\n\t\t\texpectedEnterCnt int\n\t\t\texpectedLeaveCnt int\n\t\t}{\n\t\t\t{&BetweenExpr{Expr: ce, Left: ce, Right: ce}, 3, 3},\n\t\t\t{&BinaryOperationExpr{L: ce, R: ce}, 2, 2},\n\t\t\t{&CaseExpr{Value: ce, WhenClauses: []*WhenClause{{Expr: ce, Result: ce},\n\t\t\t\t{Expr: ce, Result: ce}}, ElseClause: ce}, 6, 6},\n\t\t\t{&ColumnNameExpr{Name: &ColumnName{}}, 0, 0},\n\t\t\t{&CompareSubqueryExpr{L: ce, R: ce}, 2, 2},\n\t\t\t{&DefaultExpr{Name: &ColumnName{}}, 0, 0},\n\t\t\t{&ExistsSubqueryExpr{Sel: ce}, 1, 1},\n\t\t\t{&IsNullExpr{Expr: ce}, 1, 1},\n\t\t\t{&IsTruthExpr{Expr: ce}, 1, 1},\n\t\t\t{NewParamMarkerExpr(0, \"param1\"), 0, 0},\n\t\t\t{&ParenthesesExpr{Expr: ce}, 1, 1},\n\t\t\t{&PatternInExpr{Expr: ce, List: []ExprNode{ce, ce, ce}, Sel: ce}, 5, 5},\n\t\t\t{&PatternLikeExpr{Expr: ce, Pattern: ce}, 2, 2},\n\t\t\t{&PatternRegexpExpr{Expr: ce, Pattern: ce}, 2, 2},\n\t\t\t{&PositionExpr{}, 0, 0},\n\t\t\t{&RowExpr{Values: []ExprNode{ce, ce}}, 2, 2},\n\t\t\t{&UnaryOperationExpr{V: ce}, 1, 1},\n\t\t\t{NewValueExpr(0), 0, 0},\n\t\t\t{&ValuesExpr{Column: &ColumnNameExpr{Name: &ColumnName{}}}, 0, 0},\n\t\t\t{&VariableExpr{Value: ce}, 1, 1},\n\t\t}\n\n\tfor _, v := range stmts {\n\t\tce.reset()\n\t\tv.node.Accept(checkVisitor{})\n\t\tc.Check(ce.enterCnt, Equals, v.expectedEnterCnt)\n\t\tc.Check(ce.leaveCnt, Equals, v.expectedLeaveCnt)\n\t\tv.node.Accept(visitor1{})\n\t}\n}\n\nfunc (tc *testExpressionsSuite) TestUnaryOperationExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"++1\", \"++1\"},\n\t\t{\"--1\", \"--1\"},\n\t\t{\"-+1\", \"-+1\"},\n\t\t{\"-1\", \"-1\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestColumnNameExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"abc\", \"`abc`\"},\n\t\t{\"`abc`\", \"`abc`\"},\n\t\t{\"`ab``c`\", \"`ab``c`\"},\n\t\t{\"sabc.tABC\", \"`sabc`.`tABC`\"},\n\t\t{\"dabc.sabc.tabc\", \"`dabc`.`sabc`.`tabc`\"},\n\t\t{\"dabc.`sabc`.tabc\", \"`dabc`.`sabc`.`tabc`\"},\n\t\t{\"`dABC`.`sabc`.tabc\", \"`dABC`.`sabc`.`tabc`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestIsNullExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"a is null\", \"`a` IS NULL\"},\n\t\t{\"a is not null\", \"`a` IS NOT NULL\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestIsTruthRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"a is true\", \"`a` IS TRUE\"},\n\t\t{\"a is not true\", \"`a` IS NOT TRUE\"},\n\t\t{\"a is FALSE\", \"`a` IS FALSE\"},\n\t\t{\"a is not false\", \"`a` IS NOT FALSE\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestBetweenExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"b between 1 and 2\", \"`b` BETWEEN 1 AND 2\"},\n\t\t{\"b not between 1 and 2\", \"`b` NOT BETWEEN 1 AND 2\"},\n\t\t{\"b between a and b\", \"`b` BETWEEN `a` AND `b`\"},\n\t\t{\"b between '' and 'b'\", \"`b` BETWEEN '' AND 'b'\"},\n\t\t{\"b between '2018-11-01' and '2018-11-02'\", \"`b` BETWEEN '2018-11-01' AND '2018-11-02'\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestCaseExpr(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"case when 1 then 2 end\", \"CASE WHEN 1 THEN 2 END\"},\n\t\t{\"case when 1 then 'a' when 2 then 'b' end\", \"CASE WHEN 1 THEN 'a' WHEN 2 THEN 'b' END\"},\n\t\t{\"case when 1 then 'a' when 2 then 'b' else 'c' end\", \"CASE WHEN 1 THEN 'a' WHEN 2 THEN 'b' ELSE 'c' END\"},\n\t\t{\"case when 'a'!=1 then true else false end\", \"CASE WHEN 'a'!=1 THEN TRUE ELSE FALSE END\"},\n\t\t{\"case a when 'a' then true else false end\", \"CASE `a` WHEN 'a' THEN TRUE ELSE FALSE END\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestBinaryOperationExpr(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"'a'!=1\", \"'a'!=1\"},\n\t\t{\"a!=1\", \"`a`!=1\"},\n\t\t{\"3<5\", \"3<5\"},\n\t\t{\"10>5\", \"10>5\"},\n\t\t{\"3+5\", \"3+5\"},\n\t\t{\"3-5\", \"3-5\"},\n\t\t{\"a<>5\", \"`a`!=5\"},\n\t\t{\"a=1\", \"`a`=1\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestBinaryOperationExprWithFlags(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"'a'!=1\", \"'a' != 1\"},\n\t\t{\"a!=1\", \"`a` != 1\"},\n\t\t{\"3<5\", \"3 < 5\"},\n\t\t{\"10>5\", \"10 > 5\"},\n\t\t{\"3+5\", \"3 + 5\"},\n\t\t{\"3-5\", \"3 - 5\"},\n\t\t{\"a<>5\", \"`a` != 5\"},\n\t\t{\"a=1\", \"`a` = 1\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tflags := format.DefaultRestoreFlags | format.RestoreSpacesAroundBinaryOperation\n\tRunNodeRestoreTestWithFlags(c, testCases, \"select %s\", extractNodeFunc, flags)\n}\n\nfunc (tc *testExpressionsSuite) TestParenthesesExpr(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"(1+2)*3\", \"(1+2)*3\"},\n\t\t{\"1+2*3\", \"1+2*3\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestWhenClause(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"when 1 then 2\", \"WHEN 1 THEN 2\"},\n\t\t{\"when 1 then 'a'\", \"WHEN 1 THEN 'a'\"},\n\t\t{\"when 'a'!=1 then true\", \"WHEN 'a'!=1 THEN TRUE\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr.(*CaseExpr).WhenClauses[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select case %s end\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestDefaultExpr(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"default\", \"DEFAULT\"},\n\t\t{\"default(i)\", \"DEFAULT(`i`)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*InsertStmt).Lists[0][0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"insert into t values(%s)\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestPatternInExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"'a' in ('b')\", \"'a' IN ('b')\"},\n\t\t{\"2 in (0,3,7)\", \"2 IN (0,3,7)\"},\n\t\t{\"2 not in (0,3,7)\", \"2 NOT IN (0,3,7)\"},\n\t\t{\"2 in (select 2)\", \"2 IN (SELECT 2)\"},\n\t\t{\"2 not in (select 2)\", \"2 NOT IN (SELECT 2)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestPatternLikeExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"a like 't1'\", \"`a` LIKE 't1'\"},\n\t\t{\"a like 't1%'\", \"`a` LIKE 't1%'\"},\n\t\t{\"a like '%t1%'\", \"`a` LIKE '%t1%'\"},\n\t\t{\"a like '%t1_|'\", \"`a` LIKE '%t1_|'\"},\n\t\t{\"a not like 't1'\", \"`a` NOT LIKE 't1'\"},\n\t\t{\"a not like 't1%'\", \"`a` NOT LIKE 't1%'\"},\n\t\t{\"a not like '%D%v%'\", \"`a` NOT LIKE '%D%v%'\"},\n\t\t{\"a not like '%t1_|'\", \"`a` NOT LIKE '%t1_|'\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestValuesExpr(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"values(a)\", \"VALUES(`a`)\"},\n\t\t{\"values(a)+values(b)\", \"VALUES(`a`)+VALUES(`b`)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*InsertStmt).OnDuplicate[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"insert into t values (1,2,3) on duplicate key update c=%s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestPatternRegexpExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"a regexp 't1'\", \"`a` REGEXP 't1'\"},\n\t\t{\"a regexp '^[abc][0-9]{11}|ok$'\", \"`a` REGEXP '^[abc][0-9]{11}|ok$'\"},\n\t\t{\"a rlike 't1'\", \"`a` REGEXP 't1'\"},\n\t\t{\"a rlike '^[abc][0-9]{11}|ok$'\", \"`a` REGEXP '^[abc][0-9]{11}|ok$'\"},\n\t\t{\"a not regexp 't1'\", \"`a` NOT REGEXP 't1'\"},\n\t\t{\"a not regexp '^[abc][0-9]{11}|ok$'\", \"`a` NOT REGEXP '^[abc][0-9]{11}|ok$'\"},\n\t\t{\"a not rlike 't1'\", \"`a` NOT REGEXP 't1'\"},\n\t\t{\"a not rlike '^[abc][0-9]{11}|ok$'\", \"`a` NOT REGEXP '^[abc][0-9]{11}|ok$'\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestRowExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"(1,2)\", \"ROW(1,2)\"},\n\t\t{\"(col1,col2)\", \"ROW(`col1`,`col2`)\"},\n\t\t{\"row(1,2)\", \"ROW(1,2)\"},\n\t\t{\"row(col1,col2)\", \"ROW(`col1`,`col2`)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Where.(*BinaryOperationExpr).L\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select 1 from t1 where %s = row(1,2)\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestMaxValueExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"maxvalue\", \"MAXVALUE\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*AlterTableStmt).Specs[0].PartDefinitions[0].Clause.(*PartitionDefinitionClauseLessThan).Exprs[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"alter table posts add partition ( partition p1 values less than %s)\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestPositionExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"1\", \"1\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).OrderBy.Items[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select * from t order by %s\", extractNodeFunc)\n\n}\n\nfunc (tc *testExpressionsSuite) TestExistsSubqueryExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"EXISTS (SELECT 2)\", \"EXISTS (SELECT 2)\"},\n\t\t{\"NOT EXISTS (SELECT 2)\", \"NOT EXISTS (SELECT 2)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Where\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select 1 from t1 where %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestVariableExpr(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"@a>1\", \"@`a`>1\"},\n\t\t{\"@`aB`+1\", \"@`aB`+1\"},\n\t\t{\"@'a':=1\", \"@`a`:=1\"},\n\t\t{\"@`a``b`=4\", \"@`a``b`=4\"},\n\t\t{`@\"aBC\">1`, \"@`aBC`>1\"},\n\t\t{\"@`a`+1\", \"@`a`+1\"},\n\t\t{\"@``\", \"@``\"},\n\t\t{\"@\", \"@``\"},\n\t\t{\"@@``\", \"@@``\"},\n\t\t{\"@@\", \"@@``\"},\n\t\t{\"@@var\", \"@@`var`\"},\n\t\t{\"@@global.b='foo'\", \"@@GLOBAL.`b`='foo'\"},\n\t\t{\"@@session.'C'\", \"@@SESSION.`c`\"},\n\t\t{`@@local.\"aBc\"`, \"@@SESSION.`abc`\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (tc *testExpressionsSuite) TestMatchAgainstExpr(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{`MATCH(content, title) AGAINST ('search for')`, \"MATCH (`content`,`title`) AGAINST ('search for')\"},\n\t\t{`MATCH(content) AGAINST ('search for' IN BOOLEAN MODE)`, \"MATCH (`content`) AGAINST ('search for' IN BOOLEAN MODE)\"},\n\t\t{`MATCH(content, title) AGAINST ('search for' WITH QUERY EXPANSION)`, \"MATCH (`content`,`title`) AGAINST ('search for' WITH QUERY EXPANSION)\"},\n\t\t{`MATCH(content) AGAINST ('search for' IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION)`, \"MATCH (`content`) AGAINST ('search for' WITH QUERY EXPANSION)\"},\n\t\t{`MATCH(content) AGAINST ('search') AND id = 1`, \"MATCH (`content`) AGAINST ('search') AND `id`=1\"},\n\t\t{`MATCH(content) AGAINST ('search') OR id = 1`, \"MATCH (`content`) AGAINST ('search') OR `id`=1\"},\n\t\t{`MATCH(content) AGAINST (X'40404040' | X'01020304') OR id = 1`, \"MATCH (`content`) AGAINST (x'40404040'|x'01020304') OR `id`=1\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Where\n\t}\n\tRunNodeRestoreTest(c, testCases, \"SELECT * FROM t WHERE %s\", extractNodeFunc)\n}\n"
  },
  {
    "path": "pkg/parser/ast/flag.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\n// HasAggFlag checks if the expr contains FlagHasAggregateFunc.\nfunc HasAggFlag(expr ExprNode) bool {\n\treturn expr.GetFlag()&FlagHasAggregateFunc > 0\n}\n\nfunc HasWindowFlag(expr ExprNode) bool {\n\treturn expr.GetFlag()&FlagHasWindowFunc > 0\n}\n\n// SetFlag sets flag for expression.\nfunc SetFlag(n Node) {\n\tvar setter flagSetter\n\tn.Accept(&setter)\n}\n\ntype flagSetter struct {\n}\n\nfunc (f *flagSetter) Enter(in Node) (Node, bool) {\n\treturn in, false\n}\n\nfunc (f *flagSetter) Leave(in Node) (Node, bool) {\n\tif x, ok := in.(ParamMarkerExpr); ok {\n\t\tx.SetFlag(FlagHasParamMarker)\n\t}\n\tswitch x := in.(type) {\n\tcase *AggregateFuncExpr:\n\t\tf.aggregateFunc(x)\n\tcase *WindowFuncExpr:\n\t\tf.windowFunc(x)\n\tcase *BetweenExpr:\n\t\tx.SetFlag(x.Expr.GetFlag() | x.Left.GetFlag() | x.Right.GetFlag())\n\tcase *BinaryOperationExpr:\n\t\tx.SetFlag(x.L.GetFlag() | x.R.GetFlag())\n\tcase *CaseExpr:\n\t\tf.caseExpr(x)\n\tcase *ColumnNameExpr:\n\t\tx.SetFlag(FlagHasReference)\n\tcase *CompareSubqueryExpr:\n\t\tx.SetFlag(x.L.GetFlag() | x.R.GetFlag())\n\tcase *DefaultExpr:\n\t\tx.SetFlag(FlagHasDefault)\n\tcase *ExistsSubqueryExpr:\n\t\tx.SetFlag(x.Sel.GetFlag())\n\tcase *FuncCallExpr:\n\t\tf.funcCall(x)\n\tcase *FuncCastExpr:\n\t\tx.SetFlag(FlagHasFunc | x.Expr.GetFlag())\n\tcase *IsNullExpr:\n\t\tx.SetFlag(x.Expr.GetFlag())\n\tcase *IsTruthExpr:\n\t\tx.SetFlag(x.Expr.GetFlag())\n\tcase *ParenthesesExpr:\n\t\tx.SetFlag(x.Expr.GetFlag())\n\tcase *PatternInExpr:\n\t\tf.patternIn(x)\n\tcase *PatternLikeExpr:\n\t\tf.patternLike(x)\n\tcase *PatternRegexpExpr:\n\t\tf.patternRegexp(x)\n\tcase *PositionExpr:\n\t\tx.SetFlag(FlagHasReference)\n\tcase *RowExpr:\n\t\tf.row(x)\n\tcase *SubqueryExpr:\n\t\tx.SetFlag(FlagHasSubquery)\n\tcase *UnaryOperationExpr:\n\t\tx.SetFlag(x.V.GetFlag())\n\tcase *ValuesExpr:\n\t\tx.SetFlag(FlagHasReference)\n\tcase *VariableExpr:\n\t\tif x.Value == nil {\n\t\t\tx.SetFlag(FlagHasVariable)\n\t\t} else {\n\t\t\tx.SetFlag(FlagHasVariable | x.Value.GetFlag())\n\t\t}\n\t}\n\n\treturn in, true\n}\n\nfunc (f *flagSetter) caseExpr(x *CaseExpr) {\n\tvar flag uint64\n\tif x.Value != nil {\n\t\tflag |= x.Value.GetFlag()\n\t}\n\tfor _, val := range x.WhenClauses {\n\t\tflag |= val.Expr.GetFlag()\n\t\tflag |= val.Result.GetFlag()\n\t}\n\tif x.ElseClause != nil {\n\t\tflag |= x.ElseClause.GetFlag()\n\t}\n\tx.SetFlag(flag)\n}\n\nfunc (f *flagSetter) patternIn(x *PatternInExpr) {\n\tflag := x.Expr.GetFlag()\n\tfor _, val := range x.List {\n\t\tflag |= val.GetFlag()\n\t}\n\tif x.Sel != nil {\n\t\tflag |= x.Sel.GetFlag()\n\t}\n\tx.SetFlag(flag)\n}\n\nfunc (f *flagSetter) patternLike(x *PatternLikeExpr) {\n\tflag := x.Pattern.GetFlag()\n\tif x.Expr != nil {\n\t\tflag |= x.Expr.GetFlag()\n\t}\n\tx.SetFlag(flag)\n}\n\nfunc (f *flagSetter) patternRegexp(x *PatternRegexpExpr) {\n\tflag := x.Pattern.GetFlag()\n\tif x.Expr != nil {\n\t\tflag |= x.Expr.GetFlag()\n\t}\n\tx.SetFlag(flag)\n}\n\nfunc (f *flagSetter) row(x *RowExpr) {\n\tvar flag uint64\n\tfor _, val := range x.Values {\n\t\tflag |= val.GetFlag()\n\t}\n\tx.SetFlag(flag)\n}\n\nfunc (f *flagSetter) funcCall(x *FuncCallExpr) {\n\tflag := FlagHasFunc\n\tfor _, val := range x.Args {\n\t\tflag |= val.GetFlag()\n\t}\n\tx.SetFlag(flag)\n}\n\nfunc (f *flagSetter) aggregateFunc(x *AggregateFuncExpr) {\n\tflag := FlagHasAggregateFunc\n\tfor _, val := range x.Args {\n\t\tflag |= val.GetFlag()\n\t}\n\tx.SetFlag(flag)\n}\n\nfunc (f *flagSetter) windowFunc(x *WindowFuncExpr) {\n\tflag := FlagHasWindowFunc\n\tfor _, val := range x.Args {\n\t\tflag |= val.GetFlag()\n\t}\n\tx.SetFlag(flag)\n}\n"
  },
  {
    "path": "pkg/parser/ast/flag_test.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nvar _ = Suite(&testFlagSuite{})\n\ntype testFlagSuite struct {\n\t*parser.Parser\n}\n\nfunc (ts *testFlagSuite) SetUpSuite(c *C) {\n\tts.Parser = parser.New()\n}\n\nfunc (ts *testFlagSuite) TestHasAggFlag(c *C) {\n\texpr := &ast.BetweenExpr{}\n\tflagTests := []struct {\n\t\tflag   uint64\n\t\thasAgg bool\n\t}{\n\t\t{ast.FlagHasAggregateFunc, true},\n\t\t{ast.FlagHasAggregateFunc | ast.FlagHasVariable, true},\n\t\t{ast.FlagHasVariable, false},\n\t}\n\tfor _, tt := range flagTests {\n\t\texpr.SetFlag(tt.flag)\n\t\tc.Assert(ast.HasAggFlag(expr), Equals, tt.hasAgg)\n\t}\n}\n\nfunc (ts *testFlagSuite) TestFlag(c *C) {\n\tflagTests := []struct {\n\t\texpr string\n\t\tflag uint64\n\t}{\n\t\t{\n\t\t\t\"1 between 0 and 2\",\n\t\t\tast.FlagConstant,\n\t\t},\n\t\t{\n\t\t\t\"case 1 when 1 then 1 else 0 end\",\n\t\t\tast.FlagConstant,\n\t\t},\n\t\t{\n\t\t\t\"case 1 when 1 then 1 else 0 end\",\n\t\t\tast.FlagConstant,\n\t\t},\n\t\t{\n\t\t\t\"case 1 when a > 1 then 1 else 0 end\",\n\t\t\tast.FlagConstant | ast.FlagHasReference,\n\t\t},\n\t\t{\n\t\t\t\"1 = ANY (select 1) OR exists (select 1)\",\n\t\t\tast.FlagHasSubquery,\n\t\t},\n\t\t{\n\t\t\t\"1 in (1) or 1 is true or null is null or 'abc' like 'abc' or 'abc' rlike 'abc'\",\n\t\t\tast.FlagConstant,\n\t\t},\n\t\t{\n\t\t\t\"row (1, 1) = row (1, 1)\",\n\t\t\tast.FlagConstant,\n\t\t},\n\t\t{\n\t\t\t\"(1 + a) > {{param1}}\",\n\t\t\tast.FlagHasReference | ast.FlagHasParamMarker,\n\t\t},\n\t\t{\n\t\t\t\"trim('abc ')\",\n\t\t\tast.FlagHasFunc,\n\t\t},\n\t\t{\n\t\t\t\"now() + EXTRACT(YEAR FROM '2009-07-02') + CAST(1 AS UNSIGNED)\",\n\t\t\tast.FlagHasFunc,\n\t\t},\n\t\t{\n\t\t\t\"substring('abc', 1)\",\n\t\t\tast.FlagHasFunc,\n\t\t},\n\t\t{\n\t\t\t\"sum(a)\",\n\t\t\tast.FlagHasAggregateFunc | ast.FlagHasReference,\n\t\t},\n\t\t{\n\t\t\t\"(select 1) as a\",\n\t\t\tast.FlagHasSubquery,\n\t\t},\n\t\t{\n\t\t\t\"@auto_commit\",\n\t\t\tast.FlagHasVariable,\n\t\t},\n\t\t{\n\t\t\t\"default(a)\",\n\t\t\tast.FlagHasDefault,\n\t\t},\n\t\t{\n\t\t\t\"a is null\",\n\t\t\tast.FlagHasReference,\n\t\t},\n\t\t{\n\t\t\t\"1 is true\",\n\t\t\tast.FlagConstant,\n\t\t},\n\t\t{\n\t\t\t\"a in (1, count(*), 3)\",\n\t\t\tast.FlagConstant | ast.FlagHasReference | ast.FlagHasAggregateFunc,\n\t\t},\n\t\t{\n\t\t\t\"'Michael!' REGEXP '.*'\",\n\t\t\tast.FlagConstant,\n\t\t},\n\t\t{\n\t\t\t\"a REGEXP '.*'\",\n\t\t\tast.FlagHasReference,\n\t\t},\n\t\t{\n\t\t\t\"-a\",\n\t\t\tast.FlagHasReference,\n\t\t},\n\t}\n\tfor _, tt := range flagTests {\n\t\tstmt, err := ts.ParseOneStmt(\"select \"+tt.expr, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\t\tselectStmt := stmt.(*ast.SelectStmt)\n\t\tast.SetFlag(selectStmt)\n\t\texpr := selectStmt.Fields.Fields[0].Expr\n\t\tc.Assert(expr.GetFlag(), Equals, tt.flag, Commentf(\"For %s\", tt.expr))\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/ast/format_test.go",
    "content": "package ast_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\nvar _ = Suite(&testAstFormatSuite{})\n\ntype testAstFormatSuite struct {\n}\n\nfunc getDefaultCharsetAndCollate() (string, string) {\n\treturn \"utf8\", \"utf8_bin\"\n}\n\nfunc (ts *testAstFormatSuite) TestAstFormat(c *C) {\n\tvar testcases = []struct {\n\t\tinput  string\n\t\toutput string\n\t}{\n\t\t// Literals.\n\t\t{`null`, `NULL`},\n\t\t{`true`, `TRUE`},\n\t\t{`350`, `350`},\n\t\t{`001e-12`, `1e-12`}, // Float.\n\t\t{`345.678`, `345.678`},\n\t\t{`00.0001000`, `0.0001000`}, // Decimal.\n\t\t{`null`, `NULL`},\n\t\t{`\"Hello, world\"`, `\"Hello, world\"`},\n\t\t{`'Hello, world'`, `\"Hello, world\"`},\n\t\t{`'Hello, \"world\"'`, `\"Hello, \\\"world\\\"\"`},\n\t\t{`_utf8'你好'`, `\"你好\"`},\n\t\t{`x'bcde'`, \"x'bcde'\"},\n\t\t{`x''`, \"x''\"},\n\t\t{`x'0035'`, \"x'0035'\"}, // Shouldn't trim leading zero.\n\t\t{`b'00111111'`, `b'111111'`},\n\t\t{`time'10:10:10.123'`, ast.TimeLiteral + `(\"10:10:10.123\")`},\n\t\t{`timestamp'1999-01-01 10:0:0.123'`, ast.TimestampLiteral + `(\"1999-01-01 10:0:0.123\")`},\n\t\t{`date '1700-01-01'`, ast.DateLiteral + `(\"1700-01-01\")`},\n\n\t\t// Expressions.\n\t\t{`f between 30 and 50`, \"`f` BETWEEN 30 AND 50\"},\n\t\t{`f not between 30 and 50`, \"`f` NOT BETWEEN 30 AND 50\"},\n\t\t{`345 + \"  hello  \"`, `345 + \"  hello  \"`},\n\t\t{`\"hello world\"    >=    'hello world'`, `\"hello world\" >= \"hello world\"`},\n\t\t{`case 3 when 1 then false else true end`, `CASE 3 WHEN 1 THEN FALSE ELSE TRUE END`},\n\t\t{`database.table.column`, \"`database`.`table`.`column`\"}, // ColumnNameExpr\n\t\t{`3 is null`, `3 IS NULL`},\n\t\t{`3 is not null`, `3 IS NOT NULL`},\n\t\t{`3 is true`, `3 IS TRUE`},\n\t\t{`3 is not true`, `3 IS NOT TRUE`},\n\t\t{`3 is false`, `3 IS FALSE`},\n\t\t{`  ( x is false  )`, \"(`x` IS FALSE)\"},\n\t\t{`3 in ( a,b,\"h\",6 )`, \"3 IN (`a`,`b`,\\\"h\\\",6)\"},\n\t\t{`3 not in ( a,b,\"h\",6 )`, \"3 NOT IN (`a`,`b`,\\\"h\\\",6)\"},\n\t\t{`\"abc\" like '%b%'`, `\"abc\" LIKE \"%b%\"`},\n\t\t{`\"abc\" not like '%b%'`, `\"abc\" NOT LIKE \"%b%\"`},\n\t\t{`\"abc\" like '%b%' escape '_'`, `\"abc\" LIKE \"%b%\" ESCAPE '_'`},\n\t\t{`\"abc\" regexp '.*bc?'`, `\"abc\" REGEXP \".*bc?\"`},\n\t\t{`\"abc\" not regexp '.*bc?'`, `\"abc\" NOT REGEXP \".*bc?\"`},\n\t\t{`-  4`, `-4`},\n\t\t{`- ( - 4 ) `, `-(-4)`},\n\t\t{`a%b`, \"`a` % `b`\"},\n\t\t{`a%b+6`, \"`a` % `b` + 6\"},\n\t\t{`a%(b+6)`, \"`a` % (`b` + 6)\"},\n\t\t// Functions.\n\t\t{` json_extract ( a,'$.b',\"$.\\\"c d\\\"\" ) `, \"json_extract(`a`, \\\"$.b\\\", \\\"$.\\\\\\\"c d\\\\\\\"\\\")\"},\n\t\t{` length ( a )`, \"length(`a`)\"},\n\t\t{`a -> '$.a'`, \"json_extract(`a`, \\\"$.a\\\")\"},\n\t\t{`a.b ->> '$.a'`, \"json_unquote(json_extract(`a`.`b`, \\\"$.a\\\"))\"},\n\t\t{`DATE_ADD('1970-01-01', interval 3 second)`, `date_add(\"1970-01-01\", INTERVAL 3 SECOND)`},\n\t\t{`TIMESTAMPDIFF(month, '2001-01-01', '2001-02-02 12:03:05.123')`, `timestampdiff(MONTH, \"2001-01-01\", \"2001-02-02 12:03:05.123\")`},\n\t\t// Cast, Convert and Binary.\n\t\t// There should not be spaces between 'cast' and '(' unless 'IGNORE_SPACE' mode is set.\n\t\t// see: https://dev.mysql.com/doc/refman/5.7/en/function-resolution.html\n\t\t{` cast( a as signed ) `, \"CAST(`a` AS SIGNED)\"},\n\t\t{` cast( a as unsigned integer) `, \"CAST(`a` AS UNSIGNED)\"},\n\t\t{` cast( a as decimal ) `, \"CAST(`a` AS DECIMAL(11))\"},\n\t\t{` cast( a as decimal (3) ) `, \"CAST(`a` AS DECIMAL(3))\"},\n\t\t{` cast( a as decimal (3,3) ) `, \"CAST(`a` AS DECIMAL(3, 3))\"},\n\t\t{` ((case when (c0 = 0) then 0 when (c0 > 0) then (c1 / c0) end)) `, \"((CASE WHEN (`c0` = 0) THEN 0 WHEN (`c0` > 0) THEN (`c1` / `c0`) END))\"},\n\t\t{` convert (a, signed) `, \"CONVERT(`a`, SIGNED)\"},\n\t\t{` binary \"hello\"`, `BINARY \"hello\"`},\n\t}\n\tfor _, tt := range testcases {\n\t\texpr := fmt.Sprintf(\"select %s\", tt.input)\n\t\tcharset, collation := getDefaultCharsetAndCollate()\n\t\tstmts, _, err := parser.New().Parse(expr, charset, collation)\n\t\tnode := stmts[0].(*ast.SelectStmt).Fields.Fields[0].Expr\n\t\tc.Assert(err, IsNil)\n\n\t\twriter := bytes.NewBufferString(\"\")\n\t\tnode.Format(writer)\n\t\tc.Assert(writer.String(), Equals, tt.output)\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/ast/functions.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/types\"\n)\n\nvar (\n\t_ FuncNode = &AggregateFuncExpr{}\n\t_ FuncNode = &FuncCallExpr{}\n\t_ FuncNode = &FuncCastExpr{}\n\t_ FuncNode = &WindowFuncExpr{}\n)\n\n// List scalar function names.\nconst (\n\tLogicAnd   = \"and\"\n\tCast       = \"cast\"\n\tLeftShift  = \"leftshift\"\n\tRightShift = \"rightshift\"\n\tLogicOr    = \"or\"\n\tGE         = \"ge\"\n\tLE         = \"le\"\n\tEQ         = \"eq\"\n\tNE         = \"ne\"\n\tLT         = \"lt\"\n\tGT         = \"gt\"\n\tPlus       = \"plus\"\n\tMinus      = \"minus\"\n\tAnd        = \"bitand\"\n\tOr         = \"bitor\"\n\tMod        = \"mod\"\n\tXor        = \"bitxor\"\n\tDiv        = \"div\"\n\tMul        = \"mul\"\n\tUnaryNot   = \"not\" // Avoid name conflict with Not in github/pingcap/check.\n\tBitNeg     = \"bitneg\"\n\tIntDiv     = \"intdiv\"\n\tLogicXor   = \"xor\"\n\tNullEQ     = \"nulleq\"\n\tUnaryPlus  = \"unaryplus\"\n\tUnaryMinus = \"unaryminus\"\n\tIn         = \"in\"\n\tLike       = \"like\"\n\tCase       = \"case\"\n\tRegexp     = \"regexp\"\n\tIsNull     = \"isnull\"\n\tIsTruth    = \"istrue\"  // Avoid name conflict with IsTrue in github/pingcap/check.\n\tIsFalsity  = \"isfalse\" // Avoid name conflict with IsFalse in github/pingcap/check.\n\tRowFunc    = \"row\"\n\tSetVar     = \"setvar\"\n\tGetVar     = \"getvar\"\n\tValues     = \"values\"\n\tBitCount   = \"bit_count\"\n\tGetParam   = \"getparam\"\n\n\t// common functions\n\tCoalesce = \"coalesce\"\n\tGreatest = \"greatest\"\n\tLeast    = \"least\"\n\tInterval = \"interval\"\n\n\t// math functions\n\tAbs      = \"abs\"\n\tAcos     = \"acos\"\n\tAsin     = \"asin\"\n\tAtan     = \"atan\"\n\tAtan2    = \"atan2\"\n\tCeil     = \"ceil\"\n\tCeiling  = \"ceiling\"\n\tConv     = \"conv\"\n\tCos      = \"cos\"\n\tCot      = \"cot\"\n\tCRC32    = \"crc32\"\n\tDegrees  = \"degrees\"\n\tExp      = \"exp\"\n\tFloor    = \"floor\"\n\tLn       = \"ln\"\n\tLog      = \"log\"\n\tLog2     = \"log2\"\n\tLog10    = \"log10\"\n\tPI       = \"pi\"\n\tPow      = \"pow\"\n\tPower    = \"power\"\n\tRadians  = \"radians\"\n\tRand     = \"rand\"\n\tRound    = \"round\"\n\tSign     = \"sign\"\n\tSin      = \"sin\"\n\tSqrt     = \"sqrt\"\n\tTan      = \"tan\"\n\tTruncate = \"truncate\"\n\n\t// time functions\n\tAddDate          = \"adddate\"\n\tAddTime          = \"addtime\"\n\tConvertTz        = \"convert_tz\"\n\tCurdate          = \"curdate\"\n\tCurrentDate      = \"current_date\"\n\tCurrentTime      = \"current_time\"\n\tCurrentTimestamp = \"current_timestamp\"\n\tCurtime          = \"curtime\"\n\tDate             = \"date\"\n\tDateLiteral      = \"'tidb`.(dateliteral\"\n\tDateAdd          = \"date_add\"\n\tDateFormat       = \"date_format\"\n\tDateSub          = \"date_sub\"\n\tDateDiff         = \"datediff\"\n\tDay              = \"day\"\n\tDayName          = \"dayname\"\n\tDayOfMonth       = \"dayofmonth\"\n\tDayOfWeek        = \"dayofweek\"\n\tDayOfYear        = \"dayofyear\"\n\tExtract          = \"extract\"\n\tFromDays         = \"from_days\"\n\tFromUnixTime     = \"from_unixtime\"\n\tGetFormat        = \"get_format\"\n\tHour             = \"hour\"\n\tLocalTime        = \"localtime\"\n\tLocalTimestamp   = \"localtimestamp\"\n\tMakeDate         = \"makedate\"\n\tMakeTime         = \"maketime\"\n\tMicroSecond      = \"microsecond\"\n\tMinute           = \"minute\"\n\tMonth            = \"month\"\n\tMonthName        = \"monthname\"\n\tNow              = \"now\"\n\tPeriodAdd        = \"period_add\"\n\tPeriodDiff       = \"period_diff\"\n\tQuarter          = \"quarter\"\n\tSecToTime        = \"sec_to_time\"\n\tSecond           = \"second\"\n\tStrToDate        = \"str_to_date\"\n\tSubDate          = \"subdate\"\n\tSubTime          = \"subtime\"\n\tSysdate          = \"sysdate\"\n\tTime             = \"time\"\n\tTimeLiteral      = \"'tidb`.(timeliteral\"\n\tTimeFormat       = \"time_format\"\n\tTimeToSec        = \"time_to_sec\"\n\tTimeDiff         = \"timediff\"\n\tTimestamp        = \"timestamp\"\n\tTimestampLiteral = \"'tidb`.(timestampliteral\"\n\tTimestampAdd     = \"timestampadd\"\n\tTimestampDiff    = \"timestampdiff\"\n\tToDays           = \"to_days\"\n\tToSeconds        = \"to_seconds\"\n\tUnixTimestamp    = \"unix_timestamp\"\n\tUTCDate          = \"utc_date\"\n\tUTCTime          = \"utc_time\"\n\tUTCTimestamp     = \"utc_timestamp\"\n\tWeek             = \"week\"\n\tWeekday          = \"weekday\"\n\tWeekOfYear       = \"weekofyear\"\n\tYear             = \"year\"\n\tYearWeek         = \"yearweek\"\n\tLastDay          = \"last_day\"\n\tTiDBParseTso     = \"tidb_parse_tso\"\n\n\t// string functions\n\tASCII           = \"ascii\"\n\tBin             = \"bin\"\n\tConcat          = \"concat\"\n\tConcatWS        = \"concat_ws\"\n\tConvert         = \"convert\"\n\tElt             = \"elt\"\n\tExportSet       = \"export_set\"\n\tField           = \"field\"\n\tFormat          = \"format\"\n\tFromBase64      = \"from_base64\"\n\tInsertFunc      = \"insert_func\"\n\tInstr           = \"instr\"\n\tLcase           = \"lcase\"\n\tLeft            = \"left\"\n\tLength          = \"length\"\n\tLoadFile        = \"load_file\"\n\tLocate          = \"locate\"\n\tLower           = \"lower\"\n\tLpad            = \"lpad\"\n\tLTrim           = \"ltrim\"\n\tMakeSet         = \"make_set\"\n\tMid             = \"mid\"\n\tOct             = \"oct\"\n\tOctetLength     = \"octet_length\"\n\tOrd             = \"ord\"\n\tPosition        = \"position\"\n\tQuote           = \"quote\"\n\tRepeat          = \"repeat\"\n\tReplace         = \"replace\"\n\tReverse         = \"reverse\"\n\tRight           = \"right\"\n\tRTrim           = \"rtrim\"\n\tSpace           = \"space\"\n\tStrcmp          = \"strcmp\"\n\tSubstring       = \"substring\"\n\tSubstr          = \"substr\"\n\tSubstringIndex  = \"substring_index\"\n\tToBase64        = \"to_base64\"\n\tTrim            = \"trim\"\n\tUpper           = \"upper\"\n\tUcase           = \"ucase\"\n\tHex             = \"hex\"\n\tUnhex           = \"unhex\"\n\tRpad            = \"rpad\"\n\tBitLength       = \"bit_length\"\n\tCharFunc        = \"char_func\"\n\tCharLength      = \"char_length\"\n\tCharacterLength = \"character_length\"\n\tFindInSet       = \"find_in_set\"\n\n\t// information functions\n\tBenchmark      = \"benchmark\"\n\tCharset        = \"charset\"\n\tCoercibility   = \"coercibility\"\n\tCollation      = \"collation\"\n\tConnectionID   = \"connection_id\"\n\tCurrentUser    = \"current_user\"\n\tCurrentRole    = \"current_role\"\n\tDatabase       = \"database\"\n\tFoundRows      = \"found_rows\"\n\tLastInsertId   = \"last_insert_id\"\n\tRowCount       = \"row_count\"\n\tSchema         = \"schema\"\n\tSessionUser    = \"session_user\"\n\tSystemUser     = \"system_user\"\n\tUser           = \"user\"\n\tVersion        = \"version\"\n\tTiDBVersion    = \"tidb_version\"\n\tTiDBIsDDLOwner = \"tidb_is_ddl_owner\"\n\tTiDBDecodePlan = \"tidb_decode_plan\"\n\n\t// control functions\n\tIf     = \"if\"\n\tIfnull = \"ifnull\"\n\tNullif = \"nullif\"\n\n\t// miscellaneous functions\n\tAnyValue        = \"any_value\"\n\tDefaultFunc     = \"default_func\"\n\tInetAton        = \"inet_aton\"\n\tInetNtoa        = \"inet_ntoa\"\n\tInet6Aton       = \"inet6_aton\"\n\tInet6Ntoa       = \"inet6_ntoa\"\n\tIsFreeLock      = \"is_free_lock\"\n\tIsIPv4          = \"is_ipv4\"\n\tIsIPv4Compat    = \"is_ipv4_compat\"\n\tIsIPv4Mapped    = \"is_ipv4_mapped\"\n\tIsIPv6          = \"is_ipv6\"\n\tIsUsedLock      = \"is_used_lock\"\n\tMasterPosWait   = \"master_pos_wait\"\n\tNameConst       = \"name_const\"\n\tReleaseAllLocks = \"release_all_locks\"\n\tSleep           = \"sleep\"\n\tUUID            = \"uuid\"\n\tUUIDShort       = \"uuid_short\"\n\t// get_lock() and release_lock() is parsed but do nothing.\n\t// It is used for preventing error in Ruby's activerecord migrations.\n\tGetLock     = \"get_lock\"\n\tReleaseLock = \"release_lock\"\n\n\t// encryption and compression functions\n\tAesDecrypt               = \"aes_decrypt\"\n\tAesEncrypt               = \"aes_encrypt\"\n\tCompress                 = \"compress\"\n\tDecode                   = \"decode\"\n\tDesDecrypt               = \"des_decrypt\"\n\tDesEncrypt               = \"des_encrypt\"\n\tEncode                   = \"encode\"\n\tEncrypt                  = \"encrypt\"\n\tMD5                      = \"md5\"\n\tOldPassword              = \"old_password\"\n\tPasswordFunc             = \"password_func\"\n\tRandomBytes              = \"random_bytes\"\n\tSHA1                     = \"sha1\"\n\tSHA                      = \"sha\"\n\tSHA2                     = \"sha2\"\n\tUncompress               = \"uncompress\"\n\tUncompressedLength       = \"uncompressed_length\"\n\tValidatePasswordStrength = \"validate_password_strength\"\n\n\t// json functions\n\tJSONType          = \"json_type\"\n\tJSONExtract       = \"json_extract\"\n\tJSONUnquote       = \"json_unquote\"\n\tJSONArray         = \"json_array\"\n\tJSONObject        = \"json_object\"\n\tJSONMerge         = \"json_merge\"\n\tJSONSet           = \"json_set\"\n\tJSONInsert        = \"json_insert\"\n\tJSONReplace       = \"json_replace\"\n\tJSONRemove        = \"json_remove\"\n\tJSONContains      = \"json_contains\"\n\tJSONContainsPath  = \"json_contains_path\"\n\tJSONValid         = \"json_valid\"\n\tJSONArrayAppend   = \"json_array_append\"\n\tJSONArrayInsert   = \"json_array_insert\"\n\tJSONMergePatch    = \"json_merge_patch\"\n\tJSONMergePreserve = \"json_merge_preserve\"\n\tJSONPretty        = \"json_pretty\"\n\tJSONQuote         = \"json_quote\"\n\tJSONSearch        = \"json_search\"\n\tJSONStorageSize   = \"json_storage_size\"\n\tJSONDepth         = \"json_depth\"\n\tJSONKeys          = \"json_keys\"\n\tJSONLength        = \"json_length\"\n\n\t// TiDB internal function.\n\tTiDBDecodeKey = \"tidb_decode_key\"\n\n\t// get geography distance with two given points(longtidude, latitude)\n\tGeoDist = \"geodist\"\n)\n\nvar DateFunc = map[string]bool{\n\tAddDate:    true,\n\tDateAdd:    true,\n\tCurdate:    true,\n\tDateDiff:   true,\n\tNow:        true,\n\tSubDate:    true,\n\tDateSub:    true,\n\tLastDay:    true,\n\tStrToDate:  true,\n\tDateFormat: true,\n}\n\nvar DateFuncArgsNum = map[string]int{\n\tNow:        0,\n\tCurdate:    0,\n\tStrToDate:  2,\n\tDateFormat: 2,\n\tAddDate:    3,\n\tSubDate:    3,\n}\n\n// FuncCallExpr is for function expression.\ntype FuncCallExpr struct {\n\tfuncNode\n\t// FnName is the function name.\n\tFnName model.CIStr\n\t// Args is the function args.\n\tArgs []ExprNode\n}\n\nfunc (n *FuncCallExpr) checkDateFuncArgsNum() error {\n\tif expectedNum, ok := DateFuncArgsNum[n.FnName.L]; ok {\n\t\tif expectedNum != len(n.Args) {\n\t\t\treturn fmt.Errorf(\"%s func need %d args, but got %d args\", n.FnName.L, expectedNum, len(n.Args))\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (n *FuncCallExpr) RestoreDateFuncWithMysqlDialect(ctx *RestoreCtx) (err error) {\n\tctx.WriteKeyWord(n.FnName.O)\n\tctx.WritePlain(\"(\")\n\tswitch n.FnName.L {\n\tcase AddDate, SubDate, DateAdd, DateSub:\n\t\tif err = n.Args[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[0]\")\n\t\t}\n\t\tctx.WritePlain(\", \")\n\t\tctx.WriteKeyWord(\"INTERVAL \")\n\t\tif err := n.Args[1].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[1]\")\n\t\t}\n\t\tctx.WritePlain(\" \")\n\t\told_ctx_flags := ctx.Flags\n\t\tctx.Flags &= ^format.RestoreStringSingleQuotes\n\t\tif err := n.Args[2].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[2]\")\n\t\t}\n\t\tctx.Flags = old_ctx_flags\n\tdefault:\n\t\tfor i, argv := range n.Args {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tif err := argv.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args %d\", i)\n\t\t\t}\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\treturn nil\n}\n\nfunc (n *FuncCallExpr) RestoreDateFuncWithPostgresDialect(ctx *RestoreCtx) (err error) {\n\tswitch n.FnName.L {\n\tcase Now:\n\t\tctx.WriteKeyWord(n.FnName.O)\n\t\tctx.WritePlain(\"()\")\n\tcase Curdate:\n\t\tctx.WriteKeyWord(ctx.Dialect.GetSpecialFuncName(n.FnName.L))\n\tcase AddDate, SubDate, DateAdd, DateSub:\n\t\tif err = n.Args[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[0]\")\n\t\t}\n\t\tctx.WriteKeyWord(ctx.Dialect.GetSpecialFuncName(n.FnName.L))\n\t\tctx.WriteKeyWord(\" INTERVAL '\")\n\t\tif err := n.Args[1].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[1]\")\n\t\t}\n\t\tctx.WritePlain(\" \")\n\t\t// timeunit donot need to add single quotes\n\t\told_ctx_flags := ctx.Flags\n\t\tctx.Flags &= ^format.RestoreStringSingleQuotes\n\t\tif err := n.Args[2].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[2]\")\n\t\t}\n\t\tctx.Flags = old_ctx_flags\n\t\tctx.WritePlain(\"'\")\n\tcase DateDiff, LastDay, StrToDate, DateFormat:\n\t\t// postgres donot support datediff op because Poco can not interpret the interval type result;\n\t\t// postgres donot support last_day、str_to_date、date_format becase postgres has not these func: https://m.runoob.com/postgresql/postgresql-datetime.html\n\t\treturn fmt.Errorf(\"an error occurred while restore FuncCallExpr: %s\", n.FnName.L)\n\tdefault:\n\t\tctx.WriteKeyWord(n.FnName.O)\n\t\tctx.WritePlain(\"(\")\n\t\tfor i, argv := range n.Args {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tif err := argv.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args %d\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\treturn nil\n}\n\nfunc (n *FuncCallExpr) RestoreDateFuncWithCSVDBDialect(ctx *RestoreCtx) (err error) {\n\tswitch n.FnName.L {\n\tcase Curdate:\n\t\tctx.WriteKeyWord(ctx.Dialect.GetSpecialFuncName(n.FnName.L))\n\tcase Now:\n\t\tctx.WriteKeyWord(ctx.Dialect.GetSpecialFuncName(n.FnName.L))\n\t\tctx.WritePlain(\"()\")\n\tcase AddDate, SubDate, DateAdd, DateSub:\n\t\tif err = n.Args[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[0]\")\n\t\t}\n\t\tctx.WriteKeyWord(ctx.Dialect.GetSpecialFuncName(n.FnName.L))\n\t\tctx.WriteKeyWord(\"INTERVAL \")\n\t\tif err := n.Args[1].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[1]\")\n\t\t}\n\t\tctx.WritePlain(\" \")\n\t\told_ctx_flags := ctx.Flags\n\t\tctx.Flags &= ^format.RestoreStringSingleQuotes\n\t\tif err := n.Args[2].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[2]\")\n\t\t}\n\t\tctx.Flags = old_ctx_flags\n\tcase DateDiff:\n\t\t// csv donot support datediff op\n\t\treturn fmt.Errorf(\"an error occurred while restore FuncCallExpr: %s\", n.FnName.L)\n\tcase StrToDate:\n\t\tctx.WriteKeyWord(\"strptime\")\n\t\tctx.WritePlain(\"(\")\n\t\tif err = n.Args[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[0]\")\n\t\t}\n\t\tctx.WritePlain(\",\")\n\t\tif err = n.Args[1].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[1]\")\n\t\t}\n\t\tctx.WritePlain(\")\")\n\tcase DateFormat:\n\t\t// csv'format specifiers are diffrent from mysql\n\t\t// csv: https://duckdb.org/docs/archive/0.9.0/sql/functions/dateformat\n\t\t// mysql: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format\n\t\tctx.WriteKeyWord(\"strftime\")\n\t\tctx.WritePlain(\"(\")\n\t\tif err = n.Args[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[0]\")\n\t\t}\n\t\tctx.WritePlain(\",\")\n\t\tif err = n.Args[1].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[1]\")\n\t\t}\n\t\tctx.WritePlain(\")\")\n\tdefault:\n\t\tctx.WriteKeyWord(n.FnName.O)\n\t\tctx.WritePlain(\"(\")\n\t\tfor i, argv := range n.Args {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tif err := argv.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args %d\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\treturn nil\n}\n\n// Restore implements Node interface.\nfunc (n *FuncCallExpr) Restore(ctx *RestoreCtx) error {\n\tif _, ok := DateFunc[n.FnName.L]; ok {\n\t\tif err := n.checkDateFuncArgsNum(); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr: %s\", n.FnName.L)\n\t\t}\n\t\tswitch ctx.Dialect.(type) {\n\t\tcase *PostgresDialect:\n\t\t\treturn n.RestoreDateFuncWithPostgresDialect(ctx)\n\t\tcase *CVSDBDialect:\n\t\t\treturn n.RestoreDateFuncWithCSVDBDialect(ctx)\n\t\tdefault:\n\t\t\treturn n.RestoreDateFuncWithMysqlDialect(ctx)\n\t\t}\n\t}\n\n\tn.FnName = model.NewCIStr(ctx.Dialect.GetSpecialFuncName(n.FnName.L))\n\tvar specialLiteral string\n\tswitch n.FnName.L {\n\tcase DateLiteral:\n\t\tspecialLiteral = \"DATE \"\n\tcase TimeLiteral:\n\t\tspecialLiteral = \"TIME \"\n\tcase TimestampLiteral:\n\t\tspecialLiteral = \"TIMESTAMP \"\n\t}\n\tif specialLiteral != \"\" {\n\t\tctx.WritePlain(specialLiteral)\n\t\tif err := n.Args[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCastExpr.Expr\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tctx.WriteKeyWord(n.FnName.O)\n\tctx.WritePlain(\"(\")\n\tswitch n.FnName.L {\n\tcase \"convert\":\n\t\tif err := n.Args[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCastExpr.Expr\")\n\t\t}\n\t\tctx.WriteKeyWord(\" USING \")\n\t\tctx.WriteKeyWord(n.Args[1].GetType().Charset)\n\tcase \"date_add\", \"date_sub\":\n\t\tif err := n.Args[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[0]\")\n\t\t}\n\t\tctx.WritePlain(\", \")\n\t\tctx.WriteKeyWord(\"INTERVAL \")\n\t\tif err := n.Args[1].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[1]\")\n\t\t}\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.Args[2].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[2]\")\n\t\t}\n\tcase \"extract\":\n\t\tif err := n.Args[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[0]\")\n\t\t}\n\t\tctx.WriteKeyWord(\" FROM \")\n\t\tif err := n.Args[1].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[1]\")\n\t\t}\n\tcase \"position\":\n\t\tif err := n.Args[0].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr\")\n\t\t}\n\t\tctx.WriteKeyWord(\" IN \")\n\t\tif err := n.Args[1].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr\")\n\t\t}\n\tcase \"trim\":\n\t\tswitch len(n.Args) {\n\t\tcase 3:\n\t\t\tif err := n.Args[2].Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[2]\")\n\t\t\t}\n\t\t\tctx.WritePlain(\" \")\n\t\t\tfallthrough\n\t\tcase 2:\n\t\t\tif n.Args[1].(ValueExpr).GetValue() != nil {\n\t\t\t\tif err := n.Args[1].Restore(ctx); err != nil {\n\t\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[1]\")\n\t\t\t\t}\n\t\t\t\tctx.WritePlain(\" \")\n\t\t\t}\n\t\t\tctx.WriteKeyWord(\"FROM \")\n\t\t\tfallthrough\n\t\tcase 1:\n\t\t\tif err := n.Args[0].Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args[0]\")\n\t\t\t}\n\t\t}\n\tdefault:\n\t\tfor i, argv := range n.Args {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tif err := argv.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCallExpr.Args %d\", i)\n\t\t\t}\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *FuncCallExpr) Format(w io.Writer) {\n\tfmt.Fprintf(w, \"%s(\", n.FnName.L)\n\tif !n.specialFormatArgs(w) {\n\t\tfor i, arg := range n.Args {\n\t\t\targ.Format(w)\n\t\t\tif i != len(n.Args)-1 {\n\t\t\t\tfmt.Fprint(w, \", \")\n\t\t\t}\n\t\t}\n\t}\n\tfmt.Fprint(w, \")\")\n}\n\n// specialFormatArgs formats argument list for some special functions.\nfunc (n *FuncCallExpr) specialFormatArgs(w io.Writer) bool {\n\tswitch n.FnName.L {\n\tcase DateAdd, DateSub, AddDate, SubDate:\n\t\tn.Args[0].Format(w)\n\t\tfmt.Fprint(w, \", INTERVAL \")\n\t\tn.Args[1].Format(w)\n\t\tfmt.Fprint(w, \" \")\n\t\tn.Args[2].Format(w)\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Accept implements Node interface.\nfunc (n *FuncCallExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*FuncCallExpr)\n\tfor i, val := range n.Args {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Args[i] = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// CastFunctionType is the type for cast function.\ntype CastFunctionType int\n\n// CastFunction types\nconst (\n\tCastFunction CastFunctionType = iota + 1\n\tCastConvertFunction\n\tCastBinaryOperator\n)\n\n// FuncCastExpr is the cast function converting value to another type, e.g, cast(expr AS signed).\n// See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html\ntype FuncCastExpr struct {\n\tfuncNode\n\t// Expr is the expression to be converted.\n\tExpr ExprNode\n\t// Tp is the conversion type.\n\tTp *types.FieldType\n\t// FunctionType is either Cast, Convert or Binary.\n\tFunctionType CastFunctionType\n}\n\n// Restore implements Node interface.\nfunc (n *FuncCastExpr) Restore(ctx *RestoreCtx) error {\n\tswitch n.FunctionType {\n\tcase CastFunction:\n\t\tctx.WriteKeyWord(\"CAST\")\n\t\tctx.WritePlain(\"(\")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCastExpr.Expr\")\n\t\t}\n\t\tctx.WriteKeyWord(\" AS \")\n\t\terr := n.Tp.RestoreAsCastType(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.WritePlain(\")\")\n\tcase CastConvertFunction:\n\t\tctx.WriteKeyWord(\"CONVERT\")\n\t\tctx.WritePlain(\"(\")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCastExpr.Expr\")\n\t\t}\n\t\tctx.WritePlain(\", \")\n\t\terr := n.Tp.RestoreAsCastType(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.WritePlain(\")\")\n\tcase CastBinaryOperator:\n\t\tctx.WriteKeyWord(\"BINARY \")\n\t\tif err := n.Expr.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FuncCastExpr.Expr\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *FuncCastExpr) Format(w io.Writer) {\n\tswitch n.FunctionType {\n\tcase CastFunction:\n\t\tfmt.Fprint(w, \"CAST(\")\n\t\tn.Expr.Format(w)\n\t\tfmt.Fprint(w, \" AS \")\n\t\tn.Tp.FormatAsCastType(w)\n\t\tfmt.Fprint(w, \")\")\n\tcase CastConvertFunction:\n\t\tfmt.Fprint(w, \"CONVERT(\")\n\t\tn.Expr.Format(w)\n\t\tfmt.Fprint(w, \", \")\n\t\tn.Tp.FormatAsCastType(w)\n\t\tfmt.Fprint(w, \")\")\n\tcase CastBinaryOperator:\n\t\tfmt.Fprint(w, \"BINARY \")\n\t\tn.Expr.Format(w)\n\t}\n}\n\n// Accept implements Node Accept interface.\nfunc (n *FuncCastExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*FuncCastExpr)\n\tnode, ok := n.Expr.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Expr = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// TrimDirectionType is the type for trim direction.\ntype TrimDirectionType int\n\nconst (\n\t// TrimBothDefault trims from both direction by default.\n\tTrimBothDefault TrimDirectionType = iota\n\t// TrimBoth trims from both direction with explicit notation.\n\tTrimBoth\n\t// TrimLeading trims from left.\n\tTrimLeading\n\t// TrimTrailing trims from right.\n\tTrimTrailing\n)\n\n// String implements fmt.Stringer interface.\nfunc (direction TrimDirectionType) String() string {\n\tswitch direction {\n\tcase TrimBoth, TrimBothDefault:\n\t\treturn \"BOTH\"\n\tcase TrimLeading:\n\t\treturn \"LEADING\"\n\tcase TrimTrailing:\n\t\treturn \"TRAILING\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\n// TrimDirectionExpr is an expression representing the trim direction used in the TRIM() function.\ntype TrimDirectionExpr struct {\n\texprNode\n\t// Direction is the trim direction\n\tDirection TrimDirectionType\n}\n\n// Restore implements Node interface.\nfunc (n *TrimDirectionExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(n.Direction.String())\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *TrimDirectionExpr) Format(w io.Writer) {\n\tfmt.Fprint(w, n.Direction.String())\n}\n\n// Accept implements Node Accept interface.\nfunc (n *TrimDirectionExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// DateArithType is type for DateArith type.\ntype DateArithType byte\n\nconst (\n\t// DateArithAdd is to run adddate or date_add function option.\n\t// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate\n\t// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-add\n\tDateArithAdd DateArithType = iota + 1\n\t// DateArithSub is to run subdate or date_sub function option.\n\t// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate\n\t// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-sub\n\tDateArithSub\n)\n\nconst (\n\t// AggFuncCount is the name of Count function.\n\tAggFuncCount = \"count\"\n\t// AggFuncSum is the name of Sum function.\n\tAggFuncSum = \"sum\"\n\t// AggFuncAvg is the name of Avg function.\n\tAggFuncAvg = \"avg\"\n\t// AggFuncFirstRow is the name of FirstRowColumn function.\n\tAggFuncFirstRow = \"firstrow\"\n\t// AggFuncMax is the name of max function.\n\tAggFuncMax = \"max\"\n\t// AggFuncMin is the name of min function.\n\tAggFuncMin = \"min\"\n\t// AggFuncGroupConcat is the name of group_concat function.\n\tAggFuncGroupConcat = \"group_concat\"\n\t// AggFuncBitOr is the name of bit_or function.\n\tAggFuncBitOr = \"bit_or\"\n\t// AggFuncBitXor is the name of bit_xor function.\n\tAggFuncBitXor = \"bit_xor\"\n\t// AggFuncBitAnd is the name of bit_and function.\n\tAggFuncBitAnd = \"bit_and\"\n\t// AggFuncVarPop is the name of var_pop function\n\tAggFuncVarPop = \"var_pop\"\n\t// AggFuncVarSamp is the name of var_samp function\n\tAggFuncVarSamp = \"var_samp\"\n\t// AggFuncStddevPop is the name of std/stddev/stddev_pop function\n\tAggFuncStddevPop = \"stddev_pop\"\n\t// AggFuncStddevSamp is the name of stddev_samp function\n\tAggFuncStddevSamp = \"stddev_samp\"\n\n\t// Added by SCQL\n\t// AggFuncMedian is the name of Median function.\n\tAggFuncMedian = \"median\"\n\n\tAggPercentileDisc = \"percentile_disc\"\n)\n\n// AggregateFuncExpr represents aggregate function expression.\ntype AggregateFuncExpr struct {\n\tfuncNode\n\t// F is the function name.\n\tF string\n\t// Args is the function args.\n\tArgs []ExprNode\n\t// Distinct is true, function hence only aggregate distinct values.\n\t// For example, column c1 values are \"1\", \"2\", \"2\",  \"sum(c1)\" is \"5\",\n\t// but \"sum(distinct c1)\" is \"3\".\n\tDistinct bool\n}\n\n// Restore implements Node interface.\nfunc (n *AggregateFuncExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(ctx.Dialect.GetSpecialFuncName(n.F))\n\tctx.WritePlain(\"(\")\n\tif n.Distinct {\n\t\tctx.WriteKeyWord(\"DISTINCT \")\n\t}\n\tswitch strings.ToLower(n.F) {\n\tcase \"group_concat\":\n\t\tfor i := 0; i < len(n.Args)-1; i++ {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tif err := n.Args[i].Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AggregateFuncExpr.Args[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WriteKeyWord(\" SEPARATOR \")\n\t\tif err := n.Args[len(n.Args)-1].Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AggregateFuncExpr.Args SEPARATOR\")\n\t\t}\n\tdefault:\n\t\tfor i, argv := range n.Args {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tif err := argv.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AggregateFuncExpr.Args[%d]\", i)\n\t\t\t}\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *AggregateFuncExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *AggregateFuncExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*AggregateFuncExpr)\n\tfor i, val := range n.Args {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Args[i] = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\nconst (\n\t// WindowFuncRowNumber is the name of row_number function.\n\tWindowFuncRowNumber = \"row_number\"\n\t// WindowFuncRank is the name of rank function.\n\tWindowFuncRank = \"rank\"\n\t// WindowFuncDenseRank is the name of dense_rank function.\n\tWindowFuncDenseRank = \"dense_rank\"\n\t// WindowFuncCumeDist is the name of cume_dist function.\n\tWindowFuncCumeDist = \"cume_dist\"\n\t// WindowFuncPercentRank is the name of percent_rank function.\n\tWindowFuncPercentRank = \"percent_rank\"\n\t// WindowFuncNtile is the name of ntile function.\n\tWindowFuncNtile = \"ntile\"\n\t// WindowFuncLead is the name of lead function.\n\tWindowFuncLead = \"lead\"\n\t// WindowFuncLag is the name of lag function.\n\tWindowFuncLag = \"lag\"\n\t// WindowFuncFirstValue is the name of first_value function.\n\tWindowFuncFirstValue = \"first_value\"\n\t// WindowFuncLastValue is the name of last_value function.\n\tWindowFuncLastValue = \"last_value\"\n\t// WindowFuncNthValue is the name of nth_value function.\n\tWindowFuncNthValue = \"nth_value\"\n)\n\n// WindowFuncExpr represents window function expression.\ntype WindowFuncExpr struct {\n\tfuncNode\n\n\t// F is the function name.\n\tF string\n\t// Args is the function args.\n\tArgs []ExprNode\n\t// Distinct cannot be true for most window functions, except `max` and `min`.\n\t// We need to raise error if it is not allowed to be true.\n\tDistinct bool\n\t// IgnoreNull indicates how to handle null value.\n\t// MySQL only supports `RESPECT NULLS`, so we need to raise error if it is true.\n\tIgnoreNull bool\n\t// FromLast indicates the calculation direction of this window function.\n\t// MySQL only supports calculation from first, so we need to raise error if it is true.\n\tFromLast bool\n\t// Spec is the specification of this window.\n\tSpec WindowSpec\n}\n\n// Restore implements Node interface.\nfunc (n *WindowFuncExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(n.F)\n\tctx.WritePlain(\"(\")\n\tfor i, v := range n.Args {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t} else if n.Distinct {\n\t\t\tctx.WriteKeyWord(\"DISTINCT \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore WindowFuncExpr.Args[%d]\", i)\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\tif n.FromLast {\n\t\tctx.WriteKeyWord(\" FROM LAST\")\n\t}\n\tif n.IgnoreNull {\n\t\tctx.WriteKeyWord(\" IGNORE NULLS\")\n\t}\n\tctx.WriteKeyWord(\" OVER \")\n\tif err := n.Spec.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore WindowFuncExpr.Spec\")\n\t}\n\n\treturn nil\n}\n\n// Format formats the window function expression into a Writer.\nfunc (n *WindowFuncExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *WindowFuncExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*WindowFuncExpr)\n\tfor i, val := range n.Args {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Args[i] = node.(ExprNode)\n\t}\n\tnode, ok := n.Spec.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Spec = *node.(*WindowSpec)\n\treturn v.Leave(n)\n}\n\n// TimeUnitType is the type for time and timestamp units.\ntype TimeUnitType int\n\nconst (\n\t// TimeUnitInvalid is a placeholder for an invalid time or timestamp unit\n\tTimeUnitInvalid TimeUnitType = iota\n\t// TimeUnitMicrosecond is the time or timestamp unit MICROSECOND.\n\tTimeUnitMicrosecond\n\t// TimeUnitSecond is the time or timestamp unit SECOND.\n\tTimeUnitSecond\n\t// TimeUnitMinute is the time or timestamp unit MINUTE.\n\tTimeUnitMinute\n\t// TimeUnitHour is the time or timestamp unit HOUR.\n\tTimeUnitHour\n\t// TimeUnitDay is the time or timestamp unit DAY.\n\tTimeUnitDay\n\t// TimeUnitWeek is the time or timestamp unit WEEK.\n\tTimeUnitWeek\n\t// TimeUnitMonth is the time or timestamp unit MONTH.\n\tTimeUnitMonth\n\t// TimeUnitQuarter is the time or timestamp unit QUARTER.\n\tTimeUnitQuarter\n\t// TimeUnitYear is the time or timestamp unit YEAR.\n\tTimeUnitYear\n\t// TimeUnitSecondMicrosecond is the time unit SECOND_MICROSECOND.\n\tTimeUnitSecondMicrosecond\n\t// TimeUnitMinuteMicrosecond is the time unit MINUTE_MICROSECOND.\n\tTimeUnitMinuteMicrosecond\n\t// TimeUnitMinuteSecond is the time unit MINUTE_SECOND.\n\tTimeUnitMinuteSecond\n\t// TimeUnitHourMicrosecond is the time unit HOUR_MICROSECOND.\n\tTimeUnitHourMicrosecond\n\t// TimeUnitHourSecond is the time unit HOUR_SECOND.\n\tTimeUnitHourSecond\n\t// TimeUnitHourMinute is the time unit HOUR_MINUTE.\n\tTimeUnitHourMinute\n\t// TimeUnitDayMicrosecond is the time unit DAY_MICROSECOND.\n\tTimeUnitDayMicrosecond\n\t// TimeUnitDaySecond is the time unit DAY_SECOND.\n\tTimeUnitDaySecond\n\t// TimeUnitDayMinute is the time unit DAY_MINUTE.\n\tTimeUnitDayMinute\n\t// TimeUnitDayHour is the time unit DAY_HOUR.\n\tTimeUnitDayHour\n\t// TimeUnitYearMonth is the time unit YEAR_MONTH.\n\tTimeUnitYearMonth\n)\n\n// String implements fmt.Stringer interface.\nfunc (unit TimeUnitType) String() string {\n\tswitch unit {\n\tcase TimeUnitMicrosecond:\n\t\treturn \"MICROSECOND\"\n\tcase TimeUnitSecond:\n\t\treturn \"SECOND\"\n\tcase TimeUnitMinute:\n\t\treturn \"MINUTE\"\n\tcase TimeUnitHour:\n\t\treturn \"HOUR\"\n\tcase TimeUnitDay:\n\t\treturn \"DAY\"\n\tcase TimeUnitWeek:\n\t\treturn \"WEEK\"\n\tcase TimeUnitMonth:\n\t\treturn \"MONTH\"\n\tcase TimeUnitQuarter:\n\t\treturn \"QUARTER\"\n\tcase TimeUnitYear:\n\t\treturn \"YEAR\"\n\tcase TimeUnitSecondMicrosecond:\n\t\treturn \"SECOND_MICROSECOND\"\n\tcase TimeUnitMinuteMicrosecond:\n\t\treturn \"MINUTE_MICROSECOND\"\n\tcase TimeUnitMinuteSecond:\n\t\treturn \"MINUTE_SECOND\"\n\tcase TimeUnitHourMicrosecond:\n\t\treturn \"HOUR_MICROSECOND\"\n\tcase TimeUnitHourSecond:\n\t\treturn \"HOUR_SECOND\"\n\tcase TimeUnitHourMinute:\n\t\treturn \"HOUR_MINUTE\"\n\tcase TimeUnitDayMicrosecond:\n\t\treturn \"DAY_MICROSECOND\"\n\tcase TimeUnitDaySecond:\n\t\treturn \"DAY_SECOND\"\n\tcase TimeUnitDayMinute:\n\t\treturn \"DAY_MINUTE\"\n\tcase TimeUnitDayHour:\n\t\treturn \"DAY_HOUR\"\n\tcase TimeUnitYearMonth:\n\t\treturn \"YEAR_MONTH\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\n// TimeUnitExpr is an expression representing a time or timestamp unit.\ntype TimeUnitExpr struct {\n\texprNode\n\t// Unit is the time or timestamp unit.\n\tUnit TimeUnitType\n}\n\n// Restore implements Node interface.\nfunc (n *TimeUnitExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(n.Unit.String())\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *TimeUnitExpr) Format(w io.Writer) {\n\tfmt.Fprint(w, n.Unit.String())\n}\n\n// Accept implements Node Accept interface.\nfunc (n *TimeUnitExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// GetFormatSelectorType is the type for the first argument of GET_FORMAT() function.\ntype GetFormatSelectorType int\n\nconst (\n\t// GetFormatSelectorDate is the GET_FORMAT selector DATE.\n\tGetFormatSelectorDate GetFormatSelectorType = iota + 1\n\t// GetFormatSelectorTime is the GET_FORMAT selector TIME.\n\tGetFormatSelectorTime\n\t// GetFormatSelectorDatetime is the GET_FORMAT selector DATETIME and TIMESTAMP.\n\tGetFormatSelectorDatetime\n)\n\n// GetFormatSelectorExpr is an expression used as the first argument of GET_FORMAT() function.\ntype GetFormatSelectorExpr struct {\n\texprNode\n\t// Selector is the GET_FORMAT() selector.\n\tSelector GetFormatSelectorType\n}\n\n// String implements fmt.Stringer interface.\nfunc (selector GetFormatSelectorType) String() string {\n\tswitch selector {\n\tcase GetFormatSelectorDate:\n\t\treturn \"DATE\"\n\tcase GetFormatSelectorTime:\n\t\treturn \"TIME\"\n\tcase GetFormatSelectorDatetime:\n\t\treturn \"DATETIME\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\n// Restore implements Node interface.\nfunc (n *GetFormatSelectorExpr) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(n.Selector.String())\n\treturn nil\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *GetFormatSelectorExpr) Format(w io.Writer) {\n\tfmt.Fprint(w, n.Selector.String())\n}\n\n// Accept implements Node Accept interface.\nfunc (n *GetFormatSelectorExpr) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\treturn v.Leave(n)\n}\n"
  },
  {
    "path": "pkg/parser/ast/functions_test.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast_test\n\nimport (\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t. \"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/test_driver\"\n)\n\nvar _ = Suite(&testFunctionsSuite{})\n\ntype testFunctionsSuite struct {\n}\n\nfunc (ts *testFunctionsSuite) TestFunctionsVisitorCover(c *C) {\n\tvalueExpr := NewValueExpr(42)\n\tstmts := []Node{\n\t\t&AggregateFuncExpr{Args: []ExprNode{valueExpr}},\n\t\t&FuncCallExpr{Args: []ExprNode{valueExpr}},\n\t\t&FuncCastExpr{Expr: valueExpr},\n\t\t&WindowFuncExpr{Spec: WindowSpec{}},\n\t}\n\n\tfor _, stmt := range stmts {\n\t\tstmt.Accept(visitor{})\n\t\tstmt.Accept(visitor1{})\n\t}\n}\n\nfunc (ts *testFunctionsSuite) TestFuncCallExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"JSON_ARRAYAGG(attribute)\", \"JSON_ARRAYAGG(`attribute`)\"},\n\t\t{\"JSON_OBJECTAGG(attribute, value)\", \"JSON_OBJECTAGG(`attribute`, `value`)\"},\n\t\t{\"ABS(-1024)\", \"ABS(-1024)\"},\n\t\t{\"ACOS(3.14)\", \"ACOS(3.14)\"},\n\t\t{\"CONV('a',16,2)\", \"CONV('a', 16, 2)\"},\n\t\t{\"COS(PI())\", \"COS(PI())\"},\n\t\t{\"RAND()\", \"RAND()\"},\n\t\t{\"ADDDATE('2000-01-01', 1)\", \"ADDDATE('2000-01-01', INTERVAL 1 DAY)\"},\n\t\t{\"DATE_ADD('2000-01-01', INTERVAL 1 DAY)\", \"DATE_ADD('2000-01-01', INTERVAL 1 DAY)\"},\n\t\t{\"DATE_ADD('2000-01-01', INTERVAL '1 1:12:23.100000' DAY_MICROSECOND)\", \"DATE_ADD('2000-01-01', INTERVAL '1 1:12:23.100000' DAY_MICROSECOND)\"},\n\t\t{\"EXTRACT(DAY FROM '2000-01-01')\", \"EXTRACT(DAY FROM '2000-01-01')\"},\n\t\t{\"extract(day from '1999-01-01')\", \"EXTRACT(DAY FROM '1999-01-01')\"},\n\t\t{\"GET_FORMAT(DATE, 'EUR')\", \"GET_FORMAT(DATE, 'EUR')\"},\n\t\t{\"POSITION('a' IN 'abc')\", \"POSITION('a' IN 'abc')\"},\n\t\t{\"TRIM('  bar   ')\", \"TRIM('  bar   ')\"},\n\t\t{\"TRIM('a' FROM '  bar   ')\", \"TRIM('a' FROM '  bar   ')\"},\n\t\t{\"TRIM(LEADING FROM '  bar   ')\", \"TRIM(LEADING FROM '  bar   ')\"},\n\t\t{\"TRIM(BOTH FROM '  bar   ')\", \"TRIM(BOTH FROM '  bar   ')\"},\n\t\t{\"TRIM(TRAILING FROM '  bar   ')\", \"TRIM(TRAILING FROM '  bar   ')\"},\n\t\t{\"TRIM(LEADING 'x' FROM 'xxxyxxx')\", \"TRIM(LEADING 'x' FROM 'xxxyxxx')\"},\n\t\t{\"TRIM(BOTH 'x' FROM 'xxxyxxx')\", \"TRIM(BOTH 'x' FROM 'xxxyxxx')\"},\n\t\t{\"TRIM(TRAILING 'x' FROM 'xxxyxxx')\", \"TRIM(TRAILING 'x' FROM 'xxxyxxx')\"},\n\t\t{\"DATE_ADD('2008-01-02', INTERVAL INTERVAL(1, 0, 1) DAY)\", \"DATE_ADD('2008-01-02', INTERVAL INTERVAL(1, 0, 1) DAY)\"},\n\t\t{\"BENCHMARK(1000000, AES_ENCRYPT('text', UNHEX('F3229A0B371ED2D9441B830D21A390C3')))\", \"BENCHMARK(1000000, AES_ENCRYPT('text', UNHEX('F3229A0B371ED2D9441B830D21A390C3')))\"},\n\t\t{\"SUBSTRING('Quadratically', 5)\", \"SUBSTRING('Quadratically', 5)\"},\n\t\t{\"SUBSTRING('Quadratically' FROM 5)\", \"SUBSTRING('Quadratically', 5)\"},\n\t\t{\"SUBSTRING('Quadratically', 5, 6)\", \"SUBSTRING('Quadratically', 5, 6)\"},\n\t\t{\"SUBSTRING('Quadratically' FROM 5 FOR 6)\", \"SUBSTRING('Quadratically', 5, 6)\"},\n\t\t{\"MASTER_POS_WAIT(@log_name, @log_pos, @timeout, @channel_name)\", \"MASTER_POS_WAIT(@`log_name`, @`log_pos`, @`timeout`, @`channel_name`)\"},\n\t\t{\"JSON_TYPE('[123]')\", \"JSON_TYPE('[123]')\"},\n\t\t{\"bit_and(all c1)\", \"BIT_AND(`c1`)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (ts *testFunctionsSuite) TestAggregateFuncExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"AVG(test_score)\", \"AVG(`test_score`)\"},\n\t\t{\"AVG(distinct test_score)\", \"AVG(DISTINCT `test_score`)\"},\n\t\t{\"BIT_AND(test_score)\", \"BIT_AND(`test_score`)\"},\n\t\t{\"BIT_OR(test_score)\", \"BIT_OR(`test_score`)\"},\n\t\t{\"BIT_XOR(test_score)\", \"BIT_XOR(`test_score`)\"},\n\t\t{\"COUNT(test_score)\", \"COUNT(`test_score`)\"},\n\t\t{\"COUNT(*)\", \"COUNT(1)\"},\n\t\t{\"COUNT(DISTINCT scores, results)\", \"COUNT(DISTINCT `scores`, `results`)\"},\n\t\t{\"MIN(test_score)\", \"MIN(`test_score`)\"},\n\t\t{\"MIN(DISTINCT test_score)\", \"MIN(DISTINCT `test_score`)\"},\n\t\t{\"MAX(test_score)\", \"MAX(`test_score`)\"},\n\t\t{\"MAX(DISTINCT test_score)\", \"MAX(DISTINCT `test_score`)\"},\n\t\t{\"STD(test_score)\", \"STDDEV_POP(`test_score`)\"},\n\t\t{\"STDDEV(test_score)\", \"STDDEV_POP(`test_score`)\"},\n\t\t{\"STDDEV_POP(test_score)\", \"STDDEV_POP(`test_score`)\"},\n\t\t{\"STDDEV_SAMP(test_score)\", \"STDDEV_SAMP(`test_score`)\"},\n\t\t{\"SUM(test_score)\", \"SUM(`test_score`)\"},\n\t\t{\"SUM(DISTINCT test_score)\", \"SUM(DISTINCT `test_score`)\"},\n\t\t{\"VAR_POP(test_score)\", \"VAR_POP(`test_score`)\"},\n\t\t{\"VAR_SAMP(test_score)\", \"VAR_SAMP(`test_score`)\"},\n\t\t{\"VARIANCE(test_score)\", \"VAR_POP(`test_score`)\"},\n\t\t{\"MEDIAN(test_score)\", \"MEDIAN(`test_score`)\"},\n\t\t{\"PERCENTILE_DISC(test_score, 0.8)\", \"PERCENTILE_DISC(`test_score`, 0.8)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s\", extractNodeFunc)\n}\n\nfunc (ts *testFunctionsSuite) TestConvert(c *C) {\n\t// Test case for CONVERT(expr USING transcoding_name).\n\tcases := []struct {\n\t\tSQL          string\n\t\tCharsetName  string\n\t\tErrorMessage string\n\t}{\n\t\t{`SELECT CONVERT(\"abc\" USING \"latin1\")`, \"latin1\", \"\"},\n\t\t{`SELECT CONVERT(\"abc\" USING laTiN1)`, \"latin1\", \"\"},\n\t\t{`SELECT CONVERT(\"abc\" USING \"binary\")`, \"binary\", \"\"},\n\t\t{`SELECT CONVERT(\"abc\" USING biNaRy)`, \"binary\", \"\"},\n\t\t{`SELECT CONVERT(a USING a)`, \"\", `[parser:1115]Unknown character set: 'a'`}, // TiDB issue #4436.\n\t\t{`SELECT CONVERT(\"abc\" USING CONCAT(\"utf\", \"8\"))`, \"\", `[parser:1115]Unknown character set: 'CONCAT'`},\n\t}\n\tfor _, testCase := range cases {\n\t\tstmt, err := parser.New().ParseOneStmt(testCase.SQL, \"\", \"\")\n\t\tif testCase.ErrorMessage != \"\" {\n\t\t\tc.Assert(err.Error(), Equals, testCase.ErrorMessage)\n\t\t\tcontinue\n\t\t}\n\t\tc.Assert(err, IsNil)\n\n\t\tst := stmt.(*SelectStmt)\n\t\texpr := st.Fields.Fields[0].Expr.(*FuncCallExpr)\n\t\tcharsetArg := expr.Args[1].(*test_driver.ValueExpr)\n\t\tc.Assert(charsetArg.GetString(), Equals, testCase.CharsetName)\n\t}\n}\n\nfunc (ts *testFunctionsSuite) TestChar(c *C) {\n\t// Test case for CHAR(N USING charset_name)\n\tcases := []struct {\n\t\tSQL          string\n\t\tCharsetName  string\n\t\tErrorMessage string\n\t}{\n\t\t{`SELECT CHAR(\"abc\" USING \"latin1\")`, \"latin1\", \"\"},\n\t\t{`SELECT CHAR(\"abc\" USING laTiN1)`, \"latin1\", \"\"},\n\t\t{`SELECT CHAR(\"abc\" USING \"binary\")`, \"binary\", \"\"},\n\t\t{`SELECT CHAR(\"abc\" USING binary)`, \"binary\", \"\"},\n\t\t{`SELECT CHAR(a USING a)`, \"\", `[parser:1115]Unknown character set: 'a'`},\n\t\t{`SELECT CHAR(\"abc\" USING CONCAT(\"utf\", \"8\"))`, \"\", `[parser:1115]Unknown character set: 'CONCAT'`},\n\t}\n\tfor _, testCase := range cases {\n\t\tstmt, err := parser.New().ParseOneStmt(testCase.SQL, \"\", \"\")\n\t\tif testCase.ErrorMessage != \"\" {\n\t\t\tc.Assert(err.Error(), Equals, testCase.ErrorMessage)\n\t\t\tcontinue\n\t\t}\n\t\tc.Assert(err, IsNil)\n\n\t\tst := stmt.(*SelectStmt)\n\t\texpr := st.Fields.Fields[0].Expr.(*FuncCallExpr)\n\t\tcharsetArg := expr.Args[1].(*test_driver.ValueExpr)\n\t\tc.Assert(charsetArg.GetString(), Equals, testCase.CharsetName)\n\t}\n}\n\nfunc (ts *testDMLSuite) TestWindowFuncExprRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"RANK() OVER w\", \"RANK() OVER `w`\"},\n\t\t{\"RANK() OVER (ORDER BY w)\", \"RANK() OVER (ORDER BY `w`)\"},\n\t\t{\"RANK() OVER (PARTITION BY a)\", \"RANK() OVER (PARTITION BY `a`)\"},\n\t\t{\"MAX(DISTINCT a) OVER (PARTITION BY a)\", \"MAX(DISTINCT `a`) OVER (PARTITION BY `a`)\"},\n\t\t{\"MAX(DISTINCTROW a) OVER (PARTITION BY a)\", \"MAX(DISTINCT `a`) OVER (PARTITION BY `a`)\"},\n\t\t{\"MAX(DISTINCT ALL a) OVER (PARTITION BY a)\", \"MAX(DISTINCT `a`) OVER (PARTITION BY `a`)\"},\n\t\t{\"MAX(ALL a) OVER (PARTITION BY a)\", \"MAX(`a`) OVER (PARTITION BY `a`)\"},\n\t\t{\"FIRST_VALUE(val) IGNORE NULLS OVER (w)\", \"FIRST_VALUE(`val`) IGNORE NULLS OVER (`w`)\"},\n\t\t{\"FIRST_VALUE(val) RESPECT NULLS OVER w\", \"FIRST_VALUE(`val`) OVER `w`\"},\n\t\t{\"NTH_VALUE(val, 233) FROM LAST IGNORE NULLS OVER w\", \"NTH_VALUE(`val`, 233) FROM LAST IGNORE NULLS OVER `w`\"},\n\t\t{\"NTH_VALUE(val, 233) FROM FIRST IGNORE NULLS OVER (w)\", \"NTH_VALUE(`val`, 233) IGNORE NULLS OVER (`w`)\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).Fields.Fields[0].Expr\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select %s from t\", extractNodeFunc)\n}\n"
  },
  {
    "path": "pkg/parser/ast/misc.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/auth\"\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n)\n\nvar (\n\t_ StmtNode = &AdminStmt{}\n\t_ StmtNode = &AlterUserStmt{}\n\t_ StmtNode = &BeginStmt{}\n\t_ StmtNode = &BinlogStmt{}\n\t_ StmtNode = &CommitStmt{}\n\t_ StmtNode = &CreateUserStmt{}\n\t_ StmtNode = &DeallocateStmt{}\n\t_ StmtNode = &DoStmt{}\n\t_ StmtNode = &ExecuteStmt{}\n\t_ StmtNode = &ExplainStmt{}\n\t_ StmtNode = &GrantStmt{}\n\t_ StmtNode = &PrepareStmt{}\n\t_ StmtNode = &RollbackStmt{}\n\t_ StmtNode = &SetPwdStmt{}\n\t_ StmtNode = &SetRoleStmt{}\n\t_ StmtNode = &SetDefaultRoleStmt{}\n\t_ StmtNode = &SetStmt{}\n\t_ StmtNode = &UseStmt{}\n\t_ StmtNode = &FlushStmt{}\n\t_ StmtNode = &KillStmt{}\n\t_ StmtNode = &CreateBindingStmt{}\n\t_ StmtNode = &DropBindingStmt{}\n\t_ StmtNode = &ShutdownStmt{}\n\n\t_ Node = &PrivElem{}\n\t_ Node = &VariableAssignment{}\n)\n\n// Isolation level constants.\nconst (\n\tReadCommitted   = \"READ-COMMITTED\"\n\tReadUncommitted = \"READ-UNCOMMITTED\"\n\tSerializable    = \"SERIALIZABLE\"\n\tRepeatableRead  = \"REPEATABLE-READ\"\n\n\t// Valid formats for explain statement.\n\tExplainFormatROW  = \"row\"\n\tExplainFormatDOT  = \"dot\"\n\tExplainFormatHint = \"hint\"\n\tPumpType          = \"PUMP\"\n\tDrainerType       = \"DRAINER\"\n)\n\n// Transaction mode constants.\nconst (\n\tOptimistic  = \"OPTIMISTIC\"\n\tPessimistic = \"PESSIMISTIC\"\n)\n\nvar (\n\t// ExplainFormats stores the valid formats for explain statement, used by validator.\n\tExplainFormats = []string{\n\t\tExplainFormatROW,\n\t\tExplainFormatDOT,\n\t\tExplainFormatHint,\n\t}\n)\n\n// TypeOpt is used for parsing data type option from SQL.\ntype TypeOpt struct {\n\tIsUnsigned bool\n\tIsZerofill bool\n}\n\n// FloatOpt is used for parsing floating-point type option from SQL.\n// See http://dev.mysql.com/doc/refman/5.7/en/floating-point-types.html\ntype FloatOpt struct {\n\tFlen    int\n\tDecimal int\n}\n\n// AuthOption is used for parsing create use statement.\ntype AuthOption struct {\n\t// ByAuthString set as true, if AuthString is used for authorization. Otherwise, authorization is done by HashString.\n\tByAuthString bool\n\tAuthString   string\n\tHashString   string\n\t// TODO: support auth_plugin\n}\n\n// Restore implements Node interface.\nfunc (n *AuthOption) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"IDENTIFIED BY \")\n\tif n.ByAuthString {\n\t\tctx.WriteString(n.AuthString)\n\t} else {\n\t\tctx.WriteKeyWord(\"PASSWORD \")\n\t\tctx.WriteString(n.HashString)\n\t}\n\treturn nil\n}\n\n// TraceStmt is a statement to trace what sql actually does at background.\ntype TraceStmt struct {\n\tstmtNode\n\n\tStmt   StmtNode\n\tFormat string\n}\n\n// Restore implements Node interface.\nfunc (n *TraceStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"TRACE \")\n\tif n.Format != \"json\" {\n\t\tctx.WriteKeyWord(\"FORMAT\")\n\t\tctx.WritePlain(\" = \")\n\t\tctx.WriteString(n.Format)\n\t\tctx.WritePlain(\" \")\n\t}\n\tif err := n.Stmt.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore TraceStmt.Stmt\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *TraceStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*TraceStmt)\n\tnode, ok := n.Stmt.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Stmt = node.(StmtNode)\n\treturn v.Leave(n)\n}\n\n// ExplainForStmt is a statement to provite information about how is SQL statement executeing\n// in connection #ConnectionID\n// See https://dev.mysql.com/doc/refman/5.7/en/explain.html\ntype ExplainForStmt struct {\n\tstmtNode\n\n\tFormat       string\n\tConnectionID uint64\n}\n\n// Restore implements Node interface.\nfunc (n *ExplainForStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"EXPLAIN \")\n\tctx.WriteKeyWord(\"FORMAT \")\n\tctx.WritePlain(\"= \")\n\tctx.WriteString(n.Format)\n\tctx.WritePlain(\" \")\n\tctx.WriteKeyWord(\"FOR \")\n\tctx.WriteKeyWord(\"CONNECTION \")\n\tctx.WritePlain(strconv.FormatUint(n.ConnectionID, 10))\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ExplainForStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ExplainForStmt)\n\treturn v.Leave(n)\n}\n\n// ExplainStmt is a statement to provide information about how is SQL statement executed\n// or get columns information in a table.\n// See https://dev.mysql.com/doc/refman/5.7/en/explain.html\ntype ExplainStmt struct {\n\tstmtNode\n\n\tStmt    StmtNode\n\tFormat  string\n\tAnalyze bool\n}\n\n// Restore implements Node interface.\nfunc (n *ExplainStmt) Restore(ctx *RestoreCtx) error {\n\tif showStmt, ok := n.Stmt.(*ShowStmt); ok {\n\t\tctx.WriteKeyWord(\"DESC \")\n\t\tif err := showStmt.Table.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore ExplainStmt.ShowStmt.Table\")\n\t\t}\n\t\tif showStmt.Column != nil {\n\t\t\tctx.WritePlain(\" \")\n\t\t\tif err := showStmt.Column.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore ExplainStmt.ShowStmt.Column\")\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\tctx.WriteKeyWord(\"EXPLAIN \")\n\tif n.Analyze {\n\t\tctx.WriteKeyWord(\"ANALYZE \")\n\t} else {\n\t\tctx.WriteKeyWord(\"FORMAT \")\n\t\tctx.WritePlain(\"= \")\n\t\tctx.WriteString(n.Format)\n\t\tctx.WritePlain(\" \")\n\t}\n\tif err := n.Stmt.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore ExplainStmt.Stmt\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ExplainStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ExplainStmt)\n\tnode, ok := n.Stmt.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Stmt = node.(DMLNode)\n\treturn v.Leave(n)\n}\n\n// PrepareStmt is a statement to prepares a SQL statement which contains placeholders,\n// and it is executed with ExecuteStmt and released with DeallocateStmt.\n// See https://dev.mysql.com/doc/refman/5.7/en/prepare.html\ntype PrepareStmt struct {\n\tstmtNode\n\n\tName    string\n\tSQLText string\n\tSQLVar  *VariableExpr\n}\n\n// Restore implements Node interface.\nfunc (n *PrepareStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"PREPARE \")\n\tctx.WriteName(n.Name)\n\tctx.WriteKeyWord(\" FROM \")\n\tif n.SQLText != \"\" {\n\t\tctx.WriteString(n.SQLText)\n\t\treturn nil\n\t}\n\tif n.SQLVar != nil {\n\t\tif err := n.SQLVar.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore PrepareStmt.SQLVar\")\n\t\t}\n\t\treturn nil\n\t}\n\treturn errors.New(\"An error occurred while restore PrepareStmt\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *PrepareStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*PrepareStmt)\n\tif n.SQLVar != nil {\n\t\tnode, ok := n.SQLVar.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.SQLVar = node.(*VariableExpr)\n\t}\n\treturn v.Leave(n)\n}\n\n// DeallocateStmt is a statement to release PreparedStmt.\n// See https://dev.mysql.com/doc/refman/5.7/en/deallocate-prepare.html\ntype DeallocateStmt struct {\n\tstmtNode\n\n\tName string\n}\n\n// Restore implements Node interface.\nfunc (n *DeallocateStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"DEALLOCATE PREPARE \")\n\tctx.WriteName(n.Name)\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DeallocateStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DeallocateStmt)\n\treturn v.Leave(n)\n}\n\n// Prepared represents a prepared statement.\ntype Prepared struct {\n\tStmt          StmtNode\n\tStmtType      string\n\tParams        []ParamMarkerExpr\n\tSchemaVersion int64\n\tUseCache      bool\n\tCachedPlan    interface{}\n\tCachedNames   interface{}\n}\n\n// ExecuteStmt is a statement to execute PreparedStmt.\n// See https://dev.mysql.com/doc/refman/5.7/en/execute.html\ntype ExecuteStmt struct {\n\tstmtNode\n\n\tName       string\n\tUsingVars  []ExprNode\n\tBinaryArgs interface{}\n\tExecID     uint32\n\tIdxInMulti int\n}\n\n// Restore implements Node interface.\nfunc (n *ExecuteStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"EXECUTE \")\n\tctx.WriteName(n.Name)\n\tif len(n.UsingVars) > 0 {\n\t\tctx.WriteKeyWord(\" USING \")\n\t\tfor i, val := range n.UsingVars {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := val.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore ExecuteStmt.UsingVars index %d\", i)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ExecuteStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ExecuteStmt)\n\tfor i, val := range n.UsingVars {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.UsingVars[i] = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// BeginStmt is a statement to start a new transaction.\n// See https://dev.mysql.com/doc/refman/5.7/en/commit.html\ntype BeginStmt struct {\n\tstmtNode\n\tMode     string\n\tReadOnly bool\n\tBound    *TimestampBound\n}\n\n// Restore implements Node interface.\nfunc (n *BeginStmt) Restore(ctx *RestoreCtx) error {\n\tif n.Mode == \"\" {\n\t\tif n.ReadOnly {\n\t\t\tctx.WriteKeyWord(\"START TRANSACTION READ ONLY\")\n\t\t\tif n.Bound != nil {\n\t\t\t\tswitch n.Bound.Mode {\n\t\t\t\tcase TimestampBoundStrong:\n\t\t\t\t\tctx.WriteKeyWord(\" WITH TIMESTAMP BOUND STRONG\")\n\t\t\t\tcase TimestampBoundMaxStaleness:\n\t\t\t\t\tctx.WriteKeyWord(\" WITH TIMESTAMP BOUND MAX STALENESS \")\n\t\t\t\t\treturn n.Bound.Timestamp.Restore(ctx)\n\t\t\t\tcase TimestampBoundExactStaleness:\n\t\t\t\t\tctx.WriteKeyWord(\" WITH TIMESTAMP BOUND EXACT STALENESS \")\n\t\t\t\t\treturn n.Bound.Timestamp.Restore(ctx)\n\t\t\t\tcase TimestampBoundReadTimestamp:\n\t\t\t\t\tctx.WriteKeyWord(\" WITH TIMESTAMP BOUND READ TIMESTAMP \")\n\t\t\t\t\treturn n.Bound.Timestamp.Restore(ctx)\n\t\t\t\tcase TimestampBoundMinReadTimestamp:\n\t\t\t\t\tctx.WriteKeyWord(\" WITH TIMESTAMP BOUND MIN READ TIMESTAMP \")\n\t\t\t\t\treturn n.Bound.Timestamp.Restore(ctx)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\"START TRANSACTION\")\n\t\t}\n\t} else {\n\t\tctx.WriteKeyWord(\"BEGIN \")\n\t\tctx.WriteKeyWord(n.Mode)\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *BeginStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*BeginStmt)\n\tif n.Bound != nil && n.Bound.Timestamp != nil {\n\t\tnewTimestamp, ok := n.Bound.Timestamp.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Bound.Timestamp = newTimestamp.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// BinlogStmt is an internal-use statement.\n// We just parse and ignore it.\n// See http://dev.mysql.com/doc/refman/5.7/en/binlog.html\ntype BinlogStmt struct {\n\tstmtNode\n\tStr string\n}\n\n// Restore implements Node interface.\nfunc (n *BinlogStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"BINLOG \")\n\tctx.WriteString(n.Str)\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *BinlogStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*BinlogStmt)\n\treturn v.Leave(n)\n}\n\n// CommitStmt is a statement to commit the current transaction.\n// See https://dev.mysql.com/doc/refman/5.7/en/commit.html\ntype CommitStmt struct {\n\tstmtNode\n}\n\n// Restore implements Node interface.\nfunc (n *CommitStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"COMMIT\")\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *CommitStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*CommitStmt)\n\treturn v.Leave(n)\n}\n\n// RollbackStmt is a statement to roll back the current transaction.\n// See https://dev.mysql.com/doc/refman/5.7/en/commit.html\ntype RollbackStmt struct {\n\tstmtNode\n}\n\n// Restore implements Node interface.\nfunc (n *RollbackStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"ROLLBACK\")\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *RollbackStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*RollbackStmt)\n\treturn v.Leave(n)\n}\n\n// UseStmt is a statement to use the DBName database as the current database.\n// See https://dev.mysql.com/doc/refman/5.7/en/use.html\ntype UseStmt struct {\n\tstmtNode\n\n\tDBName string\n}\n\n// Restore implements Node interface.\nfunc (n *UseStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"USE \")\n\tctx.WriteName(n.DBName)\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *UseStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*UseStmt)\n\treturn v.Leave(n)\n}\n\nconst (\n\t// SetNames is the const for set names/charset stmt.\n\t// If VariableAssignment.Name == Names, it should be set names/charset stmt.\n\tSetNames = \"SetNAMES\"\n)\n\n// VariableAssignment is a variable assignment struct.\ntype VariableAssignment struct {\n\tnode\n\tName     string\n\tValue    ExprNode\n\tIsGlobal bool\n\tIsSystem bool\n\n\t// ExtendValue is a way to store extended info.\n\t// VariableAssignment should be able to store information for SetCharset/SetPWD Stmt.\n\t// For SetCharsetStmt, Value is charset, ExtendValue is collation.\n\t// TODO: Use SetStmt to implement set password statement.\n\tExtendValue ValueExpr\n}\n\n// Restore implements Node interface.\nfunc (n *VariableAssignment) Restore(ctx *RestoreCtx) error {\n\tif n.IsSystem {\n\t\tctx.WritePlain(\"@@\")\n\t\tif n.IsGlobal {\n\t\t\tctx.WriteKeyWord(\"GLOBAL\")\n\t\t} else {\n\t\t\tctx.WriteKeyWord(\"SESSION\")\n\t\t}\n\t\tctx.WritePlain(\".\")\n\t} else if n.Name != SetNames {\n\t\tctx.WriteKeyWord(\"@\")\n\t}\n\tif n.Name == SetNames {\n\t\tctx.WriteKeyWord(\"NAMES \")\n\t} else {\n\t\tctx.WriteName(n.Name)\n\t\tctx.WritePlain(\"=\")\n\t}\n\tif err := n.Value.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore VariableAssignment.Value\")\n\t}\n\tif n.ExtendValue != nil {\n\t\tctx.WriteKeyWord(\" COLLATE \")\n\t\tif err := n.ExtendValue.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore VariableAssignment.ExtendValue\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node interface.\nfunc (n *VariableAssignment) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*VariableAssignment)\n\tnode, ok := n.Value.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Value = node.(ExprNode)\n\treturn v.Leave(n)\n}\n\n// FlushStmtType is the type for FLUSH statement.\ntype FlushStmtType int\n\n// Flush statement types.\nconst (\n\tFlushNone FlushStmtType = iota\n\tFlushTables\n\tFlushPrivileges\n\tFlushStatus\n\tFlushTiDBPlugin\n\tFlushHosts\n\tFlushLogs\n)\n\n// LogType is the log type used in FLUSH statement.\ntype LogType int8\n\nconst (\n\tLogTypeDefault LogType = iota\n\tLogTypeBinary\n\tLogTypeEngine\n\tLogTypeError\n\tLogTypeGeneral\n\tLogTypeSlow\n)\n\n// FlushStmt is a statement to flush tables/privileges/optimizer costs and so on.\ntype FlushStmt struct {\n\tstmtNode\n\n\tTp              FlushStmtType // Privileges/Tables/...\n\tNoWriteToBinLog bool\n\tLogType         LogType\n\tTables          []*TableName // For FlushTableStmt, if Tables is empty, it means flush all tables.\n\tReadLock        bool\n\tPlugins         []string\n}\n\n// Restore implements Node interface.\nfunc (n *FlushStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"FLUSH \")\n\tif n.NoWriteToBinLog {\n\t\tctx.WriteKeyWord(\"NO_WRITE_TO_BINLOG \")\n\t}\n\tswitch n.Tp {\n\tcase FlushTables:\n\t\tctx.WriteKeyWord(\"TABLES\")\n\t\tfor i, v := range n.Tables {\n\t\t\tif i == 0 {\n\t\t\t\tctx.WritePlain(\" \")\n\t\t\t} else {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore FlushStmt.Tables[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tif n.ReadLock {\n\t\t\tctx.WriteKeyWord(\" WITH READ LOCK\")\n\t\t}\n\tcase FlushPrivileges:\n\t\tctx.WriteKeyWord(\"PRIVILEGES\")\n\tcase FlushStatus:\n\t\tctx.WriteKeyWord(\"STATUS\")\n\tcase FlushTiDBPlugin:\n\t\tctx.WriteKeyWord(\"TIDB PLUGINS\")\n\t\tfor i, v := range n.Plugins {\n\t\t\tif i == 0 {\n\t\t\t\tctx.WritePlain(\" \")\n\t\t\t} else {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tctx.WritePlain(v)\n\t\t}\n\tcase FlushHosts:\n\t\tctx.WriteKeyWord(\"HOSTS\")\n\tcase FlushLogs:\n\t\tvar logType string\n\t\tswitch n.LogType {\n\t\tcase LogTypeDefault:\n\t\t\tlogType = \"LOGS\"\n\t\tcase LogTypeBinary:\n\t\t\tlogType = \"BINARY LOGS\"\n\t\tcase LogTypeEngine:\n\t\t\tlogType = \"ENGINE LOGS\"\n\t\tcase LogTypeError:\n\t\t\tlogType = \"ERROR LOGS\"\n\t\tcase LogTypeGeneral:\n\t\t\tlogType = \"GENERAL LOGS\"\n\t\tcase LogTypeSlow:\n\t\t\tlogType = \"SLOW LOGS\"\n\t\t}\n\t\tctx.WriteKeyWord(logType)\n\tdefault:\n\t\treturn errors.New(\"Unsupported type of FlushStmt\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *FlushStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*FlushStmt)\n\treturn v.Leave(n)\n}\n\n// KillStmt is a statement to kill a query or connection.\ntype KillStmt struct {\n\tstmtNode\n\n\t// Query indicates whether terminate a single query on this connection or the whole connection.\n\t// If Query is true, terminates the statement the connection is currently executing, but leaves the connection itself intact.\n\t// If Query is false, terminates the connection associated with the given ConnectionID, after terminating any statement the connection is executing.\n\tQuery        bool\n\tConnectionID uint64\n\t// TiDBExtension is used to indicate whether the user knows he is sending kill statement to the right tidb-server.\n\t// When the SQL grammar is \"KILL TIDB [CONNECTION | QUERY] connectionID\", TiDBExtension will be set.\n\t// It's a special grammar extension in TiDB. This extension exists because, when the connection is:\n\t// client -> LVS proxy -> TiDB, and type Ctrl+C in client, the following action will be executed:\n\t// new a connection; kill xxx;\n\t// kill command may send to the wrong TiDB, because the exists of LVS proxy, and kill the wrong session.\n\t// So, \"KILL TIDB\" grammar is introduced, and it REQUIRES DIRECT client -> TiDB TOPOLOGY.\n\t// TODO: The standard KILL grammar will be supported once we have global connectionID.\n\tTiDBExtension bool\n}\n\n// Restore implements Node interface.\nfunc (n *KillStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"KILL\")\n\tif n.TiDBExtension {\n\t\tctx.WriteKeyWord(\" TIDB\")\n\t}\n\tif n.Query {\n\t\tctx.WriteKeyWord(\" QUERY\")\n\t}\n\tctx.WritePlainf(\" %d\", n.ConnectionID)\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *KillStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*KillStmt)\n\treturn v.Leave(n)\n}\n\n// SetStmt is the statement to set variables.\ntype SetStmt struct {\n\tstmtNode\n\t// Variables is the list of variable assignment.\n\tVariables []*VariableAssignment\n}\n\n// Restore implements Node interface.\nfunc (n *SetStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"SET \")\n\tfor i, v := range n.Variables {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore SetStmt.Variables[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *SetStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*SetStmt)\n\tfor i, val := range n.Variables {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Variables[i] = node.(*VariableAssignment)\n\t}\n\treturn v.Leave(n)\n}\n\n/*\n// SetCharsetStmt is a statement to assign values to character and collation variables.\n// See https://dev.mysql.com/doc/refman/5.7/en/set-statement.html\ntype SetCharsetStmt struct {\n\tstmtNode\n\n\tCharset string\n\tCollate string\n}\n\n// Accept implements Node Accept interface.\nfunc (n *SetCharsetStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*SetCharsetStmt)\n\treturn v.Leave(n)\n}\n*/\n\n// SetPwdStmt is a statement to assign a password to user account.\n// See https://dev.mysql.com/doc/refman/5.7/en/set-password.html\ntype SetPwdStmt struct {\n\tstmtNode\n\n\tUser     *auth.UserIdentity\n\tPassword string\n}\n\n// Restore implements Node interface.\nfunc (n *SetPwdStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"SET PASSWORD\")\n\tif n.User != nil {\n\t\tctx.WriteKeyWord(\" FOR \")\n\t\tif err := n.User.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SetPwdStmt.User\")\n\t\t}\n\t}\n\tctx.WritePlain(\"=\")\n\tctx.WriteString(n.Password)\n\treturn nil\n}\n\n// SecureText implements SensitiveStatement interface.\nfunc (n *SetPwdStmt) SecureText() string {\n\treturn fmt.Sprintf(\"set password for user %s\", n.User)\n}\n\n// Accept implements Node Accept interface.\nfunc (n *SetPwdStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*SetPwdStmt)\n\treturn v.Leave(n)\n}\n\ntype ChangeStmt struct {\n\tstmtNode\n\n\tNodeType string\n\tState    string\n\tNodeID   string\n}\n\n// Restore implements Node interface.\nfunc (n *ChangeStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"CHANGE \")\n\tctx.WriteKeyWord(n.NodeType)\n\tctx.WriteKeyWord(\" TO NODE_STATE \")\n\tctx.WritePlain(\"=\")\n\tctx.WriteString(n.State)\n\tctx.WriteKeyWord(\" FOR NODE_ID \")\n\tctx.WriteString(n.NodeID)\n\treturn nil\n}\n\n// SecureText implements SensitiveStatement interface.\nfunc (n *ChangeStmt) SecureText() string {\n\treturn fmt.Sprintf(\"change %s to node_state='%s' for node_id '%s'\", strings.ToLower(n.NodeType), n.State, n.NodeID)\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ChangeStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ChangeStmt)\n\treturn v.Leave(n)\n}\n\n// SetRoleStmtType is the type for FLUSH statement.\ntype SetRoleStmtType int\n\n// SetRole statement types.\nconst (\n\tSetRoleDefault SetRoleStmtType = iota\n\tSetRoleNone\n\tSetRoleAll\n\tSetRoleAllExcept\n\tSetRoleRegular\n)\n\ntype SetRoleStmt struct {\n\tstmtNode\n\n\tSetRoleOpt SetRoleStmtType\n\tRoleList   []*auth.RoleIdentity\n}\n\nfunc (n *SetRoleStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"SET ROLE\")\n\tswitch n.SetRoleOpt {\n\tcase SetRoleDefault:\n\t\tctx.WriteKeyWord(\" DEFAULT\")\n\tcase SetRoleNone:\n\t\tctx.WriteKeyWord(\" NONE\")\n\tcase SetRoleAll:\n\t\tctx.WriteKeyWord(\" ALL\")\n\tcase SetRoleAllExcept:\n\t\tctx.WriteKeyWord(\" ALL EXCEPT\")\n\t}\n\tfor i, role := range n.RoleList {\n\t\tctx.WritePlain(\" \")\n\t\terr := role.Restore(ctx)\n\t\tif err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SetRoleStmt.RoleList\")\n\t\t}\n\t\tif i != len(n.RoleList)-1 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *SetRoleStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*SetRoleStmt)\n\treturn v.Leave(n)\n}\n\ntype SetDefaultRoleStmt struct {\n\tstmtNode\n\n\tSetRoleOpt SetRoleStmtType\n\tRoleList   []*auth.RoleIdentity\n\tUserList   []*auth.UserIdentity\n}\n\nfunc (n *SetDefaultRoleStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"SET DEFAULT ROLE\")\n\tswitch n.SetRoleOpt {\n\tcase SetRoleNone:\n\t\tctx.WriteKeyWord(\" NONE\")\n\tcase SetRoleAll:\n\t\tctx.WriteKeyWord(\" ALL\")\n\tdefault:\n\t}\n\tfor i, role := range n.RoleList {\n\t\tctx.WritePlain(\" \")\n\t\terr := role.Restore(ctx)\n\t\tif err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SetDefaultRoleStmt.RoleList\")\n\t\t}\n\t\tif i != len(n.RoleList)-1 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t}\n\tctx.WritePlain(\" TO\")\n\tfor i, user := range n.UserList {\n\t\tctx.WritePlain(\" \")\n\t\terr := user.Restore(ctx)\n\t\tif err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore SetDefaultRoleStmt.UserList\")\n\t\t}\n\t\tif i != len(n.UserList)-1 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *SetDefaultRoleStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*SetDefaultRoleStmt)\n\treturn v.Leave(n)\n}\n\n// UserSpec is used for parsing create user statement.\ntype UserSpec struct {\n\tUser      *auth.UserIdentity\n\tAuthOpt   *AuthOption\n\tIsRole    bool\n\tPartyCode string\n}\n\n// Restore implements Node interface.\nfunc (n *UserSpec) Restore(ctx *RestoreCtx) error {\n\tif err := n.User.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore UserSpec.User\")\n\t}\n\tif n.PartyCode != \"\" {\n\t\tctx.WriteKeyWord(\" PARTY_CODE \")\n\t\tctx.WriteString(n.PartyCode)\n\t}\n\n\tif n.AuthOpt != nil {\n\t\tctx.WritePlain(\" \")\n\t\tif err := n.AuthOpt.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore UserSpec.AuthOpt\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// SecurityString formats the UserSpec without password information.\nfunc (n *UserSpec) SecurityString() string {\n\twithPassword := false\n\tif opt := n.AuthOpt; opt != nil {\n\t\tif len(opt.AuthString) > 0 || len(opt.HashString) > 0 {\n\t\t\twithPassword = true\n\t\t}\n\t}\n\tif withPassword {\n\t\treturn fmt.Sprintf(\"{%s password = ***}\", n.User)\n\t}\n\treturn n.User.String()\n}\n\n// EncodedPassword returns the encoded password (which is the real data mysql.user).\n// The boolean value indicates input's password format is legal or not.\nfunc (n *UserSpec) EncodedPassword() (string, bool) {\n\tif n.AuthOpt == nil {\n\t\treturn \"\", true\n\t}\n\n\topt := n.AuthOpt\n\tif opt.ByAuthString {\n\t\treturn auth.EncodePassword(opt.AuthString), true\n\t}\n\n\t// Not a legal password string.\n\tif len(opt.HashString) != mysql.PWDHashLen+1 || !strings.HasPrefix(opt.HashString, \"*\") {\n\t\treturn \"\", false\n\t}\n\treturn opt.HashString, true\n}\n\nconst (\n\tTslNone = iota\n\tSsl\n\tX509\n\tCipher\n\tIssuer\n\tSubject\n)\n\ntype TLSOption struct {\n\tType  int\n\tValue string\n}\n\nfunc (t *TLSOption) Restore(ctx *RestoreCtx) error {\n\tswitch t.Type {\n\tcase TslNone:\n\t\tctx.WriteKeyWord(\"NONE\")\n\tcase Ssl:\n\t\tctx.WriteKeyWord(\"SSL\")\n\tcase X509:\n\t\tctx.WriteKeyWord(\"X509\")\n\tcase Cipher:\n\t\tctx.WriteKeyWord(\"CIPHER \")\n\t\tctx.WriteString(t.Value)\n\tcase Issuer:\n\t\tctx.WriteKeyWord(\"ISSUER \")\n\t\tctx.WriteString(t.Value)\n\tcase Subject:\n\t\tctx.WriteKeyWord(\"SUBJECT \")\n\t\tctx.WriteString(t.Value)\n\tdefault:\n\t\treturn errors.Errorf(\"Unsupported TLSOption.Type %d\", t.Type)\n\t}\n\treturn nil\n}\n\nconst (\n\tMaxQueriesPerHour = iota + 1\n\tMaxUpdatesPerHour\n\tMaxConnectionsPerHour\n\tMaxUserConnections\n)\n\ntype PubKeyAuthOption struct {\n\tMessage   string\n\tSignature string\n\tPubKey    string\n}\n\ntype TokenAuthOption struct {\n\tToken string\n}\n\ntype EngineOption struct {\n\t// Only one of {TokenAuth, PubKeyAuth} is valid\n\tTokenAuth  *TokenAuthOption\n\tPubKeyAuth *PubKeyAuthOption\n\tEndpoints  []string\n}\n\nfunc (e *EngineOption) Restore(ctx *RestoreCtx) error {\n\tif e.TokenAuth != nil && e.PubKeyAuth != nil {\n\t\treturn errors.New(\"EngineOption fields TokenAuth and PubKeyAuth cannot be valid at the same time\")\n\t}\n\tif e.TokenAuth != nil {\n\t\tctx.WriteKeyWord(\"TOKEN \")\n\t\tctx.WriteString(e.TokenAuth.Token)\n\t}\n\n\tif e.PubKeyAuth != nil {\n\t\tctx.WritePlainf(\"%v %v %v\", e.PubKeyAuth.Message, e.PubKeyAuth.Signature, e.PubKeyAuth.PubKey)\n\t}\n\n\tif len(e.Endpoints) != 0 {\n\t\tctx.WriteKeyWord(\" ENDPOINT\")\n\t\tfor _, endpoint := range e.Endpoints {\n\t\t\tctx.WritePlain(\" \")\n\t\t\tctx.WriteString(endpoint)\n\t\t}\n\t}\n\treturn nil\n}\n\ntype ResourceOption struct {\n\tType  int\n\tCount int64\n}\n\nfunc (r *ResourceOption) Restore(ctx *RestoreCtx) error {\n\tswitch r.Type {\n\tcase MaxQueriesPerHour:\n\t\tctx.WriteKeyWord(\"MAX_QUERIES_PER_HOUR \")\n\tcase MaxUpdatesPerHour:\n\t\tctx.WriteKeyWord(\"MAX_UPDATES_PER_HOUR \")\n\tcase MaxConnectionsPerHour:\n\t\tctx.WriteKeyWord(\"MAX_CONNECTIONS_PER_HOUR \")\n\tcase MaxUserConnections:\n\t\tctx.WriteKeyWord(\"MAX_USER_CONNECTIONS \")\n\tdefault:\n\t\treturn errors.Errorf(\"Unsupported ResourceOption.Type %d\", r.Type)\n\t}\n\tctx.WritePlainf(\"%d\", r.Count)\n\treturn nil\n}\n\nconst (\n\tPasswordExpire = iota + 1\n\tPasswordExpireDefault\n\tPasswordExpireNever\n\tPasswordExpireInterval\n\tLock\n\tUnlock\n)\n\ntype PasswordOrLockOption struct {\n\tType  int\n\tCount int64\n}\n\nfunc (p *PasswordOrLockOption) Restore(ctx *RestoreCtx) error {\n\tswitch p.Type {\n\tcase PasswordExpire:\n\t\tctx.WriteKeyWord(\"PASSWORD EXPIRE\")\n\tcase PasswordExpireDefault:\n\t\tctx.WriteKeyWord(\"PASSWORD EXPIRE DEFAULT\")\n\tcase PasswordExpireNever:\n\t\tctx.WriteKeyWord(\"PASSWORD EXPIRE NEVER\")\n\tcase PasswordExpireInterval:\n\t\tctx.WriteKeyWord(\"PASSWORD EXPIRE INTERVAL\")\n\t\tctx.WritePlainf(\" %d\", p.Count)\n\t\tctx.WriteKeyWord(\" DAY\")\n\tcase Lock:\n\t\tctx.WriteKeyWord(\"ACCOUNT LOCK\")\n\tcase Unlock:\n\t\tctx.WriteKeyWord(\"ACCOUNT UNLOCK\")\n\tdefault:\n\t\treturn errors.Errorf(\"Unsupported PasswordOrLockOption.Type %d\", p.Type)\n\t}\n\treturn nil\n}\n\n// CreateUserStmt creates user account.\n// See https://dev.mysql.com/doc/refman/5.7/en/create-user.html\ntype CreateUserStmt struct {\n\tstmtNode\n\n\tIsCreateRole bool\n\tIfNotExists  bool\n\tSpecs        []*UserSpec\n\tTLSOptions   []*TLSOption\n\tEngineOpt    *EngineOption\n}\n\n// Restore implements Node interface.\nfunc (n *CreateUserStmt) Restore(ctx *RestoreCtx) error {\n\tif n.IsCreateRole {\n\t\tctx.WriteKeyWord(\"CREATE ROLE \")\n\t} else {\n\t\tctx.WriteKeyWord(\"CREATE USER \")\n\t}\n\tif n.IfNotExists {\n\t\tctx.WriteKeyWord(\"IF NOT EXISTS \")\n\t}\n\tfor i, v := range n.Specs {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore CreateUserStmt.Specs[%d]\", i)\n\t\t}\n\t}\n\n\tif len(n.TLSOptions) != 0 {\n\t\tctx.WriteKeyWord(\" REQUIRE \")\n\t}\n\n\tfor i, option := range n.TLSOptions {\n\t\tif i != 0 {\n\t\t\tctx.WriteKeyWord(\" AND \")\n\t\t}\n\t\tif err := option.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore CreateUserStmt.TLSOptions[%d]\", i)\n\t\t}\n\t}\n\n\tif n.EngineOpt != nil {\n\t\tctx.WriteKeyWord(\" WITH \")\n\t\tif err := n.EngineOpt.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore CreateUserStmt.EngineOpt\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *CreateUserStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*CreateUserStmt)\n\treturn v.Leave(n)\n}\n\n// SecureText implements SensitiveStatement interface.\nfunc (n *CreateUserStmt) SecureText() string {\n\tvar buf bytes.Buffer\n\tbuf.WriteString(\"create user\")\n\tfor _, user := range n.Specs {\n\t\tbuf.WriteString(\" \")\n\t\tbuf.WriteString(user.SecurityString())\n\t}\n\treturn buf.String()\n}\n\n// AlterUserStmt modifies user account.\n// See https://dev.mysql.com/doc/refman/5.7/en/alter-user.html\ntype AlterUserStmt struct {\n\tstmtNode\n\n\tIfExists    bool\n\tCurrentAuth *AuthOption\n\tSpecs       []*UserSpec\n\tTLSOptions  []*TLSOption\n\tEngineOpt   *EngineOption\n}\n\n// Restore implements Node interface.\nfunc (n *AlterUserStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"ALTER USER \")\n\tif n.IfExists {\n\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t}\n\tif n.CurrentAuth != nil {\n\t\tctx.WriteKeyWord(\"USER\")\n\t\tctx.WritePlain(\"() \")\n\t\tif err := n.CurrentAuth.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AlterUserStmt.CurrentAuth\")\n\t\t}\n\t}\n\tfor i, v := range n.Specs {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterUserStmt.Specs[%d]\", i)\n\t\t}\n\t}\n\n\tif len(n.TLSOptions) != 0 {\n\t\tctx.WriteKeyWord(\" REQUIRE \")\n\t}\n\n\tfor i, option := range n.TLSOptions {\n\t\tif i != 0 {\n\t\t\tctx.WriteKeyWord(\" AND \")\n\t\t}\n\t\tif err := option.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterUserStmt.TLSOptions[%d]\", i)\n\t\t}\n\t}\n\n\tif n.EngineOpt != nil {\n\t\tctx.WriteKeyWord(\" WITH \")\n\t\tif err := n.EngineOpt.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AlterUserStmt.EngineOpt\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// SecureText implements SensitiveStatement interface.\nfunc (n *AlterUserStmt) SecureText() string {\n\tvar buf bytes.Buffer\n\tbuf.WriteString(\"alter user\")\n\tfor _, user := range n.Specs {\n\t\tbuf.WriteString(\" \")\n\t\tbuf.WriteString(user.SecurityString())\n\t}\n\treturn buf.String()\n}\n\n// Accept implements Node Accept interface.\nfunc (n *AlterUserStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*AlterUserStmt)\n\treturn v.Leave(n)\n}\n\n// DropUserStmt creates user account.\n// See http://dev.mysql.com/doc/refman/5.7/en/drop-user.html\ntype DropUserStmt struct {\n\tstmtNode\n\n\tIfExists   bool\n\tIsDropRole bool\n\tUserList   []*auth.UserIdentity\n}\n\n// Restore implements Node interface.\nfunc (n *DropUserStmt) Restore(ctx *RestoreCtx) error {\n\tif n.IsDropRole {\n\t\tctx.WriteKeyWord(\"DROP ROLE \")\n\t} else {\n\t\tctx.WriteKeyWord(\"DROP USER \")\n\t}\n\tif n.IfExists {\n\t\tctx.WriteKeyWord(\"IF EXISTS \")\n\t}\n\tfor i, v := range n.UserList {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore DropUserStmt.UserList[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DropUserStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DropUserStmt)\n\treturn v.Leave(n)\n}\n\n// CreateBindingStmt creates sql binding hint.\ntype CreateBindingStmt struct {\n\tstmtNode\n\n\tGlobalScope bool\n\tOriginSel   StmtNode\n\tHintedSel   StmtNode\n}\n\nfunc (n *CreateBindingStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"CREATE \")\n\tif n.GlobalScope {\n\t\tctx.WriteKeyWord(\"GLOBAL \")\n\t} else {\n\t\tctx.WriteKeyWord(\"SESSION \")\n\t}\n\tctx.WriteKeyWord(\"BINDING FOR \")\n\tif err := n.OriginSel.Restore(ctx); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\tctx.WriteKeyWord(\" USING \")\n\tif err := n.HintedSel.Restore(ctx); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\treturn nil\n}\n\nfunc (n *CreateBindingStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*CreateBindingStmt)\n\tselnode, ok := n.OriginSel.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.OriginSel = selnode.(*SelectStmt)\n\thintedSelnode, ok := n.HintedSel.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.HintedSel = hintedSelnode.(*SelectStmt)\n\treturn v.Leave(n)\n}\n\n// DropBindingStmt deletes sql binding hint.\ntype DropBindingStmt struct {\n\tstmtNode\n\n\tGlobalScope bool\n\tOriginSel   StmtNode\n\tHintedSel   StmtNode\n}\n\nfunc (n *DropBindingStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"DROP \")\n\tif n.GlobalScope {\n\t\tctx.WriteKeyWord(\"GLOBAL \")\n\t} else {\n\t\tctx.WriteKeyWord(\"SESSION \")\n\t}\n\tctx.WriteKeyWord(\"BINDING FOR \")\n\tif err := n.OriginSel.Restore(ctx); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\tif n.HintedSel != nil {\n\t\tctx.WriteKeyWord(\" USING \")\n\t\tif err := n.HintedSel.Restore(ctx); err != nil {\n\t\t\treturn errors.Trace(err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (n *DropBindingStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DropBindingStmt)\n\tselnode, ok := n.OriginSel.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.OriginSel = selnode.(*SelectStmt)\n\tif n.HintedSel != nil {\n\t\tselnode, ok = n.HintedSel.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.HintedSel = selnode.(*SelectStmt)\n\t}\n\treturn v.Leave(n)\n}\n\n// DoStmt is the struct for DO statement.\ntype DoStmt struct {\n\tstmtNode\n\n\tExprs []ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *DoStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"DO \")\n\tfor i, v := range n.Exprs {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore DoStmt.Exprs[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DoStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DoStmt)\n\tfor i, val := range n.Exprs {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Exprs[i] = node.(ExprNode)\n\t}\n\treturn v.Leave(n)\n}\n\n// AdminStmtType is the type for admin statement.\ntype AdminStmtType int\n\n// Admin statement types.\nconst (\n\tAdminShowDDL = iota + 1\n\tAdminCheckTable\n\tAdminShowDDLJobs\n\tAdminCancelDDLJobs\n\tAdminCheckIndex\n\tAdminRecoverIndex\n\tAdminCleanupIndex\n\tAdminCheckIndexRange\n\tAdminShowDDLJobQueries\n\tAdminChecksumTable\n\tAdminShowSlow\n\tAdminShowNextRowID\n\tAdminReloadExprPushdownBlacklist\n\tAdminReloadOptRuleBlacklist\n\tAdminPluginDisable\n\tAdminPluginEnable\n\tAdminFlushBindings\n\tAdminCaptureBindings\n\tAdminEvolveBindings\n)\n\n// HandleRange represents a range where handle value >= Begin and < End.\ntype HandleRange struct {\n\tBegin int64\n\tEnd   int64\n}\n\n// ShowSlowType defines the type for SlowSlow statement.\ntype ShowSlowType int\n\nconst (\n\t// ShowSlowTop is a ShowSlowType constant.\n\tShowSlowTop ShowSlowType = iota\n\t// ShowSlowRecent is a ShowSlowType constant.\n\tShowSlowRecent\n)\n\n// ShowSlowKind defines the kind for SlowSlow statement when the type is ShowSlowTop.\ntype ShowSlowKind int\n\nconst (\n\t// ShowSlowKindDefault is a ShowSlowKind constant.\n\tShowSlowKindDefault ShowSlowKind = iota\n\t// ShowSlowKindInternal is a ShowSlowKind constant.\n\tShowSlowKindInternal\n\t// ShowSlowKindAll is a ShowSlowKind constant.\n\tShowSlowKindAll\n)\n\n// ShowSlow is used for the following command:\n//\n//\tadmin show slow top [ internal | all] N\n//\tadmin show slow recent N\ntype ShowSlow struct {\n\tTp    ShowSlowType\n\tCount uint64\n\tKind  ShowSlowKind\n}\n\n// Restore implements Node interface.\nfunc (n *ShowSlow) Restore(ctx *RestoreCtx) error {\n\tswitch n.Tp {\n\tcase ShowSlowRecent:\n\t\tctx.WriteKeyWord(\"RECENT \")\n\tcase ShowSlowTop:\n\t\tctx.WriteKeyWord(\"TOP \")\n\t\tswitch n.Kind {\n\t\tcase ShowSlowKindDefault:\n\t\t\t// do nothing\n\t\tcase ShowSlowKindInternal:\n\t\t\tctx.WriteKeyWord(\"INTERNAL \")\n\t\tcase ShowSlowKindAll:\n\t\t\tctx.WriteKeyWord(\"ALL \")\n\t\tdefault:\n\t\t\treturn errors.New(\"Unsupported kind of ShowSlowTop\")\n\t\t}\n\tdefault:\n\t\treturn errors.New(\"Unsupported type of ShowSlow\")\n\t}\n\tctx.WritePlainf(\"%d\", n.Count)\n\treturn nil\n}\n\n// AdminStmt is the struct for Admin statement.\ntype AdminStmt struct {\n\tstmtNode\n\n\tTp        AdminStmtType\n\tIndex     string\n\tTables    []*TableName\n\tJobIDs    []int64\n\tJobNumber int64\n\n\tHandleRanges []HandleRange\n\tShowSlow     *ShowSlow\n\tPlugins      []string\n\tWhere        ExprNode\n}\n\n// Restore implements Node interface.\nfunc (n *AdminStmt) Restore(ctx *RestoreCtx) error {\n\trestoreTables := func() error {\n\t\tfor i, v := range n.Tables {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AdminStmt.Tables[%d]\", i)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\trestoreJobIDs := func() {\n\t\tfor i, v := range n.JobIDs {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tctx.WritePlainf(\"%d\", v)\n\t\t}\n\t}\n\n\tctx.WriteKeyWord(\"ADMIN \")\n\tswitch n.Tp {\n\tcase AdminShowDDL:\n\t\tctx.WriteKeyWord(\"SHOW DDL\")\n\tcase AdminShowDDLJobs:\n\t\tctx.WriteKeyWord(\"SHOW DDL JOBS\")\n\t\tif n.JobNumber != 0 {\n\t\t\tctx.WritePlainf(\" %d\", n.JobNumber)\n\t\t}\n\t\tif n.Where != nil {\n\t\t\tctx.WriteKeyWord(\" WHERE \")\n\t\t\tif err := n.Where.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotate(err, \"An error occurred while restore ShowStmt.Where\")\n\t\t\t}\n\t\t}\n\tcase AdminShowNextRowID:\n\t\tctx.WriteKeyWord(\"SHOW \")\n\t\tif err := restoreTables(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.WriteKeyWord(\" NEXT_ROW_ID\")\n\tcase AdminCheckTable:\n\t\tctx.WriteKeyWord(\"CHECK TABLE \")\n\t\tif err := restoreTables(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase AdminCheckIndex:\n\t\tctx.WriteKeyWord(\"CHECK INDEX \")\n\t\tif err := restoreTables(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.WritePlainf(\" %s\", n.Index)\n\tcase AdminRecoverIndex:\n\t\tctx.WriteKeyWord(\"RECOVER INDEX \")\n\t\tif err := restoreTables(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.WritePlainf(\" %s\", n.Index)\n\tcase AdminCleanupIndex:\n\t\tctx.WriteKeyWord(\"CLEANUP INDEX \")\n\t\tif err := restoreTables(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.WritePlainf(\" %s\", n.Index)\n\tcase AdminCheckIndexRange:\n\t\tctx.WriteKeyWord(\"CHECK INDEX \")\n\t\tif err := restoreTables(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tctx.WritePlainf(\" %s\", n.Index)\n\t\tif n.HandleRanges != nil {\n\t\t\tctx.WritePlain(\" \")\n\t\t\tfor i, v := range n.HandleRanges {\n\t\t\t\tif i != 0 {\n\t\t\t\t\tctx.WritePlain(\", \")\n\t\t\t\t}\n\t\t\t\tctx.WritePlainf(\"(%d,%d)\", v.Begin, v.End)\n\t\t\t}\n\t\t}\n\tcase AdminChecksumTable:\n\t\tctx.WriteKeyWord(\"CHECKSUM TABLE \")\n\t\tif err := restoreTables(); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase AdminCancelDDLJobs:\n\t\tctx.WriteKeyWord(\"CANCEL DDL JOBS \")\n\t\trestoreJobIDs()\n\tcase AdminShowDDLJobQueries:\n\t\tctx.WriteKeyWord(\"SHOW DDL JOB QUERIES \")\n\t\trestoreJobIDs()\n\tcase AdminShowSlow:\n\t\tctx.WriteKeyWord(\"SHOW SLOW \")\n\t\tif err := n.ShowSlow.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore AdminStmt.ShowSlow\")\n\t\t}\n\tcase AdminReloadExprPushdownBlacklist:\n\t\tctx.WriteKeyWord(\"RELOAD EXPR_PUSHDOWN_BLACKLIST\")\n\tcase AdminReloadOptRuleBlacklist:\n\t\tctx.WriteKeyWord(\"RELOAD OPT_RULE_BLACKLIST\")\n\tcase AdminPluginEnable:\n\t\tctx.WriteKeyWord(\"PLUGINS ENABLE\")\n\t\tfor i, v := range n.Plugins {\n\t\t\tif i == 0 {\n\t\t\t\tctx.WritePlain(\" \")\n\t\t\t} else {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tctx.WritePlain(v)\n\t\t}\n\tcase AdminPluginDisable:\n\t\tctx.WriteKeyWord(\"PLUGINS DISABLE\")\n\t\tfor i, v := range n.Plugins {\n\t\t\tif i == 0 {\n\t\t\t\tctx.WritePlain(\" \")\n\t\t\t} else {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tctx.WritePlain(v)\n\t\t}\n\tcase AdminFlushBindings:\n\t\tctx.WriteKeyWord(\"FLUSH BINDINGS\")\n\tcase AdminCaptureBindings:\n\t\tctx.WriteKeyWord(\"CAPTURE BINDINGS\")\n\tcase AdminEvolveBindings:\n\t\tctx.WriteKeyWord(\"EVOLVE BINDINGS\")\n\tdefault:\n\t\treturn errors.New(\"Unsupported AdminStmt type\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *AdminStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\n\tn = newNode.(*AdminStmt)\n\tfor i, val := range n.Tables {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Tables[i] = node.(*TableName)\n\t}\n\n\treturn v.Leave(n)\n}\n\n// PrivElem is the privilege type and optional column list.\ntype PrivElem struct {\n\tnode\n\n\tPriv mysql.PrivilegeType\n\tCols []*ColumnName\n}\n\n// Restore implements Node interface.\nfunc (n *PrivElem) Restore(ctx *RestoreCtx) error {\n\tif n.Priv == 0 {\n\t\tctx.WritePlain(\"/* UNSUPPORTED TYPE */\")\n\t} else if n.Priv == mysql.AllPriv {\n\t\tctx.WriteKeyWord(\"ALL\")\n\t} else {\n\t\tstr, ok := mysql.Priv2Str[n.Priv]\n\t\tif ok {\n\t\t\tctx.WriteKeyWord(str)\n\t\t} else {\n\t\t\treturn errors.New(\"Undefined privilege type\")\n\t\t}\n\t}\n\tif n.Cols != nil {\n\t\tctx.WritePlain(\" (\")\n\t\tfor i, v := range n.Cols {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tif err := v.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore PrivElem.Cols[%d]\", i)\n\t\t\t}\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *PrivElem) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*PrivElem)\n\tfor i, val := range n.Cols {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Cols[i] = node.(*ColumnName)\n\t}\n\treturn v.Leave(n)\n}\n\n// ObjectTypeType is the type for object type.\ntype ObjectTypeType int\n\nconst (\n\t// ObjectTypeNone is for empty object type.\n\tObjectTypeNone ObjectTypeType = iota + 1\n\t// ObjectTypeTable means the following object is a table.\n\tObjectTypeTable\n)\n\n// Restore implements Node interface.\nfunc (n ObjectTypeType) Restore(ctx *RestoreCtx) error {\n\tswitch n {\n\tcase ObjectTypeNone:\n\t\t// do nothing\n\tcase ObjectTypeTable:\n\t\tctx.WriteKeyWord(\"TABLE\")\n\tdefault:\n\t\treturn errors.New(\"Unsupported object type\")\n\t}\n\treturn nil\n}\n\n// GrantLevelType is the type for grant level.\ntype GrantLevelType int\n\nconst (\n\t// GrantLevelNone is the dummy const for default value.\n\tGrantLevelNone GrantLevelType = iota + 1\n\t// GrantLevelGlobal means the privileges are administrative or apply to all databases on a given server.\n\tGrantLevelGlobal\n\t// GrantLevelDB means the privileges apply to all objects in a given database.\n\tGrantLevelDB\n\t// GrantLevelTable means the privileges apply to all columns in a given table.\n\tGrantLevelTable\n)\n\n// GrantLevel is used for store the privilege scope.\ntype GrantLevel struct {\n\tLevel     GrantLevelType\n\tDBName    string\n\tTableName string\n}\n\n// Restore implements Node interface.\nfunc (n *GrantLevel) Restore(ctx *RestoreCtx) error {\n\tswitch n.Level {\n\tcase GrantLevelDB:\n\t\tif n.DBName == \"\" {\n\t\t\tctx.WritePlain(\"*\")\n\t\t} else {\n\t\t\tctx.WriteName(n.DBName)\n\t\t\tctx.WritePlain(\".*\")\n\t\t}\n\tcase GrantLevelGlobal:\n\t\tctx.WritePlain(\"*.*\")\n\tcase GrantLevelTable:\n\t\tif n.DBName != \"\" {\n\t\t\tctx.WriteName(n.DBName)\n\t\t\tctx.WritePlain(\".\")\n\t\t}\n\t\tctx.WriteName(n.TableName)\n\t}\n\treturn nil\n}\n\n// RevokeStmt is the struct for REVOKE statement.\ntype RevokeStmt struct {\n\tstmtNode\n\n\tPrivs      []*PrivElem\n\tObjectType ObjectTypeType\n\tLevel      *GrantLevel\n\tUsers      []*UserSpec\n}\n\n// Restore implements Node interface.\nfunc (n *RevokeStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"REVOKE \")\n\tfor i, v := range n.Privs {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore RevokeStmt.Privs[%d]\", i)\n\t\t}\n\t}\n\tctx.WriteKeyWord(\" ON \")\n\tif n.ObjectType != ObjectTypeNone {\n\t\tif err := n.ObjectType.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore RevokeStmt.ObjectType\")\n\t\t}\n\t\tctx.WritePlain(\" \")\n\t}\n\tif err := n.Level.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore RevokeStmt.Level\")\n\t}\n\tctx.WriteKeyWord(\" FROM \")\n\tfor i, v := range n.Users {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore RevokeStmt.Users[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *RevokeStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*RevokeStmt)\n\tfor i, val := range n.Privs {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Privs[i] = node.(*PrivElem)\n\t}\n\treturn v.Leave(n)\n}\n\n// RevokeStmt is the struct for REVOKE statement.\ntype RevokeRoleStmt struct {\n\tstmtNode\n\n\tRoles []*auth.RoleIdentity\n\tUsers []*auth.UserIdentity\n}\n\n// Restore implements Node interface.\nfunc (n *RevokeRoleStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"REVOKE \")\n\tfor i, role := range n.Roles {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := role.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore RevokeRoleStmt.Roles[%d]\", i)\n\t\t}\n\t}\n\tctx.WriteKeyWord(\" FROM \")\n\tfor i, v := range n.Users {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore RevokeRoleStmt.Users[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *RevokeRoleStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*RevokeRoleStmt)\n\treturn v.Leave(n)\n}\n\n// GrantStmt is the struct for GRANT statement.\ntype GrantStmt struct {\n\tstmtNode\n\n\tPrivs      []*PrivElem\n\tObjectType ObjectTypeType\n\tLevel      *GrantLevel\n\tUsers      []*UserSpec\n\tTLSOptions []*TLSOption\n\tWithGrant  bool\n}\n\n// Restore implements Node interface.\nfunc (n *GrantStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"GRANT \")\n\tfor i, v := range n.Privs {\n\t\tif i != 0 && v.Priv != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t} else if v.Priv == 0 {\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore GrantStmt.Privs[%d]\", i)\n\t\t}\n\t}\n\tctx.WriteKeyWord(\" ON \")\n\tif n.ObjectType != ObjectTypeNone {\n\t\tif err := n.ObjectType.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotate(err, \"An error occurred while restore GrantStmt.ObjectType\")\n\t\t}\n\t\tctx.WritePlain(\" \")\n\t}\n\tif err := n.Level.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while restore GrantStmt.Level\")\n\t}\n\tctx.WriteKeyWord(\" TO \")\n\tfor i, v := range n.Users {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore GrantStmt.Users[%d]\", i)\n\t\t}\n\t}\n\tif n.TLSOptions != nil {\n\t\tif len(n.TLSOptions) != 0 {\n\t\t\tctx.WriteKeyWord(\" REQUIRE \")\n\t\t}\n\t\tfor i, option := range n.TLSOptions {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WriteKeyWord(\" AND \")\n\t\t\t}\n\t\t\tif err := option.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore GrantStmt.TLSOptions[%d]\", i)\n\t\t\t}\n\t\t}\n\t}\n\tif n.WithGrant {\n\t\tctx.WriteKeyWord(\" WITH GRANT OPTION\")\n\t}\n\treturn nil\n}\n\n// SecureText implements SensitiveStatement interface.\nfunc (n *GrantStmt) SecureText() string {\n\ttext := n.text\n\t// Filter \"identified by xxx\" because it would expose password information.\n\tidx := strings.Index(strings.ToLower(text), \"identified\")\n\tif idx > 0 {\n\t\ttext = text[:idx]\n\t}\n\treturn text\n}\n\n// Accept implements Node Accept interface.\nfunc (n *GrantStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*GrantStmt)\n\tfor i, val := range n.Privs {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.Privs[i] = node.(*PrivElem)\n\t}\n\treturn v.Leave(n)\n}\n\n// GrantRoleStmt is the struct for GRANT TO statement.\ntype GrantRoleStmt struct {\n\tstmtNode\n\n\tRoles []*auth.RoleIdentity\n\tUsers []*auth.UserIdentity\n}\n\n// Accept implements Node Accept interface.\nfunc (n *GrantRoleStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*GrantRoleStmt)\n\treturn v.Leave(n)\n}\n\n// Restore implements Node interface.\nfunc (n *GrantRoleStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"GRANT \")\n\tif len(n.Roles) > 0 {\n\t\tfor i, role := range n.Roles {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tif err := role.Restore(ctx); err != nil {\n\t\t\t\treturn errors.Annotatef(err, \"An error occurred while restore GrantRoleStmt.Roles[%d]\", i)\n\t\t\t}\n\t\t}\n\t}\n\tctx.WriteKeyWord(\" TO \")\n\tfor i, v := range n.Users {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\", \")\n\t\t}\n\t\tif err := v.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore GrantStmt.Users[%d]\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// SecureText implements SensitiveStatement interface.\nfunc (n *GrantRoleStmt) SecureText() string {\n\ttext := n.text\n\t// Filter \"identified by xxx\" because it would expose password information.\n\tidx := strings.Index(strings.ToLower(text), \"identified\")\n\tif idx > 0 {\n\t\ttext = text[:idx]\n\t}\n\treturn text\n}\n\n// ShutdownStmt is a statement to stop the TiDB server.\n// See https://dev.mysql.com/doc/refman/5.7/en/shutdown.html\ntype ShutdownStmt struct {\n\tstmtNode\n}\n\n// Restore implements Node interface.\nfunc (n *ShutdownStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"SHUTDOWN\")\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ShutdownStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ShutdownStmt)\n\treturn v.Leave(n)\n}\n\n// Ident is the table identifier composed of schema name and table name.\ntype Ident struct {\n\tSchema model.CIStr\n\tName   model.CIStr\n}\n\n// String implements fmt.Stringer interface.\nfunc (i Ident) String() string {\n\tif i.Schema.O == \"\" {\n\t\treturn i.Name.O\n\t}\n\treturn fmt.Sprintf(\"%s.%s\", i.Schema, i.Name)\n}\n\n// SelectStmtOpts wrap around select hints and switches\ntype SelectStmtOpts struct {\n\tDistinct        bool\n\tSQLBigResult    bool\n\tSQLBufferResult bool\n\tSQLCache        bool\n\tSQLSmallResult  bool\n\tCalcFoundRows   bool\n\tStraightJoin    bool\n\tPriority        mysql.PriorityEnum\n\tTableHints      []*TableOptimizerHint\n}\n\n// TableOptimizerHint is Table level optimizer hint\ntype TableOptimizerHint struct {\n\tnode\n\t// HintName is the name or alias of the table(s) which the hint will affect.\n\t// Table hints has no schema info\n\t// It allows only table name or alias (if table has an alias)\n\tHintName model.CIStr\n\t// QBName is the default effective query block of this hint.\n\tQBName    model.CIStr\n\tTables    []HintTable\n\tIndexes   []model.CIStr\n\tStoreType model.CIStr\n\t// Statement Execution Time Optimizer Hints\n\t// See https://dev.mysql.com/doc/refman/5.7/en/optimizer-hints.html#optimizer-hints-execution-time\n\tMaxExecutionTime uint64\n\tMemoryQuota      int64\n\tQueryType        model.CIStr\n\tHintFlag         bool\n}\n\n// HintTable is table in the hint. It may have query block info.\ntype HintTable struct {\n\tDBName    model.CIStr\n\tTableName model.CIStr\n\tQBName    model.CIStr\n}\n\nfunc (ht *HintTable) Restore(ctx *RestoreCtx) {\n\tif ht.DBName.L != \"\" {\n\t\tctx.WriteName(ht.DBName.String())\n\t\tctx.WriteKeyWord(\".\")\n\t}\n\tctx.WriteName(ht.TableName.String())\n\tif ht.QBName.L != \"\" {\n\t\tctx.WriteKeyWord(\"@\")\n\t\tctx.WriteName(ht.QBName.String())\n\t}\n}\n\n// Restore implements Node interface.\nfunc (n *TableOptimizerHint) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(n.HintName.String())\n\tctx.WritePlain(\"(\")\n\tif n.QBName.L != \"\" {\n\t\tif n.HintName.L != \"qb_name\" {\n\t\t\tctx.WriteKeyWord(\"@\")\n\t\t}\n\t\tctx.WriteName(n.QBName.String())\n\t}\n\t// Hints without args except query block.\n\tswitch n.HintName.L {\n\tcase \"hash_agg\", \"stream_agg\", \"agg_to_cop\", \"read_consistent_replica\", \"no_index_merge\", \"qb_name\":\n\t\tctx.WritePlain(\")\")\n\t\treturn nil\n\t}\n\tif n.QBName.L != \"\" {\n\t\tctx.WritePlain(\" \")\n\t}\n\t// Hints with args except query block.\n\tswitch n.HintName.L {\n\tcase \"max_execution_time\":\n\t\tctx.WritePlainf(\"%d\", n.MaxExecutionTime)\n\tcase \"tidb_hj\", \"tidb_smj\", \"tidb_inlj\", \"hash_join\", \"sm_join\", \"inl_join\":\n\t\tfor i, table := range n.Tables {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\ttable.Restore(ctx)\n\t\t}\n\tcase \"use_index\", \"ignore_index\", \"use_index_merge\":\n\t\tn.Tables[0].Restore(ctx)\n\t\tctx.WritePlain(\" \")\n\t\tfor i, index := range n.Indexes {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t\tctx.WriteName(index.String())\n\t\t}\n\tcase \"use_toja\", \"enable_plan_cache\":\n\t\tif n.HintFlag {\n\t\t\tctx.WritePlain(\"TRUE\")\n\t\t} else {\n\t\t\tctx.WritePlain(\"FALSE\")\n\t\t}\n\tcase \"query_type\":\n\t\tctx.WriteKeyWord(n.QueryType.String())\n\tcase \"memory_quota\":\n\t\tctx.WritePlainf(\"%d MB\", n.MemoryQuota/1024/1024)\n\tcase \"read_from_storage\":\n\t\tctx.WriteKeyWord(n.StoreType.String())\n\t\tfor i, table := range n.Tables {\n\t\t\tif i == 0 {\n\t\t\t\tctx.WritePlain(\"[\")\n\t\t\t}\n\t\t\ttable.Restore(ctx)\n\t\t\tif i == len(n.Tables)-1 {\n\t\t\t\tctx.WritePlain(\"]\")\n\t\t\t} else {\n\t\t\t\tctx.WritePlain(\", \")\n\t\t\t}\n\t\t}\n\t}\n\tctx.WritePlain(\")\")\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *TableOptimizerHint) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*TableOptimizerHint)\n\treturn v.Leave(n)\n}\n\ntype BinaryLiteral interface {\n\tToString() string\n}\n\n// NewDecimal creates a types.Decimal value, it's provided by parser driver.\nvar NewDecimal func(string) (interface{}, error)\n\n// NewHexLiteral creates a types.HexLiteral value, it's provided by parser driver.\nvar NewHexLiteral func(string) (interface{}, error)\n\n// NewBitLiteral creates a types.BitLiteral value, it's provided by parser driver.\nvar NewBitLiteral func(string) (interface{}, error)\n"
  },
  {
    "path": "pkg/parser/ast/misc_test.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast_test\n\nimport (\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t. \"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/auth\"\n)\n\nvar _ = Suite(&testMiscSuite{})\n\ntype testMiscSuite struct {\n}\n\ntype visitor struct{}\n\nfunc (v visitor) Enter(in Node) (Node, bool) {\n\treturn in, false\n}\n\nfunc (v visitor) Leave(in Node) (Node, bool) {\n\treturn in, true\n}\n\ntype visitor1 struct {\n\tvisitor\n}\n\nfunc (visitor1) Enter(in Node) (Node, bool) {\n\treturn in, true\n}\n\nfunc (ts *testMiscSuite) TestMiscVisitorCover(c *C) {\n\tvalueExpr := NewValueExpr(42)\n\tstmts := []Node{\n\t\t&AdminStmt{},\n\t\t&AlterUserStmt{},\n\t\t&BeginStmt{},\n\t\t&BinlogStmt{},\n\t\t&CommitStmt{},\n\t\t&CreateUserStmt{},\n\t\t&DeallocateStmt{},\n\t\t&DoStmt{},\n\t\t&ExecuteStmt{UsingVars: []ExprNode{valueExpr}},\n\t\t&ExplainStmt{Stmt: &ShowStmt{}},\n\t\t&GrantStmt{},\n\t\t&PrepareStmt{SQLVar: &VariableExpr{Value: valueExpr}},\n\t\t&RollbackStmt{},\n\t\t&SetPwdStmt{},\n\t\t&SetStmt{Variables: []*VariableAssignment{\n\t\t\t{\n\t\t\t\tValue: valueExpr,\n\t\t\t},\n\t\t}},\n\t\t&UseStmt{},\n\t\t&AnalyzeTableStmt{\n\t\t\tTableNames: []*TableName{\n\t\t\t\t{},\n\t\t\t},\n\t\t},\n\t\t&FlushStmt{},\n\t\t&PrivElem{},\n\t\t&VariableAssignment{Value: valueExpr},\n\t\t&KillStmt{},\n\t\t&DropStatsStmt{Table: &TableName{}},\n\t\t&ShutdownStmt{},\n\t}\n\n\tfor _, v := range stmts {\n\t\tv.Accept(visitor{})\n\t\tv.Accept(visitor1{})\n\t}\n}\n\nfunc (ts *testMiscSuite) TestDDLVisitorCover(c *C) {\n\tsql := `\ncreate table t (c1 int, c2 int);\nalter table t add column a int after b;\ncreate index t_i on t (id);\ncreate database test character set utf8;\ndrop database test;\ndrop index t_i on t;\ndrop table t;\ntruncate t;\ncreate table t (\njobAbbr string not null\n);\n`\n\tparse := parser.New()\n\tstmts, _, err := parse.Parse(sql, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tfor _, stmt := range stmts {\n\t\tstmt.Accept(visitor{})\n\t\tstmt.Accept(visitor1{})\n\t}\n}\n\nfunc (ts *testMiscSuite) TestDMLVistorCover(c *C) {\n\tsql := `delete from somelog where user = 'jcole' order by timestamp_column limit 1;\ndelete t1, t2 from t1 inner join t2 inner join t3 where t1.id=t2.id and t2.id=t3.id;\nselect * from t where exists(select * from t k where t.c = k.c having sum(c) = 1);\ninsert into t_copy select * from t where t.x > 5;\n(select /*+ TIDB_INLJ(t1) */ a from t1 where a=10 and b=1) union (select /*+ TIDB_SMJ(t2) */ a from t2 where a=11 and b=2) order by a limit 10;\nupdate t1 set col1 = col1 + 1, col2 = col1;\nshow create table t;\nload data infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b';`\n\n\tp := parser.New()\n\tstmts, _, err := p.Parse(sql, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tfor _, stmt := range stmts {\n\t\tstmt.Accept(visitor{})\n\t\tstmt.Accept(visitor1{})\n\t}\n}\n\n// test Change Pump or drainer status sql parser\nfunc (ts *testMiscSuite) TestChangeStmt(c *C) {\n\tsql := `change pump to node_state='paused' for node_id '127.0.0.1:8249';\nchange drainer to node_state='paused' for node_id '127.0.0.1:8249';\nshutdown;`\n\n\tp := parser.New()\n\tstmts, _, err := p.Parse(sql, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tfor _, stmt := range stmts {\n\t\tstmt.Accept(visitor{})\n\t\tstmt.Accept(visitor1{})\n\t}\n}\n\nfunc (ts *testMiscSuite) TestSensitiveStatement(c *C) {\n\tpositive := []StmtNode{\n\t\t&SetPwdStmt{},\n\t\t&CreateUserStmt{},\n\t\t&AlterUserStmt{},\n\t\t&GrantStmt{},\n\t}\n\tfor i, stmt := range positive {\n\t\t_, ok := stmt.(SensitiveStmtNode)\n\t\tc.Assert(ok, IsTrue, Commentf(\"%d, %#v fail\", i, stmt))\n\t}\n\n\tnegative := []StmtNode{\n\t\t&DropUserStmt{},\n\t\t&RevokeStmt{},\n\t\t&AlterTableStmt{},\n\t\t&CreateDatabaseStmt{},\n\t\t&CreateIndexStmt{},\n\t\t&CreateTableStmt{},\n\t\t&DropDatabaseStmt{},\n\t\t&DropIndexStmt{},\n\t\t&DropTableStmt{},\n\t\t&RenameTableStmt{},\n\t\t&TruncateTableStmt{},\n\t}\n\tfor _, stmt := range negative {\n\t\t_, ok := stmt.(SensitiveStmtNode)\n\t\tc.Assert(ok, IsFalse)\n\t}\n}\n\nfunc (ts *testMiscSuite) TestUserSpec(c *C) {\n\thashString := \"*F711F50F971C8C11EFFECFAA5D68DE138A5FA26E72C462FCD9A565F60063DCD2\"\n\tu := UserSpec{\n\t\tUser: &auth.UserIdentity{\n\t\t\tUsername: \"test\",\n\t\t},\n\t\tAuthOpt: &AuthOption{\n\t\t\tByAuthString: false,\n\t\t\tAuthString:   \"xxx\",\n\t\t\tHashString:   hashString,\n\t\t},\n\t}\n\tpwd, ok := u.EncodedPassword()\n\tc.Assert(ok, IsTrue)\n\tc.Assert(pwd, Equals, u.AuthOpt.HashString)\n\n\tu.AuthOpt.HashString = \"not-good-password-format\"\n\t_, ok = u.EncodedPassword()\n\tc.Assert(ok, IsFalse)\n\n\tu.AuthOpt.ByAuthString = true\n\tpwd, ok = u.EncodedPassword()\n\tc.Assert(ok, IsTrue)\n\tc.Assert(pwd, Equals, hashString)\n\n\tu.AuthOpt.AuthString = \"\"\n\tpwd, ok = u.EncodedPassword()\n\tc.Assert(ok, IsTrue)\n\tc.Assert(pwd, Equals, \"\")\n}\n\nfunc (ts *testMiscSuite) TestTableOptimizerHintRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"USE_INDEX(t1 c1)\", \"USE_INDEX(`t1` `c1`)\"},\n\t\t{\"USE_INDEX(test.t1 c1)\", \"USE_INDEX(`test`.`t1` `c1`)\"},\n\t\t{\"USE_INDEX(@sel_1 t1 c1)\", \"USE_INDEX(@`sel_1` `t1` `c1`)\"},\n\t\t{\"USE_INDEX(t1@sel_1 c1)\", \"USE_INDEX(`t1`@`sel_1` `c1`)\"},\n\t\t{\"USE_INDEX(test.t1@sel_1 c1)\", \"USE_INDEX(`test`.`t1`@`sel_1` `c1`)\"},\n\t\t{\"IGNORE_INDEX(t1 c1)\", \"IGNORE_INDEX(`t1` `c1`)\"},\n\t\t{\"IGNORE_INDEX(@sel_1 t1 c1)\", \"IGNORE_INDEX(@`sel_1` `t1` `c1`)\"},\n\t\t{\"IGNORE_INDEX(t1@sel_1 c1)\", \"IGNORE_INDEX(`t1`@`sel_1` `c1`)\"},\n\t\t{\"TIDB_SMJ(`t1`)\", \"TIDB_SMJ(`t1`)\"},\n\t\t{\"TIDB_SMJ(t1)\", \"TIDB_SMJ(`t1`)\"},\n\t\t{\"TIDB_SMJ(t1,t2)\", \"TIDB_SMJ(`t1`, `t2`)\"},\n\t\t{\"TIDB_SMJ(@sel1 t1,t2)\", \"TIDB_SMJ(@`sel1` `t1`, `t2`)\"},\n\t\t{\"TIDB_SMJ(t1@sel1,t2@sel2)\", \"TIDB_SMJ(`t1`@`sel1`, `t2`@`sel2`)\"},\n\t\t{\"TIDB_INLJ(t1,t2)\", \"TIDB_INLJ(`t1`, `t2`)\"},\n\t\t{\"TIDB_INLJ(@sel1 t1,t2)\", \"TIDB_INLJ(@`sel1` `t1`, `t2`)\"},\n\t\t{\"TIDB_INLJ(t1@sel1,t2@sel2)\", \"TIDB_INLJ(`t1`@`sel1`, `t2`@`sel2`)\"},\n\t\t{\"TIDB_HJ(t1,t2)\", \"TIDB_HJ(`t1`, `t2`)\"},\n\t\t{\"TIDB_HJ(@sel1 t1,t2)\", \"TIDB_HJ(@`sel1` `t1`, `t2`)\"},\n\t\t{\"TIDB_HJ(t1@sel1,t2@sel2)\", \"TIDB_HJ(`t1`@`sel1`, `t2`@`sel2`)\"},\n\t\t{\"SM_JOIN(t1,t2)\", \"SM_JOIN(`t1`, `t2`)\"},\n\t\t{\"INL_JOIN(t1,t2)\", \"INL_JOIN(`t1`, `t2`)\"},\n\t\t{\"HASH_JOIN(t1,t2)\", \"HASH_JOIN(`t1`, `t2`)\"},\n\t\t{\"MAX_EXECUTION_TIME(3000)\", \"MAX_EXECUTION_TIME(3000)\"},\n\t\t{\"MAX_EXECUTION_TIME(@sel1 3000)\", \"MAX_EXECUTION_TIME(@`sel1` 3000)\"},\n\t\t{\"USE_INDEX_MERGE(t1 c1)\", \"USE_INDEX_MERGE(`t1` `c1`)\"},\n\t\t{\"USE_INDEX_MERGE(@sel1 t1 c1)\", \"USE_INDEX_MERGE(@`sel1` `t1` `c1`)\"},\n\t\t{\"USE_INDEX_MERGE(t1@sel1 c1)\", \"USE_INDEX_MERGE(`t1`@`sel1` `c1`)\"},\n\t\t{\"USE_TOJA(TRUE)\", \"USE_TOJA(TRUE)\"},\n\t\t{\"USE_TOJA(FALSE)\", \"USE_TOJA(FALSE)\"},\n\t\t{\"USE_TOJA(@sel1 TRUE)\", \"USE_TOJA(@`sel1` TRUE)\"},\n\t\t{\"QUERY_TYPE(OLAP)\", \"QUERY_TYPE(OLAP)\"},\n\t\t{\"QUERY_TYPE(OLTP)\", \"QUERY_TYPE(OLTP)\"},\n\t\t{\"QUERY_TYPE(@sel1 OLTP)\", \"QUERY_TYPE(@`sel1` OLTP)\"},\n\t\t{\"MEMORY_QUOTA(1 GB)\", \"MEMORY_QUOTA(1024 MB)\"},\n\t\t{\"MEMORY_QUOTA(@sel1 1 GB)\", \"MEMORY_QUOTA(@`sel1` 1024 MB)\"},\n\t\t{\"HASH_AGG()\", \"HASH_AGG()\"},\n\t\t{\"HASH_AGG(@sel1)\", \"HASH_AGG(@`sel1`)\"},\n\t\t{\"STREAM_AGG()\", \"STREAM_AGG()\"},\n\t\t{\"STREAM_AGG(@sel1)\", \"STREAM_AGG(@`sel1`)\"},\n\t\t{\"AGG_TO_COP()\", \"AGG_TO_COP()\"},\n\t\t{\"AGG_TO_COP(@sel_1)\", \"AGG_TO_COP(@`sel_1`)\"},\n\t\t{\"NO_INDEX_MERGE()\", \"NO_INDEX_MERGE()\"},\n\t\t{\"NO_INDEX_MERGE(@sel1)\", \"NO_INDEX_MERGE(@`sel1`)\"},\n\t\t{\"READ_CONSISTENT_REPLICA()\", \"READ_CONSISTENT_REPLICA()\"},\n\t\t{\"READ_CONSISTENT_REPLICA(@sel1)\", \"READ_CONSISTENT_REPLICA(@`sel1`)\"},\n\t\t{\"QB_NAME(sel1)\", \"QB_NAME(`sel1`)\"},\n\t\t{\"READ_FROM_STORAGE(@sel TIFLASH[t1, t2])\", \"READ_FROM_STORAGE(@`sel` TIFLASH[`t1`, `t2`])\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*SelectStmt).TableHints[0]\n\t}\n\tRunNodeRestoreTest(c, testCases, \"select /*+ %s */ * from t1 join t2\", extractNodeFunc)\n}\n\nfunc (ts *testMiscSuite) TestChangeStmtRestore(c *C) {\n\ttestCases := []NodeRestoreTestCase{\n\t\t{\"CHANGE PUMP TO NODE_STATE ='paused' FOR NODE_ID '127.0.0.1:9090'\", \"CHANGE PUMP TO NODE_STATE ='paused' FOR NODE_ID '127.0.0.1:9090'\"},\n\t\t{\"CHANGE DRAINER TO NODE_STATE ='paused' FOR NODE_ID '127.0.0.1:9090'\", \"CHANGE DRAINER TO NODE_STATE ='paused' FOR NODE_ID '127.0.0.1:9090'\"},\n\t}\n\textractNodeFunc := func(node Node) Node {\n\t\treturn node.(*ChangeStmt)\n\t}\n\tRunNodeRestoreTest(c, testCases, \"%s\", extractNodeFunc)\n}\n"
  },
  {
    "path": "pkg/parser/ast/stats.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport (\n\t\"github.com/pingcap/errors\"\n\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n)\n\nvar (\n\t_ StmtNode = &AnalyzeTableStmt{}\n\t_ StmtNode = &DropStatsStmt{}\n\t_ StmtNode = &LoadStatsStmt{}\n)\n\n// AnalyzeTableStmt is used to create table statistics.\ntype AnalyzeTableStmt struct {\n\tstmtNode\n\n\tTableNames     []*TableName\n\tPartitionNames []model.CIStr\n\tIndexNames     []model.CIStr\n\tAnalyzeOpts    []AnalyzeOpt\n\n\t// IndexFlag is true when we only analyze indices for a table.\n\tIndexFlag   bool\n\tIncremental bool\n}\n\n// AnalyzeOptType is the type for analyze options.\ntype AnalyzeOptionType int\n\n// Analyze option types.\nconst (\n\tAnalyzeOptNumBuckets = iota\n\tAnalyzeOptNumTopN\n\tAnalyzeOptCMSketchDepth\n\tAnalyzeOptCMSketchWidth\n\tAnalyzeOptNumSamples\n)\n\n// AnalyzeOptionString stores the string form of analyze options.\nvar AnalyzeOptionString = map[AnalyzeOptionType]string{\n\tAnalyzeOptNumBuckets:    \"BUCKETS\",\n\tAnalyzeOptNumTopN:       \"TOPN\",\n\tAnalyzeOptCMSketchWidth: \"CMSKETCH WIDTH\",\n\tAnalyzeOptCMSketchDepth: \"CMSKETCH DEPTH\",\n\tAnalyzeOptNumSamples:    \"SAMPLES\",\n}\n\n// AnalyzeOpt stores the analyze option type and value.\ntype AnalyzeOpt struct {\n\tType  AnalyzeOptionType\n\tValue uint64\n}\n\n// Restore implements Node interface.\nfunc (n *AnalyzeTableStmt) Restore(ctx *RestoreCtx) error {\n\tif n.Incremental {\n\t\tctx.WriteKeyWord(\"ANALYZE INCREMENTAL TABLE \")\n\t} else {\n\t\tctx.WriteKeyWord(\"ANALYZE TABLE \")\n\t}\n\tfor i, table := range n.TableNames {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t\tif err := table.Restore(ctx); err != nil {\n\t\t\treturn errors.Annotatef(err, \"An error occurred while restore AnalyzeTableStmt.TableNames[%d]\", i)\n\t\t}\n\t}\n\tif len(n.PartitionNames) != 0 {\n\t\tctx.WriteKeyWord(\" PARTITION \")\n\t}\n\tfor i, partition := range n.PartitionNames {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\",\")\n\t\t}\n\t\tctx.WriteName(partition.O)\n\t}\n\tif n.IndexFlag {\n\t\tctx.WriteKeyWord(\" INDEX\")\n\t}\n\tfor i, index := range n.IndexNames {\n\t\tif i != 0 {\n\t\t\tctx.WritePlain(\",\")\n\t\t} else {\n\t\t\tctx.WritePlain(\" \")\n\t\t}\n\t\tctx.WriteName(index.O)\n\t}\n\tif len(n.AnalyzeOpts) != 0 {\n\t\tctx.WriteKeyWord(\" WITH\")\n\t\tfor i, opt := range n.AnalyzeOpts {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tctx.WritePlainf(\" %d \", opt.Value)\n\t\t\tctx.WritePlain(AnalyzeOptionString[opt.Type])\n\t\t}\n\t}\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *AnalyzeTableStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*AnalyzeTableStmt)\n\tfor i, val := range n.TableNames {\n\t\tnode, ok := val.Accept(v)\n\t\tif !ok {\n\t\t\treturn n, false\n\t\t}\n\t\tn.TableNames[i] = node.(*TableName)\n\t}\n\treturn v.Leave(n)\n}\n\n// DropStatsStmt is used to drop table statistics.\ntype DropStatsStmt struct {\n\tstmtNode\n\n\tTable *TableName\n}\n\n// Restore implements Node interface.\nfunc (n *DropStatsStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"DROP STATS \")\n\tif err := n.Table.Restore(ctx); err != nil {\n\t\treturn errors.Annotate(err, \"An error occurred while add table\")\n\t}\n\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *DropStatsStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*DropStatsStmt)\n\tnode, ok := n.Table.Accept(v)\n\tif !ok {\n\t\treturn n, false\n\t}\n\tn.Table = node.(*TableName)\n\treturn v.Leave(n)\n}\n\n// LoadStatsStmt is the statement node for loading statistic.\ntype LoadStatsStmt struct {\n\tstmtNode\n\n\tPath string\n}\n\n// Restore implements Node interface.\nfunc (n *LoadStatsStmt) Restore(ctx *RestoreCtx) error {\n\tctx.WriteKeyWord(\"LOAD STATS \")\n\tctx.WriteString(n.Path)\n\treturn nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *LoadStatsStmt) Accept(v Visitor) (Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*LoadStatsStmt)\n\treturn v.Leave(n)\n}\n"
  },
  {
    "path": "pkg/parser/ast/util.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport \"math\"\n\n// UnspecifiedSize is unspecified size.\nconst (\n\tUnspecifiedSize = math.MaxUint64\n)\n\n// IsReadOnly checks whether the input ast is readOnly.\nfunc IsReadOnly(node Node) bool {\n\tswitch st := node.(type) {\n\tcase *SelectStmt:\n\t\tif st.LockTp == SelectLockForUpdate || st.LockTp == SelectLockForUpdateNoWait {\n\t\t\treturn false\n\t\t}\n\n\t\tchecker := readOnlyChecker{\n\t\t\treadOnly: true,\n\t\t}\n\n\t\tnode.Accept(&checker)\n\t\treturn checker.readOnly\n\tcase *ExplainStmt:\n\t\treturn !st.Analyze || IsReadOnly(st.Stmt)\n\tcase *DoStmt:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// readOnlyChecker checks whether a query's ast is readonly, if it satisfied\n// 1. selectstmt;\n// 2. need not to set var;\n// it is readonly statement.\ntype readOnlyChecker struct {\n\treadOnly bool\n}\n\n// Enter implements Visitor interface.\nfunc (checker *readOnlyChecker) Enter(in Node) (out Node, skipChildren bool) {\n\tswitch node := in.(type) {\n\tcase *VariableExpr:\n\t\t// like func rewriteVariable(), this stands for SetVar.\n\t\tif !node.IsSystem && node.Value != nil {\n\t\t\tchecker.readOnly = false\n\t\t\treturn in, true\n\t\t}\n\t}\n\treturn in, false\n}\n\n// Leave implements Visitor interface.\nfunc (checker *readOnlyChecker) Leave(in Node) (out Node, ok bool) {\n\treturn in, checker.readOnly\n}\n"
  },
  {
    "path": "pkg/parser/ast/util_test.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t. \"github.com/secretflow/scql/pkg/parser/ast\"\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/test_driver\"\n)\n\nvar _ = Suite(&testCacheableSuite{})\n\ntype testCacheableSuite struct {\n}\n\nfunc (s *testCacheableSuite) TestCacheable(c *C) {\n\t// test non-SelectStmt\n\tvar stmt Node = &DeleteStmt{}\n\tc.Assert(IsReadOnly(stmt), IsFalse)\n\n\tstmt = &InsertStmt{}\n\tc.Assert(IsReadOnly(stmt), IsFalse)\n\n\tstmt = &UpdateStmt{}\n\tc.Assert(IsReadOnly(stmt), IsFalse)\n\n\tstmt = &ExplainStmt{}\n\tc.Assert(IsReadOnly(stmt), IsTrue)\n\n\tstmt = &ExplainStmt{}\n\tc.Assert(IsReadOnly(stmt), IsTrue)\n\n\tstmt = &DoStmt{}\n\tc.Assert(IsReadOnly(stmt), IsTrue)\n\n\tstmt = &ExplainStmt{\n\t\tStmt: &InsertStmt{},\n\t}\n\tc.Assert(IsReadOnly(stmt), IsTrue)\n\n\tstmt = &ExplainStmt{\n\t\tAnalyze: true,\n\t\tStmt:    &InsertStmt{},\n\t}\n\tc.Assert(IsReadOnly(stmt), IsFalse)\n\n\tstmt = &ExplainStmt{\n\t\tStmt: &SelectStmt{},\n\t}\n\tc.Assert(IsReadOnly(stmt), IsTrue)\n\n\tstmt = &ExplainStmt{\n\t\tAnalyze: true,\n\t\tStmt:    &SelectStmt{},\n\t}\n\tc.Assert(IsReadOnly(stmt), IsTrue)\n\n}\n\n// CleanNodeText set the text of node and all child node empty.\n// For test only.\nfunc CleanNodeText(node Node) {\n\tvar cleaner nodeTextCleaner\n\tnode.Accept(&cleaner)\n}\n\n// nodeTextCleaner clean the text of a node and it's child node.\n// For test only.\ntype nodeTextCleaner struct {\n}\n\n// Enter implements Visitor interface.\nfunc (checker *nodeTextCleaner) Enter(in Node) (out Node, skipChildren bool) {\n\tin.SetText(\"\")\n\tswitch node := in.(type) {\n\tcase *Constraint:\n\t\tif node.Option != nil {\n\t\t\tif node.Option.KeyBlockSize == 0x0 && node.Option.Tp == 0 && node.Option.Comment == \"\" {\n\t\t\t\tnode.Option = nil\n\t\t\t}\n\t\t}\n\tcase *FuncCallExpr:\n\t\tnode.FnName.O = strings.ToLower(node.FnName.O)\n\t\tswitch node.FnName.L {\n\t\tcase \"convert\":\n\t\t\tnode.Args[1].(*test_driver.ValueExpr).Datum.SetBytes(nil)\n\t\t}\n\tcase *AggregateFuncExpr:\n\t\tnode.F = strings.ToLower(node.F)\n\tcase *FieldList:\n\t\tfor _, f := range node.Fields {\n\t\t\tf.Offset = 0\n\t\t}\n\tcase *AlterTableSpec:\n\t\tfor _, opt := range node.Options {\n\t\t\topt.StrValue = strings.ToLower(opt.StrValue)\n\t\t}\n\t}\n\treturn in, false\n}\n\n// Leave implements Visitor interface.\nfunc (checker *nodeTextCleaner) Leave(in Node) (out Node, ok bool) {\n\treturn in, true\n}\n\ntype NodeRestoreTestCase struct {\n\tsourceSQL string\n\texpectSQL string\n}\n\nfunc RunNodeRestoreTest(c *C, nodeTestCases []NodeRestoreTestCase, template string, extractNodeFunc func(node Node) Node) {\n\tRunNodeRestoreTestWithFlags(c, nodeTestCases, template, extractNodeFunc, DefaultRestoreFlags)\n}\n\nfunc RunNodeRestoreTestWithFlags(c *C, nodeTestCases []NodeRestoreTestCase, template string, extractNodeFunc func(node Node) Node, flags RestoreFlags) {\n\tparser := parser.New()\n\tparser.EnableWindowFunc(true)\n\tfor _, testCase := range nodeTestCases {\n\t\tsourceSQL := fmt.Sprintf(template, testCase.sourceSQL)\n\t\texpectSQL := fmt.Sprintf(template, testCase.expectSQL)\n\t\tstmt, err := parser.ParseOneStmt(sourceSQL, \"\", \"\")\n\t\tcomment := Commentf(\"source %#v\", testCase)\n\t\tc.Assert(err, IsNil, comment)\n\t\tvar sb strings.Builder\n\t\terr = extractNodeFunc(stmt).Restore(NewRestoreCtx(flags, &sb))\n\t\tc.Assert(err, IsNil, comment)\n\t\trestoreSql := fmt.Sprintf(template, sb.String())\n\t\tcomment = Commentf(\"source %#v; restore %v\", testCase, restoreSql)\n\t\tc.Assert(restoreSql, Equals, expectSQL, comment)\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/auth/auth.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage auth\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\n\t\"github.com/pingcap/errors\"\n\t\"github.com/tjfoc/gmsm/sm3\"\n\n\t\"github.com/secretflow/scql/pkg/constant\"\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n)\n\nvar EncHashType = constant.Sha256Hash\n\n// UserIdentity represents username and hostname.\ntype UserIdentity struct {\n\tUsername     string\n\tHostname     string\n\tCurrentUser  bool\n\tAuthUsername string // Username matched in privileges system\n\tAuthHostname string // Match in privs system (i.e. could be a wildcard)\n}\n\n// Restore implements Node interface.\nfunc (user *UserIdentity) Restore(ctx *RestoreCtx) error {\n\tif user.CurrentUser {\n\t\tctx.WriteKeyWord(\"CURRENT_USER\")\n\t} else {\n\t\tctx.WriteName(user.Username)\n\t\tif user.Hostname != \"\" {\n\t\t\tctx.WritePlain(\"@\")\n\t\t\tctx.WriteName(user.Hostname)\n\t\t}\n\t}\n\treturn nil\n}\n\n// String converts UserIdentity to the format user@host.\nfunc (user *UserIdentity) String() string {\n\t// TODO: Escape username and hostname.\n\tif user == nil {\n\t\treturn \"\"\n\t}\n\treturn fmt.Sprintf(\"%s@%s\", user.Username, user.Hostname)\n}\n\n// AuthIdentityString returns matched identity in user@host format\nfunc (user *UserIdentity) AuthIdentityString() string {\n\t// TODO: Escape username and hostname.\n\treturn fmt.Sprintf(\"%s@%s\", user.AuthUsername, user.AuthHostname)\n}\n\ntype RoleIdentity struct {\n\tUsername string\n\tHostname string\n}\n\nfunc (role *RoleIdentity) Restore(ctx *RestoreCtx) error {\n\tctx.WriteName(role.Username)\n\tif role.Hostname != \"\" {\n\t\tctx.WritePlain(\"@\")\n\t\tctx.WriteName(role.Hostname)\n\t}\n\treturn nil\n}\n\n// String converts UserIdentity to the format user@host.\nfunc (role *RoleIdentity) String() string {\n\t// TODO: Escape username and hostname.\n\treturn fmt.Sprintf(\"`%s`@`%s`\", role.Username, role.Hostname)\n}\n\n// CheckScrambledPassword check scrambled password received from client.\n// The new authentication is performed in following manner:\n//\n//\tSERVER:  public_seed=create_random_string()\n//\t         send(public_seed)\n//\tCLIENT:  recv(public_seed)\n//\t         hash_stage1=sha1(\"password\")\n//\t         hash_stage2=sha1(hash_stage1)\n//\t         reply=xor(hash_stage1, sha1(public_seed,hash_stage2)\n//\t         // this three steps are done in scramble()\n//\t         send(reply)\n//\tSERVER:  recv(reply)\n//\t         hash_stage1=xor(reply, sha1(public_seed,hash_stage2))\n//\t         candidate_hash2=sha1(hash_stage1)\n//\t         check(candidate_hash2==hash_stage2)\n//\t         // this three steps are done in check_scramble()\nfunc CheckScrambledPassword(salt, hpwd, auth []byte) bool {\n\tcrypt := sha256.New()\n\t_, err := crypt.Write(salt)\n\tterror.Log(errors.Trace(err))\n\t_, err = crypt.Write(hpwd)\n\tterror.Log(errors.Trace(err))\n\thash := crypt.Sum(nil)\n\t// token = scrambleHash XOR stage1Hash\n\tfor i := range hash {\n\t\thash[i] ^= auth[i]\n\t}\n\n\treturn bytes.Equal(hpwd, Sha256Hash(hash))\n}\n\n// Sha256Hash is an util function to calculate sha256 hash.\nfunc Sha256Hash(bs []byte) []byte {\n\tcrypt := sha256.New()\n\t_, err := crypt.Write(bs)\n\tterror.Log(errors.Trace(err))\n\treturn crypt.Sum(nil)\n}\n\n// SM3Hash is an util function to calculate SM3 hash.\nfunc SM3Hash(bs []byte) []byte {\n\tcrypt := sm3.New()\n\t_, err := crypt.Write(bs)\n\tterror.Log(errors.Trace(err))\n\treturn crypt.Sum(nil)\n}\n\n// EncodePassword converts plaintext password to hashed hex string.\nfunc EncodePassword(pwd string) string {\n\tif len(pwd) == 0 {\n\t\treturn \"\"\n\t}\n\thashFunc := Sha256Hash\n\tif EncHashType == constant.GMsm3Hash {\n\t\thashFunc = SM3Hash\n\t}\n\thash1 := hashFunc([]byte(pwd))\n\thash2 := hashFunc(hash1)\n\n\treturn fmt.Sprintf(\"*%X\", hash2)\n}\n\n// DecodePassword converts hex string password without prefix '*' to byte array.\nfunc DecodePassword(pwd string) ([]byte, error) {\n\tx, err := hex.DecodeString(pwd[1:])\n\tif err != nil {\n\t\treturn nil, errors.Trace(err)\n\t}\n\treturn x, nil\n}\n"
  },
  {
    "path": "pkg/parser/auth/auth_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage auth\n\nimport (\n\t. \"github.com/pingcap/check\"\n)\n\nvar _ = Suite(&testAuthSuite{})\n\ntype testAuthSuite struct {\n}\n\nfunc (s *testAuthSuite) TestEncodePassword(c *C) {\n\tpwd := \"123\"\n\tc.Assert(EncodePassword(pwd), Equals, \"*23AE809DDACAF96AF0FD78ED04B6A265E05AA257\")\n}\n\nfunc (s *testAuthSuite) TestDecodePassword(c *C) {\n\tx, err := DecodePassword(EncodePassword(\"123\"))\n\tc.Assert(err, IsNil)\n\tc.Assert(x, DeepEquals, Sha256Hash(Sha256Hash([]byte(\"123\"))))\n}\n\nfunc (s *testAuthSuite) TestCheckScramble(c *C) {\n\tpwd := \"abc\"\n\tsalt := []byte{85, 92, 45, 22, 58, 79, 107, 6, 122, 125, 58, 80, 12, 90, 103, 32, 90, 10, 74, 82}\n\tauth := []byte{24, 180, 183, 225, 166, 6, 81, 102, 70, 248, 199, 143, 91, 204, 169, 9, 161, 171, 203, 33}\n\tencodepwd := EncodePassword(pwd)\n\thpwd, err := DecodePassword(encodepwd)\n\tc.Assert(err, IsNil)\n\n\tres := CheckScrambledPassword(salt, hpwd, auth)\n\tc.Assert(res, IsTrue)\n}\n"
  },
  {
    "path": "pkg/parser/bench_test.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"testing\"\n)\n\nfunc BenchmarkSysbenchSelect(b *testing.B) {\n\tparser := New()\n\tsql := \"SELECT pad FROM sbtest1 WHERE id=1;\"\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _, err := parser.Parse(sql, \"\", \"\")\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\t}\n\tb.ReportAllocs()\n}\n\nfunc BenchmarkParseComplex(b *testing.B) {\n\tvar table = []string{\n\t\t`SELECT DISTINCT ca.l9_convergence_code AS atb2, cu.cust_sub_type AS account_type, cst.description AS account_type_desc, ss.prim_resource_val AS msisdn, ca.ban AS ban_key, To_char(mo.memo_date, 'YYYYMMDD') AS memo_date, cu.l9_identification AS thai_id, ss.subscriber_no AS subs_key, ss.dealer_code AS shop_code, cd.description AS shop_name, mot.short_desc, Regexp_substr(mo.attr1value, '[^ ;]+', 1, 3) staff_id, mo.operator_id AS user_id, mo.memo_system_text, co2.soc_name AS first_socname, co3.soc_name AS previous_socname, co.soc_name AS current_socname, Regexp_substr(mo.attr1value, '[^ ; ]+', 1, 1) NAME, co.soc_description AS current_pp_desc, co3.soc_description AS prev_pp_desc, co.soc_cd AS soc_cd, ( SELECT Sum(br.amount) FROM bl1_rc_rates BR, customer CU, subscriber SS WHERE br.service_receiver_id = ss.subscriber_no AND br.receiver_customer = ss.customer_id AND br.effective_date <= br.expiration_date AND (( ss. sub_status <> 'C' AND ss. sub_status <> 'T' AND br.expiration_date IS NULL) OR ( ss. sub_status = 'C' AND br.expiration_date LIKE ss.effective_date)) AND br.pp_ind = 'Y' AND br.cycle_code = cu.bill_cycle) AS pp_rate, cu.bill_cycle AS cycle_code, To_char(Nvl(ss.l9_tmv_act_date, ss.init_act_date),'YYYYMMDD') AS activated_date, To_char(cd.effective_date, 'YYYYMMDD') AS shop_effective_date, cd.expiration_date AS shop_expired_date, ca.l9_company_code AS company_code FROM service_details S, product CO, csm_pay_channel CPC, account CA, subscriber SS, customer CU, customer_sub_type CST, csm_dealer CD, service_details S2, product CO2, service_details S3, product CO3, memo MO , memo_type MOT, logical_date LO, charge_details CHD WHERE ss.subscriber_no = chd.agreement_no AND cpc.pym_channel_no = chd.target_pcn AND chd.chg_split_type = 'DR' AND chd.expiration_date IS NULL AND s.soc = co.soc_cd AND co.soc_type = 'P' AND s.agreement_no = ss.subscriber_no AND ss.prim_resource_tp = 'C' AND cpc.payment_category = 'POST' AND ca.ban = cpc.ban AND ( ca.l9_company_code = 'RF' OR ca.l9_company_code = 'RM' OR ca.l9_company_code = 'TM') AND ss.customer_id = cu.customer_id AND cu.cust_sub_type = cst.cust_sub_type AND cu.customer_type = cst.customer_type AND ss.dealer_code = cd.dealer AND s2.effective_date= ( SELECT Max(sa1.effective_date) FROM service_details SA1, product o1 WHERE sa1.agreement_no = ss.subscriber_no AND co.soc_cd = sa1.soc AND co.soc_type = 'P' ) AND s2.agreement_no = s.agreement_no AND s2.soc = co2.soc_cd AND co2.soc_type = 'P' AND s2.effective_date = ( SELECT Min(sa1.effective_date) FROM service_details SA1, product o1 WHERE sa1.agreement_no = ss.subscriber_no AND co2.soc_cd = sa1.soc AND co.soc_type = 'P' ) AND s3.agreement_no = s.agreement_no AND s3.soc = co3.soc_cd AND co3.soc_type = 'P' AND s3.effective_date = ( SELECT Max(sa1.effective_date) FROM service_details SA1, a product o1 WHERE sa1.agreement_no = ss.subscriber_no AND sa1.effective_date < ( SELECT Max(sa1.effective_date) FROM service_details SA1, product o1 WHERE sa1.agreement_no = ss.subscriber_no AND co3.soc_cd = sa1.soc AND co3.soc_type = 'P' ) AND co3.soc_cd = sa1.soc AND o1.soc_type = 'P' ) AND mo.entity_id = ss.subscriber_no AND mo.entity_type_id = 6 AND mo.memo_type_id = mot.memo_type_id AND Trunc(mo.sys_creation_date) = ( SELECT Trunc(lo.logical_date - 1) FROM lo) trunc(lo.logical_date - 1) AND lo.expiration_date IS NULL AND lo.logical_date_type = 'B' AND lo.expiration_date IS NULL AND ( mot.short_desc = 'BCN' OR mot.short_desc = 'BCNM' )`}\n\tparser := New()\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tfor _, v := range table {\n\t\t\t_, _, err := parser.Parse(v, \"\", \"\")\n\t\t\tif err != nil {\n\t\t\t\tb.Failed()\n\t\t\t}\n\t\t}\n\t}\n\tb.ReportAllocs()\n}\n\nfunc BenchmarkParseSimple(b *testing.B) {\n\tvar table = []string{\n\t\t\"insert into t values (1), (2), (3)\",\n\t\t\"insert into t values (4), (5), (6), (7)\",\n\t\t\"select c from t where c > 2\",\n\t}\n\tparser := New()\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tfor _, v := range table {\n\t\t\t_, _, err := parser.Parse(v, \"\", \"\")\n\t\t\tif err != nil {\n\t\t\t\tb.Failed()\n\t\t\t}\n\t\t}\n\t}\n\tb.ReportAllocs()\n}\n"
  },
  {
    "path": "pkg/parser/charset/charset.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage charset\n\nimport (\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n)\n\nvar (\n\tErrUnknownCollation         = terror.ClassDDL.New(mysql.ErrUnknownCollation, mysql.MySQLErrName[mysql.ErrUnknownCollation])\n\tErrCollationCharsetMismatch = terror.ClassDDL.New(mysql.ErrCollationCharsetMismatch, mysql.MySQLErrName[mysql.ErrCollationCharsetMismatch])\n)\n\n// Charset is a charset.\n// Now we only support MySQL.\ntype Charset struct {\n\tName             string\n\tDefaultCollation string\n\tCollations       map[string]*Collation\n\tDesc             string\n\tMaxlen           int\n}\n\n// Collation is a collation.\n// Now we only support MySQL.\ntype Collation struct {\n\tID          int\n\tCharsetName string\n\tName        string\n\tIsDefault   bool\n}\n\nvar charsets = make(map[string]*Charset)\nvar collationsIDMap = make(map[int]*Collation)\nvar collationsNameMap = make(map[string]*Collation)\nvar descs = make([]*Desc, 0, len(charsetInfos))\nvar supportedCollations = make([]*Collation, 0, len(supportedCollationNames))\n\n// All the supported charsets should be in the following table.\nvar charsetInfos = []*Charset{\n\t{CharsetUTF8, CollationUTF8, make(map[string]*Collation), \"UTF-8 Unicode\", 3},\n\t{CharsetUTF8MB4, CollationUTF8MB4, make(map[string]*Collation), \"UTF-8 Unicode\", 4},\n\t{CharsetASCII, CollationASCII, make(map[string]*Collation), \"US ASCII\", 1},\n\t{CharsetLatin1, CollationLatin1, make(map[string]*Collation), \"Latin1\", 1},\n\t{CharsetBin, CollationBin, make(map[string]*Collation), \"binary\", 1},\n}\n\n// All the names supported collations should be in the following table.\nvar supportedCollationNames = map[string]struct{}{\n\tCollationUTF8:    {},\n\tCollationUTF8MB4: {},\n\tCollationASCII:   {},\n\tCollationLatin1:  {},\n\tCollationBin:     {},\n}\n\n// Desc is a charset description.\ntype Desc struct {\n\tName             string\n\tDesc             string\n\tDefaultCollation string\n\tMaxlen           int\n}\n\n// GetSupportedCharsets gets descriptions for all charsets supported so far.\nfunc GetSupportedCharsets() []*Desc {\n\treturn descs\n}\n\n// GetSupportedCollations gets information for all collations supported so far.\nfunc GetSupportedCollations() []*Collation {\n\treturn supportedCollations\n}\n\n// ValidCharsetAndCollation checks the charset and the collation validity\n// and returns a boolean.\nfunc ValidCharsetAndCollation(cs string, co string) bool {\n\t// We will use utf8 as a default charset.\n\tif cs == \"\" {\n\t\tcs = \"utf8\"\n\t}\n\tcs = strings.ToLower(cs)\n\tc, ok := charsets[cs]\n\tif !ok {\n\t\treturn false\n\t}\n\n\tif co == \"\" {\n\t\treturn true\n\t}\n\tco = strings.ToLower(co)\n\t_, ok = c.Collations[co]\n\tif !ok {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// GetDefaultCollation returns the default collation for charset.\nfunc GetDefaultCollation(charset string) (string, error) {\n\tcharset = strings.ToLower(charset)\n\tif charset == CharsetBin {\n\t\treturn CollationBin, nil\n\t}\n\tc, ok := charsets[charset]\n\tif !ok {\n\t\treturn \"\", errors.Errorf(\"Unknown charset %s\", charset)\n\t}\n\treturn c.DefaultCollation, nil\n}\n\n// GetDefaultCharsetAndCollate returns the default charset and collation.\nfunc GetDefaultCharsetAndCollate() (string, string) {\n\treturn mysql.DefaultCharset, mysql.DefaultCollationName\n}\n\n// GetCharsetInfo returns charset and collation for cs as name.\nfunc GetCharsetInfo(cs string) (string, string, error) {\n\tc, ok := charsets[strings.ToLower(cs)]\n\tif !ok {\n\t\treturn \"\", \"\", errors.Errorf(\"Unknown charset %s\", cs)\n\t}\n\treturn c.Name, c.DefaultCollation, nil\n}\n\n// GetCharsetDesc gets charset descriptions in the local charsets.\nfunc GetCharsetDesc(cs string) (*Desc, error) {\n\tswitch strings.ToLower(cs) {\n\tcase CharsetUTF8:\n\t\treturn descs[0], nil\n\tcase CharsetUTF8MB4:\n\t\treturn descs[1], nil\n\tcase CharsetASCII:\n\t\treturn descs[2], nil\n\tcase CharsetLatin1:\n\t\treturn descs[3], nil\n\tcase CharsetBin:\n\t\treturn descs[4], nil\n\tdefault:\n\t\treturn nil, errors.Errorf(\"Unknown charset %s\", cs)\n\t}\n}\n\n// GetCharsetInfoByID returns charset and collation for id as cs_number.\nfunc GetCharsetInfoByID(coID int) (string, string, error) {\n\tif coID == mysql.DefaultCollationID {\n\t\treturn mysql.DefaultCharset, mysql.DefaultCollationName, nil\n\t}\n\tif collation, ok := collationsIDMap[coID]; ok {\n\t\treturn collation.CharsetName, collation.Name, nil\n\t}\n\treturn \"\", \"\", errors.Errorf(\"Unknown charset id %d\", coID)\n}\n\n// GetCollations returns a list for all collations.\nfunc GetCollations() []*Collation {\n\treturn collations\n}\n\nfunc GetCollationByName(name string) (*Collation, error) {\n\tcollation, ok := collationsNameMap[strings.ToLower(name)]\n\tif !ok {\n\t\treturn nil, ErrUnknownCollation.GenWithStackByArgs(name)\n\t}\n\treturn collation, nil\n}\n\nconst (\n\t// CharsetBin is used for marking binary charset.\n\tCharsetBin = \"binary\"\n\t// CollationBin is the default collation for CharsetBin.\n\tCollationBin = \"binary\"\n\t// CharsetUTF8 is the default charset for string types.\n\tCharsetUTF8 = \"utf8\"\n\t// CollationUTF8 is the default collation for CharsetUTF8.\n\tCollationUTF8 = \"utf8_bin\"\n\t// CharsetUTF8MB4 represents 4 bytes utf8, which works the same way as utf8 in Go.\n\tCharsetUTF8MB4 = \"utf8mb4\"\n\t// CollationUTF8MB4 is the default collation for CharsetUTF8MB4.\n\tCollationUTF8MB4 = \"utf8mb4_bin\"\n\t// CharsetASCII is a subset of UTF8.\n\tCharsetASCII = \"ascii\"\n\t// CollationASCII is the default collation for CharsetACSII.\n\tCollationASCII = \"ascii_bin\"\n\t// CharsetLatin1 is a single byte charset.\n\tCharsetLatin1 = \"latin1\"\n\t// CollationLatin1 is the default collation for CharsetLatin1.\n\tCollationLatin1 = \"latin1_bin\"\n)\n\nvar collations = []*Collation{\n\t{1, \"big5\", \"big5_chinese_ci\", true},\n\t{2, \"latin2\", \"latin2_czech_cs\", false},\n\t{3, \"dec8\", \"dec8_swedish_ci\", true},\n\t{4, \"cp850\", \"cp850_general_ci\", true},\n\t{5, \"latin1\", \"latin1_german1_ci\", false},\n\t{6, \"hp8\", \"hp8_english_ci\", true},\n\t{7, \"koi8r\", \"koi8r_general_ci\", true},\n\t{8, \"latin1\", \"latin1_swedish_ci\", false},\n\t{9, \"latin2\", \"latin2_general_ci\", true},\n\t{10, \"swe7\", \"swe7_swedish_ci\", true},\n\t{11, \"ascii\", \"ascii_general_ci\", false},\n\t{12, \"ujis\", \"ujis_japanese_ci\", true},\n\t{13, \"sjis\", \"sjis_japanese_ci\", true},\n\t{14, \"cp1251\", \"cp1251_bulgarian_ci\", false},\n\t{15, \"latin1\", \"latin1_danish_ci\", false},\n\t{16, \"hebrew\", \"hebrew_general_ci\", true},\n\t{18, \"tis620\", \"tis620_thai_ci\", true},\n\t{19, \"euckr\", \"euckr_korean_ci\", true},\n\t{20, \"latin7\", \"latin7_estonian_cs\", false},\n\t{21, \"latin2\", \"latin2_hungarian_ci\", false},\n\t{22, \"koi8u\", \"koi8u_general_ci\", true},\n\t{23, \"cp1251\", \"cp1251_ukrainian_ci\", false},\n\t{24, \"gb2312\", \"gb2312_chinese_ci\", true},\n\t{25, \"greek\", \"greek_general_ci\", true},\n\t{26, \"cp1250\", \"cp1250_general_ci\", true},\n\t{27, \"latin2\", \"latin2_croatian_ci\", false},\n\t{28, \"gbk\", \"gbk_chinese_ci\", true},\n\t{29, \"cp1257\", \"cp1257_lithuanian_ci\", false},\n\t{30, \"latin5\", \"latin5_turkish_ci\", true},\n\t{31, \"latin1\", \"latin1_german2_ci\", false},\n\t{32, \"armscii8\", \"armscii8_general_ci\", true},\n\t{33, \"utf8\", \"utf8_general_ci\", false},\n\t{34, \"cp1250\", \"cp1250_czech_cs\", false},\n\t{35, \"ucs2\", \"ucs2_general_ci\", true},\n\t{36, \"cp866\", \"cp866_general_ci\", true},\n\t{37, \"keybcs2\", \"keybcs2_general_ci\", true},\n\t{38, \"macce\", \"macce_general_ci\", true},\n\t{39, \"macroman\", \"macroman_general_ci\", true},\n\t{40, \"cp852\", \"cp852_general_ci\", true},\n\t{41, \"latin7\", \"latin7_general_ci\", true},\n\t{42, \"latin7\", \"latin7_general_cs\", false},\n\t{43, \"macce\", \"macce_bin\", false},\n\t{44, \"cp1250\", \"cp1250_croatian_ci\", false},\n\t{45, \"utf8mb4\", \"utf8mb4_general_ci\", false},\n\t{46, \"utf8mb4\", \"utf8mb4_bin\", true},\n\t{47, \"latin1\", \"latin1_bin\", true},\n\t{48, \"latin1\", \"latin1_general_ci\", false},\n\t{49, \"latin1\", \"latin1_general_cs\", false},\n\t{50, \"cp1251\", \"cp1251_bin\", false},\n\t{51, \"cp1251\", \"cp1251_general_ci\", true},\n\t{52, \"cp1251\", \"cp1251_general_cs\", false},\n\t{53, \"macroman\", \"macroman_bin\", false},\n\t{54, \"utf16\", \"utf16_general_ci\", true},\n\t{55, \"utf16\", \"utf16_bin\", false},\n\t{56, \"utf16le\", \"utf16le_general_ci\", true},\n\t{57, \"cp1256\", \"cp1256_general_ci\", true},\n\t{58, \"cp1257\", \"cp1257_bin\", false},\n\t{59, \"cp1257\", \"cp1257_general_ci\", true},\n\t{60, \"utf32\", \"utf32_general_ci\", true},\n\t{61, \"utf32\", \"utf32_bin\", false},\n\t{62, \"utf16le\", \"utf16le_bin\", false},\n\t{63, \"binary\", \"binary\", true},\n\t{64, \"armscii8\", \"armscii8_bin\", false},\n\t{65, \"ascii\", \"ascii_bin\", true},\n\t{66, \"cp1250\", \"cp1250_bin\", false},\n\t{67, \"cp1256\", \"cp1256_bin\", false},\n\t{68, \"cp866\", \"cp866_bin\", false},\n\t{69, \"dec8\", \"dec8_bin\", false},\n\t{70, \"greek\", \"greek_bin\", false},\n\t{71, \"hebrew\", \"hebrew_bin\", false},\n\t{72, \"hp8\", \"hp8_bin\", false},\n\t{73, \"keybcs2\", \"keybcs2_bin\", false},\n\t{74, \"koi8r\", \"koi8r_bin\", false},\n\t{75, \"koi8u\", \"koi8u_bin\", false},\n\t{77, \"latin2\", \"latin2_bin\", false},\n\t{78, \"latin5\", \"latin5_bin\", false},\n\t{79, \"latin7\", \"latin7_bin\", false},\n\t{80, \"cp850\", \"cp850_bin\", false},\n\t{81, \"cp852\", \"cp852_bin\", false},\n\t{82, \"swe7\", \"swe7_bin\", false},\n\t{83, \"utf8\", \"utf8_bin\", true},\n\t{84, \"big5\", \"big5_bin\", false},\n\t{85, \"euckr\", \"euckr_bin\", false},\n\t{86, \"gb2312\", \"gb2312_bin\", false},\n\t{87, \"gbk\", \"gbk_bin\", false},\n\t{88, \"sjis\", \"sjis_bin\", false},\n\t{89, \"tis620\", \"tis620_bin\", false},\n\t{90, \"ucs2\", \"ucs2_bin\", false},\n\t{91, \"ujis\", \"ujis_bin\", false},\n\t{92, \"geostd8\", \"geostd8_general_ci\", true},\n\t{93, \"geostd8\", \"geostd8_bin\", false},\n\t{94, \"latin1\", \"latin1_spanish_ci\", false},\n\t{95, \"cp932\", \"cp932_japanese_ci\", true},\n\t{96, \"cp932\", \"cp932_bin\", false},\n\t{97, \"eucjpms\", \"eucjpms_japanese_ci\", true},\n\t{98, \"eucjpms\", \"eucjpms_bin\", false},\n\t{99, \"cp1250\", \"cp1250_polish_ci\", false},\n\t{101, \"utf16\", \"utf16_unicode_ci\", false},\n\t{102, \"utf16\", \"utf16_icelandic_ci\", false},\n\t{103, \"utf16\", \"utf16_latvian_ci\", false},\n\t{104, \"utf16\", \"utf16_romanian_ci\", false},\n\t{105, \"utf16\", \"utf16_slovenian_ci\", false},\n\t{106, \"utf16\", \"utf16_polish_ci\", false},\n\t{107, \"utf16\", \"utf16_estonian_ci\", false},\n\t{108, \"utf16\", \"utf16_spanish_ci\", false},\n\t{109, \"utf16\", \"utf16_swedish_ci\", false},\n\t{110, \"utf16\", \"utf16_turkish_ci\", false},\n\t{111, \"utf16\", \"utf16_czech_ci\", false},\n\t{112, \"utf16\", \"utf16_danish_ci\", false},\n\t{113, \"utf16\", \"utf16_lithuanian_ci\", false},\n\t{114, \"utf16\", \"utf16_slovak_ci\", false},\n\t{115, \"utf16\", \"utf16_spanish2_ci\", false},\n\t{116, \"utf16\", \"utf16_roman_ci\", false},\n\t{117, \"utf16\", \"utf16_persian_ci\", false},\n\t{118, \"utf16\", \"utf16_esperanto_ci\", false},\n\t{119, \"utf16\", \"utf16_hungarian_ci\", false},\n\t{120, \"utf16\", \"utf16_sinhala_ci\", false},\n\t{121, \"utf16\", \"utf16_german2_ci\", false},\n\t{122, \"utf16\", \"utf16_croatian_ci\", false},\n\t{123, \"utf16\", \"utf16_unicode_520_ci\", false},\n\t{124, \"utf16\", \"utf16_vietnamese_ci\", false},\n\t{128, \"ucs2\", \"ucs2_unicode_ci\", false},\n\t{129, \"ucs2\", \"ucs2_icelandic_ci\", false},\n\t{130, \"ucs2\", \"ucs2_latvian_ci\", false},\n\t{131, \"ucs2\", \"ucs2_romanian_ci\", false},\n\t{132, \"ucs2\", \"ucs2_slovenian_ci\", false},\n\t{133, \"ucs2\", \"ucs2_polish_ci\", false},\n\t{134, \"ucs2\", \"ucs2_estonian_ci\", false},\n\t{135, \"ucs2\", \"ucs2_spanish_ci\", false},\n\t{136, \"ucs2\", \"ucs2_swedish_ci\", false},\n\t{137, \"ucs2\", \"ucs2_turkish_ci\", false},\n\t{138, \"ucs2\", \"ucs2_czech_ci\", false},\n\t{139, \"ucs2\", \"ucs2_danish_ci\", false},\n\t{140, \"ucs2\", \"ucs2_lithuanian_ci\", false},\n\t{141, \"ucs2\", \"ucs2_slovak_ci\", false},\n\t{142, \"ucs2\", \"ucs2_spanish2_ci\", false},\n\t{143, \"ucs2\", \"ucs2_roman_ci\", false},\n\t{144, \"ucs2\", \"ucs2_persian_ci\", false},\n\t{145, \"ucs2\", \"ucs2_esperanto_ci\", false},\n\t{146, \"ucs2\", \"ucs2_hungarian_ci\", false},\n\t{147, \"ucs2\", \"ucs2_sinhala_ci\", false},\n\t{148, \"ucs2\", \"ucs2_german2_ci\", false},\n\t{149, \"ucs2\", \"ucs2_croatian_ci\", false},\n\t{150, \"ucs2\", \"ucs2_unicode_520_ci\", false},\n\t{151, \"ucs2\", \"ucs2_vietnamese_ci\", false},\n\t{159, \"ucs2\", \"ucs2_general_mysql500_ci\", false},\n\t{160, \"utf32\", \"utf32_unicode_ci\", false},\n\t{161, \"utf32\", \"utf32_icelandic_ci\", false},\n\t{162, \"utf32\", \"utf32_latvian_ci\", false},\n\t{163, \"utf32\", \"utf32_romanian_ci\", false},\n\t{164, \"utf32\", \"utf32_slovenian_ci\", false},\n\t{165, \"utf32\", \"utf32_polish_ci\", false},\n\t{166, \"utf32\", \"utf32_estonian_ci\", false},\n\t{167, \"utf32\", \"utf32_spanish_ci\", false},\n\t{168, \"utf32\", \"utf32_swedish_ci\", false},\n\t{169, \"utf32\", \"utf32_turkish_ci\", false},\n\t{170, \"utf32\", \"utf32_czech_ci\", false},\n\t{171, \"utf32\", \"utf32_danish_ci\", false},\n\t{172, \"utf32\", \"utf32_lithuanian_ci\", false},\n\t{173, \"utf32\", \"utf32_slovak_ci\", false},\n\t{174, \"utf32\", \"utf32_spanish2_ci\", false},\n\t{175, \"utf32\", \"utf32_roman_ci\", false},\n\t{176, \"utf32\", \"utf32_persian_ci\", false},\n\t{177, \"utf32\", \"utf32_esperanto_ci\", false},\n\t{178, \"utf32\", \"utf32_hungarian_ci\", false},\n\t{179, \"utf32\", \"utf32_sinhala_ci\", false},\n\t{180, \"utf32\", \"utf32_german2_ci\", false},\n\t{181, \"utf32\", \"utf32_croatian_ci\", false},\n\t{182, \"utf32\", \"utf32_unicode_520_ci\", false},\n\t{183, \"utf32\", \"utf32_vietnamese_ci\", false},\n\t{192, \"utf8\", \"utf8_unicode_ci\", false},\n\t{193, \"utf8\", \"utf8_icelandic_ci\", false},\n\t{194, \"utf8\", \"utf8_latvian_ci\", false},\n\t{195, \"utf8\", \"utf8_romanian_ci\", false},\n\t{196, \"utf8\", \"utf8_slovenian_ci\", false},\n\t{197, \"utf8\", \"utf8_polish_ci\", false},\n\t{198, \"utf8\", \"utf8_estonian_ci\", false},\n\t{199, \"utf8\", \"utf8_spanish_ci\", false},\n\t{200, \"utf8\", \"utf8_swedish_ci\", false},\n\t{201, \"utf8\", \"utf8_turkish_ci\", false},\n\t{202, \"utf8\", \"utf8_czech_ci\", false},\n\t{203, \"utf8\", \"utf8_danish_ci\", false},\n\t{204, \"utf8\", \"utf8_lithuanian_ci\", false},\n\t{205, \"utf8\", \"utf8_slovak_ci\", false},\n\t{206, \"utf8\", \"utf8_spanish2_ci\", false},\n\t{207, \"utf8\", \"utf8_roman_ci\", false},\n\t{208, \"utf8\", \"utf8_persian_ci\", false},\n\t{209, \"utf8\", \"utf8_esperanto_ci\", false},\n\t{210, \"utf8\", \"utf8_hungarian_ci\", false},\n\t{211, \"utf8\", \"utf8_sinhala_ci\", false},\n\t{212, \"utf8\", \"utf8_german2_ci\", false},\n\t{213, \"utf8\", \"utf8_croatian_ci\", false},\n\t{214, \"utf8\", \"utf8_unicode_520_ci\", false},\n\t{215, \"utf8\", \"utf8_vietnamese_ci\", false},\n\t{223, \"utf8\", \"utf8_general_mysql500_ci\", false},\n\t{224, \"utf8mb4\", \"utf8mb4_unicode_ci\", false},\n\t{225, \"utf8mb4\", \"utf8mb4_icelandic_ci\", false},\n\t{226, \"utf8mb4\", \"utf8mb4_latvian_ci\", false},\n\t{227, \"utf8mb4\", \"utf8mb4_romanian_ci\", false},\n\t{228, \"utf8mb4\", \"utf8mb4_slovenian_ci\", false},\n\t{229, \"utf8mb4\", \"utf8mb4_polish_ci\", false},\n\t{230, \"utf8mb4\", \"utf8mb4_estonian_ci\", false},\n\t{231, \"utf8mb4\", \"utf8mb4_spanish_ci\", false},\n\t{232, \"utf8mb4\", \"utf8mb4_swedish_ci\", false},\n\t{233, \"utf8mb4\", \"utf8mb4_turkish_ci\", false},\n\t{234, \"utf8mb4\", \"utf8mb4_czech_ci\", false},\n\t{235, \"utf8mb4\", \"utf8mb4_danish_ci\", false},\n\t{236, \"utf8mb4\", \"utf8mb4_lithuanian_ci\", false},\n\t{237, \"utf8mb4\", \"utf8mb4_slovak_ci\", false},\n\t{238, \"utf8mb4\", \"utf8mb4_spanish2_ci\", false},\n\t{239, \"utf8mb4\", \"utf8mb4_roman_ci\", false},\n\t{240, \"utf8mb4\", \"utf8mb4_persian_ci\", false},\n\t{241, \"utf8mb4\", \"utf8mb4_esperanto_ci\", false},\n\t{242, \"utf8mb4\", \"utf8mb4_hungarian_ci\", false},\n\t{243, \"utf8mb4\", \"utf8mb4_sinhala_ci\", false},\n\t{244, \"utf8mb4\", \"utf8mb4_german2_ci\", false},\n\t{245, \"utf8mb4\", \"utf8mb4_croatian_ci\", false},\n\t{246, \"utf8mb4\", \"utf8mb4_unicode_520_ci\", false},\n\t{247, \"utf8mb4\", \"utf8mb4_vietnamese_ci\", false},\n\t{255, \"utf8mb4\", \"utf8mb4_0900_ai_ci\", false},\n}\n\n// init method always puts to the end of file.\nfunc init() {\n\tfor _, c := range charsetInfos {\n\t\tcharsets[c.Name] = c\n\t\tdesc := &Desc{\n\t\t\tName:             c.Name,\n\t\t\tDefaultCollation: c.DefaultCollation,\n\t\t\tDesc:             c.Desc,\n\t\t\tMaxlen:           c.Maxlen,\n\t\t}\n\t\tdescs = append(descs, desc)\n\t}\n\n\tfor _, c := range collations {\n\t\tcollationsIDMap[c.ID] = c\n\n\t\tif _, ok := supportedCollationNames[c.Name]; ok {\n\t\t\tsupportedCollations = append(supportedCollations, c)\n\t\t}\n\n\t\tif charset, ok := charsets[c.CharsetName]; ok {\n\t\t\tcharset.Collations[c.Name] = c\n\t\t}\n\t}\n\n\tfor id, name := range mysql.Collations {\n\t\tcollationsNameMap[name] = collationsIDMap[int(id)]\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/charset/charset_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage charset\n\nimport (\n\t\"math/rand\"\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n)\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nvar _ = Suite(&testCharsetSuite{})\n\ntype testCharsetSuite struct {\n}\n\nfunc testValidCharset(c *C, charset string, collation string, expect bool) {\n\tb := ValidCharsetAndCollation(charset, collation)\n\tc.Assert(b, Equals, expect)\n}\n\nfunc (s *testCharsetSuite) TestValidCharset(c *C) {\n\ttests := []struct {\n\t\tcs   string\n\t\tco   string\n\t\tsucc bool\n\t}{\n\t\t{\"utf8\", \"utf8_general_ci\", true},\n\t\t{\"\", \"utf8_general_ci\", true},\n\t\t{\"utf8mb4\", \"utf8mb4_bin\", true},\n\t\t{\"latin1\", \"latin1_bin\", true},\n\t\t{\"utf8\", \"utf8_invalid_ci\", false},\n\t\t{\"utf16\", \"utf16_bin\", false},\n\t\t{\"gb2312\", \"gb2312_chinese_ci\", false},\n\t\t{\"UTF8\", \"UTF8_BIN\", true},\n\t\t{\"UTF8\", \"utf8_bin\", true},\n\t\t{\"UTF8MB4\", \"utf8mb4_bin\", true},\n\t\t{\"UTF8MB4\", \"UTF8MB4_bin\", true},\n\t\t{\"UTF8MB4\", \"UTF8MB4_general_ci\", true},\n\t\t{\"Utf8\", \"uTf8_bIN\", true},\n\t}\n\tfor _, tt := range tests {\n\t\ttestValidCharset(c, tt.cs, tt.co, tt.succ)\n\t}\n}\n\nfunc (s *testCharsetSuite) TestGetSupportedCharsets(c *C) {\n\tcharset := &Charset{\"test\", \"test_bin\", nil, \"Test\", 5}\n\tcharsetInfos = append(charsetInfos, charset)\n\tdescs := GetSupportedCharsets()\n\tc.Assert(len(descs), Equals, len(charsetInfos)-1)\n}\n\nfunc testGetDefaultCollation(c *C, charset string, expectCollation string, succ bool) {\n\tb, err := GetDefaultCollation(charset)\n\tif !succ {\n\t\tc.Assert(err, NotNil)\n\t\treturn\n\t}\n\tc.Assert(b, Equals, expectCollation)\n}\n\nfunc (s *testCharsetSuite) TestGetDefaultCollation(c *C) {\n\ttests := []struct {\n\t\tcs   string\n\t\tco   string\n\t\tsucc bool\n\t}{\n\t\t{\"utf8\", \"utf8_bin\", true},\n\t\t{\"UTF8\", \"utf8_bin\", true},\n\t\t{\"utf8mb4\", \"utf8mb4_bin\", true},\n\t\t{\"ascii\", \"ascii_bin\", true},\n\t\t{\"binary\", \"binary\", true},\n\t\t{\"latin1\", \"latin1_bin\", true},\n\t\t{\"invalid_cs\", \"\", false},\n\t\t{\"\", \"utf8_bin\", false},\n\t}\n\tfor _, tt := range tests {\n\t\ttestGetDefaultCollation(c, tt.cs, tt.co, tt.succ)\n\t}\n\n\t// Test the consistency of collations table and charset desc table\n\tcharset_num := 0\n\tfor _, collate := range collations {\n\t\tif collate.IsDefault {\n\t\t\tif desc, ok := charsets[collate.CharsetName]; ok {\n\t\t\t\tc.Assert(collate.Name, Equals, desc.DefaultCollation)\n\t\t\t\tcharset_num += 1\n\t\t\t}\n\t\t}\n\t}\n\tc.Assert(charset_num, Equals, len(charsets))\n}\n\nfunc (s *testCharsetSuite) TestSupportedCollations(c *C) {\n\t// All supportedCollation are defined from their names\n\tc.Assert(len(supportedCollationNames), Equals, len(supportedCollationNames))\n\n\t// The default collations of supported charsets is the subset of supported collations\n\terrMsg := \"Charset [%v] is supported but its default collation [%v] is not.\"\n\tfor _, desc := range GetSupportedCharsets() {\n\t\tfound := false\n\t\tfor _, c := range GetSupportedCollations() {\n\t\t\tif desc.DefaultCollation == c.Name {\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tc.Assert(found, IsTrue, Commentf(errMsg, desc.Name, desc.DefaultCollation))\n\t}\n}\n\nfunc (s *testCharsetSuite) TestGetCharsetDesc(c *C) {\n\ttests := []struct {\n\t\tcs     string\n\t\tresult string\n\t\tsucc   bool\n\t}{\n\t\t{\"utf8\", \"utf8\", true},\n\t\t{\"UTF8\", \"utf8\", true},\n\t\t{\"utf8mb4\", \"utf8mb4\", true},\n\t\t{\"ascii\", \"ascii\", true},\n\t\t{\"binary\", \"binary\", true},\n\t\t{\"latin1\", \"latin1\", true},\n\t\t{\"invalid_cs\", \"\", false},\n\t\t{\"\", \"utf8_bin\", false},\n\t}\n\tfor _, tt := range tests {\n\t\tdesc, err := GetCharsetDesc(tt.cs)\n\t\tif !tt.succ {\n\t\t\tc.Assert(err, NotNil)\n\t\t} else {\n\t\t\tc.Assert(desc.Name, Equals, tt.result)\n\t\t}\n\t}\n}\n\nfunc (s *testCharsetSuite) TestGetCollationByName(c *C) {\n\n\tfor _, collation := range collations {\n\t\tcoll, err := GetCollationByName(collation.Name)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(coll, Equals, collation)\n\t}\n\n\t_, err := GetCollationByName(\"non_exist\")\n\tc.Assert(err, ErrorMatches, \"\\\\[ddl:1273\\\\]Unknown collation: 'non_exist'\")\n}\n\nfunc BenchmarkGetCharsetDesc(b *testing.B) {\n\tb.ResetTimer()\n\tcharsets := []string{CharsetUTF8, CharsetUTF8MB4, CharsetASCII, CharsetLatin1, CharsetBin}\n\tindex := rand.Intn(len(charsets))\n\tcs := charsets[index]\n\n\tfor i := 0; i < b.N; i++ {\n\t\tGetCharsetDesc(cs)\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/charset/encoding_table.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage charset\n\nimport (\n\t\"strings\"\n\n\t\"golang.org/x/text/encoding\"\n\t\"golang.org/x/text/encoding/charmap\"\n\t\"golang.org/x/text/encoding/japanese\"\n\t\"golang.org/x/text/encoding/korean\"\n\t\"golang.org/x/text/encoding/simplifiedchinese\"\n\t\"golang.org/x/text/encoding/traditionalchinese\"\n\t\"golang.org/x/text/encoding/unicode\"\n)\n\n// Lookup returns the encoding with the specified label, and its canonical\n// name. It returns nil and the empty string if label is not one of the\n// standard encodings for HTML. Matching is case-insensitive and ignores\n// leading and trailing whitespace.\nfunc Lookup(label string) (e encoding.Encoding, name string) {\n\tlabel = strings.ToLower(strings.Trim(label, \"\\t\\n\\r\\f \"))\n\tenc := encodings[label]\n\treturn enc.e, enc.name\n}\n\nvar encodings = map[string]struct {\n\te    encoding.Encoding\n\tname string\n}{\n\t\"unicode-1-1-utf-8\":   {encoding.Nop, \"utf-8\"},\n\t\"utf-8\":               {encoding.Nop, \"utf-8\"},\n\t\"utf8\":                {encoding.Nop, \"utf-8\"},\n\t\"utf8mb4\":             {encoding.Nop, \"utf-8\"},\n\t\"binary\":              {encoding.Nop, \"binary\"},\n\t\"866\":                 {charmap.CodePage866, \"ibm866\"},\n\t\"cp866\":               {charmap.CodePage866, \"ibm866\"},\n\t\"csibm866\":            {charmap.CodePage866, \"ibm866\"},\n\t\"ibm866\":              {charmap.CodePage866, \"ibm866\"},\n\t\"csisolatin2\":         {charmap.ISO8859_2, \"iso-8859-2\"},\n\t\"iso-8859-2\":          {charmap.ISO8859_2, \"iso-8859-2\"},\n\t\"iso-ir-101\":          {charmap.ISO8859_2, \"iso-8859-2\"},\n\t\"iso8859-2\":           {charmap.ISO8859_2, \"iso-8859-2\"},\n\t\"iso88592\":            {charmap.ISO8859_2, \"iso-8859-2\"},\n\t\"iso_8859-2\":          {charmap.ISO8859_2, \"iso-8859-2\"},\n\t\"iso_8859-2:1987\":     {charmap.ISO8859_2, \"iso-8859-2\"},\n\t\"l2\":                  {charmap.ISO8859_2, \"iso-8859-2\"},\n\t\"latin2\":              {charmap.ISO8859_2, \"iso-8859-2\"},\n\t\"csisolatin3\":         {charmap.ISO8859_3, \"iso-8859-3\"},\n\t\"iso-8859-3\":          {charmap.ISO8859_3, \"iso-8859-3\"},\n\t\"iso-ir-109\":          {charmap.ISO8859_3, \"iso-8859-3\"},\n\t\"iso8859-3\":           {charmap.ISO8859_3, \"iso-8859-3\"},\n\t\"iso88593\":            {charmap.ISO8859_3, \"iso-8859-3\"},\n\t\"iso_8859-3\":          {charmap.ISO8859_3, \"iso-8859-3\"},\n\t\"iso_8859-3:1988\":     {charmap.ISO8859_3, \"iso-8859-3\"},\n\t\"l3\":                  {charmap.ISO8859_3, \"iso-8859-3\"},\n\t\"latin3\":              {charmap.ISO8859_3, \"iso-8859-3\"},\n\t\"csisolatin4\":         {charmap.ISO8859_4, \"iso-8859-4\"},\n\t\"iso-8859-4\":          {charmap.ISO8859_4, \"iso-8859-4\"},\n\t\"iso-ir-110\":          {charmap.ISO8859_4, \"iso-8859-4\"},\n\t\"iso8859-4\":           {charmap.ISO8859_4, \"iso-8859-4\"},\n\t\"iso88594\":            {charmap.ISO8859_4, \"iso-8859-4\"},\n\t\"iso_8859-4\":          {charmap.ISO8859_4, \"iso-8859-4\"},\n\t\"iso_8859-4:1988\":     {charmap.ISO8859_4, \"iso-8859-4\"},\n\t\"l4\":                  {charmap.ISO8859_4, \"iso-8859-4\"},\n\t\"latin4\":              {charmap.ISO8859_4, \"iso-8859-4\"},\n\t\"csisolatincyrillic\":  {charmap.ISO8859_5, \"iso-8859-5\"},\n\t\"cyrillic\":            {charmap.ISO8859_5, \"iso-8859-5\"},\n\t\"iso-8859-5\":          {charmap.ISO8859_5, \"iso-8859-5\"},\n\t\"iso-ir-144\":          {charmap.ISO8859_5, \"iso-8859-5\"},\n\t\"iso8859-5\":           {charmap.ISO8859_5, \"iso-8859-5\"},\n\t\"iso88595\":            {charmap.ISO8859_5, \"iso-8859-5\"},\n\t\"iso_8859-5\":          {charmap.ISO8859_5, \"iso-8859-5\"},\n\t\"iso_8859-5:1988\":     {charmap.ISO8859_5, \"iso-8859-5\"},\n\t\"arabic\":              {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"asmo-708\":            {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"csiso88596e\":         {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"csiso88596i\":         {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"csisolatinarabic\":    {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"ecma-114\":            {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"iso-8859-6\":          {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"iso-8859-6-e\":        {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"iso-8859-6-i\":        {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"iso-ir-127\":          {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"iso8859-6\":           {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"iso88596\":            {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"iso_8859-6\":          {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"iso_8859-6:1987\":     {charmap.ISO8859_6, \"iso-8859-6\"},\n\t\"csisolatingreek\":     {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"ecma-118\":            {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"elot_928\":            {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"greek\":               {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"greek8\":              {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"iso-8859-7\":          {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"iso-ir-126\":          {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"iso8859-7\":           {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"iso88597\":            {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"iso_8859-7\":          {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"iso_8859-7:1987\":     {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"sun_eu_greek\":        {charmap.ISO8859_7, \"iso-8859-7\"},\n\t\"csiso88598e\":         {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"csisolatinhebrew\":    {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"hebrew\":              {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"iso-8859-8\":          {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"iso-8859-8-e\":        {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"iso-ir-138\":          {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"iso8859-8\":           {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"iso88598\":            {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"iso_8859-8\":          {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"iso_8859-8:1988\":     {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"visual\":              {charmap.ISO8859_8, \"iso-8859-8\"},\n\t\"csiso88598i\":         {charmap.ISO8859_8, \"iso-8859-8-i\"},\n\t\"iso-8859-8-i\":        {charmap.ISO8859_8, \"iso-8859-8-i\"},\n\t\"logical\":             {charmap.ISO8859_8, \"iso-8859-8-i\"},\n\t\"csisolatin6\":         {charmap.ISO8859_10, \"iso-8859-10\"},\n\t\"iso-8859-10\":         {charmap.ISO8859_10, \"iso-8859-10\"},\n\t\"iso-ir-157\":          {charmap.ISO8859_10, \"iso-8859-10\"},\n\t\"iso8859-10\":          {charmap.ISO8859_10, \"iso-8859-10\"},\n\t\"iso885910\":           {charmap.ISO8859_10, \"iso-8859-10\"},\n\t\"l6\":                  {charmap.ISO8859_10, \"iso-8859-10\"},\n\t\"latin6\":              {charmap.ISO8859_10, \"iso-8859-10\"},\n\t\"iso-8859-13\":         {charmap.ISO8859_13, \"iso-8859-13\"},\n\t\"iso8859-13\":          {charmap.ISO8859_13, \"iso-8859-13\"},\n\t\"iso885913\":           {charmap.ISO8859_13, \"iso-8859-13\"},\n\t\"iso-8859-14\":         {charmap.ISO8859_14, \"iso-8859-14\"},\n\t\"iso8859-14\":          {charmap.ISO8859_14, \"iso-8859-14\"},\n\t\"iso885914\":           {charmap.ISO8859_14, \"iso-8859-14\"},\n\t\"csisolatin9\":         {charmap.ISO8859_15, \"iso-8859-15\"},\n\t\"iso-8859-15\":         {charmap.ISO8859_15, \"iso-8859-15\"},\n\t\"iso8859-15\":          {charmap.ISO8859_15, \"iso-8859-15\"},\n\t\"iso885915\":           {charmap.ISO8859_15, \"iso-8859-15\"},\n\t\"iso_8859-15\":         {charmap.ISO8859_15, \"iso-8859-15\"},\n\t\"l9\":                  {charmap.ISO8859_15, \"iso-8859-15\"},\n\t\"iso-8859-16\":         {charmap.ISO8859_16, \"iso-8859-16\"},\n\t\"cskoi8r\":             {charmap.KOI8R, \"koi8-r\"},\n\t\"koi\":                 {charmap.KOI8R, \"koi8-r\"},\n\t\"koi8\":                {charmap.KOI8R, \"koi8-r\"},\n\t\"koi8-r\":              {charmap.KOI8R, \"koi8-r\"},\n\t\"koi8_r\":              {charmap.KOI8R, \"koi8-r\"},\n\t\"koi8-u\":              {charmap.KOI8U, \"koi8-u\"},\n\t\"csmacintosh\":         {charmap.Macintosh, \"macintosh\"},\n\t\"mac\":                 {charmap.Macintosh, \"macintosh\"},\n\t\"macintosh\":           {charmap.Macintosh, \"macintosh\"},\n\t\"x-mac-roman\":         {charmap.Macintosh, \"macintosh\"},\n\t\"dos-874\":             {charmap.Windows874, \"windows-874\"},\n\t\"iso-8859-11\":         {charmap.Windows874, \"windows-874\"},\n\t\"iso8859-11\":          {charmap.Windows874, \"windows-874\"},\n\t\"iso885911\":           {charmap.Windows874, \"windows-874\"},\n\t\"tis-620\":             {charmap.Windows874, \"windows-874\"},\n\t\"windows-874\":         {charmap.Windows874, \"windows-874\"},\n\t\"cp1250\":              {charmap.Windows1250, \"windows-1250\"},\n\t\"windows-1250\":        {charmap.Windows1250, \"windows-1250\"},\n\t\"x-cp1250\":            {charmap.Windows1250, \"windows-1250\"},\n\t\"cp1251\":              {charmap.Windows1251, \"windows-1251\"},\n\t\"windows-1251\":        {charmap.Windows1251, \"windows-1251\"},\n\t\"x-cp1251\":            {charmap.Windows1251, \"windows-1251\"},\n\t\"ansi_x3.4-1968\":      {charmap.Windows1252, \"windows-1252\"},\n\t\"ascii\":               {charmap.Windows1252, \"windows-1252\"},\n\t\"cp1252\":              {charmap.Windows1252, \"windows-1252\"},\n\t\"cp819\":               {charmap.Windows1252, \"windows-1252\"},\n\t\"csisolatin1\":         {charmap.Windows1252, \"windows-1252\"},\n\t\"ibm819\":              {charmap.Windows1252, \"windows-1252\"},\n\t\"iso-8859-1\":          {charmap.Windows1252, \"windows-1252\"},\n\t\"iso-ir-100\":          {charmap.Windows1252, \"windows-1252\"},\n\t\"iso8859-1\":           {charmap.Windows1252, \"windows-1252\"},\n\t\"iso88591\":            {charmap.Windows1252, \"windows-1252\"},\n\t\"iso_8859-1\":          {charmap.Windows1252, \"windows-1252\"},\n\t\"iso_8859-1:1987\":     {charmap.Windows1252, \"windows-1252\"},\n\t\"l1\":                  {charmap.Windows1252, \"windows-1252\"},\n\t\"latin1\":              {charmap.Windows1252, \"windows-1252\"},\n\t\"us-ascii\":            {charmap.Windows1252, \"windows-1252\"},\n\t\"windows-1252\":        {charmap.Windows1252, \"windows-1252\"},\n\t\"x-cp1252\":            {charmap.Windows1252, \"windows-1252\"},\n\t\"cp1253\":              {charmap.Windows1253, \"windows-1253\"},\n\t\"windows-1253\":        {charmap.Windows1253, \"windows-1253\"},\n\t\"x-cp1253\":            {charmap.Windows1253, \"windows-1253\"},\n\t\"cp1254\":              {charmap.Windows1254, \"windows-1254\"},\n\t\"csisolatin5\":         {charmap.Windows1254, \"windows-1254\"},\n\t\"iso-8859-9\":          {charmap.Windows1254, \"windows-1254\"},\n\t\"iso-ir-148\":          {charmap.Windows1254, \"windows-1254\"},\n\t\"iso8859-9\":           {charmap.Windows1254, \"windows-1254\"},\n\t\"iso88599\":            {charmap.Windows1254, \"windows-1254\"},\n\t\"iso_8859-9\":          {charmap.Windows1254, \"windows-1254\"},\n\t\"iso_8859-9:1989\":     {charmap.Windows1254, \"windows-1254\"},\n\t\"l5\":                  {charmap.Windows1254, \"windows-1254\"},\n\t\"latin5\":              {charmap.Windows1254, \"windows-1254\"},\n\t\"windows-1254\":        {charmap.Windows1254, \"windows-1254\"},\n\t\"x-cp1254\":            {charmap.Windows1254, \"windows-1254\"},\n\t\"cp1255\":              {charmap.Windows1255, \"windows-1255\"},\n\t\"windows-1255\":        {charmap.Windows1255, \"windows-1255\"},\n\t\"x-cp1255\":            {charmap.Windows1255, \"windows-1255\"},\n\t\"cp1256\":              {charmap.Windows1256, \"windows-1256\"},\n\t\"windows-1256\":        {charmap.Windows1256, \"windows-1256\"},\n\t\"x-cp1256\":            {charmap.Windows1256, \"windows-1256\"},\n\t\"cp1257\":              {charmap.Windows1257, \"windows-1257\"},\n\t\"windows-1257\":        {charmap.Windows1257, \"windows-1257\"},\n\t\"x-cp1257\":            {charmap.Windows1257, \"windows-1257\"},\n\t\"cp1258\":              {charmap.Windows1258, \"windows-1258\"},\n\t\"windows-1258\":        {charmap.Windows1258, \"windows-1258\"},\n\t\"x-cp1258\":            {charmap.Windows1258, \"windows-1258\"},\n\t\"x-mac-cyrillic\":      {charmap.MacintoshCyrillic, \"x-mac-cyrillic\"},\n\t\"x-mac-ukrainian\":     {charmap.MacintoshCyrillic, \"x-mac-cyrillic\"},\n\t\"chinese\":             {simplifiedchinese.GBK, \"gbk\"},\n\t\"csgb2312\":            {simplifiedchinese.GBK, \"gbk\"},\n\t\"csiso58gb231280\":     {simplifiedchinese.GBK, \"gbk\"},\n\t\"gb2312\":              {simplifiedchinese.GBK, \"gbk\"},\n\t\"gb_2312\":             {simplifiedchinese.GBK, \"gbk\"},\n\t\"gb_2312-80\":          {simplifiedchinese.GBK, \"gbk\"},\n\t\"gbk\":                 {simplifiedchinese.GBK, \"gbk\"},\n\t\"iso-ir-58\":           {simplifiedchinese.GBK, \"gbk\"},\n\t\"x-gbk\":               {simplifiedchinese.GBK, \"gbk\"},\n\t\"gb18030\":             {simplifiedchinese.GB18030, \"gb18030\"},\n\t\"hz-gb-2312\":          {simplifiedchinese.HZGB2312, \"hz-gb-2312\"},\n\t\"big5\":                {traditionalchinese.Big5, \"big5\"},\n\t\"big5-hkscs\":          {traditionalchinese.Big5, \"big5\"},\n\t\"cn-big5\":             {traditionalchinese.Big5, \"big5\"},\n\t\"csbig5\":              {traditionalchinese.Big5, \"big5\"},\n\t\"x-x-big5\":            {traditionalchinese.Big5, \"big5\"},\n\t\"cseucpkdfmtjapanese\": {japanese.EUCJP, \"euc-jp\"},\n\t\"euc-jp\":              {japanese.EUCJP, \"euc-jp\"},\n\t\"x-euc-jp\":            {japanese.EUCJP, \"euc-jp\"},\n\t\"csiso2022jp\":         {japanese.ISO2022JP, \"iso-2022-jp\"},\n\t\"iso-2022-jp\":         {japanese.ISO2022JP, \"iso-2022-jp\"},\n\t\"csshiftjis\":          {japanese.ShiftJIS, \"shift_jis\"},\n\t\"ms_kanji\":            {japanese.ShiftJIS, \"shift_jis\"},\n\t\"shift-jis\":           {japanese.ShiftJIS, \"shift_jis\"},\n\t\"shift_jis\":           {japanese.ShiftJIS, \"shift_jis\"},\n\t\"sjis\":                {japanese.ShiftJIS, \"shift_jis\"},\n\t\"windows-31j\":         {japanese.ShiftJIS, \"shift_jis\"},\n\t\"x-sjis\":              {japanese.ShiftJIS, \"shift_jis\"},\n\t\"cseuckr\":             {korean.EUCKR, \"euc-kr\"},\n\t\"csksc56011987\":       {korean.EUCKR, \"euc-kr\"},\n\t\"euc-kr\":              {korean.EUCKR, \"euc-kr\"},\n\t\"iso-ir-149\":          {korean.EUCKR, \"euc-kr\"},\n\t\"korean\":              {korean.EUCKR, \"euc-kr\"},\n\t\"ks_c_5601-1987\":      {korean.EUCKR, \"euc-kr\"},\n\t\"ks_c_5601-1989\":      {korean.EUCKR, \"euc-kr\"},\n\t\"ksc5601\":             {korean.EUCKR, \"euc-kr\"},\n\t\"ksc_5601\":            {korean.EUCKR, \"euc-kr\"},\n\t\"windows-949\":         {korean.EUCKR, \"euc-kr\"},\n\t\"csiso2022kr\":         {encoding.Replacement, \"replacement\"},\n\t\"iso-2022-kr\":         {encoding.Replacement, \"replacement\"},\n\t\"iso-2022-cn\":         {encoding.Replacement, \"replacement\"},\n\t\"iso-2022-cn-ext\":     {encoding.Replacement, \"replacement\"},\n\t\"utf-16be\":            {unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM), \"utf-16be\"},\n\t\"utf-16\":              {unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM), \"utf-16le\"},\n\t\"utf-16le\":            {unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM), \"utf-16le\"},\n\t\"x-user-defined\":      {charmap.XUserDefined, \"x-user-defined\"},\n}\n"
  },
  {
    "path": "pkg/parser/consistent_test.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\tioreader \"io\"\n\t\"os\"\n\t\"path\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strings\"\n\n\t. \"github.com/pingcap/check\"\n)\n\nvar _ = Suite(&testConsistentSuite{})\n\ntype testConsistentSuite struct {\n}\n\nfunc (s *testConsistentSuite) TestKeywordConsistent(c *C) {\n\t_, filename, _, _ := runtime.Caller(0)\n\tparserFilename := path.Join(path.Dir(filename), \"parser.y\")\n\tparserFile, err := os.Open(parserFilename)\n\tc.Assert(err, IsNil)\n\tdata, err := ioreader.ReadAll(parserFile)\n\tc.Assert(err, IsNil)\n\tcontent := string(data)\n\n\treservedKeywordStartMarker := \"\\t/* The following tokens belong to ReservedKeyword. Notice: make sure these tokens are contained in ReservedKeyword. */\"\n\tunreservedKeywordStartMarker := \"\\t/* The following tokens belong to UnReservedKeyword. Notice: make sure these tokens are contained in UnReservedKeyword. */\"\n\tnotKeywordTokenStartMarker := \"\\t/* The following tokens belong to NotKeywordToken. Notice: make sure these tokens are contained in NotKeywordToken. */\"\n\ttidbKeywordStartMarker := \"\\t/* The following tokens belong to TiDBKeyword. Notice: make sure these tokens are contained in TiDBKeyword. */\"\n\tidentTokenEndMarker := \"%token\\t<item>\"\n\n\treservedKeywords := extractKeywords(content, reservedKeywordStartMarker, unreservedKeywordStartMarker)\n\n\tunreservedKeywords := extractKeywords(content, unreservedKeywordStartMarker, notKeywordTokenStartMarker)\n\n\tnotKeywordTokens := extractKeywords(content, notKeywordTokenStartMarker, tidbKeywordStartMarker)\n\n\ttidbKeywords := extractKeywords(content, tidbKeywordStartMarker, identTokenEndMarker)\n\n\tfor k, v := range aliases {\n\t\tc.Assert(k != v, IsTrue)\n\t\tc.Assert(tokenMap[k], Equals, tokenMap[v])\n\t}\n\tkeywordCount := len(reservedKeywords) + len(unreservedKeywords) + len(notKeywordTokens) + len(tidbKeywords)\n\tc.Assert(len(tokenMap)-len(aliases), Equals, keywordCount-len(windowFuncTokenMap))\n\n\tunreservedCollectionDef := extractKeywordsFromCollectionDef(content, \"\\nUnReservedKeyword:\")\n\tc.Assert(unreservedKeywords, DeepEquals, unreservedCollectionDef)\n\n\tnotKeywordTokensCollectionDef := extractKeywordsFromCollectionDef(content, \"\\nNotKeywordToken:\")\n\tc.Assert(notKeywordTokens, DeepEquals, notKeywordTokensCollectionDef)\n\n\ttidbKeywordsCollectionDef := extractKeywordsFromCollectionDef(content, \"\\nTiDBKeyword:\")\n\tc.Assert(tidbKeywords, DeepEquals, tidbKeywordsCollectionDef)\n}\n\nfunc extractMiddle(str, startMarker, endMarker string) string {\n\tstartIdx := strings.Index(str, startMarker)\n\tif startIdx == -1 {\n\t\treturn \"\"\n\t}\n\tstr = str[startIdx+len(startMarker):]\n\tendIdx := strings.Index(str, endMarker)\n\tif endIdx == -1 {\n\t\treturn \"\"\n\t}\n\treturn str[:endIdx]\n}\n\nfunc extractQuotedWords(strs []string) []string {\n\tvar words []string\n\tfor _, str := range strs {\n\t\tword := extractMiddle(str, \"\\\"\", \"\\\"\")\n\t\tif word == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\twords = append(words, word)\n\t}\n\tsort.Strings(words)\n\treturn words\n}\n\nfunc extractKeywords(content, startMarker, endMarker string) []string {\n\tkeywordSection := extractMiddle(content, startMarker, endMarker)\n\tlines := strings.Split(keywordSection, \"\\n\")\n\treturn extractQuotedWords(lines)\n}\n\nfunc extractKeywordsFromCollectionDef(content, startMarker string) []string {\n\tkeywordSection := extractMiddle(content, startMarker, \"\\n\\n\")\n\twords := strings.Split(keywordSection, \"|\")\n\treturn extractQuotedWords(words)\n}\n"
  },
  {
    "path": "pkg/parser/digester.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\thash2 \"hash\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n\t\"unicode\"\n\t\"unsafe\"\n)\n\n// DigestHash generates the digest of statements.\n// it will generate a hash on normalized form of statement text\n// which removes general property of a statement but keeps specific property.\n//\n// for example: both DigestHash('select 1') and DigestHash('select 2') => e1c71d1661ae46e09b7aaec1c390957f0d6260410df4e4bc71b9c8d681021471\n//\n// Deprecated: It is logically consistent with NormalizeDigest.\nfunc DigestHash(sql string) (result string) {\n\td := digesterPool.Get().(*sqlDigester)\n\tresult = d.doDigest(sql)\n\tdigesterPool.Put(d)\n\treturn\n}\n\n// DigestNormalized generates the digest of a normalized sql.\n// it will generate a hash on a normalized sql.\n// Normalize + DigestNormalized equals to NormalizeDigest.\n//\n// for example: DigestNormalized('select ?')\n// DigestNormalized should be called with a normalized SQL string (like 'select ?') generated by function Normalize.\n// do not call with SQL which is not normalized, DigestNormalized('select 1') and DigestNormalized('select 2') is not the same\nfunc DigestNormalized(normalized string) (result string) {\n\td := digesterPool.Get().(*sqlDigester)\n\tresult = d.doDigestNormalized(normalized)\n\tdigesterPool.Put(d)\n\treturn\n}\n\n// Normalize generates the normalized statements.\n// it will get normalized form of statement text\n// which removes general property of a statement but keeps specific property.\n//\n// for example: Normalize('select 1 from b where a = 1') => 'select ? from b where a = ?'\nfunc Normalize(sql string) (result string) {\n\td := digesterPool.Get().(*sqlDigester)\n\tresult = d.doNormalize(sql)\n\tdigesterPool.Put(d)\n\treturn\n}\n\n// NormalizeDigest combines Normalize and DigestNormalized into one method.\nfunc NormalizeDigest(sql string) (normalized, digest string) {\n\td := digesterPool.Get().(*sqlDigester)\n\tnormalized, digest = d.doNormalizeDigest(sql)\n\tdigesterPool.Put(d)\n\treturn\n}\n\nvar digesterPool = sync.Pool{\n\tNew: func() interface{} {\n\t\treturn &sqlDigester{\n\t\t\tlexer:  NewScanner(\"\"),\n\t\t\thasher: sha256.New(),\n\t\t}\n\t},\n}\n\n// sqlDigester is used to compute DigestHash or Normalize for sql.\ntype sqlDigester struct {\n\tbuffer bytes.Buffer\n\tlexer  *Scanner\n\thasher hash2.Hash\n\ttokens tokenDeque\n}\n\nfunc (d *sqlDigester) doDigestNormalized(normalized string) (result string) {\n\thdr := *(*reflect.StringHeader)(unsafe.Pointer(&normalized))\n\tb := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{\n\t\tData: hdr.Data,\n\t\tLen:  hdr.Len,\n\t\tCap:  hdr.Len,\n\t}))\n\td.hasher.Write(b)\n\tresult = fmt.Sprintf(\"%x\", d.hasher.Sum(nil))\n\td.hasher.Reset()\n\treturn\n}\n\nfunc (d *sqlDigester) doDigest(sql string) (result string) {\n\td.normalize(sql)\n\td.hasher.Write(d.buffer.Bytes())\n\td.buffer.Reset()\n\tresult = fmt.Sprintf(\"%x\", d.hasher.Sum(nil))\n\td.hasher.Reset()\n\treturn\n}\n\nfunc (d *sqlDigester) doNormalize(sql string) (result string) {\n\td.normalize(sql)\n\tresult = string(d.buffer.Bytes())\n\td.buffer.Reset()\n\treturn\n}\n\nfunc (d *sqlDigester) doNormalizeDigest(sql string) (normalized, digest string) {\n\td.normalize(sql)\n\tnormalized = string(d.buffer.Bytes())\n\td.hasher.Write(d.buffer.Bytes())\n\td.buffer.Reset()\n\tdigest = fmt.Sprintf(\"%x\", d.hasher.Sum(nil))\n\td.hasher.Reset()\n\treturn\n}\n\nconst (\n\t// genericSymbol presents parameter holder (\"?\") in statement\n\t// it can be any value as long as it is not repeated with other tokens.\n\tgenericSymbol = -1\n\t// genericSymbolList presents parameter holder lists (\"?, ?, ...\") in statement\n\t// it can be any value as long as it is not repeated with other tokens.\n\tgenericSymbolList = -2\n)\n\nfunc (d *sqlDigester) normalize(sql string) {\n\td.lexer.reset(sql)\n\tfor {\n\t\ttok, pos, lit := d.lexer.scan()\n\t\tif tok == invalid {\n\t\t\tbreak\n\t\t}\n\t\tif tok == unicode.ReplacementChar && d.lexer.r.eof() {\n\t\t\tbreak\n\t\t}\n\t\tif pos.Offset == len(sql) {\n\t\t\tbreak\n\t\t}\n\t\tcurrTok := token{tok, strings.ToLower(lit)}\n\n\t\tif d.reduceOptimizerHint(&currTok) {\n\t\t\tcontinue\n\t\t}\n\n\t\td.reduceLit(&currTok)\n\n\t\td.tokens = append(d.tokens, currTok)\n\t}\n\td.lexer.reset(\"\")\n\tfor i, token := range d.tokens {\n\t\td.buffer.WriteString(token.lit)\n\t\tif i != len(d.tokens)-1 {\n\t\t\td.buffer.WriteRune(' ')\n\t\t}\n\t}\n\td.tokens = d.tokens[:0]\n}\n\nfunc (d *sqlDigester) reduceOptimizerHint(tok *token) (reduced bool) {\n\t// ignore /*+..*/\n\tif tok.tok == hintComment {\n\t\treturn\n\t}\n\n\t// ignore force/use/ignore index(x)\n\tif tok.lit == \"index\" {\n\t\ttoks := d.tokens.back(1)\n\t\tif len(toks) > 0 {\n\t\t\tswitch strings.ToLower(toks[0].lit) {\n\t\t\tcase \"force\", \"use\", \"ignore\":\n\t\t\t\tfor {\n\t\t\t\t\ttok, _, lit := d.lexer.scan()\n\t\t\t\t\tif tok == 0 || (tok == unicode.ReplacementChar && d.lexer.r.eof()) {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tif lit == \")\" {\n\t\t\t\t\t\treduced = true\n\t\t\t\t\t\td.tokens.popBack(1)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// ignore straight_join\n\tif tok.lit == \"straight_join\" {\n\t\ttok.lit = \"join\"\n\t\treturn\n\t}\n\treturn\n}\n\nfunc (d *sqlDigester) reduceLit(currTok *token) {\n\tif !d.isLit(*currTok) {\n\t\treturn\n\t}\n\t// count(*) => count(?)\n\tif currTok.lit == \"*\" {\n\t\tif d.isStarParam() {\n\t\t\tcurrTok.tok = genericSymbol\n\t\t\tcurrTok.lit = \"?\"\n\t\t}\n\t\treturn\n\t}\n\n\t// \"-x\" or \"+x\" => \"x\"\n\tif d.isPrefixByUnary(currTok.tok) {\n\t\td.tokens.popBack(1)\n\t}\n\n\t// \"?, ?, ?, ?\" => \"...\"\n\tlast2 := d.tokens.back(2)\n\tif d.isGenericList(last2) {\n\t\td.tokens.popBack(2)\n\t\tcurrTok.tok = genericSymbolList\n\t\tcurrTok.lit = \"...\"\n\t\treturn\n\t}\n\n\t// order by n => order by n\n\tif currTok.tok == intLit {\n\t\tif d.isOrderOrGroupBy() {\n\t\t\treturn\n\t\t}\n\t}\n\n\t// 2 => ?\n\tcurrTok.tok = genericSymbol\n\tcurrTok.lit = \"?\"\n\treturn\n}\n\nfunc (d *sqlDigester) isPrefixByUnary(currTok int) (isUnary bool) {\n\tif !d.isNumLit(currTok) {\n\t\treturn\n\t}\n\tlast := d.tokens.back(1)\n\tif last == nil {\n\t\treturn\n\t}\n\t// a[0] != '-' and a[0] != '+'\n\tif last[0].lit != \"-\" && last[0].lit != \"+\" {\n\t\treturn\n\t}\n\tlast2 := d.tokens.back(2)\n\tif last2 == nil {\n\t\tisUnary = true\n\t\treturn\n\t}\n\t// '(-x' or ',-x' or ',+x' or '--x' or '+-x'\n\tswitch last2[0].lit {\n\tcase \"(\", \",\", \"+\", \"-\", \">=\", \"is\", \"<=\", \"=\", \"<\", \">\":\n\t\tisUnary = true\n\tdefault:\n\t}\n\t// select -x or select +x\n\tlast2Lit := strings.ToLower(last2[0].lit)\n\tif last2Lit == \"select\" {\n\t\tisUnary = true\n\t}\n\treturn\n}\n\nfunc (d *sqlDigester) isGenericList(last2 []token) (generic bool) {\n\tif len(last2) < 2 {\n\t\treturn false\n\t}\n\tif !d.isComma(last2[1]) {\n\t\treturn false\n\t}\n\tswitch last2[0].tok {\n\tcase genericSymbol, genericSymbolList:\n\t\tgeneric = true\n\tdefault:\n\t}\n\treturn\n}\n\nfunc (d *sqlDigester) isOrderOrGroupBy() (orderOrGroupBy bool) {\n\tvar (\n\t\tlast []token\n\t\tn    int\n\t)\n\t// skip number item lists, e.g. \"order by 1, 2, 3\" should NOT convert to \"order by ?, ?, ?\"\n\tfor n = 2; ; n += 2 {\n\t\tlast = d.tokens.back(n)\n\t\tif len(last) < 2 {\n\t\t\treturn false\n\t\t}\n\t\tif !d.isComma(last[1]) {\n\t\t\tbreak\n\t\t}\n\t}\n\t// handle group by number item list surround by \"()\", e.g. \"group by (1, 2)\" should not convert to \"group by (?, ?)\"\n\tif last[1].lit == \"(\" {\n\t\tlast = d.tokens.back(n + 1)\n\t\tif len(last) < 2 {\n\t\t\treturn false\n\t\t}\n\t}\n\torderOrGroupBy = (last[0].lit == \"order\" || last[0].lit == \"group\") && last[1].lit == \"by\"\n\treturn\n}\n\nfunc (d *sqlDigester) isStarParam() (starParam bool) {\n\tlast := d.tokens.back(1)\n\tif last == nil {\n\t\tstarParam = false\n\t\treturn\n\t}\n\tstarParam = last[0].lit == \"(\"\n\treturn\n}\n\nfunc (d *sqlDigester) isLit(t token) (beLit bool) {\n\ttok := t.tok\n\tif d.isNumLit(tok) || tok == stringLit || tok == bitLit {\n\t\tbeLit = true\n\t} else if t.lit == \"*\" {\n\t\tbeLit = true\n\t}\n\treturn\n}\n\nfunc (d *sqlDigester) isNumLit(tok int) (beNum bool) {\n\tswitch tok {\n\tcase intLit, decLit, floatLit, hexLit:\n\t\tbeNum = true\n\tdefault:\n\t}\n\treturn\n}\n\nfunc (d *sqlDigester) isComma(tok token) (isComma bool) {\n\tisComma = tok.lit == \",\"\n\treturn\n}\n\ntype token struct {\n\ttok int\n\tlit string\n}\n\ntype tokenDeque []token\n\nfunc (s *tokenDeque) pushBack(t token) {\n\t*s = append(*s, t)\n}\n\nfunc (s *tokenDeque) popBack(n int) (t []token) {\n\tif len(*s) < n {\n\t\tt = nil\n\t\treturn\n\t}\n\tt = (*s)[len(*s)-n:]\n\t*s = (*s)[:len(*s)-n]\n\treturn\n}\n\nfunc (s *tokenDeque) back(n int) (t []token) {\n\tif len(*s)-n < 0 {\n\t\treturn\n\t}\n\tt = (*s)[len(*s)-n:]\n\treturn\n}\n"
  },
  {
    "path": "pkg/parser/digester_test.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser_test\n\nimport (\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser\"\n)\n\nvar _ = Suite(&testSQLDigestSuite{})\n\ntype testSQLDigestSuite struct {\n}\n\nfunc (s *testSQLDigestSuite) TestNormalize(c *C) {\n\ttests := []struct {\n\t\tinput  string\n\t\texpect string\n\t}{\n\t\t{\"SELECT 1\", \"select ?\"},\n\t\t{\"select * from b where id = 1\", \"select * from b where id = ?\"},\n\t\t{\"select 1 from b where id in (1, 3, '3', 1, 2, 3, 4)\", \"select ? from b where id in ( ... )\"},\n\t\t{\"select 1 from b where id in (1, a, 4)\", \"select ? from b where id in ( ? , a , ? )\"},\n\t\t{\"select 1 from b order by 2\", \"select ? from b order by 2\"},\n\t\t{\"select /*+ a hint */ 1\", \"select ?\"},\n\t\t{\"select /* a hint */ 1\", \"select ?\"},\n\t\t{\"select truncate(1, 2)\", \"select truncate ( ... )\"},\n\t\t{\"select -1 + - 2 + b - c + 0.2 + (-2) from c where d in (1, -2, +3)\", \"select ? + ? + b - c + ? + ( ? ) from c where d in ( ... )\"},\n\t\t{\"select * from t where a <= -1 and b < -2 and c = -3 and c > -4 and c >= -5 and e is 1\", \"select * from t where a <= ? and b < ? and c = ? and c > ? and c >= ? and e is ?\"},\n\t\t{\"select count(a), b from t group by 2\", \"select count ( a ) , b from t group by 2\"},\n\t\t{\"select count(a), b, c from t group by 2, 3\", \"select count ( a ) , b , c from t group by 2 , 3\"},\n\t\t{\"select count(a), b, c from t group by (2, 3)\", \"select count ( a ) , b , c from t group by ( 2 , 3 )\"},\n\t\t{\"select a, b from t order by 1, 2\", \"select a , b from t order by 1 , 2\"},\n\t\t{\"select count(*) from t\", \"select count ( ? ) from t\"},\n\t\t{\"select * from t Force Index(kk)\", \"select * from t\"},\n\t\t{\"select * from t USE Index(kk)\", \"select * from t\"},\n\t\t{\"select * from t Ignore Index(kk)\", \"select * from t\"},\n\t\t{\"select * from t1 straight_join t2 on t1.id=t2.id\", \"select * from t1 join t2 on t1 . id = t2 . id\"},\n\t\t// test syntax error, it will be checked by parser, but it should not make normalize dead loop.\n\t\t{\"select * from t ignore index(\", \"select * from t ignore index\"},\n\t\t{\"select /*+ \", \"select \"},\n\t\t{\"select * from 🥳\", \"select * from\"},\n\t}\n\tfor _, test := range tests {\n\t\tnormalized := parser.Normalize(test.input)\n\t\tdigest := parser.DigestNormalized(normalized)\n\t\tc.Assert(normalized, Equals, test.expect)\n\n\t\tnormalized2, digest2 := parser.NormalizeDigest(test.input)\n\t\tc.Assert(normalized2, Equals, normalized)\n\t\tc.Assert(digest2, Equals, digest, Commentf(\"%+v\", test))\n\t}\n}\n\nfunc (s *testSQLDigestSuite) TestNormalizeDigest(c *C) {\n\ttests := []struct {\n\t\tsql        string\n\t\tnormalized string\n\t\tdigest     string\n\t}{\n\t\t{\"select 1 from b where id in (1, 3, '3', 1, 2, 3, 4)\", \"select ? from b where id in ( ... )\", \"f36161eef94dbfbd5e2f6b9a2f498a4c7facc6860621fbeb8084f63898275016\"},\n\t}\n\tfor _, test := range tests {\n\t\tnormalized, digest := parser.NormalizeDigest(test.sql)\n\t\tc.Assert(normalized, Equals, test.normalized)\n\t\tc.Assert(digest, Equals, test.digest)\n\n\t\tnormalized = parser.Normalize(test.sql)\n\t\tdigest = parser.DigestNormalized(normalized)\n\t\tc.Assert(normalized, Equals, test.normalized)\n\t\tc.Assert(digest, Equals, test.digest)\n\t}\n}\n\nfunc (s *testSQLDigestSuite) TestDigestHashEqForSimpleSQL(c *C) {\n\tsqlGroups := [][]string{\n\t\t{\"select * from b where id = 1\", \"select * from b where id = '1'\", \"select * from b where id =2\"},\n\t\t{\"select 2 from b, c where c.id > 1\", \"select 4 from b, c where c.id > 23\"},\n\t\t{\"Select 3\", \"select 1\"},\n\t}\n\tfor _, sqlGroup := range sqlGroups {\n\t\tvar d string\n\t\tfor _, sql := range sqlGroup {\n\t\t\tdig := parser.DigestHash(sql)\n\t\t\tif d == \"\" {\n\t\t\t\td = dig\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tc.Assert(d, Equals, dig)\n\t\t}\n\t}\n}\n\nfunc (s *testSQLDigestSuite) TestDigestHashNotEqForSimpleSQL(c *C) {\n\tsqlGroups := [][]string{\n\t\t{\"select * from b where id = 1\", \"select a from b where id = 1\", \"select * from d where bid =1\"},\n\t}\n\tfor _, sqlGroup := range sqlGroups {\n\t\tvar d string\n\t\tfor _, sql := range sqlGroup {\n\t\t\tdig := parser.DigestHash(sql)\n\t\t\tif d == \"\" {\n\t\t\t\td = dig\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tc.Assert(d, Not(Equals), dig)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/export_test.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\n// WindowFuncTokenMapForTest exports windowFuncTokenMap in test-case\nvar WindowFuncTokenMapForTest = windowFuncTokenMap\n"
  },
  {
    "path": "pkg/parser/format/format.go",
    "content": "// Copyright (c) 2014 The sortutil Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/STRUTIL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage format\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n)\n\nconst (\n\tst0 = iota\n\tstBOL\n\tstPERC\n\tstBOLPERC\n)\n\n// Formatter is an io.Writer extended formatter by a fmt.Printf like function Format.\ntype Formatter interface {\n\tio.Writer\n\tFormat(format string, args ...interface{}) (n int, errno error)\n}\n\ntype indentFormatter struct {\n\tio.Writer\n\tindent      []byte\n\tindentLevel int\n\tstate       int\n}\n\nvar replace = map[rune]string{\n\t'\\000': \"\\\\0\",\n\t'\\'':   \"''\",\n\t'\\n':   \"\\\\n\",\n\t'\\r':   \"\\\\r\",\n}\n\n// IndentFormatter returns a new Formatter which interprets %i and %u in the\n// Format() formats string as indent and unindent commands. The commands can\n// nest. The Formatter writes to io.Writer 'w' and inserts one 'indent'\n// string per current indent level value.\n// Behaviour of commands reaching negative indent levels is undefined.\n//\n//\tIndentFormatter(os.Stdout, \"\\t\").Format(\"abc%d%%e%i\\nx\\ny\\n%uz\\n\", 3)\n//\n// output:\n//\n//\tabc3%e\n//\t    x\n//\t    y\n//\tz\n//\n// The Go quoted string literal form of the above is:\n//\n//\t\"abc%%e\\n\\tx\\n\\tx\\nz\\n\"\n//\n// The commands can be scattered between separate invocations of Format(),\n// i.e. the formatter keeps track of the indent level and knows if it is\n// positioned on start of a line and should emit indentation(s).\n// The same output as above can be produced by e.g.:\n//\n//\tf := IndentFormatter(os.Stdout, \" \")\n//\tf.Format(\"abc%d%%e%i\\nx\\n\", 3)\n//\tf.Format(\"y\\n%uz\\n\")\nfunc IndentFormatter(w io.Writer, indent string) Formatter {\n\treturn &indentFormatter{w, []byte(indent), 0, stBOL}\n}\n\nfunc (f *indentFormatter) format(flat bool, format string, args ...interface{}) (n int, errno error) {\n\tvar buf = make([]byte, 0)\n\tfor i := 0; i < len(format); i++ {\n\t\tc := format[i]\n\t\tswitch f.state {\n\t\tcase st0:\n\t\t\tswitch c {\n\t\t\tcase '\\n':\n\t\t\t\tcc := c\n\t\t\t\tif flat && f.indentLevel != 0 {\n\t\t\t\t\tcc = ' '\n\t\t\t\t}\n\t\t\t\tbuf = append(buf, cc)\n\t\t\t\tf.state = stBOL\n\t\t\tcase '%':\n\t\t\t\tf.state = stPERC\n\t\t\tdefault:\n\t\t\t\tbuf = append(buf, c)\n\t\t\t}\n\t\tcase stBOL:\n\t\t\tswitch c {\n\t\t\tcase '\\n':\n\t\t\t\tcc := c\n\t\t\t\tif flat && f.indentLevel != 0 {\n\t\t\t\t\tcc = ' '\n\t\t\t\t}\n\t\t\t\tbuf = append(buf, cc)\n\t\t\tcase '%':\n\t\t\t\tf.state = stBOLPERC\n\t\t\tdefault:\n\t\t\t\tif !flat {\n\t\t\t\t\tfor i := 0; i < f.indentLevel; i++ {\n\t\t\t\t\t\tbuf = append(buf, f.indent...)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbuf = append(buf, c)\n\t\t\t\tf.state = st0\n\t\t\t}\n\t\tcase stBOLPERC:\n\t\t\tswitch c {\n\t\t\tcase 'i':\n\t\t\t\tf.indentLevel++\n\t\t\t\tf.state = stBOL\n\t\t\tcase 'u':\n\t\t\t\tf.indentLevel--\n\t\t\t\tf.state = stBOL\n\t\t\tdefault:\n\t\t\t\tif !flat {\n\t\t\t\t\tfor i := 0; i < f.indentLevel; i++ {\n\t\t\t\t\t\tbuf = append(buf, f.indent...)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbuf = append(buf, '%', c)\n\t\t\t\tf.state = st0\n\t\t\t}\n\t\tcase stPERC:\n\t\t\tswitch c {\n\t\t\tcase 'i':\n\t\t\t\tf.indentLevel++\n\t\t\t\tf.state = st0\n\t\t\tcase 'u':\n\t\t\t\tf.indentLevel--\n\t\t\t\tf.state = st0\n\t\t\tdefault:\n\t\t\t\tbuf = append(buf, '%', c)\n\t\t\t\tf.state = st0\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(\"unexpected state\")\n\t\t}\n\t}\n\tswitch f.state {\n\tcase stPERC, stBOLPERC:\n\t\tbuf = append(buf, '%')\n\t}\n\treturn f.Write([]byte(fmt.Sprintf(string(buf), args...)))\n}\n\n// Format implements Format interface.\nfunc (f *indentFormatter) Format(format string, args ...interface{}) (n int, errno error) {\n\treturn f.format(false, format, args...)\n}\n\ntype flatFormatter indentFormatter\n\n// FlatFormatter returns a newly created Formatter with the same functionality as the one returned\n// by IndentFormatter except it allows a newline in the 'format' string argument of Format\n// to pass through if the indent level is current zero.\n//\n// If the indent level is non-zero then such new lines are changed to a space character.\n// There is no indent string, the %i and %u format verbs are used solely to determine the indent level.\n//\n// The FlatFormatter is intended for flattening of normally nested structure textual representation to\n// a one top level structure per line form.\n//\n//\tFlatFormatter(os.Stdout, \" \").Format(\"abc%d%%e%i\\nx\\ny\\n%uz\\n\", 3)\n//\n// output in the form of a Go quoted string literal:\n//\n//\t\"abc3%%e x y z\\n\"\nfunc FlatFormatter(w io.Writer) Formatter {\n\treturn (*flatFormatter)(IndentFormatter(w, \"\").(*indentFormatter))\n}\n\n// Format implements Format interface.\nfunc (f *flatFormatter) Format(format string, args ...interface{}) (n int, errno error) {\n\treturn (*indentFormatter)(f).format(true, format, args...)\n}\n\n// OutputFormat output escape character with backslash.\nfunc OutputFormat(s string) string {\n\tvar buf bytes.Buffer\n\tfor _, old := range s {\n\t\tif newVal, ok := replace[old]; ok {\n\t\t\tbuf.WriteString(newVal)\n\t\t\tcontinue\n\t\t}\n\t\tbuf.WriteRune(old)\n\t}\n\n\treturn buf.String()\n}\n\n// RestoreFlag mark the Restore format\ntype RestoreFlags uint64\n\n// Mutually exclusive group of `RestoreFlags`:\n// [RestoreStringSingleQuotes, RestoreStringDoubleQuotes]\n// [RestoreKeyWordUppercase, RestoreKeyWordLowercase]\n// [RestoreNameUppercase, RestoreNameLowercase]\n// [RestoreNameDoubleQuotes, RestoreNameBackQuotes]\n// The flag with the left position in each group has a higher priority.\nconst (\n\tRestoreStringSingleQuotes RestoreFlags = 1 << iota\n\tRestoreStringDoubleQuotes\n\tRestoreStringEscapeBackslash\n\n\tRestoreKeyWordUppercase\n\tRestoreKeyWordLowercase\n\n\tRestoreNameUppercase\n\tRestoreNameLowercase\n\tRestoreNameDoubleQuotes\n\tRestoreNameBackQuotes\n\n\tRestoreSpacesAroundBinaryOperation\n)\n\nconst (\n\tDefaultRestoreFlags = RestoreStringSingleQuotes | RestoreKeyWordUppercase | RestoreNameBackQuotes\n)\n\nfunc (rf RestoreFlags) has(flag RestoreFlags) bool {\n\treturn rf&flag != 0\n}\n\n// HasStringSingleQuotesFlag returns a boolean indicating when `rf` has `RestoreStringSingleQuotes` flag.\nfunc (rf RestoreFlags) HasStringSingleQuotesFlag() bool {\n\treturn rf.has(RestoreStringSingleQuotes)\n}\n\n// HasStringDoubleQuotesFlag returns a boolean indicating whether `rf` has `RestoreStringDoubleQuotes` flag.\nfunc (rf RestoreFlags) HasStringDoubleQuotesFlag() bool {\n\treturn rf.has(RestoreStringDoubleQuotes)\n}\n\n// HasStringEscapeBackslashFlag returns a boolean indicating whether `rf` has `RestoreStringEscapeBackslash` flag.\nfunc (rf RestoreFlags) HasStringEscapeBackslashFlag() bool {\n\treturn rf.has(RestoreStringEscapeBackslash)\n}\n\n// HasKeyWordUppercaseFlag returns a boolean indicating whether `rf` has `RestoreKeyWordUppercase` flag.\nfunc (rf RestoreFlags) HasKeyWordUppercaseFlag() bool {\n\treturn rf.has(RestoreKeyWordUppercase)\n}\n\n// HasKeyWordLowercaseFlag returns a boolean indicating whether `rf` has `RestoreKeyWordLowercase` flag.\nfunc (rf RestoreFlags) HasKeyWordLowercaseFlag() bool {\n\treturn rf.has(RestoreKeyWordLowercase)\n}\n\n// HasNameUppercaseFlag returns a boolean indicating whether `rf` has `RestoreNameUppercase` flag.\nfunc (rf RestoreFlags) HasNameUppercaseFlag() bool {\n\treturn rf.has(RestoreNameUppercase)\n}\n\n// HasNameLowercaseFlag returns a boolean indicating whether `rf` has `RestoreNameLowercase` flag.\nfunc (rf RestoreFlags) HasNameLowercaseFlag() bool {\n\treturn rf.has(RestoreNameLowercase)\n}\n\n// HasNameDoubleQuotesFlag returns a boolean indicating whether `rf` has `RestoreNameDoubleQuotes` flag.\nfunc (rf RestoreFlags) HasNameDoubleQuotesFlag() bool {\n\treturn rf.has(RestoreNameDoubleQuotes)\n}\n\n// HasNameBackQuotesFlag returns a boolean indicating whether `rf` has `RestoreNameBackQuotes` flag.\nfunc (rf RestoreFlags) HasNameBackQuotesFlag() bool {\n\treturn rf.has(RestoreNameBackQuotes)\n}\n\n// HasSpacesAroundBinaryOperationFlag returns a boolean indicating whether `rf` has `RestoreSpacesAroundBinaryOperation` flag.\nfunc (rf RestoreFlags) HasSpacesAroundBinaryOperationFlag() bool {\n\treturn rf.has(RestoreSpacesAroundBinaryOperation)\n}\n\n// RestoreCtx is `Restore` context to hold flags and writer.\ntype RestoreCtx struct {\n\tFlags     RestoreFlags\n\tIn        io.Writer\n\tJoinLevel int\n\tDialect   Dialect\n}\n\n// NewRestoreCtx returns a new `RestoreCtx`.\nfunc NewRestoreCtx(flags RestoreFlags, in io.Writer) *RestoreCtx {\n\treturn &RestoreCtx{flags, in, 0, &TiDBDialect{}}\n}\n\n// NewRestoreCtx returns a new `RestoreCtx`.\nfunc NewRestoreCtxWithDialect(flags RestoreFlags, in io.Writer, d Dialect) *RestoreCtx {\n\treturn &RestoreCtx{flags, in, 0, d}\n}\n\n// WriteKeyWord writes the `keyWord` into writer.\n// `keyWord` will be converted format(uppercase and lowercase for now) according to `RestoreFlags`.\nfunc (ctx *RestoreCtx) WriteKeyWord(keyWord string) {\n\tswitch {\n\tcase ctx.Flags.HasKeyWordUppercaseFlag():\n\t\tkeyWord = strings.ToUpper(keyWord)\n\tcase ctx.Flags.HasKeyWordLowercaseFlag():\n\t\tkeyWord = strings.ToLower(keyWord)\n\t}\n\tfmt.Fprint(ctx.In, keyWord)\n}\n\n// WriteString writes the string into writer\n// `str` may be wrapped in quotes and escaped according to RestoreFlags.\nfunc (ctx *RestoreCtx) WriteString(str string) {\n\tif ctx.Flags.HasStringEscapeBackslashFlag() {\n\t\tstr = strings.Replace(str, `\\`, `\\\\`, -1)\n\t}\n\tquotes := \"\"\n\tswitch {\n\tcase ctx.Flags.HasStringSingleQuotesFlag():\n\t\tstr = strings.Replace(str, `'`, `''`, -1)\n\t\tquotes = `'`\n\tcase ctx.Flags.HasStringDoubleQuotesFlag():\n\t\tstr = strings.Replace(str, `\"`, `\"\"`, -1)\n\t\tquotes = `\"`\n\t}\n\tfmt.Fprint(ctx.In, quotes, str, quotes)\n}\n\n// WriteName writes the name into writer\n// `name` maybe wrapped in quotes and escaped according to RestoreFlags.\nfunc (ctx *RestoreCtx) WriteName(name string) {\n\tswitch {\n\tcase ctx.Flags.HasNameUppercaseFlag():\n\t\tname = strings.ToUpper(name)\n\tcase ctx.Flags.HasNameLowercaseFlag():\n\t\tname = strings.ToLower(name)\n\t}\n\tquotes := \"\"\n\tswitch {\n\tcase ctx.Flags.HasNameDoubleQuotesFlag():\n\t\tname = strings.Replace(name, `\"`, `\"\"`, -1)\n\t\tquotes = `\"`\n\tcase ctx.Flags.HasNameBackQuotesFlag():\n\t\tname = strings.Replace(name, \"`\", \"``\", -1)\n\t\tquotes = \"`\"\n\t}\n\tfmt.Fprint(ctx.In, quotes, name, quotes)\n}\n\n// WritePlain writes the plain text into writer without any handling.\nfunc (ctx *RestoreCtx) WritePlain(plainText string) {\n\tfmt.Fprint(ctx.In, plainText)\n}\n\n// WritePlainf write the plain text into writer without any handling.\nfunc (ctx *RestoreCtx) WritePlainf(format string, a ...interface{}) {\n\tfmt.Fprintf(ctx.In, format, a...)\n}\n"
  },
  {
    "path": "pkg/parser/format/format_dialect.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage format\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n)\n\nconst maxCSVDecimalWidth = 38\n\nvar (\n\t_ Dialect = &MySQLDialect{}\n\t_ Dialect = &TiDBDialect{}\n\t_ Dialect = &PostgresDialect{}\n\t_ Dialect = &CVSDBDialect{}\n\t_ Dialect = &OdpsDialect{}\n)\n\ntype Dialect interface {\n\tConvertCastTypeToString(asType byte, flen int, decimal int, flag uint) (keyword string, plainWord string, err error)\n\tSkipSchemaInColName() bool\n\t// special means functions which have different function names in different backends\n\t// If the function has been renamed inside the function, return the renamed name; otherwise,\n\t// return the original name. If you are sure that the function name is the same in all backends,\n\t// please use the original name directly; otherwise, please call this function.\n\t// Of course, you can also override the differences in function names of different backend databases within this function.\n\tGetSpecialFuncName(string) string\n\tGetOperator(string) string\n\t// need parentheses or not for continuous comparison operator\n\t// such as: a = b = c\n\t// for mysql a = b = c\n\t// for pg (a = b) = c\n\tNeedParenthesesForCmpOperand() bool\n\t// for cross join, whether to show the CROSS keyword obviously\n\tObviousCrossWhenCrossJoin() bool\n}\n\nfunc NewMySQLDialect() Dialect {\n\treturn &MySQLDialect{}\n}\n\ntype MySQLDialect struct {\n}\n\nfunc (d *MySQLDialect) SkipSchemaInColName() bool {\n\treturn true\n}\n\nfunc (d *MySQLDialect) ConvertCastTypeToString(asType byte, flen int, decimal int, flag uint) (keyword string, plainWord string, err error) {\n\tunspecifiedLength := -1\n\tswitch asType {\n\tcase mysql.TypeVarString, mysql.TypeVarchar:\n\t\tkeyword = \"CHAR\"\n\t\tif flen != unspecifiedLength {\n\t\t\tplainWord = fmt.Sprintf(\"(%d)\", flen)\n\t\t}\n\tcase mysql.TypeDate:\n\t\tkeyword = \"DATE\"\n\tcase mysql.TypeDatetime:\n\t\tkeyword = \"DATETIME\"\n\t\tif decimal > 0 {\n\t\t\tplainWord = fmt.Sprintf(\"(%d)\", decimal)\n\t\t}\n\tcase mysql.TypeNewDecimal:\n\t\tkeyword = \"DECIMAL\"\n\t\tif flen > 0 && decimal > 0 {\n\t\t\tplainWord = fmt.Sprintf(\"(%d, %d)\", flen, decimal)\n\t\t} else if flen > 0 {\n\t\t\tplainWord = fmt.Sprintf(\"(%d)\", flen)\n\n\t\t}\n\tcase mysql.TypeDuration:\n\t\tkeyword = \"TIME\"\n\t\tif decimal > 0 {\n\t\t\tplainWord = fmt.Sprintf(\"(%d)\", decimal)\n\t\t}\n\tcase mysql.TypeLonglong:\n\t\tif flag&mysql.UnsignedFlag != 0 {\n\t\t\tkeyword = \"UNSIGNED\"\n\t\t} else {\n\t\t\tkeyword = \"SIGNED\"\n\t\t}\n\tcase mysql.TypeJSON:\n\t\tkeyword = \"JSON\"\n\tcase mysql.TypeDouble:\n\t\tkeyword = \"DECIMAL\"\n\t\tplainWord = \"(64,30)\"\n\tcase mysql.TypeFloat:\n\t\tkeyword = \"DECIMAL\"\n\t\tplainWord = \"(64,30)\"\n\tdefault:\n\t\terr = fmt.Errorf(\"unsupported cast as data type: %+v\", asType)\n\t}\n\treturn\n}\n\nfunc (d *MySQLDialect) GetSpecialFuncName(originName string) string {\n\treturn originName\n}\n\nfunc (d *MySQLDialect) GetOperator(op string) string {\n\treturn op\n}\n\nfunc (d *MySQLDialect) NeedParenthesesForCmpOperand() bool {\n\treturn false\n}\n\nfunc (d *MySQLDialect) ObviousCrossWhenCrossJoin() bool {\n\treturn false\n}\n\ntype TiDBDialect struct {\n\tMySQLDialect\n}\n\nfunc NewTiDBDialect() Dialect {\n\treturn &TiDBDialect{}\n}\n\nfunc (d *TiDBDialect) GetCastFieldType(dtype string) string {\n\treturn dtype\n}\n\nfunc (d *TiDBDialect) SkipSchemaInColName() bool {\n\treturn false\n}\n\nfunc (d *TiDBDialect) ConvertCastTypeToString(asType byte, flen int, decimal int, flag uint) (keyword string, plainWord string, err error) {\n\tunspecifiedLength := -1\n\tswitch asType {\n\tcase mysql.TypeVarString, mysql.TypeVarchar:\n\t\tkeyword = \"CHAR\"\n\t\tif flen != unspecifiedLength {\n\t\t\tplainWord = fmt.Sprintf(\"(%d)\", flen)\n\t\t}\n\tcase mysql.TypeDate:\n\t\tkeyword = \"DATE\"\n\tcase mysql.TypeDatetime:\n\t\tkeyword = \"DATETIME\"\n\t\tif decimal > 0 {\n\t\t\tplainWord = fmt.Sprintf(\"(%d)\", decimal)\n\t\t}\n\tcase mysql.TypeNewDecimal:\n\t\tkeyword = \"DECIMAL\"\n\t\tif flen > 0 && decimal > 0 {\n\t\t\tplainWord = fmt.Sprintf(\"(%d, %d)\", flen, decimal)\n\t\t} else if flen > 0 {\n\t\t\tplainWord = fmt.Sprintf(\"(%d)\", flen)\n\n\t\t}\n\tcase mysql.TypeDuration:\n\t\tkeyword = \"TIME\"\n\t\tif decimal > 0 {\n\t\t\tplainWord = fmt.Sprintf(\"(%d)\", decimal)\n\t\t}\n\tcase mysql.TypeLonglong:\n\t\tif flag&mysql.UnsignedFlag != 0 {\n\t\t\tkeyword = \"UNSIGNED\"\n\t\t} else {\n\t\t\tkeyword = \"SIGNED\"\n\t\t}\n\tcase mysql.TypeJSON:\n\t\tkeyword = \"JSON\"\n\tcase mysql.TypeDouble:\n\t\tkeyword = \"DOUBLE\"\n\tcase mysql.TypeFloat:\n\t\tkeyword = \"FLOAT\"\n\tdefault:\n\t\terr = fmt.Errorf(\"unsupported cast as data type: %+v\", asType)\n\t}\n\treturn\n}\n\ntype PostgresDialect struct {\n\tMySQLDialect\n\tfuncNameMap map[string]string\n}\n\nfunc NewPostgresDialect() Dialect {\n\treturn &PostgresDialect{\n\t\tfuncNameMap: map[string]string{\n\t\t\t// don't use package ast here, may cause circle dependency\n\t\t\t\"ifnull\":   \"coalesce\",\n\t\t\t\"truncate\": \"trunc\",\n\t\t\t\"curdate\":  \"current_date\",\n\t\t\t\"adddate\":  \"+\",\n\t\t\t\"date_add\": \"+\",\n\t\t\t\"subdate\":  \"-\",\n\t\t\t\"date_sub\": \"-\",\n\t\t\t\"datediff\": \"-\",\n\t\t\t\"intdiv\":   \"div\",\n\t\t},\n\t}\n}\n\nfunc (d *PostgresDialect) ConvertCastTypeToString(asType byte, flen int, decimal int, flag uint) (keyword string, plainWord string, err error) {\n\tswitch asType {\n\tcase mysql.TypeNewDecimal:\n\t\tkeyword = \"NUMERIC\"\n\t\tif flen > 0 && decimal > 0 {\n\t\t\tplainWord = fmt.Sprintf(\"(%d, %d)\", flen, decimal)\n\t\t} else if flen > 0 {\n\t\t\tplainWord = fmt.Sprintf(\"(%d)\", flen)\n\n\t\t}\n\tcase mysql.TypeDouble, mysql.TypeFloat:\n\t\tkeyword = \"DOUBLE PRECISION\"\n\tcase mysql.TypeLong, mysql.TypeLonglong, mysql.TypeInt24, mysql.TypeShort:\n\t\tif flag&mysql.UnsignedFlag != 0 {\n\t\t\terr = fmt.Errorf(\"unsupported cast as data type %+v\", asType)\n\t\t\treturn\n\t\t} else {\n\t\t\tkeyword = \"INTEGER\"\n\t\t}\n\tcase mysql.TypeVarString, mysql.TypeVarchar:\n\t\tkeyword = \"VARCHAR\"\n\tcase mysql.TypeDate:\n\t\tkeyword = \"DATE\"\n\tcase mysql.TypeDatetime:\n\t\tkeyword = \"TIMESTAMP\"\n\tcase mysql.TypeDuration:\n\t\tkeyword = \"INTERVAL\"\n\tcase mysql.TypeTiny:\n\t\tkeyword = \"BOOLEAN\"\n\tdefault:\n\t\terr = fmt.Errorf(\"unsupported cast as data type: %+v\", asType)\n\t}\n\treturn\n}\n\nfunc (d *PostgresDialect) SkipSchemaInColName() bool {\n\treturn true\n}\n\nfunc (d *PostgresDialect) GetSpecialFuncName(originName string) string {\n\tif res, ok := d.funcNameMap[originName]; ok {\n\t\treturn res\n\t}\n\treturn originName\n}\n\nfunc (d *PostgresDialect) NeedParenthesesForCmpOperand() bool {\n\treturn true\n}\n\ntype CVSDBDialect struct {\n\tPostgresDialect\n\tfuncNameMap map[string]string\n\toperatorMap map[string]string\n}\n\nfunc NewCVSDBDialect() Dialect {\n\treturn &CVSDBDialect{\n\t\tfuncNameMap: map[string]string{\n\t\t\t// don't use package ast here, may cause circle dependency\n\t\t\t\"ifnull\":   \"coalesce\",\n\t\t\t\"truncate\": \"trunc\",\n\t\t\t\"now\":      \"now\",\n\t\t\t\"curdate\":  \"current_date\",\n\t\t\t\"adddate\":  \"+\",\n\t\t\t\"date_add\": \"+\",\n\t\t\t\"subdate\":  \"-\",\n\t\t\t\"date_sub\": \"-\",\n\t\t\t\"datediff\": \"-\",\n\t\t},\n\t\toperatorMap: map[string]string{\n\t\t\t// ref to https://duckdb.org/docs/archive/0.9/sql/functions/numeric\n\t\t\t\" DIV \": \" // \",\n\t\t},\n\t}\n}\n\nfunc (d *CVSDBDialect) ConvertCastTypeToString(asType byte, flen int, decimal int, flag uint) (keyword string, plainWord string, err error) {\n\tswitch asType {\n\tcase mysql.TypeNewDecimal:\n\t\tkeyword = \"NUMERIC\"\n\t\t// ref: https://github.com/duckdb/duckdb/blob/v0.9.2/src/parser/transform/helpers/transform_typename.cpp#L167\n\t\tif flen <= maxCSVDecimalWidth {\n\t\t\tif flen > 0 && decimal > 0 {\n\t\t\t\tplainWord = fmt.Sprintf(\"(%d, %d)\", flen, decimal)\n\t\t\t} else if flen > 0 {\n\t\t\t\tplainWord = fmt.Sprintf(\"(%d)\", flen)\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn d.PostgresDialect.ConvertCastTypeToString(asType, flen, decimal, flag)\n\t}\n\treturn\n}\n\nfunc (d *CVSDBDialect) SkipSchemaInColName() bool {\n\treturn true\n}\n\nfunc (d *CVSDBDialect) GetSpecialFuncName(originName string) string {\n\tif res, ok := d.funcNameMap[originName]; ok {\n\t\treturn res\n\t}\n\treturn originName\n}\n\nfunc (d *CVSDBDialect) GetOperator(originName string) string {\n\tif res, ok := d.operatorMap[originName]; ok {\n\t\treturn res\n\t}\n\treturn originName\n}\n\n// duckdb need cross keyword for cross join\nfunc (d *CVSDBDialect) ObviousCrossWhenCrossJoin() bool {\n\treturn true\n}\n\ntype OdpsDialect struct {\n\tMySQLDialect\n\tfuncNameMap map[string]string\n}\n\nfunc NewOdpsDialect() Dialect {\n\treturn &OdpsDialect{\n\t\tfuncNameMap: map[string]string{\n\t\t\t\"truncate\": \"trunc\",\n\t\t\t\"ifnull\":   \"nvl\",\n\t\t},\n\t}\n}\n\nfunc (d *OdpsDialect) SkipSchemaInColName() bool {\n\treturn true\n}\n\nfunc (d *OdpsDialect) GetSpecialFuncName(originName string) string {\n\tif res, ok := d.funcNameMap[originName]; ok {\n\t\treturn res\n\t}\n\treturn originName\n}\n\nfunc (d *OdpsDialect) ConvertCastTypeToString(asType byte, flen int, decimal int, flag uint) (keyword string, plainWord string, err error) {\n\tswitch asType {\n\tcase mysql.TypeVarString, mysql.TypeVarchar:\n\t\tkeyword = \"STRING\"\n\tcase mysql.TypeNewDecimal:\n\t\t// odps don't support decimal, so we use double replace decimal(xx,xx)\n\t\tkeyword = \"BIGINT\"\n\t\tif flen > 0 && decimal > 0 {\n\t\t\tkeyword = \"DECIMAL\"\n\t\t}\n\tcase mysql.TypeLonglong:\n\t\tif flag&mysql.UnsignedFlag != 0 {\n\t\t\terr = fmt.Errorf(\"unsupported cast as data type %+v\", asType)\n\t\t\treturn\n\t\t} else {\n\t\t\tkeyword = \"BIGINT\"\n\t\t}\n\tcase mysql.TypeFloat:\n\t\tkeyword = \"DOUBLE\"\n\tcase mysql.TypeDouble:\n\t\tkeyword = \"DOUBLE\"\n\tdefault:\n\t\treturn d.MySQLDialect.ConvertCastTypeToString(asType, flen, decimal, flag)\n\t}\n\treturn\n}\n\nfunc (d *OdpsDialect) NeedParenthesesForCmpOperand() bool {\n\treturn true\n}\n"
  },
  {
    "path": "pkg/parser/format/format_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage format\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n)\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nvar _ = Suite(&testFormatSuite{})\nvar _ = Suite(&testRestoreCtxSuite{})\n\ntype testFormatSuite struct {\n}\n\nfunc checkFormat(c *C, f Formatter, buf *bytes.Buffer, str, expect string) {\n\t_, err := f.Format(str, 3)\n\tc.Assert(err, IsNil)\n\tb, err := io.ReadAll(buf)\n\tc.Assert(err, IsNil)\n\tc.Assert(string(b), Equals, expect)\n}\n\nfunc (s *testFormatSuite) TestFormat(c *C) {\n\tstr := \"abc%d%%e%i\\nx\\ny\\n%uz\\n\"\n\tbuf := &bytes.Buffer{}\n\tf := IndentFormatter(buf, \"\\t\")\n\texpect := `abc3%e\n\tx\n\ty\nz\n`\n\tcheckFormat(c, f, buf, str, expect)\n\n\tstr = \"abc%d%%e%i\\nx\\ny\\n%uz\\n%i\\n\"\n\tbuf = &bytes.Buffer{}\n\tf = FlatFormatter(buf)\n\texpect = \"abc3%e x y z\\n \"\n\tcheckFormat(c, f, buf, str, expect)\n}\n\ntype testRestoreCtxSuite struct {\n}\n\nfunc (s *testRestoreCtxSuite) TestRestoreCtx(c *C) {\n\ttestCases := []struct {\n\t\tflag   RestoreFlags\n\t\texpect string\n\t}{\n\t\t{0, \"key`.'\\\"Word\\\\ str`.'\\\"ing\\\\ na`.'\\\"Me\\\\\"},\n\t\t{RestoreStringSingleQuotes, \"key`.'\\\"Word\\\\ 'str`.''\\\"ing\\\\' na`.'\\\"Me\\\\\"},\n\t\t{RestoreStringDoubleQuotes, \"key`.'\\\"Word\\\\ \\\"str`.'\\\"\\\"ing\\\\\\\" na`.'\\\"Me\\\\\"},\n\t\t{RestoreStringEscapeBackslash, \"key`.'\\\"Word\\\\ str`.'\\\"ing\\\\\\\\ na`.'\\\"Me\\\\\"},\n\t\t{RestoreKeyWordUppercase, \"KEY`.'\\\"WORD\\\\ str`.'\\\"ing\\\\ na`.'\\\"Me\\\\\"},\n\t\t{RestoreKeyWordLowercase, \"key`.'\\\"word\\\\ str`.'\\\"ing\\\\ na`.'\\\"Me\\\\\"},\n\t\t{RestoreNameUppercase, \"key`.'\\\"Word\\\\ str`.'\\\"ing\\\\ NA`.'\\\"ME\\\\\"},\n\t\t{RestoreNameLowercase, \"key`.'\\\"Word\\\\ str`.'\\\"ing\\\\ na`.'\\\"me\\\\\"},\n\t\t{RestoreNameDoubleQuotes, \"key`.'\\\"Word\\\\ str`.'\\\"ing\\\\ \\\"na`.'\\\"\\\"Me\\\\\\\"\"},\n\t\t{RestoreNameBackQuotes, \"key`.'\\\"Word\\\\ str`.'\\\"ing\\\\ `na``.'\\\"Me\\\\`\"},\n\t\t{DefaultRestoreFlags, \"KEY`.'\\\"WORD\\\\ 'str`.''\\\"ing\\\\' `na``.'\\\"Me\\\\`\"},\n\t\t{RestoreStringSingleQuotes | RestoreStringDoubleQuotes, \"key`.'\\\"Word\\\\ 'str`.''\\\"ing\\\\' na`.'\\\"Me\\\\\"},\n\t\t{RestoreKeyWordUppercase | RestoreKeyWordLowercase, \"KEY`.'\\\"WORD\\\\ str`.'\\\"ing\\\\ na`.'\\\"Me\\\\\"},\n\t\t{RestoreNameUppercase | RestoreNameLowercase, \"key`.'\\\"Word\\\\ str`.'\\\"ing\\\\ NA`.'\\\"ME\\\\\"},\n\t\t{RestoreNameDoubleQuotes | RestoreNameBackQuotes, \"key`.'\\\"Word\\\\ str`.'\\\"ing\\\\ \\\"na`.'\\\"\\\"Me\\\\\\\"\"},\n\t}\n\tvar sb strings.Builder\n\tfor _, testCase := range testCases {\n\t\tsb.Reset()\n\t\tctx := NewRestoreCtx(testCase.flag, &sb)\n\t\tctx.WriteKeyWord(\"key`.'\\\"Word\\\\\")\n\t\tctx.WritePlain(\" \")\n\t\tctx.WriteString(\"str`.'\\\"ing\\\\\")\n\t\tctx.WritePlain(\" \")\n\t\tctx.WriteName(\"na`.'\\\"Me\\\\\")\n\t\tc.Assert(sb.String(), Equals, testCase.expect, Commentf(\"case: %#v\", testCase))\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/goyacc/format_yacc.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\tgofmt \"go/format\"\n\t\"go/token\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/cznic/strutil\"\n\t\"github.com/pingcap/errors\"\n\tparser \"modernc.org/parser/yacc\"\n\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n)\n\nfunc Format(inputFilename string, goldenFilename string) (err error) {\n\tspec, err := parseFileToSpec(inputFilename)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tyFmt := &OutputFormatter{}\n\tif err = yFmt.Setup(goldenFilename); err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tteardownErr := yFmt.Teardown()\n\t\tif err == nil {\n\t\t\terr = teardownErr\n\t\t}\n\t}()\n\n\tif err = printDefinitions(yFmt, spec.Defs); err != nil {\n\t\treturn err\n\t}\n\n\treturn printRules(yFmt, spec.Rules)\n}\n\nfunc parseFileToSpec(inputFilename string) (*parser.Specification, error) {\n\tsrc, err := os.ReadFile(inputFilename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn parser.Parse(token.NewFileSet(), inputFilename, src)\n}\n\n// Definition represents data reduced by productions:\n//\n//\tDefinition:\n//\t        START IDENTIFIER\n//\t|       UNION                      // Case 1\n//\t|       LCURL RCURL                // Case 2\n//\t|       ReservedWord Tag NameList  // Case 3\n//\t|       ReservedWord Tag           // Case 4\n//\t|       ERROR_VERBOSE              // Case 5\nconst (\n\tStartIdentifierCase = iota\n\tUnionDefinitionCase\n\tLCURLRCURLCase\n\tReservedWordTagNameListCase\n\tReservedWordTagCase\n)\n\nfunc printDefinitions(formatter format.Formatter, definitions []*parser.Definition) error {\n\tfor _, def := range definitions {\n\t\tvar err error\n\t\tswitch def.Case {\n\t\tcase StartIdentifierCase:\n\t\t\terr = handleStart(formatter, def)\n\t\tcase UnionDefinitionCase:\n\t\t\terr = handleUnion(formatter, def)\n\t\tcase LCURLRCURLCase:\n\t\t\terr = handleProlog(formatter, def)\n\t\tcase ReservedWordTagNameListCase, ReservedWordTagCase:\n\t\t\terr = handleReservedWordTagNameList(formatter, def)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t_, err := formatter.Format(\"\\n%%%%\")\n\treturn err\n}\n\nfunc handleStart(f format.Formatter, definition *parser.Definition) error {\n\tif err := Ensure(definition).\n\t\tand(definition.Token2).\n\t\tand(definition.Token2).NotNil(); err != nil {\n\t\treturn err\n\t}\n\tcmt1 := strings.Join(definition.Token.Comments, \"\\n\")\n\tcmt2 := strings.Join(definition.Token2.Comments, \"\\n\")\n\t_, err := f.Format(\"\\n%s%s\\t%s%s\\n\", cmt1, definition.Token.Val, cmt2, definition.Token2.Val)\n\treturn err\n}\n\nfunc handleUnion(f format.Formatter, definition *parser.Definition) error {\n\tif err := Ensure(definition).\n\t\tand(definition.Value).NotNil(); err != nil {\n\t\treturn err\n\t}\n\tif len(definition.Value) != 0 {\n\t\t_, err := f.Format(\"%%union%i%s%u\\n\\n\", definition.Value)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc handleProlog(f format.Formatter, definition *parser.Definition) error {\n\tif err := Ensure(definition).\n\t\tand(definition.Value).NotNil(); err != nil {\n\t\treturn err\n\t}\n\t_, err := f.Format(\"%%{%s%%}\\n\\n\", definition.Value)\n\treturn err\n}\n\nfunc handleReservedWordTagNameList(f format.Formatter, def *parser.Definition) error {\n\tif err := Ensure(def).\n\t\tand(def.ReservedWord).\n\t\tand(def.ReservedWord.Token).NotNil(); err != nil {\n\t\treturn err\n\t}\n\tcomment := getTokenComment(def.ReservedWord.Token, divNewLineStringLayout)\n\tdirective := def.ReservedWord.Token.Val\n\n\thasTag := def.Tag != nil\n\tvar wordAfterDirective string\n\tif hasTag {\n\t\twordAfterDirective = joinTag(def.Tag)\n\t} else {\n\t\twordAfterDirective = joinNames(def.Nlist)\n\t}\n\n\tif _, err := f.Format(\"%s%s%s%i\", comment, directive, wordAfterDirective); err != nil {\n\t\treturn err\n\t}\n\tif hasTag {\n\t\tif _, err := f.Format(\"\\n\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := printNameListVertical(f, def.Nlist); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t_, err := f.Format(\"%u\\n\")\n\treturn err\n}\n\nfunc joinTag(tag *parser.Tag) string {\n\tvar sb strings.Builder\n\tsb.WriteString(\"\\t\")\n\tif tag.Token != nil {\n\t\tsb.WriteString(tag.Token.Val)\n\t}\n\tif tag.Token2 != nil {\n\t\tsb.WriteString(tag.Token2.Val)\n\t}\n\tif tag.Token3 != nil {\n\t\tsb.WriteString(tag.Token3.Val)\n\t}\n\treturn sb.String()\n}\n\ntype stringLayout int8\n\nconst (\n\tspanStringLayout stringLayout = iota\n\tdivStringLayout\n\tdivNewLineStringLayout\n)\n\nfunc getTokenComment(token *parser.Token, layout stringLayout) string {\n\tif len(token.Comments) == 0 {\n\t\treturn \"\"\n\t}\n\tvar splitter, beforeComment string\n\tswitch layout {\n\tcase spanStringLayout:\n\t\tsplitter, beforeComment = \" \", \"\"\n\tcase divStringLayout:\n\t\tsplitter, beforeComment = \"\\n\", \"\"\n\tcase divNewLineStringLayout:\n\t\tsplitter, beforeComment = \"\\n\", \"\\n\"\n\tdefault:\n\t\tpanic(errors.Errorf(\"unsupported stringLayout: %v\", layout))\n\t}\n\n\tvar sb strings.Builder\n\tsb.WriteString(beforeComment)\n\tfor _, comment := range token.Comments {\n\t\tsb.WriteString(comment)\n\t\tsb.WriteString(splitter)\n\t}\n\treturn sb.String()\n}\n\nfunc printNameListVertical(f format.Formatter, names NameArr) (err error) {\n\trest := names\n\tfor len(rest) != 0 {\n\t\tvar processing NameArr\n\t\tprocessing, rest = rest[:1], rest[1:]\n\n\t\tvar noComments NameArr\n\t\tnoComments, rest = rest.span(noComment)\n\t\tprocessing = append(processing, noComments...)\n\n\t\tmaxCharLength := processing.findMaxLength()\n\t\tfor _, name := range processing {\n\t\t\tif err := printSingleName(f, name, maxCharLength); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc joinNames(names NameArr) string {\n\tvar sb strings.Builder\n\tfor _, name := range names {\n\t\tsb.WriteString(\" \")\n\t\tsb.WriteString(getTokenComment(name.Token, spanStringLayout))\n\t\tsb.WriteString(name.Token.Val)\n\t}\n\treturn sb.String()\n}\n\nfunc printSingleName(f format.Formatter, name *parser.Name, maxCharLength int) error {\n\tcmt := getTokenComment(name.Token, divNewLineStringLayout)\n\tif _, err := f.Format(escapePercent(cmt)); err != nil {\n\t\treturn err\n\t}\n\tstrLit := name.LiteralStringOpt\n\tif strLit != nil && strLit.Token != nil {\n\t\t_, err := f.Format(\"%-*s %s\\n\", maxCharLength, name.Token.Val, strLit.Token.Val)\n\t\treturn err\n\t}\n\t_, err := f.Format(\"%s\\n\", name.Token.Val)\n\treturn err\n}\n\ntype NameArr []*parser.Name\n\nfunc (ns NameArr) span(pred func(*parser.Name) bool) (first NameArr, second NameArr) {\n\tfirst = ns.takeWhile(pred)\n\tsecond = ns[len(first):]\n\treturn first, second\n}\n\nfunc (ns NameArr) takeWhile(pred func(*parser.Name) bool) NameArr {\n\tfor i, def := range ns {\n\t\tif pred(def) {\n\t\t\tcontinue\n\t\t}\n\t\treturn ns[:i]\n\t}\n\treturn ns\n}\n\nfunc (ns NameArr) findMaxLength() int {\n\tmaxLen := -1\n\tfor _, s := range ns {\n\t\tif len(s.Token.Val) > maxLen {\n\t\t\tmaxLen = len(s.Token.Val)\n\t\t}\n\t}\n\treturn maxLen\n}\n\nfunc hasComments(n *parser.Name) bool {\n\treturn len(n.Token.Comments) != 0\n}\n\nfunc noComment(n *parser.Name) bool {\n\treturn !hasComments(n)\n}\n\nfunc containsActionInRule(rule *parser.Rule) bool {\n\tfor _, b := range rule.Body {\n\t\tif _, ok := b.(*parser.Action); ok {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\ntype RuleArr []*parser.Rule\n\nfunc printRules(f format.Formatter, rules RuleArr) (err error) {\n\tvar lastRuleName string\n\tfor _, rule := range rules {\n\t\tif rule.Name.Val == lastRuleName {\n\t\t\tcmt := getTokenComment(rule.Token, divStringLayout)\n\t\t\t_, err = f.Format(\"\\n%s|\\t%i\", cmt)\n\t\t} else {\n\t\t\tcmt := getTokenComment(rule.Name, divStringLayout)\n\t\t\t_, err = f.Format(\"\\n\\n%s%s:%i\\n\", cmt, rule.Name.Val)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tlastRuleName = rule.Name.Val\n\n\t\tif err = printRuleBody(f, rule); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, err = f.Format(\"%u\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t_, err = f.Format(\"\\n%%%%\\n\")\n\treturn err\n}\n\ntype ruleItemType int8\n\nconst (\n\tidentRuleItemType      ruleItemType = 1\n\tactionRuleItemType     ruleItemType = 2\n\tstrLiteralRuleItemType ruleItemType = 3\n)\n\nfunc printRuleBody(f format.Formatter, rule *parser.Rule) error {\n\tfirstRuleItem, counter := rule.RuleItemList, 0\n\tfor ri := rule.RuleItemList; ri != nil; ri = ri.RuleItemList {\n\t\tswitch ruleItemType(ri.Case) {\n\t\tcase identRuleItemType, strLiteralRuleItemType:\n\t\t\tterm := fmt.Sprintf(\" %s\", ri.Token.Val)\n\t\t\tif ri == firstRuleItem {\n\t\t\t\tterm = term[1:]\n\t\t\t}\n\t\t\tcmt := getTokenComment(ri.Token, divStringLayout)\n\n\t\t\tif _, err := f.Format(escapePercent(cmt)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif _, err := f.Format(\"%s\", term); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase actionRuleItemType:\n\t\t\tisFirstRuleItem := ri == firstRuleItem\n\t\t\tif err := handlePrecedence(f, rule.Precedence, isFirstRuleItem); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := handleAction(f, rule, ri.Action, isFirstRuleItem); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tcounter++\n\t}\n\tif err := checkInconsistencyInYaccParser(f, rule, counter); err != nil {\n\t\treturn err\n\t}\n\tif !containsActionInRule(rule) {\n\t\tif err := handlePrecedence(f, rule.Precedence, counter == 0); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc handleAction(f format.Formatter, rule *parser.Rule, action *parser.Action, isFirstItem bool) error {\n\tif !isFirstItem || rule.Precedence != nil {\n\t\tif _, err := f.Format(\"\\n\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tcmt := getTokenComment(action.Token, divStringLayout)\n\tif _, err := f.Format(escapePercent(cmt)); err != nil {\n\t\treturn err\n\t}\n\n\tgoSnippet, err := formatGoSnippet(action.Values)\n\tgoSnippet = escapePercent(goSnippet)\n\tif err != nil {\n\t\treturn err\n\t}\n\tsnippet := \"{}\"\n\tif len(goSnippet) != 0 {\n\t\tsnippet = fmt.Sprintf(\"{%%i\\n%s%%u\\n}\", goSnippet)\n\t}\n\t_, err = f.Format(snippet)\n\treturn err\n}\n\nfunc handlePrecedence(f format.Formatter, p *parser.Precedence, isFirstItem bool) error {\n\tif p == nil {\n\t\treturn nil\n\t}\n\tif err := Ensure(p.Token).\n\t\tand(p.Token2).NotNil(); err != nil {\n\t\treturn err\n\t}\n\tcmt := getTokenComment(p.Token, spanStringLayout)\n\tif !isFirstItem {\n\t\tif _, err := f.Format(\" \"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t_, err := f.Format(\"%s%s %s\", cmt, p.Token.Val, p.Token2.Val)\n\treturn err\n}\n\nfunc formatGoSnippet(actVal []*parser.ActionValue) (string, error) {\n\ttran := &SpecialActionValTransformer{\n\t\tstore: map[string]string{},\n\t}\n\tgoSnippet := collectGoSnippet(tran, actVal)\n\tformatted, err := gofmt.Source([]byte(goSnippet))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tformattedSnippet := tran.restore(string(formatted))\n\treturn strings.TrimSpace(formattedSnippet), nil\n}\n\nfunc collectGoSnippet(tran *SpecialActionValTransformer, actionValArr []*parser.ActionValue) string {\n\tvar sb strings.Builder\n\tfor _, value := range actionValArr {\n\t\ttrimTab := removeLineBeginBlanks(value.Src)\n\t\tsb.WriteString(tran.transform(trimTab))\n\t}\n\tsnipWithPar := strings.TrimSpace(sb.String())\n\tif strings.HasPrefix(snipWithPar, \"{\") && strings.HasSuffix(snipWithPar, \"}\") {\n\t\treturn snipWithPar[1 : len(snipWithPar)-1]\n\t}\n\treturn \"\"\n}\n\nvar lineBeginBlankRegex = regexp.MustCompile(\"(?m)^[\\t ]+\")\n\nfunc removeLineBeginBlanks(src string) string {\n\treturn lineBeginBlankRegex.ReplaceAllString(src, \"\")\n}\n\ntype SpecialActionValTransformer struct {\n\tstore map[string]string\n}\n\nconst yaccFmtVar = \"_yaccfmt_var_\"\n\nvar yaccFmtVarRegex = regexp.MustCompile(\"_yaccfmt_var_[0-9]{1,5}\")\n\nfunc (s *SpecialActionValTransformer) transform(val string) string {\n\tif strings.HasPrefix(val, \"$\") {\n\t\tgenerated := fmt.Sprintf(\"%s%d\", yaccFmtVar, len(s.store))\n\t\ts.store[generated] = val\n\t\treturn generated\n\t}\n\treturn val\n}\n\nfunc (s *SpecialActionValTransformer) restore(src string) string {\n\treturn yaccFmtVarRegex.ReplaceAllStringFunc(src, func(matched string) string {\n\t\torigin, ok := s.store[matched]\n\t\tif !ok {\n\t\t\tpanic(errors.Errorf(\"mismatch in SpecialActionValTransformer\"))\n\t\t}\n\t\treturn origin\n\t})\n}\n\ntype OutputFormatter struct {\n\tfile      *os.File\n\tout       *bufio.Writer\n\tformatter strutil.Formatter\n}\n\nfunc (y *OutputFormatter) Setup(filename string) (err error) {\n\tif y.file, err = os.Create(filename); err != nil {\n\t\treturn\n\t}\n\ty.out = bufio.NewWriter(y.file)\n\ty.formatter = strutil.IndentFormatter(y.out, \"\\t\")\n\treturn\n}\n\nfunc (y *OutputFormatter) Teardown() error {\n\tif y.out != nil {\n\t\tif err := y.out.Flush(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif y.file != nil {\n\t\tif err := y.file.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (y *OutputFormatter) Format(format string, args ...interface{}) (int, error) {\n\treturn y.formatter.Format(format, args...)\n}\n\nfunc (y *OutputFormatter) Write(bytes []byte) (int, error) {\n\treturn y.formatter.Write(bytes)\n}\n\ntype NotNilAssert struct {\n\tidx int\n\terr error\n}\n\nfunc (n *NotNilAssert) and(target interface{}) *NotNilAssert {\n\tif n.err != nil {\n\t\treturn n\n\t}\n\tif target == nil {\n\t\tn.err = errors.Errorf(\"encounter nil, index: %d\", n.idx)\n\t}\n\tn.idx++\n\treturn n\n}\n\nfunc (n *NotNilAssert) NotNil() error {\n\treturn n.err\n}\n\nfunc Ensure(target interface{}) *NotNilAssert {\n\treturn (&NotNilAssert{}).and(target)\n}\n\nfunc escapePercent(src string) string {\n\treturn strings.ReplaceAll(src, \"%\", \"%%\")\n}\n\nfunc checkInconsistencyInYaccParser(f format.Formatter, rule *parser.Rule, counter int) error {\n\tif counter == len(rule.Body) {\n\t\treturn nil\n\t}\n\t// pickup rule item in ruleBody\n\tfor i := counter; i < len(rule.Body); i++ {\n\t\tbody := rule.Body[i]\n\t\tswitch b := body.(type) {\n\t\tcase string, int:\n\t\t\tif bInt, ok := b.(int); ok {\n\t\t\t\tb = fmt.Sprintf(\"'%c'\", bInt)\n\t\t\t}\n\t\t\tterm := fmt.Sprintf(\" %s\", b)\n\t\t\tif i == 0 {\n\t\t\t\tterm = term[1:]\n\t\t\t}\n\t\t\t_, err := f.Format(\"%s\", term)\n\t\t\treturn err\n\t\tcase *parser.Action:\n\t\t\tisFirstRuleItem := i == 0\n\t\t\tif err := handlePrecedence(f, rule.Precedence, isFirstRuleItem); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := handleAction(f, rule, b, isFirstRuleItem); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/parser/goyacc/main.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Copyright 2014 The goyacc Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// This source code uses portions of code previously published in the Go tool\n// yacc[0] program, the respective license can be found in the LICENSE-GO-YACC\n// file.\n\n// Goyacc is a version of yacc generating Go parsers.\n//\n// # Usage\n//\n// Note: If no non flag arguments are given, goyacc reads standard input.\n//\n//\tgoyacc [options] [input]\n//\n//\toptions and (defaults)\n//\t\t-c                  Report state closures. (false)\n//\t\t-cr                 Check all states are reducible. (false)\n//\t\t-dlval              Debug value when runtime yyDebug >= 3. (\"lval\")\n//\t\t-dlvalf             Debug format of -dlval. (\"%+v\")\n//\t\t-ex                 Explain how were conflicts resolved. (false)\n//\t\t-l                  Disable line directives, for compatibility only - ignored. (false)\n//\t\t-la                 Report all lookahead sets. (false)\n//\t\t-o outputFile       Parser output. (\"y.go\")\n//\t\t-p prefix           Name prefix to use in generated code. (\"yy\")\n//\t\t-v reportFile       Create grammar report. (\"y.output\")\n//\t\t-xe examplesFile    Generate error messages by examples. (\"\")\n//\t\t-xegen examplesFile Generate a file suitable for -xe automatically from the grammar.\n//\t\t                    The file must not exist. (\"\")\n//\n// # Changelog\n//\n// 2015-03-24: The search for a custom error message is now extended to include\n// also the last state that was shifted into, if any. This change resolves a\n// problem in which a lookahead symbol is valid for a reduce action in state A,\n// but the same symbol is later never accepted by any shift action in some\n// state B which is popped from the state stack after the reduction is\n// performed. The computed from example state is A but when the error is\n// actually detected, the state is now B and the custom error was thus not\n// used.\n//\n// 2015-02-23: Added -xegen flag. It can be used to automagically generate a\n// skeleton errors by example file which can be, for example, edited and/or\n// submited later as an argument of the -xe option.\n//\n// 2014-12-18: Support %precedence for better bison compatibility[3]. The\n// actual changes are in packages goyacc is dependent on. Goyacc users should\n// rebuild the binary:\n//\n//\t$ go get -u github.com/cznic/goyacc\n//\n// 2014-12-02: Added support for the optional yyLexerEx interface. The Reduced\n// method can be useful for debugging and/or automatically producing examples\n// by parsing code fragments. If it returns true the parser exits immediately\n// with return value -1.\n//\n// # Overview\n//\n// The generated parser is reentrant and mostly backwards compatible with\n// parsers generated by go tool yacc[0]. yyParse expects to be given an\n// argument that conforms to the following interface:\n//\n//\ttype yyLexer interface {\n//\t\tLex(lval *yySymType) int\n//\t\tErrorf(format string,  a ...interface{})\n//\t\tErrors() (warns []error, errs []error)\n//\t}\n//\n// Optionally the argument to yyParse may implement the following interface:\n//\n//\ttype yyLexerEx interface {\n//\t\tyyLexer\n//\t\t// Hook for recording a reduction.\n//\t\tReduced(rule, state int, lval *yySymType) (stop bool) // Client should copy *lval.\n//\t}\n//\n// Lex should return the token identifier, and place other token information in\n// lval (which replaces the usual yylval). Error is equivalent to yyerror in\n// the original yacc.\n//\n// Code inside the parser may refer to the variable yylex, which holds the\n// yyLexer passed to Parse.\n//\n// Multiple grammars compiled into a single program should be placed in\n// distinct packages. If that is impossible, the \"-p prefix\" flag to yacc sets\n// the prefix, by default yy, that begins the names of symbols, including\n// types, the parser, and the lexer, generated and referenced by yacc's\n// generated code. Setting it to distinct values allows multiple grammars to be\n// placed in a single package.\n//\n// # Differences wrt go tool yacc\n//\n// - goyacc implements ideas from \"Generating LR Syntax Error Messages from\n// Examples\"[1]. Use the -xe flag to pass a name of the example file. For more\n// details about the example format please see [2].\n//\n// - The grammar report includes example token sequences leading to the\n// particular state. Can help understanding conflicts.\n//\n// - Minor changes in parser debug output.\n//\n// # Links\n//\n// Referenced from elsewhere:\n//\n//\t[0]: http://golang.org/cmd/yacc/\n//\t[1]: http://people.via.ecp.fr/~stilgar/doc/compilo/parser/Generating%20LR%20Syntax%20Error%20Messages.pdf\n//\t[2]: http://godoc.org/github.com/cznic/y#hdr-Error_Examples\n//\t[3]: http://www.gnu.org/software/bison/manual/html_node/Precedence-Only.html#Precedence-Only\npackage main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"flag\"\n\t\"fmt\"\n\t\"go/format\"\n\t\"go/scanner\"\n\t\"go/token\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"slices\"\n\n\t\"github.com/cznic/mathutil\"\n\t\"github.com/cznic/sortutil\"\n\t\"github.com/cznic/strutil\"\n\tparser \"modernc.org/parser/yacc\"\n\t\"modernc.org/y\"\n)\n\nvar (\n\t//oNoDefault = flag.Bool(\"nodefault\", false, \"disable generating $default actions\")\n\toClosures   = flag.Bool(\"c\", false, \"report state closures\")\n\toReducible  = flag.Bool(\"cr\", false, \"check all states are reducible\")\n\toDlval      = flag.String(\"dlval\", \"lval\", \"debug value (runtime yyDebug >= 3)\")\n\toDlvalf     = flag.String(\"dlvalf\", \"%+v\", \"debug format of -dlval (runtime yyDebug >= 3)\")\n\toLA         = flag.Bool(\"la\", false, \"report all lookahead sets\")\n\toNoLines    = flag.Bool(\"l\", false, \"disable line directives (for compatibility ony - ignored)\")\n\toOut        = flag.String(\"o\", \"y.go\", \"parser output\")\n\toPref       = flag.String(\"p\", \"yy\", \"name prefix to use in generated code\")\n\toReport     = flag.String(\"v\", \"y.output\", \"create grammar report\")\n\toResolved   = flag.Bool(\"ex\", false, \"explain how were conflicts resolved\")\n\toXErrors    = flag.String(\"xe\", \"\", \"generate eXtra errors from examples source file\")\n\toXErrorsGen = flag.String(\"xegen\", \"\", \"generate error from examples source file automatically from the grammar\")\n\toFormat     = flag.Bool(\"fmt\", false, \"format the yacc file\")\n\toFormatOut  = flag.String(\"fmtout\", \"golden.y\", \"yacc formatter output\")\n\toParserType = flag.String(\"t\", \"Parser\", \"name of the parser in the generated yyParse() function\")\n)\n\nfunc main() {\n\tlog.SetFlags(0)\n\n\tdefer func() {\n\t\t_, file, line, ok := runtime.Caller(2)\n\t\tif e := recover(); e != nil {\n\t\t\tswitch {\n\t\t\tcase ok:\n\t\t\t\tlog.Fatalf(\"%s:%d: panic: %v\", file, line, e)\n\t\t\tdefault:\n\t\t\t\tlog.Fatalf(\"panic: %v\", e)\n\t\t\t}\n\t\t}\n\t}()\n\n\tflag.Parse()\n\tvar in string\n\tswitch flag.NArg() {\n\tcase 0:\n\t\tin = os.Stdin.Name()\n\tcase 1:\n\t\tin = flag.Arg(0)\n\tdefault:\n\t\tlog.Fatal(\"expected at most one non flag argument\")\n\t}\n\n\tif *oFormat {\n\t\tif err := Format(in, *oFormatOut); err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\t\treturn\n\t}\n\n\tif err := main1(in); err != nil {\n\t\tswitch x := err.(type) {\n\t\tcase scanner.ErrorList:\n\t\t\tfor _, v := range x {\n\t\t\t\tfmt.Fprintf(os.Stderr, \"%v\\n\", v)\n\t\t\t}\n\t\t\tos.Exit(1)\n\t\tdefault:\n\t\t\tlog.Fatal(err)\n\t\t}\n\t}\n}\n\ntype symUsed struct {\n\tsym  *y.Symbol\n\tused int\n}\n\ntype symsUsed []symUsed\n\nfunc (s symsUsed) Len() int      { return len(s) }\nfunc (s symsUsed) Swap(i, j int) { s[i], s[j] = s[j], s[i] }\n\nfunc (s symsUsed) Less(i, j int) bool {\n\tif s[i].used > s[j].used {\n\t\treturn true\n\t}\n\n\tif s[i].used < s[j].used {\n\t\treturn false\n\t}\n\n\tcaseFoldedCompare := strings.Compare(strings.ToLower(s[i].sym.Name), strings.ToLower(s[j].sym.Name))\n\tif caseFoldedCompare < 0 {\n\t\treturn true\n\t}\n\tif caseFoldedCompare > 0 {\n\t\treturn false\n\t}\n\n\treturn s[i].sym.Name < s[j].sym.Name\n}\n\nfunc main1(in string) (err error) {\n\tvar out io.Writer\n\tif nm := *oOut; nm != \"\" {\n\t\tvar f *os.File\n\t\tvar e error\n\t\tif f, err = os.Create(nm); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif e1 := f.Close(); e1 != nil && err == nil {\n\t\t\t\terr = e1\n\t\t\t}\n\t\t}()\n\t\tw := bufio.NewWriter(f)\n\t\tdefer func() {\n\t\t\tif e1 := w.Flush(); e1 != nil && err == nil {\n\t\t\t\terr = e1\n\t\t\t}\n\t\t}()\n\t\tbuf := bytes.NewBuffer(nil)\n\t\tout = buf\n\t\tdefer func() {\n\t\t\tvar dest []byte\n\t\t\tif dest, e = format.Source(buf.Bytes()); e != nil {\n\t\t\t\tdest = buf.Bytes()\n\t\t\t}\n\n\t\t\tif _, e = w.Write(dest); e != nil && err == nil {\n\t\t\t\terr = e\n\t\t\t}\n\t\t}()\n\t}\n\n\tvar rep io.Writer\n\tif nm := *oReport; nm != \"\" {\n\t\tf, err1 := os.Create(nm)\n\t\tif err1 != nil {\n\t\t\treturn err1\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif e := f.Close(); e != nil && err == nil {\n\t\t\t\terr = e\n\t\t\t}\n\t\t}()\n\t\tw := bufio.NewWriter(f)\n\t\tdefer func() {\n\t\t\tif e := w.Flush(); e != nil && err == nil {\n\t\t\t\terr = e\n\t\t\t}\n\t\t}()\n\t\trep = w\n\t}\n\n\tvar xerrors []byte\n\tif nm := *oXErrors; nm != \"\" {\n\t\tb, err1 := os.ReadFile(nm)\n\t\tif err1 != nil {\n\t\t\treturn err1\n\t\t}\n\n\t\txerrors = b\n\t}\n\n\tp, err := y.ProcessFile(token.NewFileSet(), in, &y.Options{\n\t\t//NoDefault:   *oNoDefault,\n\t\tAllowConflicts: false,\n\t\tClosures:       *oClosures,\n\t\tLA:             *oLA,\n\t\tReducible:      *oReducible,\n\t\tReport:         rep,\n\t\tResolved:       *oResolved,\n\t\tXErrorsName:    *oXErrors,\n\t\tXErrorsSrc:     xerrors,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif fn := *oXErrorsGen; fn != \"\" {\n\t\tf, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0600)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tb := bufio.NewWriter(f)\n\t\tif err := p.SkeletonXErrors(b); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := b.Flush(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := f.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tmsu := make(map[*y.Symbol]int, len(p.Syms)) // sym -> usage\n\tfor nm, sym := range p.Syms {\n\t\tif nm == \"\" || nm == \"ε\" || nm == \"$accept\" || nm == \"#\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tmsu[sym] = 0\n\t}\n\tvar minArg, maxArg int\n\tfor _, state := range p.Table {\n\t\tfor _, act := range state {\n\t\t\tmsu[act.Sym]++\n\t\t\tk, arg := act.Kind()\n\t\t\tif k == 'a' {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif k == 'r' {\n\t\t\t\targ = -arg\n\t\t\t}\n\t\t\tminArg, maxArg = mathutil.Min(minArg, arg), mathutil.Max(maxArg, arg)\n\t\t}\n\t}\n\tsu := make(symsUsed, 0, len(msu))\n\tfor sym, used := range msu {\n\t\tsu = append(su, symUsed{sym, used})\n\t}\n\tsort.Sort(su)\n\n\t// ----------------------------------------------------------- Prologue\n\tf := strutil.IndentFormatter(out, \"\\t\")\n\tmustFormat(f, \"// Code generated by goyacc DO NOT EDIT.\\n\\n\")\n\tmustFormat(f, \"%s\", injectImport(p.Prologue))\n\tmustFormat(f, `\ntype %[1]sSymType %i%s%u\n\ntype %[1]sXError struct {\n\tstate, xsym int\n}\n`, *oPref, p.UnionSrc)\n\n\t// ---------------------------------------------------------- Constants\n\tnsyms := map[string]*y.Symbol{}\n\ta := make([]string, 0, len(msu))\n\tmaxTokName := 0\n\tfor sym := range msu {\n\t\tnm := sym.Name\n\t\tif nm == \"$default\" || nm == \"$end\" || sym.IsTerminal && nm[0] != '\\'' && sym.Value > 0 {\n\t\t\tmaxTokName = mathutil.Max(maxTokName, len(nm))\n\t\t\ta = append(a, nm)\n\t\t}\n\t\tnsyms[nm] = sym\n\t}\n\tslices.Sort(a)\n\tmustFormat(f, \"\\nconst (%i\\n\")\n\tfor _, v := range a {\n\t\tnm := v\n\t\tswitch nm {\n\t\tcase \"error\":\n\t\t\tnm = *oPref + \"ErrCode\"\n\t\tcase \"$default\":\n\t\t\tnm = *oPref + \"Default\"\n\t\tcase \"$end\":\n\t\t\tnm = *oPref + \"EOFCode\"\n\t\t}\n\t\tmustFormat(f, \"%s%s = %d\\n\", nm, strings.Repeat(\" \", maxTokName-len(nm)+1), nsyms[v].Value)\n\t}\n\tminArg-- // eg: [-13, 42], minArg -14 maps -13 to 1 so zero cell values -> empty.\n\tmustFormat(f, \"\\n%sMaxDepth = 200\\n\", *oPref)\n\tmustFormat(f, \"%sTabOfs   = %d\\n\", *oPref, minArg)\n\tmustFormat(f, \"%u)\")\n\n\t// ---------------------------------------------------------- Variables\n\tmustFormat(f, \"\\n\\nvar (%i\\n\")\n\n\t// Lex translation table\n\tmustFormat(f, \"%sXLAT = map[int]int{%i\\n\", *oPref)\n\txlat := make(map[int]int, len(su))\n\tvar errSym int\n\tfor i, v := range su {\n\t\tif v.sym.Name == \"error\" {\n\t\t\terrSym = i\n\t\t}\n\t\txlat[v.sym.Value] = i\n\t\tmustFormat(f, \"%6d: %3d, // %s (%dx)\\n\", v.sym.Value, i, v.sym.Name, msu[v.sym])\n\t}\n\tmustFormat(f, \"%u}\\n\")\n\n\t// Symbol names\n\tmustFormat(f, \"\\n%sSymNames = []string{%i\\n\", *oPref)\n\tfor _, v := range su {\n\t\tmustFormat(f, \"%q,\\n\", v.sym.Name)\n\t}\n\tmustFormat(f, \"%u}\\n\")\n\n\t// Reduction table\n\tmustFormat(f, \"\\n%sReductions = []struct{xsym, components int}{%i\\n\", *oPref)\n\tfor _, rule := range p.Rules {\n\t\tmustFormat(f, \"{%d, %d},\\n\", xlat[rule.Sym.Value], len(rule.Components))\n\t}\n\tmustFormat(f, \"%u}\\n\")\n\n\t// XError table\n\tmustFormat(f, \"\\n%[1]sXErrors = map[%[1]sXError]string{%i\\n\", *oPref)\n\tfor _, xerr := range p.XErrors {\n\t\tstate := xerr.Stack[len(xerr.Stack)-1]\n\t\txsym := -1\n\t\tif xerr.Lookahead != nil {\n\t\t\txsym = xlat[xerr.Lookahead.Value]\n\t\t}\n\t\tmustFormat(f, \"%[1]sXError{%d, %d}: \\\"%s\\\",\\n\", *oPref, state, xsym, xerr.Msg)\n\t}\n\tmustFormat(f, \"%u}\\n\\n\")\n\n\t// Parse table\n\ttbits := 32\n\tswitch n := mathutil.BitLen(maxArg - minArg + 1); {\n\tcase n < 8:\n\t\ttbits = 8\n\tcase n < 16:\n\t\ttbits = 16\n\t}\n\tmustFormat(f, \"%sParseTab = [%d][]uint%d{%i\\n\", *oPref, len(p.Table), tbits)\n\tnCells := 0\n\tvar tabRow sortutil.Uint64Slice\n\tfor si, state := range p.Table {\n\t\ttabRow = tabRow[:0]\n\t\tmax := 0\n\t\tfor _, act := range state {\n\t\t\tsym := act.Sym\n\t\t\txsym, ok := xlat[sym.Value]\n\t\t\tif !ok {\n\t\t\t\tpanic(\"internal error 001\")\n\t\t\t}\n\n\t\t\tmax = mathutil.Max(max, xsym)\n\t\t\tkind, arg := act.Kind()\n\t\t\tswitch kind {\n\t\t\tcase 'a':\n\t\t\t\targ = 0\n\t\t\tcase 'r':\n\t\t\t\targ *= -1\n\t\t\t}\n\t\t\ttabRow = append(tabRow, uint64(xsym)<<32|uint64(arg-minArg))\n\t\t}\n\t\tnCells += max\n\t\ttabRow.Sort()\n\t\tcol := -1\n\t\tif si%5 == 0 {\n\t\t\tmustFormat(f, \"// %d\\n\", si)\n\t\t}\n\t\tmustFormat(f, \"{\")\n\t\tfor i, v := range tabRow {\n\t\t\txsym := int(uint32(v >> 32))\n\t\t\targ := int(uint32(v))\n\t\t\tif col+1 != xsym {\n\t\t\t\tmustFormat(f, \"%d: \", xsym)\n\t\t\t}\n\t\t\tswitch {\n\t\t\tcase i == len(tabRow)-1:\n\t\t\t\tmustFormat(f, \"%d\", arg)\n\t\t\tdefault:\n\t\t\t\tmustFormat(f, \"%d, \", arg)\n\t\t\t}\n\t\t\tcol = xsym\n\t\t}\n\t\tmustFormat(f, \"},\\n\")\n\t}\n\tmustFormat(f, \"%u}\\n\")\n\tfmt.Fprintf(os.Stderr, \"Parse table entries: %d of %d, x %d bits == %d bytes\\n\", nCells, len(p.Table)*len(msu), tbits, nCells*tbits/8)\n\tif n := p.ConflictsSR; n != 0 {\n\t\tfmt.Fprintf(os.Stderr, \"conflicts: %d shift/reduce\\n\", n)\n\t}\n\tif n := p.ConflictsRR; n != 0 {\n\t\tfmt.Fprintf(os.Stderr, \"conflicts: %d reduce/reduce\\n\", n)\n\t}\n\n\tmustFormat(f, `%u)\n\nvar %[1]sDebug = 0\n\ntype %[1]sLexer interface {\n\tLex(lval *%[1]sSymType) int\n\tErrorf(format string, a ...interface{}) error\n\tAppendError(err error)\n\tErrors() (warns []error, errs []error)\n}\n\ntype %[1]sLexerEx interface {\n\t%[1]sLexer\n\tReduced(rule, state int, lval *%[1]sSymType) bool\n}\n\nfunc %[1]sSymName(c int) (s string) {\n\tx, ok := %[1]sXLAT[c]\n\tif ok {\n\t\treturn %[1]sSymNames[x]\n\t}\n\n\treturn __yyfmt__.Sprintf(\"%%d\", c)\n}\n\nfunc %[1]slex1(yylex %[1]sLexer, lval *%[1]sSymType) (n int) {\n\tn = yylex.Lex(lval)\n\tif n <= 0 {\n\t\tn = %[1]sEOFCode\n\t}\n\tif %[1]sDebug >= 3 {\n\t\t__yyfmt__.Printf(\"\\nlex %%s(%%#x %%d), %[4]s: %[3]s\\n\", %[1]sSymName(n), n, n, %[4]s)\n\t}\n\treturn n\n}\n\nfunc %[1]sParse(yylex %[1]sLexer, parser *%[5]s) int {\n\tconst yyError = %[2]d\n\n\tyyEx, _ := yylex.(%[1]sLexerEx)\n\tvar yyn int\n\tparser.yylval = %[1]sSymType{}\n\tyyS := parser.cache\n\n\tNerrs := 0   /* number of errors */\n\tErrflag := 0 /* error recovery flag */\n\tyyerrok := func() {\n\t\tif %[1]sDebug >= 2 {\n\t\t\t__yyfmt__.Printf(\"yyerrok()\\n\")\n\t\t}\n\t\tErrflag = 0\n\t}\n\t_ = yyerrok\n\tyystate := 0\n\tyychar := -1\n\tvar yyxchar int\n\tvar yyshift int\n\tyyp := -1\n\tgoto yystack\n\nret0:\n\treturn 0\n\nret1:\n\treturn 1\n\nyystack:\n\t/* put a state and value onto the stack */\n\tyyp++\n\tif yyp+1 >= len(yyS) {\n\t\tnyys := make([]%[1]sSymType, len(yyS)*2)\n\t\tcopy(nyys, yyS)\n\t\tyyS = nyys\n\t\tparser.cache = yyS\n\t}\n\tparser.yyVAL = &yyS[yyp+1]\n\tyyS[yyp].yys = yystate\n\nyynewstate:\n\tif yychar < 0 {\n\t\tyychar = %[1]slex1(yylex, &parser.yylval)\n\t\tvar ok bool\n\t\tif yyxchar, ok = %[1]sXLAT[yychar]; !ok {\n\t\t\tyyxchar = len(%[1]sSymNames) // > tab width\n\t\t}\n\t}\n\tif %[1]sDebug >= 4 {\n\t\tvar a []int\n\t\tfor _, v := range yyS[:yyp+1] {\n\t\t\ta = append(a, v.yys)\n\t\t}\n\t\t__yyfmt__.Printf(\"state stack %%v\\n\", a)\n\t}\n\trow := %[1]sParseTab[yystate]\n\tyyn = 0\n\tif yyxchar < len(row) {\n\t\tif yyn = int(row[yyxchar]); yyn != 0 {\n\t\t\tyyn += %[1]sTabOfs\n\t\t}\n\t}\n\tswitch {\n\tcase yyn > 0: // shift\n\t\tyychar = -1\n\t\t*parser.yyVAL = parser.yylval\n\t\tyystate = yyn\n\t\tyyshift = yyn\n\t\tif %[1]sDebug >= 2 {\n\t\t\t__yyfmt__.Printf(\"shift, and goto state %%d\\n\", yystate)\n\t\t}\n\t\tif Errflag > 0 {\n\t\t\tErrflag--\n\t\t}\n\t\tgoto yystack\n\tcase yyn < 0: // reduce\n\tcase yystate == 1: // accept\n\t\tif %[1]sDebug >= 2 {\n\t\t\t__yyfmt__.Println(\"accept\")\n\t\t}\n\t\tgoto ret0\n\t}\n\n\tif yyn == 0 {\n\t\t/* error ... attempt to resume parsing */\n\t\tswitch Errflag {\n\t\tcase 0: /* brand new error */\n\t\t\tif %[1]sDebug >= 1 {\n\t\t\t\t__yyfmt__.Printf(\"no action for %%s in state %%d\\n\", %[1]sSymName(yychar), yystate)\n\t\t\t}\n\t\t\tmsg, ok := %[1]sXErrors[%[1]sXError{yystate, yyxchar}]\n\t\t\tif !ok {\n\t\t\t\tmsg, ok = %[1]sXErrors[%[1]sXError{yystate, -1}]\n\t\t\t}\n\t\t\tif !ok && yyshift != 0 {\n\t\t\t\tmsg, ok = %[1]sXErrors[%[1]sXError{yyshift, yyxchar}]\n\t\t\t}\n\t\t\tif !ok {\n\t\t\t\tmsg, ok = %[1]sXErrors[%[1]sXError{yyshift, -1}]\n\t\t\t}\n\t\t\tif !ok || msg == \"\" {\n\t\t\t\tmsg = \"syntax error\"\n\t\t\t}\n\t\t\t// ignore goyacc error message\n\t\t\tyylex.AppendError(yylex.Errorf(\"\"))\n\t\t\tNerrs++\n\t\t\tfallthrough\n\n\t\tcase 1, 2: /* incompletely recovered error ... try again */\n\t\t\tErrflag = 3\n\n\t\t\t/* find a state where \"error\" is a legal shift action */\n\t\t\tfor yyp >= 0 {\n\t\t\t\trow := %[1]sParseTab[yyS[yyp].yys]\n\t\t\t\tif yyError < len(row) {\n\t\t\t\t\tyyn = int(row[yyError])+%[1]sTabOfs\n\t\t\t\t\tif yyn > 0 { // hit\n\t\t\t\t\t\tif %[1]sDebug >= 2 {\n\t\t\t\t\t\t\t__yyfmt__.Printf(\"error recovery found error shift in state %%d\\n\", yyS[yyp].yys)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyystate = yyn /* simulate a shift of \"error\" */\n\t\t\t\t\t\tgoto yystack\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* the current p has no shift on \"error\", pop stack */\n\t\t\t\tif %[1]sDebug >= 2 {\n\t\t\t\t\t__yyfmt__.Printf(\"error recovery pops state %%d\\n\", yyS[yyp].yys)\n\t\t\t\t}\n\t\t\t\tyyp--\n\t\t\t}\n\t\t\t/* there is no state on the stack with an error shift ... abort */\n\t\t\tif %[1]sDebug >= 2 {\n\t\t\t\t__yyfmt__.Printf(\"error recovery failed\\n\")\n\t\t\t}\n\t\t\tgoto ret1\n\n\t\tcase 3: /* no shift yet; clobber input char */\n\t\t\tif %[1]sDebug >= 2 {\n\t\t\t\t__yyfmt__.Printf(\"error recovery discards %%s\\n\", %[1]sSymName(yychar))\n\t\t\t}\n\t\t\tif yychar == %[1]sEOFCode {\n\t\t\t\tgoto ret1\n\t\t\t}\n\n\t\t\tyychar = -1\n\t\t\tgoto yynewstate /* try again in the same state */\n\t\t}\n\t}\n\n\tr := -yyn\n\tx0 := %[1]sReductions[r]\n\tx, n := x0.xsym, x0.components\n\tyypt := yyp\n\t_ = yypt // guard against \"declared and not used\"\n\n\tyyp -= n\n\tif yyp+1 >= len(yyS) {\n\t\tnyys := make([]%[1]sSymType, len(yyS)*2)\n\t\tcopy(nyys, yyS)\n\t\tyyS = nyys\n\t\tparser.cache = yyS\n\t}\n\tparser.yyVAL = &yyS[yyp+1]\n\n\t/* consult goto table to find next state */\n\texState := yystate\n\tyystate = int(%[1]sParseTab[yyS[yyp].yys][x])+%[1]sTabOfs\n\t/* reduction by production r */\n\tif %[1]sDebug >= 2 {\n\t\t__yyfmt__.Printf(\"reduce using rule %%v (%%s), and goto state %%d\\n\", r, %[1]sSymNames[x], yystate)\n\t}\n\n\tswitch r {%i\n`,\n\t\t*oPref, errSym, *oDlvalf, *oDlval, *oParserType)\n\tfor r, rule := range p.Rules {\n\t\tif rule.Action == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\taction := rule.Action.Values\n\t\tif len(action) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(action) == 1 {\n\t\t\tpart := action[0]\n\t\t\tif part.Type == parser.ActionValueGo {\n\t\t\t\tsrc := part.Src\n\t\t\t\tsrc = src[1 : len(src)-1] // Remove lead '{' and trail '}'\n\t\t\t\tif strings.TrimSpace(src) == \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tcomponents := rule.Components\n\t\ttyp := rule.Sym.Type\n\t\tmax := len(components)\n\t\tif p1 := rule.Parent; p1 != nil {\n\t\t\tmax = rule.MaxParentDlr\n\t\t\tcomponents = p1.Components\n\t\t}\n\t\tmustFormat(f, \"case %d: \", r)\n\t\tfor _, part := range action {\n\t\t\tnum := part.Num\n\t\t\tswitch part.Type {\n\t\t\tcase parser.ActionValueGo:\n\t\t\t\tmustFormat(f, \"%s\", part.Src)\n\t\t\tcase parser.ActionValueDlrDlr:\n\t\t\t\tmustFormat(f, \"parser.yyVAL.%s\", typ)\n\t\t\t\tif typ == \"\" {\n\t\t\t\t\tpanic(\"internal error 002\")\n\t\t\t\t}\n\t\t\tcase parser.ActionValueDlrNum:\n\t\t\t\ttyp := p.Syms[components[num-1]].Type\n\t\t\t\tif typ == \"\" {\n\t\t\t\t\tpanic(\"internal error 003\")\n\t\t\t\t}\n\t\t\t\tmustFormat(f, \"yyS[yypt-%d].%s\", max-num, typ)\n\t\t\tcase parser.ActionValueDlrTagDlr:\n\t\t\t\tmustFormat(f, \"parser.yyVAL.%s\", part.Tag)\n\t\t\tcase parser.ActionValueDlrTagNum:\n\t\t\t\tmustFormat(f, \"yyS[yypt-%d].%s\", max-num, part.Tag)\n\t\t\t}\n\t\t}\n\t\tmustFormat(f, \"\\n\")\n\t}\n\tmustFormat(f, `%u\n\t}\n\n\tif yyEx != nil && yyEx.Reduced(r, exState, parser.yyVAL) {\n\t\treturn -1\n\t}\n\tgoto yystack /* stack new state and value */\n}\n\n%[2]s\n`, *oPref, p.Tail)\n\t_ = oNoLines //TODO Ignored for now\n\treturn nil\n}\n\nfunc injectImport(src string) string {\n\tconst inj = `\n\nimport __yyfmt__ \"fmt\"\n`\n\tfset := token.NewFileSet()\n\tfile := fset.AddFile(\"\", -1, len(src))\n\tvar s scanner.Scanner\n\ts.Init(\n\t\tfile,\n\t\t[]byte(src),\n\t\tnil,\n\t\tscanner.ScanComments,\n\t)\n\tfor {\n\t\tswitch _, tok, _ := s.Scan(); tok {\n\t\tcase token.EOF:\n\t\t\treturn inj + src\n\t\tcase token.PACKAGE:\n\t\t\ts.Scan() // ident\n\t\t\tpos, _, _ := s.Scan()\n\t\t\tofs := file.Offset(pos)\n\t\t\treturn src[:ofs] + inj + src[ofs:]\n\t\t}\n\t}\n}\n\nfunc mustFormat(f strutil.Formatter, format string, args ...interface{}) {\n\t_, err := f.Format(format, args...)\n\tif err != nil {\n\t\tlog.Fatalf(\"format error %v\", err)\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/hintparser.go",
    "content": "// Code generated by goyacc DO NOT EDIT.\n\n// Copyright 2020 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport __yyfmt__ \"fmt\"\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n)\n\ntype yyhintSymType struct {\n\tyys    int\n\tident  string\n\tnumber uint64\n\thint   *ast.TableOptimizerHint\n\thints  []*ast.TableOptimizerHint\n\ttable  ast.HintTable\n}\n\ntype yyhintXError struct {\n\tstate, xsym int\n}\n\nconst (\n\tyyhintDefault             = 57407\n\tyyhintEOFCode             = 57344\n\tyyhintErrCode             = 57345\n\thintAggToCop              = 57376\n\thintBKA                   = 57354\n\thintBNL                   = 57356\n\thintDupsWeedOut           = 57403\n\thintEnablePlanCache       = 57377\n\thintFalse                 = 57399\n\thintFirstMatch            = 57404\n\thintGB                    = 57402\n\thintHashAgg               = 57378\n\thintHashJoin              = 57358\n\thintIdentifier            = 57347\n\thintIgnoreIndex           = 57379\n\thintIndexMerge            = 57362\n\thintInlHashJoin           = 57380\n\thintInlJoin               = 57381\n\thintInlMergeJoin          = 57382\n\thintIntLit                = 57346\n\thintJoinFixedOrder        = 57350\n\thintJoinOrder             = 57351\n\thintJoinPrefix            = 57352\n\thintJoinSuffix            = 57353\n\thintLooseScan             = 57405\n\thintMB                    = 57401\n\thintMRR                   = 57364\n\thintMaterialization       = 57406\n\thintMaxExecutionTime      = 57372\n\thintMemoryQuota           = 57383\n\thintMerge                 = 57360\n\thintNoBKA                 = 57355\n\thintNoBNL                 = 57357\n\thintNoHashJoin            = 57359\n\thintNoICP                 = 57366\n\thintNoIndexMerge          = 57363\n\thintNoMRR                 = 57365\n\thintNoMerge               = 57361\n\thintNoRangeOptimization   = 57367\n\thintNoSemijoin            = 57371\n\thintNoSkipScan            = 57369\n\thintNoSwapJoinInputs      = 57384\n\thintOLAP                  = 57395\n\thintOLTP                  = 57396\n\thintQBName                = 57375\n\thintQueryType             = 57385\n\thintReadConsistentReplica = 57386\n\thintReadFromStorage       = 57387\n\thintResourceGroup         = 57374\n\thintSMJoin                = 57388\n\thintSemijoin              = 57370\n\thintSetVar                = 57373\n\thintSingleAtIdentifier    = 57348\n\thintSkipScan              = 57368\n\thintStreamAgg             = 57389\n\thintStringLit             = 57349\n\thintSwapJoinInputs        = 57390\n\thintTiFlash               = 57398\n\thintTiKV                  = 57397\n\thintTrue                  = 57400\n\thintUseIndex              = 57392\n\thintUseIndexMerge         = 57391\n\thintUsePlanCache          = 57393\n\thintUseToja               = 57394\n\n\tyyhintMaxDepth = 200\n\tyyhintTabOfs   = -154\n)\n\nvar (\n\tyyhintXLAT = map[int]int{\n\t\t41:    0,   // ')' (115x)\n\t\t57376: 1,   // hintAggToCop (105x)\n\t\t57354: 2,   // hintBKA (105x)\n\t\t57356: 3,   // hintBNL (105x)\n\t\t57377: 4,   // hintEnablePlanCache (105x)\n\t\t57378: 5,   // hintHashAgg (105x)\n\t\t57358: 6,   // hintHashJoin (105x)\n\t\t57379: 7,   // hintIgnoreIndex (105x)\n\t\t57362: 8,   // hintIndexMerge (105x)\n\t\t57380: 9,   // hintInlHashJoin (105x)\n\t\t57381: 10,  // hintInlJoin (105x)\n\t\t57382: 11,  // hintInlMergeJoin (105x)\n\t\t57350: 12,  // hintJoinFixedOrder (105x)\n\t\t57351: 13,  // hintJoinOrder (105x)\n\t\t57352: 14,  // hintJoinPrefix (105x)\n\t\t57353: 15,  // hintJoinSuffix (105x)\n\t\t57372: 16,  // hintMaxExecutionTime (105x)\n\t\t57383: 17,  // hintMemoryQuota (105x)\n\t\t57360: 18,  // hintMerge (105x)\n\t\t57364: 19,  // hintMRR (105x)\n\t\t57355: 20,  // hintNoBKA (105x)\n\t\t57357: 21,  // hintNoBNL (105x)\n\t\t57359: 22,  // hintNoHashJoin (105x)\n\t\t57366: 23,  // hintNoICP (105x)\n\t\t57363: 24,  // hintNoIndexMerge (105x)\n\t\t57361: 25,  // hintNoMerge (105x)\n\t\t57365: 26,  // hintNoMRR (105x)\n\t\t57367: 27,  // hintNoRangeOptimization (105x)\n\t\t57371: 28,  // hintNoSemijoin (105x)\n\t\t57369: 29,  // hintNoSkipScan (105x)\n\t\t57384: 30,  // hintNoSwapJoinInputs (105x)\n\t\t57375: 31,  // hintQBName (105x)\n\t\t57385: 32,  // hintQueryType (105x)\n\t\t57386: 33,  // hintReadConsistentReplica (105x)\n\t\t57387: 34,  // hintReadFromStorage (105x)\n\t\t57374: 35,  // hintResourceGroup (105x)\n\t\t57370: 36,  // hintSemijoin (105x)\n\t\t57373: 37,  // hintSetVar (105x)\n\t\t57368: 38,  // hintSkipScan (105x)\n\t\t57388: 39,  // hintSMJoin (105x)\n\t\t57389: 40,  // hintStreamAgg (105x)\n\t\t57390: 41,  // hintSwapJoinInputs (105x)\n\t\t57392: 42,  // hintUseIndex (105x)\n\t\t57391: 43,  // hintUseIndexMerge (105x)\n\t\t57393: 44,  // hintUsePlanCache (105x)\n\t\t57394: 45,  // hintUseToja (105x)\n\t\t44:    46,  // ',' (104x)\n\t\t57403: 47,  // hintDupsWeedOut (85x)\n\t\t57404: 48,  // hintFirstMatch (85x)\n\t\t57405: 49,  // hintLooseScan (85x)\n\t\t57406: 50,  // hintMaterialization (85x)\n\t\t57398: 51,  // hintTiFlash (85x)\n\t\t57397: 52,  // hintTiKV (85x)\n\t\t57399: 53,  // hintFalse (84x)\n\t\t57395: 54,  // hintOLAP (84x)\n\t\t57396: 55,  // hintOLTP (84x)\n\t\t57400: 56,  // hintTrue (84x)\n\t\t57402: 57,  // hintGB (83x)\n\t\t57401: 58,  // hintMB (83x)\n\t\t57347: 59,  // hintIdentifier (82x)\n\t\t57348: 60,  // hintSingleAtIdentifier (74x)\n\t\t93:    61,  // ']' (66x)\n\t\t46:    62,  // '.' (59x)\n\t\t61:    63,  // '=' (59x)\n\t\t40:    64,  // '(' (53x)\n\t\t57344: 65,  // $end (22x)\n\t\t57425: 66,  // QueryBlockOpt (16x)\n\t\t57419: 67,  // Identifier (11x)\n\t\t57346: 68,  // hintIntLit (6x)\n\t\t57415: 69,  // HintTable (4x)\n\t\t57416: 70,  // HintTableList (4x)\n\t\t91:    71,  // '[' (3x)\n\t\t57408: 72,  // BooleanHintName (2x)\n\t\t57409: 73,  // CommaOpt (2x)\n\t\t57410: 74,  // HintIndexList (2x)\n\t\t57412: 75,  // HintStorageType (2x)\n\t\t57413: 76,  // HintStorageTypeAndTable (2x)\n\t\t57417: 77,  // HintTableListOpt (2x)\n\t\t57422: 78,  // JoinOrderOptimizerHintName (2x)\n\t\t57423: 79,  // NullaryHintName (2x)\n\t\t57427: 80,  // StorageOptimizerHintOpt (2x)\n\t\t57428: 81,  // SubqueryOptimizerHintName (2x)\n\t\t57431: 82,  // SubqueryStrategy (2x)\n\t\t57432: 83,  // SupportedIndexLevelOptimizerHintName (2x)\n\t\t57433: 84,  // SupportedTableLevelOptimizerHintName (2x)\n\t\t57434: 85,  // TableOptimizerHintOpt (2x)\n\t\t57436: 86,  // UnsupportedIndexLevelOptimizerHintName (2x)\n\t\t57437: 87,  // UnsupportedTableLevelOptimizerHintName (2x)\n\t\t57411: 88,  // HintQueryType (1x)\n\t\t57414: 89,  // HintStorageTypeAndTableList (1x)\n\t\t57349: 90,  // hintStringLit (1x)\n\t\t57418: 91,  // HintTrueOrFalse (1x)\n\t\t57420: 92,  // IndexNameList (1x)\n\t\t57421: 93,  // IndexNameListOpt (1x)\n\t\t57424: 94,  // OptimizerHintList (1x)\n\t\t57426: 95,  // Start (1x)\n\t\t57429: 96,  // SubqueryStrategies (1x)\n\t\t57430: 97,  // SubqueryStrategiesOpt (1x)\n\t\t57435: 98,  // UnitOfBytes (1x)\n\t\t57438: 99,  // Value (1x)\n\t\t57407: 100, // $default (0x)\n\t\t57345: 101, // error (0x)\n\t}\n\n\tyyhintSymNames = []string{\n\t\t\"')'\",\n\t\t\"hintAggToCop\",\n\t\t\"hintBKA\",\n\t\t\"hintBNL\",\n\t\t\"hintEnablePlanCache\",\n\t\t\"hintHashAgg\",\n\t\t\"hintHashJoin\",\n\t\t\"hintIgnoreIndex\",\n\t\t\"hintIndexMerge\",\n\t\t\"hintInlHashJoin\",\n\t\t\"hintInlJoin\",\n\t\t\"hintInlMergeJoin\",\n\t\t\"hintJoinFixedOrder\",\n\t\t\"hintJoinOrder\",\n\t\t\"hintJoinPrefix\",\n\t\t\"hintJoinSuffix\",\n\t\t\"hintMaxExecutionTime\",\n\t\t\"hintMemoryQuota\",\n\t\t\"hintMerge\",\n\t\t\"hintMRR\",\n\t\t\"hintNoBKA\",\n\t\t\"hintNoBNL\",\n\t\t\"hintNoHashJoin\",\n\t\t\"hintNoICP\",\n\t\t\"hintNoIndexMerge\",\n\t\t\"hintNoMerge\",\n\t\t\"hintNoMRR\",\n\t\t\"hintNoRangeOptimization\",\n\t\t\"hintNoSemijoin\",\n\t\t\"hintNoSkipScan\",\n\t\t\"hintNoSwapJoinInputs\",\n\t\t\"hintQBName\",\n\t\t\"hintQueryType\",\n\t\t\"hintReadConsistentReplica\",\n\t\t\"hintReadFromStorage\",\n\t\t\"hintResourceGroup\",\n\t\t\"hintSemijoin\",\n\t\t\"hintSetVar\",\n\t\t\"hintSkipScan\",\n\t\t\"hintSMJoin\",\n\t\t\"hintStreamAgg\",\n\t\t\"hintSwapJoinInputs\",\n\t\t\"hintUseIndex\",\n\t\t\"hintUseIndexMerge\",\n\t\t\"hintUsePlanCache\",\n\t\t\"hintUseToja\",\n\t\t\"','\",\n\t\t\"hintDupsWeedOut\",\n\t\t\"hintFirstMatch\",\n\t\t\"hintLooseScan\",\n\t\t\"hintMaterialization\",\n\t\t\"hintTiFlash\",\n\t\t\"hintTiKV\",\n\t\t\"hintFalse\",\n\t\t\"hintOLAP\",\n\t\t\"hintOLTP\",\n\t\t\"hintTrue\",\n\t\t\"hintGB\",\n\t\t\"hintMB\",\n\t\t\"hintIdentifier\",\n\t\t\"hintSingleAtIdentifier\",\n\t\t\"']'\",\n\t\t\"'.'\",\n\t\t\"'='\",\n\t\t\"'('\",\n\t\t\"$end\",\n\t\t\"QueryBlockOpt\",\n\t\t\"Identifier\",\n\t\t\"hintIntLit\",\n\t\t\"HintTable\",\n\t\t\"HintTableList\",\n\t\t\"'['\",\n\t\t\"BooleanHintName\",\n\t\t\"CommaOpt\",\n\t\t\"HintIndexList\",\n\t\t\"HintStorageType\",\n\t\t\"HintStorageTypeAndTable\",\n\t\t\"HintTableListOpt\",\n\t\t\"JoinOrderOptimizerHintName\",\n\t\t\"NullaryHintName\",\n\t\t\"StorageOptimizerHintOpt\",\n\t\t\"SubqueryOptimizerHintName\",\n\t\t\"SubqueryStrategy\",\n\t\t\"SupportedIndexLevelOptimizerHintName\",\n\t\t\"SupportedTableLevelOptimizerHintName\",\n\t\t\"TableOptimizerHintOpt\",\n\t\t\"UnsupportedIndexLevelOptimizerHintName\",\n\t\t\"UnsupportedTableLevelOptimizerHintName\",\n\t\t\"HintQueryType\",\n\t\t\"HintStorageTypeAndTableList\",\n\t\t\"hintStringLit\",\n\t\t\"HintTrueOrFalse\",\n\t\t\"IndexNameList\",\n\t\t\"IndexNameListOpt\",\n\t\t\"OptimizerHintList\",\n\t\t\"Start\",\n\t\t\"SubqueryStrategies\",\n\t\t\"SubqueryStrategiesOpt\",\n\t\t\"UnitOfBytes\",\n\t\t\"Value\",\n\t\t\"$default\",\n\t\t\"error\",\n\t}\n\n\tyyhintReductions = []struct{ xsym, components int }{\n\t\t{0, 1},\n\t\t{95, 1},\n\t\t{94, 1},\n\t\t{94, 3},\n\t\t{94, 1},\n\t\t{94, 3},\n\t\t{85, 4},\n\t\t{85, 4},\n\t\t{85, 4},\n\t\t{85, 4},\n\t\t{85, 4},\n\t\t{85, 4},\n\t\t{85, 5},\n\t\t{85, 5},\n\t\t{85, 6},\n\t\t{85, 4},\n\t\t{85, 4},\n\t\t{85, 6},\n\t\t{85, 5},\n\t\t{85, 4},\n\t\t{85, 5},\n\t\t{80, 5},\n\t\t{89, 1},\n\t\t{89, 3},\n\t\t{76, 4},\n\t\t{66, 0},\n\t\t{66, 1},\n\t\t{73, 0},\n\t\t{73, 1},\n\t\t{77, 1},\n\t\t{77, 1},\n\t\t{70, 2},\n\t\t{70, 3},\n\t\t{69, 2},\n\t\t{69, 4},\n\t\t{74, 4},\n\t\t{93, 0},\n\t\t{93, 1},\n\t\t{92, 1},\n\t\t{92, 3},\n\t\t{97, 0},\n\t\t{97, 1},\n\t\t{96, 1},\n\t\t{96, 3},\n\t\t{99, 1},\n\t\t{99, 1},\n\t\t{99, 1},\n\t\t{98, 1},\n\t\t{98, 1},\n\t\t{91, 1},\n\t\t{91, 1},\n\t\t{78, 1},\n\t\t{78, 1},\n\t\t{78, 1},\n\t\t{87, 1},\n\t\t{87, 1},\n\t\t{87, 1},\n\t\t{87, 1},\n\t\t{87, 1},\n\t\t{87, 1},\n\t\t{87, 1},\n\t\t{84, 1},\n\t\t{84, 1},\n\t\t{84, 1},\n\t\t{84, 1},\n\t\t{84, 1},\n\t\t{84, 1},\n\t\t{84, 1},\n\t\t{86, 1},\n\t\t{86, 1},\n\t\t{86, 1},\n\t\t{86, 1},\n\t\t{86, 1},\n\t\t{86, 1},\n\t\t{86, 1},\n\t\t{83, 1},\n\t\t{83, 1},\n\t\t{83, 1},\n\t\t{81, 1},\n\t\t{81, 1},\n\t\t{82, 1},\n\t\t{82, 1},\n\t\t{82, 1},\n\t\t{82, 1},\n\t\t{72, 1},\n\t\t{72, 1},\n\t\t{79, 1},\n\t\t{79, 1},\n\t\t{79, 1},\n\t\t{79, 1},\n\t\t{79, 1},\n\t\t{79, 1},\n\t\t{88, 1},\n\t\t{88, 1},\n\t\t{75, 1},\n\t\t{75, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t\t{67, 1},\n\t}\n\n\tyyhintXErrors = map[yyhintXError]string{}\n\n\tyyhintParseTab = [223][]uint16{\n\t\t// 0\n\t\t{1: 209, 178, 180, 205, 207, 191, 200, 192, 187, 186, 190, 159, 175, 176, 177, 166, 170, 183, 193, 179, 181, 182, 195, 210, 184, 194, 196, 203, 198, 189, 169, 173, 211, 174, 168, 202, 167, 197, 185, 208, 188, 199, 201, 206, 204, 72: 171, 78: 160, 172, 158, 165, 83: 164, 162, 157, 163, 161, 94: 156, 155},\n\t\t{65: 154},\n\t\t{1: 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 349, 65: 153, 73: 374},\n\t\t{1: 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 65: 152},\n\t\t{1: 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 65: 150},\n\t\t// 5\n\t\t{64: 371},\n\t\t{64: 368},\n\t\t{64: 365},\n\t\t{64: 360},\n\t\t{64: 357},\n\t\t// 10\n\t\t{64: 345},\n\t\t{64: 333},\n\t\t{64: 329},\n\t\t{64: 321},\n\t\t{64: 318},\n\t\t// 15\n\t\t{64: 315},\n\t\t{64: 308},\n\t\t{64: 302},\n\t\t{64: 299},\n\t\t{64: 293},\n\t\t// 20\n\t\t{64: 212},\n\t\t{64: 103},\n\t\t{64: 102},\n\t\t{64: 101},\n\t\t{64: 100},\n\t\t// 25\n\t\t{64: 99},\n\t\t{64: 98},\n\t\t{64: 97},\n\t\t{64: 96},\n\t\t{64: 95},\n\t\t// 30\n\t\t{64: 94},\n\t\t{64: 93},\n\t\t{64: 92},\n\t\t{64: 91},\n\t\t{64: 90},\n\t\t// 35\n\t\t{64: 89},\n\t\t{64: 88},\n\t\t{64: 87},\n\t\t{64: 86},\n\t\t{64: 85},\n\t\t// 40\n\t\t{64: 84},\n\t\t{64: 83},\n\t\t{64: 82},\n\t\t{64: 81},\n\t\t{64: 80},\n\t\t// 45\n\t\t{64: 79},\n\t\t{64: 78},\n\t\t{64: 77},\n\t\t{64: 76},\n\t\t{64: 75},\n\t\t// 50\n\t\t{64: 70},\n\t\t{64: 69},\n\t\t{64: 68},\n\t\t{64: 67},\n\t\t{64: 66},\n\t\t// 55\n\t\t{64: 65},\n\t\t{64: 64},\n\t\t{64: 63},\n\t\t{51: 129, 129, 60: 214, 66: 213},\n\t\t{51: 219, 218, 75: 217, 216, 89: 215},\n\t\t// 60\n\t\t{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 61: 128, 68: 128},\n\t\t{290, 46: 291},\n\t\t{132, 46: 132},\n\t\t{71: 220},\n\t\t{71: 60},\n\t\t// 65\n\t\t{71: 59},\n\t\t{1: 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 47: 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 214, 66: 222, 70: 221},\n\t\t{46: 288, 61: 287},\n\t\t{1: 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 224, 69: 223},\n\t\t{123, 46: 123, 61: 123},\n\t\t// 70\n\t\t{129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 214, 129, 284, 66: 283},\n\t\t{58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58},\n\t\t{57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57},\n\t\t{56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56},\n\t\t{55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55},\n\t\t// 75\n\t\t{54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54},\n\t\t{53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53},\n\t\t{52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52},\n\t\t{51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51},\n\t\t{50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50},\n\t\t// 80\n\t\t{49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49},\n\t\t{48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48},\n\t\t{47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47},\n\t\t{46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46},\n\t\t{45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45},\n\t\t// 85\n\t\t{44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44},\n\t\t{43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43},\n\t\t{42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42},\n\t\t{41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41},\n\t\t{40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40},\n\t\t// 90\n\t\t{39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39},\n\t\t{38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38},\n\t\t{37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37},\n\t\t{36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36},\n\t\t{35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35},\n\t\t// 95\n\t\t{34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34},\n\t\t{33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33},\n\t\t{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32},\n\t\t{31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31},\n\t\t{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},\n\t\t// 100\n\t\t{29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29},\n\t\t{28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28},\n\t\t{27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27},\n\t\t{26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26},\n\t\t{25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25},\n\t\t// 105\n\t\t{24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24},\n\t\t{23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23},\n\t\t{22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22},\n\t\t{21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21},\n\t\t{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},\n\t\t// 110\n\t\t{19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19},\n\t\t{18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18},\n\t\t{17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17},\n\t\t{16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16},\n\t\t{15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15},\n\t\t// 115\n\t\t{14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14},\n\t\t{13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13},\n\t\t{12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12},\n\t\t{11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11},\n\t\t{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10},\n\t\t// 120\n\t\t{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},\n\t\t{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},\n\t\t{7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7},\n\t\t{6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},\n\t\t{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},\n\t\t// 125\n\t\t{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},\n\t\t{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},\n\t\t{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},\n\t\t{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},\n\t\t{121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 61: 121},\n\t\t// 130\n\t\t{1: 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 285},\n\t\t{129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 214, 129, 66: 286},\n\t\t{120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 61: 120},\n\t\t{130, 46: 130},\n\t\t{1: 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 224, 69: 289},\n\t\t// 135\n\t\t{122, 46: 122, 61: 122},\n\t\t{1: 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 65: 133},\n\t\t{51: 219, 218, 75: 217, 292},\n\t\t{131, 46: 131},\n\t\t{54: 129, 129, 60: 214, 66: 294},\n\t\t// 140\n\t\t{54: 296, 297, 88: 295},\n\t\t{298},\n\t\t{62},\n\t\t{61},\n\t\t{1: 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 65: 134},\n\t\t// 145\n\t\t{129, 60: 214, 66: 300},\n\t\t{301},\n\t\t{1: 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 65: 135},\n\t\t{53: 129, 56: 129, 60: 214, 66: 303},\n\t\t{53: 306, 56: 305, 91: 304},\n\t\t// 150\n\t\t{307},\n\t\t{105},\n\t\t{104},\n\t\t{1: 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 65: 136},\n\t\t{60: 214, 66: 309, 68: 129},\n\t\t// 155\n\t\t{68: 310},\n\t\t{57: 313, 312, 98: 311},\n\t\t{314},\n\t\t{107},\n\t\t{106},\n\t\t// 160\n\t\t{1: 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 65: 137},\n\t\t{1: 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 316},\n\t\t{317},\n\t\t{1: 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 65: 138},\n\t\t{1: 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 319},\n\t\t// 165\n\t\t{320},\n\t\t{1: 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 65: 139},\n\t\t{1: 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 322},\n\t\t{63: 323},\n\t\t{1: 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 326, 327, 90: 325, 99: 324},\n\t\t// 170\n\t\t{328},\n\t\t{110},\n\t\t{109},\n\t\t{108},\n\t\t{1: 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 65: 140},\n\t\t// 175\n\t\t{60: 214, 66: 330, 68: 129},\n\t\t{68: 331},\n\t\t{332},\n\t\t{1: 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 65: 141},\n\t\t{129, 47: 129, 129, 129, 129, 60: 214, 66: 334},\n\t\t// 180\n\t\t{114, 47: 338, 339, 340, 341, 82: 337, 96: 336, 335},\n\t\t{344},\n\t\t{113, 46: 342},\n\t\t{112, 46: 112},\n\t\t{74, 46: 74},\n\t\t// 185\n\t\t{73, 46: 73},\n\t\t{72, 46: 72},\n\t\t{71, 46: 71},\n\t\t{47: 338, 339, 340, 341, 82: 343},\n\t\t{111, 46: 111},\n\t\t// 190\n\t\t{1: 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 65: 142},\n\t\t{1: 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 47: 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 214, 66: 347, 74: 346},\n\t\t{356},\n\t\t{1: 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 224, 69: 348},\n\t\t{127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 349, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 73: 350},\n\t\t// 195\n\t\t{126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 47: 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126},\n\t\t{118, 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 353, 92: 352, 351},\n\t\t{119},\n\t\t{117, 46: 354},\n\t\t{116, 46: 116},\n\t\t// 200\n\t\t{1: 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 355},\n\t\t{115, 46: 115},\n\t\t{1: 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 65: 143},\n\t\t{1: 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 47: 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 214, 66: 347, 74: 358},\n\t\t{359},\n\t\t// 205\n\t\t{1: 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 65: 144},\n\t\t{129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 47: 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 214, 66: 363, 70: 362, 77: 361},\n\t\t{364},\n\t\t{125, 46: 288},\n\t\t{124, 252, 230, 232, 253, 254, 234, 255, 238, 256, 257, 258, 226, 227, 228, 229, 248, 259, 236, 240, 231, 233, 235, 242, 239, 237, 241, 243, 247, 245, 260, 251, 261, 262, 263, 250, 246, 249, 244, 264, 265, 266, 268, 267, 269, 270, 47: 279, 280, 281, 282, 274, 273, 275, 271, 272, 276, 278, 277, 225, 67: 224, 69: 223},\n\t\t// 210\n\t\t{1: 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 65: 145},\n\t\t{129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 47: 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 214, 66: 363, 70: 362, 77: 366},\n\t\t{367},\n\t\t{1: 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 65: 146},\n\t\t{1: 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 47: 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 214, 66: 222, 70: 369},\n\t\t// 215\n\t\t{370, 46: 288},\n\t\t{1: 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 65: 147},\n\t\t{129, 60: 214, 66: 372},\n\t\t{373},\n\t\t{1: 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 65: 148},\n\t\t// 220\n\t\t{1: 209, 178, 180, 205, 207, 191, 200, 192, 187, 186, 190, 159, 175, 176, 177, 166, 170, 183, 193, 179, 181, 182, 195, 210, 184, 194, 196, 203, 198, 189, 169, 173, 211, 174, 168, 202, 167, 197, 185, 208, 188, 199, 201, 206, 204, 72: 171, 78: 160, 172, 376, 165, 83: 164, 162, 375, 163, 161},\n\t\t{1: 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 65: 151},\n\t\t{1: 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 65: 149},\n\t}\n)\n\nvar yyhintDebug = 0\n\ntype yyhintLexer interface {\n\tLex(lval *yyhintSymType) int\n\tErrorf(format string, a ...interface{}) error\n\tAppendError(err error)\n\tErrors() (warns []error, errs []error)\n}\n\ntype yyhintLexerEx interface {\n\tyyhintLexer\n\tReduced(rule, state int, lval *yyhintSymType) bool\n}\n\nfunc yyhintSymName(c int) (s string) {\n\tx, ok := yyhintXLAT[c]\n\tif ok {\n\t\treturn yyhintSymNames[x]\n\t}\n\n\treturn __yyfmt__.Sprintf(\"%d\", c)\n}\n\nfunc yyhintlex1(yylex yyhintLexer, lval *yyhintSymType) (n int) {\n\tn = yylex.Lex(lval)\n\tif n <= 0 {\n\t\tn = yyhintEOFCode\n\t}\n\tif yyhintDebug >= 3 {\n\t\t__yyfmt__.Printf(\"\\nlex %s(%#x %d), lval: %+v\\n\", yyhintSymName(n), n, n, lval)\n\t}\n\treturn n\n}\n\nfunc yyhintParse(yylex yyhintLexer, parser *hintParser) int {\n\tconst yyError = 101\n\n\tyyEx, _ := yylex.(yyhintLexerEx)\n\tvar yyn int\n\tparser.yylval = yyhintSymType{}\n\tyyS := parser.cache\n\n\tNerrs := 0   /* number of errors */\n\tErrflag := 0 /* error recovery flag */\n\tyyerrok := func() {\n\t\tif yyhintDebug >= 2 {\n\t\t\t__yyfmt__.Printf(\"yyerrok()\\n\")\n\t\t}\n\t\tErrflag = 0\n\t}\n\t_ = yyerrok\n\tyystate := 0\n\tyychar := -1\n\tvar yyxchar int\n\tvar yyshift int\n\tyyp := -1\n\tgoto yystack\n\nret0:\n\treturn 0\n\nret1:\n\treturn 1\n\nyystack:\n\t/* put a state and value onto the stack */\n\tyyp++\n\tif yyp+1 >= len(yyS) {\n\t\tnyys := make([]yyhintSymType, len(yyS)*2)\n\t\tcopy(nyys, yyS)\n\t\tyyS = nyys\n\t\tparser.cache = yyS\n\t}\n\tparser.yyVAL = &yyS[yyp+1]\n\tyyS[yyp].yys = yystate\n\nyynewstate:\n\tif yychar < 0 {\n\t\tyychar = yyhintlex1(yylex, &parser.yylval)\n\t\tvar ok bool\n\t\tif yyxchar, ok = yyhintXLAT[yychar]; !ok {\n\t\t\tyyxchar = len(yyhintSymNames) // > tab width\n\t\t}\n\t}\n\tif yyhintDebug >= 4 {\n\t\tvar a []int\n\t\tfor _, v := range yyS[:yyp+1] {\n\t\t\ta = append(a, v.yys)\n\t\t}\n\t\t__yyfmt__.Printf(\"state stack %v\\n\", a)\n\t}\n\trow := yyhintParseTab[yystate]\n\tyyn = 0\n\tif yyxchar < len(row) {\n\t\tif yyn = int(row[yyxchar]); yyn != 0 {\n\t\t\tyyn += yyhintTabOfs\n\t\t}\n\t}\n\tswitch {\n\tcase yyn > 0: // shift\n\t\tyychar = -1\n\t\t*parser.yyVAL = parser.yylval\n\t\tyystate = yyn\n\t\tyyshift = yyn\n\t\tif yyhintDebug >= 2 {\n\t\t\t__yyfmt__.Printf(\"shift, and goto state %d\\n\", yystate)\n\t\t}\n\t\tif Errflag > 0 {\n\t\t\tErrflag--\n\t\t}\n\t\tgoto yystack\n\tcase yyn < 0: // reduce\n\tcase yystate == 1: // accept\n\t\tif yyhintDebug >= 2 {\n\t\t\t__yyfmt__.Println(\"accept\")\n\t\t}\n\t\tgoto ret0\n\t}\n\n\tif yyn == 0 {\n\t\t/* error ... attempt to resume parsing */\n\t\tswitch Errflag {\n\t\tcase 0: /* brand new error */\n\t\t\tif yyhintDebug >= 1 {\n\t\t\t\t__yyfmt__.Printf(\"no action for %s in state %d\\n\", yyhintSymName(yychar), yystate)\n\t\t\t}\n\t\t\tmsg, ok := yyhintXErrors[yyhintXError{yystate, yyxchar}]\n\t\t\tif !ok {\n\t\t\t\tmsg, ok = yyhintXErrors[yyhintXError{yystate, -1}]\n\t\t\t}\n\t\t\tif !ok && yyshift != 0 {\n\t\t\t\tmsg, ok = yyhintXErrors[yyhintXError{yyshift, yyxchar}]\n\t\t\t}\n\t\t\tif !ok {\n\t\t\t\tmsg, ok = yyhintXErrors[yyhintXError{yyshift, -1}]\n\t\t\t}\n\t\t\tif !ok || msg == \"\" {\n\t\t\t\tmsg = \"syntax error\"\n\t\t\t}\n\t\t\t// ignore goyacc error message\n\t\t\tyylex.AppendError(yylex.Errorf(\"\"))\n\t\t\tNerrs++\n\t\t\tfallthrough\n\n\t\tcase 1, 2: /* incompletely recovered error ... try again */\n\t\t\tErrflag = 3\n\n\t\t\t/* find a state where \"error\" is a legal shift action */\n\t\t\tfor yyp >= 0 {\n\t\t\t\trow := yyhintParseTab[yyS[yyp].yys]\n\t\t\t\tif yyError < len(row) {\n\t\t\t\t\tyyn = int(row[yyError]) + yyhintTabOfs\n\t\t\t\t\tif yyn > 0 { // hit\n\t\t\t\t\t\tif yyhintDebug >= 2 {\n\t\t\t\t\t\t\t__yyfmt__.Printf(\"error recovery found error shift in state %d\\n\", yyS[yyp].yys)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyystate = yyn /* simulate a shift of \"error\" */\n\t\t\t\t\t\tgoto yystack\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* the current p has no shift on \"error\", pop stack */\n\t\t\t\tif yyhintDebug >= 2 {\n\t\t\t\t\t__yyfmt__.Printf(\"error recovery pops state %d\\n\", yyS[yyp].yys)\n\t\t\t\t}\n\t\t\t\tyyp--\n\t\t\t}\n\t\t\t/* there is no state on the stack with an error shift ... abort */\n\t\t\tif yyhintDebug >= 2 {\n\t\t\t\t__yyfmt__.Printf(\"error recovery failed\\n\")\n\t\t\t}\n\t\t\tgoto ret1\n\n\t\tcase 3: /* no shift yet; clobber input char */\n\t\t\tif yyhintDebug >= 2 {\n\t\t\t\t__yyfmt__.Printf(\"error recovery discards %s\\n\", yyhintSymName(yychar))\n\t\t\t}\n\t\t\tif yychar == yyhintEOFCode {\n\t\t\t\tgoto ret1\n\t\t\t}\n\n\t\t\tyychar = -1\n\t\t\tgoto yynewstate /* try again in the same state */\n\t\t}\n\t}\n\n\tr := -yyn\n\tx0 := yyhintReductions[r]\n\tx, n := x0.xsym, x0.components\n\tyypt := yyp\n\t_ = yypt // guard against \"declared and not used\"\n\n\tyyp -= n\n\tif yyp+1 >= len(yyS) {\n\t\tnyys := make([]yyhintSymType, len(yyS)*2)\n\t\tcopy(nyys, yyS)\n\t\tyyS = nyys\n\t\tparser.cache = yyS\n\t}\n\tparser.yyVAL = &yyS[yyp+1]\n\n\t/* consult goto table to find next state */\n\texState := yystate\n\tyystate = int(yyhintParseTab[yyS[yyp].yys][x]) + yyhintTabOfs\n\t/* reduction by production r */\n\tif yyhintDebug >= 2 {\n\t\t__yyfmt__.Printf(\"reduce using rule %v (%s), and goto state %d\\n\", r, yyhintSymNames[x], yystate)\n\t}\n\n\tswitch r {\n\tcase 1:\n\t\t{\n\t\t\tparser.result = yyS[yypt-0].hints\n\t\t}\n\tcase 2:\n\t\t{\n\t\t\tif yyS[yypt-0].hint != nil {\n\t\t\t\tparser.yyVAL.hints = []*ast.TableOptimizerHint{yyS[yypt-0].hint}\n\t\t\t}\n\t\t}\n\tcase 3:\n\t\t{\n\t\t\tif yyS[yypt-0].hint != nil {\n\t\t\t\tparser.yyVAL.hints = append(yyS[yypt-2].hints, yyS[yypt-0].hint)\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.hints = yyS[yypt-2].hints\n\t\t\t}\n\t\t}\n\tcase 4:\n\t\t{\n\t\t\tparser.yyVAL.hints = yyS[yypt-0].hints\n\t\t}\n\tcase 5:\n\t\t{\n\t\t\tparser.yyVAL.hints = append(yyS[yypt-2].hints, yyS[yypt-0].hints...)\n\t\t}\n\tcase 6:\n\t\t{\n\t\t\tparser.warnUnsupportedHint(yyS[yypt-3].ident)\n\t\t\tparser.yyVAL.hint = nil\n\t\t}\n\tcase 7:\n\t\t{\n\t\t\tparser.warnUnsupportedHint(yyS[yypt-3].ident)\n\t\t\tparser.yyVAL.hint = nil\n\t\t}\n\tcase 8:\n\t\t{\n\t\t\tparser.warnUnsupportedHint(yyS[yypt-3].ident)\n\t\t\tparser.yyVAL.hint = nil\n\t\t}\n\tcase 9:\n\t\t{\n\t\t\th := yyS[yypt-1].hint\n\t\t\th.HintName = model.NewCIStr(yyS[yypt-3].ident)\n\t\t\tparser.yyVAL.hint = h\n\t\t}\n\tcase 10:\n\t\t{\n\t\t\tparser.warnUnsupportedHint(yyS[yypt-3].ident)\n\t\t\tparser.yyVAL.hint = nil\n\t\t}\n\tcase 11:\n\t\t{\n\t\t\th := yyS[yypt-1].hint\n\t\t\th.HintName = model.NewCIStr(yyS[yypt-3].ident)\n\t\t\tparser.yyVAL.hint = h\n\t\t}\n\tcase 12:\n\t\t{\n\t\t\tparser.warnUnsupportedHint(yyS[yypt-4].ident)\n\t\t\tparser.yyVAL.hint = nil\n\t\t}\n\tcase 13:\n\t\t{\n\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{\n\t\t\t\tHintName:         model.NewCIStr(yyS[yypt-4].ident),\n\t\t\t\tQBName:           model.NewCIStr(yyS[yypt-2].ident),\n\t\t\t\tMaxExecutionTime: yyS[yypt-1].number,\n\t\t\t}\n\t\t}\n\tcase 14:\n\t\t{\n\t\t\tparser.warnUnsupportedHint(yyS[yypt-5].ident)\n\t\t\tparser.yyVAL.hint = nil\n\t\t}\n\tcase 15:\n\t\t{\n\t\t\tparser.warnUnsupportedHint(yyS[yypt-3].ident)\n\t\t\tparser.yyVAL.hint = nil\n\t\t}\n\tcase 16:\n\t\t{\n\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{\n\t\t\t\tHintName: model.NewCIStr(yyS[yypt-3].ident),\n\t\t\t\tQBName:   model.NewCIStr(yyS[yypt-1].ident),\n\t\t\t}\n\t\t}\n\tcase 17:\n\t\t{\n\t\t\tmaxValue := uint64(math.MaxInt64) / yyS[yypt-1].number\n\t\t\tif yyS[yypt-2].number <= maxValue {\n\t\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{\n\t\t\t\t\tHintName:    model.NewCIStr(yyS[yypt-5].ident),\n\t\t\t\t\tMemoryQuota: int64(yyS[yypt-2].number * yyS[yypt-1].number),\n\t\t\t\t\tQBName:      model.NewCIStr(yyS[yypt-3].ident),\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tyylex.AppendError(ErrWarnMemoryQuotaOverflow.GenWithStackByArgs(math.MaxInt64))\n\t\t\t\tparser.lastErrorAsWarn()\n\t\t\t\tparser.yyVAL.hint = nil\n\t\t\t}\n\t\t}\n\tcase 18:\n\t\t{\n\t\t\th := yyS[yypt-1].hint\n\t\t\th.HintName = model.NewCIStr(yyS[yypt-4].ident)\n\t\t\th.QBName = model.NewCIStr(yyS[yypt-2].ident)\n\t\t\tparser.yyVAL.hint = h\n\t\t}\n\tcase 19:\n\t\t{\n\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{\n\t\t\t\tHintName: model.NewCIStr(yyS[yypt-3].ident),\n\t\t\t\tQBName:   model.NewCIStr(yyS[yypt-1].ident),\n\t\t\t}\n\t\t}\n\tcase 20:\n\t\t{\n\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{\n\t\t\t\tHintName:  model.NewCIStr(yyS[yypt-4].ident),\n\t\t\t\tQBName:    model.NewCIStr(yyS[yypt-2].ident),\n\t\t\t\tQueryType: model.NewCIStr(yyS[yypt-1].ident),\n\t\t\t}\n\t\t}\n\tcase 21:\n\t\t{\n\t\t\ths := yyS[yypt-1].hints\n\t\t\tname := model.NewCIStr(yyS[yypt-4].ident)\n\t\t\tqb := model.NewCIStr(yyS[yypt-2].ident)\n\t\t\tfor _, h := range hs {\n\t\t\t\th.HintName = name\n\t\t\t\th.QBName = qb\n\t\t\t}\n\t\t\tparser.yyVAL.hints = hs\n\t\t}\n\tcase 22:\n\t\t{\n\t\t\tparser.yyVAL.hints = []*ast.TableOptimizerHint{yyS[yypt-0].hint}\n\t\t}\n\tcase 23:\n\t\t{\n\t\t\tparser.yyVAL.hints = append(yyS[yypt-2].hints, yyS[yypt-0].hint)\n\t\t}\n\tcase 24:\n\t\t{\n\t\t\th := yyS[yypt-1].hint\n\t\t\th.StoreType = model.NewCIStr(yyS[yypt-3].ident)\n\t\t\tparser.yyVAL.hint = h\n\t\t}\n\tcase 25:\n\t\t{\n\t\t\tparser.yyVAL.ident = \"\"\n\t\t}\n\tcase 30:\n\t\t{\n\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{\n\t\t\t\tQBName: model.NewCIStr(yyS[yypt-0].ident),\n\t\t\t}\n\t\t}\n\tcase 31:\n\t\t{\n\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{\n\t\t\t\tTables: []ast.HintTable{yyS[yypt-0].table},\n\t\t\t\tQBName: model.NewCIStr(yyS[yypt-1].ident),\n\t\t\t}\n\t\t}\n\tcase 32:\n\t\t{\n\t\t\th := yyS[yypt-2].hint\n\t\t\th.Tables = append(h.Tables, yyS[yypt-0].table)\n\t\t\tparser.yyVAL.hint = h\n\t\t}\n\tcase 33:\n\t\t{\n\t\t\tparser.yyVAL.table = ast.HintTable{\n\t\t\t\tTableName: model.NewCIStr(yyS[yypt-1].ident),\n\t\t\t\tQBName:    model.NewCIStr(yyS[yypt-0].ident),\n\t\t\t}\n\t\t}\n\tcase 34:\n\t\t{\n\t\t\tparser.yyVAL.table = ast.HintTable{\n\t\t\t\tDBName:    model.NewCIStr(yyS[yypt-3].ident),\n\t\t\t\tTableName: model.NewCIStr(yyS[yypt-1].ident),\n\t\t\t\tQBName:    model.NewCIStr(yyS[yypt-0].ident),\n\t\t\t}\n\t\t}\n\tcase 35:\n\t\t{\n\t\t\th := yyS[yypt-0].hint\n\t\t\th.Tables = []ast.HintTable{yyS[yypt-2].table}\n\t\t\th.QBName = model.NewCIStr(yyS[yypt-3].ident)\n\t\t\tparser.yyVAL.hint = h\n\t\t}\n\tcase 36:\n\t\t{\n\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{}\n\t\t}\n\tcase 38:\n\t\t{\n\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{\n\t\t\t\tIndexes: []model.CIStr{model.NewCIStr(yyS[yypt-0].ident)},\n\t\t\t}\n\t\t}\n\tcase 39:\n\t\t{\n\t\t\th := yyS[yypt-2].hint\n\t\t\th.Indexes = append(h.Indexes, model.NewCIStr(yyS[yypt-0].ident))\n\t\t\tparser.yyVAL.hint = h\n\t\t}\n\tcase 46:\n\t\t{\n\t\t\tparser.yyVAL.ident = strconv.FormatUint(yyS[yypt-0].number, 10)\n\t\t}\n\tcase 47:\n\t\t{\n\t\t\tparser.yyVAL.number = 1024 * 1024\n\t\t}\n\tcase 48:\n\t\t{\n\t\t\tparser.yyVAL.number = 1024 * 1024 * 1024\n\t\t}\n\tcase 49:\n\t\t{\n\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{HintFlag: true}\n\t\t}\n\tcase 50:\n\t\t{\n\t\t\tparser.yyVAL.hint = &ast.TableOptimizerHint{HintFlag: false}\n\t\t}\n\n\t}\n\n\tif yyEx != nil && yyEx.Reduced(r, exState, parser.yyVAL) {\n\t\treturn -1\n\t}\n\tgoto yystack /* stack new state and value */\n}\n"
  },
  {
    "path": "pkg/parser/hintparser.y",
    "content": "%{\n// Copyright 2020 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n)\n\n%}\n\n%union {\n\tident   string\n\tnumber  uint64\n\thint    *ast.TableOptimizerHint\n\thints []*ast.TableOptimizerHint\n\ttable \tast.HintTable\n}\n\n%token\t<number>\n\n\t/*yy:token \"%d\" */\n\thintIntLit \"a 64-bit unsigned integer\"\n\n%token\t<ident>\n\n\t/*yy:token \"%c\" */\n\thintIdentifier\n\n\t/*yy:token \"@%c\" */\n\thintSingleAtIdentifier \"identifier with single leading at\"\n\n\t/*yy:token \"'%c'\" */\n\thintStringLit\n\n\t/* MySQL 8.0 hint names */\n\thintJoinFixedOrder      \"JOIN_FIXED_ORDER\"\n\thintJoinOrder           \"JOIN_ORDER\"\n\thintJoinPrefix          \"JOIN_PREFIX\"\n\thintJoinSuffix          \"JOIN_SUFFIX\"\n\thintBKA                 \"BKA\"\n\thintNoBKA               \"NO_BKA\"\n\thintBNL                 \"BNL\"\n\thintNoBNL               \"NO_BNL\"\n\thintHashJoin            \"HASH_JOIN\"\n\thintNoHashJoin          \"NO_HASH_JOIN\"\n\thintMerge               \"MERGE\"\n\thintNoMerge             \"NO_MERGE\"\n\thintIndexMerge          \"INDEX_MERGE\"\n\thintNoIndexMerge        \"NO_INDEX_MERGE\"\n\thintMRR                 \"MRR\"\n\thintNoMRR               \"NO_MRR\"\n\thintNoICP               \"NO_ICP\"\n\thintNoRangeOptimization \"NO_RANGE_OPTIMIZATION\"\n\thintSkipScan            \"SKIP_SCAN\"\n\thintNoSkipScan          \"NO_SKIP_SCAN\"\n\thintSemijoin            \"SEMIJOIN\"\n\thintNoSemijoin          \"NO_SEMIJOIN\"\n\thintMaxExecutionTime    \"MAX_EXECUTION_TIME\"\n\thintSetVar              \"SET_VAR\"\n\thintResourceGroup       \"RESOURCE_GROUP\"\n\thintQBName              \"QB_NAME\"\n\n\t/* TiDB hint names */\n\thintAggToCop              \"AGG_TO_COP\"\n\thintEnablePlanCache       \"ENABLE_PLAN_CACHE\"\n\thintHashAgg               \"HASH_AGG\"\n\thintIgnoreIndex           \"IGNORE_INDEX\"\n\thintInlHashJoin           \"INL_HASH_JOIN\"\n\thintInlJoin               \"INL_JOIN\"\n\thintInlMergeJoin          \"INL_MERGE_JOIN\"\n\thintMemoryQuota           \"MEMORY_QUOTA\"\n\thintNoSwapJoinInputs      \"NO_SWAP_JOIN_INPUTS\"\n\thintQueryType             \"QUERY_TYPE\"\n\thintReadConsistentReplica \"READ_CONSISTENT_REPLICA\"\n\thintReadFromStorage       \"READ_FROM_STORAGE\"\n\thintSMJoin                \"SM_JOIN\"\n\thintStreamAgg             \"STREAM_AGG\"\n\thintSwapJoinInputs        \"SWAP_JOIN_INPUTS\"\n\thintUseIndexMerge         \"USE_INDEX_MERGE\"\n\thintUseIndex              \"USE_INDEX\"\n\thintUsePlanCache          \"USE_PLAN_CACHE\"\n\thintUseToja               \"USE_TOJA\"\n\n\t/* Other keywords */\n\thintOLAP            \"OLAP\"\n\thintOLTP            \"OLTP\"\n\thintTiKV            \"TIKV\"\n\thintTiFlash         \"TIFLASH\"\n\thintFalse           \"FALSE\"\n\thintTrue            \"TRUE\"\n\thintMB              \"MB\"\n\thintGB              \"GB\"\n\thintDupsWeedOut     \"DUPSWEEDOUT\"\n\thintFirstMatch      \"FIRSTMATCH\"\n\thintLooseScan       \"LOOSESCAN\"\n\thintMaterialization \"MATERIALIZATION\"\n\n%type\t<ident>\n\tIdentifier                             \"identifier (including keywords)\"\n\tQueryBlockOpt                          \"Query block identifier optional\"\n\tJoinOrderOptimizerHintName\n\tUnsupportedTableLevelOptimizerHintName\n\tSupportedTableLevelOptimizerHintName\n\tUnsupportedIndexLevelOptimizerHintName\n\tSupportedIndexLevelOptimizerHintName\n\tSubqueryOptimizerHintName\n\tBooleanHintName                        \"name of hints which take a boolean input\"\n\tNullaryHintName                        \"name of hints which take no input\"\n\tSubqueryStrategy\n\tValue                                  \"the value in the SET_VAR() hint\"\n\tHintQueryType                          \"query type in optimizer hint (OLAP or OLTP)\"\n\tHintStorageType                        \"storage type in optimizer hint (TiKV or TiFlash)\"\n\n%type\t<number>\n\tUnitOfBytes \"unit of bytes (MB or GB)\"\n\tCommaOpt    \"optional ','\"\n\n%type\t<hints>\n\tOptimizerHintList           \"optimizer hint list\"\n\tStorageOptimizerHintOpt     \"storage level optimizer hint\"\n\tHintStorageTypeAndTableList \"storage type and tables list in optimizer hint\"\n\n%type\t<hint>\n\tTableOptimizerHintOpt   \"optimizer hint\"\n\tHintTableList           \"table list in optimizer hint\"\n\tHintTableListOpt        \"optional table list in optimizer hint\"\n\tHintIndexList           \"table name with index list in optimizer hint\"\n\tIndexNameList           \"index list in optimizer hint\"\n\tIndexNameListOpt        \"optional index list in optimizer hint\"\n\tSubqueryStrategies      \"subquery strategies\"\n\tSubqueryStrategiesOpt   \"optional subquery strategies\"\n\tHintTrueOrFalse         \"true or false in optimizer hint\"\n\tHintStorageTypeAndTable \"storage type and tables in optimizer hint\"\n\n%type\t<table>\n\tHintTable \"Table in optimizer hint\"\n\n\n%start\tStart\n\n%%\n\nStart:\n\tOptimizerHintList\n\t{\n\t\tparser.result = $1\n\t}\n\nOptimizerHintList:\n\tTableOptimizerHintOpt\n\t{\n\t\tif $1 != nil {\n\t\t\t$$ = []*ast.TableOptimizerHint{$1}\n\t\t}\n\t}\n|\tOptimizerHintList CommaOpt TableOptimizerHintOpt\n\t{\n\t\tif $3 != nil {\n\t\t\t$$ = append($1, $3)\n\t\t} else {\n\t\t\t$$ = $1\n\t\t}\n\t}\n|\tStorageOptimizerHintOpt\n\t{\n\t\t$$ = $1\n\t}\n|\tOptimizerHintList CommaOpt StorageOptimizerHintOpt\n\t{\n\t\t$$ = append($1, $3...)\n\t}\n\nTableOptimizerHintOpt:\n\t\"JOIN_FIXED_ORDER\" '(' QueryBlockOpt ')'\n\t{\n\t\tparser.warnUnsupportedHint($1)\n\t\t$$ = nil\n\t}\n|\tJoinOrderOptimizerHintName '(' HintTableList ')'\n\t{\n\t\tparser.warnUnsupportedHint($1)\n\t\t$$ = nil\n\t}\n|\tUnsupportedTableLevelOptimizerHintName '(' HintTableListOpt ')'\n\t{\n\t\tparser.warnUnsupportedHint($1)\n\t\t$$ = nil\n\t}\n|\tSupportedTableLevelOptimizerHintName '(' HintTableListOpt ')'\n\t{\n\t\th := $3\n\t\th.HintName = model.NewCIStr($1)\n\t\t$$ = h\n\t}\n|\tUnsupportedIndexLevelOptimizerHintName '(' HintIndexList ')'\n\t{\n\t\tparser.warnUnsupportedHint($1)\n\t\t$$ = nil\n\t}\n|\tSupportedIndexLevelOptimizerHintName '(' HintIndexList ')'\n\t{\n\t\th := $3\n\t\th.HintName = model.NewCIStr($1)\n\t\t$$ = h\n\t}\n|\tSubqueryOptimizerHintName '(' QueryBlockOpt SubqueryStrategiesOpt ')'\n\t{\n\t\tparser.warnUnsupportedHint($1)\n\t\t$$ = nil\n\t}\n|\t\"MAX_EXECUTION_TIME\" '(' QueryBlockOpt hintIntLit ')'\n\t{\n\t\t$$ = &ast.TableOptimizerHint{\n\t\t\tHintName:         model.NewCIStr($1),\n\t\t\tQBName:           model.NewCIStr($3),\n\t\t\tMaxExecutionTime: $4,\n\t\t}\n\t}\n|\t\"SET_VAR\" '(' Identifier '=' Value ')'\n\t{\n\t\tparser.warnUnsupportedHint($1)\n\t\t$$ = nil\n\t}\n|\t\"RESOURCE_GROUP\" '(' Identifier ')'\n\t{\n\t\tparser.warnUnsupportedHint($1)\n\t\t$$ = nil\n\t}\n|\t\"QB_NAME\" '(' Identifier ')'\n\t{\n\t\t$$ = &ast.TableOptimizerHint{\n\t\t\tHintName: model.NewCIStr($1),\n\t\t\tQBName:   model.NewCIStr($3),\n\t\t}\n\t}\n|\t\"MEMORY_QUOTA\" '(' QueryBlockOpt hintIntLit UnitOfBytes ')'\n\t{\n\t\tmaxValue := uint64(math.MaxInt64) / $5\n\t\tif $4 <= maxValue {\n\t\t\t$$ = &ast.TableOptimizerHint{\n\t\t\t\tHintName:    model.NewCIStr($1),\n\t\t\t\tMemoryQuota: int64($4 * $5),\n\t\t\t\tQBName:      model.NewCIStr($3),\n\t\t\t}\n\t\t} else {\n\t\t\tyylex.AppendError(ErrWarnMemoryQuotaOverflow.GenWithStackByArgs(math.MaxInt64))\n\t\t\tparser.lastErrorAsWarn()\n\t\t\t$$ = nil\n\t\t}\n\t}\n|\tBooleanHintName '(' QueryBlockOpt HintTrueOrFalse ')'\n\t{\n\t\th := $4\n\t\th.HintName = model.NewCIStr($1)\n\t\th.QBName = model.NewCIStr($3)\n\t\t$$ = h\n\t}\n|\tNullaryHintName '(' QueryBlockOpt ')'\n\t{\n\t\t$$ = &ast.TableOptimizerHint{\n\t\t\tHintName: model.NewCIStr($1),\n\t\t\tQBName:   model.NewCIStr($3),\n\t\t}\n\t}\n|\t\"QUERY_TYPE\" '(' QueryBlockOpt HintQueryType ')'\n\t{\n\t\t$$ = &ast.TableOptimizerHint{\n\t\t\tHintName:  model.NewCIStr($1),\n\t\t\tQBName:    model.NewCIStr($3),\n\t\t\tQueryType: model.NewCIStr($4),\n\t\t}\n\t}\n\nStorageOptimizerHintOpt:\n\t\"READ_FROM_STORAGE\" '(' QueryBlockOpt HintStorageTypeAndTableList ')'\n\t{\n\t\ths := $4\n\t\tname := model.NewCIStr($1)\n\t\tqb := model.NewCIStr($3)\n\t\tfor _, h := range hs {\n\t\t\th.HintName = name\n\t\t\th.QBName = qb\n\t\t}\n\t\t$$ = hs\n\t}\n\nHintStorageTypeAndTableList:\n\tHintStorageTypeAndTable\n\t{\n\t\t$$ = []*ast.TableOptimizerHint{$1}\n\t}\n|\tHintStorageTypeAndTableList ',' HintStorageTypeAndTable\n\t{\n\t\t$$ = append($1, $3)\n\t}\n\nHintStorageTypeAndTable:\n\tHintStorageType '[' HintTableList ']'\n\t{\n\t\th := $3\n\t\th.StoreType = model.NewCIStr($1)\n\t\t$$ = h\n\t}\n\nQueryBlockOpt:\n\t/* empty */\n\t{\n\t\t$$ = \"\"\n\t}\n|\thintSingleAtIdentifier\n\nCommaOpt:\n\t/*empty*/\n\t{}\n|\t','\n\t{}\n\n/**\n * HintTableListOpt:\n *\n *\t[@query_block_name] [tbl_name [, tbl_name] ...]\n *\t[tbl_name@query_block_name [, tbl_name@query_block_name] ...]\n *\n */\nHintTableListOpt:\n\tHintTableList\n|\tQueryBlockOpt\n\t{\n\t\t$$ = &ast.TableOptimizerHint{\n\t\t\tQBName: model.NewCIStr($1),\n\t\t}\n\t}\n\nHintTableList:\n\tQueryBlockOpt HintTable\n\t{\n\t\t$$ = &ast.TableOptimizerHint{\n\t\t\tTables: []ast.HintTable{$2},\n\t\t\tQBName: model.NewCIStr($1),\n\t\t}\n\t}\n|\tHintTableList ',' HintTable\n\t{\n\t\th := $1\n\t\th.Tables = append(h.Tables, $3)\n\t\t$$ = h\n\t}\n\nHintTable:\n\tIdentifier QueryBlockOpt\n\t{\n\t\t$$ = ast.HintTable{\n\t\t\tTableName: model.NewCIStr($1),\n\t\t\tQBName:    model.NewCIStr($2),\n\t\t}\n\t}\n|\tIdentifier '.' Identifier QueryBlockOpt\n\t{\n\t\t$$ = ast.HintTable{\n\t\t\tDBName:    model.NewCIStr($1),\n\t\t\tTableName: model.NewCIStr($3),\n\t\t\tQBName:    model.NewCIStr($4),\n\t\t}\n\t}\n\n/**\n * HintIndexList:\n *\n *\t[@query_block_name] tbl_name [index_name [, index_name] ...]\n *\ttbl_name@query_block_name [index_name [, index_name] ...]\n */\nHintIndexList:\n\tQueryBlockOpt HintTable CommaOpt IndexNameListOpt\n\t{\n\t\th := $4\n\t\th.Tables = []ast.HintTable{$2}\n\t\th.QBName = model.NewCIStr($1)\n\t\t$$ = h\n\t}\n\nIndexNameListOpt:\n\t/* empty */\n\t{\n\t\t$$ = &ast.TableOptimizerHint{}\n\t}\n|\tIndexNameList\n\nIndexNameList:\n\tIdentifier\n\t{\n\t\t$$ = &ast.TableOptimizerHint{\n\t\t\tIndexes: []model.CIStr{model.NewCIStr($1)},\n\t\t}\n\t}\n|\tIndexNameList ',' Identifier\n\t{\n\t\th := $1\n\t\th.Indexes = append(h.Indexes, model.NewCIStr($3))\n\t\t$$ = h\n\t}\n\n/**\n * Miscellaneous rules\n */\nSubqueryStrategiesOpt:\n\t/* empty */\n\t{}\n|\tSubqueryStrategies\n\nSubqueryStrategies:\n\tSubqueryStrategy\n\t{}\n|\tSubqueryStrategies ',' SubqueryStrategy\n\nValue:\n\thintStringLit\n|\tIdentifier\n|\thintIntLit\n\t{\n\t\t$$ = strconv.FormatUint($1, 10)\n\t}\n\nUnitOfBytes:\n\t\"MB\"\n\t{\n\t\t$$ = 1024 * 1024\n\t}\n|\t\"GB\"\n\t{\n\t\t$$ = 1024 * 1024 * 1024\n\t}\n\nHintTrueOrFalse:\n\t\"TRUE\"\n\t{\n\t\t$$ = &ast.TableOptimizerHint{HintFlag: true}\n\t}\n|\t\"FALSE\"\n\t{\n\t\t$$ = &ast.TableOptimizerHint{HintFlag: false}\n\t}\n\nJoinOrderOptimizerHintName:\n\t\"JOIN_ORDER\"\n|\t\"JOIN_PREFIX\"\n|\t\"JOIN_SUFFIX\"\n\nUnsupportedTableLevelOptimizerHintName:\n\t\"BKA\"\n|\t\"NO_BKA\"\n|\t\"BNL\"\n|\t\"NO_BNL\"\n/* HASH_JOIN is supported by TiDB */\n|\t\"NO_HASH_JOIN\"\n|\t\"MERGE\"\n|\t\"NO_MERGE\"\n\nSupportedTableLevelOptimizerHintName:\n\t\"SM_JOIN\"\n|\t\"INL_JOIN\"\n|\t\"INL_HASH_JOIN\"\n|\t\"SWAP_JOIN_INPUTS\"\n|\t\"NO_SWAP_JOIN_INPUTS\"\n|\t\"INL_MERGE_JOIN\"\n|\t\"HASH_JOIN\"\n\nUnsupportedIndexLevelOptimizerHintName:\n\t\"INDEX_MERGE\"\n/* NO_INDEX_MERGE is currently a nullary hint in TiDB */\n|\t\"MRR\"\n|\t\"NO_MRR\"\n|\t\"NO_ICP\"\n|\t\"NO_RANGE_OPTIMIZATION\"\n|\t\"SKIP_SCAN\"\n|\t\"NO_SKIP_SCAN\"\n\nSupportedIndexLevelOptimizerHintName:\n\t\"USE_INDEX\"\n|\t\"IGNORE_INDEX\"\n|\t\"USE_INDEX_MERGE\"\n\nSubqueryOptimizerHintName:\n\t\"SEMIJOIN\"\n|\t\"NO_SEMIJOIN\"\n\nSubqueryStrategy:\n\t\"DUPSWEEDOUT\"\n|\t\"FIRSTMATCH\"\n|\t\"LOOSESCAN\"\n|\t\"MATERIALIZATION\"\n\nBooleanHintName:\n\t\"USE_TOJA\"\n|\t\"ENABLE_PLAN_CACHE\"\n\nNullaryHintName:\n\t\"USE_PLAN_CACHE\"\n|\t\"HASH_AGG\"\n|\t\"STREAM_AGG\"\n|\t\"AGG_TO_COP\"\n|\t\"NO_INDEX_MERGE\"\n|\t\"READ_CONSISTENT_REPLICA\"\n\nHintQueryType:\n\t\"OLAP\"\n|\t\"OLTP\"\n\nHintStorageType:\n\t\"TIKV\"\n|\t\"TIFLASH\"\n\nIdentifier:\n\thintIdentifier\n/* MySQL 8.0 hint names */\n|\t\"JOIN_FIXED_ORDER\"\n|\t\"JOIN_ORDER\"\n|\t\"JOIN_PREFIX\"\n|\t\"JOIN_SUFFIX\"\n|\t\"BKA\"\n|\t\"NO_BKA\"\n|\t\"BNL\"\n|\t\"NO_BNL\"\n|\t\"HASH_JOIN\"\n|\t\"NO_HASH_JOIN\"\n|\t\"MERGE\"\n|\t\"NO_MERGE\"\n|\t\"INDEX_MERGE\"\n|\t\"NO_INDEX_MERGE\"\n|\t\"MRR\"\n|\t\"NO_MRR\"\n|\t\"NO_ICP\"\n|\t\"NO_RANGE_OPTIMIZATION\"\n|\t\"SKIP_SCAN\"\n|\t\"NO_SKIP_SCAN\"\n|\t\"SEMIJOIN\"\n|\t\"NO_SEMIJOIN\"\n|\t\"MAX_EXECUTION_TIME\"\n|\t\"SET_VAR\"\n|\t\"RESOURCE_GROUP\"\n|\t\"QB_NAME\"\n/* TiDB hint names */\n|\t\"AGG_TO_COP\"\n|\t\"ENABLE_PLAN_CACHE\"\n|\t\"HASH_AGG\"\n|\t\"IGNORE_INDEX\"\n|\t\"INL_HASH_JOIN\"\n|\t\"INL_JOIN\"\n|\t\"INL_MERGE_JOIN\"\n|\t\"MEMORY_QUOTA\"\n|\t\"NO_SWAP_JOIN_INPUTS\"\n|\t\"QUERY_TYPE\"\n|\t\"READ_CONSISTENT_REPLICA\"\n|\t\"READ_FROM_STORAGE\"\n|\t\"SM_JOIN\"\n|\t\"STREAM_AGG\"\n|\t\"SWAP_JOIN_INPUTS\"\n|\t\"USE_INDEX_MERGE\"\n|\t\"USE_INDEX\"\n|\t\"USE_PLAN_CACHE\"\n|\t\"USE_TOJA\"\n/* other keywords */\n|\t\"OLAP\"\n|\t\"OLTP\"\n|\t\"TIKV\"\n|\t\"TIFLASH\"\n|\t\"FALSE\"\n|\t\"TRUE\"\n|\t\"MB\"\n|\t\"GB\"\n|\t\"DUPSWEEDOUT\"\n|\t\"FIRSTMATCH\"\n|\t\"LOOSESCAN\"\n|\t\"MATERIALIZATION\"\n%%\n"
  },
  {
    "path": "pkg/parser/hintparser_test.go",
    "content": "// Copyright 2020 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser_test\n\nimport (\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n)\n\nvar _ = Suite(&testHintParserSuite{})\n\ntype testHintParserSuite struct{}\n\nfunc (s *testHintParserSuite) TestParseHint(c *C) {\n\ttestCases := []struct {\n\t\tinput  string\n\t\tmode   mysql.SQLMode\n\t\toutput []*ast.TableOptimizerHint\n\t\terrs   []string\n\t}{\n\t\t{\n\t\t\tinput: \"\",\n\t\t\terrs:  []string{`.*Optimizer hint syntax error at line 1 .*`},\n\t\t},\n\t\t{\n\t\t\tinput: \"MEMORY_QUOTA(8 MB) MEMORY_QUOTA(6 GB)\",\n\t\t\toutput: []*ast.TableOptimizerHint{\n\t\t\t\t{\n\t\t\t\t\tHintName:    model.NewCIStr(\"MEMORY_QUOTA\"),\n\t\t\t\t\tMemoryQuota: int64(8 * 1024 * 1024),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName:    model.NewCIStr(\"MEMORY_QUOTA\"),\n\t\t\t\t\tMemoryQuota: int64(6 * 1024 * 1024 * 1024),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"QB_NAME(qb1) QB_NAME(`qb2`), QB_NAME(TRUE) QB_NAME(\\\"ANSI quoted\\\") QB_NAME(_utf8), QB_NAME(0b10) QB_NAME(0x1a)\",\n\t\t\tmode:  mysql.ModeANSIQuotes,\n\t\t\toutput: []*ast.TableOptimizerHint{\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"QB_NAME\"),\n\t\t\t\t\tQBName:   model.NewCIStr(\"qb1\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"QB_NAME\"),\n\t\t\t\t\tQBName:   model.NewCIStr(\"qb2\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"QB_NAME\"),\n\t\t\t\t\tQBName:   model.NewCIStr(\"TRUE\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"QB_NAME\"),\n\t\t\t\t\tQBName:   model.NewCIStr(\"ANSI quoted\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"QB_NAME\"),\n\t\t\t\t\tQBName:   model.NewCIStr(\"_utf8\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"QB_NAME\"),\n\t\t\t\t\tQBName:   model.NewCIStr(\"0b10\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"QB_NAME\"),\n\t\t\t\t\tQBName:   model.NewCIStr(\"0x1a\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"QB_NAME(1)\",\n\t\t\terrs:  []string{`.*Optimizer hint syntax error at line 1 .*`},\n\t\t},\n\t\t{\n\t\t\tinput: \"QB_NAME('string literal')\",\n\t\t\terrs:  []string{`.*Optimizer hint syntax error at line 1 .*`},\n\t\t},\n\t\t{\n\t\t\tinput: \"QB_NAME(many identifiers)\",\n\t\t\terrs:  []string{`.*Optimizer hint syntax error at line 1 .*`},\n\t\t},\n\t\t{\n\t\t\tinput: \"QB_NAME(@qb1)\",\n\t\t\terrs:  []string{`.*Optimizer hint syntax error at line 1 .*`},\n\t\t},\n\t\t{\n\t\t\tinput: \"QB_NAME(b'10')\",\n\t\t\terrs: []string{\n\t\t\t\t`.*Cannot use bit-value literal.*`,\n\t\t\t\t`.*Optimizer hint syntax error at line 1 .*`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"QB_NAME(x'1a')\",\n\t\t\terrs: []string{\n\t\t\t\t`.*Cannot use hexadecimal literal.*`,\n\t\t\t\t`.*Optimizer hint syntax error at line 1 .*`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"JOIN_FIXED_ORDER() BKA()\",\n\t\t\terrs: []string{\n\t\t\t\t`.*Optimizer hint JOIN_FIXED_ORDER is not supported.*`,\n\t\t\t\t`.*Optimizer hint BKA is not supported.*`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"HASH_JOIN() TIDB_HJ(@qb1) INL_JOIN(x, `y y`.z) sm_join(w@`First QB`)\",\n\t\t\toutput: []*ast.TableOptimizerHint{\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"HASH_JOIN\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"TIDB_HJ\"),\n\t\t\t\t\tQBName:   model.NewCIStr(\"qb1\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"INL_JOIN\"),\n\t\t\t\t\tTables: []ast.HintTable{\n\t\t\t\t\t\t{TableName: model.NewCIStr(\"x\")},\n\t\t\t\t\t\t{DBName: model.NewCIStr(\"y y\"), TableName: model.NewCIStr(\"z\")},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"sm_join\"),\n\t\t\t\t\tTables: []ast.HintTable{\n\t\t\t\t\t\t{TableName: model.NewCIStr(\"w\"), QBName: model.NewCIStr(\"First QB\")},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"USE_INDEX_MERGE(@qb1 tbl1 x, y, z) IGNORE_INDEX(tbl2@qb2) USE_INDEX(tbl3 PRIMARY)\",\n\t\t\toutput: []*ast.TableOptimizerHint{\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"USE_INDEX_MERGE\"),\n\t\t\t\t\tTables:   []ast.HintTable{{TableName: model.NewCIStr(\"tbl1\")}},\n\t\t\t\t\tQBName:   model.NewCIStr(\"qb1\"),\n\t\t\t\t\tIndexes:  []model.CIStr{model.NewCIStr(\"x\"), model.NewCIStr(\"y\"), model.NewCIStr(\"z\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"IGNORE_INDEX\"),\n\t\t\t\t\tTables:   []ast.HintTable{{TableName: model.NewCIStr(\"tbl2\"), QBName: model.NewCIStr(\"qb2\")}},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"USE_INDEX\"),\n\t\t\t\t\tTables:   []ast.HintTable{{TableName: model.NewCIStr(\"tbl3\")}},\n\t\t\t\t\tIndexes:  []model.CIStr{model.NewCIStr(\"PRIMARY\")},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: `SET_VAR(sbs = 16M) SET_VAR(fkc=OFF) SET_VAR(os=\"mcb=off\") set_var(abc=1)`,\n\t\t\terrs: []string{\n\t\t\t\t`.*Optimizer hint SET_VAR is not supported.*`,\n\t\t\t\t`.*Optimizer hint SET_VAR is not supported.*`,\n\t\t\t\t`.*Optimizer hint SET_VAR is not supported.*`,\n\t\t\t\t`.*Optimizer hint set_var is not supported.*`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"USE_TOJA(TRUE) ENABLE_PLAN_CACHE(FALSE) QUERY_TYPE(@qb1 OLAP) QUERY_TYPE(OLTP) NO_INDEX_MERGE()\",\n\t\t\toutput: []*ast.TableOptimizerHint{\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"USE_TOJA\"),\n\t\t\t\t\tHintFlag: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"ENABLE_PLAN_CACHE\"),\n\t\t\t\t\tHintFlag: false,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName:  model.NewCIStr(\"QUERY_TYPE\"),\n\t\t\t\t\tQBName:    model.NewCIStr(\"qb1\"),\n\t\t\t\t\tQueryType: model.NewCIStr(\"OLAP\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName:  model.NewCIStr(\"QUERY_TYPE\"),\n\t\t\t\t\tQueryType: model.NewCIStr(\"OLTP\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"NO_INDEX_MERGE\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"READ_FROM_STORAGE(@foo TIKV[a, b], TIFLASH[c, d]) HASH_AGG() READ_FROM_STORAGE(TIKV[e])\",\n\t\t\toutput: []*ast.TableOptimizerHint{\n\t\t\t\t{\n\t\t\t\t\tHintName:  model.NewCIStr(\"READ_FROM_STORAGE\"),\n\t\t\t\t\tStoreType: model.NewCIStr(\"TIKV\"),\n\t\t\t\t\tQBName:    model.NewCIStr(\"foo\"),\n\t\t\t\t\tTables: []ast.HintTable{\n\t\t\t\t\t\t{TableName: model.NewCIStr(\"a\")},\n\t\t\t\t\t\t{TableName: model.NewCIStr(\"b\")},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName:  model.NewCIStr(\"READ_FROM_STORAGE\"),\n\t\t\t\t\tStoreType: model.NewCIStr(\"TIFLASH\"),\n\t\t\t\t\tQBName:    model.NewCIStr(\"foo\"),\n\t\t\t\t\tTables: []ast.HintTable{\n\t\t\t\t\t\t{TableName: model.NewCIStr(\"c\")},\n\t\t\t\t\t\t{TableName: model.NewCIStr(\"d\")},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName: model.NewCIStr(\"HASH_AGG\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tHintName:  model.NewCIStr(\"READ_FROM_STORAGE\"),\n\t\t\t\t\tStoreType: model.NewCIStr(\"TIKV\"),\n\t\t\t\t\tTables: []ast.HintTable{\n\t\t\t\t\t\t{TableName: model.NewCIStr(\"e\")},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"unknown_hint()\",\n\t\t\terrs:  []string{`.*Optimizer hint syntax error at line 1 .*`},\n\t\t},\n\t\t{\n\t\t\tinput: \"set_var(timestamp = 1.5)\",\n\t\t\terrs: []string{\n\t\t\t\t`.*Cannot use decimal number.*`,\n\t\t\t\t`.*Optimizer hint syntax error at line 1 .*`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"set_var(timestamp = _utf8mb4'1234')\", // Optimizer hint doesn't recognize _charset'strings'.\n\t\t\terrs:  []string{`.*Optimizer hint syntax error at line 1 .*`},\n\t\t},\n\t\t{\n\t\t\tinput: \"set_var(timestamp = 9999999999999999999999999999999999999)\",\n\t\t\terrs: []string{\n\t\t\t\t`.*integer value is out of range.*`,\n\t\t\t\t`.*Optimizer hint syntax error at line 1 .*`,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\toutput, errs := parser.ParseHint(\"/*+\"+tc.input+\"*/\", tc.mode, parser.Pos{Line: 1})\n\t\tc.Assert(errs, HasLen, len(tc.errs), Commentf(\"input = %s,\\n... errs = %q\", tc.input, errs))\n\t\tfor i, err := range errs {\n\t\t\tc.Assert(err, ErrorMatches, tc.errs[i], Commentf(\"input = %s, i = %d\", tc.input, i))\n\t\t}\n\t\tc.Assert(output, DeepEquals, tc.output, Commentf(\"input = %s,\\n... output = %q\", tc.input, output))\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/hintparserimpl.go",
    "content": "// Copyright 2020 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n)\n\nvar (\n\tErrWarnOptimizerHintUnsupportedHint = terror.ClassParser.New(mysql.ErrWarnOptimizerHintUnsupportedHint, mysql.MySQLErrName[mysql.ErrWarnOptimizerHintUnsupportedHint])\n\tErrWarnOptimizerHintInvalidToken    = terror.ClassParser.New(mysql.ErrWarnOptimizerHintInvalidToken, mysql.MySQLErrName[mysql.ErrWarnOptimizerHintInvalidToken])\n\tErrWarnMemoryQuotaOverflow          = terror.ClassParser.New(mysql.ErrWarnMemoryQuotaOverflow, mysql.MySQLErrName[mysql.ErrWarnMemoryQuotaOverflow])\n\tErrWarnOptimizerHintParseError      = terror.ClassParser.New(mysql.ErrWarnOptimizerHintParseError, mysql.MySQLErrName[mysql.ErrWarnOptimizerHintParseError])\n\tErrWarnOptimizerHintInvalidInteger  = terror.ClassParser.New(mysql.ErrWarnOptimizerHintInvalidInteger, mysql.MySQLErrName[mysql.ErrWarnOptimizerHintInvalidInteger])\n)\n\n// hintScanner implements the yyhintLexer interface\ntype hintScanner struct {\n\tScanner\n}\n\nfunc (hs *hintScanner) Errorf(format string, args ...interface{}) error {\n\tinner := hs.Scanner.Errorf(format, args...)\n\treturn ErrWarnOptimizerHintParseError.GenWithStackByArgs(inner)\n}\n\nfunc (hs *hintScanner) Lex(lval *yyhintSymType) int {\n\ttok, pos, lit := hs.scan()\n\ths.lastScanOffset = pos.Offset\n\tvar errorTokenType string\n\n\tswitch tok {\n\tcase intLit:\n\t\tn, e := strconv.ParseUint(lit, 10, 64)\n\t\tif e != nil {\n\t\t\ths.AppendError(ErrWarnOptimizerHintInvalidInteger.GenWithStackByArgs(lit))\n\t\t\treturn int(unicode.ReplacementChar)\n\t\t}\n\t\tlval.number = n\n\t\treturn hintIntLit\n\n\tcase singleAtIdentifier:\n\t\tlval.ident = lit\n\t\treturn hintSingleAtIdentifier\n\n\tcase identifier:\n\t\tlval.ident = lit\n\t\tif tok1, ok := hintTokenMap[strings.ToUpper(lit)]; ok {\n\t\t\treturn tok1\n\t\t}\n\t\treturn hintIdentifier\n\n\tcase stringLit:\n\t\tlval.ident = lit\n\t\tif hs.sqlMode.HasANSIQuotesMode() && hs.r.s[pos.Offset] == '\"' {\n\t\t\treturn hintIdentifier\n\t\t}\n\t\treturn hintStringLit\n\n\tcase bitLit:\n\t\tif strings.HasPrefix(lit, \"0b\") {\n\t\t\tlval.ident = lit\n\t\t\treturn hintIdentifier\n\t\t}\n\t\terrorTokenType = \"bit-value literal\"\n\n\tcase hexLit:\n\t\tif strings.HasPrefix(lit, \"0x\") {\n\t\t\tlval.ident = lit\n\t\t\treturn hintIdentifier\n\t\t}\n\t\terrorTokenType = \"hexadecimal literal\"\n\n\tcase quotedIdentifier:\n\t\tlval.ident = lit\n\t\treturn hintIdentifier\n\n\tcase eq:\n\t\treturn '='\n\n\tcase floatLit:\n\t\terrorTokenType = \"floating point number\"\n\tcase decLit:\n\t\terrorTokenType = \"decimal number\"\n\n\tdefault:\n\t\tif tok <= 0x7f {\n\t\t\treturn tok\n\t\t}\n\t\terrorTokenType = \"unknown token\"\n\t}\n\n\ths.AppendError(ErrWarnOptimizerHintInvalidToken.GenWithStackByArgs(errorTokenType, lit, tok))\n\treturn int(unicode.ReplacementChar)\n}\n\ntype hintParser struct {\n\tlexer  hintScanner\n\tresult []*ast.TableOptimizerHint\n\n\t// the following fields are used by yyParse to reduce allocation.\n\tcache  []yyhintSymType\n\tyylval yyhintSymType\n\tyyVAL  *yyhintSymType\n}\n\nfunc newHintParser() *hintParser {\n\treturn &hintParser{cache: make([]yyhintSymType, 50)}\n}\n\nfunc (hp *hintParser) parse(input string, sqlMode mysql.SQLMode, initPos Pos) ([]*ast.TableOptimizerHint, []error) {\n\thp.result = nil\n\thp.lexer.reset(input[3:])\n\thp.lexer.SetSQLMode(sqlMode)\n\thp.lexer.r.p = Pos{\n\t\tLine:   initPos.Line,\n\t\tCol:    initPos.Col + 3, // skipped the initial '/*+'\n\t\tOffset: 0,\n\t}\n\thp.lexer.inBangComment = true // skip the final '*/' (we need the '*/' for reporting warnings)\n\n\tyyhintParse(&hp.lexer, hp)\n\n\twarns, errs := hp.lexer.Errors()\n\tif len(errs) == 0 {\n\t\terrs = warns\n\t}\n\treturn hp.result, errs\n}\n\n// ParseHint parses an optimizer hint (the interior of `/*+ ... */`).\nfunc ParseHint(input string, sqlMode mysql.SQLMode, initPos Pos) ([]*ast.TableOptimizerHint, []error) {\n\thp := newHintParser()\n\treturn hp.parse(input, sqlMode, initPos)\n}\n\nfunc (hp *hintParser) warnUnsupportedHint(name string) {\n\twarn := ErrWarnOptimizerHintUnsupportedHint.GenWithStackByArgs(name)\n\thp.lexer.warns = append(hp.lexer.warns, warn)\n}\n\nfunc (hp *hintParser) lastErrorAsWarn() {\n\thp.lexer.lastErrorAsWarn()\n}\n"
  },
  {
    "path": "pkg/parser/lexer.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n)\n\nvar _ = yyLexer(&Scanner{})\n\n// Pos represents the position of a token.\ntype Pos struct {\n\tLine   int\n\tCol    int\n\tOffset int\n}\n\n// Scanner implements the yyLexer interface.\ntype Scanner struct {\n\tr   reader\n\tbuf bytes.Buffer\n\n\terrs         []error\n\twarns        []error\n\tstmtStartPos int\n\n\t// inBangComment is true if we are inside a `/*! ... */` block.\n\t// It is used to ignore a stray `*/` when scanning.\n\tinBangComment bool\n\n\tsqlMode mysql.SQLMode\n\n\t// If the lexer should recognize keywords for window function.\n\t// It may break the compatibility when support those keywords,\n\t// because some application may already use them as identifiers.\n\tsupportWindowFunc bool\n\n\t// lastScanOffset indicates last offset returned by scan().\n\t// It's used to substring sql in syntax error message.\n\tlastScanOffset int\n\n\t// lastKeyword records the previous keyword returned by scan().\n\t// determine whether an optimizer hint should be parsed or ignored.\n\tlastKeyword int\n\n\t// hintPos records the start position of the previous optimizer hint.\n\tlastHintPos Pos\n}\n\n// Errors returns the errors and warns during a scan.\nfunc (s *Scanner) Errors() (warns []error, errs []error) {\n\treturn s.warns, s.errs\n}\n\n// reset resets the sql string to be scanned.\nfunc (s *Scanner) reset(sql string) {\n\ts.r = reader{s: sql, p: Pos{Line: 1}}\n\ts.buf.Reset()\n\ts.errs = s.errs[:0]\n\ts.warns = s.warns[:0]\n\ts.stmtStartPos = 0\n\ts.inBangComment = false\n\ts.lastKeyword = 0\n}\n\nfunc (s *Scanner) stmtText() string {\n\tendPos := s.r.pos().Offset\n\tif s.r.s[endPos-1] == '\\n' {\n\t\tendPos = endPos - 1 // trim new line\n\t}\n\tif s.r.s[s.stmtStartPos] == '\\n' {\n\t\ts.stmtStartPos++\n\t}\n\n\ttext := s.r.s[s.stmtStartPos:endPos]\n\n\ts.stmtStartPos = endPos\n\treturn text\n}\n\n// Errorf tells scanner something is wrong.\n// Scanner satisfies yyLexer interface which need this function.\nfunc (s *Scanner) Errorf(format string, a ...interface{}) (err error) {\n\tstr := fmt.Sprintf(format, a...)\n\tval := s.r.s[s.lastScanOffset:]\n\tvar lenStr = \"\"\n\tif len(val) > 2048 {\n\t\tlenStr = \"(total length \" + strconv.Itoa(len(val)) + \")\"\n\t\tval = val[:2048]\n\t}\n\terr = fmt.Errorf(\"line %d column %d near \\\"%s\\\"%s %s\",\n\t\ts.r.p.Line, s.r.p.Col, val, str, lenStr)\n\treturn\n}\n\n// AppendError sets error into scanner.\n// Scanner satisfies yyLexer interface which need this function.\nfunc (s *Scanner) AppendError(err error) {\n\tif err == nil {\n\t\treturn\n\t}\n\ts.errs = append(s.errs, err)\n}\n\n// Lex returns a token and store the token value in v.\n// Scanner satisfies yyLexer interface.\n// 0 and invalid are special token id this function would return:\n// return 0 tells parser that scanner meets EOF,\n// return invalid tells parser that scanner meets illegal character.\nfunc (s *Scanner) Lex(v *yySymType) int {\n\ttok, pos, lit := s.scan()\n\ts.lastScanOffset = pos.Offset\n\ts.lastKeyword = 0\n\tv.offset = pos.Offset\n\tv.ident = lit\n\tif tok == identifier {\n\t\ttok = handleIdent(v)\n\t}\n\tif tok == identifier {\n\t\tif tok1 := s.isTokenIdentifier(lit, pos.Offset); tok1 != 0 {\n\t\t\ttok = tok1\n\t\t\ts.lastKeyword = tok1\n\t\t}\n\t}\n\tif s.sqlMode.HasANSIQuotesMode() &&\n\t\ttok == stringLit &&\n\t\ts.r.s[v.offset] == '\"' {\n\t\ttok = identifier\n\t}\n\n\tif tok == pipes && !(s.sqlMode.HasPipesAsConcatMode()) {\n\t\treturn pipesAsOr\n\t}\n\n\tif tok == not && s.sqlMode.HasHighNotPrecedenceMode() {\n\t\treturn not2\n\t}\n\n\tswitch tok {\n\tcase intLit:\n\t\treturn toInt(s, v, lit)\n\tcase floatLit:\n\t\treturn toFloat(s, v, lit)\n\tcase decLit:\n\t\treturn toDecimal(s, v, lit)\n\tcase hexLit:\n\t\treturn toHex(s, v, lit)\n\tcase bitLit:\n\t\treturn toBit(s, v, lit)\n\tcase singleAtIdentifier, doubleAtIdentifier, cast, extract:\n\t\tv.item = lit\n\t\treturn tok\n\tcase null:\n\t\tv.item = nil\n\tcase quotedIdentifier:\n\t\ttok = identifier\n\t}\n\n\tif tok == unicode.ReplacementChar {\n\t\treturn invalid\n\t}\n\n\treturn tok\n}\n\n// SetSQLMode sets the SQL mode for scanner.\nfunc (s *Scanner) SetSQLMode(mode mysql.SQLMode) {\n\ts.sqlMode = mode\n}\n\n// GetSQLMode return the SQL mode of scanner.\nfunc (s *Scanner) GetSQLMode() mysql.SQLMode {\n\treturn s.sqlMode\n}\n\n// EnableWindowFunc controls whether the scanner recognize the keywords of window function.\nfunc (s *Scanner) EnableWindowFunc(val bool) {\n\ts.supportWindowFunc = val\n}\n\n// InheritScanner returns a new scanner object which inherits configurations from the parent scanner.\nfunc (s *Scanner) InheritScanner(sql string) *Scanner {\n\treturn &Scanner{\n\t\tr:                 reader{s: sql},\n\t\tsqlMode:           s.sqlMode,\n\t\tsupportWindowFunc: s.supportWindowFunc,\n\t}\n}\n\n// NewScanner returns a new scanner object.\nfunc NewScanner(s string) *Scanner {\n\treturn &Scanner{r: reader{s: s}}\n}\n\nfunc (s *Scanner) skipWhitespace() rune {\n\treturn s.r.incAsLongAs(unicode.IsSpace)\n}\n\nfunc (s *Scanner) scan() (tok int, pos Pos, lit string) {\n\tch0 := s.r.peek()\n\tif unicode.IsSpace(ch0) {\n\t\tch0 = s.skipWhitespace()\n\t}\n\tpos = s.r.pos()\n\tif s.r.eof() {\n\t\t// when scanner meets EOF, the returned token should be 0,\n\t\t// because 0 is a special token id to remind the parser that stream is end.\n\t\treturn 0, pos, \"\"\n\t}\n\n\tif !s.r.eof() && isIdentExtend(ch0) {\n\t\treturn scanIdentifier(s)\n\t}\n\n\t// search a trie to get a token.\n\tnode := &ruleTable\n\tfor ch0 >= 0 && ch0 <= 255 {\n\t\tif node.childs[ch0] == nil || s.r.eof() {\n\t\t\tbreak\n\t\t}\n\t\tnode = node.childs[ch0]\n\t\tif node.fn != nil {\n\t\t\treturn node.fn(s)\n\t\t}\n\t\ts.r.inc()\n\t\tch0 = s.r.peek()\n\t}\n\n\ttok, lit = node.token, s.r.data(&pos)\n\treturn\n}\n\nfunc startWithXx(s *Scanner) (tok int, pos Pos, lit string) {\n\tpos = s.r.pos()\n\ts.r.inc()\n\tif s.r.peek() == '\\'' {\n\t\ts.r.inc()\n\t\ts.scanHex()\n\t\tif s.r.peek() == '\\'' {\n\t\t\ts.r.inc()\n\t\t\ttok, lit = hexLit, s.r.data(&pos)\n\t\t} else {\n\t\t\ttok = unicode.ReplacementChar\n\t\t}\n\t\treturn\n\t}\n\ts.r.incAsLongAs(isIdentChar)\n\ttok, lit = identifier, s.r.data(&pos)\n\treturn\n}\n\nfunc startWithNn(s *Scanner) (tok int, pos Pos, lit string) {\n\ttok, pos, lit = scanIdentifier(s)\n\t// The National Character Set, N'some text' or n'some test'.\n\t// See https://dev.mysql.com/doc/refman/5.7/en/string-literals.html\n\t// and https://dev.mysql.com/doc/refman/5.7/en/charset-national.html\n\tif lit == \"N\" || lit == \"n\" {\n\t\tif s.r.peek() == '\\'' {\n\t\t\ttok = underscoreCS\n\t\t\tlit = \"utf8\"\n\t\t}\n\t}\n\treturn\n}\n\nfunc startWithBb(s *Scanner) (tok int, pos Pos, lit string) {\n\tpos = s.r.pos()\n\ts.r.inc()\n\tif s.r.peek() == '\\'' {\n\t\ts.r.inc()\n\t\ts.scanBit()\n\t\tif s.r.peek() == '\\'' {\n\t\t\ts.r.inc()\n\t\t\ttok, lit = bitLit, s.r.data(&pos)\n\t\t} else {\n\t\t\ttok = unicode.ReplacementChar\n\t\t}\n\t\treturn\n\t}\n\ts.r.incAsLongAs(isIdentChar)\n\ttok, lit = identifier, s.r.data(&pos)\n\treturn\n}\n\nfunc startWithSharp(s *Scanner) (tok int, pos Pos, lit string) {\n\ts.r.incAsLongAs(func(ch rune) bool {\n\t\treturn ch != '\\n'\n\t})\n\treturn s.scan()\n}\n\nfunc startWithDash(s *Scanner) (tok int, pos Pos, lit string) {\n\tpos = s.r.pos()\n\tif strings.HasPrefix(s.r.s[pos.Offset:], \"--\") {\n\t\tremainLen := len(s.r.s[pos.Offset:])\n\t\tif remainLen == 2 || (remainLen > 2 && unicode.IsSpace(rune(s.r.s[pos.Offset+2]))) {\n\t\t\ts.r.incAsLongAs(func(ch rune) bool {\n\t\t\t\treturn ch != '\\n'\n\t\t\t})\n\t\t\treturn s.scan()\n\t\t}\n\t}\n\tif strings.HasPrefix(s.r.s[pos.Offset:], \"->>\") {\n\t\ttok = juss\n\t\ts.r.incN(3)\n\t\treturn\n\t}\n\tif strings.HasPrefix(s.r.s[pos.Offset:], \"->\") {\n\t\ttok = jss\n\t\ts.r.incN(2)\n\t\treturn\n\t}\n\ttok = int('-')\n\tlit = \"-\"\n\ts.r.inc()\n\treturn\n}\n\nfunc startWithSlash(s *Scanner) (tok int, pos Pos, lit string) {\n\tpos = s.r.pos()\n\ts.r.inc()\n\tif s.r.peek() != '*' {\n\t\ttok = int('/')\n\t\treturn\n\t}\n\n\tisOptimizerHint := false\n\tcurrentCharIsStar := false\n\n\ts.r.inc() // we see '/*' so far.\n\tswitch s.r.readByte() {\n\tcase '!': // '/*!' MySQL-specific comments\n\t\t// See http://dev.mysql.com/doc/refman/5.7/en/comments.html\n\t\t// in '/*!', which we always recognize regardless of version.\n\t\t_ = s.scanVersionDigits(5, 5)\n\t\ts.inBangComment = true\n\t\treturn s.scan()\n\n\tcase 'T': // '/*T' maybe TiDB-specific comments\n\t\tif s.r.peek() != '!' {\n\t\t\t// '/*TX' is just normal comment.\n\t\t\tbreak\n\t\t}\n\t\ts.r.inc()\n\t\t// in '/*T!', try to consume the 5 to 6 digit version string.\n\t\tcommentVersion := s.scanVersionDigits(5, 6)\n\t\tif commentVersion <= CommentCodeCurrentVersion {\n\t\t\ts.inBangComment = true\n\t\t\treturn s.scan()\n\t\t}\n\n\tcase 'M': // '/*M' maybe MariaDB-specific comments\n\t\t// no special treatment for now.\n\t\tbreak\n\n\tcase '+': // '/*+' optimizer hints\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/optimizer-hints.html\n\t\tif _, ok := hintedTokens[s.lastKeyword]; ok {\n\t\t\t// only recognize optimizers hints directly followed by certain\n\t\t\t// keywords like SELECT, INSERT, etc.\n\t\t\tisOptimizerHint = true\n\t\t}\n\n\tcase '*': // '/**' if the next char is '/' it would close the comment.\n\t\tcurrentCharIsStar = true\n\n\tdefault:\n\t\tbreak\n\t}\n\n\t// standard C-like comment. read until we see '*/' then drop it.\n\tfor {\n\t\tif currentCharIsStar || s.r.incAsLongAs(func(ch rune) bool { return ch != '*' }) == '*' {\n\t\t\tswitch s.r.readByte() {\n\t\t\tcase '/':\n\t\t\t\t// Meets */, means comment end.\n\t\t\t\tif isOptimizerHint {\n\t\t\t\t\ts.lastHintPos = pos\n\t\t\t\t\treturn hintComment, pos, s.r.data(&pos)\n\t\t\t\t} else {\n\t\t\t\t\treturn s.scan()\n\t\t\t\t}\n\t\t\tcase 0:\n\t\t\t\tbreak\n\t\t\tcase '*':\n\t\t\t\tcurrentCharIsStar = true\n\t\t\t\tcontinue\n\t\t\tdefault:\n\t\t\t\tcurrentCharIsStar = false\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\t// unclosed comment or other errors.\n\t\ts.errs = append(s.errs, ParseErrorWith(s.r.data(&pos), s.r.p.Line))\n\t\treturn\n\t}\n}\n\nfunc startWithStar(s *Scanner) (tok int, pos Pos, lit string) {\n\tpos = s.r.pos()\n\ts.r.inc()\n\n\t// skip and exit '/*!' if we see '*/'\n\tif s.inBangComment && s.r.peek() == '/' {\n\t\ts.inBangComment = false\n\t\ts.r.inc()\n\t\treturn s.scan()\n\t}\n\t// otherwise it is just a normal star.\n\treturn '*', pos, \"*\"\n}\n\nfunc startWithAt(s *Scanner) (tok int, pos Pos, lit string) {\n\tpos = s.r.pos()\n\ts.r.inc()\n\n\ttok, lit = scanIdentifierOrString(s)\n\tswitch tok {\n\tcase '@':\n\t\ts.r.inc()\n\t\tstream := s.r.s[pos.Offset+2:]\n\t\tvar prefix string\n\t\tfor _, v := range []string{\"global.\", \"session.\", \"local.\"} {\n\t\t\tif len(v) > len(stream) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif strings.EqualFold(stream[:len(v)], v) {\n\t\t\t\tprefix = v\n\t\t\t\ts.r.incN(len(v))\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\ttok, lit = scanIdentifierOrString(s)\n\t\tswitch tok {\n\t\tcase stringLit, quotedIdentifier:\n\t\t\ttok, lit = doubleAtIdentifier, \"@@\"+prefix+lit\n\t\tcase identifier:\n\t\t\ttok, lit = doubleAtIdentifier, s.r.data(&pos)\n\t\t}\n\tcase unicode.ReplacementChar:\n\t\tbreak\n\tdefault:\n\t\ttok = singleAtIdentifier\n\t}\n\n\treturn\n}\n\nfunc scanIdentifier(s *Scanner) (int, Pos, string) {\n\tpos := s.r.pos()\n\ts.r.inc()\n\ts.r.incAsLongAs(isIdentChar)\n\treturn identifier, pos, s.r.data(&pos)\n}\n\nfunc scanIdentifierOrString(s *Scanner) (tok int, lit string) {\n\tch1 := s.r.peek()\n\tswitch ch1 {\n\tcase '\\'', '\"':\n\t\ttok, _, lit = startString(s)\n\tcase '`':\n\t\ttok, _, lit = scanQuotedIdent(s)\n\tdefault:\n\t\tif isUserVarChar(ch1) {\n\t\t\tpos := s.r.pos()\n\t\t\ts.r.incAsLongAs(isUserVarChar)\n\t\t\ttok, lit = identifier, s.r.data(&pos)\n\t\t} else {\n\t\t\ttok = int(ch1)\n\t\t}\n\t}\n\treturn\n}\n\nvar (\n\tquotedIdentifier = -identifier\n)\n\nfunc scanQuotedIdent(s *Scanner) (tok int, pos Pos, lit string) {\n\tpos = s.r.pos()\n\ts.r.inc()\n\ts.buf.Reset()\n\tfor {\n\t\tch := s.r.readByte()\n\t\tif ch == unicode.ReplacementChar && s.r.eof() {\n\t\t\ttok = unicode.ReplacementChar\n\t\t\treturn\n\t\t}\n\t\tif ch == '`' {\n\t\t\tif s.r.peek() != '`' {\n\t\t\t\t// don't return identifier in case that it's interpreted as keyword token later.\n\t\t\t\ttok, lit = quotedIdentifier, s.buf.String()\n\t\t\t\treturn\n\t\t\t}\n\t\t\ts.r.inc()\n\t\t}\n\t\ts.buf.WriteRune(ch)\n\t}\n}\n\nfunc startString(s *Scanner) (tok int, pos Pos, lit string) {\n\treturn s.scanString()\n}\n\n// lazyBuf is used to avoid allocation if possible.\n// it has a useBuf field indicates whether bytes.Buffer is necessary. if\n// useBuf is false, we can avoid calling bytes.Buffer.String(), which\n// make a copy of data and cause allocation.\ntype lazyBuf struct {\n\tuseBuf bool\n\tr      *reader\n\tb      *bytes.Buffer\n\tp      *Pos\n}\n\nfunc (mb *lazyBuf) setUseBuf(str string) {\n\tif !mb.useBuf {\n\t\tmb.useBuf = true\n\t\tmb.b.Reset()\n\t\tmb.b.WriteString(str)\n\t}\n}\n\nfunc (mb *lazyBuf) writeRune(r rune, w int) {\n\tif mb.useBuf {\n\t\tif w > 1 {\n\t\t\tmb.b.WriteRune(r)\n\t\t} else {\n\t\t\tmb.b.WriteByte(byte(r))\n\t\t}\n\t}\n}\n\nfunc (mb *lazyBuf) data() string {\n\tvar lit string\n\tif mb.useBuf {\n\t\tlit = mb.b.String()\n\t} else {\n\t\tlit = mb.r.data(mb.p)\n\t\tlit = lit[1 : len(lit)-1]\n\t}\n\treturn lit\n}\n\nfunc (s *Scanner) scanString() (tok int, pos Pos, lit string) {\n\ttok, pos = stringLit, s.r.pos()\n\tmb := lazyBuf{false, &s.r, &s.buf, &pos}\n\tending := s.r.readByte()\n\tch0 := s.r.peek()\n\tfor !s.r.eof() {\n\t\tif ch0 == ending {\n\t\t\ts.r.inc()\n\t\t\tif s.r.peek() != ending {\n\t\t\t\tlit = mb.data()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tstr := mb.r.data(&pos)\n\t\t\tmb.setUseBuf(str[1 : len(str)-1])\n\t\t} else if ch0 == '\\\\' && !s.sqlMode.HasNoBackslashEscapesMode() {\n\t\t\tmb.setUseBuf(mb.r.data(&pos)[1:])\n\t\t\tch0 = handleEscape(s)\n\t\t}\n\t\tmb.writeRune(ch0, s.r.w)\n\t\tif !s.r.eof() {\n\t\t\ts.r.inc()\n\t\t\tch0 = s.r.peek()\n\t\t}\n\t}\n\n\ttok = unicode.ReplacementChar\n\treturn\n}\n\n// handleEscape handles the case in scanString when previous char is '\\'.\nfunc handleEscape(s *Scanner) rune {\n\ts.r.inc()\n\tch0 := s.r.peek()\n\t/*\n\t\t\\\" \\' \\\\ \\n \\0 \\b \\Z \\r \\t ==> escape to one char\n\t\t\\% \\_ ==> preserve both char\n\t\tother ==> remove \\\n\t*/\n\tswitch ch0 {\n\tcase 'n':\n\t\tch0 = '\\n'\n\tcase '0':\n\t\tch0 = 0\n\tcase 'b':\n\t\tch0 = 8\n\tcase 'Z':\n\t\tch0 = 26\n\tcase 'r':\n\t\tch0 = '\\r'\n\tcase 't':\n\t\tch0 = '\\t'\n\tcase '%', '_':\n\t\ts.buf.WriteByte('\\\\')\n\t}\n\treturn ch0\n}\n\nfunc startWithNumber(s *Scanner) (tok int, pos Pos, lit string) {\n\tpos = s.r.pos()\n\ttok = intLit\n\tch0 := s.r.readByte()\n\tif ch0 == '0' {\n\t\ttok = intLit\n\t\tch1 := s.r.peek()\n\t\tswitch {\n\t\tcase ch1 >= '0' && ch1 <= '7':\n\t\t\ts.r.inc()\n\t\t\ts.scanOct()\n\t\tcase ch1 == 'x' || ch1 == 'X':\n\t\t\ts.r.inc()\n\t\t\tp1 := s.r.pos()\n\t\t\ts.scanHex()\n\t\t\tp2 := s.r.pos()\n\t\t\t// 0x, 0x7fz3 are identifier\n\t\t\tif p1 == p2 || isDigit(s.r.peek()) {\n\t\t\t\ts.r.incAsLongAs(isIdentChar)\n\t\t\t\treturn identifier, pos, s.r.data(&pos)\n\t\t\t}\n\t\t\ttok = hexLit\n\t\tcase ch1 == 'b':\n\t\t\ts.r.inc()\n\t\t\tp1 := s.r.pos()\n\t\t\ts.scanBit()\n\t\t\tp2 := s.r.pos()\n\t\t\t// 0b, 0b123, 0b1ab are identifier\n\t\t\tif p1 == p2 || isDigit(s.r.peek()) {\n\t\t\t\ts.r.incAsLongAs(isIdentChar)\n\t\t\t\treturn identifier, pos, s.r.data(&pos)\n\t\t\t}\n\t\t\ttok = bitLit\n\t\tcase ch1 == '.':\n\t\t\treturn s.scanFloat(&pos)\n\t\tcase ch1 == 'B':\n\t\t\ts.r.incAsLongAs(isIdentChar)\n\t\t\treturn identifier, pos, s.r.data(&pos)\n\t\t}\n\t}\n\n\ts.scanDigits()\n\tch0 = s.r.peek()\n\tif ch0 == '.' || ch0 == 'e' || ch0 == 'E' {\n\t\treturn s.scanFloat(&pos)\n\t}\n\n\t// Identifiers may begin with a digit but unless quoted may not consist solely of digits.\n\tif !s.r.eof() && isIdentChar(ch0) {\n\t\ts.r.incAsLongAs(isIdentChar)\n\t\treturn identifier, pos, s.r.data(&pos)\n\t}\n\tlit = s.r.data(&pos)\n\treturn\n}\n\nfunc startWithDot(s *Scanner) (tok int, pos Pos, lit string) {\n\tpos = s.r.pos()\n\ts.r.inc()\n\tsave := s.r.pos()\n\tif isDigit(s.r.peek()) {\n\t\ttok, _, lit = s.scanFloat(&pos)\n\t\tif s.r.eof() || !isIdentChar(s.r.peek()) {\n\t\t\treturn\n\t\t}\n\t\t// Fail to parse a float, reset to dot.\n\t\ts.r.p = save\n\t}\n\ttok, lit = int('.'), \".\"\n\treturn\n}\n\nfunc (s *Scanner) scanOct() {\n\ts.r.incAsLongAs(func(ch rune) bool {\n\t\treturn ch >= '0' && ch <= '7'\n\t})\n}\n\nfunc (s *Scanner) scanHex() {\n\ts.r.incAsLongAs(func(ch rune) bool {\n\t\treturn ch >= '0' && ch <= '9' ||\n\t\t\tch >= 'a' && ch <= 'f' ||\n\t\t\tch >= 'A' && ch <= 'F'\n\t})\n}\n\nfunc (s *Scanner) scanBit() {\n\ts.r.incAsLongAs(func(ch rune) bool {\n\t\treturn ch == '0' || ch == '1'\n\t})\n}\n\nfunc (s *Scanner) scanFloat(beg *Pos) (tok int, pos Pos, lit string) {\n\ts.r.p = *beg\n\t// float = D1 . D2 e D3\n\ts.scanDigits()\n\tch0 := s.r.peek()\n\tif ch0 == '.' {\n\t\ts.r.inc()\n\t\ts.scanDigits()\n\t\tch0 = s.r.peek()\n\t}\n\tif ch0 == 'e' || ch0 == 'E' {\n\t\ts.r.inc()\n\t\tch0 = s.r.peek()\n\t\tif ch0 == '-' || ch0 == '+' || isDigit(ch0) {\n\t\t\ts.r.inc()\n\t\t\ts.scanDigits()\n\t\t\ttok = floatLit\n\t\t} else {\n\t\t\t// D1 . D2 e XX when XX is not D3, parse the result to an identifier.\n\t\t\t// 9e9e = 9e9(float) + e(identifier)\n\t\t\t// 9est = 9est(identifier)\n\t\t\ts.r.incAsLongAs(isIdentChar)\n\t\t\ttok = identifier\n\t\t}\n\t} else {\n\t\ttok = decLit\n\t}\n\tpos, lit = *beg, s.r.data(beg)\n\treturn\n}\n\nfunc (s *Scanner) scanDigits() string {\n\tpos := s.r.pos()\n\ts.r.incAsLongAs(isDigit)\n\treturn s.r.data(&pos)\n}\n\n// scanVersionDigits scans for `min` to `max` digits (range inclusive) used in\n// `/*!12345 ... */` comments.\nfunc (s *Scanner) scanVersionDigits(min, max int) (version CommentCodeVersion) {\n\tpos := s.r.pos()\n\tfor i := 0; i < max; i++ {\n\t\tch := s.r.peek()\n\t\tif isDigit(ch) {\n\t\t\tversion = version*10 + CommentCodeVersion(ch-'0')\n\t\t\ts.r.inc()\n\t\t} else if i < min {\n\t\t\ts.r.p = pos\n\t\t\treturn CommentCodeNoVersion\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn\n}\n\nfunc (s *Scanner) lastErrorAsWarn() {\n\tif len(s.errs) == 0 {\n\t\treturn\n\t}\n\ts.warns = append(s.warns, s.errs[len(s.errs)-1])\n\ts.errs = s.errs[:len(s.errs)-1]\n}\n\ntype reader struct {\n\ts string\n\tp Pos\n\tw int\n}\n\nvar eof = Pos{-1, -1, -1}\n\nfunc (r *reader) eof() bool {\n\treturn r.p.Offset >= len(r.s)\n}\n\n// peek() peeks a rune from underlying reader.\n// if reader meets EOF, it will return unicode.ReplacementChar. to distinguish from\n// the real unicode.ReplacementChar, the caller should call r.eof() again to check.\nfunc (r *reader) peek() rune {\n\tif r.eof() {\n\t\treturn unicode.ReplacementChar\n\t}\n\tv, w := rune(r.s[r.p.Offset]), 1\n\tswitch {\n\tcase v == 0:\n\t\tr.w = w\n\t\treturn v // illegal UTF-8 encoding\n\tcase v >= 0x80:\n\t\tv, w = utf8.DecodeRuneInString(r.s[r.p.Offset:])\n\t\tif v == utf8.RuneError && w == 1 {\n\t\t\tv = rune(r.s[r.p.Offset]) // illegal UTF-8 encoding\n\t\t}\n\t}\n\tr.w = w\n\treturn v\n}\n\n// inc increase the position offset of the reader.\n// peek must be called before calling inc!\nfunc (r *reader) inc() {\n\tif r.s[r.p.Offset] == '\\n' {\n\t\tr.p.Line++\n\t\tr.p.Col = 0\n\t}\n\tr.p.Offset += r.w\n\tr.p.Col++\n}\n\nfunc (r *reader) incN(n int) {\n\tfor i := 0; i < n; i++ {\n\t\tr.inc()\n\t}\n}\n\nfunc (r *reader) readByte() (ch rune) {\n\tch = r.peek()\n\tif ch == unicode.ReplacementChar && r.eof() {\n\t\treturn\n\t}\n\tr.inc()\n\treturn\n}\n\nfunc (r *reader) pos() Pos {\n\treturn r.p\n}\n\nfunc (r *reader) data(from *Pos) string {\n\treturn r.s[from.Offset:r.p.Offset]\n}\n\nfunc (r *reader) incAsLongAs(fn func(rune) bool) rune {\n\tfor {\n\t\tch := r.peek()\n\t\tif !fn(ch) {\n\t\t\treturn ch\n\t\t}\n\t\tif ch == unicode.ReplacementChar && r.eof() {\n\t\t\treturn 0\n\t\t}\n\t\tr.inc()\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/lexer_test.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"fmt\"\n\t\"unicode\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n)\n\nvar _ = Suite(&testLexerSuite{})\n\ntype testLexerSuite struct {\n}\n\nfunc (s *testLexerSuite) TestTokenID(c *C) {\n\tfor str, tok := range tokenMap {\n\t\tl := NewScanner(str)\n\t\tvar v yySymType\n\t\ttok1 := l.Lex(&v)\n\t\tc.Check(tok, Equals, tok1)\n\t}\n}\n\nfunc (s *testLexerSuite) TestSingleChar(c *C) {\n\ttable := []byte{'|', '&', '-', '+', '*', '/', '%', '^', '~', '(', ',', ')'}\n\tfor _, tok := range table {\n\t\tl := NewScanner(string(tok))\n\t\tvar v yySymType\n\t\ttok1 := l.Lex(&v)\n\t\tc.Check(int(tok), Equals, tok1)\n\t}\n}\n\ntype testCaseItem struct {\n\tstr string\n\ttok int\n}\n\nfunc (s *testLexerSuite) TestSingleCharOther(c *C) {\n\ttable := []testCaseItem{\n\t\t{\"AT\", identifier},\n\t\t{\"PLACEHOLDER\", identifier},\n\t\t{\"=\", eq},\n\t\t{\".\", int('.')},\n\t}\n\trunTest(c, table)\n}\n\nfunc (s *testLexerSuite) TestAtLeadingIdentifier(c *C) {\n\ttable := []testCaseItem{\n\t\t{\"@\", singleAtIdentifier},\n\t\t{\"@''\", singleAtIdentifier},\n\t\t{\"@1\", singleAtIdentifier},\n\t\t{\"@.1_\", singleAtIdentifier},\n\t\t{\"@-1.\", singleAtIdentifier},\n\t\t{\"@~\", singleAtIdentifier},\n\t\t{\"@$\", singleAtIdentifier},\n\t\t{\"@a_3cbbc\", singleAtIdentifier},\n\t\t{\"@`a_3cbbc`\", singleAtIdentifier},\n\t\t{\"@-3cbbc\", singleAtIdentifier},\n\t\t{\"@!3cbbc\", singleAtIdentifier},\n\t\t{\"@@global.test\", doubleAtIdentifier},\n\t\t{\"@@session.test\", doubleAtIdentifier},\n\t\t{\"@@local.test\", doubleAtIdentifier},\n\t\t{\"@@test\", doubleAtIdentifier},\n\t\t{\"@@global.`test`\", doubleAtIdentifier},\n\t\t{\"@@session.`test`\", doubleAtIdentifier},\n\t\t{\"@@local.`test`\", doubleAtIdentifier},\n\t\t{\"@@`test`\", doubleAtIdentifier},\n\t}\n\trunTest(c, table)\n}\n\nfunc (s *testLexerSuite) TestUnderscoreCS(c *C) {\n\tvar v yySymType\n\tscanner := NewScanner(`_utf8\"string\"`)\n\ttok := scanner.Lex(&v)\n\tc.Check(tok, Equals, underscoreCS)\n\ttok = scanner.Lex(&v)\n\tc.Check(tok, Equals, stringLit)\n\n\tscanner.reset(\"N'string'\")\n\ttok = scanner.Lex(&v)\n\tc.Check(tok, Equals, underscoreCS)\n\ttok = scanner.Lex(&v)\n\tc.Check(tok, Equals, stringLit)\n}\n\nfunc (s *testLexerSuite) TestLiteral(c *C) {\n\ttable := []testCaseItem{\n\t\t{`'''a'''`, stringLit},\n\t\t{`''a''`, stringLit},\n\t\t{`\"\"a\"\"`, stringLit},\n\t\t{`\\'a\\'`, int('\\\\')},\n\t\t{`\\\"a\\\"`, int('\\\\')},\n\t\t{\"0.2314\", decLit},\n\t\t{\"1234567890123456789012345678901234567890\", decLit},\n\t\t{\"132.313\", decLit},\n\t\t{\"132.3e231\", floatLit},\n\t\t{\"132.3e-231\", floatLit},\n\t\t{\"001e-12\", floatLit},\n\t\t{\"23416\", intLit},\n\t\t{\"123test\", identifier},\n\t\t{\"123\" + string(unicode.ReplacementChar) + \"xxx\", identifier},\n\t\t{\"0\", intLit},\n\t\t{\"0x3c26\", hexLit},\n\t\t{\"x'13181C76734725455A'\", hexLit},\n\t\t{\"0b01\", bitLit},\n\t\t{fmt.Sprintf(\"t1%c\", 0), identifier},\n\t\t{\"N'some text'\", underscoreCS},\n\t\t{\"n'some text'\", underscoreCS},\n\t\t{\"\\\\N\", null},\n\t\t{\".*\", int('.')},       // `.`, `*`\n\t\t{\".1_t_1_x\", int('.')}, // `.`, `1_t_1_x`\n\t\t{\"9e9e\", floatLit},     // 9e9e = 9e9 + e\n\t\t// Issue #3954\n\t\t{\".1e23\", floatLit}, // `.1e23`\n\t\t{\".123\", decLit},    // `.123`\n\t\t{\".1*23\", decLit},   // `.1`, `*`, `23`\n\t\t{\".1,23\", decLit},   // `.1`, `,`, `23`\n\t\t{\".1 23\", decLit},   // `.1`, `23`\n\t\t// TODO: See #3963. The following test cases do not test the ambiguity.\n\t\t{\".1$23\", int('.')},    // `.`, `1$23`\n\t\t{\".1a23\", int('.')},    // `.`, `1a23`\n\t\t{\".1e23$23\", int('.')}, // `.`, `1e23$23`\n\t\t{\".1e23a23\", int('.')}, // `.`, `1e23a23`\n\t\t{\".1C23\", int('.')},    // `.`, `1C23`\n\t\t{\".1\\u0081\", int('.')}, // `.`, `1\\u0081`\n\t\t{\".1\\uff34\", int('.')}, // `.`, `1\\uff34`\n\t\t{`b''`, bitLit},\n\t\t{`b'0101'`, bitLit},\n\t\t{`0b0101`, bitLit},\n\t}\n\trunTest(c, table)\n}\n\nfunc runTest(c *C, table []testCaseItem) {\n\tvar val yySymType\n\tfor _, v := range table {\n\t\tl := NewScanner(v.str)\n\t\ttok := l.Lex(&val)\n\t\tc.Check(tok, Equals, v.tok, Commentf(v.str))\n\t}\n}\n\nfunc (s *testLexerSuite) TestComment(c *C) {\n\n\ttable := []testCaseItem{\n\t\t{\"-- select --\\n1\", intLit},\n\t\t{\"/*!40101 SET character_set_client = utf8 */;\", set},\n\t\t{\"/* SET character_set_client = utf8 */;\", int(';')},\n\t\t{\"/* some comments */ SELECT \", selectKwd},\n\t\t{`-- comment continues to the end of line\nSELECT`, selectKwd},\n\t\t{`# comment continues to the end of line\nSELECT`, selectKwd},\n\t\t{\"#comment\\n123\", intLit},\n\t\t{\"--5\", int('-')},\n\t\t{\"--\\nSELECT\", selectKwd},\n\t\t{\"--\\tSELECT\", 0},\n\t\t{\"--\\r\\nSELECT\", selectKwd},\n\t\t{\"--\", 0},\n\n\t\t// The odd behavior of '*/' inside conditional comment is the same as\n\t\t// that of MySQL.\n\t\t{\"/*T!99999 '*/0 -- ' */\", intLit},    // equivalent to 0\n\t\t{\"/*T!00000 '*/0 -- ' */\", stringLit}, // equivalent to '*/0 -- '\n\t}\n\trunTest(c, table)\n}\n\nfunc (s *testLexerSuite) TestscanQuotedIdent(c *C) {\n\tl := NewScanner(\"`fk`\")\n\tl.r.peek()\n\ttok, pos, lit := scanQuotedIdent(l)\n\tc.Assert(pos.Offset, Equals, 0)\n\tc.Assert(tok, Equals, quotedIdentifier)\n\tc.Assert(lit, Equals, \"fk\")\n}\n\nfunc (s *testLexerSuite) TestscanString(c *C) {\n\ttable := []struct {\n\t\traw    string\n\t\texpect string\n\t}{\n\t\t{`' \\n\\tTest String'`, \" \\n\\tTest String\"},\n\t\t{`'\\x\\B'`, \"xB\"},\n\t\t{`'\\0\\'\\\"\\b\\n\\r\\t\\\\'`, \"\\000'\\\"\\b\\n\\r\\t\\\\\"},\n\t\t{`'\\Z'`, \"\\x1a\"},\n\t\t{`'\\%\\_'`, `\\%\\_`},\n\t\t{`'hello'`, \"hello\"},\n\t\t{`'\"hello\"'`, `\"hello\"`},\n\t\t{`'\"\"hello\"\"'`, `\"\"hello\"\"`},\n\t\t{`'hel''lo'`, \"hel'lo\"},\n\t\t{`'\\'hello'`, \"'hello\"},\n\t\t{`\"hello\"`, \"hello\"},\n\t\t{`\"'hello'\"`, \"'hello'\"},\n\t\t{`\"''hello''\"`, \"''hello''\"},\n\t\t{`\"hel\"\"lo\"`, `hel\"lo`},\n\t\t{`\"\\\"hello\"`, `\"hello`},\n\t\t{`'disappearing\\ backslash'`, \"disappearing backslash\"},\n\t\t{\"'한국의中文UTF8およびテキストトラック'\", \"한국의中文UTF8およびテキストトラック\"},\n\t\t{\"'\\\\a\\x90'\", \"a\\x90\"},\n\t\t{`\"\\a\u0018èàø»\u0005\"`, `a\u0018èàø»\u0005`},\n\t}\n\n\tfor _, v := range table {\n\t\tl := NewScanner(v.raw)\n\t\ttok, pos, lit := l.scan()\n\t\tc.Assert(tok, Equals, stringLit)\n\t\tc.Assert(pos.Offset, Equals, 0)\n\t\tc.Assert(lit, Equals, v.expect)\n\t}\n}\n\nfunc (s *testLexerSuite) TestIdentifier(c *C) {\n\treplacementString := string(unicode.ReplacementChar) + \"xxx\"\n\ttable := [][2]string{\n\t\t{`哈哈`, \"哈哈\"},\n\t\t{\"`numeric`\", \"numeric\"},\n\t\t{\"\\r\\n \\r \\n \\tthere\\t \\n\", \"there\"},\n\t\t{`5number`, `5number`},\n\t\t{\"1_x\", \"1_x\"},\n\t\t{\"0_x\", \"0_x\"},\n\t\t{replacementString, replacementString},\n\t\t{\"9e\", \"9e\"},\n\t\t{\"0b\", \"0b\"},\n\t\t{\"0b123\", \"0b123\"},\n\t\t{\"0b1ab\", \"0b1ab\"},\n\t\t{\"0B01\", \"0B01\"},\n\t\t{\"0x\", \"0x\"},\n\t\t{\"0x7fz3\", \"0x7fz3\"},\n\t\t{\"023a4\", \"023a4\"},\n\t\t{\"9eTSs\", \"9eTSs\"},\n\t\t{fmt.Sprintf(\"t1%cxxx\", 0), \"t1\"},\n\t}\n\tl := &Scanner{}\n\tfor _, item := range table {\n\t\tl.reset(item[0])\n\t\tvar v yySymType\n\t\ttok := l.Lex(&v)\n\t\tc.Assert(tok, Equals, identifier)\n\t\tc.Assert(v.ident, Equals, item[1])\n\t}\n}\n\nfunc (s *testLexerSuite) TestSpecialComment(c *C) {\n\tl := NewScanner(\"/*!40101 select\\n5*/\")\n\ttok, pos, lit := l.scan()\n\tc.Assert(tok, Equals, identifier)\n\tc.Assert(lit, Equals, \"select\")\n\tc.Assert(pos, Equals, Pos{0, 9, 9})\n\n\ttok, pos, lit = l.scan()\n\tc.Assert(tok, Equals, intLit)\n\tc.Assert(lit, Equals, \"5\")\n\tc.Assert(pos, Equals, Pos{1, 1, 16})\n}\n\nfunc (s *testLexerSuite) TestSpecialCodeComment(c *C) {\n\tl := NewScanner(\"/*T!40000 auto_random(5) */\")\n\ttok, pos, lit := l.scan()\n\tc.Assert(tok, Equals, identifier)\n\tc.Assert(lit, Equals, \"auto_random\")\n\tc.Assert(pos, Equals, Pos{0, 10, 10})\n\ttok, pos, lit = l.scan()\n\tc.Assert(tok, Equals, int('('))\n\ttok, pos, lit = l.scan()\n\tc.Assert(lit, Equals, \"5\")\n\tc.Assert(pos, Equals, Pos{0, 22, 22})\n\ttok, pos, lit = l.scan()\n\tc.Assert(tok, Equals, int(')'))\n\n\tl = NewScanner(WrapStringWithCodeVersion(\"auto_random(5)\", CommentCodeCurrentVersion+1))\n\ttok, pos, lit = l.scan()\n\tc.Assert(tok, Equals, 0)\n}\n\nfunc (s *testLexerSuite) TestOptimizerHint(c *C) {\n\tl := NewScanner(\"SELECT /*+ BKA(t1) */ 0;\")\n\ttokens := []struct {\n\t\ttok   int\n\t\tident string\n\t\tpos   int\n\t}{\n\t\t{selectKwd, \"SELECT\", 0},\n\t\t{hintComment, \"/*+ BKA(t1) */\", 7},\n\t\t{intLit, \"0\", 22},\n\t\t{';', \";\", 23},\n\t}\n\tfor i := 0; ; i++ {\n\t\tvar sym yySymType\n\t\ttok := l.Lex(&sym)\n\t\tif tok == 0 {\n\t\t\treturn\n\t\t}\n\t\tc.Assert(tok, Equals, tokens[i].tok, Commentf(\"%d\", i))\n\t\tc.Assert(sym.ident, Equals, tokens[i].ident, Commentf(\"%d\", i))\n\t\tc.Assert(sym.offset, Equals, tokens[i].pos, Commentf(\"%d\", i))\n\t}\n}\n\nfunc (s *testLexerSuite) TestOptimizerHintAfterCertainKeywordOnly(c *C) {\n\ttests := []struct {\n\t\tinput  string\n\t\ttokens []int\n\t}{\n\t\t{\n\t\t\tinput:  \"SELECT /*+ hint */ *\",\n\t\t\ttokens: []int{selectKwd, hintComment, '*', 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"UPDATE /*+ hint */\",\n\t\t\ttokens: []int{update, hintComment, 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"INSERT /*+ hint */\",\n\t\t\ttokens: []int{insert, hintComment, 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"REPLACE /*+ hint */\",\n\t\t\ttokens: []int{replace, hintComment, 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"DELETE /*+ hint */\",\n\t\t\ttokens: []int{deleteKwd, hintComment, 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"CREATE /*+ hint */\",\n\t\t\ttokens: []int{create, hintComment, 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"/*+ hint */ SELECT *\",\n\t\t\ttokens: []int{selectKwd, '*', 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"SELECT /* comment */ /*+ hint */ *\",\n\t\t\ttokens: []int{selectKwd, hintComment, '*', 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"SELECT * /*+ hint */\",\n\t\t\ttokens: []int{selectKwd, '*', 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"SELECT /*T!000000 * */ /*+ hint */\",\n\t\t\ttokens: []int{selectKwd, '*', 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"SELECT /*T!999999 * */ /*+ hint */\",\n\t\t\ttokens: []int{selectKwd, hintComment, 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"SELECT /*+ hint1 */ /*+ hint2 */ *\",\n\t\t\ttokens: []int{selectKwd, hintComment, '*', 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"SELECT * FROM /*+ hint */\",\n\t\t\ttokens: []int{selectKwd, '*', from, 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"`SELECT` /*+ hint */\",\n\t\t\ttokens: []int{identifier, 0},\n\t\t},\n\t\t{\n\t\t\tinput:  \"'SELECT' /*+ hint */\",\n\t\t\ttokens: []int{stringLit, 0},\n\t\t},\n\t}\n\n\tfor _, tc := range tests {\n\t\tscanner := NewScanner(tc.input)\n\t\tvar sym yySymType\n\t\tfor i := 0; ; i++ {\n\t\t\ttok := scanner.Lex(&sym)\n\t\t\tc.Assert(tok, Equals, tc.tokens[i], Commentf(\"input = [%s], i = %d\", tc.input, i))\n\t\t\tif tok == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (s *testLexerSuite) TestInt(c *C) {\n\ttests := []struct {\n\t\tinput  string\n\t\texpect uint64\n\t}{\n\t\t{\"01000001783\", 1000001783},\n\t\t{\"00001783\", 1783},\n\t\t{\"0\", 0},\n\t\t{\"0000\", 0},\n\t\t{\"01\", 1},\n\t\t{\"10\", 10},\n\t}\n\tscanner := NewScanner(\"\")\n\tfor _, t := range tests {\n\t\tvar v yySymType\n\t\tscanner.reset(t.input)\n\t\ttok := scanner.Lex(&v)\n\t\tc.Assert(tok, Equals, intLit)\n\t\tswitch i := v.item.(type) {\n\t\tcase int64:\n\t\t\tc.Assert(uint64(i), Equals, t.expect)\n\t\tcase uint64:\n\t\t\tc.Assert(i, Equals, t.expect)\n\t\tdefault:\n\t\t\tc.Fail()\n\t\t}\n\t}\n}\n\nfunc (s *testLexerSuite) TestSQLModeANSIQuotes(c *C) {\n\ttests := []struct {\n\t\tinput string\n\t\ttok   int\n\t\tident string\n\t}{\n\t\t{`\"identifier\"`, identifier, \"identifier\"},\n\t\t{\"`identifier`\", identifier, \"identifier\"},\n\t\t{`\"identifier\"\"and\"`, identifier, `identifier\"and`},\n\t\t{`'string''string'`, stringLit, \"string'string\"},\n\t\t{`\"identifier\"'and'`, identifier, \"identifier\"},\n\t\t{`'string'\"identifier\"`, stringLit, \"string\"},\n\t}\n\tscanner := NewScanner(\"\")\n\tscanner.SetSQLMode(mysql.ModeANSIQuotes)\n\tfor _, t := range tests {\n\t\tvar v yySymType\n\t\tscanner.reset(t.input)\n\t\ttok := scanner.Lex(&v)\n\t\tc.Assert(tok, Equals, t.tok)\n\t\tc.Assert(v.ident, Equals, t.ident)\n\t}\n\tscanner.reset(`'string' 'string'`)\n\tvar v yySymType\n\ttok := scanner.Lex(&v)\n\tc.Assert(tok, Equals, stringLit)\n\tc.Assert(v.ident, Equals, \"string\")\n\ttok = scanner.Lex(&v)\n\tc.Assert(tok, Equals, stringLit)\n\tc.Assert(v.ident, Equals, \"string\")\n}\n\nfunc (s *testLexerSuite) TestIllegal(c *C) {\n\ttable := []testCaseItem{\n\t\t{\"'\", invalid},\n\t\t{\"'fu\", invalid},\n\t\t{\"'\\\\n\", invalid},\n\t\t{\"'\\\\\", invalid},\n\t\t{fmt.Sprintf(\"%c\", 0), invalid},\n\t\t{\"`\", invalid},\n\t\t{`\"`, invalid},\n\t\t{\"@`\", invalid},\n\t\t{\"@'\", invalid},\n\t\t{`@\"`, invalid},\n\t\t{\"@@`\", invalid},\n\t\t{\"@@global.`\", invalid},\n\t}\n\trunTest(c, table)\n}\n\nfunc (s *testLexerSuite) TestVersionDigits(c *C) {\n\ttests := []struct {\n\t\tinput    string\n\t\tmin      int\n\t\tmax      int\n\t\tversion  CommentCodeVersion\n\t\tnextChar rune\n\t}{\n\t\t{\n\t\t\tinput:    \"12345\",\n\t\t\tmin:      5,\n\t\t\tmax:      5,\n\t\t\tversion:  12345,\n\t\t\tnextChar: unicode.ReplacementChar,\n\t\t},\n\t\t{\n\t\t\tinput:    \"12345xyz\",\n\t\t\tmin:      5,\n\t\t\tmax:      5,\n\t\t\tversion:  12345,\n\t\t\tnextChar: 'x',\n\t\t},\n\t\t{\n\t\t\tinput:    \"1234xyz\",\n\t\t\tmin:      5,\n\t\t\tmax:      5,\n\t\t\tversion:  CommentCodeNoVersion,\n\t\t\tnextChar: '1',\n\t\t},\n\t\t{\n\t\t\tinput:    \"123456\",\n\t\t\tmin:      5,\n\t\t\tmax:      5,\n\t\t\tversion:  12345,\n\t\t\tnextChar: '6',\n\t\t},\n\t\t{\n\t\t\tinput:    \"1234\",\n\t\t\tmin:      5,\n\t\t\tmax:      5,\n\t\t\tversion:  CommentCodeNoVersion,\n\t\t\tnextChar: '1',\n\t\t},\n\t\t{\n\t\t\tinput:    \"\",\n\t\t\tmin:      5,\n\t\t\tmax:      5,\n\t\t\tversion:  CommentCodeNoVersion,\n\t\t\tnextChar: unicode.ReplacementChar,\n\t\t},\n\t\t{\n\t\t\tinput:    \"1234567xyz\",\n\t\t\tmin:      5,\n\t\t\tmax:      6,\n\t\t\tversion:  123456,\n\t\t\tnextChar: '7',\n\t\t},\n\t\t{\n\t\t\tinput:    \"12345xyz\",\n\t\t\tmin:      5,\n\t\t\tmax:      6,\n\t\t\tversion:  12345,\n\t\t\tnextChar: 'x',\n\t\t},\n\t\t{\n\t\t\tinput:    \"12345\",\n\t\t\tmin:      5,\n\t\t\tmax:      6,\n\t\t\tversion:  12345,\n\t\t\tnextChar: unicode.ReplacementChar,\n\t\t},\n\t\t{\n\t\t\tinput:    \"1234xyz\",\n\t\t\tmin:      5,\n\t\t\tmax:      6,\n\t\t\tversion:  CommentCodeNoVersion,\n\t\t\tnextChar: '1',\n\t\t},\n\t}\n\n\tscanner := NewScanner(\"\")\n\tfor _, t := range tests {\n\t\tcomment := Commentf(\"input = %s\", t.input)\n\t\tscanner.reset(t.input)\n\t\tversion := scanner.scanVersionDigits(t.min, t.max)\n\t\tc.Assert(version, Equals, t.version, comment)\n\t\tnextChar := scanner.r.readByte()\n\t\tc.Assert(nextChar, Equals, t.nextChar, comment)\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/misc.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Modified by Ant Group in 2023\n\npackage parser\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n)\n\n// CommentCodeVersion is used to track the highest version can be parsed in the comment with pattern /*T!00001 xxx */\ntype CommentCodeVersion int\n\nconst (\n\tCommentCodeNoVersion  CommentCodeVersion = iota\n\tCommentCodeAutoRandom CommentCodeVersion = 40000\n\n\tCommentCodeCurrentVersion\n)\n\nfunc (ccv CommentCodeVersion) String() string {\n\treturn fmt.Sprintf(\"%05d\", ccv)\n}\n\n// WrapStringWithCodeVersion convert a string `str` to `/*T!xxxxx str */`, where `xxxxx` is determined by CommentCodeVersion.\nfunc WrapStringWithCodeVersion(str string, ccv CommentCodeVersion) string {\n\treturn fmt.Sprintf(\"/*T!%05d %s */\", ccv, str)\n}\n\nfunc isLetter(ch rune) bool {\n\treturn (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')\n}\n\nfunc isDigit(ch rune) bool {\n\treturn ch >= '0' && ch <= '9'\n}\n\nfunc isIdentChar(ch rune) bool {\n\treturn isLetter(ch) || isDigit(ch) || ch == '_' || ch == '$' || isIdentExtend(ch)\n}\n\nfunc isIdentExtend(ch rune) bool {\n\treturn ch >= 0x80 && ch <= '\\uffff'\n}\n\nfunc isUserVarChar(ch rune) bool {\n\treturn isLetter(ch) || isDigit(ch) || ch == '_' || ch == '$' || ch == '.' || isIdentExtend(ch)\n}\n\ntype trieNode struct {\n\tchilds [256]*trieNode\n\ttoken  int\n\tfn     func(s *Scanner) (int, Pos, string)\n}\n\nvar ruleTable trieNode\n\nfunc initTokenByte(c byte, tok int) {\n\tif ruleTable.childs[c] == nil {\n\t\truleTable.childs[c] = &trieNode{}\n\t}\n\truleTable.childs[c].token = tok\n}\n\nfunc initTokenString(str string, tok int) {\n\tnode := &ruleTable\n\tfor _, c := range str {\n\t\tif node.childs[c] == nil {\n\t\t\tnode.childs[c] = &trieNode{}\n\t\t}\n\t\tnode = node.childs[c]\n\t}\n\tnode.token = tok\n}\n\nfunc initTokenFunc(str string, fn func(s *Scanner) (int, Pos, string)) {\n\tfor i := 0; i < len(str); i++ {\n\t\tc := str[i]\n\t\tif ruleTable.childs[c] == nil {\n\t\t\truleTable.childs[c] = &trieNode{}\n\t\t}\n\t\truleTable.childs[c].fn = fn\n\t}\n\treturn\n}\n\nfunc init() {\n\t// invalid is a special token defined in parser.y, when parser meet\n\t// this token, it will throw an error.\n\t// set root trie node's token to invalid, so when input match nothing\n\t// in the trie, invalid will be the default return token.\n\truleTable.token = invalid\n\tinitTokenByte('/', int('/'))\n\tinitTokenByte('+', int('+'))\n\tinitTokenByte('>', int('>'))\n\tinitTokenByte('<', int('<'))\n\tinitTokenByte('(', int('('))\n\tinitTokenByte(')', int(')'))\n\tinitTokenByte('[', int('['))\n\tinitTokenByte(']', int(']'))\n\tinitTokenByte(';', int(';'))\n\tinitTokenByte(',', int(','))\n\tinitTokenByte('&', int('&'))\n\tinitTokenByte('%', int('%'))\n\tinitTokenByte(':', int(':'))\n\tinitTokenByte('|', int('|'))\n\tinitTokenByte('!', int('!'))\n\tinitTokenByte('^', int('^'))\n\tinitTokenByte('~', int('~'))\n\tinitTokenByte('\\\\', int('\\\\'))\n\tinitTokenByte('=', eq)\n\tinitTokenByte('{', int('{'))\n\tinitTokenByte('}', int('}'))\n\tinitTokenString(\"{{\", leftMarker)\n\tinitTokenString(\"}}\", rightMarker)\n\tinitTokenString(\"||\", pipes)\n\tinitTokenString(\"&&\", andand)\n\tinitTokenString(\"&^\", andnot)\n\tinitTokenString(\":=\", assignmentEq)\n\tinitTokenString(\"<=>\", nulleq)\n\tinitTokenString(\">=\", ge)\n\tinitTokenString(\"<=\", le)\n\tinitTokenString(\"!=\", neq)\n\tinitTokenString(\"<>\", neqSynonym)\n\tinitTokenString(\"<<\", lsh)\n\tinitTokenString(\">>\", rsh)\n\tinitTokenString(\"\\\\N\", null)\n\n\tinitTokenFunc(\"@\", startWithAt)\n\tinitTokenFunc(\"/\", startWithSlash)\n\tinitTokenFunc(\"*\", startWithStar)\n\tinitTokenFunc(\"-\", startWithDash)\n\tinitTokenFunc(\"#\", startWithSharp)\n\tinitTokenFunc(\"Xx\", startWithXx)\n\tinitTokenFunc(\"Nn\", startWithNn)\n\tinitTokenFunc(\"Bb\", startWithBb)\n\tinitTokenFunc(\".\", startWithDot)\n\tinitTokenFunc(\"_$ACDEFGHIJKLMOPQRSTUVWYZacdefghijklmopqrstuvwyz\", scanIdentifier)\n\tinitTokenFunc(\"`\", scanQuotedIdent)\n\tinitTokenFunc(\"0123456789\", startWithNumber)\n\tinitTokenFunc(\"'\\\"\", startString)\n}\n\nvar tokenMap = map[string]int{\n\t\"ACCOUNT\":                   account,\n\t\"ACTION\":                    action,\n\t\"ADD\":                       add,\n\t\"ADDDATE\":                   addDate,\n\t\"ADVISE\":                    advise,\n\t\"ADMIN\":                     admin,\n\t\"AFTER\":                     after,\n\t\"AGAINST\":                   against,\n\t\"ALL\":                       all,\n\t\"ALGORITHM\":                 algorithm,\n\t\"ALTER\":                     alter,\n\t\"ALWAYS\":                    always,\n\t\"ANALYZE\":                   analyze,\n\t\"AND\":                       and,\n\t\"ANY\":                       any,\n\t\"AS\":                        as,\n\t\"ASC\":                       asc,\n\t\"ASCII\":                     ascii,\n\t\"AUTO_INCREMENT\":            autoIncrement,\n\t\"AUTO_RANDOM\":               autoRandom,\n\t\"AVG\":                       avg,\n\t\"AVG_ROW_LENGTH\":            avgRowLength,\n\t\"BEGIN\":                     begin,\n\t\"BETWEEN\":                   between,\n\t\"BIGINT\":                    bigIntType,\n\t\"BINARY\":                    binaryType,\n\t\"BINLOG\":                    binlog,\n\t\"BIT\":                       bitType,\n\t\"BIT_AND\":                   bitAnd,\n\t\"BIT_OR\":                    bitOr,\n\t\"BIT_XOR\":                   bitXor,\n\t\"BLOB\":                      blobType,\n\t\"BLOCK\":                     block,\n\t\"BOOL\":                      boolType,\n\t\"BOOLEAN\":                   booleanType,\n\t\"BOTH\":                      both,\n\t\"BOUND\":                     bound,\n\t\"BTREE\":                     btree,\n\t\"BUCKETS\":                   buckets,\n\t\"BUILTINS\":                  builtins,\n\t\"BY\":                        by,\n\t\"BYTE\":                      byteType,\n\t\"CACHE\":                     cache,\n\t\"CANCEL\":                    cancel,\n\t\"CASCADE\":                   cascade,\n\t\"CASCADED\":                  cascaded,\n\t\"CASE\":                      caseKwd,\n\t\"CAST\":                      cast,\n\t\"CAPTURE\":                   capture,\n\t\"CHANGE\":                    change,\n\t\"CHAR\":                      charType,\n\t\"CHARACTER\":                 character,\n\t\"CHARSET\":                   charsetKwd,\n\t\"CHECK\":                     check,\n\t\"CHECKSUM\":                  checksum,\n\t\"CIPHER\":                    cipher,\n\t\"CLEANUP\":                   cleanup,\n\t\"CLIENT\":                    client,\n\t\"CMSKETCH\":                  cmSketch,\n\t\"COALESCE\":                  coalesce,\n\t\"COLLATE\":                   collate,\n\t\"COLLATION\":                 collation,\n\t\"COLUMN\":                    column,\n\t\"COLUMN_FORMAT\":             columnFormat,\n\t\"COLUMNS\":                   columns,\n\t\"COMMENT\":                   comment,\n\t\"COMMIT\":                    commit,\n\t\"COMMITTED\":                 committed,\n\t\"COMPACT\":                   compact,\n\t\"COMPRESSED\":                compressed,\n\t\"COMPRESSION\":               compression,\n\t\"CONNECTION\":                connection,\n\t\"CONSISTENT\":                consistent,\n\t\"CONSTRAINT\":                constraint,\n\t\"CONTEXT\":                   context,\n\t\"CONVERT\":                   convert,\n\t\"COPY\":                      copyKwd,\n\t\"COUNT\":                     count,\n\t\"CPU\":                       cpu,\n\t\"CREATE\":                    create,\n\t\"CROSS\":                     cross,\n\t\"CURRENT\":                   current,\n\t\"CURRENT_DATE\":              currentDate,\n\t\"CURRENT_TIME\":              currentTime,\n\t\"CURRENT_TIMESTAMP\":         currentTs,\n\t\"CURRENT_USER\":              currentUser,\n\t\"CURRENT_ROLE\":              currentRole,\n\t\"CURTIME\":                   curTime,\n\t\"CYCLE\":                     cycle,\n\t\"DATA\":                      data,\n\t\"DATABASE\":                  database,\n\t\"DATABASES\":                 databases,\n\t\"DATE\":                      dateType,\n\t\"DATE_ADD\":                  dateAdd,\n\t\"DATE_SUB\":                  dateSub,\n\t\"DATETIME\":                  datetimeType,\n\t\"DAY\":                       day,\n\t\"DAY_HOUR\":                  dayHour,\n\t\"DAY_MICROSECOND\":           dayMicrosecond,\n\t\"DAY_MINUTE\":                dayMinute,\n\t\"DAY_SECOND\":                daySecond,\n\t\"DDL\":                       ddl,\n\t\"DEALLOCATE\":                deallocate,\n\t\"DEC\":                       decimalType,\n\t\"DECIMAL\":                   decimalType,\n\t\"DEFAULT\":                   defaultKwd,\n\t\"DEFINER\":                   definer,\n\t\"DELAY_KEY_WRITE\":           delayKeyWrite,\n\t\"DELAYED\":                   delayed,\n\t\"DELETE\":                    deleteKwd,\n\t\"DEPTH\":                     depth,\n\t\"DESC\":                      desc,\n\t\"DESCRIBE\":                  describe,\n\t\"DIRECTORY\":                 directory,\n\t\"DISABLE\":                   disable,\n\t\"DISCARD\":                   discard,\n\t\"DISK\":                      disk,\n\t\"DISTINCT\":                  distinct,\n\t\"DISTINCTROW\":               distinct,\n\t\"DIV\":                       div,\n\t\"DO\":                        do,\n\t\"DOUBLE\":                    doubleType,\n\t\"DRAINER\":                   drainer,\n\t\"DROP\":                      drop,\n\t\"DUAL\":                      dual,\n\t\"DUPLICATE\":                 duplicate,\n\t\"DYNAMIC\":                   dynamic,\n\t\"ELSE\":                      elseKwd,\n\t\"ENABLE\":                    enable,\n\t\"ENCLOSED\":                  enclosed,\n\t\"ENCRYPTION\":                encryption,\n\t\"END\":                       end,\n\t\"ENFORCED\":                  enforced,\n\t\"ENGINE\":                    engine,\n\t\"ENGINES\":                   engines,\n\t\"ENUM\":                      enum,\n\t\"ERROR\":                     errorKwd,\n\t\"ESCAPE\":                    escape,\n\t\"ESCAPED\":                   escaped,\n\t\"EVENT\":                     event,\n\t\"EVENTS\":                    events,\n\t\"EVOLVE\":                    evolve,\n\t\"EXACT\":                     exact,\n\t\"EXCLUSIVE\":                 exclusive,\n\t\"EXCEPT\":                    except,\n\t\"EXCHANGE\":                  exchange,\n\t\"EXECUTE\":                   execute,\n\t\"EXISTS\":                    exists,\n\t\"EXPANSION\":                 expansion,\n\t\"EXPIRE\":                    expire,\n\t\"EXPLAIN\":                   explain,\n\t\"EXTENDED\":                  extended,\n\t\"EXTRACT\":                   extract,\n\t\"FALSE\":                     falseKwd,\n\t\"FAULTS\":                    faultsSym,\n\t\"FIELDS\":                    fields,\n\t\"FILE\":                      file,\n\t\"FIRST\":                     first,\n\t\"FIXED\":                     fixed,\n\t\"FLOAT\":                     floatType,\n\t\"FLUSH\":                     flush,\n\t\"FLASHBACK\":                 flashback,\n\t\"FOLLOWING\":                 following,\n\t\"FOR\":                       forKwd,\n\t\"FORCE\":                     force,\n\t\"FOREIGN\":                   foreign,\n\t\"FORMAT\":                    format,\n\t\"FROM\":                      from,\n\t\"FULL\":                      full,\n\t\"FULLTEXT\":                  fulltext,\n\t\"FUNCTION\":                  function,\n\t\"GENERATED\":                 generated,\n\t\"GENERAL\":                   general,\n\t\"GET_FORMAT\":                getFormat,\n\t\"GLOBAL\":                    global,\n\t\"GRANT\":                     grant,\n\t\"GRANTS\":                    grants,\n\t\"GROUP\":                     group,\n\t\"GROUP_CONCAT\":              groupConcat,\n\t\"HASH\":                      hash,\n\t\"HAVING\":                    having,\n\t\"HIGH_PRIORITY\":             highPriority,\n\t\"HISTORY\":                   history,\n\t\"HOSTS\":                     hosts,\n\t\"HOUR\":                      hour,\n\t\"HOUR_MICROSECOND\":          hourMicrosecond,\n\t\"HOUR_MINUTE\":               hourMinute,\n\t\"HOUR_SECOND\":               hourSecond,\n\t\"IDENTIFIED\":                identified,\n\t\"IF\":                        ifKwd,\n\t\"IGNORE\":                    ignore,\n\t\"IMPORT\":                    importKwd,\n\t\"IN\":                        in,\n\t\"INCREMENT\":                 increment,\n\t\"INCREMENTAL\":               incremental,\n\t\"INDEX\":                     index,\n\t\"INDEXES\":                   indexes,\n\t\"INFILE\":                    infile,\n\t\"INNER\":                     inner,\n\t\"INPLACE\":                   inplace,\n\t\"INSTANT\":                   instant,\n\t\"INSERT\":                    insert,\n\t\"INSERT_METHOD\":             insertMethod,\n\t\"INT\":                       intType,\n\t\"INT1\":                      int1Type,\n\t\"INT2\":                      int2Type,\n\t\"INT3\":                      int3Type,\n\t\"INT4\":                      int4Type,\n\t\"INT8\":                      int8Type,\n\t\"IO\":                        io,\n\t\"IPC\":                       ipc,\n\t\"INTEGER\":                   integerType,\n\t\"INTERVAL\":                  interval,\n\t\"INTERNAL\":                  internal,\n\t\"INTO\":                      into,\n\t\"OUTFILE\":                   outfile,\n\t\"INVISIBLE\":                 invisible,\n\t\"INVOKER\":                   invoker,\n\t\"IS\":                        is,\n\t\"ISSUER\":                    issuer,\n\t\"ISOLATION\":                 isolation,\n\t\"JOBS\":                      jobs,\n\t\"JOB\":                       job,\n\t\"JOIN\":                      join,\n\t\"JSON\":                      jsonType,\n\t\"KEY\":                       key,\n\t\"KEY_BLOCK_SIZE\":            keyBlockSize,\n\t\"KEYS\":                      keys,\n\t\"KILL\":                      kill,\n\t\"LABELS\":                    labels,\n\t\"LANGUAGE\":                  language,\n\t\"LAST\":                      last,\n\t\"LEADING\":                   leading,\n\t\"LEFT\":                      left,\n\t\"LESS\":                      less,\n\t\"LEVEL\":                     level,\n\t\"LIKE\":                      like,\n\t\"LIMIT\":                     limit,\n\t\"LINES\":                     lines,\n\t\"LINEAR\":                    linear,\n\t\"LIST\":                      list,\n\t\"LOAD\":                      load,\n\t\"LOCAL\":                     local,\n\t\"LOCALTIME\":                 localTime,\n\t\"LOCALTIMESTAMP\":            localTs,\n\t\"LOCATION\":                  location,\n\t\"LOCK\":                      lock,\n\t\"LOGS\":                      logs,\n\t\"LONG\":                      long,\n\t\"LONGBLOB\":                  longblobType,\n\t\"LONGTEXT\":                  longtextType,\n\t\"LOW_PRIORITY\":              lowPriority,\n\t\"MASTER\":                    master,\n\t\"MATCH\":                     match,\n\t\"MAX\":                       max,\n\t\"MAX_CONNECTIONS_PER_HOUR\":  maxConnectionsPerHour,\n\t\"MAX_IDXNUM\":                max_idxnum,\n\t\"MAX_MINUTES\":               max_minutes,\n\t\"MAX_QUERIES_PER_HOUR\":      maxQueriesPerHour,\n\t\"MAX_ROWS\":                  maxRows,\n\t\"MAX_UPDATES_PER_HOUR\":      maxUpdatesPerHour,\n\t\"MAX_USER_CONNECTIONS\":      maxUserConnections,\n\t\"MAXVALUE\":                  maxValue,\n\t\"MEDIUMBLOB\":                mediumblobType,\n\t\"MEDIUMINT\":                 mediumIntType,\n\t\"MEDIUMTEXT\":                mediumtextType,\n\t\"MEMORY\":                    memory,\n\t\"MERGE\":                     merge,\n\t\"MICROSECOND\":               microsecond,\n\t\"MIN\":                       min,\n\t\"MIN_ROWS\":                  minRows,\n\t\"MINUTE\":                    minute,\n\t\"MINUTE_MICROSECOND\":        minuteMicrosecond,\n\t\"MINUTE_SECOND\":             minuteSecond,\n\t\"MINVALUE\":                  minValue,\n\t\"MOD\":                       mod,\n\t\"MODE\":                      mode,\n\t\"MODIFY\":                    modify,\n\t\"MONTH\":                     month,\n\t\"NAMES\":                     names,\n\t\"NATIONAL\":                  national,\n\t\"NATURAL\":                   natural,\n\t\"NEVER\":                     never,\n\t\"NEXT_ROW_ID\":               next_row_id,\n\t\"NO\":                        no,\n\t\"NO_WRITE_TO_BINLOG\":        noWriteToBinLog,\n\t\"NOCACHE\":                   nocache,\n\t\"NOCYCLE\":                   nocycle,\n\t\"NODE_ID\":                   nodeID,\n\t\"NODE_STATE\":                nodeState,\n\t\"NODEGROUP\":                 nodegroup,\n\t\"NOMAXVALUE\":                nomaxvalue,\n\t\"NOMINVALUE\":                nominvalue,\n\t\"NONE\":                      none,\n\t\"NOORDER\":                   noorder,\n\t\"NOT\":                       not,\n\t\"NOW\":                       now,\n\t\"NULL\":                      null,\n\t\"NULLS\":                     nulls,\n\t\"NUMERIC\":                   numericType,\n\t\"NCHAR\":                     ncharType,\n\t\"NVARCHAR\":                  nvarcharType,\n\t\"OFFSET\":                    offset,\n\t\"ON\":                        on,\n\t\"ONLY\":                      only,\n\t\"OPTIMISTIC\":                optimistic,\n\t\"OPTIMIZE\":                  optimize,\n\t\"OPTION\":                    option,\n\t\"OPTIONALLY\":                optionally,\n\t\"OR\":                        or,\n\t\"ORDER\":                     order,\n\t\"OUTER\":                     outer,\n\t\"PACK_KEYS\":                 packKeys,\n\t\"PAGE\":                      pageSym,\n\t\"PARSER\":                    parser,\n\t\"PARTIAL\":                   partial,\n\t\"PARTITION\":                 partition,\n\t\"PARTITIONING\":              partitioning,\n\t\"PARTITIONS\":                partitions,\n\t\"PARTY_CODE\":                partyCode,\n\t\"PASSWORD\":                  password,\n\t\"PESSIMISTIC\":               pessimistic,\n\t\"PERCENTILE_DISC\":           percentileDisc,\n\t\"PER_TABLE\":                 per_table,\n\t\"PER_DB\":                    per_db,\n\t\"PLUGINS\":                   plugins,\n\t\"POSITION\":                  position,\n\t\"PRECEDING\":                 preceding,\n\t\"PRECISION\":                 precisionType,\n\t\"PREPARE\":                   prepare,\n\t\"PRIMARY\":                   primary,\n\t\"PRIVILEGES\":                privileges,\n\t\"PROCEDURE\":                 procedure,\n\t\"PROCESS\":                   process,\n\t\"PROCESSLIST\":               processlist,\n\t\"PROFILE\":                   profile,\n\t\"PROFILES\":                  profiles,\n\t\"PUMP\":                      pump,\n\t\"QUARTER\":                   quarter,\n\t\"QUERY\":                     query,\n\t\"QUERIES\":                   queries,\n\t\"QUICK\":                     quick,\n\t\"SHARD_ROW_ID_BITS\":         shardRowIDBits,\n\t\"PRE_SPLIT_REGIONS\":         preSplitRegions,\n\t\"RANGE\":                     rangeKwd,\n\t\"RECOVER\":                   recover,\n\t\"REBUILD\":                   rebuild,\n\t\"READ\":                      read,\n\t\"REAL\":                      realType,\n\t\"RECENT\":                    recent,\n\t\"REDUNDANT\":                 redundant,\n\t\"REFERENCES\":                references,\n\t\"REGEXP\":                    regexpKwd,\n\t\"REGIONS\":                   regions,\n\t\"REGION\":                    region,\n\t\"RELOAD\":                    reload,\n\t\"REMOVE\":                    remove,\n\t\"RENAME\":                    rename,\n\t\"REORGANIZE\":                reorganize,\n\t\"REPAIR\":                    repair,\n\t\"REPEAT\":                    repeat,\n\t\"REPEATABLE\":                repeatable,\n\t\"REPLACE\":                   replace,\n\t\"RESPECT\":                   respect,\n\t\"REPLICA\":                   replica,\n\t\"REPLICATION\":               replication,\n\t\"REQUIRE\":                   require,\n\t\"RESTRICT\":                  restrict,\n\t\"REVERSE\":                   reverse,\n\t\"REVOKE\":                    revoke,\n\t\"RIGHT\":                     right,\n\t\"RLIKE\":                     rlike,\n\t\"ROLE\":                      role,\n\t\"ROLLBACK\":                  rollback,\n\t\"ROUTINE\":                   routine,\n\t\"ROW\":                       row,\n\t\"ROW_COUNT\":                 rowCount,\n\t\"ROW_FORMAT\":                rowFormat,\n\t\"RTREE\":                     rtree,\n\t\"SAMPLES\":                   samples,\n\t\"SCHEMA\":                    database,\n\t\"SCHEMAS\":                   databases,\n\t\"SECOND\":                    second,\n\t\"SECONDARY_ENGINE\":          secondaryEngine,\n\t\"SECONDARY_LOAD\":            secondaryLoad,\n\t\"SECONDARY_UNLOAD\":          secondaryUnload,\n\t\"SECOND_MICROSECOND\":        secondMicrosecond,\n\t\"SECURITY\":                  security,\n\t\"SELECT\":                    selectKwd,\n\t\"SEQUENCE\":                  sequence,\n\t\"SERIAL\":                    serial,\n\t\"SERIALIZABLE\":              serializable,\n\t\"SESSION\":                   session,\n\t\"SET\":                       set,\n\t\"SEPARATOR\":                 separator,\n\t\"SHARE\":                     share,\n\t\"SHARED\":                    shared,\n\t\"SHOW\":                      show,\n\t\"SHUTDOWN\":                  shutdown,\n\t\"SIGNED\":                    signed,\n\t\"SIMPLE\":                    simple,\n\t\"SLAVE\":                     slave,\n\t\"SLOW\":                      slow,\n\t\"SMALLINT\":                  smallIntType,\n\t\"SNAPSHOT\":                  snapshot,\n\t\"SOME\":                      some,\n\t\"SPATIAL\":                   spatial,\n\t\"SPLIT\":                     split,\n\t\"SQL\":                       sql,\n\t\"SQL_BIG_RESULT\":            sqlBigResult,\n\t\"SQL_BUFFER_RESULT\":         sqlBufferResult,\n\t\"SQL_CACHE\":                 sqlCache,\n\t\"SQL_CALC_FOUND_ROWS\":       sqlCalcFoundRows,\n\t\"SQL_NO_CACHE\":              sqlNoCache,\n\t\"SQL_SMALL_RESULT\":          sqlSmallResult,\n\t\"SQL_TSI_DAY\":               sqlTsiDay,\n\t\"SQL_TSI_HOUR\":              sqlTsiHour,\n\t\"SQL_TSI_MINUTE\":            sqlTsiMinute,\n\t\"SQL_TSI_MONTH\":             sqlTsiMonth,\n\t\"SQL_TSI_QUARTER\":           sqlTsiQuarter,\n\t\"SQL_TSI_SECOND\":            sqlTsiSecond,\n\t\"SQL_TSI_WEEK\":              sqlTsiWeek,\n\t\"SQL_TSI_YEAR\":              sqlTsiYear,\n\t\"SOURCE\":                    source,\n\t\"SSL\":                       ssl,\n\t\"STALENESS\":                 staleness,\n\t\"START\":                     start,\n\t\"STARTING\":                  starting,\n\t\"STATS\":                     stats,\n\t\"STATS_BUCKETS\":             statsBuckets,\n\t\"STATS_HISTOGRAMS\":          statsHistograms,\n\t\"STATS_HEALTHY\":             statsHealthy,\n\t\"STATS_META\":                statsMeta,\n\t\"STATS_AUTO_RECALC\":         statsAutoRecalc,\n\t\"STATS_PERSISTENT\":          statsPersistent,\n\t\"STATS_SAMPLE_PAGES\":        statsSamplePages,\n\t\"STATUS\":                    status,\n\t\"STORAGE\":                   storage,\n\t\"SWAPS\":                     swaps,\n\t\"SWITCHES\":                  switchesSym,\n\t\"SYSTEM_TIME\":               systemTime,\n\t\"OPEN\":                      open,\n\t\"STD\":                       stddevPop,\n\t\"STDDEV\":                    stddevPop,\n\t\"STDDEV_POP\":                stddevPop,\n\t\"STDDEV_SAMP\":               stddevSamp,\n\t\"STORED\":                    stored,\n\t\"STRAIGHT_JOIN\":             straightJoin,\n\t\"STRONG\":                    strong,\n\t\"SUBDATE\":                   subDate,\n\t\"SUBJECT\":                   subject,\n\t\"SUBPARTITION\":              subpartition,\n\t\"SUBPARTITIONS\":             subpartitions,\n\t\"SUBSTR\":                    substring,\n\t\"SUBSTRING\":                 substring,\n\t\"SUM\":                       sum,\n\t\"SUPER\":                     super,\n\t\"TABLE\":                     tableKwd,\n\t\"TABLE_CHECKSUM\":            tableChecksum,\n\t\"TABLES\":                    tables,\n\t\"TABLESPACE\":                tablespace,\n\t\"TEMPORARY\":                 temporary,\n\t\"TEMPTABLE\":                 temptable,\n\t\"TERMINATED\":                terminated,\n\t\"TEXT\":                      textType,\n\t\"THAN\":                      than,\n\t\"THEN\":                      then,\n\t\"TIDB\":                      tidb,\n\t\"TIFLASH\":                   tiFlash,\n\t\"TIME\":                      timeType,\n\t\"TIMESTAMP\":                 timestampType,\n\t\"TIMESTAMPADD\":              timestampAdd,\n\t\"TIMESTAMPDIFF\":             timestampDiff,\n\t\"TINYBLOB\":                  tinyblobType,\n\t\"TINYINT\":                   tinyIntType,\n\t\"TINYTEXT\":                  tinytextType,\n\t\"TO\":                        to,\n\t\"TOKUDB_DEFAULT\":            tokudbDefault,\n\t\"TOKUDB_FAST\":               tokudbFast,\n\t\"TOKUDB_LZMA\":               tokudbLzma,\n\t\"TOKUDB_QUICKLZ\":            tokudbQuickLZ,\n\t\"TOKUDB_SNAPPY\":             tokudbSnappy,\n\t\"TOKUDB_SMALL\":              tokudbSmall,\n\t\"TOKUDB_UNCOMPRESSED\":       tokudbUncompressed,\n\t\"TOKUDB_ZLIB\":               tokudbZlib,\n\t\"TOP\":                       top,\n\t\"TOPN\":                      topn,\n\t\"TRACE\":                     trace,\n\t\"TRADITIONAL\":               traditional,\n\t\"TRAILING\":                  trailing,\n\t\"TRANSACTION\":               transaction,\n\t\"TRIGGER\":                   trigger,\n\t\"TRIGGERS\":                  triggers,\n\t\"TRIM\":                      trim,\n\t\"TRUE\":                      trueKwd,\n\t\"TRUNCATE\":                  truncate,\n\t\"TYPE\":                      tp,\n\t\"UNBOUNDED\":                 unbounded,\n\t\"UNCOMMITTED\":               uncommitted,\n\t\"UNICODE\":                   unicodeSym,\n\t\"UNDEFINED\":                 undefined,\n\t\"UNION\":                     union,\n\t\"UNIQUE\":                    unique,\n\t\"UNKNOWN\":                   unknown,\n\t\"UNLOCK\":                    unlock,\n\t\"UNSIGNED\":                  unsigned,\n\t\"UNTIL\":                     until,\n\t\"UPDATE\":                    update,\n\t\"USAGE\":                     usage,\n\t\"USE\":                       use,\n\t\"USER\":                      user,\n\t\"USING\":                     using,\n\t\"UTC_DATE\":                  utcDate,\n\t\"UTC_TIME\":                  utcTime,\n\t\"UTC_TIMESTAMP\":             utcTimestamp,\n\t\"VALIDATION\":                validation,\n\t\"VALUE\":                     value,\n\t\"VALUES\":                    values,\n\t\"VARBINARY\":                 varbinaryType,\n\t\"VARCHAR\":                   varcharType,\n\t\"VARCHARACTER\":              varcharacter,\n\t\"VARIABLES\":                 variables,\n\t\"VARIANCE\":                  varPop,\n\t\"VARYING\":                   varying,\n\t\"VAR_POP\":                   varPop,\n\t\"VAR_SAMP\":                  varSamp,\n\t\"VIEW\":                      view,\n\t\"VIRTUAL\":                   virtual,\n\t\"VISIBLE\":                   visible,\n\t\"WARNINGS\":                  warnings,\n\t\"ERRORS\":                    identSQLErrors,\n\t\"WEEK\":                      week,\n\t\"WHEN\":                      when,\n\t\"WHERE\":                     where,\n\t\"WIDTH\":                     width,\n\t\"WITH\":                      with,\n\t\"WITHOUT\":                   without,\n\t\"WRITE\":                     write,\n\t\"XOR\":                       xor,\n\t\"X509\":                      x509,\n\t\"YEAR\":                      yearType,\n\t\"YEAR_MONTH\":                yearMonth,\n\t\"ZEROFILL\":                  zerofill,\n\t\"BINDING\":                   binding,\n\t\"BINDINGS\":                  bindings,\n\t\"EXPR_PUSHDOWN_BLACKLIST\":   exprPushdownBlacklist,\n\t\"OPT_RULE_BLACKLIST\":        optRuleBlacklist,\n\t\"NOWAIT\":                    nowait,\n\t\"PLAINTEXT\":                 plaintext,\n\t\"PLAINTEXT_AFTER_JOIN\":      plaintextAfterJoin,\n\t\"PLAINTEXT_AS_JOIN_PAYLOAD\": plaintextAsJoinPayload,\n\t\"PLAINTEXT_AFTER_GROUP_BY\":  plaintextAfterGroupBy,\n\t\"PLAINTEXT_AFTER_COMPARE\":   plaintextAfterCompare,\n\t\"PLAINTEXT_AFTER_AGGREGATE\": plaintextAfterAggregate,\n\t\"REVEAL_RANK\":               revealRank,\n\t\"ENCRYPTED_ONLY\":            encryptedOnly,\n\t\"TOKEN\":                     tokenWord,\n\t\"ENDPOINT\":                  endpoint,\n\t\"REF_TABLE\":                 refTable,\n\t\"DB_TYPE\":                   dbType,\n\t\"{{\":                        leftMarker,\n\t\"}}\":                        rightMarker,\n}\n\n// See https://dev.mysql.com/doc/refman/5.7/en/function-resolution.html for details\nvar btFuncTokenMap = map[string]int{\n\t\"ADDDATE\":         builtinAddDate,\n\t\"BIT_AND\":         builtinBitAnd,\n\t\"BIT_OR\":          builtinBitOr,\n\t\"BIT_XOR\":         builtinBitXor,\n\t\"CAST\":            builtinCast,\n\t\"COUNT\":           builtinCount,\n\t\"CURDATE\":         builtinCurDate,\n\t\"CURTIME\":         builtinCurTime,\n\t\"DATE_ADD\":        builtinDateAdd,\n\t\"DATE_SUB\":        builtinDateSub,\n\t\"EXTRACT\":         builtinExtract,\n\t\"GROUP_CONCAT\":    builtinGroupConcat,\n\t\"MAX\":             builtinMax,\n\t\"MID\":             builtinSubstring,\n\t\"MIN\":             builtinMin,\n\t\"NOW\":             builtinNow,\n\t\"PERCENTILE_DISC\": builtinPercentileDisc,\n\t\"POSITION\":        builtinPosition,\n\t\"SESSION_USER\":    builtinUser,\n\t\"STD\":             builtinStddevPop,\n\t\"STDDEV\":          builtinStddevPop,\n\t\"STDDEV_POP\":      builtinStddevPop,\n\t\"STDDEV_SAMP\":     builtinStddevSamp,\n\t\"SUBDATE\":         builtinSubDate,\n\t\"SUBSTR\":          builtinSubstring,\n\t\"SUBSTRING\":       builtinSubstring,\n\t\"SUM\":             builtinSum,\n\t\"SYSDATE\":         builtinSysDate,\n\t\"SYSTEM_USER\":     builtinUser,\n\t\"TRIM\":            builtinTrim,\n\t\"VARIANCE\":        builtinVarPop,\n\t\"VAR_POP\":         builtinVarPop,\n\t\"VAR_SAMP\":        builtinVarSamp,\n\t\"MEDIAN\":          builtinMedian,\n}\n\nvar windowFuncTokenMap = map[string]int{\n\t\"CUME_DIST\":    cumeDist,\n\t\"DENSE_RANK\":   denseRank,\n\t\"FIRST_VALUE\":  firstValue,\n\t\"GROUPS\":       groups,\n\t\"LAG\":          lag,\n\t\"LAST_VALUE\":   lastValue,\n\t\"LEAD\":         lead,\n\t\"NTH_VALUE\":    nthValue,\n\t\"NTILE\":        ntile,\n\t\"OVER\":         over,\n\t\"PERCENT_RANK\": percentRank,\n\t\"RANK\":         rank,\n\t\"ROWS\":         rows,\n\t\"ROW_NUMBER\":   rowNumber,\n\t\"WINDOW\":       window,\n}\n\n// aliases are strings directly map to another string and use the same token.\nvar aliases = map[string]string{\n\t\"SCHEMA\":  \"DATABASE\",\n\t\"SCHEMAS\": \"DATABASES\",\n\t\"DEC\":     \"DECIMAL\",\n\t\"SUBSTR\":  \"SUBSTRING\",\n}\n\n// hintedTokens is a set of tokens which recognizes a hint.\n// According to https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html,\n// only SELECT, INSERT, REPLACE, UPDATE and DELETE accept optimizer hints.\n// additionally we support CREATE and PARTITION for hints at table creation.\nvar hintedTokens = map[int]struct{}{\n\tselectKwd: {},\n\tinsert:    {},\n\treplace:   {},\n\tupdate:    {},\n\tdeleteKwd: {},\n\tcreate:    {},\n\tpartition: {},\n}\n\nvar hintTokenMap = map[string]int{\n\t// MySQL 8.0 hint names\n\t\"JOIN_FIXED_ORDER\":      hintJoinFixedOrder,\n\t\"JOIN_ORDER\":            hintJoinOrder,\n\t\"JOIN_PREFIX\":           hintJoinPrefix,\n\t\"JOIN_SUFFIX\":           hintJoinSuffix,\n\t\"BKA\":                   hintBKA,\n\t\"NO_BKA\":                hintNoBKA,\n\t\"BNL\":                   hintBNL,\n\t\"NO_BNL\":                hintNoBNL,\n\t\"HASH_JOIN\":             hintHashJoin,\n\t\"NO_HASH_JOIN\":          hintNoHashJoin,\n\t\"MERGE\":                 hintMerge,\n\t\"NO_MERGE\":              hintNoMerge,\n\t\"INDEX_MERGE\":           hintIndexMerge,\n\t\"NO_INDEX_MERGE\":        hintNoIndexMerge,\n\t\"MRR\":                   hintMRR,\n\t\"NO_MRR\":                hintNoMRR,\n\t\"NO_ICP\":                hintNoICP,\n\t\"NO_RANGE_OPTIMIZATION\": hintNoRangeOptimization,\n\t\"SKIP_SCAN\":             hintSkipScan,\n\t\"NO_SKIP_SCAN\":          hintNoSkipScan,\n\t\"SEMIJOIN\":              hintSemijoin,\n\t\"NO_SEMIJOIN\":           hintNoSemijoin,\n\t\"MAX_EXECUTION_TIME\":    hintMaxExecutionTime,\n\t\"SET_VAR\":               hintSetVar,\n\t\"RESOURCE_GROUP\":        hintResourceGroup,\n\t\"QB_NAME\":               hintQBName,\n\n\t// TiDB hint names\n\t\"AGG_TO_COP\":              hintAggToCop,\n\t\"ENABLE_PLAN_CACHE\":       hintEnablePlanCache,\n\t\"HASH_AGG\":                hintHashAgg,\n\t\"IGNORE_INDEX\":            hintIgnoreIndex,\n\t\"INL_HASH_JOIN\":           hintInlHashJoin,\n\t\"INL_JOIN\":                hintInlJoin,\n\t\"INL_MERGE_JOIN\":          hintInlMergeJoin,\n\t\"MEMORY_QUOTA\":            hintMemoryQuota,\n\t\"NO_SWAP_JOIN_INPUTS\":     hintNoSwapJoinInputs,\n\t\"QUERY_TYPE\":              hintQueryType,\n\t\"READ_CONSISTENT_REPLICA\": hintReadConsistentReplica,\n\t\"READ_FROM_STORAGE\":       hintReadFromStorage,\n\t\"SM_JOIN\":                 hintSMJoin,\n\t\"STREAM_AGG\":              hintStreamAgg,\n\t\"SWAP_JOIN_INPUTS\":        hintSwapJoinInputs,\n\t\"USE_INDEX_MERGE\":         hintUseIndexMerge,\n\t\"USE_INDEX\":               hintUseIndex,\n\t\"USE_PLAN_CACHE\":          hintUsePlanCache,\n\t\"USE_TOJA\":                hintUseToja,\n\n\t// TiDB hint aliases\n\t\"TIDB_HJ\":   hintHashJoin,\n\t\"TIDB_INLJ\": hintInlJoin,\n\t\"TIDB_SMJ\":  hintSMJoin,\n\n\t// Other keywords\n\t\"OLAP\":            hintOLAP,\n\t\"OLTP\":            hintOLTP,\n\t\"TIKV\":            hintTiKV,\n\t\"TIFLASH\":         hintTiFlash,\n\t\"FALSE\":           hintFalse,\n\t\"TRUE\":            hintTrue,\n\t\"MB\":              hintMB,\n\t\"GB\":              hintGB,\n\t\"DUPSWEEDOUT\":     hintDupsWeedOut,\n\t\"FIRSTMATCH\":      hintFirstMatch,\n\t\"LOOSESCAN\":       hintLooseScan,\n\t\"MATERIALIZATION\": hintMaterialization,\n}\n\nfunc (s *Scanner) isTokenIdentifier(lit string, offset int) int {\n\t// An identifier before or after '.' means it is part of a qualified identifier.\n\t// We do not parse it as keyword.\n\tif s.r.peek() == '.' {\n\t\treturn 0\n\t}\n\tif offset > 0 && s.r.s[offset-1] == '.' {\n\t\treturn 0\n\t}\n\tbuf := &s.buf\n\tbuf.Reset()\n\tbuf.Grow(len(lit))\n\tdata := buf.Bytes()[:len(lit)]\n\tfor i := 0; i < len(lit); i++ {\n\t\tif lit[i] >= 'a' && lit[i] <= 'z' {\n\t\t\tdata[i] = lit[i] + 'A' - 'a'\n\t\t} else {\n\t\t\tdata[i] = lit[i]\n\t\t}\n\t}\n\n\tcheckBtFuncToken := false\n\tif s.r.peek() == '(' {\n\t\tcheckBtFuncToken = true\n\t} else if s.sqlMode.HasIgnoreSpaceMode() {\n\t\ts.skipWhitespace()\n\t\tif s.r.peek() == '(' {\n\t\t\tcheckBtFuncToken = true\n\t\t}\n\t}\n\tif checkBtFuncToken {\n\t\tif tok := btFuncTokenMap[string(data)]; tok != 0 {\n\t\t\treturn tok\n\t\t}\n\t}\n\ttok, ok := tokenMap[string(data)]\n\tif !ok && s.supportWindowFunc {\n\t\ttok = windowFuncTokenMap[string(data)]\n\t}\n\treturn tok\n}\n\nfunc handleIdent(lval *yySymType) int {\n\ts := lval.ident\n\t// A character string literal may have an optional character set introducer and COLLATE clause:\n\t// [_charset_name]'string' [COLLATE collation_name]\n\t// See https://dev.mysql.com/doc/refman/5.7/en/charset-literal.html\n\tif !strings.HasPrefix(s, \"_\") {\n\t\treturn identifier\n\t}\n\tcs, _, err := charset.GetCharsetInfo(s[1:])\n\tif err != nil {\n\t\treturn identifier\n\t}\n\tlval.ident = cs\n\treturn underscoreCS\n}\n"
  },
  {
    "path": "pkg/parser/model/ddl.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage model\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n)\n\n// ActionType is the type for DDL action.\ntype ActionType byte\n\n// List DDL actions.\nconst (\n\tActionNone                          ActionType = 0\n\tActionCreateSchema                  ActionType = 1\n\tActionDropSchema                    ActionType = 2\n\tActionCreateTable                   ActionType = 3\n\tActionDropTable                     ActionType = 4\n\tActionAddColumn                     ActionType = 5\n\tActionDropColumn                    ActionType = 6\n\tActionAddIndex                      ActionType = 7\n\tActionDropIndex                     ActionType = 8\n\tActionAddForeignKey                 ActionType = 9\n\tActionDropForeignKey                ActionType = 10\n\tActionTruncateTable                 ActionType = 11\n\tActionModifyColumn                  ActionType = 12\n\tActionRebaseAutoID                  ActionType = 13\n\tActionRenameTable                   ActionType = 14\n\tActionSetDefaultValue               ActionType = 15\n\tActionShardRowID                    ActionType = 16\n\tActionModifyTableComment            ActionType = 17\n\tActionRenameIndex                   ActionType = 18\n\tActionAddTablePartition             ActionType = 19\n\tActionDropTablePartition            ActionType = 20\n\tActionCreateView                    ActionType = 21\n\tActionModifyTableCharsetAndCollate  ActionType = 22\n\tActionTruncateTablePartition        ActionType = 23\n\tActionDropView                      ActionType = 24\n\tActionRecoverTable                  ActionType = 25\n\tActionModifySchemaCharsetAndCollate ActionType = 26\n\tActionLockTable                     ActionType = 27\n\tActionUnlockTable                   ActionType = 28\n\tActionRepairTable                   ActionType = 29\n\tActionSetTiFlashReplica             ActionType = 30\n\tActionUpdateTiFlashReplicaStatus    ActionType = 31\n\tActionAddPrimaryKey                 ActionType = 32\n\tActionDropPrimaryKey                ActionType = 33\n\tActionCreateSequence                ActionType = 34\n\tActionAlterSequence                 ActionType = 35\n\tActionDropSequence                  ActionType = 36\n)\n\nconst (\n\t// AddIndexStr is a string related to the operation of \"add index\".\n\tAddIndexStr      = \"add index\"\n\tAddPrimaryKeyStr = \"add primary key\"\n)\n\nvar actionMap = map[ActionType]string{\n\tActionCreateSchema:                  \"create schema\",\n\tActionDropSchema:                    \"drop schema\",\n\tActionCreateTable:                   \"create table\",\n\tActionDropTable:                     \"drop table\",\n\tActionAddColumn:                     \"add column\",\n\tActionDropColumn:                    \"drop column\",\n\tActionAddIndex:                      AddIndexStr,\n\tActionDropIndex:                     \"drop index\",\n\tActionAddForeignKey:                 \"add foreign key\",\n\tActionDropForeignKey:                \"drop foreign key\",\n\tActionTruncateTable:                 \"truncate table\",\n\tActionModifyColumn:                  \"modify column\",\n\tActionRebaseAutoID:                  \"rebase auto_increment ID\",\n\tActionRenameTable:                   \"rename table\",\n\tActionSetDefaultValue:               \"set default value\",\n\tActionShardRowID:                    \"shard row ID\",\n\tActionModifyTableComment:            \"modify table comment\",\n\tActionRenameIndex:                   \"rename index\",\n\tActionAddTablePartition:             \"add partition\",\n\tActionDropTablePartition:            \"drop partition\",\n\tActionCreateView:                    \"create view\",\n\tActionModifyTableCharsetAndCollate:  \"modify table charset and collate\",\n\tActionTruncateTablePartition:        \"truncate partition\",\n\tActionDropView:                      \"drop view\",\n\tActionRecoverTable:                  \"recover table\",\n\tActionModifySchemaCharsetAndCollate: \"modify schema charset and collate\",\n\tActionLockTable:                     \"lock table\",\n\tActionUnlockTable:                   \"unlock table\",\n\tActionRepairTable:                   \"repair table\",\n\tActionSetTiFlashReplica:             \"set tiflash replica\",\n\tActionUpdateTiFlashReplicaStatus:    \"update tiflash replica status\",\n\tActionAddPrimaryKey:                 AddPrimaryKeyStr,\n\tActionDropPrimaryKey:                \"drop primary key\",\n\tActionCreateSequence:                \"create sequence\",\n\tActionAlterSequence:                 \"alter sequence\",\n\tActionDropSequence:                  \"drop sequence\",\n}\n\n// String return current ddl action in string\nfunc (action ActionType) String() string {\n\tif v, ok := actionMap[action]; ok {\n\t\treturn v\n\t}\n\treturn \"none\"\n}\n\n// HistoryInfo is used for binlog.\ntype HistoryInfo struct {\n\tSchemaVersion int64\n\tDBInfo        *DBInfo\n\tTableInfo     *TableInfo\n\tFinishedTS    uint64\n}\n\n// AddDBInfo adds schema version and schema information that are used for binlog.\n// dbInfo is added in the following operations: create database, drop database.\nfunc (h *HistoryInfo) AddDBInfo(schemaVer int64, dbInfo *DBInfo) {\n\th.SchemaVersion = schemaVer\n\th.DBInfo = dbInfo\n}\n\n// AddTableInfo adds schema version and table information that are used for binlog.\n// tblInfo is added except for the following operations: create database, drop database.\nfunc (h *HistoryInfo) AddTableInfo(schemaVer int64, tblInfo *TableInfo) {\n\th.SchemaVersion = schemaVer\n\th.TableInfo = tblInfo\n}\n\n// Clean cleans history information.\nfunc (h *HistoryInfo) Clean() {\n\th.SchemaVersion = 0\n\th.DBInfo = nil\n\th.TableInfo = nil\n}\n\n// DDLReorgMeta is meta info of DDL reorganization.\ntype DDLReorgMeta struct {\n\t// EndHandle is the last handle of the adding indices table.\n\t// We should only backfill indices in the range [startHandle, EndHandle].\n\tEndHandle int64 `json:\"end_handle\"`\n}\n\n// NewDDLReorgMeta new a DDLReorgMeta.\nfunc NewDDLReorgMeta() *DDLReorgMeta {\n\treturn &DDLReorgMeta{\n\t\tEndHandle: math.MaxInt64,\n\t}\n}\n\n// Job is for a DDL operation.\ntype Job struct {\n\tID         int64         `json:\"id\"`\n\tType       ActionType    `json:\"type\"`\n\tSchemaID   int64         `json:\"schema_id\"`\n\tTableID    int64         `json:\"table_id\"`\n\tSchemaName string        `json:\"schema_name\"`\n\tState      JobState      `json:\"state\"`\n\tError      *terror.Error `json:\"err\"`\n\t// ErrorCount will be increased, every time we meet an error when running job.\n\tErrorCount int64 `json:\"err_count\"`\n\t// RowCount means the number of rows that are processed.\n\tRowCount int64         `json:\"row_count\"`\n\tMu       sync.Mutex    `json:\"-\"`\n\tArgs     []interface{} `json:\"-\"`\n\t// RawArgs : We must use json raw message to delay parsing special args.\n\tRawArgs     json.RawMessage `json:\"raw_args\"`\n\tSchemaState SchemaState     `json:\"schema_state\"`\n\t// SnapshotVer means snapshot version for this job.\n\tSnapshotVer uint64 `json:\"snapshot_ver\"`\n\t// StartTS uses timestamp allocated by TSO.\n\t// Now it's the TS when we put the job to TiKV queue.\n\tStartTS uint64 `json:\"start_ts\"`\n\t// DependencyID is the job's ID that the current job depends on.\n\tDependencyID int64 `json:\"dependency_id\"`\n\t// Query string of the ddl job.\n\tQuery      string       `json:\"query\"`\n\tBinlogInfo *HistoryInfo `json:\"binlog\"`\n\n\t// Version indicates the DDL job version. For old jobs, it will be 0.\n\tVersion int64 `json:\"version\"`\n\n\t// ReorgMeta is meta info of ddl reorganization.\n\t// This field is depreciated.\n\tReorgMeta *DDLReorgMeta `json:\"reorg_meta\"`\n\n\t// Priority is only used to set the operation priority of adding indices.\n\tPriority int `json:\"priority\"`\n}\n\n// FinishTableJob is called when a job is finished.\n// It updates the job's state information and adds tblInfo to the binlog.\nfunc (job *Job) FinishTableJob(jobState JobState, schemaState SchemaState, ver int64, tblInfo *TableInfo) {\n\tjob.State = jobState\n\tjob.SchemaState = schemaState\n\tjob.BinlogInfo.AddTableInfo(ver, tblInfo)\n}\n\n// FinishDBJob is called when a job is finished.\n// It updates the job's state information and adds dbInfo the binlog.\nfunc (job *Job) FinishDBJob(jobState JobState, schemaState SchemaState, ver int64, dbInfo *DBInfo) {\n\tjob.State = jobState\n\tjob.SchemaState = schemaState\n\tjob.BinlogInfo.AddDBInfo(ver, dbInfo)\n}\n\n// TSConvert2Time converts timestamp to time.\nfunc TSConvert2Time(ts uint64) time.Time {\n\tt := int64(ts >> 18) // 18 is for the logical time.\n\treturn time.Unix(t/1e3, (t%1e3)*1e6)\n}\n\n// SetRowCount sets the number of rows. Make sure it can pass `make race`.\nfunc (job *Job) SetRowCount(count int64) {\n\tjob.Mu.Lock()\n\tdefer job.Mu.Unlock()\n\n\tjob.RowCount = count\n}\n\n// GetRowCount gets the number of rows. Make sure it can pass `make race`.\nfunc (job *Job) GetRowCount() int64 {\n\tjob.Mu.Lock()\n\tdefer job.Mu.Unlock()\n\n\treturn job.RowCount\n}\n\n// Encode encodes job with json format.\n// updateRawArgs is used to determine whether to update the raw args.\nfunc (job *Job) Encode(updateRawArgs bool) ([]byte, error) {\n\tvar err error\n\tif updateRawArgs {\n\t\tjob.RawArgs, err = json.Marshal(job.Args)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Trace(err)\n\t\t}\n\t}\n\n\tvar b []byte\n\tjob.Mu.Lock()\n\tdefer job.Mu.Unlock()\n\tb, err = json.Marshal(job)\n\n\treturn b, errors.Trace(err)\n}\n\n// Decode decodes job from the json buffer, we must use DecodeArgs later to\n// decode special args for this job.\nfunc (job *Job) Decode(b []byte) error {\n\terr := json.Unmarshal(b, job)\n\treturn errors.Trace(err)\n}\n\n// DecodeArgs decodes job args.\nfunc (job *Job) DecodeArgs(args ...interface{}) error {\n\tjob.Args = args\n\terr := json.Unmarshal(job.RawArgs, &job.Args)\n\treturn errors.Trace(err)\n}\n\n// String implements fmt.Stringer interface.\nfunc (job *Job) String() string {\n\trowCount := job.GetRowCount()\n\treturn fmt.Sprintf(\"ID:%d, Type:%s, State:%s, SchemaState:%s, SchemaID:%d, TableID:%d, RowCount:%d, ArgLen:%d, start time: %v, Err:%v, ErrCount:%d, SnapshotVersion:%v\",\n\t\tjob.ID, job.Type, job.State, job.SchemaState, job.SchemaID, job.TableID, rowCount, len(job.Args), TSConvert2Time(job.StartTS), job.Error, job.ErrorCount, job.SnapshotVer)\n}\n\nfunc (job *Job) hasDependentSchema(other *Job) (bool, error) {\n\tif other.Type == ActionDropSchema || other.Type == ActionCreateSchema {\n\t\tif other.SchemaID == job.SchemaID {\n\t\t\treturn true, nil\n\t\t}\n\t\tif job.Type == ActionRenameTable {\n\t\t\tvar oldSchemaID int64\n\t\t\tif err := job.DecodeArgs(&oldSchemaID); err != nil {\n\t\t\t\treturn false, errors.Trace(err)\n\t\t\t}\n\t\t\tif other.SchemaID == oldSchemaID {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t}\n\t}\n\treturn false, nil\n}\n\n// IsDependentOn returns whether the job depends on \"other\".\n// How to check the job depends on \"other\"?\n// 1. The two jobs handle the same database when one of the two jobs is an ActionDropSchema or ActionCreateSchema type.\n// 2. Or the two jobs handle the same table.\nfunc (job *Job) IsDependentOn(other *Job) (bool, error) {\n\tisDependent, err := job.hasDependentSchema(other)\n\tif err != nil || isDependent {\n\t\treturn isDependent, errors.Trace(err)\n\t}\n\tisDependent, err = other.hasDependentSchema(job)\n\tif err != nil || isDependent {\n\t\treturn isDependent, errors.Trace(err)\n\t}\n\n\t// TODO: If a job is ActionRenameTable, we need to check table name.\n\tif other.TableID == job.TableID {\n\t\treturn true, nil\n\t}\n\treturn false, nil\n}\n\n// IsFinished returns whether job is finished or not.\n// If the job state is Done or Cancelled, it is finished.\nfunc (job *Job) IsFinished() bool {\n\treturn job.State == JobStateDone || job.State == JobStateRollbackDone || job.State == JobStateCancelled\n}\n\n// IsCancelled returns whether the job is cancelled or not.\nfunc (job *Job) IsCancelled() bool {\n\treturn job.State == JobStateCancelled\n}\n\n// IsRollbackDone returns whether the job is rolled back or not.\nfunc (job *Job) IsRollbackDone() bool {\n\treturn job.State == JobStateRollbackDone\n}\n\n// IsRollingback returns whether the job is rolling back or not.\nfunc (job *Job) IsRollingback() bool {\n\treturn job.State == JobStateRollingback\n}\n\n// IsCancelling returns whether the job is cancelling or not.\nfunc (job *Job) IsCancelling() bool {\n\treturn job.State == JobStateCancelling\n}\n\n// IsSynced returns whether the DDL modification is synced among all TiDB servers.\nfunc (job *Job) IsSynced() bool {\n\treturn job.State == JobStateSynced\n}\n\n// IsDone returns whether job is done.\nfunc (job *Job) IsDone() bool {\n\treturn job.State == JobStateDone\n}\n\n// IsRunning returns whether job is still running or not.\nfunc (job *Job) IsRunning() bool {\n\treturn job.State == JobStateRunning\n}\n\n// JobState is for job state.\ntype JobState byte\n\n// List job states.\nconst (\n\tJobStateNone    JobState = 0\n\tJobStateRunning JobState = 1\n\t// When DDL encountered an unrecoverable error at reorganization state,\n\t// some keys has been added already, we need to remove them.\n\t// JobStateRollingback is the state to do the rolling back job.\n\tJobStateRollingback  JobState = 2\n\tJobStateRollbackDone JobState = 3\n\tJobStateDone         JobState = 4\n\tJobStateCancelled    JobState = 5\n\t// JobStateSynced is used to mark the information about the completion of this job\n\t// has been synchronized to all servers.\n\tJobStateSynced JobState = 6\n\t// JobStateCancelling is used to mark the DDL job is cancelled by the client, but the DDL work hasn't handle it.\n\tJobStateCancelling JobState = 7\n)\n\n// String implements fmt.Stringer interface.\nfunc (s JobState) String() string {\n\tswitch s {\n\tcase JobStateRunning:\n\t\treturn \"running\"\n\tcase JobStateRollingback:\n\t\treturn \"rollingback\"\n\tcase JobStateRollbackDone:\n\t\treturn \"rollback done\"\n\tcase JobStateDone:\n\t\treturn \"done\"\n\tcase JobStateCancelled:\n\t\treturn \"cancelled\"\n\tcase JobStateCancelling:\n\t\treturn \"cancelling\"\n\tcase JobStateSynced:\n\t\treturn \"synced\"\n\tdefault:\n\t\treturn \"none\"\n\t}\n}\n\n// SchemaDiff contains the schema modification at a particular schema version.\n// It is used to reduce schema reload cost.\ntype SchemaDiff struct {\n\tVersion  int64      `json:\"version\"`\n\tType     ActionType `json:\"type\"`\n\tSchemaID int64      `json:\"schema_id\"`\n\tTableID  int64      `json:\"table_id\"`\n\n\t// OldTableID is the table ID before truncate, only used by truncate table DDL.\n\tOldTableID int64 `json:\"old_table_id\"`\n\t// OldSchemaID is the schema ID before rename table, only used by rename table DDL.\n\tOldSchemaID int64 `json:\"old_schema_id\"`\n}\n"
  },
  {
    "path": "pkg/parser/model/flags.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage model\n\n// Flags are used by tipb.SelectRequest.Flags to handle execution mode, like how to handle truncate error.\nconst (\n\t// FlagIgnoreTruncate indicates if truncate error should be ignored.\n\t// Read-only statements should ignore truncate error, write statements should not ignore truncate error.\n\tFlagIgnoreTruncate uint64 = 1\n\t// FlagTruncateAsWarning indicates if truncate error should be returned as warning.\n\t// This flag only matters if FlagIgnoreTruncate is not set, in strict sql mode, truncate error should\n\t// be returned as error, in non-strict sql mode, truncate error should be saved as warning.\n\tFlagTruncateAsWarning = 1 << 1\n\t// FlagPadCharToFullLength indicates if sql_mode 'PAD_CHAR_TO_FULL_LENGTH' is set.\n\tFlagPadCharToFullLength = 1 << 2\n\t// FlagInInsertStmt indicates if this is a INSERT statement.\n\tFlagInInsertStmt = 1 << 3\n\t// FlagInUpdateOrDeleteStmt indicates if this is a UPDATE statement or a DELETE statement.\n\tFlagInUpdateOrDeleteStmt = 1 << 4\n\t// FlagInSelectStmt indicates if this is a SELECT statement.\n\tFlagInSelectStmt = 1 << 5\n\t// FlagOverflowAsWarning indicates if overflow error should be returned as warning.\n\t// In strict sql mode, overflow error should be returned as error,\n\t// in non-strict sql mode, overflow error should be saved as warning.\n\tFlagOverflowAsWarning = 1 << 6\n\t// FlagIgnoreZeroInDate indicates if ZeroInDate error should be ignored.\n\t// Read-only statements should ignore ZeroInDate error.\n\t// Write statements should not ignore ZeroInDate error in strict sql mode.\n\tFlagIgnoreZeroInDate = 1 << 7\n\t// FlagDividedByZeroAsWarning indicates if DividedByZero should be returned as warning.\n\tFlagDividedByZeroAsWarning = 1 << 8\n\t// FlagInUnionStmt indicates if this is a UNION statement.\n\tFlagInUnionStmt = 1 << 9\n\t// FlagInLoadDataStmt indicates if this is a LOAD DATA statement.\n\tFlagInLoadDataStmt = 1 << 10\n)\n"
  },
  {
    "path": "pkg/parser/model/model.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage model\n\nimport (\n\t\"encoding/json\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/auth\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/types\"\n)\n\n// SchemaState is the state for schema elements.\ntype SchemaState byte\n\nconst (\n\t// StateNone means this schema element is absent and can't be used.\n\tStateNone SchemaState = iota\n\t// StateDeleteOnly means we can only delete items for this schema element.\n\tStateDeleteOnly\n\t// StateWriteOnly means we can use any write operation on this schema element,\n\t// but outer can't read the changed data.\n\tStateWriteOnly\n\t// StateWriteReorganization means we are re-organizing whole data after write only state.\n\tStateWriteReorganization\n\t// StateDeleteReorganization means we are re-organizing whole data after delete only state.\n\tStateDeleteReorganization\n\t// StatePublic means this schema element is ok for all write and read operations.\n\tStatePublic\n)\n\n// String implements fmt.Stringer interface.\nfunc (s SchemaState) String() string {\n\tswitch s {\n\tcase StateDeleteOnly:\n\t\treturn \"delete only\"\n\tcase StateWriteOnly:\n\t\treturn \"write only\"\n\tcase StateWriteReorganization:\n\t\treturn \"write reorganization\"\n\tcase StateDeleteReorganization:\n\t\treturn \"delete reorganization\"\n\tcase StatePublic:\n\t\treturn \"public\"\n\tdefault:\n\t\treturn \"none\"\n\t}\n}\n\nconst (\n\t// ColumnInfoVersion0 means the column info version is 0.\n\tColumnInfoVersion0 = uint64(0)\n\t// ColumnInfoVersion1 means the column info version is 1.\n\tColumnInfoVersion1 = uint64(1)\n\t// ColumnInfoVersion2 means the column info version is 2.\n\t// This is for v2.1.7 to Compatible with older versions charset problem.\n\t// Old version such as v2.0.8 treat utf8 as utf8mb4, because there is no UTF8 check in v2.0.8.\n\t// After version V2.1.2 (PR#8738) , TiDB add UTF8 check, then the user upgrade from v2.0.8 insert some UTF8MB4 characters will got error.\n\t// This is not compatibility for user. Then we try to fix this in PR #9820, and increase the version number.\n\tColumnInfoVersion2 = uint64(2)\n\n\t// CurrLatestColumnInfoVersion means the latest column info in the current TiDB.\n\tCurrLatestColumnInfoVersion = ColumnInfoVersion2\n)\n\n// ColumnInfo provides meta data describing of a table column.\ntype ColumnInfo struct {\n\tID                  int64               `json:\"id\"`\n\tName                CIStr               `json:\"name\"`\n\tOffset              int                 `json:\"offset\"`\n\tOriginDefaultValue  interface{}         `json:\"origin_default\"`\n\tDefaultValue        interface{}         `json:\"default\"`\n\tDefaultValueBit     []byte              `json:\"default_bit\"`\n\tGeneratedExprString string              `json:\"generated_expr_string\"`\n\tGeneratedStored     bool                `json:\"generated_stored\"`\n\tDependences         map[string]struct{} `json:\"dependences\"`\n\ttypes.FieldType     `json:\"type\"`\n\tState               SchemaState `json:\"state\"`\n\tComment             string      `json:\"comment\"`\n\t// A hidden column is used internally(expression index) and are not accessible by users.\n\tHidden bool `json:\"hidden\"`\n\t// Version means the version of the column info.\n\t// Version = 0: For OriginDefaultValue and DefaultValue of timestamp column will stores the default time in system time zone.\n\t//              That is a bug if multiple TiDB servers in different system time zone.\n\t// Version = 1: For OriginDefaultValue and DefaultValue of timestamp column will stores the default time in UTC time zone.\n\t//              This will fix bug in version 0. For compatibility with version 0, we add version field in column info struct.\n\tVersion uint64 `json:\"version\"`\n}\n\n// Clone clones ColumnInfo.\nfunc (c *ColumnInfo) Clone() *ColumnInfo {\n\tnc := *c\n\treturn &nc\n}\n\n// IsGenerated returns true if the column is generated column.\nfunc (c *ColumnInfo) IsGenerated() bool {\n\treturn len(c.GeneratedExprString) != 0\n}\n\n// SetDefaultValue sets the default value.\nfunc (c *ColumnInfo) SetDefaultValue(value interface{}) error {\n\tc.DefaultValue = value\n\tif c.Tp == mysql.TypeBit {\n\t\t// For mysql.TypeBit type, the default value storage format must be a string.\n\t\t// Other value such as int must convert to string format first.\n\t\t// The mysql.TypeBit type supports the null default value.\n\t\tif value == nil {\n\t\t\treturn nil\n\t\t}\n\t\tif v, ok := value.(string); ok {\n\t\t\tc.DefaultValueBit = []byte(v)\n\t\t\treturn nil\n\t\t}\n\t\treturn types.ErrInvalidDefault.GenWithStackByArgs(c.Name)\n\t}\n\treturn nil\n}\n\n// GetDefaultValue gets the default value of the column.\n// Default value use to stored in DefaultValue field, but now,\n// bit type default value will store in DefaultValueBit for fix bit default value decode/encode bug.\nfunc (c *ColumnInfo) GetDefaultValue() interface{} {\n\tif c.Tp == mysql.TypeBit && c.DefaultValueBit != nil {\n\t\treturn string(c.DefaultValueBit)\n\t}\n\treturn c.DefaultValue\n}\n\n// GetTypeDesc gets the description for column type.\nfunc (c *ColumnInfo) GetTypeDesc() string {\n\tdesc := c.FieldType.CompactStr()\n\tif mysql.HasUnsignedFlag(c.Flag) && c.Tp != mysql.TypeBit && c.Tp != mysql.TypeYear {\n\t\tdesc += \" unsigned\"\n\t}\n\tif mysql.HasZerofillFlag(c.Flag) && c.Tp != mysql.TypeYear {\n\t\tdesc += \" zerofill\"\n\t}\n\treturn desc\n}\n\n// FindColumnInfo finds ColumnInfo in cols by name.\nfunc FindColumnInfo(cols []*ColumnInfo, name string) *ColumnInfo {\n\tname = strings.ToLower(name)\n\tfor _, col := range cols {\n\t\tif col.Name.L == name {\n\t\t\treturn col\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ExtraHandleID is the column ID of column which we need to append to schema to occupy the handle's position\n// for use of execution phase.\nconst ExtraHandleID = -1\n\nconst (\n\t// TableInfoVersion0 means the table info version is 0.\n\t// Upgrade from v2.1.1 or v2.1.2 to v2.1.3 and later, and then execute a \"change/modify column\" statement\n\t// that does not specify a charset value for column. Then the following error may be reported:\n\t// ERROR 1105 (HY000): unsupported modify charset from utf8mb4 to utf8.\n\t// To eliminate this error, we will not modify the charset of this column\n\t// when executing a change/modify column statement that does not specify a charset value for column.\n\t// This behavior is not compatible with MySQL.\n\tTableInfoVersion0 = uint16(0)\n\t// TableInfoVersion1 means the table info version is 1.\n\t// When we execute a change/modify column statement that does not specify a charset value for column,\n\t// we set the charset of this column to the charset of table. This behavior is compatible with MySQL.\n\tTableInfoVersion1 = uint16(1)\n\t// TableInfoVersion2 means the table info version is 2.\n\t// This is for v2.1.7 to Compatible with older versions charset problem.\n\t// Old version such as v2.0.8 treat utf8 as utf8mb4, because there is no UTF8 check in v2.0.8.\n\t// After version V2.1.2 (PR#8738) , TiDB add UTF8 check, then the user upgrade from v2.0.8 insert some UTF8MB4 characters will got error.\n\t// This is not compatibility for user. Then we try to fix this in PR #9820, and increase the version number.\n\tTableInfoVersion2 = uint16(2)\n\t// TableInfoVersion3 means the table info version is 3.\n\t// This version aims to deal with upper-cased charset name in TableInfo stored by versions prior to TiDB v2.1.9:\n\t// TiDB always suppose all charsets / collations as lower-cased and try to convert them if they're not.\n\t// However, the convert is missed in some scenarios before v2.1.9, so for all those tables prior to TableInfoVersion3, their\n\t// charsets / collations will be converted to lower-case while loading from the storage.\n\tTableInfoVersion3 = uint16(3)\n\n\t// CurrLatestTableInfoVersion means the latest table info in the current TiDB.\n\tCurrLatestTableInfoVersion = TableInfoVersion3\n)\n\n// ExtraHandleName is the name of ExtraHandle Column.\nvar ExtraHandleName = NewCIStr(\"_tidb_rowid\")\n\n// TableInfo provides meta data describing a DB table.\ntype TableInfo struct {\n\tID      int64  `json:\"id\"`\n\tName    CIStr  `json:\"name\"`\n\tCharset string `json:\"charset\"`\n\tCollate string `json:\"collate\"`\n\t// Columns are listed in the order in which they appear in the schema.\n\tColumns     []*ColumnInfo `json:\"cols\"`\n\tIndices     []*IndexInfo  `json:\"index_info\"`\n\tForeignKeys []*FKInfo     `json:\"fk_info\"`\n\tState       SchemaState   `json:\"state\"`\n\tPKIsHandle  bool          `json:\"pk_is_handle\"`\n\tComment     string        `json:\"comment\"`\n\tAutoIncID   int64         `json:\"auto_inc_id\"`\n\tMaxColumnID int64         `json:\"max_col_id\"`\n\tMaxIndexID  int64         `json:\"max_idx_id\"`\n\t// UpdateTS is used to record the timestamp of updating the table's schema information.\n\t// These changing schema operations don't include 'truncate table' and 'rename table'.\n\tUpdateTS uint64 `json:\"update_timestamp\"`\n\t// OldSchemaID :\n\t// Because auto increment ID has schemaID as prefix,\n\t// We need to save original schemaID to keep autoID unchanged\n\t// while renaming a table from one database to another.\n\t// TODO: Remove it.\n\t// Now it only uses for compatibility with the old version that already uses this field.\n\tOldSchemaID int64 `json:\"old_schema_id,omitempty\"`\n\n\t// ShardRowIDBits specify if the implicit row ID is sharded.\n\tShardRowIDBits uint64\n\t// MaxShardRowIDBits uses to record the max ShardRowIDBits be used so far.\n\tMaxShardRowIDBits uint64 `json:\"max_shard_row_id_bits\"`\n\t// AutoRandomBits is used to set the bit number to shard automatically when PKIsHandle.\n\tAutoRandomBits uint64 `json:\"auto_random_bits\"`\n\t// PreSplitRegions specify the pre-split region when create table.\n\t// The pre-split region num is 2^(PreSplitRegions-1).\n\t// And the PreSplitRegions should less than or equal to ShardRowIDBits.\n\tPreSplitRegions uint64 `json:\"pre_split_regions\"`\n\n\tPartition *PartitionInfo `json:\"partition\"`\n\n\tCompression string `json:\"compression\"`\n\n\tView *ViewInfo `json:\"view\"`\n\n\tSequence *SequenceInfo `json:\"sequence\"`\n\n\t// Lock represent the table lock info.\n\tLock *TableLockInfo `json:\"Lock\"`\n\n\t// Version means the version of the table info.\n\tVersion uint16 `json:\"version\"`\n\n\t// TiFlashReplica means the TiFlash replica info.\n\tTiFlashReplica *TiFlashReplicaInfo `json:\"tiflash_replica\"`\n\n\t// New field for SCQL\n\tTableId      string `json:\"table_id\"`\n\tPartyCode    string `json:\"party_code\"`\n\tAccessParams string `json:\"access_params\"`\n}\n\n// TableLockInfo provides meta data describing a table lock.\ntype TableLockInfo struct {\n\tTp TableLockType\n\t// Use array because there may be multiple sessions holding the same read lock.\n\tSessions []SessionInfo\n\tState    TableLockState\n\t// TS is used to record the timestamp this table lock been locked.\n\tTS uint64\n}\n\n// SessionInfo contain the session ID and the server ID.\ntype SessionInfo struct {\n\tServerID  string\n\tSessionID uint64\n}\n\nfunc (s SessionInfo) String() string {\n\treturn \"server: \" + s.ServerID + \"_session: \" + strconv.FormatUint(s.SessionID, 10)\n}\n\n// TableLockTpInfo is composed by schema ID, table ID and table lock type.\ntype TableLockTpInfo struct {\n\tSchemaID int64\n\tTableID  int64\n\tTp       TableLockType\n}\n\n// TableLockState is the state for table lock.\ntype TableLockState byte\n\nconst (\n\t// TableLockStateNone means this table lock is absent.\n\tTableLockStateNone TableLockState = iota\n\t// TableLockStatePreLock means this table lock is pre-lock state. Other session doesn't hold this lock should't do corresponding operation according to the lock type.\n\tTableLockStatePreLock\n\t// TableLockStatePublic means this table lock is public state.\n\tTableLockStatePublic\n)\n\n// String implements fmt.Stringer interface.\nfunc (t TableLockState) String() string {\n\tswitch t {\n\tcase TableLockStatePreLock:\n\t\treturn \"pre-lock\"\n\tcase TableLockStatePublic:\n\t\treturn \"public\"\n\tdefault:\n\t\treturn \"none\"\n\t}\n}\n\n// TableLockType is the type of the table lock.\ntype TableLockType byte\n\nconst (\n\tTableLockNone TableLockType = iota\n\t// TableLockRead means the session with this lock can read the table (but not write it).\n\t// Multiple sessions can acquire a READ lock for the table at the same time.\n\t// Other sessions can read the table without explicitly acquiring a READ lock.\n\tTableLockRead\n\t// TableLockReadLocal is not supported.\n\tTableLockReadLocal\n\t// TableLockWrite means only the session with this lock has write/read permission.\n\t// Only the session that holds the lock can access the table. No other session can access it until the lock is released.\n\tTableLockWrite\n\t// TableLockWriteLocal means the session with this lock has write/read permission, and the other session still has read permission.\n\tTableLockWriteLocal\n)\n\nfunc (t TableLockType) String() string {\n\tswitch t {\n\tcase TableLockNone:\n\t\treturn \"NONE\"\n\tcase TableLockRead:\n\t\treturn \"READ\"\n\tcase TableLockReadLocal:\n\t\treturn \"READ LOCAL\"\n\tcase TableLockWriteLocal:\n\t\treturn \"WRITE LOCAL\"\n\tcase TableLockWrite:\n\t\treturn \"WRITE\"\n\t}\n\treturn \"\"\n}\n\n// TiFlashReplicaInfo means the flash replica info.\ntype TiFlashReplicaInfo struct {\n\tCount          uint64\n\tLocationLabels []string\n\tAvailable      bool\n}\n\n// GetPartitionInfo returns the partition information.\nfunc (t *TableInfo) GetPartitionInfo() *PartitionInfo {\n\tif t.Partition != nil && t.Partition.Enable {\n\t\treturn t.Partition\n\t}\n\treturn nil\n}\n\n// GetUpdateTime gets the table's updating time.\nfunc (t *TableInfo) GetUpdateTime() time.Time {\n\treturn TSConvert2Time(t.UpdateTS)\n}\n\n// GetDBID returns the schema ID that is used to create an allocator.\n// TODO: Remove it after removing OldSchemaID.\nfunc (t *TableInfo) GetDBID(dbID int64) int64 {\n\tif t.OldSchemaID != 0 {\n\t\treturn t.OldSchemaID\n\t}\n\treturn dbID\n}\n\n// Clone clones TableInfo.\nfunc (t *TableInfo) Clone() *TableInfo {\n\tnt := *t\n\tnt.Columns = make([]*ColumnInfo, len(t.Columns))\n\tnt.Indices = make([]*IndexInfo, len(t.Indices))\n\tnt.ForeignKeys = make([]*FKInfo, len(t.ForeignKeys))\n\tnt.PartyCode = t.PartyCode\n\tfor i := range t.Columns {\n\t\tnt.Columns[i] = t.Columns[i].Clone()\n\t}\n\n\tfor i := range t.Indices {\n\t\tnt.Indices[i] = t.Indices[i].Clone()\n\t}\n\n\tfor i := range t.ForeignKeys {\n\t\tnt.ForeignKeys[i] = t.ForeignKeys[i].Clone()\n\t}\n\n\treturn &nt\n}\n\n// GetPkName will return the pk name if pk exists.\nfunc (t *TableInfo) GetPkName() CIStr {\n\tfor _, colInfo := range t.Columns {\n\t\tif mysql.HasPriKeyFlag(colInfo.Flag) {\n\t\t\treturn colInfo.Name\n\t\t}\n\t}\n\treturn CIStr{}\n}\n\n// GetPkColInfo gets the ColumnInfo of pk if exists.\n// Make sure PkIsHandle checked before call this method.\nfunc (t *TableInfo) GetPkColInfo() *ColumnInfo {\n\tfor _, colInfo := range t.Columns {\n\t\tif mysql.HasPriKeyFlag(colInfo.Flag) {\n\t\t\treturn colInfo\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (t *TableInfo) GetAutoIncrementColInfo() *ColumnInfo {\n\tfor _, colInfo := range t.Columns {\n\t\tif mysql.HasAutoIncrementFlag(colInfo.Flag) {\n\t\t\treturn colInfo\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (t *TableInfo) IsAutoIncColUnsigned() bool {\n\tcol := t.GetAutoIncrementColInfo()\n\tif col == nil {\n\t\treturn false\n\t}\n\treturn mysql.HasUnsignedFlag(col.Flag)\n}\n\n// ContainsAutoRandomBits indicates whether a table contains auto_random column.\nfunc (t *TableInfo) ContainsAutoRandomBits() bool {\n\treturn t.AutoRandomBits != 0\n}\n\n// IsAutoRandomBitColUnsigned indicates whether the auto_random column is unsigned. Make sure the table contains auto_random before calling this method.\nfunc (t *TableInfo) IsAutoRandomBitColUnsigned() bool {\n\tif !t.PKIsHandle || t.AutoRandomBits == 0 {\n\t\treturn false\n\t}\n\treturn mysql.HasUnsignedFlag(t.GetPkColInfo().Flag)\n}\n\n// Cols returns the columns of the table in public state.\nfunc (t *TableInfo) Cols() []*ColumnInfo {\n\tpublicColumns := make([]*ColumnInfo, len(t.Columns))\n\tmaxOffset := -1\n\tfor _, col := range t.Columns {\n\t\tif col.State != StatePublic {\n\t\t\tcontinue\n\t\t}\n\t\tpublicColumns[col.Offset] = col\n\t\tif maxOffset < col.Offset {\n\t\t\tmaxOffset = col.Offset\n\t\t}\n\t}\n\treturn publicColumns[0 : maxOffset+1]\n}\n\n// FindIndexByName finds index by name.\nfunc (t *TableInfo) FindIndexByName(idxName string) *IndexInfo {\n\tfor _, idx := range t.Indices {\n\t\tif idx.Name.L == idxName {\n\t\t\treturn idx\n\t\t}\n\t}\n\treturn nil\n}\n\n// IsLocked checks whether the table was locked.\nfunc (t *TableInfo) IsLocked() bool {\n\treturn t.Lock != nil && len(t.Lock.Sessions) > 0\n}\n\n// NewExtraHandleColInfo mocks a column info for extra handle column.\nfunc NewExtraHandleColInfo() *ColumnInfo {\n\tcolInfo := &ColumnInfo{\n\t\tID:   ExtraHandleID,\n\t\tName: ExtraHandleName,\n\t}\n\tcolInfo.Flag = mysql.PriKeyFlag\n\tcolInfo.Tp = mysql.TypeLonglong\n\tcolInfo.Flen, colInfo.Decimal = mysql.GetDefaultFieldLengthAndDecimal(mysql.TypeLonglong)\n\treturn colInfo\n}\n\n// ColumnIsInIndex checks whether c is included in any indices of t.\nfunc (t *TableInfo) ColumnIsInIndex(c *ColumnInfo) bool {\n\tfor _, index := range t.Indices {\n\t\tfor _, column := range index.Columns {\n\t\t\tif column.Name.L == c.Name.L {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// IsView checks if TableInfo is a view.\nfunc (t *TableInfo) IsView() bool {\n\treturn t.View != nil\n}\n\n// IsSequence checks if TableInfo is a sequence.\nfunc (t *TableInfo) IsSequence() bool {\n\treturn t.Sequence != nil\n}\n\n// ViewAlgorithm is VIEW's SQL AlGORITHM characteristic.\n// See https://dev.mysql.com/doc/refman/5.7/en/view-algorithms.html\ntype ViewAlgorithm int\n\nconst (\n\tAlgorithmUndefined ViewAlgorithm = iota\n\tAlgorithmMerge\n\tAlgorithmTemptable\n)\n\nfunc (v *ViewAlgorithm) String() string {\n\tswitch *v {\n\tcase AlgorithmMerge:\n\t\treturn \"MERGE\"\n\tcase AlgorithmTemptable:\n\t\treturn \"TEMPTABLE\"\n\tcase AlgorithmUndefined:\n\t\treturn \"UNDEFINED\"\n\tdefault:\n\t\treturn \"UNDEFINED\"\n\t}\n}\n\n// ViewSecurity is VIEW's SQL SECURITY characteristic.\n// See https://dev.mysql.com/doc/refman/5.7/en/create-view.html\ntype ViewSecurity int\n\nconst (\n\tSecurityDefiner ViewSecurity = iota\n\tSecurityInvoker\n)\n\nfunc (v *ViewSecurity) String() string {\n\tswitch *v {\n\tcase SecurityInvoker:\n\t\treturn \"INVOKER\"\n\tcase SecurityDefiner:\n\t\treturn \"DEFINER\"\n\tdefault:\n\t\treturn \"DEFINER\"\n\t}\n}\n\n// ViewCheckOption is VIEW's WITH CHECK OPTION clause part.\n// See https://dev.mysql.com/doc/refman/5.7/en/view-check-option.html\ntype ViewCheckOption int\n\nconst (\n\tCheckOptionLocal ViewCheckOption = iota\n\tCheckOptionCascaded\n)\n\nfunc (v *ViewCheckOption) String() string {\n\tswitch *v {\n\tcase CheckOptionLocal:\n\t\treturn \"LOCAL\"\n\tcase CheckOptionCascaded:\n\t\treturn \"CASCADED\"\n\tdefault:\n\t\treturn \"CASCADED\"\n\t}\n}\n\n// ViewInfo provides meta data describing a DB view.\ntype ViewInfo struct {\n\tAlgorithm   ViewAlgorithm      `json:\"view_algorithm\"`\n\tDefiner     *auth.UserIdentity `json:\"view_definer\"`\n\tSecurity    ViewSecurity       `json:\"view_security\"`\n\tSelectStmt  string             `json:\"view_select\"`\n\tCheckOption ViewCheckOption    `json:\"view_checkoption\"`\n\tCols        []CIStr            `json:\"view_cols\"`\n}\n\nconst (\n\tDefaultSequenceCacheBool          = true\n\tDefaultSequenceCycleBool          = false\n\tDefaultSequenceOrderBool          = false\n\tDefaultSequenceCacheValue         = int64(1000)\n\tDefaultSequenceIncrementValue     = int64(1)\n\tDefaultPositiveSequenceStartValue = int64(1)\n\tDefaultNegativeSequenceStartValue = int64(-1)\n\tDefaultPositiveSequenceMinValue   = int64(1)\n\tDefaultPositiveSequenceMaxValue   = int64(9223372036854775806)\n\tDefaultNegativeSequenceMaxValue   = int64(-1)\n\tDefaultNegativeSequenceMinValue   = int64(-9223372036854775807)\n)\n\n// SequenceInfo provide meta data describing a DB sequence.\ntype SequenceInfo struct {\n\tStart      int64  `json:\"sequence_start\"`\n\tCache      bool   `json:\"sequence_cache\"`\n\tOrder      bool   `json:\"sequence_order\"`\n\tCycle      bool   `json:\"sequence_cycle\"`\n\tMinValue   int64  `json:\"sequence_min_value\"`\n\tMaxValue   int64  `json:\"sequence_max_value\"`\n\tIncrement  int64  `json:\"sequence_increment\"`\n\tCacheValue int64  `json:\"sequence_cache_value\"`\n\tComment    string `json:\"sequence_comment\"`\n}\n\n// PartitionType is the type for PartitionInfo\ntype PartitionType int\n\n// Partition types.\nconst (\n\tPartitionTypeRange      PartitionType = 1\n\tPartitionTypeHash                     = 2\n\tPartitionTypeList                     = 3\n\tPartitionTypeKey                      = 4\n\tPartitionTypeSystemTime               = 5\n)\n\nfunc (p PartitionType) String() string {\n\tswitch p {\n\tcase PartitionTypeRange:\n\t\treturn \"RANGE\"\n\tcase PartitionTypeHash:\n\t\treturn \"HASH\"\n\tcase PartitionTypeList:\n\t\treturn \"LIST\"\n\tcase PartitionTypeKey:\n\t\treturn \"KEY\"\n\tcase PartitionTypeSystemTime:\n\t\treturn \"SYSTEM_TIME\"\n\tdefault:\n\t\treturn \"\"\n\t}\n\n}\n\n// PartitionInfo provides table partition info.\ntype PartitionInfo struct {\n\tType    PartitionType `json:\"type\"`\n\tExpr    string        `json:\"expr\"`\n\tColumns []CIStr       `json:\"columns\"`\n\n\t// User may already creates table with partition but table partition is not\n\t// yet supported back then. When Enable is true, write/read need use tid\n\t// rather than pid.\n\tEnable bool `json:\"enable\"`\n\n\tDefinitions []PartitionDefinition `json:\"definitions\"`\n\tNum         uint64                `json:\"num\"`\n}\n\n// GetNameByID gets the partition name by ID.\nfunc (pi *PartitionInfo) GetNameByID(id int64) string {\n\tfor _, def := range pi.Definitions {\n\t\tif id == def.ID {\n\t\t\treturn def.Name.L\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// PartitionDefinition defines a single partition.\ntype PartitionDefinition struct {\n\tID       int64    `json:\"id\"`\n\tName     CIStr    `json:\"name\"`\n\tLessThan []string `json:\"less_than\"`\n\tComment  string   `json:\"comment,omitempty\"`\n}\n\n// IndexColumn provides index column info.\ntype IndexColumn struct {\n\tName   CIStr `json:\"name\"`   // Index name\n\tOffset int   `json:\"offset\"` // Index offset\n\t// Length of prefix when using column prefix\n\t// for indexing;\n\t// UnspecifedLength if not using prefix indexing\n\tLength int `json:\"length\"`\n}\n\n// Clone clones IndexColumn.\nfunc (i *IndexColumn) Clone() *IndexColumn {\n\tni := *i\n\treturn &ni\n}\n\n// IndexType is the type of index\ntype IndexType int\n\n// String implements Stringer interface.\nfunc (t IndexType) String() string {\n\tswitch t {\n\tcase IndexTypeBtree:\n\t\treturn \"BTREE\"\n\tcase IndexTypeHash:\n\t\treturn \"HASH\"\n\tcase IndexTypeRtree:\n\t\treturn \"RTREE\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\n// IndexTypes\nconst (\n\tIndexTypeInvalid IndexType = iota\n\tIndexTypeBtree\n\tIndexTypeHash\n\tIndexTypeRtree\n)\n\n// IndexInfo provides meta data describing a DB index.\n// It corresponds to the statement `CREATE INDEX Name ON Table (Column);`\n// See https://dev.mysql.com/doc/refman/5.7/en/create-index.html\ntype IndexInfo struct {\n\tID      int64          `json:\"id\"`\n\tName    CIStr          `json:\"idx_name\"`   // Index name.\n\tTable   CIStr          `json:\"tbl_name\"`   // Table name.\n\tColumns []*IndexColumn `json:\"idx_cols\"`   // Index columns.\n\tUnique  bool           `json:\"is_unique\"`  // Whether the index is unique.\n\tPrimary bool           `json:\"is_primary\"` // Whether the index is primary key.\n\tState   SchemaState    `json:\"state\"`\n\tComment string         `json:\"comment\"`    // Comment\n\tTp      IndexType      `json:\"index_type\"` // Index type: Btree, Hash or Rtree\n}\n\n// Clone clones IndexInfo.\nfunc (index *IndexInfo) Clone() *IndexInfo {\n\tni := *index\n\tni.Columns = make([]*IndexColumn, len(index.Columns))\n\tfor i := range index.Columns {\n\t\tni.Columns[i] = index.Columns[i].Clone()\n\t}\n\treturn &ni\n}\n\n// HasPrefixIndex returns whether any columns of this index uses prefix length.\nfunc (index *IndexInfo) HasPrefixIndex() bool {\n\tfor _, ic := range index.Columns {\n\t\tif ic.Length != types.UnspecifiedLength {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// FKInfo provides meta data describing a foreign key constraint.\ntype FKInfo struct {\n\tID       int64       `json:\"id\"`\n\tName     CIStr       `json:\"fk_name\"`\n\tRefTable CIStr       `json:\"ref_table\"`\n\tRefCols  []CIStr     `json:\"ref_cols\"`\n\tCols     []CIStr     `json:\"cols\"`\n\tOnDelete int         `json:\"on_delete\"`\n\tOnUpdate int         `json:\"on_update\"`\n\tState    SchemaState `json:\"state\"`\n}\n\n// Clone clones FKInfo.\nfunc (fk *FKInfo) Clone() *FKInfo {\n\tnfk := *fk\n\n\tnfk.RefCols = make([]CIStr, len(fk.RefCols))\n\tnfk.Cols = make([]CIStr, len(fk.Cols))\n\tcopy(nfk.RefCols, fk.RefCols)\n\tcopy(nfk.Cols, fk.Cols)\n\n\treturn &nfk\n}\n\n// DBInfo provides meta data describing a DB.\ntype DBInfo struct {\n\tID      int64        `json:\"id\"`      // Database ID\n\tName    CIStr        `json:\"db_name\"` // DB name.\n\tCharset string       `json:\"charset\"`\n\tCollate string       `json:\"collate\"`\n\tTables  []*TableInfo `json:\"-\"` // Tables in the DB.\n\tState   SchemaState  `json:\"state\"`\n}\n\n// Clone clones DBInfo.\nfunc (db *DBInfo) Clone() *DBInfo {\n\tnewInfo := *db\n\tnewInfo.Tables = make([]*TableInfo, len(db.Tables))\n\tfor i := range db.Tables {\n\t\tnewInfo.Tables[i] = db.Tables[i].Clone()\n\t}\n\treturn &newInfo\n}\n\n// Copy shallow copies DBInfo.\nfunc (db *DBInfo) Copy() *DBInfo {\n\tnewInfo := *db\n\tnewInfo.Tables = make([]*TableInfo, len(db.Tables))\n\tcopy(newInfo.Tables, db.Tables)\n\treturn &newInfo\n}\n\n// CIStr is case insensitive string.\ntype CIStr struct {\n\tO string `json:\"O\"` // Original string.\n\tL string `json:\"L\"` // Lower case string.\n}\n\n// String implements fmt.Stringer interface.\nfunc (cis CIStr) String() string {\n\treturn cis.O\n}\n\n// NewCIStr creates a new CIStr.\nfunc NewCIStr(s string) (cs CIStr) {\n\tcs.O = s\n\tcs.L = strings.ToLower(s)\n\treturn\n}\n\n// UnmarshalJSON implements the user defined unmarshal method.\n// CIStr can be unmarshaled from a single string, so PartitionDefinition.Name\n// in this change https://github.com/pingcap/tidb/pull/6460/files would be\n// compatible during TiDB upgrading.\nfunc (cis *CIStr) UnmarshalJSON(b []byte) error {\n\ttype T CIStr\n\tif err := json.Unmarshal(b, (*T)(cis)); err == nil {\n\t\treturn nil\n\t}\n\n\t// Unmarshal CIStr from a single string.\n\terr := json.Unmarshal(b, &cis.O)\n\tif err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\tcis.L = strings.ToLower(cis.O)\n\treturn nil\n}\n\n//// ColumnsToProto converts a slice of model.ColumnInfo to a slice of tipb.ColumnInfo.\n//func ColumnsToProto(columns []*ColumnInfo, pkIsHandle bool) []*tipb.ColumnInfo {\n//\tcols := make([]*tipb.ColumnInfo, 0, len(columns))\n//\tfor _, c := range columns {\n//\t\tcol := ColumnToProto(c)\n//\t\t// TODO: Here `PkHandle`'s meaning is changed, we will change it to `IsHandle` when tikv's old select logic\n//\t\t// is abandoned.\n//\t\tif (pkIsHandle && mysql.HasPriKeyFlag(c.Flag)) || c.ID == ExtraHandleID {\n//\t\t\tcol.PkHandle = true\n//\t\t} else {\n//\t\t\tcol.PkHandle = false\n//\t\t}\n//\t\tcols = append(cols, col)\n//\t}\n//\treturn cols\n//}\n\n//// IndexToProto converts a model.IndexInfo to a tipb.IndexInfo.\n//func IndexToProto(t *TableInfo, idx *IndexInfo) *tipb.IndexInfo {\n//\tpi := &tipb.IndexInfo{\n//\t\tTableId: t.ID,\n//\t\tIndexId: idx.ID,\n//\t\tUnique:  idx.Unique,\n//\t}\n//\tcols := make([]*tipb.ColumnInfo, 0, len(idx.Columns)+1)\n//\tfor _, c := range idx.Columns {\n//\t\tcols = append(cols, ColumnToProto(t.Columns[c.Offset]))\n//\t}\n//\tif t.PKIsHandle {\n//\t\t// Coprocessor needs to know PKHandle column info, so we need to append it.\n//\t\tfor _, col := range t.Columns {\n//\t\t\tif mysql.HasPriKeyFlag(col.Flag) {\n//\t\t\t\tcolPB := ColumnToProto(col)\n//\t\t\t\tcolPB.PkHandle = true\n//\t\t\t\tcols = append(cols, colPB)\n//\t\t\t\tbreak\n//\t\t\t}\n//\t\t}\n//\t}\n//\tpi.Columns = cols\n//\treturn pi\n//}\n\n//// ColumnToProto converts model.ColumnInfo to tipb.ColumnInfo.\n//func ColumnToProto(c *ColumnInfo) *tipb.ColumnInfo {\n//\tpc := &tipb.ColumnInfo{\n//\t\tColumnId:  c.ID,\n//\t\tCollation: collationToProto(c.FieldType.Collate),\n//\t\tColumnLen: int32(c.FieldType.Flen),\n//\t\tDecimal:   int32(c.FieldType.Decimal),\n//\t\tFlag:      int32(c.Flag),\n//\t\tElems:     c.Elems,\n//\t}\n//\tpc.Tp = int32(c.FieldType.Tp)\n//\treturn pc\n//}\n//\n//// TODO: update it when more collate is supported.\n//func collationToProto(c string) int32 {\n//\tv := mysql.CollationNames[c]\n//\tif v == mysql.BinaryDefaultCollationID {\n//\t\treturn int32(mysql.BinaryDefaultCollationID)\n//\t}\n//\t// We only support binary and utf8_bin collation.\n//\t// Setting other collations to utf8_bin for old data compatibility.\n//\t// For the data created when we didn't enforce utf8_bin collation in create table.\n//\treturn int32(mysql.DefaultCollationID)\n//}\n\n// TableColumnID is composed by table ID and column ID.\ntype TableColumnID struct {\n\tTableID  int64\n\tColumnID int64\n}\n"
  },
  {
    "path": "pkg/parser/model/model_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage model\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/types\"\n)\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nvar _ = Suite(&testModelSuite{})\n\ntype testModelSuite struct {\n}\n\nfunc (*testModelSuite) TestT(c *C) {\n\tabc := NewCIStr(\"aBC\")\n\tc.Assert(abc.O, Equals, \"aBC\")\n\tc.Assert(abc.L, Equals, \"abc\")\n\tc.Assert(abc.String(), Equals, \"aBC\")\n}\n\nfunc (*testModelSuite) TestModelBasic(c *C) {\n\tcolumn := &ColumnInfo{\n\t\tID:           1,\n\t\tName:         NewCIStr(\"c\"),\n\t\tOffset:       0,\n\t\tDefaultValue: 0,\n\t\tFieldType:    *types.NewFieldType(0),\n\t\tHidden:       true,\n\t}\n\tcolumn.Flag |= mysql.PriKeyFlag\n\n\tindex := &IndexInfo{\n\t\tName:  NewCIStr(\"key\"),\n\t\tTable: NewCIStr(\"t\"),\n\t\tColumns: []*IndexColumn{\n\t\t\t{\n\t\t\t\tName:   NewCIStr(\"c\"),\n\t\t\t\tOffset: 0,\n\t\t\t\tLength: 10,\n\t\t\t}},\n\t\tUnique:  true,\n\t\tPrimary: true,\n\t}\n\n\tfk := &FKInfo{\n\t\tRefCols: []CIStr{NewCIStr(\"a\")},\n\t\tCols:    []CIStr{NewCIStr(\"a\")},\n\t}\n\n\tseq := &SequenceInfo{\n\t\tIncrement: 1,\n\t\tMinValue:  1,\n\t\tMaxValue:  100,\n\t}\n\n\ttable := &TableInfo{\n\t\tID:          1,\n\t\tName:        NewCIStr(\"t\"),\n\t\tCharset:     \"utf8\",\n\t\tCollate:     \"utf8_bin\",\n\t\tColumns:     []*ColumnInfo{column},\n\t\tIndices:     []*IndexInfo{index},\n\t\tForeignKeys: []*FKInfo{fk},\n\t\tPKIsHandle:  true,\n\t}\n\n\ttable2 := &TableInfo{\n\t\tID:       2,\n\t\tName:     NewCIStr(\"s\"),\n\t\tSequence: seq,\n\t}\n\n\tdbInfo := &DBInfo{\n\t\tID:      1,\n\t\tName:    NewCIStr(\"test\"),\n\t\tCharset: \"utf8\",\n\t\tCollate: \"utf8_bin\",\n\t\tTables:  []*TableInfo{table},\n\t}\n\n\tn := dbInfo.Clone()\n\tc.Assert(n, DeepEquals, dbInfo)\n\n\tpkName := table.GetPkName()\n\tc.Assert(pkName, Equals, NewCIStr(\"c\"))\n\tnewColumn := table.GetPkColInfo()\n\tc.Assert(newColumn.Hidden, Equals, true)\n\tc.Assert(newColumn, DeepEquals, column)\n\tinIdx := table.ColumnIsInIndex(column)\n\tc.Assert(inIdx, Equals, true)\n\ttp := IndexTypeBtree\n\tc.Assert(tp.String(), Equals, \"BTREE\")\n\ttp = IndexTypeHash\n\tc.Assert(tp.String(), Equals, \"HASH\")\n\ttp = 1e5\n\tc.Assert(tp.String(), Equals, \"\")\n\thas := index.HasPrefixIndex()\n\tc.Assert(has, Equals, true)\n\tt := table.GetUpdateTime()\n\tc.Assert(t, Equals, TSConvert2Time(table.UpdateTS))\n\tc.Assert(table2.IsSequence(), Equals, true)\n\n\t// Corner cases\n\tcolumn.Flag ^= mysql.PriKeyFlag\n\tpkName = table.GetPkName()\n\tc.Assert(pkName, Equals, NewCIStr(\"\"))\n\tnewColumn = table.GetPkColInfo()\n\tc.Assert(newColumn, IsNil)\n\tanCol := &ColumnInfo{\n\t\tName: NewCIStr(\"d\"),\n\t}\n\texIdx := table.ColumnIsInIndex(anCol)\n\tc.Assert(exIdx, Equals, false)\n\tanIndex := &IndexInfo{\n\t\tColumns: []*IndexColumn{},\n\t}\n\tno := anIndex.HasPrefixIndex()\n\tc.Assert(no, Equals, false)\n}\n\nfunc (*testModelSuite) TestJobStartTime(c *C) {\n\tjob := &Job{\n\t\tID:         123,\n\t\tBinlogInfo: &HistoryInfo{},\n\t}\n\tt := time.Unix(0, 0)\n\tc.Assert(t, Equals, TSConvert2Time(job.StartTS))\n\tret := fmt.Sprintf(\"%s\", job)\n\tc.Assert(job.String(), Equals, ret)\n}\n\nfunc (*testModelSuite) TestJobCodec(c *C) {\n\ttype A struct {\n\t\tName string\n\t}\n\tjob := &Job{\n\t\tID:         1,\n\t\tTableID:    2,\n\t\tSchemaID:   1,\n\t\tBinlogInfo: &HistoryInfo{},\n\t\tArgs:       []interface{}{NewCIStr(\"a\"), A{Name: \"abc\"}},\n\t}\n\tjob.BinlogInfo.AddDBInfo(123, &DBInfo{ID: 1, Name: NewCIStr(\"test_history_db\")})\n\tjob.BinlogInfo.AddTableInfo(123, &TableInfo{ID: 1, Name: NewCIStr(\"test_history_tbl\")})\n\n\t// Test IsDependentOn.\n\t// job: table ID is 2\n\t// job1: table ID is 2\n\tvar err error\n\tjob1 := &Job{\n\t\tID:         2,\n\t\tTableID:    2,\n\t\tSchemaID:   1,\n\t\tType:       ActionRenameTable,\n\t\tBinlogInfo: &HistoryInfo{},\n\t\tArgs:       []interface{}{int64(3), NewCIStr(\"new_table_name\")},\n\t}\n\tjob1.RawArgs, err = json.Marshal(job1.Args)\n\tc.Assert(err, IsNil)\n\tisDependent, err := job.IsDependentOn(job1)\n\tc.Assert(err, IsNil)\n\tc.Assert(isDependent, IsTrue)\n\t// job1: rename table, old schema ID is 3\n\t// job2: create schema, schema ID is 3\n\tjob2 := &Job{\n\t\tID:         3,\n\t\tTableID:    3,\n\t\tSchemaID:   3,\n\t\tType:       ActionCreateSchema,\n\t\tBinlogInfo: &HistoryInfo{},\n\t}\n\tisDependent, err = job2.IsDependentOn(job1)\n\tc.Assert(err, IsNil)\n\tc.Assert(isDependent, IsTrue)\n\n\tc.Assert(job.IsCancelled(), Equals, false)\n\tb, err := job.Encode(false)\n\tc.Assert(err, IsNil)\n\tnewJob := &Job{}\n\terr = newJob.Decode(b)\n\tc.Assert(err, IsNil)\n\tc.Assert(newJob.BinlogInfo, DeepEquals, job.BinlogInfo)\n\tname := CIStr{}\n\ta := A{}\n\terr = newJob.DecodeArgs(&name, &a)\n\tc.Assert(err, IsNil)\n\tc.Assert(name, DeepEquals, NewCIStr(\"\"))\n\tc.Assert(a, DeepEquals, A{Name: \"\"})\n\tc.Assert(len(newJob.String()), Greater, 0)\n\n\tjob.BinlogInfo.Clean()\n\tb1, err := job.Encode(true)\n\tc.Assert(err, IsNil)\n\tnewJob = &Job{}\n\terr = newJob.Decode(b1)\n\tc.Assert(err, IsNil)\n\tc.Assert(newJob.BinlogInfo, DeepEquals, &HistoryInfo{})\n\tname = CIStr{}\n\ta = A{}\n\terr = newJob.DecodeArgs(&name, &a)\n\tc.Assert(err, IsNil)\n\tc.Assert(name, DeepEquals, NewCIStr(\"a\"))\n\tc.Assert(a, DeepEquals, A{Name: \"abc\"})\n\tc.Assert(len(newJob.String()), Greater, 0)\n\n\tb2, err := job.Encode(true)\n\tc.Assert(err, IsNil)\n\tnewJob = &Job{}\n\terr = newJob.Decode(b2)\n\tc.Assert(err, IsNil)\n\tname = CIStr{}\n\t// Don't decode to a here.\n\terr = newJob.DecodeArgs(&name)\n\tc.Assert(err, IsNil)\n\tc.Assert(name, DeepEquals, NewCIStr(\"a\"))\n\tc.Assert(len(newJob.String()), Greater, 0)\n\n\tjob.State = JobStateDone\n\tc.Assert(job.IsDone(), IsTrue)\n\tc.Assert(job.IsFinished(), IsTrue)\n\tc.Assert(job.IsRunning(), IsFalse)\n\tc.Assert(job.IsSynced(), IsFalse)\n\tc.Assert(job.IsRollbackDone(), IsFalse)\n\tjob.SetRowCount(3)\n\tc.Assert(job.GetRowCount(), Equals, int64(3))\n}\n\nfunc (testModelSuite) TestState(c *C) {\n\tschemaTbl := []SchemaState{\n\t\tStateDeleteOnly,\n\t\tStateWriteOnly,\n\t\tStateWriteReorganization,\n\t\tStateDeleteReorganization,\n\t\tStatePublic,\n\t}\n\n\tfor _, state := range schemaTbl {\n\t\tc.Assert(len(state.String()), Greater, 0)\n\t}\n\n\tjobTbl := []JobState{\n\t\tJobStateRunning,\n\t\tJobStateDone,\n\t\tJobStateCancelled,\n\t\tJobStateRollingback,\n\t\tJobStateRollbackDone,\n\t\tJobStateSynced,\n\t}\n\n\tfor _, state := range jobTbl {\n\t\tc.Assert(len(state.String()), Greater, 0)\n\t}\n}\n\nfunc (testModelSuite) TestString(c *C) {\n\tacts := []struct {\n\t\tact    ActionType\n\t\tresult string\n\t}{\n\t\t{ActionNone, \"none\"},\n\t\t{ActionAddForeignKey, \"add foreign key\"},\n\t\t{ActionDropForeignKey, \"drop foreign key\"},\n\t\t{ActionTruncateTable, \"truncate table\"},\n\t\t{ActionModifyColumn, \"modify column\"},\n\t\t{ActionRenameTable, \"rename table\"},\n\t\t{ActionSetDefaultValue, \"set default value\"},\n\t\t{ActionCreateSchema, \"create schema\"},\n\t\t{ActionDropSchema, \"drop schema\"},\n\t\t{ActionCreateTable, \"create table\"},\n\t\t{ActionDropTable, \"drop table\"},\n\t\t{ActionAddIndex, \"add index\"},\n\t\t{ActionDropIndex, \"drop index\"},\n\t\t{ActionAddColumn, \"add column\"},\n\t\t{ActionDropColumn, \"drop column\"},\n\t\t{ActionModifySchemaCharsetAndCollate, \"modify schema charset and collate\"},\n\t}\n\n\tfor _, v := range acts {\n\t\tstr := v.act.String()\n\t\tc.Assert(str, Equals, v.result)\n\t}\n}\n\nfunc (testModelSuite) TestUnmarshalCIStr(c *C) {\n\tvar ci CIStr\n\n\t// Test unmarshal CIStr from a single string.\n\tstr := \"aaBB\"\n\tbuf, err := json.Marshal(str)\n\tc.Assert(err, IsNil)\n\tci.UnmarshalJSON(buf)\n\tc.Assert(ci.O, Equals, str)\n\tc.Assert(ci.L, Equals, \"aabb\")\n\n\tbuf, err = json.Marshal(ci)\n\tc.Assert(string(buf), Equals, `{\"O\":\"aaBB\",\"L\":\"aabb\"}`)\n\tci.UnmarshalJSON(buf)\n\tc.Assert(ci.O, Equals, str)\n\tc.Assert(ci.L, Equals, \"aabb\")\n}\n"
  },
  {
    "path": "pkg/parser/mysql/charset.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\nimport \"unicode\"\n\n// CharsetNameToID maps charset name to its default collation ID.\nfunc CharsetNameToID(charset string) uint8 {\n\t// Use quick path for TiDB to avoid access CharsetIDs map\n\t// \"SHOW CHARACTER SET;\" to see all the supported character sets.\n\tif charset == \"utf8mb4\" {\n\t\treturn UTF8MB4DefaultCollationID\n\t} else if charset == \"binary\" {\n\t\treturn BinaryDefaultCollationID\n\t} else if charset == \"utf8\" {\n\t\treturn UTF8DefaultCollationID\n\t} else if charset == \"ascii\" {\n\t\treturn ASCIIDefaultCollationID\n\t} else if charset == \"latin1\" {\n\t\treturn Latin1DefaultCollationID\n\t} else {\n\t\treturn CharsetIDs[charset]\n\t}\n}\n\n// CharsetIDs maps charset name to its default collation ID.\nvar CharsetIDs = map[string]uint8{\n\t\"big5\":     1,\n\t\"dec8\":     3,\n\t\"cp850\":    4,\n\t\"hp8\":      6,\n\t\"koi8r\":    7,\n\t\"latin1\":   Latin1DefaultCollationID,\n\t\"latin2\":   9,\n\t\"swe7\":     10,\n\t\"ascii\":    ASCIIDefaultCollationID,\n\t\"ujis\":     12,\n\t\"sjis\":     13,\n\t\"hebrew\":   16,\n\t\"tis620\":   18,\n\t\"euckr\":    19,\n\t\"koi8u\":    22,\n\t\"gb2312\":   24,\n\t\"greek\":    25,\n\t\"cp1250\":   26,\n\t\"gbk\":      28,\n\t\"latin5\":   30,\n\t\"armscii8\": 32,\n\t\"utf8\":     UTF8DefaultCollationID,\n\t\"ucs2\":     35,\n\t\"cp866\":    36,\n\t\"keybcs2\":  37,\n\t\"macce\":    38,\n\t\"macroman\": 39,\n\t\"cp852\":    40,\n\t\"latin7\":   41,\n\t\"utf8mb4\":  UTF8MB4DefaultCollationID,\n\t\"cp1251\":   51,\n\t\"utf16\":    54,\n\t\"utf16le\":  56,\n\t\"cp1256\":   57,\n\t\"cp1257\":   59,\n\t\"utf32\":    60,\n\t\"binary\":   BinaryDefaultCollationID,\n\t\"geostd8\":  92,\n\t\"cp932\":    95,\n\t\"eucjpms\":  97,\n}\n\n// Charsets maps charset name to its default collation name.\nvar Charsets = map[string]string{\n\t\"big5\":     \"big5_chinese_ci\",\n\t\"dec8\":     \"dec8_swedish_ci\",\n\t\"cp850\":    \"cp850_general_ci\",\n\t\"hp8\":      \"hp8_english_ci\",\n\t\"koi8r\":    \"koi8r_general_ci\",\n\t\"latin1\":   \"latin1_bin\",\n\t\"latin2\":   \"latin2_general_ci\",\n\t\"swe7\":     \"swe7_swedish_ci\",\n\t\"ascii\":    \"ascii_bin\",\n\t\"ujis\":     \"ujis_japanese_ci\",\n\t\"sjis\":     \"sjis_japanese_ci\",\n\t\"hebrew\":   \"hebrew_general_ci\",\n\t\"tis620\":   \"tis620_thai_ci\",\n\t\"euckr\":    \"euckr_korean_ci\",\n\t\"koi8u\":    \"koi8u_general_ci\",\n\t\"gb2312\":   \"gb2312_chinese_ci\",\n\t\"greek\":    \"greek_general_ci\",\n\t\"cp1250\":   \"cp1250_general_ci\",\n\t\"gbk\":      \"gbk_chinese_ci\",\n\t\"latin5\":   \"latin5_turkish_ci\",\n\t\"armscii8\": \"armscii8_general_ci\",\n\t\"utf8\":     \"utf8_bin\",\n\t\"ucs2\":     \"ucs2_general_ci\",\n\t\"cp866\":    \"cp866_general_ci\",\n\t\"keybcs2\":  \"keybcs2_general_ci\",\n\t\"macce\":    \"macce_general_ci\",\n\t\"macroman\": \"macroman_general_ci\",\n\t\"cp852\":    \"cp852_general_ci\",\n\t\"latin7\":   \"latin7_general_ci\",\n\t\"utf8mb4\":  \"utf8mb4_bin\",\n\t\"cp1251\":   \"cp1251_general_ci\",\n\t\"utf16\":    \"utf16_general_ci\",\n\t\"utf16le\":  \"utf16le_general_ci\",\n\t\"cp1256\":   \"cp1256_general_ci\",\n\t\"cp1257\":   \"cp1257_general_ci\",\n\t\"utf32\":    \"utf32_general_ci\",\n\t\"binary\":   \"binary\",\n\t\"geostd8\":  \"geostd8_general_ci\",\n\t\"cp932\":    \"cp932_japanese_ci\",\n\t\"eucjpms\":  \"eucjpms_japanese_ci\",\n}\n\n// Collations maps MySQL collation ID to its name.\nvar Collations = map[uint8]string{\n\t1:   \"big5_chinese_ci\",\n\t2:   \"latin2_czech_cs\",\n\t3:   \"dec8_swedish_ci\",\n\t4:   \"cp850_general_ci\",\n\t5:   \"latin1_german1_ci\",\n\t6:   \"hp8_english_ci\",\n\t7:   \"koi8r_general_ci\",\n\t8:   \"latin1_swedish_ci\",\n\t9:   \"latin2_general_ci\",\n\t10:  \"swe7_swedish_ci\",\n\t11:  \"ascii_general_ci\",\n\t12:  \"ujis_japanese_ci\",\n\t13:  \"sjis_japanese_ci\",\n\t14:  \"cp1251_bulgarian_ci\",\n\t15:  \"latin1_danish_ci\",\n\t16:  \"hebrew_general_ci\",\n\t18:  \"tis620_thai_ci\",\n\t19:  \"euckr_korean_ci\",\n\t20:  \"latin7_estonian_cs\",\n\t21:  \"latin2_hungarian_ci\",\n\t22:  \"koi8u_general_ci\",\n\t23:  \"cp1251_ukrainian_ci\",\n\t24:  \"gb2312_chinese_ci\",\n\t25:  \"greek_general_ci\",\n\t26:  \"cp1250_general_ci\",\n\t27:  \"latin2_croatian_ci\",\n\t28:  \"gbk_chinese_ci\",\n\t29:  \"cp1257_lithuanian_ci\",\n\t30:  \"latin5_turkish_ci\",\n\t31:  \"latin1_german2_ci\",\n\t32:  \"armscii8_general_ci\",\n\t33:  \"utf8_general_ci\",\n\t34:  \"cp1250_czech_cs\",\n\t35:  \"ucs2_general_ci\",\n\t36:  \"cp866_general_ci\",\n\t37:  \"keybcs2_general_ci\",\n\t38:  \"macce_general_ci\",\n\t39:  \"macroman_general_ci\",\n\t40:  \"cp852_general_ci\",\n\t41:  \"latin7_general_ci\",\n\t42:  \"latin7_general_cs\",\n\t43:  \"macce_bin\",\n\t44:  \"cp1250_croatian_ci\",\n\t45:  \"utf8mb4_general_ci\",\n\t46:  \"utf8mb4_bin\",\n\t47:  \"latin1_bin\",\n\t48:  \"latin1_general_ci\",\n\t49:  \"latin1_general_cs\",\n\t50:  \"cp1251_bin\",\n\t51:  \"cp1251_general_ci\",\n\t52:  \"cp1251_general_cs\",\n\t53:  \"macroman_bin\",\n\t54:  \"utf16_general_ci\",\n\t55:  \"utf16_bin\",\n\t56:  \"utf16le_general_ci\",\n\t57:  \"cp1256_general_ci\",\n\t58:  \"cp1257_bin\",\n\t59:  \"cp1257_general_ci\",\n\t60:  \"utf32_general_ci\",\n\t61:  \"utf32_bin\",\n\t62:  \"utf16le_bin\",\n\t63:  \"binary\",\n\t64:  \"armscii8_bin\",\n\t65:  \"ascii_bin\",\n\t66:  \"cp1250_bin\",\n\t67:  \"cp1256_bin\",\n\t68:  \"cp866_bin\",\n\t69:  \"dec8_bin\",\n\t70:  \"greek_bin\",\n\t71:  \"hebrew_bin\",\n\t72:  \"hp8_bin\",\n\t73:  \"keybcs2_bin\",\n\t74:  \"koi8r_bin\",\n\t75:  \"koi8u_bin\",\n\t77:  \"latin2_bin\",\n\t78:  \"latin5_bin\",\n\t79:  \"latin7_bin\",\n\t80:  \"cp850_bin\",\n\t81:  \"cp852_bin\",\n\t82:  \"swe7_bin\",\n\t83:  \"utf8_bin\",\n\t84:  \"big5_bin\",\n\t85:  \"euckr_bin\",\n\t86:  \"gb2312_bin\",\n\t87:  \"gbk_bin\",\n\t88:  \"sjis_bin\",\n\t89:  \"tis620_bin\",\n\t90:  \"ucs2_bin\",\n\t91:  \"ujis_bin\",\n\t92:  \"geostd8_general_ci\",\n\t93:  \"geostd8_bin\",\n\t94:  \"latin1_spanish_ci\",\n\t95:  \"cp932_japanese_ci\",\n\t96:  \"cp932_bin\",\n\t97:  \"eucjpms_japanese_ci\",\n\t98:  \"eucjpms_bin\",\n\t99:  \"cp1250_polish_ci\",\n\t101: \"utf16_unicode_ci\",\n\t102: \"utf16_icelandic_ci\",\n\t103: \"utf16_latvian_ci\",\n\t104: \"utf16_romanian_ci\",\n\t105: \"utf16_slovenian_ci\",\n\t106: \"utf16_polish_ci\",\n\t107: \"utf16_estonian_ci\",\n\t108: \"utf16_spanish_ci\",\n\t109: \"utf16_swedish_ci\",\n\t110: \"utf16_turkish_ci\",\n\t111: \"utf16_czech_ci\",\n\t112: \"utf16_danish_ci\",\n\t113: \"utf16_lithuanian_ci\",\n\t114: \"utf16_slovak_ci\",\n\t115: \"utf16_spanish2_ci\",\n\t116: \"utf16_roman_ci\",\n\t117: \"utf16_persian_ci\",\n\t118: \"utf16_esperanto_ci\",\n\t119: \"utf16_hungarian_ci\",\n\t120: \"utf16_sinhala_ci\",\n\t121: \"utf16_german2_ci\",\n\t122: \"utf16_croatian_ci\",\n\t123: \"utf16_unicode_520_ci\",\n\t124: \"utf16_vietnamese_ci\",\n\t128: \"ucs2_unicode_ci\",\n\t129: \"ucs2_icelandic_ci\",\n\t130: \"ucs2_latvian_ci\",\n\t131: \"ucs2_romanian_ci\",\n\t132: \"ucs2_slovenian_ci\",\n\t133: \"ucs2_polish_ci\",\n\t134: \"ucs2_estonian_ci\",\n\t135: \"ucs2_spanish_ci\",\n\t136: \"ucs2_swedish_ci\",\n\t137: \"ucs2_turkish_ci\",\n\t138: \"ucs2_czech_ci\",\n\t139: \"ucs2_danish_ci\",\n\t140: \"ucs2_lithuanian_ci\",\n\t141: \"ucs2_slovak_ci\",\n\t142: \"ucs2_spanish2_ci\",\n\t143: \"ucs2_roman_ci\",\n\t144: \"ucs2_persian_ci\",\n\t145: \"ucs2_esperanto_ci\",\n\t146: \"ucs2_hungarian_ci\",\n\t147: \"ucs2_sinhala_ci\",\n\t148: \"ucs2_german2_ci\",\n\t149: \"ucs2_croatian_ci\",\n\t150: \"ucs2_unicode_520_ci\",\n\t151: \"ucs2_vietnamese_ci\",\n\t159: \"ucs2_general_mysql500_ci\",\n\t160: \"utf32_unicode_ci\",\n\t161: \"utf32_icelandic_ci\",\n\t162: \"utf32_latvian_ci\",\n\t163: \"utf32_romanian_ci\",\n\t164: \"utf32_slovenian_ci\",\n\t165: \"utf32_polish_ci\",\n\t166: \"utf32_estonian_ci\",\n\t167: \"utf32_spanish_ci\",\n\t168: \"utf32_swedish_ci\",\n\t169: \"utf32_turkish_ci\",\n\t170: \"utf32_czech_ci\",\n\t171: \"utf32_danish_ci\",\n\t172: \"utf32_lithuanian_ci\",\n\t173: \"utf32_slovak_ci\",\n\t174: \"utf32_spanish2_ci\",\n\t175: \"utf32_roman_ci\",\n\t176: \"utf32_persian_ci\",\n\t177: \"utf32_esperanto_ci\",\n\t178: \"utf32_hungarian_ci\",\n\t179: \"utf32_sinhala_ci\",\n\t180: \"utf32_german2_ci\",\n\t181: \"utf32_croatian_ci\",\n\t182: \"utf32_unicode_520_ci\",\n\t183: \"utf32_vietnamese_ci\",\n\t192: \"utf8_unicode_ci\",\n\t193: \"utf8_icelandic_ci\",\n\t194: \"utf8_latvian_ci\",\n\t195: \"utf8_romanian_ci\",\n\t196: \"utf8_slovenian_ci\",\n\t197: \"utf8_polish_ci\",\n\t198: \"utf8_estonian_ci\",\n\t199: \"utf8_spanish_ci\",\n\t200: \"utf8_swedish_ci\",\n\t201: \"utf8_turkish_ci\",\n\t202: \"utf8_czech_ci\",\n\t203: \"utf8_danish_ci\",\n\t204: \"utf8_lithuanian_ci\",\n\t205: \"utf8_slovak_ci\",\n\t206: \"utf8_spanish2_ci\",\n\t207: \"utf8_roman_ci\",\n\t208: \"utf8_persian_ci\",\n\t209: \"utf8_esperanto_ci\",\n\t210: \"utf8_hungarian_ci\",\n\t211: \"utf8_sinhala_ci\",\n\t212: \"utf8_german2_ci\",\n\t213: \"utf8_croatian_ci\",\n\t214: \"utf8_unicode_520_ci\",\n\t215: \"utf8_vietnamese_ci\",\n\t223: \"utf8_general_mysql500_ci\",\n\t224: \"utf8mb4_unicode_ci\",\n\t225: \"utf8mb4_icelandic_ci\",\n\t226: \"utf8mb4_latvian_ci\",\n\t227: \"utf8mb4_romanian_ci\",\n\t228: \"utf8mb4_slovenian_ci\",\n\t229: \"utf8mb4_polish_ci\",\n\t230: \"utf8mb4_estonian_ci\",\n\t231: \"utf8mb4_spanish_ci\",\n\t232: \"utf8mb4_swedish_ci\",\n\t233: \"utf8mb4_turkish_ci\",\n\t234: \"utf8mb4_czech_ci\",\n\t235: \"utf8mb4_danish_ci\",\n\t236: \"utf8mb4_lithuanian_ci\",\n\t237: \"utf8mb4_slovak_ci\",\n\t238: \"utf8mb4_spanish2_ci\",\n\t239: \"utf8mb4_roman_ci\",\n\t240: \"utf8mb4_persian_ci\",\n\t241: \"utf8mb4_esperanto_ci\",\n\t242: \"utf8mb4_hungarian_ci\",\n\t243: \"utf8mb4_sinhala_ci\",\n\t244: \"utf8mb4_german2_ci\",\n\t245: \"utf8mb4_croatian_ci\",\n\t246: \"utf8mb4_unicode_520_ci\",\n\t247: \"utf8mb4_vietnamese_ci\",\n\t255: \"utf8mb4_0900_ai_ci\",\n}\n\n// CollationNames maps MySQL collation name to its ID\nvar CollationNames = map[string]uint8{\n\t\"big5_chinese_ci\":          1,\n\t\"latin2_czech_cs\":          2,\n\t\"dec8_swedish_ci\":          3,\n\t\"cp850_general_ci\":         4,\n\t\"latin1_german1_ci\":        5,\n\t\"hp8_english_ci\":           6,\n\t\"koi8r_general_ci\":         7,\n\t\"latin1_swedish_ci\":        8,\n\t\"latin2_general_ci\":        9,\n\t\"swe7_swedish_ci\":          10,\n\t\"ascii_general_ci\":         11,\n\t\"ujis_japanese_ci\":         12,\n\t\"sjis_japanese_ci\":         13,\n\t\"cp1251_bulgarian_ci\":      14,\n\t\"latin1_danish_ci\":         15,\n\t\"hebrew_general_ci\":        16,\n\t\"tis620_thai_ci\":           18,\n\t\"euckr_korean_ci\":          19,\n\t\"latin7_estonian_cs\":       20,\n\t\"latin2_hungarian_ci\":      21,\n\t\"koi8u_general_ci\":         22,\n\t\"cp1251_ukrainian_ci\":      23,\n\t\"gb2312_chinese_ci\":        24,\n\t\"greek_general_ci\":         25,\n\t\"cp1250_general_ci\":        26,\n\t\"latin2_croatian_ci\":       27,\n\t\"gbk_chinese_ci\":           28,\n\t\"cp1257_lithuanian_ci\":     29,\n\t\"latin5_turkish_ci\":        30,\n\t\"latin1_german2_ci\":        31,\n\t\"armscii8_general_ci\":      32,\n\t\"utf8_general_ci\":          33,\n\t\"cp1250_czech_cs\":          34,\n\t\"ucs2_general_ci\":          35,\n\t\"cp866_general_ci\":         36,\n\t\"keybcs2_general_ci\":       37,\n\t\"macce_general_ci\":         38,\n\t\"macroman_general_ci\":      39,\n\t\"cp852_general_ci\":         40,\n\t\"latin7_general_ci\":        41,\n\t\"latin7_general_cs\":        42,\n\t\"macce_bin\":                43,\n\t\"cp1250_croatian_ci\":       44,\n\t\"utf8mb4_general_ci\":       45,\n\t\"utf8mb4_bin\":              46,\n\t\"latin1_bin\":               47,\n\t\"latin1_general_ci\":        48,\n\t\"latin1_general_cs\":        49,\n\t\"cp1251_bin\":               50,\n\t\"cp1251_general_ci\":        51,\n\t\"cp1251_general_cs\":        52,\n\t\"macroman_bin\":             53,\n\t\"utf16_general_ci\":         54,\n\t\"utf16_bin\":                55,\n\t\"utf16le_general_ci\":       56,\n\t\"cp1256_general_ci\":        57,\n\t\"cp1257_bin\":               58,\n\t\"cp1257_general_ci\":        59,\n\t\"utf32_general_ci\":         60,\n\t\"utf32_bin\":                61,\n\t\"utf16le_bin\":              62,\n\t\"binary\":                   63,\n\t\"armscii8_bin\":             64,\n\t\"ascii_bin\":                65,\n\t\"cp1250_bin\":               66,\n\t\"cp1256_bin\":               67,\n\t\"cp866_bin\":                68,\n\t\"dec8_bin\":                 69,\n\t\"greek_bin\":                70,\n\t\"hebrew_bin\":               71,\n\t\"hp8_bin\":                  72,\n\t\"keybcs2_bin\":              73,\n\t\"koi8r_bin\":                74,\n\t\"koi8u_bin\":                75,\n\t\"latin2_bin\":               77,\n\t\"latin5_bin\":               78,\n\t\"latin7_bin\":               79,\n\t\"cp850_bin\":                80,\n\t\"cp852_bin\":                81,\n\t\"swe7_bin\":                 82,\n\t\"utf8_bin\":                 83,\n\t\"big5_bin\":                 84,\n\t\"euckr_bin\":                85,\n\t\"gb2312_bin\":               86,\n\t\"gbk_bin\":                  87,\n\t\"sjis_bin\":                 88,\n\t\"tis620_bin\":               89,\n\t\"ucs2_bin\":                 90,\n\t\"ujis_bin\":                 91,\n\t\"geostd8_general_ci\":       92,\n\t\"geostd8_bin\":              93,\n\t\"latin1_spanish_ci\":        94,\n\t\"cp932_japanese_ci\":        95,\n\t\"cp932_bin\":                96,\n\t\"eucjpms_japanese_ci\":      97,\n\t\"eucjpms_bin\":              98,\n\t\"cp1250_polish_ci\":         99,\n\t\"utf16_unicode_ci\":         101,\n\t\"utf16_icelandic_ci\":       102,\n\t\"utf16_latvian_ci\":         103,\n\t\"utf16_romanian_ci\":        104,\n\t\"utf16_slovenian_ci\":       105,\n\t\"utf16_polish_ci\":          106,\n\t\"utf16_estonian_ci\":        107,\n\t\"utf16_spanish_ci\":         108,\n\t\"utf16_swedish_ci\":         109,\n\t\"utf16_turkish_ci\":         110,\n\t\"utf16_czech_ci\":           111,\n\t\"utf16_danish_ci\":          112,\n\t\"utf16_lithuanian_ci\":      113,\n\t\"utf16_slovak_ci\":          114,\n\t\"utf16_spanish2_ci\":        115,\n\t\"utf16_roman_ci\":           116,\n\t\"utf16_persian_ci\":         117,\n\t\"utf16_esperanto_ci\":       118,\n\t\"utf16_hungarian_ci\":       119,\n\t\"utf16_sinhala_ci\":         120,\n\t\"utf16_german2_ci\":         121,\n\t\"utf16_croatian_ci\":        122,\n\t\"utf16_unicode_520_ci\":     123,\n\t\"utf16_vietnamese_ci\":      124,\n\t\"ucs2_unicode_ci\":          128,\n\t\"ucs2_icelandic_ci\":        129,\n\t\"ucs2_latvian_ci\":          130,\n\t\"ucs2_romanian_ci\":         131,\n\t\"ucs2_slovenian_ci\":        132,\n\t\"ucs2_polish_ci\":           133,\n\t\"ucs2_estonian_ci\":         134,\n\t\"ucs2_spanish_ci\":          135,\n\t\"ucs2_swedish_ci\":          136,\n\t\"ucs2_turkish_ci\":          137,\n\t\"ucs2_czech_ci\":            138,\n\t\"ucs2_danish_ci\":           139,\n\t\"ucs2_lithuanian_ci\":       140,\n\t\"ucs2_slovak_ci\":           141,\n\t\"ucs2_spanish2_ci\":         142,\n\t\"ucs2_roman_ci\":            143,\n\t\"ucs2_persian_ci\":          144,\n\t\"ucs2_esperanto_ci\":        145,\n\t\"ucs2_hungarian_ci\":        146,\n\t\"ucs2_sinhala_ci\":          147,\n\t\"ucs2_german2_ci\":          148,\n\t\"ucs2_croatian_ci\":         149,\n\t\"ucs2_unicode_520_ci\":      150,\n\t\"ucs2_vietnamese_ci\":       151,\n\t\"ucs2_general_mysql500_ci\": 159,\n\t\"utf32_unicode_ci\":         160,\n\t\"utf32_icelandic_ci\":       161,\n\t\"utf32_latvian_ci\":         162,\n\t\"utf32_romanian_ci\":        163,\n\t\"utf32_slovenian_ci\":       164,\n\t\"utf32_polish_ci\":          165,\n\t\"utf32_estonian_ci\":        166,\n\t\"utf32_spanish_ci\":         167,\n\t\"utf32_swedish_ci\":         168,\n\t\"utf32_turkish_ci\":         169,\n\t\"utf32_czech_ci\":           170,\n\t\"utf32_danish_ci\":          171,\n\t\"utf32_lithuanian_ci\":      172,\n\t\"utf32_slovak_ci\":          173,\n\t\"utf32_spanish2_ci\":        174,\n\t\"utf32_roman_ci\":           175,\n\t\"utf32_persian_ci\":         176,\n\t\"utf32_esperanto_ci\":       177,\n\t\"utf32_hungarian_ci\":       178,\n\t\"utf32_sinhala_ci\":         179,\n\t\"utf32_german2_ci\":         180,\n\t\"utf32_croatian_ci\":        181,\n\t\"utf32_unicode_520_ci\":     182,\n\t\"utf32_vietnamese_ci\":      183,\n\t\"utf8_unicode_ci\":          192,\n\t\"utf8_icelandic_ci\":        193,\n\t\"utf8_latvian_ci\":          194,\n\t\"utf8_romanian_ci\":         195,\n\t\"utf8_slovenian_ci\":        196,\n\t\"utf8_polish_ci\":           197,\n\t\"utf8_estonian_ci\":         198,\n\t\"utf8_spanish_ci\":          199,\n\t\"utf8_swedish_ci\":          200,\n\t\"utf8_turkish_ci\":          201,\n\t\"utf8_czech_ci\":            202,\n\t\"utf8_danish_ci\":           203,\n\t\"utf8_lithuanian_ci\":       204,\n\t\"utf8_slovak_ci\":           205,\n\t\"utf8_spanish2_ci\":         206,\n\t\"utf8_roman_ci\":            207,\n\t\"utf8_persian_ci\":          208,\n\t\"utf8_esperanto_ci\":        209,\n\t\"utf8_hungarian_ci\":        210,\n\t\"utf8_sinhala_ci\":          211,\n\t\"utf8_german2_ci\":          212,\n\t\"utf8_croatian_ci\":         213,\n\t\"utf8_unicode_520_ci\":      214,\n\t\"utf8_vietnamese_ci\":       215,\n\t\"utf8_general_mysql500_ci\": 223,\n\t\"utf8mb4_unicode_ci\":       224,\n\t\"utf8mb4_icelandic_ci\":     225,\n\t\"utf8mb4_latvian_ci\":       226,\n\t\"utf8mb4_romanian_ci\":      227,\n\t\"utf8mb4_slovenian_ci\":     228,\n\t\"utf8mb4_polish_ci\":        229,\n\t\"utf8mb4_estonian_ci\":      230,\n\t\"utf8mb4_spanish_ci\":       231,\n\t\"utf8mb4_swedish_ci\":       232,\n\t\"utf8mb4_turkish_ci\":       233,\n\t\"utf8mb4_czech_ci\":         234,\n\t\"utf8mb4_danish_ci\":        235,\n\t\"utf8mb4_lithuanian_ci\":    236,\n\t\"utf8mb4_slovak_ci\":        237,\n\t\"utf8mb4_spanish2_ci\":      238,\n\t\"utf8mb4_roman_ci\":         239,\n\t\"utf8mb4_persian_ci\":       240,\n\t\"utf8mb4_esperanto_ci\":     241,\n\t\"utf8mb4_hungarian_ci\":     242,\n\t\"utf8mb4_sinhala_ci\":       243,\n\t\"utf8mb4_german2_ci\":       244,\n\t\"utf8mb4_croatian_ci\":      245,\n\t\"utf8mb4_unicode_520_ci\":   246,\n\t\"utf8mb4_vietnamese_ci\":    247,\n\t\"utf8mb4_0900_ai_ci\":       255,\n}\n\n// MySQL collation information.\nconst (\n\tUTF8Charset    = \"utf8\"\n\tUTF8MB4Charset = \"utf8mb4\"\n\tDefaultCharset = UTF8MB4Charset\n\t// DefaultCollationID is utf8mb4_bin(46)\n\tDefaultCollationID        = 46\n\tLatin1DefaultCollationID  = 47\n\tASCIIDefaultCollationID   = 65\n\tUTF8DefaultCollationID    = 83\n\tUTF8MB4DefaultCollationID = 46\n\tBinaryDefaultCollationID  = 63\n\tUTF8DefaultCollation      = \"utf8_bin\"\n\tUTF8MB4DefaultCollation   = \"utf8mb4_bin\"\n\tDefaultCollationName      = UTF8MB4DefaultCollation\n\n\t// MaxBytesOfCharacter, is the max bytes length of a character,\n\t// refer to RFC3629, in UTF-8, characters from the U+0000..U+10FFFF range\n\t// (the UTF-16 accessible range) are encoded using sequences of 1 to 4 octets.\n\tMaxBytesOfCharacter = 4\n)\n\n// IsUTF8Charset checks if charset is utf8 or utf8mb4\nfunc IsUTF8Charset(charset string) bool {\n\treturn charset == UTF8Charset || charset == UTF8MB4Charset\n}\n\n// RangeGraph defines valid unicode characters to use in column names. It strictly follows MySQL's definition.\n// See #3994.\nvar RangeGraph = []*unicode.RangeTable{\n\t// _MY_PNT\n\tunicode.No,\n\tunicode.Mn,\n\tunicode.Me,\n\tunicode.Pc,\n\tunicode.Pd,\n\tunicode.Pd,\n\tunicode.Ps,\n\tunicode.Pe,\n\tunicode.Pi,\n\tunicode.Pf,\n\tunicode.Po,\n\tunicode.Sm,\n\tunicode.Sc,\n\tunicode.Sk,\n\tunicode.So,\n\t// _MY_U\n\tunicode.Lu,\n\tunicode.Lt,\n\tunicode.Nl,\n\t// _MY_L\n\tunicode.Ll,\n\tunicode.Lm,\n\tunicode.Lo,\n\tunicode.Nl,\n\tunicode.Mn,\n\tunicode.Mc,\n\tunicode.Me,\n\t// _MY_NMR\n\tunicode.Nd,\n\tunicode.Nl,\n\tunicode.No,\n}\n"
  },
  {
    "path": "pkg/parser/mysql/const.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\nimport (\n\t\"strings\"\n)\n\nfunc newInvalidModeErr(s string) error {\n\treturn NewErr(ErrWrongValueForVar, \"sql_mode\", s)\n}\n\n// Header information.\nconst (\n\tOKHeader          byte = 0x00\n\tErrHeader         byte = 0xff\n\tEOFHeader         byte = 0xfe\n\tLocalInFileHeader byte = 0xfb\n)\n\n// Server information.\nconst (\n\tServerStatusInTrans            uint16 = 0x0001\n\tServerStatusAutocommit         uint16 = 0x0002\n\tServerMoreResultsExists        uint16 = 0x0008\n\tServerStatusNoGoodIndexUsed    uint16 = 0x0010\n\tServerStatusNoIndexUsed        uint16 = 0x0020\n\tServerStatusCursorExists       uint16 = 0x0040\n\tServerStatusLastRowSend        uint16 = 0x0080\n\tServerStatusDBDropped          uint16 = 0x0100\n\tServerStatusNoBackslashEscaped uint16 = 0x0200\n\tServerStatusMetadataChanged    uint16 = 0x0400\n\tServerStatusWasSlow            uint16 = 0x0800\n\tServerPSOutParams              uint16 = 0x1000\n)\n\n// HasCursorExistsFlag return true if cursor exists indicated by server status.\nfunc HasCursorExistsFlag(serverStatus uint16) bool {\n\treturn serverStatus&ServerStatusCursorExists > 0\n}\n\n// Identifier length limitations.\n// See https://dev.mysql.com/doc/refman/5.7/en/identifiers.html\nconst (\n\t// MaxPayloadLen is the max packet payload length.\n\tMaxPayloadLen = 1<<24 - 1\n\t// MaxTableNameLength is max length of table name identifier.\n\tMaxTableNameLength = 64\n\t// MaxDatabaseNameLength is max length of database name identifier.\n\tMaxDatabaseNameLength = 64\n\t// MaxColumnNameLength is max length of column name identifier.\n\tMaxColumnNameLength = 64\n\t// MaxKeyParts is max length of key parts.\n\tMaxKeyParts = 16\n\t// MaxIndexIdentifierLen is max length of index identifier.\n\tMaxIndexIdentifierLen = 64\n\t// MaxConstraintIdentifierLen is max length of constrain identifier.\n\tMaxConstraintIdentifierLen = 64\n\t// MaxViewIdentifierLen is max length of view identifier.\n\tMaxViewIdentifierLen = 64\n\t// MaxAliasIdentifierLen is max length of alias identifier.\n\tMaxAliasIdentifierLen = 256\n\t// MaxUserDefinedVariableLen is max length of user-defined variable.\n\tMaxUserDefinedVariableLen = 64\n)\n\n// ErrTextLength error text length limit.\nconst ErrTextLength = 80\n\n// Command information.\nconst (\n\tComSleep byte = iota\n\tComQuit\n\tComInitDB\n\tComQuery\n\tComFieldList\n\tComCreateDB\n\tComDropDB\n\tComRefresh\n\tComShutdown\n\tComStatistics\n\tComProcessInfo\n\tComConnect\n\tComProcessKill\n\tComDebug\n\tComPing\n\tComTime\n\tComDelayedInsert\n\tComChangeUser\n\tComBinlogDump\n\tComTableDump\n\tComConnectOut\n\tComRegisterSlave\n\tComStmtPrepare\n\tComStmtExecute\n\tComStmtSendLongData\n\tComStmtClose\n\tComStmtReset\n\tComSetOption\n\tComStmtFetch\n\tComDaemon\n\tComBinlogDumpGtid\n\tComResetConnection\n\tComEnd\n)\n\n// Client information.\nconst (\n\tClientLongPassword uint32 = 1 << iota\n\tClientFoundRows\n\tClientLongFlag\n\tClientConnectWithDB\n\tClientNoSchema\n\tClientCompress\n\tClientODBC\n\tClientLocalFiles\n\tClientIgnoreSpace\n\tClientProtocol41\n\tClientInteractive\n\tClientSSL\n\tClientIgnoreSigpipe\n\tClientTransactions\n\tClientReserved\n\tClientSecureConnection\n\tClientMultiStatements\n\tClientMultiResults\n\tClientPSMultiResults\n\tClientPluginAuth\n\tClientConnectAtts\n\tClientPluginAuthLenencClientData\n)\n\n// Cache type information.\nconst (\n\tTypeNoCache byte = 0xff\n)\n\n// Auth name information.\nconst (\n\tAuthName = \"mysql_native_password\"\n)\n\n// MySQL database and tables.\nconst (\n\t// SystemDB is the name of system database.\n\tSystemDB = \"mysql\"\n\t// GlobalPrivTable is the table in system db contains global scope privilege info.\n\tGlobalPrivTable = \"global_priv\"\n\t// UserTable is the table in system db contains user info.\n\tUserTable = \"User\"\n\t// DBTable is the table in system db contains db scope privilege info.\n\tDBTable = \"DB\"\n\t// TablePrivTable is the table in system db contains table scope privilege info.\n\tTablePrivTable = \"Tables_priv\"\n\t// ColumnPrivTable is the table in system db contains column scope privilege info.\n\tColumnPrivTable = \"Columns_priv\"\n\t// GlobalVariablesTable is the table contains global system variables.\n\tGlobalVariablesTable = \"GLOBAL_VARIABLES\"\n\t// GlobalStatusTable is the table contains global status variables.\n\tGlobalStatusTable = \"GLOBAL_STATUS\"\n\t// TiDBTable is the table contains tidb info.\n\tTiDBTable = \"tidb\"\n\t//  RoleEdgesTable is the table contains role relation info\n\tRoleEdgeTable = \"role_edges\"\n\t// DefaultRoleTable is the table contain default active role info\n\tDefaultRoleTable = \"default_roles\"\n)\n\n// PrivilegeType  privilege\ntype PrivilegeType uint64\n\nconst (\n\t_ PrivilegeType = 1 << iota\n\t// CreatePriv is the privilege to create schema/table.\n\tCreatePriv\n\t// SelectPriv is the privilege to read from table.\n\tSelectPriv\n\t// InsertPriv is the privilege to insert data into table.\n\tInsertPriv\n\t// UpdatePriv is the privilege to update data in table.\n\tUpdatePriv\n\t// DeletePriv is the privilege to delete data from table.\n\tDeletePriv\n\t// ShowDBPriv is the privilege to run show databases statement.\n\tShowDBPriv\n\t// SuperPriv enables many operations and server behaviors.\n\tSuperPriv\n\t// CreateUserPriv is the privilege to create user.\n\tCreateUserPriv\n\t// TriggerPriv is not checked yet.\n\tTriggerPriv\n\t// DropPriv is the privilege to drop schema/table.\n\tDropPriv\n\t// ProcessPriv pertains to display of information about the threads executing within the server.\n\tProcessPriv\n\t// GrantPriv is the privilege to grant privilege to user.\n\tGrantPriv\n\t// ReferencesPriv is not checked yet.\n\tReferencesPriv\n\t// AlterPriv is the privilege to run alter statement.\n\tAlterPriv\n\t// ExecutePriv is the privilege to run execute statement.\n\tExecutePriv\n\t// IndexPriv is the privilege to create/drop index.\n\tIndexPriv\n\t// CreateViewPriv is the privilege to create view.\n\tCreateViewPriv\n\t// ShowViewPriv is the privilege to show create view.\n\tShowViewPriv\n\t// CreateRolePriv the privilege to create a role.\n\tCreateRolePriv\n\t// DropRolePriv is the privilege to drop a role.\n\tDropRolePriv\n\n\tCreateTMPTablePriv\n\tLockTablesPriv\n\tCreateRoutinePriv\n\tAlterRoutinePriv\n\tEventPriv\n\n\t// ShutdownPriv the privilege to shutdown a server.\n\tShutdownPriv\n\t// ReloadPriv is the privilege to enable the use of the FLUSH statement.\n\tReloadPriv\n\t// FilePriv is the privilege to enable the use of LOAD DATA and SELECT ... INTO OUTFILE.\n\tFilePriv\n\n\t// VisibilityPriv for SCQL\n\t// DescribePriv the privilege to `Describe` table priv\n\tDescribePriv\n\t// ShowPriv the privilege to `Show` databases/tables/grants\n\tShowPriv\n\n\t// AllPriv is the privilege for all actions.\n\tAllPriv\n\n\t// VisibilityPriv for SCQL\n\tPlaintextPriv\n\tPlaintextAfterJoinPriv\n\tPlaintextAsJoinPayloadPriv\n\tPlaintextAfterGroupByPriv\n\tPlaintextAfterAggregatePriv\n\tPlaintextAfterComparePriv\n\tEncryptedOnlyPriv\n\tRevealRankPriv\n)\n\n// AllPrivMask is the mask for PrivilegeType with all bits set to 1.\n// If it's passed to RequestVerification, it means any privilege would be OK.\nconst AllPrivMask = AllPriv - 1\n\n// MySQL type maximum length.\nconst (\n\t// For arguments that have no fixed number of decimals, the decimals value is set to 31,\n\t// which is 1 more than the maximum number of decimals permitted for the DECIMAL, FLOAT, and DOUBLE data types.\n\tNotFixedDec = 31\n\n\tMaxIntWidth              = 20\n\tMaxRealWidth             = 23\n\tMaxFloatingTypeScale     = 30\n\tMaxFloatingTypeWidth     = 255\n\tMaxDecimalScale          = 30\n\tMaxDecimalWidth          = 65\n\tMaxDateWidth             = 10 // YYYY-MM-DD.\n\tMaxDatetimeWidthNoFsp    = 19 // YYYY-MM-DD HH:MM:SS\n\tMaxDatetimeWidthWithFsp  = 26 // YYYY-MM-DD HH:MM:SS[.fraction]\n\tMaxDatetimeFullWidth     = 29 // YYYY-MM-DD HH:MM:SS.###### AM\n\tMaxDurationWidthNoFsp    = 10 // HH:MM:SS\n\tMaxDurationWidthWithFsp  = 15 // HH:MM:SS[.fraction]\n\tMaxBlobWidth             = 16777216\n\tMaxBitDisplayWidth       = 64\n\tMaxFloatPrecisionLength  = 24\n\tMaxDoublePrecisionLength = 53\n)\n\n// MySQL max type field length.\nconst (\n\tMaxFieldCharLength    = 255\n\tMaxFieldVarCharLength = 65535\n)\n\n// MaxTypeSetMembers is the number of set members.\nconst MaxTypeSetMembers = 64\n\n// PWDHashLen is the length of password's hash.\nconst PWDHashLen = 64\n\n// Priv2UserCol is the privilege to mysql.user table column name.\nvar Priv2UserCol = map[PrivilegeType]string{\n\tCreatePriv:                  \"Create_priv\",\n\tSelectPriv:                  \"Select_priv\",\n\tInsertPriv:                  \"Insert_priv\",\n\tUpdatePriv:                  \"Update_priv\",\n\tDeletePriv:                  \"Delete_priv\",\n\tShowDBPriv:                  \"Show_db_priv\",\n\tSuperPriv:                   \"Super_priv\",\n\tCreateUserPriv:              \"Create_user_priv\",\n\tTriggerPriv:                 \"Trigger_priv\",\n\tDropPriv:                    \"Drop_priv\",\n\tProcessPriv:                 \"Process_priv\",\n\tGrantPriv:                   \"Grant_priv\",\n\tReferencesPriv:              \"References_priv\",\n\tAlterPriv:                   \"Alter_priv\",\n\tExecutePriv:                 \"Execute_priv\",\n\tIndexPriv:                   \"Index_priv\",\n\tCreateViewPriv:              \"Create_view_priv\",\n\tShowViewPriv:                \"Show_view_priv\",\n\tCreateRolePriv:              \"Create_role_priv\",\n\tDropRolePriv:                \"Drop_role_priv\",\n\tCreateTMPTablePriv:          \"Create_tmp_table_priv\",\n\tLockTablesPriv:              \"Lock_tables_priv\",\n\tCreateRoutinePriv:           \"Create_routine_priv\",\n\tAlterRoutinePriv:            \"Alter_routine_priv\",\n\tEventPriv:                   \"Event_priv\",\n\tShutdownPriv:                \"Shutdown_priv\",\n\tReloadPriv:                  \"Reload_priv\",\n\tFilePriv:                    \"File_priv\",\n\tDescribePriv:                \"Describe_priv\",\n\tShowPriv:                    \"Show_priv\",\n\tPlaintextPriv:               \"Plaintext_priv\",\n\tPlaintextAfterJoinPriv:      \"Plaintext_after_join_priv\",\n\tPlaintextAsJoinPayloadPriv:  \"Plaintext_as_join_payload\",\n\tPlaintextAfterGroupByPriv:   \"Plaintext_after_group_by_priv\",\n\tPlaintextAfterComparePriv:   \"PLAINTEXT_AFTER_COMPARE_priv\",\n\tPlaintextAfterAggregatePriv: \"PLAINTEXT_AFTER_AGGREGATE_priv\",\n\tRevealRankPriv:              \"Reveal_rank_priv\",\n\tEncryptedOnlyPriv:           \"Encrypted_only_priv\",\n}\n\n// Col2PrivType is the privilege tables column name to privilege type.\nvar Col2PrivType = map[string]PrivilegeType{\n\t\"Create_priv\":                    CreatePriv,\n\t\"Select_priv\":                    SelectPriv,\n\t\"Insert_priv\":                    InsertPriv,\n\t\"Update_priv\":                    UpdatePriv,\n\t\"Delete_priv\":                    DeletePriv,\n\t\"Show_db_priv\":                   ShowDBPriv,\n\t\"Super_priv\":                     SuperPriv,\n\t\"Create_user_priv\":               CreateUserPriv,\n\t\"Trigger_priv\":                   TriggerPriv,\n\t\"Drop_priv\":                      DropPriv,\n\t\"Process_priv\":                   ProcessPriv,\n\t\"Grant_priv\":                     GrantPriv,\n\t\"References_priv\":                ReferencesPriv,\n\t\"Alter_priv\":                     AlterPriv,\n\t\"Execute_priv\":                   ExecutePriv,\n\t\"Index_priv\":                     IndexPriv,\n\t\"Create_view_priv\":               CreateViewPriv,\n\t\"Show_view_priv\":                 ShowViewPriv,\n\t\"Create_role_priv\":               CreateRolePriv,\n\t\"Drop_role_priv\":                 DropRolePriv,\n\t\"Create_tmp_table_priv\":          CreateTMPTablePriv,\n\t\"Lock_tables_priv\":               LockTablesPriv,\n\t\"Create_routine_priv\":            CreateRoutinePriv,\n\t\"Alter_routine_priv\":             AlterRoutinePriv,\n\t\"Event_priv\":                     EventPriv,\n\t\"Shutdown_priv\":                  ShutdownPriv,\n\t\"Reload_priv\":                    ReloadPriv,\n\t\"File_priv\":                      FilePriv,\n\t\"Describe_priv\":                  DescribePriv,\n\t\"Show_priv\":                      ShowPriv,\n\t\"Plaintext_priv\":                 PlaintextPriv,\n\t\"Plaintext_after_join_priv\":      PlaintextAfterJoinPriv,\n\t\"Plaintext_as_join_payload\":      PlaintextAsJoinPayloadPriv,\n\t\"Plaintext_after_group_by_priv\":  PlaintextAfterGroupByPriv,\n\t\"PLAINTEXT_AFTER_COMPARE_priv\":   PlaintextAfterComparePriv,\n\t\"PLAINTEXT_AFTER_AGGREGATE_priv\": PlaintextAfterAggregatePriv,\n\t\"Reveal_rank_priv\":               RevealRankPriv,\n\t\"Encrypted_only_priv\":            EncryptedOnlyPriv,\n}\n\n// Command2Str is the command information to command name.\nvar Command2Str = map[byte]string{\n\tComSleep:            \"Sleep\",\n\tComQuit:             \"Quit\",\n\tComInitDB:           \"Init DB\",\n\tComQuery:            \"Query\",\n\tComFieldList:        \"Field List\",\n\tComCreateDB:         \"Create DB\",\n\tComDropDB:           \"Drop DB\",\n\tComRefresh:          \"Refresh\",\n\tComShutdown:         \"Shutdown\",\n\tComStatistics:       \"Statistics\",\n\tComProcessInfo:      \"Processlist\",\n\tComConnect:          \"Connect\",\n\tComProcessKill:      \"Kill\",\n\tComDebug:            \"Debug\",\n\tComPing:             \"Ping\",\n\tComTime:             \"Time\",\n\tComDelayedInsert:    \"Delayed Insert\",\n\tComChangeUser:       \"Change User\",\n\tComBinlogDump:       \"Binlog Dump\",\n\tComTableDump:        \"Table Dump\",\n\tComConnectOut:       \"Connect out\",\n\tComRegisterSlave:    \"Register Slave\",\n\tComStmtPrepare:      \"Prepare\",\n\tComStmtExecute:      \"Execute\",\n\tComStmtSendLongData: \"Long Data\",\n\tComStmtClose:        \"Close stmt\",\n\tComStmtReset:        \"Reset stmt\",\n\tComSetOption:        \"Set option\",\n\tComStmtFetch:        \"Fetch\",\n\tComDaemon:           \"Daemon\",\n\tComBinlogDumpGtid:   \"Binlog Dump\",\n\tComResetConnection:  \"Reset connect\",\n}\n\n// Priv2Str is the map for privilege to string.\nvar Priv2Str = map[PrivilegeType]string{\n\tCreatePriv:                  \"Create\",\n\tSelectPriv:                  \"Select\",\n\tInsertPriv:                  \"Insert\",\n\tUpdatePriv:                  \"Update\",\n\tDeletePriv:                  \"Delete\",\n\tShowDBPriv:                  \"Show Databases\",\n\tSuperPriv:                   \"Super\",\n\tCreateUserPriv:              \"Create User\",\n\tTriggerPriv:                 \"Trigger\",\n\tDropPriv:                    \"Drop\",\n\tProcessPriv:                 \"Process\",\n\tGrantPriv:                   \"Grant Option\",\n\tReferencesPriv:              \"References\",\n\tAlterPriv:                   \"Alter\",\n\tExecutePriv:                 \"Execute\",\n\tIndexPriv:                   \"Index\",\n\tCreateViewPriv:              \"Create View\",\n\tShowViewPriv:                \"Show View\",\n\tCreateRolePriv:              \"Create Role\",\n\tDropRolePriv:                \"Drop Role\",\n\tCreateTMPTablePriv:          \"CREATE TEMPORARY TABLES\",\n\tLockTablesPriv:              \"LOCK TABLES\",\n\tCreateRoutinePriv:           \"CREATE ROUTINE\",\n\tAlterRoutinePriv:            \"ALTER ROUTINE\",\n\tEventPriv:                   \"EVENT\",\n\tShutdownPriv:                \"SHUTDOWN\",\n\tReloadPriv:                  \"RELOAD\",\n\tFilePriv:                    \"FILE\",\n\tDescribePriv:                \"DESCRIBE\",\n\tShowPriv:                    \"SHOW\",\n\tPlaintextPriv:               \"SELECT PLAINTEXT\",\n\tPlaintextAfterJoinPriv:      \"SELECT PLAINTEXT_AFTER_JOIN\",\n\tPlaintextAsJoinPayloadPriv:  \"SELECT PLAINTEXT_AS_JOIN_PAYLOAD\",\n\tPlaintextAfterGroupByPriv:   \"SELECT PLAINTEXT_AFTER_GROUP_BY\",\n\tPlaintextAfterComparePriv:   \"SELECT PLAINTEXT_AFTER_COMPARE\",\n\tPlaintextAfterAggregatePriv: \"SELECT PLAINTEXT_AFTER_AGGREGATE\",\n\tRevealRankPriv:              \"SELECT REVEAL_RANK\",\n\tEncryptedOnlyPriv:           \"SELECT ENCRYPTED_ONLY\",\n}\n\n// Priv2SetStr is the map for privilege to string.\nvar Priv2SetStr = map[PrivilegeType]string{\n\tCreatePriv:     \"Create\",\n\tSelectPriv:     \"Select\",\n\tInsertPriv:     \"Insert\",\n\tUpdatePriv:     \"Update\",\n\tDeletePriv:     \"Delete\",\n\tDropPriv:       \"Drop\",\n\tGrantPriv:      \"Grant\",\n\tAlterPriv:      \"Alter\",\n\tExecutePriv:    \"Execute\",\n\tIndexPriv:      \"Index\",\n\tCreateViewPriv: \"Create View\",\n\tShowViewPriv:   \"Show View\",\n\tCreateRolePriv: \"Create Role\",\n\tDropRolePriv:   \"Drop Role\",\n\tShutdownPriv:   \"Shutdown Role\",\n}\n\n// SetStr2Priv is the map for privilege set string to privilege type.\nvar SetStr2Priv = map[string]PrivilegeType{\n\t\"Create\":      CreatePriv,\n\t\"Select\":      SelectPriv,\n\t\"Insert\":      InsertPriv,\n\t\"Update\":      UpdatePriv,\n\t\"Delete\":      DeletePriv,\n\t\"Drop\":        DropPriv,\n\t\"Grant\":       GrantPriv,\n\t\"Alter\":       AlterPriv,\n\t\"Execute\":     ExecutePriv,\n\t\"Index\":       IndexPriv,\n\t\"Create View\": CreateViewPriv,\n\t\"Show View\":   ShowViewPriv,\n}\n\n// AllGlobalPrivs is all the privileges in global scope.\nvar AllGlobalPrivs = []PrivilegeType{SelectPriv, InsertPriv, UpdatePriv, DeletePriv, CreatePriv, DropPriv, ProcessPriv, ReferencesPriv, AlterPriv, ShowDBPriv, SuperPriv, ExecutePriv, IndexPriv, CreateUserPriv, TriggerPriv, CreateViewPriv, ShowViewPriv, CreateRolePriv, DropRolePriv, CreateTMPTablePriv, LockTablesPriv, CreateRoutinePriv, AlterRoutinePriv, EventPriv, ShutdownPriv, ReloadPriv, FilePriv, DescribePriv, ShowPriv, PlaintextPriv, PlaintextAfterJoinPriv, PlaintextAsJoinPayloadPriv, PlaintextAfterGroupByPriv, PlaintextAfterAggregatePriv, PlaintextAfterComparePriv, EncryptedOnlyPriv, RevealRankPriv}\n\n// AllDBPrivs is all the privileges in database scope.\nvar AllDBPrivs = []PrivilegeType{SelectPriv, InsertPriv, UpdatePriv, DeletePriv, CreatePriv, DropPriv, AlterPriv, ExecutePriv, IndexPriv, CreateViewPriv, ShowViewPriv, DescribePriv, ShowPriv}\n\n// AllTablePrivs is all the privileges in table scope.\nvar AllTablePrivs = []PrivilegeType{SelectPriv, InsertPriv, UpdatePriv, DeletePriv, CreatePriv, DropPriv, AlterPriv, IndexPriv}\n\n// AllColumnPrivs is all the privileges in column scope.\nvar AllColumnPrivs = []PrivilegeType{SelectPriv, InsertPriv, UpdatePriv}\n\n// AllPrivilegeLiteral is the string literal for All Privilege.\nconst AllPrivilegeLiteral = \"ALL PRIVILEGES\"\n\n// DefaultSQLMode for GLOBAL_VARIABLES\nconst DefaultSQLMode = \"ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION\"\n\n// DefaultLengthOfMysqlTypes is the map for default physical length of MySQL data types.\n// See http://dev.mysql.com/doc/refman/5.7/en/storage-requirements.html\nvar DefaultLengthOfMysqlTypes = map[byte]int{\n\tTypeYear:      1,\n\tTypeDate:      3,\n\tTypeDuration:  3,\n\tTypeDatetime:  8,\n\tTypeTimestamp: 4,\n\n\tTypeTiny:     1,\n\tTypeShort:    2,\n\tTypeInt24:    3,\n\tTypeLong:     4,\n\tTypeLonglong: 8,\n\tTypeFloat:    4,\n\tTypeDouble:   8,\n\n\tTypeEnum:   2,\n\tTypeString: 1,\n\tTypeSet:    8,\n}\n\n// DefaultLengthOfTimeFraction is the map for default physical length of time fractions.\nvar DefaultLengthOfTimeFraction = map[int]int{\n\t0: 0,\n\n\t1: 1,\n\t2: 1,\n\n\t3: 2,\n\t4: 2,\n\n\t5: 3,\n\t6: 3,\n}\n\n// SQLMode is the type for MySQL sql_mode.\n// See https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html\ntype SQLMode int\n\n// HasNoZeroDateMode detects if 'NO_ZERO_DATE' mode is set in SQLMode\nfunc (m SQLMode) HasNoZeroDateMode() bool {\n\treturn m&ModeNoZeroDate == ModeNoZeroDate\n}\n\n// HasNoZeroInDateMode detects if 'NO_ZERO_IN_DATE' mode is set in SQLMode\nfunc (m SQLMode) HasNoZeroInDateMode() bool {\n\treturn m&ModeNoZeroInDate == ModeNoZeroInDate\n}\n\n// HasErrorForDivisionByZeroMode detects if 'ERROR_FOR_DIVISION_BY_ZERO' mode is set in SQLMode\nfunc (m SQLMode) HasErrorForDivisionByZeroMode() bool {\n\treturn m&ModeErrorForDivisionByZero == ModeErrorForDivisionByZero\n}\n\n// HasOnlyFullGroupBy detects if 'ONLY_FULL_GROUP_BY' mode is set in SQLMode\nfunc (m SQLMode) HasOnlyFullGroupBy() bool {\n\treturn m&ModeOnlyFullGroupBy == ModeOnlyFullGroupBy\n}\n\n// HasStrictMode detects if 'STRICT_TRANS_TABLES' or 'STRICT_ALL_TABLES' mode is set in SQLMode\nfunc (m SQLMode) HasStrictMode() bool {\n\treturn m&ModeStrictTransTables == ModeStrictTransTables || m&ModeStrictAllTables == ModeStrictAllTables\n}\n\n// HasPipesAsConcatMode detects if 'PIPES_AS_CONCAT' mode is set in SQLMode\nfunc (m SQLMode) HasPipesAsConcatMode() bool {\n\treturn m&ModePipesAsConcat == ModePipesAsConcat\n}\n\n// HasNoUnsignedSubtractionMode detects if 'NO_UNSIGNED_SUBTRACTION' mode is set in SQLMode\nfunc (m SQLMode) HasNoUnsignedSubtractionMode() bool {\n\treturn m&ModeNoUnsignedSubtraction == ModeNoUnsignedSubtraction\n}\n\n// HasHighNotPrecedenceMode detects if 'HIGH_NOT_PRECEDENCE' mode is set in SQLMode\nfunc (m SQLMode) HasHighNotPrecedenceMode() bool {\n\treturn m&ModeHighNotPrecedence == ModeHighNotPrecedence\n}\n\n// HasANSIQuotesMode detects if 'ANSI_QUOTES' mode is set in SQLMode\nfunc (m SQLMode) HasANSIQuotesMode() bool {\n\treturn m&ModeANSIQuotes == ModeANSIQuotes\n}\n\n// HasRealAsFloatMode detects if 'REAL_AS_FLOAT' mode is set in SQLMode\nfunc (m SQLMode) HasRealAsFloatMode() bool {\n\treturn m&ModeRealAsFloat == ModeRealAsFloat\n}\n\n// HasPadCharToFullLengthMode detects if 'PAD_CHAR_TO_FULL_LENGTH' mode is set in SQLMode\nfunc (m SQLMode) HasPadCharToFullLengthMode() bool {\n\treturn m&ModePadCharToFullLength == ModePadCharToFullLength\n}\n\n// HasNoBackslashEscapesMode detects if 'NO_BACKSLASH_ESCAPES' mode is set in SQLMode\nfunc (m SQLMode) HasNoBackslashEscapesMode() bool {\n\treturn m&ModeNoBackslashEscapes == ModeNoBackslashEscapes\n}\n\n// HasIgnoreSpaceMode detects if 'IGNORE_SPACE' mode is set in SQLMode\nfunc (m SQLMode) HasIgnoreSpaceMode() bool {\n\treturn m&ModeIgnoreSpace == ModeIgnoreSpace\n}\n\n// HasNoAutoCreateUserMode detects if 'NO_AUTO_CREATE_USER' mode is set in SQLMode\nfunc (m SQLMode) HasNoAutoCreateUserMode() bool {\n\treturn m&ModeNoAutoCreateUser == ModeNoAutoCreateUser\n}\n\n// HasAllowInvalidDatesMode detects if 'ALLOW_INVALID_DATES' mode is set in SQLMode\nfunc (m SQLMode) HasAllowInvalidDatesMode() bool {\n\treturn m&ModeAllowInvalidDates == ModeAllowInvalidDates\n}\n\n// consts for sql modes.\nconst (\n\tModeNone        SQLMode = 0\n\tModeRealAsFloat SQLMode = 1 << iota\n\tModePipesAsConcat\n\tModeANSIQuotes\n\tModeIgnoreSpace\n\tModeNotUsed\n\tModeOnlyFullGroupBy\n\tModeNoUnsignedSubtraction\n\tModeNoDirInCreate\n\tModePostgreSQL\n\tModeOracle\n\tModeMsSQL\n\tModeDb2\n\tModeMaxdb\n\tModeNoKeyOptions\n\tModeNoTableOptions\n\tModeNoFieldOptions\n\tModeMySQL323\n\tModeMySQL40\n\tModeANSI\n\tModeNoAutoValueOnZero\n\tModeNoBackslashEscapes\n\tModeStrictTransTables\n\tModeStrictAllTables\n\tModeNoZeroInDate\n\tModeNoZeroDate\n\tModeInvalidDates\n\tModeErrorForDivisionByZero\n\tModeTraditional\n\tModeNoAutoCreateUser\n\tModeHighNotPrecedence\n\tModeNoEngineSubstitution\n\tModePadCharToFullLength\n\tModeAllowInvalidDates\n)\n\n// FormatSQLModeStr re-format 'SQL_MODE' variable.\nfunc FormatSQLModeStr(s string) string {\n\ts = strings.ToUpper(strings.TrimRight(s, \" \"))\n\tparts := strings.Split(s, \",\")\n\tvar nonEmptyParts []string\n\texistParts := make(map[string]string)\n\tfor _, part := range parts {\n\t\tif len(part) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif modeParts, ok := CombinationSQLMode[part]; ok {\n\t\t\tfor _, modePart := range modeParts {\n\t\t\t\tif _, exist := existParts[modePart]; !exist {\n\t\t\t\t\tnonEmptyParts = append(nonEmptyParts, modePart)\n\t\t\t\t\texistParts[modePart] = modePart\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif _, exist := existParts[part]; !exist {\n\t\t\tnonEmptyParts = append(nonEmptyParts, part)\n\t\t\texistParts[part] = part\n\t\t}\n\t}\n\treturn strings.Join(nonEmptyParts, \",\")\n}\n\n// GetSQLMode gets the sql mode for string literal. SQL_mode is a list of different modes separated by commas.\n// The input string must be formatted by 'FormatSQLModeStr'\nfunc GetSQLMode(s string) (SQLMode, error) {\n\tstrs := strings.Split(s, \",\")\n\tvar sqlMode SQLMode\n\tfor i, length := 0, len(strs); i < length; i++ {\n\t\tmode, ok := Str2SQLMode[strs[i]]\n\t\tif !ok && strs[i] != \"\" {\n\t\t\treturn sqlMode, newInvalidModeErr(strs[i])\n\t\t}\n\t\tsqlMode = sqlMode | mode\n\t}\n\treturn sqlMode, nil\n}\n\n// Str2SQLMode is the string represent of sql_mode to sql_mode map.\nvar Str2SQLMode = map[string]SQLMode{\n\t\"REAL_AS_FLOAT\":              ModeRealAsFloat,\n\t\"PIPES_AS_CONCAT\":            ModePipesAsConcat,\n\t\"ANSI_QUOTES\":                ModeANSIQuotes,\n\t\"IGNORE_SPACE\":               ModeIgnoreSpace,\n\t\"NOT_USED\":                   ModeNotUsed,\n\t\"ONLY_FULL_GROUP_BY\":         ModeOnlyFullGroupBy,\n\t\"NO_UNSIGNED_SUBTRACTION\":    ModeNoUnsignedSubtraction,\n\t\"NO_DIR_IN_CREATE\":           ModeNoDirInCreate,\n\t\"POSTGRESQL\":                 ModePostgreSQL,\n\t\"ORACLE\":                     ModeOracle,\n\t\"MSSQL\":                      ModeMsSQL,\n\t\"DB2\":                        ModeDb2,\n\t\"MAXDB\":                      ModeMaxdb,\n\t\"NO_KEY_OPTIONS\":             ModeNoKeyOptions,\n\t\"NO_TABLE_OPTIONS\":           ModeNoTableOptions,\n\t\"NO_FIELD_OPTIONS\":           ModeNoFieldOptions,\n\t\"MYSQL323\":                   ModeMySQL323,\n\t\"MYSQL40\":                    ModeMySQL40,\n\t\"ANSI\":                       ModeANSI,\n\t\"NO_AUTO_VALUE_ON_ZERO\":      ModeNoAutoValueOnZero,\n\t\"NO_BACKSLASH_ESCAPES\":       ModeNoBackslashEscapes,\n\t\"STRICT_TRANS_TABLES\":        ModeStrictTransTables,\n\t\"STRICT_ALL_TABLES\":          ModeStrictAllTables,\n\t\"NO_ZERO_IN_DATE\":            ModeNoZeroInDate,\n\t\"NO_ZERO_DATE\":               ModeNoZeroDate,\n\t\"INVALID_DATES\":              ModeInvalidDates,\n\t\"ERROR_FOR_DIVISION_BY_ZERO\": ModeErrorForDivisionByZero,\n\t\"TRADITIONAL\":                ModeTraditional,\n\t\"NO_AUTO_CREATE_USER\":        ModeNoAutoCreateUser,\n\t\"HIGH_NOT_PRECEDENCE\":        ModeHighNotPrecedence,\n\t\"NO_ENGINE_SUBSTITUTION\":     ModeNoEngineSubstitution,\n\t\"PAD_CHAR_TO_FULL_LENGTH\":    ModePadCharToFullLength,\n\t\"ALLOW_INVALID_DATES\":        ModeAllowInvalidDates,\n}\n\n// CombinationSQLMode is the special modes that provided as shorthand for combinations of mode values.\n// See https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-combo.\nvar CombinationSQLMode = map[string][]string{\n\t\"ANSI\":        {\"REAL_AS_FLOAT\", \"PIPES_AS_CONCAT\", \"ANSI_QUOTES\", \"IGNORE_SPACE\", \"ONLY_FULL_GROUP_BY\"},\n\t\"DB2\":         {\"PIPES_AS_CONCAT\", \"ANSI_QUOTES\", \"IGNORE_SPACE\", \"NO_KEY_OPTIONS\", \"NO_TABLE_OPTIONS\", \"NO_FIELD_OPTIONS\"},\n\t\"MAXDB\":       {\"PIPES_AS_CONCAT\", \"ANSI_QUOTES\", \"IGNORE_SPACE\", \"NO_KEY_OPTIONS\", \"NO_TABLE_OPTIONS\", \"NO_FIELD_OPTIONS\", \"NO_AUTO_CREATE_USER\"},\n\t\"MSSQL\":       {\"PIPES_AS_CONCAT\", \"ANSI_QUOTES\", \"IGNORE_SPACE\", \"NO_KEY_OPTIONS\", \"NO_TABLE_OPTIONS\", \"NO_FIELD_OPTIONS\"},\n\t\"MYSQL323\":    {\"MYSQL323\", \"HIGH_NOT_PRECEDENCE\"},\n\t\"MYSQL40\":     {\"MYSQL40\", \"HIGH_NOT_PRECEDENCE\"},\n\t\"ORACLE\":      {\"PIPES_AS_CONCAT\", \"ANSI_QUOTES\", \"IGNORE_SPACE\", \"NO_KEY_OPTIONS\", \"NO_TABLE_OPTIONS\", \"NO_FIELD_OPTIONS\", \"NO_AUTO_CREATE_USER\"},\n\t\"POSTGRESQL\":  {\"PIPES_AS_CONCAT\", \"ANSI_QUOTES\", \"IGNORE_SPACE\", \"NO_KEY_OPTIONS\", \"NO_TABLE_OPTIONS\", \"NO_FIELD_OPTIONS\"},\n\t\"TRADITIONAL\": {\"STRICT_TRANS_TABLES\", \"STRICT_ALL_TABLES\", \"NO_ZERO_IN_DATE\", \"NO_ZERO_DATE\", \"ERROR_FOR_DIVISION_BY_ZERO\", \"NO_AUTO_CREATE_USER\", \"NO_ENGINE_SUBSTITUTION\"},\n}\n\n// FormatFunc is the locale format function signature.\ntype FormatFunc func(string, string) (string, error)\n\n// GetLocaleFormatFunction get the format function for sepcific locale.\nfunc GetLocaleFormatFunction(loc string) FormatFunc {\n\tlocale, exist := locale2FormatFunction[loc]\n\tif !exist {\n\t\treturn formatNotSupport\n\t}\n\treturn locale\n}\n\n// locale2FormatFunction is the string represent of locale format function.\nvar locale2FormatFunction = map[string]FormatFunc{\n\t\"en_US\": formatENUS,\n\t\"zh_CN\": formatZHCN,\n}\n\n// PriorityEnum is defined for Priority const values.\ntype PriorityEnum int\n\n// Priority const values.\n// See https://dev.mysql.com/doc/refman/5.7/en/insert.html\nconst (\n\tNoPriority PriorityEnum = iota\n\tLowPriority\n\tHighPriority\n\tDelayedPriority\n)\n\n// Priority2Str is used to convert the statement priority to string.\nvar Priority2Str = map[PriorityEnum]string{\n\tNoPriority:      \"NO_PRIORITY\",\n\tLowPriority:     \"LOW_PRIORITY\",\n\tHighPriority:    \"HIGH_PRIORITY\",\n\tDelayedPriority: \"DELAYED\",\n}\n\n// Str2Priority is used to convert a string to a priority.\nfunc Str2Priority(val string) PriorityEnum {\n\tval = strings.ToUpper(val)\n\tswitch val {\n\tcase \"NO_PRIORITY\":\n\t\treturn NoPriority\n\tcase \"HIGH_PRIORITY\":\n\t\treturn HighPriority\n\tcase \"LOW_PRIORITY\":\n\t\treturn LowPriority\n\tcase \"DELAYED\":\n\t\treturn DelayedPriority\n\tdefault:\n\t\treturn NoPriority\n\t}\n}\n\n// PrimaryKeyName defines primary key name.\nconst (\n\tPrimaryKeyName = \"PRIMARY\"\n)\n"
  },
  {
    "path": "pkg/parser/mysql/const_test.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n)\n\nvar _ = Suite(&testConstSuite{})\n\ntype testConstSuite struct{}\n\nfunc TestT(t *testing.T) {\n\tTestingT(t)\n}\n\nfunc (s *testConstSuite) TestPrivAllConsistency(c *C) {\n\t// AllPriv in mysql.user columns.\n\tfor priv := PrivilegeType(CreatePriv); priv != AllPriv; priv = priv << 1 {\n\t\t_, ok := Priv2UserCol[priv]\n\t\tc.Assert(ok, IsTrue, Commentf(\"priv fail %d\", priv))\n\t}\n\n\tfor _, v := range AllGlobalPrivs {\n\t\t_, ok := Priv2UserCol[v]\n\t\tc.Assert(ok, IsTrue)\n\t}\n\n\tc.Assert(len(Priv2UserCol), Equals, len(AllGlobalPrivs)+1)\n\n\tfor _, v := range Priv2UserCol {\n\t\t_, ok := Col2PrivType[v]\n\t\tc.Assert(ok, IsTrue)\n\t}\n\tfor _, v := range Col2PrivType {\n\t\t_, ok := Priv2UserCol[v]\n\t\tc.Assert(ok, IsTrue)\n\t}\n\n\tc.Assert(len(Priv2Str), Equals, len(Priv2UserCol))\n}\n"
  },
  {
    "path": "pkg/parser/mysql/errcode.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\n// MySQL error code.\n// This value is numeric. It is not portable to other database systems.\nconst (\n\tErrErrorFirst                                            uint16 = 1000\n\tErrHashchk                                                      = 1000\n\tErrNisamchk                                                     = 1001\n\tErrNo                                                           = 1002\n\tErrYes                                                          = 1003\n\tErrCantCreateFile                                               = 1004\n\tErrCantCreateTable                                              = 1005\n\tErrCantCreateDB                                                 = 1006\n\tErrDBCreateExists                                               = 1007\n\tErrDBDropExists                                                 = 1008\n\tErrDBDropDelete                                                 = 1009\n\tErrDBDropRmdir                                                  = 1010\n\tErrCantDeleteFile                                               = 1011\n\tErrCantFindSystemRec                                            = 1012\n\tErrCantGetStat                                                  = 1013\n\tErrCantGetWd                                                    = 1014\n\tErrCantLock                                                     = 1015\n\tErrCantOpenFile                                                 = 1016\n\tErrFileNotFound                                                 = 1017\n\tErrCantReadDir                                                  = 1018\n\tErrCantSetWd                                                    = 1019\n\tErrCheckread                                                    = 1020\n\tErrDiskFull                                                     = 1021\n\tErrDupKey                                                       = 1022\n\tErrErrorOnClose                                                 = 1023\n\tErrErrorOnRead                                                  = 1024\n\tErrErrorOnRename                                                = 1025\n\tErrErrorOnWrite                                                 = 1026\n\tErrFileUsed                                                     = 1027\n\tErrFilsortAbort                                                 = 1028\n\tErrFormNotFound                                                 = 1029\n\tErrGetErrno                                                     = 1030\n\tErrIllegalHa                                                    = 1031\n\tErrKeyNotFound                                                  = 1032\n\tErrNotFormFile                                                  = 1033\n\tErrNotKeyFile                                                   = 1034\n\tErrOldKeyFile                                                   = 1035\n\tErrOpenAsReadonly                                               = 1036\n\tErrOutofMemory                                                  = 1037\n\tErrOutOfSortMemory                                              = 1038\n\tErrUnexpectedEOF                                                = 1039\n\tErrConCount                                                     = 1040\n\tErrOutOfResources                                               = 1041\n\tErrBadHost                                                      = 1042\n\tErrHandshake                                                    = 1043\n\tErrDBaccessDenied                                               = 1044\n\tErrAccessDenied                                                 = 1045\n\tErrNoDB                                                         = 1046\n\tErrUnknownCom                                                   = 1047\n\tErrBadNull                                                      = 1048\n\tErrBadDB                                                        = 1049\n\tErrTableExists                                                  = 1050\n\tErrBadTable                                                     = 1051\n\tErrNonUniq                                                      = 1052\n\tErrServerShutdown                                               = 1053\n\tErrBadField                                                     = 1054\n\tErrFieldNotInGroupBy                                            = 1055\n\tErrWrongGroupField                                              = 1056\n\tErrWrongSumSelect                                               = 1057\n\tErrWrongValueCount                                              = 1058\n\tErrTooLongIdent                                                 = 1059\n\tErrDupFieldName                                                 = 1060\n\tErrDupKeyName                                                   = 1061\n\tErrDupEntry                                                     = 1062\n\tErrWrongFieldSpec                                               = 1063\n\tErrParse                                                        = 1064\n\tErrEmptyQuery                                                   = 1065\n\tErrNonuniqTable                                                 = 1066\n\tErrInvalidDefault                                               = 1067\n\tErrMultiplePriKey                                               = 1068\n\tErrTooManyKeys                                                  = 1069\n\tErrTooManyKeyParts                                              = 1070\n\tErrTooLongKey                                                   = 1071\n\tErrKeyColumnDoesNotExits                                        = 1072\n\tErrBlobUsedAsKey                                                = 1073\n\tErrTooBigFieldlength                                            = 1074\n\tErrWrongAutoKey                                                 = 1075\n\tErrReady                                                        = 1076\n\tErrNormalShutdown                                               = 1077\n\tErrGotSignal                                                    = 1078\n\tErrShutdownComplete                                             = 1079\n\tErrForcingClose                                                 = 1080\n\tErrIpsock                                                       = 1081\n\tErrNoSuchIndex                                                  = 1082\n\tErrWrongFieldTerminators                                        = 1083\n\tErrBlobsAndNoTerminated                                         = 1084\n\tErrTextFileNotReadable                                          = 1085\n\tErrFileExists                                                   = 1086\n\tErrLoadInfo                                                     = 1087\n\tErrAlterInfo                                                    = 1088\n\tErrWrongSubKey                                                  = 1089\n\tErrCantRemoveAllFields                                          = 1090\n\tErrCantDropFieldOrKey                                           = 1091\n\tErrInsertInfo                                                   = 1092\n\tErrUpdateTableUsed                                              = 1093\n\tErrNoSuchThread                                                 = 1094\n\tErrKillDenied                                                   = 1095\n\tErrNoTablesUsed                                                 = 1096\n\tErrTooBigSet                                                    = 1097\n\tErrNoUniqueLogFile                                              = 1098\n\tErrTableNotLockedForWrite                                       = 1099\n\tErrTableNotLocked                                               = 1100\n\tErrBlobCantHaveDefault                                          = 1101\n\tErrWrongDBName                                                  = 1102\n\tErrWrongTableName                                               = 1103\n\tErrTooBigSelect                                                 = 1104\n\tErrUnknown                                                      = 1105\n\tErrUnknownProcedure                                             = 1106\n\tErrWrongParamcountToProcedure                                   = 1107\n\tErrWrongParametersToProcedure                                   = 1108\n\tErrUnknownTable                                                 = 1109\n\tErrFieldSpecifiedTwice                                          = 1110\n\tErrInvalidGroupFuncUse                                          = 1111\n\tErrUnsupportedExtension                                         = 1112\n\tErrTableMustHaveColumns                                         = 1113\n\tErrRecordFileFull                                               = 1114\n\tErrUnknownCharacterSet                                          = 1115\n\tErrTooManyTables                                                = 1116\n\tErrTooManyFields                                                = 1117\n\tErrTooBigRowsize                                                = 1118\n\tErrStackOverrun                                                 = 1119\n\tErrWrongOuterJoin                                               = 1120\n\tErrNullColumnInIndex                                            = 1121\n\tErrCantFindUdf                                                  = 1122\n\tErrCantInitializeUdf                                            = 1123\n\tErrUdfNoPaths                                                   = 1124\n\tErrUdfExists                                                    = 1125\n\tErrCantOpenLibrary                                              = 1126\n\tErrCantFindDlEntry                                              = 1127\n\tErrFunctionNotDefined                                           = 1128\n\tErrHostIsBlocked                                                = 1129\n\tErrHostNotPrivileged                                            = 1130\n\tErrPasswordAnonymousUser                                        = 1131\n\tErrPasswordNotAllowed                                           = 1132\n\tErrPasswordNoMatch                                              = 1133\n\tErrUpdateInfo                                                   = 1134\n\tErrCantCreateThread                                             = 1135\n\tErrWrongValueCountOnRow                                         = 1136\n\tErrCantReopenTable                                              = 1137\n\tErrInvalidUseOfNull                                             = 1138\n\tErrRegexp                                                       = 1139\n\tErrMixOfGroupFuncAndFields                                      = 1140\n\tErrNonexistingGrant                                             = 1141\n\tErrTableaccessDenied                                            = 1142\n\tErrColumnaccessDenied                                           = 1143\n\tErrIllegalGrantForTable                                         = 1144\n\tErrGrantWrongHostOrUser                                         = 1145\n\tErrNoSuchTable                                                  = 1146\n\tErrNonexistingTableGrant                                        = 1147\n\tErrNotAllowedCommand                                            = 1148\n\tErrSyntax                                                       = 1149\n\tErrDelayedCantChangeLock                                        = 1150\n\tErrTooManyDelayedThreads                                        = 1151\n\tErrAbortingConnection                                           = 1152\n\tErrNetPacketTooLarge                                            = 1153\n\tErrNetReadErrorFromPipe                                         = 1154\n\tErrNetFcntl                                                     = 1155\n\tErrNetPacketsOutOfOrder                                         = 1156\n\tErrNetUncompress                                                = 1157\n\tErrNetRead                                                      = 1158\n\tErrNetReadInterrupted                                           = 1159\n\tErrNetErrorOnWrite                                              = 1160\n\tErrNetWriteInterrupted                                          = 1161\n\tErrTooLongString                                                = 1162\n\tErrTableCantHandleBlob                                          = 1163\n\tErrTableCantHandleAutoIncrement                                 = 1164\n\tErrDelayedInsertTableLocked                                     = 1165\n\tErrWrongColumnName                                              = 1166\n\tErrWrongKeyColumn                                               = 1167\n\tErrWrongMrgTable                                                = 1168\n\tErrDupUnique                                                    = 1169\n\tErrBlobKeyWithoutLength                                         = 1170\n\tErrPrimaryCantHaveNull                                          = 1171\n\tErrTooManyRows                                                  = 1172\n\tErrRequiresPrimaryKey                                           = 1173\n\tErrNoRaidCompiled                                               = 1174\n\tErrUpdateWithoutKeyInSafeMode                                   = 1175\n\tErrKeyDoesNotExist                                              = 1176\n\tErrCheckNoSuchTable                                             = 1177\n\tErrCheckNotImplemented                                          = 1178\n\tErrCantDoThisDuringAnTransaction                                = 1179\n\tErrErrorDuringCommit                                            = 1180\n\tErrErrorDuringRollback                                          = 1181\n\tErrErrorDuringFlushLogs                                         = 1182\n\tErrErrorDuringCheckpoint                                        = 1183\n\tErrNewAbortingConnection                                        = 1184\n\tErrDumpNotImplemented                                           = 1185\n\tErrFlushMasterBinlogClosed                                      = 1186\n\tErrIndexRebuild                                                 = 1187\n\tErrMaster                                                       = 1188\n\tErrMasterNetRead                                                = 1189\n\tErrMasterNetWrite                                               = 1190\n\tErrFtMatchingKeyNotFound                                        = 1191\n\tErrLockOrActiveTransaction                                      = 1192\n\tErrUnknownSystemVariable                                        = 1193\n\tErrCrashedOnUsage                                               = 1194\n\tErrCrashedOnRepair                                              = 1195\n\tErrWarningNotCompleteRollback                                   = 1196\n\tErrTransCacheFull                                               = 1197\n\tErrSlaveMustStop                                                = 1198\n\tErrSlaveNotRunning                                              = 1199\n\tErrBadSlave                                                     = 1200\n\tErrMasterInfo                                                   = 1201\n\tErrSlaveThread                                                  = 1202\n\tErrTooManyUserConnections                                       = 1203\n\tErrSetConstantsOnly                                             = 1204\n\tErrLockWaitTimeout                                              = 1205\n\tErrLockTableFull                                                = 1206\n\tErrReadOnlyTransaction                                          = 1207\n\tErrDropDBWithReadLock                                           = 1208\n\tErrCreateDBWithReadLock                                         = 1209\n\tErrWrongArguments                                               = 1210\n\tErrNoPermissionToCreateUser                                     = 1211\n\tErrUnionTablesInDifferentDir                                    = 1212\n\tErrLockDeadlock                                                 = 1213\n\tErrTableCantHandleFt                                            = 1214\n\tErrCannotAddForeign                                             = 1215\n\tErrNoReferencedRow                                              = 1216\n\tErrRowIsReferenced                                              = 1217\n\tErrConnectToMaster                                              = 1218\n\tErrQueryOnMaster                                                = 1219\n\tErrErrorWhenExecutingCommand                                    = 1220\n\tErrWrongUsage                                                   = 1221\n\tErrWrongNumberOfColumnsInSelect                                 = 1222\n\tErrCantUpdateWithReadlock                                       = 1223\n\tErrMixingNotAllowed                                             = 1224\n\tErrDupArgument                                                  = 1225\n\tErrUserLimitReached                                             = 1226\n\tErrSpecificAccessDenied                                         = 1227\n\tErrLocalVariable                                                = 1228\n\tErrGlobalVariable                                               = 1229\n\tErrNoDefault                                                    = 1230\n\tErrWrongValueForVar                                             = 1231\n\tErrWrongTypeForVar                                              = 1232\n\tErrVarCantBeRead                                                = 1233\n\tErrCantUseOptionHere                                            = 1234\n\tErrNotSupportedYet                                              = 1235\n\tErrMasterFatalErrorReadingBinlog                                = 1236\n\tErrSlaveIgnoredTable                                            = 1237\n\tErrIncorrectGlobalLocalVar                                      = 1238\n\tErrWrongFkDef                                                   = 1239\n\tErrKeyRefDoNotMatchTableRef                                     = 1240\n\tErrOperandColumns                                               = 1241\n\tErrSubqueryNo1Row                                               = 1242\n\tErrUnknownStmtHandler                                           = 1243\n\tErrCorruptHelpDB                                                = 1244\n\tErrCyclicReference                                              = 1245\n\tErrAutoConvert                                                  = 1246\n\tErrIllegalReference                                             = 1247\n\tErrDerivedMustHaveAlias                                         = 1248\n\tErrSelectReduced                                                = 1249\n\tErrTablenameNotAllowedHere                                      = 1250\n\tErrNotSupportedAuthMode                                         = 1251\n\tErrSpatialCantHaveNull                                          = 1252\n\tErrCollationCharsetMismatch                                     = 1253\n\tErrSlaveWasRunning                                              = 1254\n\tErrSlaveWasNotRunning                                           = 1255\n\tErrTooBigForUncompress                                          = 1256\n\tErrZlibZMem                                                     = 1257\n\tErrZlibZBuf                                                     = 1258\n\tErrZlibZData                                                    = 1259\n\tErrCutValueGroupConcat                                          = 1260\n\tErrWarnTooFewRecords                                            = 1261\n\tErrWarnTooManyRecords                                           = 1262\n\tErrWarnNullToNotnull                                            = 1263\n\tErrWarnDataOutOfRange                                           = 1264\n\tWarnDataTruncated                                               = 1265\n\tErrWarnUsingOtherHandler                                        = 1266\n\tErrCantAggregate2collations                                     = 1267\n\tErrDropUser                                                     = 1268\n\tErrRevokeGrants                                                 = 1269\n\tErrCantAggregate3collations                                     = 1270\n\tErrCantAggregateNcollations                                     = 1271\n\tErrVariableIsNotStruct                                          = 1272\n\tErrUnknownCollation                                             = 1273\n\tErrSlaveIgnoredSslParams                                        = 1274\n\tErrServerIsInSecureAuthMode                                     = 1275\n\tErrWarnFieldResolved                                            = 1276\n\tErrBadSlaveUntilCond                                            = 1277\n\tErrMissingSkipSlave                                             = 1278\n\tErrUntilCondIgnored                                             = 1279\n\tErrWrongNameForIndex                                            = 1280\n\tErrWrongNameForCatalog                                          = 1281\n\tErrWarnQcResize                                                 = 1282\n\tErrBadFtColumn                                                  = 1283\n\tErrUnknownKeyCache                                              = 1284\n\tErrWarnHostnameWontWork                                         = 1285\n\tErrUnknownStorageEngine                                         = 1286\n\tErrWarnDeprecatedSyntax                                         = 1287\n\tErrNonUpdatableTable                                            = 1288\n\tErrFeatureDisabled                                              = 1289\n\tErrOptionPreventsStatement                                      = 1290\n\tErrDuplicatedValueInType                                        = 1291\n\tErrTruncatedWrongValue                                          = 1292\n\tErrTooMuchAutoTimestampCols                                     = 1293\n\tErrInvalidOnUpdate                                              = 1294\n\tErrUnsupportedPs                                                = 1295\n\tErrGetErrmsg                                                    = 1296\n\tErrGetTemporaryErrmsg                                           = 1297\n\tErrUnknownTimeZone                                              = 1298\n\tErrWarnInvalidTimestamp                                         = 1299\n\tErrInvalidCharacterString                                       = 1300\n\tErrWarnAllowedPacketOverflowed                                  = 1301\n\tErrConflictingDeclarations                                      = 1302\n\tErrSpNoRecursiveCreate                                          = 1303\n\tErrSpAlreadyExists                                              = 1304\n\tErrSpDoesNotExist                                               = 1305\n\tErrSpDropFailed                                                 = 1306\n\tErrSpStoreFailed                                                = 1307\n\tErrSpLilabelMismatch                                            = 1308\n\tErrSpLabelRedefine                                              = 1309\n\tErrSpLabelMismatch                                              = 1310\n\tErrSpUninitVar                                                  = 1311\n\tErrSpBadselect                                                  = 1312\n\tErrSpBadreturn                                                  = 1313\n\tErrSpBadstatement                                               = 1314\n\tErrUpdateLogDeprecatedIgnored                                   = 1315\n\tErrUpdateLogDeprecatedTranslated                                = 1316\n\tErrQueryInterrupted                                             = 1317\n\tErrSpWrongNoOfArgs                                              = 1318\n\tErrSpCondMismatch                                               = 1319\n\tErrSpNoreturn                                                   = 1320\n\tErrSpNoreturnend                                                = 1321\n\tErrSpBadCursorQuery                                             = 1322\n\tErrSpBadCursorSelect                                            = 1323\n\tErrSpCursorMismatch                                             = 1324\n\tErrSpCursorAlreadyOpen                                          = 1325\n\tErrSpCursorNotOpen                                              = 1326\n\tErrSpUndeclaredVar                                              = 1327\n\tErrSpWrongNoOfFetchArgs                                         = 1328\n\tErrSpFetchNoData                                                = 1329\n\tErrSpDupParam                                                   = 1330\n\tErrSpDupVar                                                     = 1331\n\tErrSpDupCond                                                    = 1332\n\tErrSpDupCurs                                                    = 1333\n\tErrSpCantAlter                                                  = 1334\n\tErrSpSubselectNyi                                               = 1335\n\tErrStmtNotAllowedInSfOrTrg                                      = 1336\n\tErrSpVarcondAfterCurshndlr                                      = 1337\n\tErrSpCursorAfterHandler                                         = 1338\n\tErrSpCaseNotFound                                               = 1339\n\tErrFparserTooBigFile                                            = 1340\n\tErrFparserBadHeader                                             = 1341\n\tErrFparserEOFInComment                                          = 1342\n\tErrFparserErrorInParameter                                      = 1343\n\tErrFparserEOFInUnknownParameter                                 = 1344\n\tErrViewNoExplain                                                = 1345\n\tErrFrmUnknownType                                               = 1346\n\tErrWrongObject                                                  = 1347\n\tErrNonupdateableColumn                                          = 1348\n\tErrViewSelectDerived                                            = 1349\n\tErrViewSelectClause                                             = 1350\n\tErrViewSelectVariable                                           = 1351\n\tErrViewSelectTmptable                                           = 1352\n\tErrViewWrongList                                                = 1353\n\tErrWarnViewMerge                                                = 1354\n\tErrWarnViewWithoutKey                                           = 1355\n\tErrViewInvalid                                                  = 1356\n\tErrSpNoDropSp                                                   = 1357\n\tErrSpGotoInHndlr                                                = 1358\n\tErrTrgAlreadyExists                                             = 1359\n\tErrTrgDoesNotExist                                              = 1360\n\tErrTrgOnViewOrTempTable                                         = 1361\n\tErrTrgCantChangeRow                                             = 1362\n\tErrTrgNoSuchRowInTrg                                            = 1363\n\tErrNoDefaultForField                                            = 1364\n\tErrDivisionByZero                                               = 1365\n\tErrTruncatedWrongValueForField                                  = 1366\n\tErrIllegalValueForType                                          = 1367\n\tErrViewNonupdCheck                                              = 1368\n\tErrViewCheckFailed                                              = 1369\n\tErrProcaccessDenied                                             = 1370\n\tErrRelayLogFail                                                 = 1371\n\tErrPasswdLength                                                 = 1372\n\tErrUnknownTargetBinlog                                          = 1373\n\tErrIoErrLogIndexRead                                            = 1374\n\tErrBinlogPurgeProhibited                                        = 1375\n\tErrFseekFail                                                    = 1376\n\tErrBinlogPurgeFatalErr                                          = 1377\n\tErrLogInUse                                                     = 1378\n\tErrLogPurgeUnknownErr                                           = 1379\n\tErrRelayLogInit                                                 = 1380\n\tErrNoBinaryLogging                                              = 1381\n\tErrReservedSyntax                                               = 1382\n\tErrWsasFailed                                                   = 1383\n\tErrDiffGroupsProc                                               = 1384\n\tErrNoGroupForProc                                               = 1385\n\tErrOrderWithProc                                                = 1386\n\tErrLoggingProhibitChangingOf                                    = 1387\n\tErrNoFileMapping                                                = 1388\n\tErrWrongMagic                                                   = 1389\n\tErrPsManyParam                                                  = 1390\n\tErrKeyPart0                                                     = 1391\n\tErrViewChecksum                                                 = 1392\n\tErrViewMultiupdate                                              = 1393\n\tErrViewNoInsertFieldList                                        = 1394\n\tErrViewDeleteMergeView                                          = 1395\n\tErrCannotUser                                                   = 1396\n\tErrXaerNota                                                     = 1397\n\tErrXaerInval                                                    = 1398\n\tErrXaerRmfail                                                   = 1399\n\tErrXaerOutside                                                  = 1400\n\tErrXaerRmerr                                                    = 1401\n\tErrXaRbrollback                                                 = 1402\n\tErrNonexistingProcGrant                                         = 1403\n\tErrProcAutoGrantFail                                            = 1404\n\tErrProcAutoRevokeFail                                           = 1405\n\tErrDataTooLong                                                  = 1406\n\tErrSpBadSQLstate                                                = 1407\n\tErrStartup                                                      = 1408\n\tErrLoadFromFixedSizeRowsToVar                                   = 1409\n\tErrCantCreateUserWithGrant                                      = 1410\n\tErrWrongValueForType                                            = 1411\n\tErrTableDefChanged                                              = 1412\n\tErrSpDupHandler                                                 = 1413\n\tErrSpNotVarArg                                                  = 1414\n\tErrSpNoRetset                                                   = 1415\n\tErrCantCreateGeometryObject                                     = 1416\n\tErrFailedRoutineBreakBinlog                                     = 1417\n\tErrBinlogUnsafeRoutine                                          = 1418\n\tErrBinlogCreateRoutineNeedSuper                                 = 1419\n\tErrExecStmtWithOpenCursor                                       = 1420\n\tErrStmtHasNoOpenCursor                                          = 1421\n\tErrCommitNotAllowedInSfOrTrg                                    = 1422\n\tErrNoDefaultForViewField                                        = 1423\n\tErrSpNoRecursion                                                = 1424\n\tErrTooBigScale                                                  = 1425\n\tErrTooBigPrecision                                              = 1426\n\tErrMBiggerThanD                                                 = 1427\n\tErrWrongLockOfSystemTable                                       = 1428\n\tErrConnectToForeignDataSource                                   = 1429\n\tErrQueryOnForeignDataSource                                     = 1430\n\tErrForeignDataSourceDoesntExist                                 = 1431\n\tErrForeignDataStringInvalidCantCreate                           = 1432\n\tErrForeignDataStringInvalid                                     = 1433\n\tErrCantCreateFederatedTable                                     = 1434\n\tErrTrgInWrongSchema                                             = 1435\n\tErrStackOverrunNeedMore                                         = 1436\n\tErrTooLongBody                                                  = 1437\n\tErrWarnCantDropDefaultKeycache                                  = 1438\n\tErrTooBigDisplaywidth                                           = 1439\n\tErrXaerDupid                                                    = 1440\n\tErrDatetimeFunctionOverflow                                     = 1441\n\tErrCantUpdateUsedTableInSfOrTrg                                 = 1442\n\tErrViewPreventUpdate                                            = 1443\n\tErrPsNoRecursion                                                = 1444\n\tErrSpCantSetAutocommit                                          = 1445\n\tErrMalformedDefiner                                             = 1446\n\tErrViewFrmNoUser                                                = 1447\n\tErrViewOtherUser                                                = 1448\n\tErrNoSuchUser                                                   = 1449\n\tErrForbidSchemaChange                                           = 1450\n\tErrRowIsReferenced2                                             = 1451\n\tErrNoReferencedRow2                                             = 1452\n\tErrSpBadVarShadow                                               = 1453\n\tErrTrgNoDefiner                                                 = 1454\n\tErrOldFileFormat                                                = 1455\n\tErrSpRecursionLimit                                             = 1456\n\tErrSpProcTableCorrupt                                           = 1457\n\tErrSpWrongName                                                  = 1458\n\tErrTableNeedsUpgrade                                            = 1459\n\tErrSpNoAggregate                                                = 1460\n\tErrMaxPreparedStmtCountReached                                  = 1461\n\tErrViewRecursive                                                = 1462\n\tErrNonGroupingFieldUsed                                         = 1463\n\tErrTableCantHandleSpkeys                                        = 1464\n\tErrNoTriggersOnSystemSchema                                     = 1465\n\tErrRemovedSpaces                                                = 1466\n\tErrAutoincReadFailed                                            = 1467\n\tErrUsername                                                     = 1468\n\tErrHostname                                                     = 1469\n\tErrWrongStringLength                                            = 1470\n\tErrNonInsertableTable                                           = 1471\n\tErrAdminWrongMrgTable                                           = 1472\n\tErrTooHighLevelOfNestingForSelect                               = 1473\n\tErrNameBecomesEmpty                                             = 1474\n\tErrAmbiguousFieldTerm                                           = 1475\n\tErrForeignServerExists                                          = 1476\n\tErrForeignServerDoesntExist                                     = 1477\n\tErrIllegalHaCreateOption                                        = 1478\n\tErrPartitionRequiresValues                                      = 1479\n\tErrPartitionWrongValues                                         = 1480\n\tErrPartitionMaxvalue                                            = 1481\n\tErrPartitionSubpartition                                        = 1482\n\tErrPartitionSubpartMix                                          = 1483\n\tErrPartitionWrongNoPart                                         = 1484\n\tErrPartitionWrongNoSubpart                                      = 1485\n\tErrWrongExprInPartitionFunc                                     = 1486\n\tErrNoConstExprInRangeOrList                                     = 1487\n\tErrFieldNotFoundPart                                            = 1488\n\tErrListOfFieldsOnlyInHash                                       = 1489\n\tErrInconsistentPartitionInfo                                    = 1490\n\tErrPartitionFuncNotAllowed                                      = 1491\n\tErrPartitionsMustBeDefined                                      = 1492\n\tErrRangeNotIncreasing                                           = 1493\n\tErrInconsistentTypeOfFunctions                                  = 1494\n\tErrMultipleDefConstInListPart                                   = 1495\n\tErrPartitionEntry                                               = 1496\n\tErrMixHandler                                                   = 1497\n\tErrPartitionNotDefined                                          = 1498\n\tErrTooManyPartitions                                            = 1499\n\tErrSubpartition                                                 = 1500\n\tErrCantCreateHandlerFile                                        = 1501\n\tErrBlobFieldInPartFunc                                          = 1502\n\tErrUniqueKeyNeedAllFieldsInPf                                   = 1503\n\tErrNoParts                                                      = 1504\n\tErrPartitionMgmtOnNonpartitioned                                = 1505\n\tErrForeignKeyOnPartitioned                                      = 1506\n\tErrDropPartitionNonExistent                                     = 1507\n\tErrDropLastPartition                                            = 1508\n\tErrCoalesceOnlyOnHashPartition                                  = 1509\n\tErrReorgHashOnlyOnSameNo                                        = 1510\n\tErrReorgNoParam                                                 = 1511\n\tErrOnlyOnRangeListPartition                                     = 1512\n\tErrAddPartitionSubpart                                          = 1513\n\tErrAddPartitionNoNewPartition                                   = 1514\n\tErrCoalescePartitionNoPartition                                 = 1515\n\tErrReorgPartitionNotExist                                       = 1516\n\tErrSameNamePartition                                            = 1517\n\tErrNoBinlog                                                     = 1518\n\tErrConsecutiveReorgPartitions                                   = 1519\n\tErrReorgOutsideRange                                            = 1520\n\tErrPartitionFunctionFailure                                     = 1521\n\tErrPartState                                                    = 1522\n\tErrLimitedPartRange                                             = 1523\n\tErrPluginIsNotLoaded                                            = 1524\n\tErrWrongValue                                                   = 1525\n\tErrNoPartitionForGivenValue                                     = 1526\n\tErrFilegroupOptionOnlyOnce                                      = 1527\n\tErrCreateFilegroupFailed                                        = 1528\n\tErrDropFilegroupFailed                                          = 1529\n\tErrTablespaceAutoExtend                                         = 1530\n\tErrWrongSizeNumber                                              = 1531\n\tErrSizeOverflow                                                 = 1532\n\tErrAlterFilegroupFailed                                         = 1533\n\tErrBinlogRowLoggingFailed                                       = 1534\n\tErrBinlogRowWrongTableDef                                       = 1535\n\tErrBinlogRowRbrToSbr                                            = 1536\n\tErrEventAlreadyExists                                           = 1537\n\tErrEventStoreFailed                                             = 1538\n\tErrEventDoesNotExist                                            = 1539\n\tErrEventCantAlter                                               = 1540\n\tErrEventDropFailed                                              = 1541\n\tErrEventIntervalNotPositiveOrTooBig                             = 1542\n\tErrEventEndsBeforeStarts                                        = 1543\n\tErrEventExecTimeInThePast                                       = 1544\n\tErrEventOpenTableFailed                                         = 1545\n\tErrEventNeitherMExprNorMAt                                      = 1546\n\tErrObsoleteColCountDoesntMatchCorrupted                         = 1547\n\tErrObsoleteCannotLoadFromTable                                  = 1548\n\tErrEventCannotDelete                                            = 1549\n\tErrEventCompile                                                 = 1550\n\tErrEventSameName                                                = 1551\n\tErrEventDataTooLong                                             = 1552\n\tErrDropIndexFk                                                  = 1553\n\tErrWarnDeprecatedSyntaxWithVer                                  = 1554\n\tErrCantWriteLockLogTable                                        = 1555\n\tErrCantLockLogTable                                             = 1556\n\tErrForeignDuplicateKeyOldUnused                                 = 1557\n\tErrColCountDoesntMatchPleaseUpdate                              = 1558\n\tErrTempTablePreventsSwitchOutOfRbr                              = 1559\n\tErrStoredFunctionPreventsSwitchBinlogFormat                     = 1560\n\tErrNdbCantSwitchBinlogFormat                                    = 1561\n\tErrPartitionNoTemporary                                         = 1562\n\tErrPartitionConstDomain                                         = 1563\n\tErrPartitionFunctionIsNotAllowed                                = 1564\n\tErrDdlLog                                                       = 1565\n\tErrNullInValuesLessThan                                         = 1566\n\tErrWrongPartitionName                                           = 1567\n\tErrCantChangeTxCharacteristics                                  = 1568\n\tErrDupEntryAutoincrementCase                                    = 1569\n\tErrEventModifyQueue                                             = 1570\n\tErrEventSetVar                                                  = 1571\n\tErrPartitionMerge                                               = 1572\n\tErrCantActivateLog                                              = 1573\n\tErrRbrNotAvailable                                              = 1574\n\tErrBase64Decode                                                 = 1575\n\tErrEventRecursionForbidden                                      = 1576\n\tErrEventsDB                                                     = 1577\n\tErrOnlyIntegersAllowed                                          = 1578\n\tErrUnsuportedLogEngine                                          = 1579\n\tErrBadLogStatement                                              = 1580\n\tErrCantRenameLogTable                                           = 1581\n\tErrWrongParamcountToNativeFct                                   = 1582\n\tErrWrongParametersToNativeFct                                   = 1583\n\tErrWrongParametersToStoredFct                                   = 1584\n\tErrNativeFctNameCollision                                       = 1585\n\tErrDupEntryWithKeyName                                          = 1586\n\tErrBinlogPurgeEmFile                                            = 1587\n\tErrEventCannotCreateInThePast                                   = 1588\n\tErrEventCannotAlterInThePast                                    = 1589\n\tErrSlaveIncident                                                = 1590\n\tErrNoPartitionForGivenValueSilent                               = 1591\n\tErrBinlogUnsafeStatement                                        = 1592\n\tErrSlaveFatal                                                   = 1593\n\tErrSlaveRelayLogReadFailure                                     = 1594\n\tErrSlaveRelayLogWriteFailure                                    = 1595\n\tErrSlaveCreateEventFailure                                      = 1596\n\tErrSlaveMasterComFailure                                        = 1597\n\tErrBinlogLoggingImpossible                                      = 1598\n\tErrViewNoCreationCtx                                            = 1599\n\tErrViewInvalidCreationCtx                                       = 1600\n\tErrSrInvalidCreationCtx                                         = 1601\n\tErrTrgCorruptedFile                                             = 1602\n\tErrTrgNoCreationCtx                                             = 1603\n\tErrTrgInvalidCreationCtx                                        = 1604\n\tErrEventInvalidCreationCtx                                      = 1605\n\tErrTrgCantOpenTable                                             = 1606\n\tErrCantCreateSroutine                                           = 1607\n\tErrNeverUsed                                                    = 1608\n\tErrNoFormatDescriptionEventBeforeBinlogStatement                = 1609\n\tErrSlaveCorruptEvent                                            = 1610\n\tErrLoadDataInvalidColumn                                        = 1611\n\tErrLogPurgeNoFile                                               = 1612\n\tErrXaRbtimeout                                                  = 1613\n\tErrXaRbdeadlock                                                 = 1614\n\tErrNeedReprepare                                                = 1615\n\tErrDelayedNotSupported                                          = 1616\n\tWarnNoMasterInfo                                                = 1617\n\tWarnOptionIgnored                                               = 1618\n\tWarnPluginDeleteBuiltin                                         = 1619\n\tWarnPluginBusy                                                  = 1620\n\tErrVariableIsReadonly                                           = 1621\n\tErrWarnEngineTransactionRollback                                = 1622\n\tErrSlaveHeartbeatFailure                                        = 1623\n\tErrSlaveHeartbeatValueOutOfRange                                = 1624\n\tErrNdbReplicationSchema                                         = 1625\n\tErrConflictFnParse                                              = 1626\n\tErrExceptionsWrite                                              = 1627\n\tErrTooLongTableComment                                          = 1628\n\tErrTooLongFieldComment                                          = 1629\n\tErrFuncInexistentNameCollision                                  = 1630\n\tErrDatabaseName                                                 = 1631\n\tErrTableName                                                    = 1632\n\tErrPartitionName                                                = 1633\n\tErrSubpartitionName                                             = 1634\n\tErrTemporaryName                                                = 1635\n\tErrRenamedName                                                  = 1636\n\tErrTooManyConcurrentTrxs                                        = 1637\n\tWarnNonASCIISeparatorNotImplemented                             = 1638\n\tErrDebugSyncTimeout                                             = 1639\n\tErrDebugSyncHitLimit                                            = 1640\n\tErrDupSignalSet                                                 = 1641\n\tErrSignalWarn                                                   = 1642\n\tErrSignalNotFound                                               = 1643\n\tErrSignalException                                              = 1644\n\tErrResignalWithoutActiveHandler                                 = 1645\n\tErrSignalBadConditionType                                       = 1646\n\tWarnCondItemTruncated                                           = 1647\n\tErrCondItemTooLong                                              = 1648\n\tErrUnknownLocale                                                = 1649\n\tErrSlaveIgnoreServerIds                                         = 1650\n\tErrQueryCacheDisabled                                           = 1651\n\tErrSameNamePartitionField                                       = 1652\n\tErrPartitionColumnList                                          = 1653\n\tErrWrongTypeColumnValue                                         = 1654\n\tErrTooManyPartitionFuncFields                                   = 1655\n\tErrMaxvalueInValuesIn                                           = 1656\n\tErrTooManyValues                                                = 1657\n\tErrRowSinglePartitionField                                      = 1658\n\tErrFieldTypeNotAllowedAsPartitionField                          = 1659\n\tErrPartitionFieldsTooLong                                       = 1660\n\tErrBinlogRowEngineAndStmtEngine                                 = 1661\n\tErrBinlogRowModeAndStmtEngine                                   = 1662\n\tErrBinlogUnsafeAndStmtEngine                                    = 1663\n\tErrBinlogRowInjectionAndStmtEngine                              = 1664\n\tErrBinlogStmtModeAndRowEngine                                   = 1665\n\tErrBinlogRowInjectionAndStmtMode                                = 1666\n\tErrBinlogMultipleEnginesAndSelfLoggingEngine                    = 1667\n\tErrBinlogUnsafeLimit                                            = 1668\n\tErrBinlogUnsafeInsertDelayed                                    = 1669\n\tErrBinlogUnsafeSystemTable                                      = 1670\n\tErrBinlogUnsafeAutoincColumns                                   = 1671\n\tErrBinlogUnsafeUdf                                              = 1672\n\tErrBinlogUnsafeSystemVariable                                   = 1673\n\tErrBinlogUnsafeSystemFunction                                   = 1674\n\tErrBinlogUnsafeNontransAfterTrans                               = 1675\n\tErrMessageAndStatement                                          = 1676\n\tErrSlaveConversionFailed                                        = 1677\n\tErrSlaveCantCreateConversion                                    = 1678\n\tErrInsideTransactionPreventsSwitchBinlogFormat                  = 1679\n\tErrPathLength                                                   = 1680\n\tErrWarnDeprecatedSyntaxNoReplacement                            = 1681\n\tErrWrongNativeTableStructure                                    = 1682\n\tErrWrongPerfSchemaUsage                                         = 1683\n\tErrWarnISSkippedTable                                           = 1684\n\tErrInsideTransactionPreventsSwitchBinlogDirect                  = 1685\n\tErrStoredFunctionPreventsSwitchBinlogDirect                     = 1686\n\tErrSpatialMustHaveGeomCol                                       = 1687\n\tErrTooLongIndexComment                                          = 1688\n\tErrLockAborted                                                  = 1689\n\tErrDataOutOfRange                                               = 1690\n\tErrWrongSpvarTypeInLimit                                        = 1691\n\tErrBinlogUnsafeMultipleEnginesAndSelfLoggingEngine              = 1692\n\tErrBinlogUnsafeMixedStatement                                   = 1693\n\tErrInsideTransactionPreventsSwitchSQLLogBin                     = 1694\n\tErrStoredFunctionPreventsSwitchSQLLogBin                        = 1695\n\tErrFailedReadFromParFile                                        = 1696\n\tErrValuesIsNotIntType                                           = 1697\n\tErrAccessDeniedNoPassword                                       = 1698\n\tErrSetPasswordAuthPlugin                                        = 1699\n\tErrGrantPluginUserExists                                        = 1700\n\tErrTruncateIllegalFk                                            = 1701\n\tErrPluginIsPermanent                                            = 1702\n\tErrSlaveHeartbeatValueOutOfRangeMin                             = 1703\n\tErrSlaveHeartbeatValueOutOfRangeMax                             = 1704\n\tErrStmtCacheFull                                                = 1705\n\tErrMultiUpdateKeyConflict                                       = 1706\n\tErrTableNeedsRebuild                                            = 1707\n\tWarnOptionBelowLimit                                            = 1708\n\tErrIndexColumnTooLong                                           = 1709\n\tErrErrorInTriggerBody                                           = 1710\n\tErrErrorInUnknownTriggerBody                                    = 1711\n\tErrIndexCorrupt                                                 = 1712\n\tErrUndoRecordTooBig                                             = 1713\n\tErrBinlogUnsafeInsertIgnoreSelect                               = 1714\n\tErrBinlogUnsafeInsertSelectUpdate                               = 1715\n\tErrBinlogUnsafeReplaceSelect                                    = 1716\n\tErrBinlogUnsafeCreateIgnoreSelect                               = 1717\n\tErrBinlogUnsafeCreateReplaceSelect                              = 1718\n\tErrBinlogUnsafeUpdateIgnore                                     = 1719\n\tErrPluginNoUninstall                                            = 1720\n\tErrPluginNoInstall                                              = 1721\n\tErrBinlogUnsafeWriteAutoincSelect                               = 1722\n\tErrBinlogUnsafeCreateSelectAutoinc                              = 1723\n\tErrBinlogUnsafeInsertTwoKeys                                    = 1724\n\tErrTableInFkCheck                                               = 1725\n\tErrUnsupportedEngine                                            = 1726\n\tErrBinlogUnsafeAutoincNotFirst                                  = 1727\n\tErrCannotLoadFromTableV2                                        = 1728\n\tErrMasterDelayValueOutOfRange                                   = 1729\n\tErrOnlyFdAndRbrEventsAllowedInBinlogStatement                   = 1730\n\tErrPartitionExchangeDifferentOption                             = 1731\n\tErrPartitionExchangePartTable                                   = 1732\n\tErrPartitionExchangeTempTable                                   = 1733\n\tErrPartitionInsteadOfSubpartition                               = 1734\n\tErrUnknownPartition                                             = 1735\n\tErrTablesDifferentMetadata                                      = 1736\n\tErrRowDoesNotMatchPartition                                     = 1737\n\tErrBinlogCacheSizeGreaterThanMax                                = 1738\n\tErrWarnIndexNotApplicable                                       = 1739\n\tErrPartitionExchangeForeignKey                                  = 1740\n\tErrNoSuchKeyValue                                               = 1741\n\tErrRplInfoDataTooLong                                           = 1742\n\tErrNetworkReadEventChecksumFailure                              = 1743\n\tErrBinlogReadEventChecksumFailure                               = 1744\n\tErrBinlogStmtCacheSizeGreaterThanMax                            = 1745\n\tErrCantUpdateTableInCreateTableSelect                           = 1746\n\tErrPartitionClauseOnNonpartitioned                              = 1747\n\tErrRowDoesNotMatchGivenPartitionSet                             = 1748\n\tErrNoSuchPartitionunused                                        = 1749\n\tErrChangeRplInfoRepositoryFailure                               = 1750\n\tErrWarningNotCompleteRollbackWithCreatedTempTable               = 1751\n\tErrWarningNotCompleteRollbackWithDroppedTempTable               = 1752\n\tErrMtsFeatureIsNotSupported                                     = 1753\n\tErrMtsUpdatedDBsGreaterMax                                      = 1754\n\tErrMtsCantParallel                                              = 1755\n\tErrMtsInconsistentData                                          = 1756\n\tErrFulltextNotSupportedWithPartitioning                         = 1757\n\tErrDaInvalidConditionNumber                                     = 1758\n\tErrInsecurePlainText                                            = 1759\n\tErrInsecureChangeMaster                                         = 1760\n\tErrForeignDuplicateKeyWithChildInfo                             = 1761\n\tErrForeignDuplicateKeyWithoutChildInfo                          = 1762\n\tErrSQLthreadWithSecureSlave                                     = 1763\n\tErrTableHasNoFt                                                 = 1764\n\tErrVariableNotSettableInSfOrTrigger                             = 1765\n\tErrVariableNotSettableInTransaction                             = 1766\n\tErrGtidNextIsNotInGtidNextList                                  = 1767\n\tErrCantChangeGtidNextInTransactionWhenGtidNextListIsNull        = 1768\n\tErrSetStatementCannotInvokeFunction                             = 1769\n\tErrGtidNextCantBeAutomaticIfGtidNextListIsNonNull               = 1770\n\tErrSkippingLoggedTransaction                                    = 1771\n\tErrMalformedGtidSetSpecification                                = 1772\n\tErrMalformedGtidSetEncoding                                     = 1773\n\tErrMalformedGtidSpecification                                   = 1774\n\tErrGnoExhausted                                                 = 1775\n\tErrBadSlaveAutoPosition                                         = 1776\n\tErrAutoPositionRequiresGtidModeOn                               = 1777\n\tErrCantDoImplicitCommitInTrxWhenGtidNextIsSet                   = 1778\n\tErrGtidMode2Or3RequiresEnforceGtidConsistencyOn                 = 1779\n\tErrGtidModeRequiresBinlog                                       = 1780\n\tErrCantSetGtidNextToGtidWhenGtidModeIsOff                       = 1781\n\tErrCantSetGtidNextToAnonymousWhenGtidModeIsOn                   = 1782\n\tErrCantSetGtidNextListToNonNullWhenGtidModeIsOff                = 1783\n\tErrFoundGtidEventWhenGtidModeIsOff                              = 1784\n\tErrGtidUnsafeNonTransactionalTable                              = 1785\n\tErrGtidUnsafeCreateSelect                                       = 1786\n\tErrGtidUnsafeCreateDropTemporaryTableInTransaction              = 1787\n\tErrGtidModeCanOnlyChangeOneStepAtATime                          = 1788\n\tErrMasterHasPurgedRequiredGtids                                 = 1789\n\tErrCantSetGtidNextWhenOwningGtid                                = 1790\n\tErrUnknownExplainFormat                                         = 1791\n\tErrCantExecuteInReadOnlyTransaction                             = 1792\n\tErrTooLongTablePartitionComment                                 = 1793\n\tErrSlaveConfiguration                                           = 1794\n\tErrInnodbFtLimit                                                = 1795\n\tErrInnodbNoFtTempTable                                          = 1796\n\tErrInnodbFtWrongDocidColumn                                     = 1797\n\tErrInnodbFtWrongDocidIndex                                      = 1798\n\tErrInnodbOnlineLogTooBig                                        = 1799\n\tErrUnknownAlterAlgorithm                                        = 1800\n\tErrUnknownAlterLock                                             = 1801\n\tErrMtsChangeMasterCantRunWithGaps                               = 1802\n\tErrMtsRecoveryFailure                                           = 1803\n\tErrMtsResetWorkers                                              = 1804\n\tErrColCountDoesntMatchCorruptedV2                               = 1805\n\tErrSlaveSilentRetryTransaction                                  = 1806\n\tErrDiscardFkChecksRunning                                       = 1807\n\tErrTableSchemaMismatch                                          = 1808\n\tErrTableInSystemTablespace                                      = 1809\n\tErrIoRead                                                       = 1810\n\tErrIoWrite                                                      = 1811\n\tErrTablespaceMissing                                            = 1812\n\tErrTablespaceExists                                             = 1813\n\tErrTablespaceDiscarded                                          = 1814\n\tErrInternal                                                     = 1815\n\tErrInnodbImport                                                 = 1816\n\tErrInnodbIndexCorrupt                                           = 1817\n\tErrInvalidYearColumnLength                                      = 1818\n\tErrNotValidPassword                                             = 1819\n\tErrMustChangePassword                                           = 1820\n\tErrFkNoIndexChild                                               = 1821\n\tErrFkNoIndexParent                                              = 1822\n\tErrFkFailAddSystem                                              = 1823\n\tErrFkCannotOpenParent                                           = 1824\n\tErrFkIncorrectOption                                            = 1825\n\tErrFkDupName                                                    = 1826\n\tErrPasswordFormat                                               = 1827\n\tErrFkColumnCannotDrop                                           = 1828\n\tErrFkColumnCannotDropChild                                      = 1829\n\tErrFkColumnNotNull                                              = 1830\n\tErrDupIndex                                                     = 1831\n\tErrFkColumnCannotChange                                         = 1832\n\tErrFkColumnCannotChangeChild                                    = 1833\n\tErrFkCannotDeleteParent                                         = 1834\n\tErrMalformedPacket                                              = 1835\n\tErrReadOnlyMode                                                 = 1836\n\tErrGtidNextTypeUndefinedGroup                                   = 1837\n\tErrVariableNotSettableInSp                                      = 1838\n\tErrCantSetGtidPurgedWhenGtidModeIsOff                           = 1839\n\tErrCantSetGtidPurgedWhenGtidExecutedIsNotEmpty                  = 1840\n\tErrCantSetGtidPurgedWhenOwnedGtidsIsNotEmpty                    = 1841\n\tErrGtidPurgedWasChanged                                         = 1842\n\tErrGtidExecutedWasChanged                                       = 1843\n\tErrBinlogStmtModeAndNoReplTables                                = 1844\n\tErrAlterOperationNotSupported                                   = 1845\n\tErrAlterOperationNotSupportedReason                             = 1846\n\tErrAlterOperationNotSupportedReasonCopy                         = 1847\n\tErrAlterOperationNotSupportedReasonPartition                    = 1848\n\tErrAlterOperationNotSupportedReasonFkRename                     = 1849\n\tErrAlterOperationNotSupportedReasonColumnType                   = 1850\n\tErrAlterOperationNotSupportedReasonFkCheck                      = 1851\n\tErrAlterOperationNotSupportedReasonIgnore                       = 1852\n\tErrAlterOperationNotSupportedReasonNopk                         = 1853\n\tErrAlterOperationNotSupportedReasonAutoinc                      = 1854\n\tErrAlterOperationNotSupportedReasonHiddenFts                    = 1855\n\tErrAlterOperationNotSupportedReasonChangeFts                    = 1856\n\tErrAlterOperationNotSupportedReasonFts                          = 1857\n\tErrSQLSlaveSkipCounterNotSettableInGtidMode                     = 1858\n\tErrDupUnknownInIndex                                            = 1859\n\tErrIdentCausesTooLongPath                                       = 1860\n\tErrAlterOperationNotSupportedReasonNotNull                      = 1861\n\tErrMustChangePasswordLogin                                      = 1862\n\tErrRowInWrongPartition                                          = 1863\n\tErrErrorLast                                                    = 1863\n\tErrMaxExecTimeExceeded                                          = 1907\n\tErrInvalidFieldSize                                             = 3013\n\tErrIncorrectType                                                = 3064\n\tErrInvalidJSONData                                              = 3069\n\tErrGeneratedColumnFunctionIsNotAllowed                          = 3102\n\tErrUnsupportedAlterInplaceOnVirtualColumn                       = 3103\n\tErrWrongFKOptionForGeneratedColumn                              = 3104\n\tErrBadGeneratedColumn                                           = 3105\n\tErrUnsupportedOnGeneratedColumn                                 = 3106\n\tErrGeneratedColumnNonPrior                                      = 3107\n\tErrDependentByGeneratedColumn                                   = 3108\n\tErrGeneratedColumnRefAutoInc                                    = 3109\n\tErrInvalidArgumentForLogarithm                                  = 3020\n\tErrInvalidJSONText                                              = 3140\n\tErrInvalidJSONPath                                              = 3143\n\tErrInvalidTypeForJSON                                           = 3146\n\tErrInvalidJSONPathWildcard                                      = 3149\n\tErrInvalidJSONContainsPathType                                  = 3150\n\tErrJSONUsedAsKey                                                = 3152\n\tErrBadUser                                                      = 3162\n\tErrUserAlreadyExists                                            = 3163\n\tErrInvalidJSONPathArrayCell                                     = 3165\n\tErrInvalidEncryptionOption                                      = 3184\n\tErrRoleNotGranted                                               = 3530\n\tErrLockAcquireFailAndNoWaitSet                                  = 3572\n\tErrWindowNoSuchWindow                                           = 3579\n\tErrWindowCircularityInWindowGraph                               = 3580\n\tErrWindowNoChildPartitioning                                    = 3581\n\tErrWindowNoInherentFrame                                        = 3582\n\tErrWindowNoRedefineOrderBy                                      = 3583\n\tErrWindowFrameStartIllegal                                      = 3584\n\tErrWindowFrameEndIllegal                                        = 3585\n\tErrWindowFrameIllegal                                           = 3586\n\tErrWindowRangeFrameOrderType                                    = 3587\n\tErrWindowRangeFrameTemporalType                                 = 3588\n\tErrWindowRangeFrameNumericType                                  = 3589\n\tErrWindowRangeBoundNotConstant                                  = 3590\n\tErrWindowDuplicateName                                          = 3591\n\tErrWindowIllegalOrderBy                                         = 3592\n\tErrWindowInvalidWindowFuncUse                                   = 3593\n\tErrWindowInvalidWindowFuncAliasUse                              = 3594\n\tErrWindowNestedWindowFuncUseInWindowSpec                        = 3595\n\tErrWindowRowsIntervalUse                                        = 3596\n\tErrWindowNoGroupOrderUnused                                     = 3597\n\tErrWindowExplainJson                                            = 3598\n\tErrWindowFunctionIgnoresFrame                                   = 3599\n\tErrDataTruncatedFunctionalIndex                                 = 3751\n\tErrDataOutOfRangeFunctionalIndex                                = 3752\n\tErrFunctionalIndexOnJsonOrGeometryFunction                      = 3753\n\tErrFunctionalIndexRefAutoIncrement                              = 3754\n\tErrCannotDropColumnFunctionalIndex                              = 3755\n\tErrFunctionalIndexPrimaryKey                                    = 3756\n\tErrFunctionalIndexOnLob                                         = 3757\n\tErrFunctionalIndexFunctionIsNotAllowed                          = 3758\n\tErrFulltextFunctionalIndex                                      = 3759\n\tErrSpatialFunctionalIndex                                       = 3760\n\tErrWrongKeyColumnFunctionalIndex                                = 3761\n\tErrFunctionalIndexOnField                                       = 3762\n\tErrFKIncompatibleColumns                                        = 3780\n\tErrFunctionalIndexRowValueIsNotAllowed                          = 3800\n\tErrDependentByFunctionalIndex                                   = 3837\n\tErrInvalidJsonValueForFuncIndex                                 = 3903\n\tErrJsonValueOutOfRangeForFuncIndex                              = 3904\n\tErrFunctionalIndexDataIsTooLong                                 = 3907\n\tErrFunctionalIndexNotApplicable                                 = 3909\n\n\t// MariaDB errors.\n\tErrOnlyOneDefaultPartionAllowed         = 4030\n\tErrWrongPartitionTypeExpectedSystemTime = 4113\n\tErrSystemVersioningWrongPartitions      = 4128\n\tErrSequenceRunOut                       = 4135\n\tErrSequenceInvalidData                  = 4136\n\tErrSequenceAccessFail                   = 4137\n\tErrNotSequence                          = 4138\n\tErrUnknownSequence                      = 4139\n\tErrWrongInsertIntoSequence              = 4140\n\tErrSequenceInvalidTableStructure        = 4141\n\n\t// TiDB self-defined errors.\n\tErrMemExceedThreshold                  = 8001\n\tErrForUpdateCantRetry                  = 8002\n\tErrAdminCheckTable                     = 8003\n\tErrTxnTooLarge                         = 8004\n\tErrWriteConflictInTiDB                 = 8005\n\tErrInvalidPluginID                     = 8101\n\tErrInvalidPluginManifest               = 8102\n\tErrInvalidPluginName                   = 8103\n\tErrInvalidPluginVersion                = 8104\n\tErrDuplicatePlugin                     = 8105\n\tErrInvalidPluginSysVarName             = 8106\n\tErrRequireVersionCheckFail             = 8107\n\tErrUnsupportedType                     = 8108\n\tErrAnalyzeMissIndex                    = 8109\n\tErrCartesianProductUnsupported         = 8110\n\tErrPreparedStmtNotFound                = 8111\n\tErrWrongParamCount                     = 8112\n\tErrSchemaChanged                       = 8113\n\tErrUnknownPlan                         = 8114\n\tErrPrepareMulti                        = 8115\n\tErrPrepareDDL                          = 8116\n\tErrResultIsEmpty                       = 8117\n\tErrBuildExecutor                       = 8118\n\tErrBatchInsertFail                     = 8119\n\tErrGetStartTS                          = 8120\n\tErrPrivilegeCheckFail                  = 8121\n\tErrInvalidWildCard                     = 8122\n\tErrMixOfGroupFuncAndFieldsIncompatible = 8123\n\tErrUnsupportedReloadPlugin             = 8018\n\tErrUnsupportedReloadPluginVar          = 8019\n\tErrTableLocked                         = 8020\n\tErrNotExist                            = 8021\n\tErrTxnRetryable                        = 8022\n\tErrCannotSetNilValue                   = 8023\n\tErrInvalidTxn                          = 8024\n\tErrEntryTooLarge                       = 8025\n\tErrNotImplemented                      = 8026\n\tErrInfoSchemaExpired                   = 8027\n\tErrInfoSchemaChanged                   = 8028\n\tErrBadNumber                           = 8029\n\tErrCastAsSignedOverflow                = 8030\n\tErrCastNegIntAsUnsigned                = 8031\n\tErrInvalidYearFormat                   = 8032\n\tErrInvalidYear                         = 8033\n\tErrIncorrectDatetimeValue              = 8034\n\tErrInvalidTimeFormat                   = 8036\n\tErrInvalidWeekModeFormat               = 8037\n\tErrFieldGetDefaultFailed               = 8038\n\tErrIndexOutBound                       = 8039\n\tErrUnsupportedOp                       = 8040\n\tErrRowNotFound                         = 8041\n\tErrTableStateCantNone                  = 8042\n\tErrColumnStateNonPublic                = 8043\n\tErrIndexStateCantNone                  = 8044\n\tErrInvalidRecordKey                    = 8045\n\tErrColumnStateCantNone                 = 8046\n\tErrUnsupportedValueForVar              = 8047\n\tErrUnsupportedIsolationLevel           = 8048\n\tErrLoadPrivilege                       = 8049\n\tErrInvalidPrivilegeType                = 8050\n\tErrUnknownFieldType                    = 8051\n\tErrInvalidSequence                     = 8052\n\tErrCantGetValidID                      = 8053\n\tErrCantSetToNull                       = 8054\n\tErrSnapshotTooOld                      = 8055\n\tErrInvalidTableID                      = 8056\n\tErrInvalidType                         = 8057\n\tErrUnknownAllocatorType                = 8058\n\tErrAutoRandReadFailed                  = 8059\n\tErrInvalidIncrementAndOffset           = 8060\n\tErrWarnOptimizerHintUnsupportedHint    = 8061\n\tErrWarnOptimizerHintInvalidToken       = 8062\n\tErrWarnMemoryQuotaOverflow             = 8063\n\tErrWarnOptimizerHintParseError         = 8064\n\tErrWarnOptimizerHintInvalidInteger     = 8065\n\n\t// Error codes used by TiDB ddl package\n\tErrUnsupportedDDLOperation        = 8200\n\tErrNotOwner                       = 8201\n\tErrCantDecodeIndex                = 8202\n\tErrInvalidDDLWorker               = 8203\n\tErrInvalidDDLJob                  = 8204\n\tErrInvalidDDLJobFlag              = 8205\n\tErrWaitReorgTimeout               = 8206\n\tErrInvalidStoreVersion            = 8207\n\tErrUnknownTypeLength              = 8208\n\tErrUnknownFractionLength          = 8209\n\tErrInvalidDDLState                = 8210\n\tErrReorgPanic                     = 8211\n\tErrInvalidSplitRegionRanges       = 8212\n\tErrInvalidDDLJobVersion           = 8213\n\tErrCancelledDDLJob                = 8214\n\tErrRepairTable                    = 8215\n\tErrInvalidAutoRandom              = 8216\n\tErrInvalidHashKeyFlag             = 8217\n\tErrInvalidListIndex               = 8218\n\tErrInvalidListMetaData            = 8219\n\tErrWriteOnSnapshot                = 8220\n\tErrInvalidKey                     = 8221\n\tErrInvalidIndexKey                = 8222\n\tErrDataInConsistent               = 8223\n\tErrDDLJobNotFound                 = 8224\n\tErrCancelFinishedDDLJob           = 8225\n\tErrCannotCancelDDLJob             = 8226\n\tErrSequenceUnsupportedTableOption = 8227\n\n\t// TiKV/PD errors.\n\tErrPDServerTimeout    = 9001\n\tErrTiKVServerTimeout  = 9002\n\tErrTiKVServerBusy     = 9003\n\tErrResolveLockTimeout = 9004\n\tErrRegionUnavailable  = 9005\n\tErrGCTooEarly         = 9006\n\tErrWriteConflict      = 9007\n\tErrTiKVStoreLimit     = 9008\n)\n"
  },
  {
    "path": "pkg/parser/mysql/errname.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\n// MySQLErrName maps error code to MySQL error messages.\nvar MySQLErrName = map[uint16]string{\n\tErrHashchk:                                  \"hashchk\",\n\tErrNisamchk:                                 \"isamchk\",\n\tErrNo:                                       \"NO\",\n\tErrYes:                                      \"YES\",\n\tErrCantCreateFile:                           \"Can't create file '%-.200s' (errno: %d - %s)\",\n\tErrCantCreateTable:                          \"Can't create table '%-.200s' (errno: %d)\",\n\tErrCantCreateDB:                             \"Can't create database '%-.192s' (errno: %d)\",\n\tErrDBCreateExists:                           \"Can't create database '%-.192s'; database exists\",\n\tErrDBDropExists:                             \"Can't drop database '%-.192s'; database doesn't exist\",\n\tErrDBDropDelete:                             \"Error dropping database (can't delete '%-.192s', errno: %d)\",\n\tErrDBDropRmdir:                              \"Error dropping database (can't rmdir '%-.192s', errno: %d)\",\n\tErrCantDeleteFile:                           \"Error on delete of '%-.192s' (errno: %d - %s)\",\n\tErrCantFindSystemRec:                        \"Can't read record in system table\",\n\tErrCantGetStat:                              \"Can't get status of '%-.200s' (errno: %d - %s)\",\n\tErrCantGetWd:                                \"Can't get working directory (errno: %d - %s)\",\n\tErrCantLock:                                 \"Can't lock file (errno: %d - %s)\",\n\tErrCantOpenFile:                             \"Can't open file: '%-.200s' (errno: %d - %s)\",\n\tErrFileNotFound:                             \"Can't find file: '%-.200s' (errno: %d - %s)\",\n\tErrCantReadDir:                              \"Can't read dir of '%-.192s' (errno: %d - %s)\",\n\tErrCantSetWd:                                \"Can't change dir to '%-.192s' (errno: %d - %s)\",\n\tErrCheckread:                                \"Record has changed since last read in table '%-.192s'\",\n\tErrDiskFull:                                 \"Disk full (%s); waiting for someone to free some space... (errno: %d - %s)\",\n\tErrDupKey:                                   \"Can't write; duplicate key in table '%-.192s'\",\n\tErrErrorOnClose:                             \"Error on close of '%-.192s' (errno: %d - %s)\",\n\tErrErrorOnRead:                              \"Error reading file '%-.200s' (errno: %d - %s)\",\n\tErrErrorOnRename:                            \"Error on rename of '%-.210s' to '%-.210s' (errno: %d - %s)\",\n\tErrErrorOnWrite:                             \"Error writing file '%-.200s' (errno: %d - %s)\",\n\tErrFileUsed:                                 \"'%-.192s' is locked against change\",\n\tErrFilsortAbort:                             \"Sort aborted\",\n\tErrFormNotFound:                             \"View '%-.192s' doesn't exist for '%-.192s'\",\n\tErrGetErrno:                                 \"Got error %d from storage engine\",\n\tErrIllegalHa:                                \"Table storage engine for '%-.192s' doesn't have this option\",\n\tErrKeyNotFound:                              \"Can't find record in '%-.192s'\",\n\tErrNotFormFile:                              \"Incorrect information in file: '%-.200s'\",\n\tErrNotKeyFile:                               \"Incorrect key file for table '%-.200s'; try to repair it\",\n\tErrOldKeyFile:                               \"Old key file for table '%-.192s'; repair it!\",\n\tErrOpenAsReadonly:                           \"Table '%-.192s' is read only\",\n\tErrOutofMemory:                              \"Out of memory; restart server and try again (needed %d bytes)\",\n\tErrOutOfSortMemory:                          \"Out of sort memory, consider increasing server sort buffer size\",\n\tErrUnexpectedEOF:                            \"Unexpected EOF found when reading file '%-.192s' (errno: %d - %s)\",\n\tErrConCount:                                 \"Too many connections\",\n\tErrOutOfResources:                           \"Out of memory; check if mysqld or some other process uses all available memory; if not, you may have to use 'ulimit' to allow mysqld to use more memory or you can add more swap space\",\n\tErrBadHost:                                  \"Can't get hostname for your address\",\n\tErrHandshake:                                \"Bad handshake\",\n\tErrDBaccessDenied:                           \"Access denied for user '%-.48s'@'%-.64s' to database '%-.192s'\",\n\tErrAccessDenied:                             \"Access denied for user '%-.48s'@'%-.64s' (using password: %s)\",\n\tErrNoDB:                                     \"No database selected\",\n\tErrUnknownCom:                               \"Unknown command\",\n\tErrBadNull:                                  \"Column '%-.192s' cannot be null\",\n\tErrBadDB:                                    \"Unknown database '%-.192s'\",\n\tErrTableExists:                              \"Table '%-.192s' already exists\",\n\tErrBadTable:                                 \"Unknown table '%-.100s'\",\n\tErrNonUniq:                                  \"Column '%-.192s' in %-.192s is ambiguous\",\n\tErrServerShutdown:                           \"Server shutdown in progress\",\n\tErrBadField:                                 \"Unknown column '%-.192s' in '%-.192s'\",\n\tErrFieldNotInGroupBy:                        \"Expression #%d of %s is not in GROUP BY clause and contains nonaggregated column '%s' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by\",\n\tErrWrongGroupField:                          \"Can't group on '%-.192s'\",\n\tErrWrongSumSelect:                           \"Statement has sum functions and columns in same statement\",\n\tErrWrongValueCount:                          \"Column count doesn't match value count\",\n\tErrTooLongIdent:                             \"Identifier name '%-.100s' is too long\",\n\tErrDupFieldName:                             \"Duplicate column name '%-.192s'\",\n\tErrDupKeyName:                               \"Duplicate key name '%-.192s'\",\n\tErrDupEntry:                                 \"Duplicate entry '%-.64s' for key '%-.192s'\",\n\tErrWrongFieldSpec:                           \"Incorrect column specifier for column '%-.192s'\",\n\tErrParse:                                    \"%s %s\",\n\tErrEmptyQuery:                               \"Query was empty\",\n\tErrNonuniqTable:                             \"Not unique table/alias: '%-.192s'\",\n\tErrInvalidDefault:                           \"Invalid default value for '%-.192s'\",\n\tErrMultiplePriKey:                           \"Multiple primary key defined\",\n\tErrTooManyKeys:                              \"Too many keys specified; max %d keys allowed\",\n\tErrTooManyKeyParts:                          \"Too many key parts specified; max %d parts allowed\",\n\tErrTooLongKey:                               \"Specified key was too long; max key length is %d bytes\",\n\tErrKeyColumnDoesNotExits:                    \"Key column '%-.192s' doesn't exist in table\",\n\tErrBlobUsedAsKey:                            \"BLOB column '%-.192s' can't be used in key specification with the used table type\",\n\tErrTooBigFieldlength:                        \"Column length too big for column '%-.192s' (max = %d); use BLOB or TEXT instead\",\n\tErrWrongAutoKey:                             \"Incorrect table definition; there can be only one auto column and it must be defined as a key\",\n\tErrReady:                                    \"%s: ready for connections.\\nVersion: '%s'  socket: '%s'  port: %d\",\n\tErrNormalShutdown:                           \"%s: Normal shutdown\\n\",\n\tErrGotSignal:                                \"%s: Got signal %d. Aborting!\\n\",\n\tErrShutdownComplete:                         \"%s: Shutdown complete\\n\",\n\tErrForcingClose:                             \"%s: Forcing close of thread %d  user: '%-.48s'\\n\",\n\tErrIpsock:                                   \"Can't create IP socket\",\n\tErrNoSuchIndex:                              \"Table '%-.192s' has no index like the one used in CREATE INDEX; recreate the table\",\n\tErrWrongFieldTerminators:                    \"Field separator argument is not what is expected; check the manual\",\n\tErrBlobsAndNoTerminated:                     \"You can't use fixed rowlength with BLOBs; please use 'fields terminated by'\",\n\tErrTextFileNotReadable:                      \"The file '%-.128s' must be in the database directory or be readable by all\",\n\tErrFileExists:                               \"File '%-.200s' already exists\",\n\tErrLoadInfo:                                 \"Records: %d  Deleted: %d  Skipped: %d  Warnings: %d\",\n\tErrAlterInfo:                                \"Records: %d  Duplicates: %d\",\n\tErrWrongSubKey:                              \"Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys\",\n\tErrCantRemoveAllFields:                      \"You can't delete all columns with ALTER TABLE; use DROP TABLE instead\",\n\tErrCantDropFieldOrKey:                       \"Can't DROP '%-.192s'; check that column/key exists\",\n\tErrInsertInfo:                               \"Records: %d  Duplicates: %d  Warnings: %d\",\n\tErrUpdateTableUsed:                          \"You can't specify target table '%-.192s' for update in FROM clause\",\n\tErrNoSuchThread:                             \"Unknown thread id: %d\",\n\tErrKillDenied:                               \"You are not owner of thread %d\",\n\tErrNoTablesUsed:                             \"No tables used\",\n\tErrTooBigSet:                                \"Too many strings for column %-.192s and SET\",\n\tErrNoUniqueLogFile:                          \"Can't generate a unique log-filename %-.200s.(1-999)\\n\",\n\tErrTableNotLockedForWrite:                   \"Table '%-.192s' was locked with a READ lock and can't be updated\",\n\tErrTableNotLocked:                           \"Table '%-.192s' was not locked with LOCK TABLES\",\n\tErrBlobCantHaveDefault:                      \"BLOB/TEXT/JSON column '%-.192s' can't have a default value\",\n\tErrWrongDBName:                              \"Incorrect database name '%-.100s'\",\n\tErrWrongTableName:                           \"Incorrect table name '%-.100s'\",\n\tErrTooBigSelect:                             \"The SELECT would examine more than MAXJOINSIZE rows; check your WHERE and use SET SQLBIGSELECTS=1 or SET MAXJOINSIZE=# if the SELECT is okay\",\n\tErrUnknown:                                  \"Unknown error\",\n\tErrUnknownProcedure:                         \"Unknown procedure '%-.192s'\",\n\tErrWrongParamcountToProcedure:               \"Incorrect parameter count to procedure '%-.192s'\",\n\tErrWrongParametersToProcedure:               \"Incorrect parameters to procedure '%-.192s'\",\n\tErrUnknownTable:                             \"Unknown table '%-.192s' in %-.32s\",\n\tErrFieldSpecifiedTwice:                      \"Column '%-.192s' specified twice\",\n\tErrInvalidGroupFuncUse:                      \"Invalid use of group function\",\n\tErrUnsupportedExtension:                     \"Table '%-.192s' uses an extension that doesn't exist in this MySQL version\",\n\tErrTableMustHaveColumns:                     \"A table must have at least 1 column\",\n\tErrRecordFileFull:                           \"The table '%-.192s' is full\",\n\tErrUnknownCharacterSet:                      \"Unknown character set: '%-.64s'\",\n\tErrTooManyTables:                            \"Too many tables; MySQL can only use %d tables in a join\",\n\tErrTooManyFields:                            \"Too many columns\",\n\tErrTooBigRowsize:                            \"Row size too large. The maximum row size for the used table type, not counting BLOBs, is %d. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs\",\n\tErrStackOverrun:                             \"Thread stack overrun:  Used: %d of a %d stack.  Use 'mysqld --threadStack=#' to specify a bigger stack if needed\",\n\tErrWrongOuterJoin:                           \"Cross dependency found in OUTER JOIN; examine your ON conditions\",\n\tErrNullColumnInIndex:                        \"Table handler doesn't support NULL in given index. Please change column '%-.192s' to be NOT NULL or use another handler\",\n\tErrCantFindUdf:                              \"Can't load function '%-.192s'\",\n\tErrCantInitializeUdf:                        \"Can't initialize function '%-.192s'; %-.80s\",\n\tErrUdfNoPaths:                               \"No paths allowed for shared library\",\n\tErrUdfExists:                                \"Function '%-.192s' already exists\",\n\tErrCantOpenLibrary:                          \"Can't open shared library '%-.192s' (errno: %d %-.128s)\",\n\tErrCantFindDlEntry:                          \"Can't find symbol '%-.128s' in library\",\n\tErrFunctionNotDefined:                       \"Function '%-.192s' is not defined\",\n\tErrHostIsBlocked:                            \"Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'\",\n\tErrHostNotPrivileged:                        \"Host '%-.64s' is not allowed to connect to this MySQL server\",\n\tErrPasswordAnonymousUser:                    \"You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords\",\n\tErrPasswordNotAllowed:                       \"You must have privileges to update tables in the mysql database to be able to change passwords for others\",\n\tErrPasswordNoMatch:                          \"Can't find any matching row in the user table\",\n\tErrUpdateInfo:                               \"Rows matched: %d  Changed: %d  Warnings: %d\",\n\tErrCantCreateThread:                         \"Can't create a new thread (errno %d); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug\",\n\tErrWrongValueCountOnRow:                     \"Column count doesn't match value count at row %d\",\n\tErrCantReopenTable:                          \"Can't reopen table: '%-.192s'\",\n\tErrInvalidUseOfNull:                         \"Invalid use of NULL value\",\n\tErrRegexp:                                   \"Got error '%-.64s' from regexp\",\n\tErrMixOfGroupFuncAndFields:                  \"Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause\",\n\tErrNonexistingGrant:                         \"There is no such grant defined for user '%-.48s' on host '%-.64s'\",\n\tErrTableaccessDenied:                        \"%-.128s command denied to user '%-.48s'@'%-.64s' for table '%-.64s'\",\n\tErrColumnaccessDenied:                       \"%-.16s command denied to user '%-.48s'@'%-.64s' for column '%-.192s' in table '%-.192s'\",\n\tErrIllegalGrantForTable:                     \"Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used\",\n\tErrGrantWrongHostOrUser:                     \"The host or user argument to GRANT is too long\",\n\tErrNoSuchTable:                              \"Table '%-.192s.%-.192s' doesn't exist\",\n\tErrNonexistingTableGrant:                    \"There is no such grant defined for user '%-.48s' on host '%-.64s' on table '%-.192s'\",\n\tErrNotAllowedCommand:                        \"The used command is not allowed with this MySQL version\",\n\tErrSyntax:                                   \"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use\",\n\tErrDelayedCantChangeLock:                    \"Delayed insert thread couldn't get requested lock for table %-.192s\",\n\tErrTooManyDelayedThreads:                    \"Too many delayed threads in use\",\n\tErrAbortingConnection:                       \"Aborted connection %d to db: '%-.192s' user: '%-.48s' (%-.64s)\",\n\tErrNetPacketTooLarge:                        \"Got a packet bigger than 'maxAllowedPacket' bytes\",\n\tErrNetReadErrorFromPipe:                     \"Got a read error from the connection pipe\",\n\tErrNetFcntl:                                 \"Got an error from fcntl()\",\n\tErrNetPacketsOutOfOrder:                     \"Got packets out of order\",\n\tErrNetUncompress:                            \"Couldn't uncompress communication packet\",\n\tErrNetRead:                                  \"Got an error reading communication packets\",\n\tErrNetReadInterrupted:                       \"Got timeout reading communication packets\",\n\tErrNetErrorOnWrite:                          \"Got an error writing communication packets\",\n\tErrNetWriteInterrupted:                      \"Got timeout writing communication packets\",\n\tErrTooLongString:                            \"Result string is longer than 'maxAllowedPacket' bytes\",\n\tErrTableCantHandleBlob:                      \"The used table type doesn't support BLOB/TEXT columns\",\n\tErrTableCantHandleAutoIncrement:             \"The used table type doesn't support AUTOINCREMENT columns\",\n\tErrDelayedInsertTableLocked:                 \"INSERT DELAYED can't be used with table '%-.192s' because it is locked with LOCK TABLES\",\n\tErrWrongColumnName:                          \"Incorrect column name '%-.100s'\",\n\tErrWrongKeyColumn:                           \"The used storage engine can't index column '%-.192s'\",\n\tErrWrongMrgTable:                            \"Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist\",\n\tErrDupUnique:                                \"Can't write, because of unique constraint, to table '%-.192s'\",\n\tErrBlobKeyWithoutLength:                     \"BLOB/TEXT column '%-.192s' used in key specification without a key length\",\n\tErrPrimaryCantHaveNull:                      \"All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead\",\n\tErrTooManyRows:                              \"Result consisted of more than one row\",\n\tErrRequiresPrimaryKey:                       \"This table type requires a primary key\",\n\tErrNoRaidCompiled:                           \"This version of MySQL is not compiled with RAID support\",\n\tErrUpdateWithoutKeyInSafeMode:               \"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column\",\n\tErrKeyDoesNotExist:                          \"Key '%-.192s' doesn't exist in table '%-.192s'\",\n\tErrCheckNoSuchTable:                         \"Can't open table\",\n\tErrCheckNotImplemented:                      \"The storage engine for the table doesn't support %s\",\n\tErrCantDoThisDuringAnTransaction:            \"You are not allowed to execute this command in a transaction\",\n\tErrErrorDuringCommit:                        \"Got error %d during COMMIT\",\n\tErrErrorDuringRollback:                      \"Got error %d during ROLLBACK\",\n\tErrErrorDuringFlushLogs:                     \"Got error %d during FLUSHLOGS\",\n\tErrErrorDuringCheckpoint:                    \"Got error %d during CHECKPOINT\",\n\tErrNewAbortingConnection:                    \"Aborted connection %d to db: '%-.192s' user: '%-.48s' host: '%-.64s' (%-.64s)\",\n\tErrDumpNotImplemented:                       \"The storage engine for the table does not support binary table dump\",\n\tErrFlushMasterBinlogClosed:                  \"Binlog closed, cannot RESET MASTER\",\n\tErrIndexRebuild:                             \"Failed rebuilding the index of  dumped table '%-.192s'\",\n\tErrMaster:                                   \"Error from master: '%-.64s'\",\n\tErrMasterNetRead:                            \"Net error reading from master\",\n\tErrMasterNetWrite:                           \"Net error writing to master\",\n\tErrFtMatchingKeyNotFound:                    \"Can't find FULLTEXT index matching the column list\",\n\tErrLockOrActiveTransaction:                  \"Can't execute the given command because you have active locked tables or an active transaction\",\n\tErrUnknownSystemVariable:                    \"Unknown system variable '%-.64s'\",\n\tErrCrashedOnUsage:                           \"Table '%-.192s' is marked as crashed and should be repaired\",\n\tErrCrashedOnRepair:                          \"Table '%-.192s' is marked as crashed and last (automatic?) repair failed\",\n\tErrWarningNotCompleteRollback:               \"Some non-transactional changed tables couldn't be rolled back\",\n\tErrTransCacheFull:                           \"Multi-statement transaction required more than 'maxBinlogCacheSize' bytes of storage; increase this mysqld variable and try again\",\n\tErrSlaveMustStop:                            \"This operation cannot be performed with a running slave; run STOP SLAVE first\",\n\tErrSlaveNotRunning:                          \"This operation requires a running slave; configure slave and do START SLAVE\",\n\tErrBadSlave:                                 \"The server is not configured as slave; fix in config file or with CHANGE MASTER TO\",\n\tErrMasterInfo:                               \"Could not initialize master info structure; more error messages can be found in the MySQL error log\",\n\tErrSlaveThread:                              \"Could not create slave thread; check system resources\",\n\tErrTooManyUserConnections:                   \"User %-.64s already has more than 'maxUserConnections' active connections\",\n\tErrSetConstantsOnly:                         \"You may only use constant expressions with SET\",\n\tErrLockWaitTimeout:                          \"Lock wait timeout exceeded; try restarting transaction\",\n\tErrLockTableFull:                            \"The total number of locks exceeds the lock table size\",\n\tErrReadOnlyTransaction:                      \"Update locks cannot be acquired during a READ UNCOMMITTED transaction\",\n\tErrDropDBWithReadLock:                       \"DROP DATABASE not allowed while thread is holding global read lock\",\n\tErrCreateDBWithReadLock:                     \"CREATE DATABASE not allowed while thread is holding global read lock\",\n\tErrWrongArguments:                           \"Incorrect arguments to %s\",\n\tErrNoPermissionToCreateUser:                 \"'%-.48s'@'%-.64s' is not allowed to create new users\",\n\tErrUnionTablesInDifferentDir:                \"Incorrect table definition; all MERGE tables must be in the same database\",\n\tErrLockDeadlock:                             \"Deadlock found when trying to get lock; try restarting transaction\",\n\tErrTableCantHandleFt:                        \"The used table type doesn't support FULLTEXT indexes\",\n\tErrCannotAddForeign:                         \"Cannot add foreign key constraint\",\n\tErrNoReferencedRow:                          \"Cannot add or update a child row: a foreign key constraint fails\",\n\tErrRowIsReferenced:                          \"Cannot delete or update a parent row: a foreign key constraint fails\",\n\tErrConnectToMaster:                          \"Error connecting to master: %-.128s\",\n\tErrQueryOnMaster:                            \"Error running query on master: %-.128s\",\n\tErrErrorWhenExecutingCommand:                \"Error when executing command %s: %-.128s\",\n\tErrWrongUsage:                               \"Incorrect usage of %s and %s\",\n\tErrWrongNumberOfColumnsInSelect:             \"The used SELECT statements have a different number of columns\",\n\tErrCantUpdateWithReadlock:                   \"Can't execute the query because you have a conflicting read lock\",\n\tErrMixingNotAllowed:                         \"Mixing of transactional and non-transactional tables is disabled\",\n\tErrDupArgument:                              \"Option '%s' used twice in statement\",\n\tErrUserLimitReached:                         \"User '%-.64s' has exceeded the '%s' resource (current value: %d)\",\n\tErrSpecificAccessDenied:                     \"Access denied; you need (at least one of) the %-.128s privilege(s) for this operation\",\n\tErrLocalVariable:                            \"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL\",\n\tErrGlobalVariable:                           \"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL\",\n\tErrNoDefault:                                \"Variable '%-.64s' doesn't have a default value\",\n\tErrWrongValueForVar:                         \"Variable '%-.64s' can't be set to the value of '%-.200s'\",\n\tErrWrongTypeForVar:                          \"Incorrect argument type to variable '%-.64s'\",\n\tErrVarCantBeRead:                            \"Variable '%-.64s' can only be set, not read\",\n\tErrCantUseOptionHere:                        \"Incorrect usage/placement of '%s'\",\n\tErrNotSupportedYet:                          \"This version of TiDB doesn't yet support '%s'\",\n\tErrMasterFatalErrorReadingBinlog:            \"Got fatal error %d from master when reading data from binary log: '%-.320s'\",\n\tErrSlaveIgnoredTable:                        \"Slave SQL thread ignored the query because of replicate-*-table rules\",\n\tErrIncorrectGlobalLocalVar:                  \"Variable '%-.192s' is a %s variable\",\n\tErrWrongFkDef:                               \"Incorrect foreign key definition for '%-.192s': %s\",\n\tErrKeyRefDoNotMatchTableRef:                 \"Key reference and table reference don't match\",\n\tErrOperandColumns:                           \"Operand should contain %d column(s)\",\n\tErrSubqueryNo1Row:                           \"Subquery returns more than 1 row\",\n\tErrUnknownStmtHandler:                       \"Unknown prepared statement handler (%.*s) given to %s\",\n\tErrCorruptHelpDB:                            \"Help database is corrupt or does not exist\",\n\tErrCyclicReference:                          \"Cyclic reference on subqueries\",\n\tErrAutoConvert:                              \"Converting column '%s' from %s to %s\",\n\tErrIllegalReference:                         \"Reference '%-.64s' not supported (%s)\",\n\tErrDerivedMustHaveAlias:                     \"Every derived table must have its own alias\",\n\tErrSelectReduced:                            \"Select %d was reduced during optimization\",\n\tErrTablenameNotAllowedHere:                  \"Table '%s' from one of the %ss cannot be used in %s\",\n\tErrNotSupportedAuthMode:                     \"Client does not support authentication protocol requested by server; consider upgrading MySQL client\",\n\tErrSpatialCantHaveNull:                      \"All parts of a SPATIAL index must be NOT NULL\",\n\tErrCollationCharsetMismatch:                 \"COLLATION '%s' is not valid for CHARACTER SET '%s'\",\n\tErrSlaveWasRunning:                          \"Slave is already running\",\n\tErrSlaveWasNotRunning:                       \"Slave already has been stopped\",\n\tErrTooBigForUncompress:                      \"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)\",\n\tErrZlibZMem:                                 \"ZLIB: Not enough memory\",\n\tErrZlibZBuf:                                 \"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)\",\n\tErrZlibZData:                                \"ZLIB: Input data corrupted\",\n\tErrCutValueGroupConcat:                      \"Some rows were cut by GROUPCONCAT(%s)\",\n\tErrWarnTooFewRecords:                        \"Row %d doesn't contain data for all columns\",\n\tErrWarnTooManyRecords:                       \"Row %d was truncated; it contained more data than there were input columns\",\n\tErrWarnNullToNotnull:                        \"Column set to default value; NULL supplied to NOT NULL column '%s' at row %d\",\n\tErrWarnDataOutOfRange:                       \"Out of range value for column '%s' at row %d\",\n\tWarnDataTruncated:                           \"Data truncated for column '%s' at row %d\",\n\tErrWarnUsingOtherHandler:                    \"Using storage engine %s for table '%s'\",\n\tErrCantAggregate2collations:                 \"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'\",\n\tErrDropUser:                                 \"Cannot drop one or more of the requested users\",\n\tErrRevokeGrants:                             \"Can't revoke all privileges for one or more of the requested users\",\n\tErrCantAggregate3collations:                 \"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'\",\n\tErrCantAggregateNcollations:                 \"Illegal mix of collations for operation '%s'\",\n\tErrVariableIsNotStruct:                      \"Variable '%-.64s' is not a variable component (can't be used as XXXX.variableName)\",\n\tErrUnknownCollation:                         \"Unknown collation: '%-.64s'\",\n\tErrSlaveIgnoredSslParams:                    \"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started\",\n\tErrServerIsInSecureAuthMode:                 \"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format\",\n\tErrWarnFieldResolved:                        \"Field or reference '%-.192s%s%-.192s%s%-.192s' of SELECT #%d was resolved in SELECT #%d\",\n\tErrBadSlaveUntilCond:                        \"Incorrect parameter or combination of parameters for START SLAVE UNTIL\",\n\tErrMissingSkipSlave:                         \"It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you will get problems if you get an unexpected slave's mysqld restart\",\n\tErrUntilCondIgnored:                         \"SQL thread is not to be started so UNTIL options are ignored\",\n\tErrWrongNameForIndex:                        \"Incorrect index name '%-.100s'\",\n\tErrWrongNameForCatalog:                      \"Incorrect catalog name '%-.100s'\",\n\tErrWarnQcResize:                             \"Query cache failed to set size %d; new query cache size is %d\",\n\tErrBadFtColumn:                              \"Column '%-.192s' cannot be part of FULLTEXT index\",\n\tErrUnknownKeyCache:                          \"Unknown key cache '%-.100s'\",\n\tErrWarnHostnameWontWork:                     \"MySQL is started in --skip-name-resolve mode; you must restart it without this switch for this grant to work\",\n\tErrUnknownStorageEngine:                     \"Unknown storage engine '%s'\",\n\tErrWarnDeprecatedSyntax:                     \"'%s' is deprecated and will be removed in a future release. Please use %s instead\",\n\tErrNonUpdatableTable:                        \"The target table %-.100s of the %s is not updatable\",\n\tErrFeatureDisabled:                          \"The '%s' feature is disabled; you need MySQL built with '%s' to have it working\",\n\tErrOptionPreventsStatement:                  \"The MySQL server is running with the %s option so it cannot execute this statement\",\n\tErrDuplicatedValueInType:                    \"Column '%-.100s' has duplicated value '%-.64s' in %s\",\n\tErrTruncatedWrongValue:                      \"Truncated incorrect %-.64s value: '%-.128s'\",\n\tErrTooMuchAutoTimestampCols:                 \"Incorrect table definition; there can be only one TIMESTAMP column with CURRENTTIMESTAMP in DEFAULT or ON UPDATE clause\",\n\tErrInvalidOnUpdate:                          \"Invalid ON UPDATE clause for '%-.192s' column\",\n\tErrUnsupportedPs:                            \"This command is not supported in the prepared statement protocol yet\",\n\tErrGetErrmsg:                                \"Got error %d '%-.100s' from %s\",\n\tErrGetTemporaryErrmsg:                       \"Got temporary error %d '%-.100s' from %s\",\n\tErrUnknownTimeZone:                          \"Unknown or incorrect time zone: '%-.64s'\",\n\tErrWarnInvalidTimestamp:                     \"Invalid TIMESTAMP value in column '%s' at row %d\",\n\tErrInvalidCharacterString:                   \"Invalid %s character string: '%.64s'\",\n\tErrWarnAllowedPacketOverflowed:              \"Result of %s() was larger than max_allowed_packet (%d) - truncated\",\n\tErrConflictingDeclarations:                  \"Conflicting declarations: '%s%s' and '%s%s'\",\n\tErrSpNoRecursiveCreate:                      \"Can't create a %s from within another stored routine\",\n\tErrSpAlreadyExists:                          \"%s %s already exists\",\n\tErrSpDoesNotExist:                           \"%s %s does not exist\",\n\tErrSpDropFailed:                             \"Failed to DROP %s %s\",\n\tErrSpStoreFailed:                            \"Failed to CREATE %s %s\",\n\tErrSpLilabelMismatch:                        \"%s with no matching label: %s\",\n\tErrSpLabelRedefine:                          \"Redefining label %s\",\n\tErrSpLabelMismatch:                          \"End-label %s without match\",\n\tErrSpUninitVar:                              \"Referring to uninitialized variable %s\",\n\tErrSpBadselect:                              \"PROCEDURE %s can't return a result set in the given context\",\n\tErrSpBadreturn:                              \"RETURN is only allowed in a FUNCTION\",\n\tErrSpBadstatement:                           \"%s is not allowed in stored procedures\",\n\tErrUpdateLogDeprecatedIgnored:               \"The update log is deprecated and replaced by the binary log; SET SQLLOGUPDATE has been ignored.\",\n\tErrUpdateLogDeprecatedTranslated:            \"The update log is deprecated and replaced by the binary log; SET SQLLOGUPDATE has been translated to SET SQLLOGBIN.\",\n\tErrQueryInterrupted:                         \"Query execution was interrupted\",\n\tErrSpWrongNoOfArgs:                          \"Incorrect number of arguments for %s %s; expected %d, got %d\",\n\tErrSpCondMismatch:                           \"Undefined CONDITION: %s\",\n\tErrSpNoreturn:                               \"No RETURN found in FUNCTION %s\",\n\tErrSpNoreturnend:                            \"FUNCTION %s ended without RETURN\",\n\tErrSpBadCursorQuery:                         \"Cursor statement must be a SELECT\",\n\tErrSpBadCursorSelect:                        \"Cursor SELECT must not have INTO\",\n\tErrSpCursorMismatch:                         \"Undefined CURSOR: %s\",\n\tErrSpCursorAlreadyOpen:                      \"Cursor is already open\",\n\tErrSpCursorNotOpen:                          \"Cursor is not open\",\n\tErrSpUndeclaredVar:                          \"Undeclared variable: %s\",\n\tErrSpWrongNoOfFetchArgs:                     \"Incorrect number of FETCH variables\",\n\tErrSpFetchNoData:                            \"No data - zero rows fetched, selected, or processed\",\n\tErrSpDupParam:                               \"Duplicate parameter: %s\",\n\tErrSpDupVar:                                 \"Duplicate variable: %s\",\n\tErrSpDupCond:                                \"Duplicate condition: %s\",\n\tErrSpDupCurs:                                \"Duplicate cursor: %s\",\n\tErrSpCantAlter:                              \"Failed to ALTER %s %s\",\n\tErrSpSubselectNyi:                           \"Subquery value not supported\",\n\tErrStmtNotAllowedInSfOrTrg:                  \"%s is not allowed in stored function or trigger\",\n\tErrSpVarcondAfterCurshndlr:                  \"Variable or condition declaration after cursor or handler declaration\",\n\tErrSpCursorAfterHandler:                     \"Cursor declaration after handler declaration\",\n\tErrSpCaseNotFound:                           \"Case not found for CASE statement\",\n\tErrFparserTooBigFile:                        \"Configuration file '%-.192s' is too big\",\n\tErrFparserBadHeader:                         \"Malformed file type header in file '%-.192s'\",\n\tErrFparserEOFInComment:                      \"Unexpected end of file while parsing comment '%-.200s'\",\n\tErrFparserErrorInParameter:                  \"Error while parsing parameter '%-.192s' (line: '%-.192s')\",\n\tErrFparserEOFInUnknownParameter:             \"Unexpected end of file while skipping unknown parameter '%-.192s'\",\n\tErrViewNoExplain:                            \"EXPLAIN/SHOW can not be issued; lacking privileges for underlying table\",\n\tErrFrmUnknownType:                           \"File '%-.192s' has unknown type '%-.64s' in its header\",\n\tErrWrongObject:                              \"'%-.192s.%-.192s' is not %s\",\n\tErrNonupdateableColumn:                      \"Column '%-.192s' is not updatable\",\n\tErrViewSelectDerived:                        \"View's SELECT contains a subquery in the FROM clause\",\n\tErrViewSelectClause:                         \"View's SELECT contains a '%s' clause\",\n\tErrViewSelectVariable:                       \"View's SELECT contains a variable or parameter\",\n\tErrViewSelectTmptable:                       \"View's SELECT refers to a temporary table '%-.192s'\",\n\tErrViewWrongList:                            \"View's SELECT and view's field list have different column counts\",\n\tErrWarnViewMerge:                            \"View merge algorithm can't be used here for now (assumed undefined algorithm)\",\n\tErrWarnViewWithoutKey:                       \"View being updated does not have complete key of underlying table in it\",\n\tErrViewInvalid:                              \"View '%-.192s.%-.192s' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them\",\n\tErrSpNoDropSp:                               \"Can't drop or alter a %s from within another stored routine\",\n\tErrSpGotoInHndlr:                            \"GOTO is not allowed in a stored procedure handler\",\n\tErrTrgAlreadyExists:                         \"Trigger already exists\",\n\tErrTrgDoesNotExist:                          \"Trigger does not exist\",\n\tErrTrgOnViewOrTempTable:                     \"Trigger's '%-.192s' is view or temporary table\",\n\tErrTrgCantChangeRow:                         \"Updating of %s row is not allowed in %strigger\",\n\tErrTrgNoSuchRowInTrg:                        \"There is no %s row in %s trigger\",\n\tErrNoDefaultForField:                        \"Field '%-.192s' doesn't have a default value\",\n\tErrDivisionByZero:                           \"Division by 0\",\n\tErrTruncatedWrongValueForField:              \"Incorrect %-.32s value: '%-.128s' for column '%.192s' at row %d\",\n\tErrIllegalValueForType:                      \"Illegal %s '%-.192s' value found during parsing\",\n\tErrViewNonupdCheck:                          \"CHECK OPTION on non-updatable view '%-.192s.%-.192s'\",\n\tErrViewCheckFailed:                          \"CHECK OPTION failed '%-.192s.%-.192s'\",\n\tErrProcaccessDenied:                         \"%-.16s command denied to user '%-.48s'@'%-.64s' for routine '%-.192s'\",\n\tErrRelayLogFail:                             \"Failed purging old relay logs: %s\",\n\tErrPasswdLength:                             \"Password hash should be a %d-digit hexadecimal number\",\n\tErrUnknownTargetBinlog:                      \"Target log not found in binlog index\",\n\tErrIoErrLogIndexRead:                        \"I/O error reading log index file\",\n\tErrBinlogPurgeProhibited:                    \"Server configuration does not permit binlog purge\",\n\tErrFseekFail:                                \"Failed on fseek()\",\n\tErrBinlogPurgeFatalErr:                      \"Fatal error during log purge\",\n\tErrLogInUse:                                 \"A purgeable log is in use, will not purge\",\n\tErrLogPurgeUnknownErr:                       \"Unknown error during log purge\",\n\tErrRelayLogInit:                             \"Failed initializing relay log position: %s\",\n\tErrNoBinaryLogging:                          \"You are not using binary logging\",\n\tErrReservedSyntax:                           \"The '%-.64s' syntax is reserved for purposes internal to the MySQL server\",\n\tErrWsasFailed:                               \"WSAStartup Failed\",\n\tErrDiffGroupsProc:                           \"Can't handle procedures with different groups yet\",\n\tErrNoGroupForProc:                           \"Select must have a group with this procedure\",\n\tErrOrderWithProc:                            \"Can't use ORDER clause with this procedure\",\n\tErrLoggingProhibitChangingOf:                \"Binary logging and replication forbid changing the global server %s\",\n\tErrNoFileMapping:                            \"Can't map file: %-.200s, errno: %d\",\n\tErrWrongMagic:                               \"Wrong magic in %-.64s\",\n\tErrPsManyParam:                              \"Prepared statement contains too many placeholders\",\n\tErrKeyPart0:                                 \"Key part '%-.192s' length cannot be 0\",\n\tErrViewChecksum:                             \"View text checksum failed\",\n\tErrViewMultiupdate:                          \"Can not modify more than one base table through a join view '%-.192s.%-.192s'\",\n\tErrViewNoInsertFieldList:                    \"Can not insert into join view '%-.192s.%-.192s' without fields list\",\n\tErrViewDeleteMergeView:                      \"Can not delete from join view '%-.192s.%-.192s'\",\n\tErrCannotUser:                               \"Operation %s failed for %.256s\",\n\tErrXaerNota:                                 \"XAERNOTA: Unknown XID\",\n\tErrXaerInval:                                \"XAERINVAL: Invalid arguments (or unsupported command)\",\n\tErrXaerRmfail:                               \"XAERRMFAIL: The command cannot be executed when global transaction is in the  %.64s state\",\n\tErrXaerOutside:                              \"XAEROUTSIDE: Some work is done outside global transaction\",\n\tErrXaerRmerr:                                \"XAERRMERR: Fatal error occurred in the transaction branch - check your data for consistency\",\n\tErrXaRbrollback:                             \"XARBROLLBACK: Transaction branch was rolled back\",\n\tErrNonexistingProcGrant:                     \"There is no such grant defined for user '%-.48s' on host '%-.64s' on routine '%-.192s'\",\n\tErrProcAutoGrantFail:                        \"Failed to grant EXECUTE and ALTER ROUTINE privileges\",\n\tErrProcAutoRevokeFail:                       \"Failed to revoke all privileges to dropped routine\",\n\tErrDataTooLong:                              \"Data too long for column '%s' at row %d\",\n\tErrSpBadSQLstate:                            \"Bad SQLSTATE: '%s'\",\n\tErrStartup:                                  \"%s: ready for connections.\\nVersion: '%s'  socket: '%s'  port: %d  %s\",\n\tErrLoadFromFixedSizeRowsToVar:               \"Can't load value from file with fixed size rows to variable\",\n\tErrCantCreateUserWithGrant:                  \"You are not allowed to create a user with GRANT\",\n\tErrWrongValueForType:                        \"Incorrect %-.32s value: '%-.128s' for function %-.32s\",\n\tErrTableDefChanged:                          \"Table definition has changed, please retry transaction\",\n\tErrSpDupHandler:                             \"Duplicate handler declared in the same block\",\n\tErrSpNotVarArg:                              \"OUT or INOUT argument %d for routine %s is not a variable or NEW pseudo-variable in BEFORE trigger\",\n\tErrSpNoRetset:                               \"Not allowed to return a result set from a %s\",\n\tErrCantCreateGeometryObject:                 \"Cannot get geometry object from data you send to the GEOMETRY field\",\n\tErrFailedRoutineBreakBinlog:                 \"A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes\",\n\tErrBinlogUnsafeRoutine:                      \"This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe logBinTrustFunctionCreators variable)\",\n\tErrBinlogCreateRoutineNeedSuper:             \"You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe logBinTrustFunctionCreators variable)\",\n\tErrExecStmtWithOpenCursor:                   \"You can't execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it.\",\n\tErrStmtHasNoOpenCursor:                      \"The statement (%d) has no open cursor.\",\n\tErrCommitNotAllowedInSfOrTrg:                \"Explicit or implicit commit is not allowed in stored function or trigger.\",\n\tErrNoDefaultForViewField:                    \"Field of view '%-.192s.%-.192s' underlying table doesn't have a default value\",\n\tErrSpNoRecursion:                            \"Recursive stored functions and triggers are not allowed.\",\n\tErrTooBigScale:                              \"Too big scale %d specified for column '%-.192s'. Maximum is %d.\",\n\tErrTooBigPrecision:                          \"Too big precision %d specified for column '%-.192s'. Maximum is %d.\",\n\tErrMBiggerThanD:                             \"For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s').\",\n\tErrWrongLockOfSystemTable:                   \"You can't combine write-locking of system tables with other tables or lock types\",\n\tErrConnectToForeignDataSource:               \"Unable to connect to foreign data source: %.64s\",\n\tErrQueryOnForeignDataSource:                 \"There was a problem processing the query on the foreign data source. Data source : %-.64s\",\n\tErrForeignDataSourceDoesntExist:             \"The foreign data source you are trying to reference does not exist. Data source :  %-.64s\",\n\tErrForeignDataStringInvalidCantCreate:       \"Can't create federated table. The data source connection string '%-.64s' is not in the correct format\",\n\tErrForeignDataStringInvalid:                 \"The data source connection string '%-.64s' is not in the correct format\",\n\tErrCantCreateFederatedTable:                 \"Can't create federated table. Foreign data src :  %-.64s\",\n\tErrTrgInWrongSchema:                         \"Trigger in wrong schema\",\n\tErrStackOverrunNeedMore:                     \"Thread stack overrun:  %d bytes used of a %d byte stack, and %d bytes needed.  Use 'mysqld --threadStack=#' to specify a bigger stack.\",\n\tErrTooLongBody:                              \"Routine body for '%-.100s' is too long\",\n\tErrWarnCantDropDefaultKeycache:              \"Cannot drop default keycache\",\n\tErrTooBigDisplaywidth:                       \"Display width out of range for column '%-.192s' (max = %d)\",\n\tErrXaerDupid:                                \"XAERDUPID: The XID already exists\",\n\tErrDatetimeFunctionOverflow:                 \"Datetime function: %-.32s field overflow\",\n\tErrCantUpdateUsedTableInSfOrTrg:             \"Can't update table '%-.192s' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.\",\n\tErrViewPreventUpdate:                        \"The definition of table '%-.192s' prevents operation %.192s on table '%-.192s'.\",\n\tErrPsNoRecursion:                            \"The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner\",\n\tErrSpCantSetAutocommit:                      \"Not allowed to set autocommit from a stored function or trigger\",\n\tErrMalformedDefiner:                         \"Definer is not fully qualified\",\n\tErrViewFrmNoUser:                            \"View '%-.192s'.'%-.192s' has no definer information (old table format). Current user is used as definer. Please recreate the view!\",\n\tErrViewOtherUser:                            \"You need the SUPER privilege for creation view with '%-.192s'@'%-.192s' definer\",\n\tErrNoSuchUser:                               \"The user specified as a definer ('%-.64s'@'%-.64s') does not exist\",\n\tErrForbidSchemaChange:                       \"Changing schema from '%-.192s' to '%-.192s' is not allowed.\",\n\tErrRowIsReferenced2:                         \"Cannot delete or update a parent row: a foreign key constraint fails (%.192s)\",\n\tErrNoReferencedRow2:                         \"Cannot add or update a child row: a foreign key constraint fails (%.192s)\",\n\tErrSpBadVarShadow:                           \"Variable '%-.64s' must be quoted with `...`, or renamed\",\n\tErrTrgNoDefiner:                             \"No definer attribute for trigger '%-.192s'.'%-.192s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.\",\n\tErrOldFileFormat:                            \"'%-.192s' has an old format, you should re-create the '%s' object(s)\",\n\tErrSpRecursionLimit:                         \"Recursive limit %d (as set by the maxSpRecursionDepth variable) was exceeded for routine %.192s\",\n\tErrSpProcTableCorrupt:                       \"Failed to load routine %-.192s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)\",\n\tErrSpWrongName:                              \"Incorrect routine name '%-.192s'\",\n\tErrTableNeedsUpgrade:                        \"Table upgrade required. Please do \\\"REPAIR TABLE `%-.32s`\\\"\",\n\tErrSpNoAggregate:                            \"AGGREGATE is not supported for stored functions\",\n\tErrMaxPreparedStmtCountReached:              \"Can't create more than maxPreparedStmtCount statements (current value: %d)\",\n\tErrViewRecursive:                            \"`%-.192s`.`%-.192s` contains view recursion\",\n\tErrNonGroupingFieldUsed:                     \"Non-grouping field '%-.192s' is used in %-.64s clause\",\n\tErrTableCantHandleSpkeys:                    \"The used table type doesn't support SPATIAL indexes\",\n\tErrNoTriggersOnSystemSchema:                 \"Triggers can not be created on system tables\",\n\tErrRemovedSpaces:                            \"Leading spaces are removed from name '%s'\",\n\tErrAutoincReadFailed:                        \"Failed to read auto-increment value from storage engine\",\n\tErrUsername:                                 \"user name\",\n\tErrHostname:                                 \"host name\",\n\tErrWrongStringLength:                        \"String '%-.70s' is too long for %s (should be no longer than %d)\",\n\tErrNonInsertableTable:                       \"The target table %-.100s of the %s is not insertable-into\",\n\tErrAdminWrongMrgTable:                       \"Table '%-.64s' is differently defined or of non-MyISAM type or doesn't exist\",\n\tErrTooHighLevelOfNestingForSelect:           \"Too high level of nesting for select\",\n\tErrNameBecomesEmpty:                         \"Name '%-.64s' has become ''\",\n\tErrAmbiguousFieldTerm:                       \"First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY\",\n\tErrForeignServerExists:                      \"The foreign server, %s, you are trying to create already exists.\",\n\tErrForeignServerDoesntExist:                 \"The foreign server name you are trying to reference does not exist. Data source :  %-.64s\",\n\tErrIllegalHaCreateOption:                    \"Table storage engine '%-.64s' does not support the create option '%.64s'\",\n\tErrPartitionRequiresValues:                  \"Syntax : %-.64s PARTITIONING requires definition of VALUES %-.64s for each partition\",\n\tErrPartitionWrongValues:                     \"Only %-.64s PARTITIONING can use VALUES %-.64s in partition definition\",\n\tErrPartitionMaxvalue:                        \"MAXVALUE can only be used in last partition definition\",\n\tErrPartitionSubpartition:                    \"Subpartitions can only be hash partitions and by key\",\n\tErrPartitionSubpartMix:                      \"Must define subpartitions on all partitions if on one partition\",\n\tErrPartitionWrongNoPart:                     \"Wrong number of partitions defined, mismatch with previous setting\",\n\tErrPartitionWrongNoSubpart:                  \"Wrong number of subpartitions defined, mismatch with previous setting\",\n\tErrWrongExprInPartitionFunc:                 \"Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed\",\n\tErrNoConstExprInRangeOrList:                 \"Expression in RANGE/LIST VALUES must be constant\",\n\tErrFieldNotFoundPart:                        \"Field in list of fields for partition function not found in table\",\n\tErrListOfFieldsOnlyInHash:                   \"List of fields is only allowed in KEY partitions\",\n\tErrInconsistentPartitionInfo:                \"The partition info in the frm file is not consistent with what can be written into the frm file\",\n\tErrPartitionFuncNotAllowed:                  \"The %-.192s function returns the wrong type\",\n\tErrPartitionsMustBeDefined:                  \"For %-.64s partitions each partition must be defined\",\n\tErrRangeNotIncreasing:                       \"VALUES LESS THAN value must be strictly increasing for each partition\",\n\tErrInconsistentTypeOfFunctions:              \"VALUES value must be of same type as partition function\",\n\tErrMultipleDefConstInListPart:               \"Multiple definition of same constant in list partitioning\",\n\tErrPartitionEntry:                           \"Partitioning can not be used stand-alone in query\",\n\tErrMixHandler:                               \"The mix of handlers in the partitions is not allowed in this version of MySQL\",\n\tErrPartitionNotDefined:                      \"For the partitioned engine it is necessary to define all %-.64s\",\n\tErrTooManyPartitions:                        \"Too many partitions (including subpartitions) were defined\",\n\tErrSubpartition:                             \"It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning\",\n\tErrCantCreateHandlerFile:                    \"Failed to create specific handler file\",\n\tErrBlobFieldInPartFunc:                      \"A BLOB field is not allowed in partition function\",\n\tErrUniqueKeyNeedAllFieldsInPf:               \"A %-.192s must include all columns in the table's partitioning function\",\n\tErrNoParts:                                  \"Number of %-.64s = 0 is not an allowed value\",\n\tErrPartitionMgmtOnNonpartitioned:            \"Partition management on a not partitioned table is not possible\",\n\tErrForeignKeyOnPartitioned:                  \"Foreign key clause is not yet supported in conjunction with partitioning\",\n\tErrDropPartitionNonExistent:                 \"Error in list of partitions to %-.64s\",\n\tErrDropLastPartition:                        \"Cannot remove all partitions, use DROP TABLE instead\",\n\tErrCoalesceOnlyOnHashPartition:              \"COALESCE PARTITION can only be used on HASH/KEY partitions\",\n\tErrReorgHashOnlyOnSameNo:                    \"REORGANIZE PARTITION can only be used to reorganize partitions not to change their numbers\",\n\tErrReorgNoParam:                             \"REORGANIZE PARTITION without parameters can only be used on auto-partitioned tables using HASH PARTITIONs\",\n\tErrOnlyOnRangeListPartition:                 \"%-.64s PARTITION can only be used on RANGE/LIST partitions\",\n\tErrAddPartitionSubpart:                      \"Trying to Add partition(s) with wrong number of subpartitions\",\n\tErrAddPartitionNoNewPartition:               \"At least one partition must be added\",\n\tErrCoalescePartitionNoPartition:             \"At least one partition must be coalesced\",\n\tErrReorgPartitionNotExist:                   \"More partitions to reorganize than there are partitions\",\n\tErrSameNamePartition:                        \"Duplicate partition name %-.192s\",\n\tErrNoBinlog:                                 \"It is not allowed to shut off binlog on this command\",\n\tErrConsecutiveReorgPartitions:               \"When reorganizing a set of partitions they must be in consecutive order\",\n\tErrReorgOutsideRange:                        \"Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range\",\n\tErrPartitionFunctionFailure:                 \"Partition function not supported in this version for this handler\",\n\tErrPartState:                                \"Partition state cannot be defined from CREATE/ALTER TABLE\",\n\tErrLimitedPartRange:                         \"The %-.64s handler only supports 32 bit integers in VALUES\",\n\tErrPluginIsNotLoaded:                        \"Plugin '%-.192s' is not loaded\",\n\tErrWrongValue:                               \"Incorrect %-.32s value: '%-.128s'\",\n\tErrNoPartitionForGivenValue:                 \"Table has no partition for value %-.64s\",\n\tErrFilegroupOptionOnlyOnce:                  \"It is not allowed to specify %s more than once\",\n\tErrCreateFilegroupFailed:                    \"Failed to create %s\",\n\tErrDropFilegroupFailed:                      \"Failed to drop %s\",\n\tErrTablespaceAutoExtend:                     \"The handler doesn't support autoextend of tablespaces\",\n\tErrWrongSizeNumber:                          \"A size parameter was incorrectly specified, either number or on the form 10M\",\n\tErrSizeOverflow:                             \"The size number was correct but we don't allow the digit part to be more than 2 billion\",\n\tErrAlterFilegroupFailed:                     \"Failed to alter: %s\",\n\tErrBinlogRowLoggingFailed:                   \"Writing one row to the row-based binary log failed\",\n\tErrBinlogRowWrongTableDef:                   \"Table definition on master and slave does not match: %s\",\n\tErrBinlogRowRbrToSbr:                        \"Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events\",\n\tErrEventAlreadyExists:                       \"Event '%-.192s' already exists\",\n\tErrEventStoreFailed:                         \"Failed to store event %s. Error code %d from storage engine.\",\n\tErrEventDoesNotExist:                        \"Unknown event '%-.192s'\",\n\tErrEventCantAlter:                           \"Failed to alter event '%-.192s'\",\n\tErrEventDropFailed:                          \"Failed to drop %s\",\n\tErrEventIntervalNotPositiveOrTooBig:         \"INTERVAL is either not positive or too big\",\n\tErrEventEndsBeforeStarts:                    \"ENDS is either invalid or before STARTS\",\n\tErrEventExecTimeInThePast:                   \"Event execution time is in the past. Event has been disabled\",\n\tErrEventOpenTableFailed:                     \"Failed to open mysql.event\",\n\tErrEventNeitherMExprNorMAt:                  \"No datetime expression provided\",\n\tErrObsoleteColCountDoesntMatchCorrupted:     \"Column count of mysql.%s is wrong. Expected %d, found %d. The table is probably corrupted\",\n\tErrObsoleteCannotLoadFromTable:              \"Cannot load from mysql.%s. The table is probably corrupted\",\n\tErrEventCannotDelete:                        \"Failed to delete the event from mysql.event\",\n\tErrEventCompile:                             \"Error during compilation of event's body\",\n\tErrEventSameName:                            \"Same old and new event name\",\n\tErrEventDataTooLong:                         \"Data for column '%s' too long\",\n\tErrDropIndexFk:                              \"Cannot drop index '%-.192s': needed in a foreign key constraint\",\n\tErrWarnDeprecatedSyntaxWithVer:              \"The syntax '%s' is deprecated and will be removed in MySQL %s. Please use %s instead\",\n\tErrCantWriteLockLogTable:                    \"You can't write-lock a log table. Only read access is possible\",\n\tErrCantLockLogTable:                         \"You can't use locks with log tables.\",\n\tErrForeignDuplicateKeyOldUnused:             \"Upholding foreign key constraints for table '%.192s', entry '%-.192s', key %d would lead to a duplicate entry\",\n\tErrColCountDoesntMatchPleaseUpdate:          \"Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use mysqlUpgrade to fix this error.\",\n\tErrTempTablePreventsSwitchOutOfRbr:          \"Cannot switch out of the row-based binary log format when the session has open temporary tables\",\n\tErrStoredFunctionPreventsSwitchBinlogFormat: \"Cannot change the binary logging format inside a stored function or trigger\",\n\tErrNdbCantSwitchBinlogFormat:                \"The NDB cluster engine does not support changing the binlog format on the fly yet\",\n\tErrPartitionNoTemporary:                     \"Cannot create temporary table with partitions\",\n\tErrPartitionConstDomain:                     \"Partition constant is out of partition function domain\",\n\tErrPartitionFunctionIsNotAllowed:            \"This partition function is not allowed\",\n\tErrDdlLog:                                   \"Error in DDL log\",\n\tErrNullInValuesLessThan:                     \"Not allowed to use NULL value in VALUES LESS THAN\",\n\tErrWrongPartitionName:                       \"Incorrect partition name\",\n\tErrCantChangeTxCharacteristics:              \"Transaction characteristics can't be changed while a transaction is in progress\",\n\tErrDupEntryAutoincrementCase:                \"ALTER TABLE causes autoIncrement resequencing, resulting in duplicate entry '%-.192s' for key '%-.192s'\",\n\tErrEventModifyQueue:                         \"Internal scheduler error %d\",\n\tErrEventSetVar:                              \"Error during starting/stopping of the scheduler. Error code %d\",\n\tErrPartitionMerge:                           \"Engine cannot be used in partitioned tables\",\n\tErrCantActivateLog:                          \"Cannot activate '%-.64s' log\",\n\tErrRbrNotAvailable:                          \"The server was not built with row-based replication\",\n\tErrBase64Decode:                             \"Decoding of base64 string failed\",\n\tErrEventRecursionForbidden:                  \"Recursion of EVENT DDL statements is forbidden when body is present\",\n\tErrEventsDB:                                 \"Cannot proceed because system tables used by Event Scheduler were found damaged at server start\",\n\tErrOnlyIntegersAllowed:                      \"Only integers allowed as number here\",\n\tErrUnsuportedLogEngine:                      \"This storage engine cannot be used for log tables\\\"\",\n\tErrBadLogStatement:                          \"You cannot '%s' a log table if logging is enabled\",\n\tErrCantRenameLogTable:                       \"Cannot rename '%s'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to '%s'\",\n\tErrWrongParamcountToNativeFct:               \"Incorrect parameter count in the call to native function '%-.192s'\",\n\tErrWrongParametersToNativeFct:               \"Incorrect parameters in the call to native function '%-.192s'\",\n\tErrWrongParametersToStoredFct:               \"Incorrect parameters in the call to stored function '%-.192s'\",\n\tErrNativeFctNameCollision:                   \"This function '%-.192s' has the same name as a native function\",\n\tErrDupEntryWithKeyName:                      \"Duplicate entry '%-.64s' for key '%-.192s'\",\n\tErrBinlogPurgeEmFile:                        \"Too many files opened, please execute the command again\",\n\tErrEventCannotCreateInThePast:               \"Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation.\",\n\tErrEventCannotAlterInThePast:                \"Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was not changed. Specify a time in the future.\",\n\tErrSlaveIncident:                            \"The incident %s occurred on the master. Message: %-.64s\",\n\tErrNoPartitionForGivenValueSilent:           \"Table has no partition for some existing values\",\n\tErrBinlogUnsafeStatement:                    \"Unsafe statement written to the binary log using statement format since BINLOGFORMAT = STATEMENT. %s\",\n\tErrSlaveFatal:                               \"Fatal : %s\",\n\tErrSlaveRelayLogReadFailure:                 \"Relay log read failure: %s\",\n\tErrSlaveRelayLogWriteFailure:                \"Relay log write failure: %s\",\n\tErrSlaveCreateEventFailure:                  \"Failed to create %s\",\n\tErrSlaveMasterComFailure:                    \"Master command %s failed: %s\",\n\tErrBinlogLoggingImpossible:                  \"Binary logging not possible. Message: %s\",\n\tErrViewNoCreationCtx:                        \"View `%-.64s`.`%-.64s` has no creation context\",\n\tErrViewInvalidCreationCtx:                   \"Creation context of view `%-.64s`.`%-.64s' is invalid\",\n\tErrSrInvalidCreationCtx:                     \"Creation context of stored routine `%-.64s`.`%-.64s` is invalid\",\n\tErrTrgCorruptedFile:                         \"Corrupted TRG file for table `%-.64s`.`%-.64s`\",\n\tErrTrgNoCreationCtx:                         \"Triggers for table `%-.64s`.`%-.64s` have no creation context\",\n\tErrTrgInvalidCreationCtx:                    \"Trigger creation context of table `%-.64s`.`%-.64s` is invalid\",\n\tErrEventInvalidCreationCtx:                  \"Creation context of event `%-.64s`.`%-.64s` is invalid\",\n\tErrTrgCantOpenTable:                         \"Cannot open table for trigger `%-.64s`.`%-.64s`\",\n\tErrCantCreateSroutine:                       \"Cannot create stored routine `%-.64s`. Check warnings\",\n\tErrNeverUsed:                                \"Ambiguous slave modes combination. %s\",\n\tErrNoFormatDescriptionEventBeforeBinlogStatement:         \"The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement.\",\n\tErrSlaveCorruptEvent:                                     \"Corrupted replication event was detected\",\n\tErrLoadDataInvalidColumn:                                 \"Invalid column reference (%-.64s) in LOAD DATA\",\n\tErrLogPurgeNoFile:                                        \"Being purged log %s was not found\",\n\tErrXaRbtimeout:                                           \"XARBTIMEOUT: Transaction branch was rolled back: took too long\",\n\tErrXaRbdeadlock:                                          \"XARBDEADLOCK: Transaction branch was rolled back: deadlock was detected\",\n\tErrNeedReprepare:                                         \"Prepared statement needs to be re-prepared\",\n\tErrDelayedNotSupported:                                   \"DELAYED option not supported for table '%-.192s'\",\n\tWarnNoMasterInfo:                                         \"The master info structure does not exist\",\n\tWarnOptionIgnored:                                        \"<%-.64s> option ignored\",\n\tWarnPluginDeleteBuiltin:                                  \"Built-in plugins cannot be deleted\",\n\tWarnPluginBusy:                                           \"Plugin is busy and will be uninstalled on shutdown\",\n\tErrVariableIsReadonly:                                    \"%s variable '%s' is read-only. Use SET %s to assign the value\",\n\tErrWarnEngineTransactionRollback:                         \"Storage engine %s does not support rollback for this statement. Transaction rolled back and must be restarted\",\n\tErrSlaveHeartbeatFailure:                                 \"Unexpected master's heartbeat data: %s\",\n\tErrSlaveHeartbeatValueOutOfRange:                         \"The requested value for the heartbeat period is either negative or exceeds the maximum allowed (%s seconds).\",\n\tErrNdbReplicationSchema:                                  \"Bad schema for mysql.ndbReplication table. Message: %-.64s\",\n\tErrConflictFnParse:                                       \"Error in parsing conflict function. Message: %-.64s\",\n\tErrExceptionsWrite:                                       \"Write to exceptions table failed. Message: %-.128s\\\"\",\n\tErrTooLongTableComment:                                   \"Comment for table '%-.64s' is too long (max = %d)\",\n\tErrTooLongFieldComment:                                   \"Comment for field '%-.64s' is too long (max = %d)\",\n\tErrFuncInexistentNameCollision:                           \"FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual\",\n\tErrDatabaseName:                                          \"Database\",\n\tErrTableName:                                             \"Table\",\n\tErrPartitionName:                                         \"Partition\",\n\tErrSubpartitionName:                                      \"Subpartition\",\n\tErrTemporaryName:                                         \"Temporary\",\n\tErrRenamedName:                                           \"Renamed\",\n\tErrTooManyConcurrentTrxs:                                 \"Too many active concurrent transactions\",\n\tWarnNonASCIISeparatorNotImplemented:                      \"Non-ASCII separator arguments are not fully supported\",\n\tErrDebugSyncTimeout:                                      \"debug sync point wait timed out\",\n\tErrDebugSyncHitLimit:                                     \"debug sync point hit limit reached\",\n\tErrDupSignalSet:                                          \"Duplicate condition information item '%s'\",\n\tErrSignalWarn:                                            \"Unhandled user-defined warning condition\",\n\tErrSignalNotFound:                                        \"Unhandled user-defined not found condition\",\n\tErrSignalException:                                       \"Unhandled user-defined exception condition\",\n\tErrResignalWithoutActiveHandler:                          \"RESIGNAL when handler not active\",\n\tErrSignalBadConditionType:                                \"SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE\",\n\tWarnCondItemTruncated:                                    \"Data truncated for condition item '%s'\",\n\tErrCondItemTooLong:                                       \"Data too long for condition item '%s'\",\n\tErrUnknownLocale:                                         \"Unknown locale: '%-.64s'\",\n\tErrSlaveIgnoreServerIds:                                  \"The requested server id %d clashes with the slave startup option --replicate-same-server-id\",\n\tErrQueryCacheDisabled:                                    \"Query cache is disabled; restart the server with queryCacheType=1 to enable it\",\n\tErrSameNamePartitionField:                                \"Duplicate partition field name '%-.192s'\",\n\tErrPartitionColumnList:                                   \"Inconsistency in usage of column lists for partitioning\",\n\tErrWrongTypeColumnValue:                                  \"Partition column values of incorrect type\",\n\tErrTooManyPartitionFuncFields:                            \"Too many fields in '%-.192s'\",\n\tErrMaxvalueInValuesIn:                                    \"Cannot use MAXVALUE as value in VALUES IN\",\n\tErrTooManyValues:                                         \"Cannot have more than one value for this type of %-.64s partitioning\",\n\tErrRowSinglePartitionField:                               \"Row expressions in VALUES IN only allowed for multi-field column partitioning\",\n\tErrFieldTypeNotAllowedAsPartitionField:                   \"Field '%-.192s' is of a not allowed type for this type of partitioning\",\n\tErrPartitionFieldsTooLong:                                \"The total length of the partitioning fields is too large\",\n\tErrBinlogRowEngineAndStmtEngine:                          \"Cannot execute statement: impossible to write to binary log since both row-incapable engines and statement-incapable engines are involved.\",\n\tErrBinlogRowModeAndStmtEngine:                            \"Cannot execute statement: impossible to write to binary log since BINLOGFORMAT = ROW and at least one table uses a storage engine limited to statement-based logging.\",\n\tErrBinlogUnsafeAndStmtEngine:                             \"Cannot execute statement: impossible to write to binary log since statement is unsafe, storage engine is limited to statement-based logging, and BINLOGFORMAT = MIXED. %s\",\n\tErrBinlogRowInjectionAndStmtEngine:                       \"Cannot execute statement: impossible to write to binary log since statement is in row format and at least one table uses a storage engine limited to statement-based logging.\",\n\tErrBinlogStmtModeAndRowEngine:                            \"Cannot execute statement: impossible to write to binary log since BINLOGFORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging.%s\",\n\tErrBinlogRowInjectionAndStmtMode:                         \"Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOGFORMAT = STATEMENT.\",\n\tErrBinlogMultipleEnginesAndSelfLoggingEngine:             \"Cannot execute statement: impossible to write to binary log since more than one engine is involved and at least one engine is self-logging.\",\n\tErrBinlogUnsafeLimit:                                     \"The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted.\",\n\tErrBinlogUnsafeInsertDelayed:                             \"The statement is unsafe because it uses INSERT DELAYED. This is unsafe because the times when rows are inserted cannot be predicted.\",\n\tErrBinlogUnsafeSystemTable:                               \"The statement is unsafe because it uses the general log, slow query log, or performanceSchema table(s). This is unsafe because system tables may differ on slaves.\",\n\tErrBinlogUnsafeAutoincColumns:                            \"Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTOINCREMENT column. Inserted values cannot be logged correctly.\",\n\tErrBinlogUnsafeUdf:                                       \"Statement is unsafe because it uses a UDF which may not return the same value on the slave.\",\n\tErrBinlogUnsafeSystemVariable:                            \"Statement is unsafe because it uses a system variable that may have a different value on the slave.\",\n\tErrBinlogUnsafeSystemFunction:                            \"Statement is unsafe because it uses a system function that may return a different value on the slave.\",\n\tErrBinlogUnsafeNontransAfterTrans:                        \"Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.\",\n\tErrMessageAndStatement:                                   \"%s Statement: %s\",\n\tErrSlaveConversionFailed:                                 \"Column %d of table '%-.192s.%-.192s' cannot be converted from type '%-.32s' to type '%-.32s'\",\n\tErrSlaveCantCreateConversion:                             \"Can't create conversion table for table '%-.192s.%-.192s'\",\n\tErrInsideTransactionPreventsSwitchBinlogFormat:           \"Cannot modify @@session.binlogFormat inside a transaction\",\n\tErrPathLength:                                            \"The path specified for %.64s is too long.\",\n\tErrWarnDeprecatedSyntaxNoReplacement:                     \"'%s' is deprecated and will be removed in a future release.\",\n\tErrWrongNativeTableStructure:                             \"Native table '%-.64s'.'%-.64s' has the wrong structure\",\n\tErrWrongPerfSchemaUsage:                                  \"Invalid performanceSchema usage.\",\n\tErrWarnISSkippedTable:                                    \"Table '%s'.'%s' was skipped since its definition is being modified by concurrent DDL statement\",\n\tErrInsideTransactionPreventsSwitchBinlogDirect:           \"Cannot modify @@session.binlogDirectNonTransactionalUpdates inside a transaction\",\n\tErrStoredFunctionPreventsSwitchBinlogDirect:              \"Cannot change the binlog direct flag inside a stored function or trigger\",\n\tErrSpatialMustHaveGeomCol:                                \"A SPATIAL index may only contain a geometrical type column\",\n\tErrTooLongIndexComment:                                   \"Comment for index '%-.64s' is too long (max = %d)\",\n\tErrLockAborted:                                           \"Wait on a lock was aborted due to a pending exclusive lock\",\n\tErrDataOutOfRange:                                        \"%s value is out of range in '%s'\",\n\tErrWrongSpvarTypeInLimit:                                 \"A variable of a non-integer based type in LIMIT clause\",\n\tErrBinlogUnsafeMultipleEnginesAndSelfLoggingEngine:       \"Mixing self-logging and non-self-logging engines in a statement is unsafe.\",\n\tErrBinlogUnsafeMixedStatement:                            \"Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.\",\n\tErrInsideTransactionPreventsSwitchSQLLogBin:              \"Cannot modify @@session.sqlLogBin inside a transaction\",\n\tErrStoredFunctionPreventsSwitchSQLLogBin:                 \"Cannot change the sqlLogBin inside a stored function or trigger\",\n\tErrFailedReadFromParFile:                                 \"Failed to read from the .par file\",\n\tErrValuesIsNotIntType:                                    \"VALUES value for partition '%-.64s' must have type INT\",\n\tErrAccessDeniedNoPassword:                                \"Access denied for user '%-.48s'@'%-.64s'\",\n\tErrSetPasswordAuthPlugin:                                 \"SET PASSWORD has no significance for users authenticating via plugins\",\n\tErrGrantPluginUserExists:                                 \"GRANT with IDENTIFIED WITH is illegal because the user %-.*s already exists\",\n\tErrTruncateIllegalFk:                                     \"Cannot truncate a table referenced in a foreign key constraint (%.192s)\",\n\tErrPluginIsPermanent:                                     \"Plugin '%s' is forcePlusPermanent and can not be unloaded\",\n\tErrSlaveHeartbeatValueOutOfRangeMin:                      \"The requested value for the heartbeat period is less than 1 millisecond. The value is reset to 0, meaning that heartbeating will effectively be disabled.\",\n\tErrSlaveHeartbeatValueOutOfRangeMax:                      \"The requested value for the heartbeat period exceeds the value of `slaveNetTimeout' seconds. A sensible value for the period should be less than the timeout.\",\n\tErrStmtCacheFull:                                         \"Multi-row statements required more than 'maxBinlogStmtCacheSize' bytes of storage; increase this mysqld variable and try again\",\n\tErrMultiUpdateKeyConflict:                                \"Primary key/partition key update is not allowed since the table is updated both as '%-.192s' and '%-.192s'.\",\n\tErrTableNeedsRebuild:                                     \"Table rebuild required. Please do \\\"ALTER TABLE `%-.32s` FORCE\\\" or dump/reload to fix it!\",\n\tWarnOptionBelowLimit:                                     \"The value of '%s' should be no less than the value of '%s'\",\n\tErrIndexColumnTooLong:                                    \"Index column size too large. The maximum column size is %d bytes.\",\n\tErrErrorInTriggerBody:                                    \"Trigger '%-.64s' has an error in its body: '%-.256s'\",\n\tErrErrorInUnknownTriggerBody:                             \"Unknown trigger has an error in its body: '%-.256s'\",\n\tErrIndexCorrupt:                                          \"Index %s is corrupted\",\n\tErrUndoRecordTooBig:                                      \"Undo log record is too big.\",\n\tErrBinlogUnsafeInsertIgnoreSelect:                        \"INSERT IGNORE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave.\",\n\tErrBinlogUnsafeInsertSelectUpdate:                        \"INSERT... SELECT... ON DUPLICATE KEY UPDATE is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are updated. This order cannot be predicted and may differ on master and the slave.\",\n\tErrBinlogUnsafeReplaceSelect:                             \"REPLACE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave.\",\n\tErrBinlogUnsafeCreateIgnoreSelect:                        \"CREATE... IGNORE SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave.\",\n\tErrBinlogUnsafeCreateReplaceSelect:                       \"CREATE... REPLACE SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave.\",\n\tErrBinlogUnsafeUpdateIgnore:                              \"UPDATE IGNORE is unsafe because the order in which rows are updated determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave.\",\n\tErrPluginNoUninstall:                                     \"Plugin '%s' is marked as not dynamically uninstallable. You have to stop the server to uninstall it.\",\n\tErrPluginNoInstall:                                       \"Plugin '%s' is marked as not dynamically installable. You have to stop the server to install it.\",\n\tErrBinlogUnsafeWriteAutoincSelect:                        \"Statements writing to a table with an auto-increment column after selecting from another table are unsafe because the order in which rows are retrieved determines what (if any) rows will be written. This order cannot be predicted and may differ on master and the slave.\",\n\tErrBinlogUnsafeCreateSelectAutoinc:                       \"CREATE TABLE... SELECT...  on a table with an auto-increment column is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are inserted. This order cannot be predicted and may differ on master and the slave.\",\n\tErrBinlogUnsafeInsertTwoKeys:                             \"INSERT... ON DUPLICATE KEY UPDATE  on a table with more than one UNIQUE KEY is unsafe\",\n\tErrTableInFkCheck:                                        \"Table is being used in foreign key check.\",\n\tErrUnsupportedEngine:                                     \"Storage engine '%s' does not support system tables. [%s.%s]\",\n\tErrBinlogUnsafeAutoincNotFirst:                           \"INSERT into autoincrement field which is not the first part in the composed primary key is unsafe.\",\n\tErrCannotLoadFromTableV2:                                 \"Cannot load from %s.%s. The table is probably corrupted\",\n\tErrMasterDelayValueOutOfRange:                            \"The requested value %d for the master delay exceeds the maximum %d\",\n\tErrOnlyFdAndRbrEventsAllowedInBinlogStatement:            \"Only FormatDescriptionLogEvent and row events are allowed in BINLOG statements (but %s was provided)\",\n\tErrPartitionExchangeDifferentOption:                      \"Non matching attribute '%-.64s' between partition and table\",\n\tErrPartitionExchangePartTable:                            \"Table to exchange with partition is partitioned: '%-.64s'\",\n\tErrPartitionExchangeTempTable:                            \"Table to exchange with partition is temporary: '%-.64s'\",\n\tErrPartitionInsteadOfSubpartition:                        \"Subpartitioned table, use subpartition instead of partition\",\n\tErrUnknownPartition:                                      \"Unknown partition '%-.64s' in table '%-.64s'\",\n\tErrTablesDifferentMetadata:                               \"Tables have different definitions\",\n\tErrRowDoesNotMatchPartition:                              \"Found a row that does not match the partition\",\n\tErrBinlogCacheSizeGreaterThanMax:                         \"Option binlogCacheSize (%d) is greater than maxBinlogCacheSize (%d); setting binlogCacheSize equal to maxBinlogCacheSize.\",\n\tErrWarnIndexNotApplicable:                                \"Cannot use %-.64s access on index '%-.64s' due to type or collation conversion on field '%-.64s'\",\n\tErrPartitionExchangeForeignKey:                           \"Table to exchange with partition has foreign key references: '%-.64s'\",\n\tErrNoSuchKeyValue:                                        \"Key value '%-.192s' was not found in table '%-.192s.%-.192s'\",\n\tErrRplInfoDataTooLong:                                    \"Data for column '%s' too long\",\n\tErrNetworkReadEventChecksumFailure:                       \"Replication event checksum verification failed while reading from network.\",\n\tErrBinlogReadEventChecksumFailure:                        \"Replication event checksum verification failed while reading from a log file.\",\n\tErrBinlogStmtCacheSizeGreaterThanMax:                     \"Option binlogStmtCacheSize (%d) is greater than maxBinlogStmtCacheSize (%d); setting binlogStmtCacheSize equal to maxBinlogStmtCacheSize.\",\n\tErrCantUpdateTableInCreateTableSelect:                    \"Can't update table '%-.192s' while '%-.192s' is being created.\",\n\tErrPartitionClauseOnNonpartitioned:                       \"PARTITION () clause on non partitioned table\",\n\tErrRowDoesNotMatchGivenPartitionSet:                      \"Found a row not matching the given partition set\",\n\tErrNoSuchPartitionunused:                                 \"partition '%-.64s' doesn't exist\",\n\tErrChangeRplInfoRepositoryFailure:                        \"Failure while changing the type of replication repository: %s.\",\n\tErrWarningNotCompleteRollbackWithCreatedTempTable:        \"The creation of some temporary tables could not be rolled back.\",\n\tErrWarningNotCompleteRollbackWithDroppedTempTable:        \"Some temporary tables were dropped, but these operations could not be rolled back.\",\n\tErrMtsFeatureIsNotSupported:                              \"%s is not supported in multi-threaded slave mode. %s\",\n\tErrMtsUpdatedDBsGreaterMax:                               \"The number of modified databases exceeds the maximum %d; the database names will not be included in the replication event metadata.\",\n\tErrMtsCantParallel:                                       \"Cannot execute the current event group in the parallel mode. Encountered event %s, relay-log name %s, position %s which prevents execution of this event group in parallel mode. Reason: %s.\",\n\tErrMtsInconsistentData:                                   \"%s\",\n\tErrFulltextNotSupportedWithPartitioning:                  \"FULLTEXT index is not supported for partitioned tables.\",\n\tErrDaInvalidConditionNumber:                              \"Invalid condition number\",\n\tErrInsecurePlainText:                                     \"Sending passwords in plain text without SSL/TLS is extremely insecure.\",\n\tErrInsecureChangeMaster:                                  \"Storing MySQL user name or password information in the master.info repository is not secure and is therefore not recommended. Please see the MySQL Manual for more about this issue and possible alternatives.\",\n\tErrForeignDuplicateKeyWithChildInfo:                      \"Foreign key constraint for table '%.192s', record '%-.192s' would lead to a duplicate entry in table '%.192s', key '%.192s'\",\n\tErrForeignDuplicateKeyWithoutChildInfo:                   \"Foreign key constraint for table '%.192s', record '%-.192s' would lead to a duplicate entry in a child table\",\n\tErrSQLthreadWithSecureSlave:                              \"Setting authentication options is not possible when only the Slave SQL Thread is being started.\",\n\tErrTableHasNoFt:                                          \"The table does not have FULLTEXT index to support this query\",\n\tErrVariableNotSettableInSfOrTrigger:                      \"The system variable %.200s cannot be set in stored functions or triggers.\",\n\tErrVariableNotSettableInTransaction:                      \"The system variable %.200s cannot be set when there is an ongoing transaction.\",\n\tErrGtidNextIsNotInGtidNextList:                           \"The system variable @@SESSION.GTIDNEXT has the value %.200s, which is not listed in @@SESSION.GTIDNEXTLIST.\",\n\tErrCantChangeGtidNextInTransactionWhenGtidNextListIsNull: \"When @@SESSION.GTIDNEXTLIST == NULL, the system variable @@SESSION.GTIDNEXT cannot change inside a transaction.\",\n\tErrSetStatementCannotInvokeFunction:                      \"The statement 'SET %.200s' cannot invoke a stored function.\",\n\tErrGtidNextCantBeAutomaticIfGtidNextListIsNonNull:        \"The system variable @@SESSION.GTIDNEXT cannot be 'AUTOMATIC' when @@SESSION.GTIDNEXTLIST is non-NULL.\",\n\tErrSkippingLoggedTransaction:                             \"Skipping transaction %.200s because it has already been executed and logged.\",\n\tErrMalformedGtidSetSpecification:                         \"Malformed GTID set specification '%.200s'.\",\n\tErrMalformedGtidSetEncoding:                              \"Malformed GTID set encoding.\",\n\tErrMalformedGtidSpecification:                            \"Malformed GTID specification '%.200s'.\",\n\tErrGnoExhausted:                                          \"Impossible to generate Global Transaction Identifier: the integer component reached the maximal value. Restart the server with a new serverUuid.\",\n\tErrBadSlaveAutoPosition:                                  \"Parameters MASTERLOGFILE, MASTERLOGPOS, RELAYLOGFILE and RELAYLOGPOS cannot be set when MASTERAUTOPOSITION is active.\",\n\tErrAutoPositionRequiresGtidModeOn:                        \"CHANGE MASTER TO MASTERAUTOPOSITION = 1 can only be executed when @@GLOBAL.GTIDMODE = ON.\",\n\tErrCantDoImplicitCommitInTrxWhenGtidNextIsSet:            \"Cannot execute statements with implicit commit inside a transaction when @@SESSION.GTIDNEXT != AUTOMATIC or @@SESSION.GTIDNEXTLIST != NULL.\",\n\tErrGtidMode2Or3RequiresEnforceGtidConsistencyOn:          \"@@GLOBAL.GTIDMODE = ON or UPGRADESTEP2 requires @@GLOBAL.ENFORCEGTIDCONSISTENCY = 1.\",\n\tErrGtidModeRequiresBinlog:                                \"@@GLOBAL.GTIDMODE = ON or UPGRADESTEP1 or UPGRADESTEP2 requires --log-bin and --log-slave-updates.\",\n\tErrCantSetGtidNextToGtidWhenGtidModeIsOff:                \"@@SESSION.GTIDNEXT cannot be set to UUID:NUMBER when @@GLOBAL.GTIDMODE = OFF.\",\n\tErrCantSetGtidNextToAnonymousWhenGtidModeIsOn:            \"@@SESSION.GTIDNEXT cannot be set to ANONYMOUS when @@GLOBAL.GTIDMODE = ON.\",\n\tErrCantSetGtidNextListToNonNullWhenGtidModeIsOff:         \"@@SESSION.GTIDNEXTLIST cannot be set to a non-NULL value when @@GLOBAL.GTIDMODE = OFF.\",\n\tErrFoundGtidEventWhenGtidModeIsOff:                       \"Found a GtidLogEvent or PreviousGtidsLogEvent when @@GLOBAL.GTIDMODE = OFF.\",\n\tErrGtidUnsafeNonTransactionalTable:                       \"When @@GLOBAL.ENFORCEGTIDCONSISTENCY = 1, updates to non-transactional tables can only be done in either autocommitted statements or single-statement transactions, and never in the same statement as updates to transactional tables.\",\n\tErrGtidUnsafeCreateSelect:                                \"CREATE TABLE ... SELECT is forbidden when @@GLOBAL.ENFORCEGTIDCONSISTENCY = 1.\",\n\tErrGtidUnsafeCreateDropTemporaryTableInTransaction:       \"When @@GLOBAL.ENFORCEGTIDCONSISTENCY = 1, the statements CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE can be executed in a non-transactional context only, and require that AUTOCOMMIT = 1.\",\n\tErrGtidModeCanOnlyChangeOneStepAtATime:                   \"The value of @@GLOBAL.GTIDMODE can only change one step at a time: OFF <-> UPGRADESTEP1 <-> UPGRADESTEP2 <-> ON. Also note that this value must be stepped up or down simultaneously on all servers; see the Manual for instructions.\",\n\tErrMasterHasPurgedRequiredGtids:                          \"The slave is connecting using CHANGE MASTER TO MASTERAUTOPOSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.\",\n\tErrCantSetGtidNextWhenOwningGtid:                         \"@@SESSION.GTIDNEXT cannot be changed by a client that owns a GTID. The client owns %s. Ownership is released on COMMIT or ROLLBACK.\",\n\tErrUnknownExplainFormat:                                  \"Unknown EXPLAIN format name: '%s'\",\n\tErrCantExecuteInReadOnlyTransaction:                      \"Cannot execute statement in a READ ONLY transaction.\",\n\tErrTooLongTablePartitionComment:                          \"Comment for table partition '%-.64s' is too long (max = %d)\",\n\tErrSlaveConfiguration:                                    \"Slave is not configured or failed to initialize properly. You must at least set --server-id to enable either a master or a slave. Additional error messages can be found in the MySQL error log.\",\n\tErrInnodbFtLimit:                                         \"InnoDB presently supports one FULLTEXT index creation at a time\",\n\tErrInnodbNoFtTempTable:                                   \"Cannot create FULLTEXT index on temporary InnoDB table\",\n\tErrInnodbFtWrongDocidColumn:                              \"Column '%-.192s' is of wrong type for an InnoDB FULLTEXT index\",\n\tErrInnodbFtWrongDocidIndex:                               \"Index '%-.192s' is of wrong type for an InnoDB FULLTEXT index\",\n\tErrInnodbOnlineLogTooBig:                                 \"Creating index '%-.192s' required more than 'innodbOnlineAlterLogMaxSize' bytes of modification log. Please try again.\",\n\tErrUnknownAlterAlgorithm:                                 \"Unknown ALGORITHM '%s'\",\n\tErrUnknownAlterLock:                                      \"Unknown LOCK type '%s'\",\n\tErrMtsChangeMasterCantRunWithGaps:                        \"CHANGE MASTER cannot be executed when the slave was stopped with an error or killed in MTS mode. Consider using RESET SLAVE or START SLAVE UNTIL.\",\n\tErrMtsRecoveryFailure:                                    \"Cannot recover after SLAVE errored out in parallel execution mode. Additional error messages can be found in the MySQL error log.\",\n\tErrMtsResetWorkers:                                       \"Cannot clean up worker info tables. Additional error messages can be found in the MySQL error log.\",\n\tErrColCountDoesntMatchCorruptedV2:                        \"Column count of %s.%s is wrong. Expected %d, found %d. The table is probably corrupted\",\n\tErrSlaveSilentRetryTransaction:                           \"Slave must silently retry current transaction\",\n\tErrDiscardFkChecksRunning:                                \"There is a foreign key check running on table '%-.192s'. Cannot discard the table.\",\n\tErrTableSchemaMismatch:                                   \"Schema mismatch (%s)\",\n\tErrTableInSystemTablespace:                               \"Table '%-.192s' in system tablespace\",\n\tErrIoRead:                                                \"IO Read : (%d, %s) %s\",\n\tErrIoWrite:                                               \"IO Write : (%d, %s) %s\",\n\tErrTablespaceMissing:                                     \"Tablespace is missing for table '%-.192s'\",\n\tErrTablespaceExists:                                      \"Tablespace for table '%-.192s' exists. Please DISCARD the tablespace before IMPORT.\",\n\tErrTablespaceDiscarded:                                   \"Tablespace has been discarded for table '%-.192s'\",\n\tErrInternal:                                              \"Internal : %s\",\n\tErrInnodbImport:                                          \"ALTER TABLE '%-.192s' IMPORT TABLESPACE failed with error %d : '%s'\",\n\tErrInnodbIndexCorrupt:                                    \"Index corrupt: %s\",\n\tErrInvalidYearColumnLength:                               \"Supports only YEAR or YEAR(4) column\",\n\tErrNotValidPassword:                                      \"Your password does not satisfy the current policy requirements\",\n\tErrMustChangePassword:                                    \"You must SET PASSWORD before executing this statement\",\n\tErrFkNoIndexChild:                                        \"Failed to add the foreign key constaint. Missing index for constraint '%s' in the foreign table '%s'\",\n\tErrFkNoIndexParent:                                       \"Failed to add the foreign key constaint. Missing index for constraint '%s' in the referenced table '%s'\",\n\tErrFkFailAddSystem:                                       \"Failed to add the foreign key constraint '%s' to system tables\",\n\tErrFkCannotOpenParent:                                    \"Failed to open the referenced table '%s'\",\n\tErrFkIncorrectOption:                                     \"Failed to add the foreign key constraint on table '%s'. Incorrect options in FOREIGN KEY constraint '%s'\",\n\tErrFkDupName:                                             \"Duplicate foreign key constraint name '%s'\",\n\tErrPasswordFormat:                                        \"The password hash doesn't have the expected format. Check if the correct password algorithm is being used with the PASSWORD() function.\",\n\tErrFkColumnCannotDrop:                                    \"Cannot drop column '%-.192s': needed in a foreign key constraint '%-.192s'\",\n\tErrFkColumnCannotDropChild:                               \"Cannot drop column '%-.192s': needed in a foreign key constraint '%-.192s' of table '%-.192s'\",\n\tErrFkColumnNotNull:                                       \"Column '%-.192s' cannot be NOT NULL: needed in a foreign key constraint '%-.192s' SET NULL\",\n\tErrDupIndex:                                              \"Duplicate index '%-.64s' defined on the table '%-.64s.%-.64s'. This is deprecated and will be disallowed in a future release.\",\n\tErrFkColumnCannotChange:                                  \"Cannot change column '%-.192s': used in a foreign key constraint '%-.192s'\",\n\tErrFkColumnCannotChangeChild:                             \"Cannot change column '%-.192s': used in a foreign key constraint '%-.192s' of table '%-.192s'\",\n\tErrFkCannotDeleteParent:                                  \"Cannot delete rows from table which is parent in a foreign key constraint '%-.192s' of table '%-.192s'\",\n\tErrMalformedPacket:                                       \"Malformed communication packet.\",\n\tErrReadOnlyMode:                                          \"Running in read-only mode\",\n\tErrGtidNextTypeUndefinedGroup:                            \"When @@SESSION.GTIDNEXT is set to a GTID, you must explicitly set it again after a COMMIT or ROLLBACK. If you see this error message in the slave SQL thread, it means that a table in the current transaction is transactional on the master and non-transactional on the slave. In a client connection, it means that you executed SET @@SESSION.GTIDNEXT before a transaction and forgot to set @@SESSION.GTIDNEXT to a different identifier or to 'AUTOMATIC' after COMMIT or ROLLBACK. Current @@SESSION.GTIDNEXT is '%s'.\",\n\tErrVariableNotSettableInSp:                               \"The system variable %.200s cannot be set in stored procedures.\",\n\tErrCantSetGtidPurgedWhenGtidModeIsOff:                    \"@@GLOBAL.GTIDPURGED can only be set when @@GLOBAL.GTIDMODE = ON.\",\n\tErrCantSetGtidPurgedWhenGtidExecutedIsNotEmpty:           \"@@GLOBAL.GTIDPURGED can only be set when @@GLOBAL.GTIDEXECUTED is empty.\",\n\tErrCantSetGtidPurgedWhenOwnedGtidsIsNotEmpty:             \"@@GLOBAL.GTIDPURGED can only be set when there are no ongoing transactions (not even in other clients).\",\n\tErrGtidPurgedWasChanged:                                  \"@@GLOBAL.GTIDPURGED was changed from '%s' to '%s'.\",\n\tErrGtidExecutedWasChanged:                                \"@@GLOBAL.GTIDEXECUTED was changed from '%s' to '%s'.\",\n\tErrBinlogStmtModeAndNoReplTables:                         \"Cannot execute statement: impossible to write to binary log since BINLOGFORMAT = STATEMENT, and both replicated and non replicated tables are written to.\",\n\tErrAlterOperationNotSupported:                            \"%s is not supported for this operation. Try %s.\",\n\tErrAlterOperationNotSupportedReason:                      \"%s is not supported. Reason: %s. Try %s.\",\n\tErrAlterOperationNotSupportedReasonCopy:                  \"COPY algorithm requires a lock\",\n\tErrAlterOperationNotSupportedReasonPartition:             \"Partition specific operations do not yet support LOCK/ALGORITHM\",\n\tErrAlterOperationNotSupportedReasonFkRename:              \"Columns participating in a foreign key are renamed\",\n\tErrAlterOperationNotSupportedReasonColumnType:            \"Cannot change column type INPLACE\",\n\tErrAlterOperationNotSupportedReasonFkCheck:               \"Adding foreign keys needs foreignKeyChecks=OFF\",\n\tErrAlterOperationNotSupportedReasonIgnore:                \"Creating unique indexes with IGNORE requires COPY algorithm to remove duplicate rows\",\n\tErrAlterOperationNotSupportedReasonNopk:                  \"Dropping a primary key is not allowed without also adding a new primary key\",\n\tErrAlterOperationNotSupportedReasonAutoinc:               \"Adding an auto-increment column requires a lock\",\n\tErrAlterOperationNotSupportedReasonHiddenFts:             \"Cannot replace hidden FTSDOCID with a user-visible one\",\n\tErrAlterOperationNotSupportedReasonChangeFts:             \"Cannot drop or rename FTSDOCID\",\n\tErrAlterOperationNotSupportedReasonFts:                   \"Fulltext index creation requires a lock\",\n\tErrSQLSlaveSkipCounterNotSettableInGtidMode:              \"sqlSlaveSkipCounter can not be set when the server is running with @@GLOBAL.GTIDMODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction\",\n\tErrDupUnknownInIndex:                                     \"Duplicate entry for key '%-.192s'\",\n\tErrIdentCausesTooLongPath:                                \"Long database name and identifier for object resulted in path length exceeding %d characters. Path: '%s'.\",\n\tErrAlterOperationNotSupportedReasonNotNull:               \"cannot silently convert NULL values, as required in this SQLMODE\",\n\tErrMustChangePasswordLogin:                               \"Your password has expired. To log in you must change it using a client that supports expired passwords.\",\n\tErrRowInWrongPartition:                                   \"Found a row in wrong partition %s\",\n\tErrGeneratedColumnFunctionIsNotAllowed:                   \"Expression of generated column '%s' contains a disallowed function.\",\n\tErrUnsupportedAlterInplaceOnVirtualColumn:                \"INPLACE ADD or DROP of virtual columns cannot be combined with other ALTER TABLE actions.\",\n\tErrWrongFKOptionForGeneratedColumn:                       \"Cannot define foreign key with %s clause on a generated column.\",\n\tErrBadGeneratedColumn:                                    \"The value specified for generated column '%s' in table '%s' is not allowed.\",\n\tErrUnsupportedOnGeneratedColumn:                          \"'%s' is not supported for generated columns.\",\n\tErrGeneratedColumnNonPrior:                               \"Generated column can refer only to generated columns defined prior to it.\",\n\tErrDependentByGeneratedColumn:                            \"Column '%s' has a generated column dependency.\",\n\tErrGeneratedColumnRefAutoInc:                             \"Generated column '%s' cannot refer to auto-increment column.\",\n\tErrInvalidFieldSize:                                      \"Invalid size for column '%s'.\",\n\tErrIncorrectType:                                         \"Incorrect type for argument %s in function %s.\",\n\tErrInvalidJSONData:                                       \"Invalid JSON data provided to function %s: %s\",\n\tErrInvalidJSONText:                                       \"Invalid JSON text: %-.192s\",\n\tErrInvalidJSONPath:                                       \"Invalid JSON path expression %s.\",\n\tErrInvalidTypeForJSON:                                    \"Invalid data type for JSON data in argument %d to function %s; a JSON string or JSON type is required.\",\n\tErrInvalidJSONPathWildcard:                               \"In this situation, path expressions may not contain the * and ** tokens.\",\n\tErrInvalidJSONContainsPathType:                           \"The second argument can only be either 'one' or 'all'.\",\n\tErrJSONUsedAsKey:                                         \"JSON column '%-.192s' cannot be used in key specification.\",\n\tErrBadUser:                                               \"User %s does not exist.\",\n\tErrUserAlreadyExists:                                     \"User %s already exists.\",\n\tErrInvalidJSONPathArrayCell:                              \"A path expression is not a path to a cell in an array.\",\n\tErrInvalidEncryptionOption:                               \"Invalid encryption option.\",\n\tErrWindowNoSuchWindow:                                    \"Window name '%s' is not defined.\",\n\tErrWindowCircularityInWindowGraph:                        \"There is a circularity in the window dependency graph.\",\n\tErrWindowNoChildPartitioning:                             \"A window which depends on another cannot define partitioning.\",\n\tErrWindowNoInherentFrame:                                 \"Window '%s' has a frame definition, so cannot be referenced by another window.\",\n\tErrWindowNoRedefineOrderBy:                               \"Window '%s' cannot inherit '%s' since both contain an ORDER BY clause.\",\n\tErrWindowFrameStartIllegal:                               \"Window '%s': frame start cannot be UNBOUNDED FOLLOWING.\",\n\tErrWindowFrameEndIllegal:                                 \"Window '%s': frame end cannot be UNBOUNDED PRECEDING.\",\n\tErrWindowFrameIllegal:                                    \"Window '%s': frame start or end is negative, NULL or of non-integral type\",\n\tErrWindowRangeFrameOrderType:                             \"Window '%s' with RANGE N PRECEDING/FOLLOWING frame requires exactly one ORDER BY expression, of numeric or temporal type\",\n\tErrWindowRangeFrameTemporalType:                          \"Window '%s' with RANGE frame has ORDER BY expression of datetime type. Only INTERVAL bound value allowed.\",\n\tErrWindowRangeFrameNumericType:                           \"Window '%s' with RANGE frame has ORDER BY expression of numeric type, INTERVAL bound value not allowed.\",\n\tErrWindowRangeBoundNotConstant:                           \"Window '%s' has a non-constant frame bound.\",\n\tErrWindowDuplicateName:                                   \"Window '%s' is defined twice.\",\n\tErrWindowIllegalOrderBy:                                  \"Window '%s': ORDER BY or PARTITION BY uses legacy position indication which is not supported, use expression.\",\n\tErrWindowInvalidWindowFuncUse:                            \"You cannot use the window function '%s' in this context.'\",\n\tErrWindowInvalidWindowFuncAliasUse:                       \"You cannot use the alias '%s' of an expression containing a window function in this context.'\",\n\tErrWindowNestedWindowFuncUseInWindowSpec:                 \"You cannot nest a window function in the specification of window '%s'.\",\n\tErrWindowRowsIntervalUse:                                 \"Window '%s': INTERVAL can only be used with RANGE frames.\",\n\tErrWindowNoGroupOrderUnused:                              \"ASC or DESC with GROUP BY isn't allowed with window functions; put ASC or DESC in ORDER BY\",\n\tErrWindowExplainJson:                                     \"To get information about window functions use EXPLAIN FORMAT=JSON\",\n\tErrWindowFunctionIgnoresFrame:                            \"Window function '%s' ignores the frame clause of window '%s' and aggregates over the whole partition\",\n\tErrRoleNotGranted:                                        \"%s is is not granted to %s\",\n\tErrMaxExecTimeExceeded:                                   \"Query execution was interrupted, max_execution_time exceeded.\",\n\tErrLockAcquireFailAndNoWaitSet:                           \"Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set.\",\n\tErrDataTruncatedFunctionalIndex:                          \"Data truncated for functional index '%s' at row %d\",\n\tErrDataOutOfRangeFunctionalIndex:                         \"Value is out of range for functional index '%s' at row %d\",\n\tErrFunctionalIndexOnJsonOrGeometryFunction:               \"Cannot create a functional index on a function that returns a JSON or GEOMETRY value\",\n\tErrFunctionalIndexRefAutoIncrement:                       \"Functional index '%s' cannot refer to an auto-increment column\",\n\tErrCannotDropColumnFunctionalIndex:                       \"Cannot drop column '%s' because it is used by a functional index. In order to drop the column, you must remove the functional index\",\n\tErrFunctionalIndexPrimaryKey:                             \"The primary key cannot be a functional index\",\n\tErrFunctionalIndexOnLob:                                  \"Cannot create a functional index on an expression that returns a BLOB or TEXT. Please consider using CAST\",\n\tErrFunctionalIndexFunctionIsNotAllowed:                   \"Expression of functional index '%s' contains a disallowed function\",\n\tErrFulltextFunctionalIndex:                               \"Fulltext functional index is not supported\",\n\tErrSpatialFunctionalIndex:                                \"Spatial functional index is not supported\",\n\tErrWrongKeyColumnFunctionalIndex:                         \"The used storage engine cannot index the expression '%s'\",\n\tErrFunctionalIndexOnField:                                \"Functional index on a column is not supported. Consider using a regular index instead\",\n\tErrFKIncompatibleColumns:                                 \"Referencing column '%s' in foreign key constraint '%s' are incompatible\",\n\tErrFunctionalIndexRowValueIsNotAllowed:                   \"Expression of functional index '%s' cannot refer to a row value\",\n\tErrDependentByFunctionalIndex:                            \"Column '%s' has a functional index dependency and cannot be dropped or renamed\",\n\tErrInvalidJsonValueForFuncIndex:                          \"Invalid JSON value for CAST for functional index '%s'\",\n\tErrJsonValueOutOfRangeForFuncIndex:                       \"Out of range JSON value for CAST for functional index '%s'\",\n\tErrFunctionalIndexDataIsTooLong:                          \"Data too long for functional index '%s'\",\n\tErrFunctionalIndexNotApplicable:                          \"Cannot use functional index '%s' due to type or collation conversion\",\n\n\t// MariaDB errors.\n\tErrOnlyOneDefaultPartionAllowed:         \"Only one DEFAULT partition allowed\",\n\tErrWrongPartitionTypeExpectedSystemTime: \"Wrong partitioning type, expected type: `SYSTEM_TIME`\",\n\tErrSystemVersioningWrongPartitions:      \"Wrong Partitions: must have at least one HISTORY and exactly one last CURRENT\",\n\tErrSequenceRunOut:                       \"Sequence '%-.64s.%-.64s' has run out\",\n\tErrSequenceInvalidData:                  \"Sequence '%-.64s.%-.64s' values are conflicting\",\n\tErrSequenceAccessFail:                   \"Sequence '%-.64s.%-.64s' access error\",\n\tErrNotSequence:                          \"'%-.64s.%-.64s' is not a SEQUENCE\",\n\tErrUnknownSequence:                      \"Unknown SEQUENCE: '%-.300s'\",\n\tErrWrongInsertIntoSequence:              \"Wrong INSERT into a SEQUENCE. One can only do single table INSERT into a sequence object (like with mysqldump).  If you want to change the SEQUENCE, use ALTER SEQUENCE instead.\",\n\tErrSequenceInvalidTableStructure:        \"Sequence '%-.64s.%-.64s' table structure is invalid (%s)\",\n\n\t// TiDB errors.\n\tErrMemExceedThreshold:         \"%s holds %dB memory, exceeds threshold %dB.%s\",\n\tErrForUpdateCantRetry:         \"[%d] can not retry select for update statement\",\n\tErrAdminCheckTable:            \"TiDB admin check table failed.\",\n\tErrTxnTooLarge:                \"Transaction is too large, size: %d\",\n\tErrWriteConflictInTiDB:        \"Write conflict, txnStartTS %d is stale\",\n\tErrInvalidPluginID:            \"Wrong plugin id: %s, valid plugin id is [name]-[version], both name and version should not contain '-'\",\n\tErrInvalidPluginManifest:      \"Cannot read plugin %s's manifest\",\n\tErrInvalidPluginName:          \"Plugin load with %s but got wrong name %s\",\n\tErrInvalidPluginVersion:       \"Plugin load with %s but got %s\",\n\tErrDuplicatePlugin:            \"Plugin [%s] is redeclared\",\n\tErrInvalidPluginSysVarName:    \"Plugin %s's sysVar %s must start with its plugin name %s\",\n\tErrRequireVersionCheckFail:    \"Plugin %s require %s be %v but got %v\",\n\tErrUnsupportedReloadPlugin:    \"Plugin %s isn't loaded so cannot be reloaded\",\n\tErrUnsupportedReloadPluginVar: \"Reload plugin with different sysVar is unsupported %v\",\n\tErrTableLocked:                \"Table '%s' was locked in %s by %v\",\n\tErrNotExist:                   \"Error: key not exist\",\n\tErrTxnRetryable:               \"Error: KV error safe to retry %s \",\n\tErrCannotSetNilValue:          \"can not set nil value\",\n\tErrInvalidTxn:                 \"invalid transaction\",\n\tErrEntryTooLarge:              \"entry too large, the max entry size is %d, the size of data is %d\",\n\tErrNotImplemented:             \"not implemented\",\n\tErrInfoSchemaExpired:          \"Information schema is out of date: schema failed to update in 1 lease, please make sure TiDB can connect to TiKV\",\n\tErrInfoSchemaChanged:          \"Information schema is changed during the execution of the statement(for example, table definition may be updated by other DDL ran in parallel). If you see this error often, try increasing `tidb_max_delta_schema_count`\",\n\tErrBadNumber:                  \"Bad Number\",\n\tErrCastAsSignedOverflow:       \"Cast to signed converted positive out-of-range integer to it's negative complement\",\n\tErrCastNegIntAsUnsigned:       \"Cast to unsigned converted negative integer to it's positive complement\",\n\tErrInvalidYearFormat:          \"invalid year format\",\n\tErrInvalidYear:                \"invalid year\",\n\tErrIncorrectDatetimeValue:     \"Incorrect datetime value: '%s'\",\n\tErrInvalidTimeFormat:          \"invalid time format: '%v'\",\n\tErrInvalidWeekModeFormat:      \"invalid week mode format: '%v'\",\n\tErrFieldGetDefaultFailed:      \"Field '%s' get default value fail\",\n\tErrIndexOutBound:              \"Index column %s offset out of bound, offset: %d, row: %v\",\n\tErrUnsupportedOp:              \"operation not supported\",\n\tErrRowNotFound:                \"can not find the row: %s\",\n\tErrTableStateCantNone:         \"table %s can't be in none state\",\n\tErrColumnStateCantNone:        \"column %s can't be in none state\",\n\tErrColumnStateNonPublic:       \"can not use non-public column\",\n\tErrIndexStateCantNone:         \"index %s can't be in none state\",\n\tErrInvalidRecordKey:           \"invalid record key\",\n\tErrUnsupportedValueForVar:     \"variable '%s' does not yet support value: %s\",\n\tErrUnsupportedIsolationLevel:  \"The isolation level '%s' is not supported. Set tidb_skip_isolation_level_check=1 to skip this error\",\n\tErrInvalidDDLWorker:           \"Invalid DDL worker\",\n\tErrUnsupportedDDLOperation:    \"Unsupported %s\",\n\tErrNotOwner:                   \"TiDB server is not a DDL owner\",\n\tErrCantDecodeIndex:            \"Cannot decode index value, because %s\",\n\tErrInvalidDDLJob:              \"Invalid DDL job\",\n\tErrInvalidDDLJobFlag:          \"Invalid DDL job flag\",\n\tErrWaitReorgTimeout:           \"Timeout waiting for data reorganization\",\n\tErrInvalidStoreVersion:        \"Invalid storage current version: %d\",\n\tErrUnknownTypeLength:          \"Unknown length for type %d\",\n\tErrUnknownFractionLength:      \"Unknown length for type %d and fraction %d\",\n\tErrInvalidDDLJobVersion:       \"Version %d of DDL job is greater than current one: %d\",\n\tErrInvalidSplitRegionRanges:   \"Failed to split region ranges\",\n\tErrReorgPanic:                 \"Reorg worker panic\",\n\tErrInvalidDDLState:            \"Invalid %s state: %v\",\n\tErrCancelledDDLJob:            \"Cancelled DDL job\",\n\tErrRepairTable:                \"Failed to repair table: %s\",\n\tErrLoadPrivilege:              \"Load privilege table fail: %s\",\n\tErrInvalidPrivilegeType:       \"unknown privilege type %s\",\n\tErrUnknownFieldType:           \"unknown field type\",\n\tErrInvalidSequence:            \"invalid sequence\",\n\tErrInvalidType:                \"invalid type\",\n\tErrCantGetValidID:             \"cannot get valid auto-increment id in retry\",\n\tErrCantSetToNull:              \"cannot set variable to null\",\n\tErrSnapshotTooOld:             \"snapshot is older than GC safe point %s\",\n\tErrInvalidTableID:             \"invalid TableID\",\n\tErrInvalidAutoRandom:          \"Invalid auto random: %s\",\n\tErrInvalidHashKeyFlag:         \"invalid encoded hash key flag\",\n\tErrInvalidListIndex:           \"invalid list index\",\n\tErrInvalidListMetaData:        \"invalid list meta data\",\n\tErrWriteOnSnapshot:            \"write on snapshot\",\n\tErrInvalidKey:                 \"invalid key\",\n\tErrInvalidIndexKey:            \"invalid index key\",\n\tErrDataInConsistent:           \"data isn't equal\",\n\tErrDDLJobNotFound:             \"DDL Job:%v not found\",\n\tErrCancelFinishedDDLJob:       \"This job:%v is finished, so can't be cancelled\",\n\tErrCannotCancelDDLJob:         \"This job:%v is almost finished, can't be cancelled now\",\n\tErrUnknownAllocatorType:       \"Invalid allocator type\",\n\tErrAutoRandReadFailed:         \"Failed to read auto-random value from storage engine\",\n\tErrInvalidIncrementAndOffset:  \"Invalid auto_increment settings: auto_increment_increment: %d, auto_increment_offset: %d, both of them must be in range [1..65535]\",\n\n\tErrWarnOptimizerHintInvalidInteger:  \"integer value is out of range in '%s'\",\n\tErrWarnOptimizerHintUnsupportedHint: \"Optimizer hint %s is not supported by TiDB and is ignored\",\n\tErrWarnOptimizerHintInvalidToken:    \"Cannot use %s '%s' (tok = %d) in an optimizer hint\",\n\tErrWarnMemoryQuotaOverflow:          \"Max value of MEMORY_QUOTA is %d bytes, ignore this invalid limit\",\n\tErrWarnOptimizerHintParseError:      \"Optimizer hint syntax error at %v\",\n\n\tErrSequenceUnsupportedTableOption:      \"Unsupported sequence table-option %s\",\n\tErrUnsupportedType:                     \"Unsupported type %T\",\n\tErrAnalyzeMissIndex:                    \"Index '%s' in field list does not exist in table '%s'\",\n\tErrCartesianProductUnsupported:         \"Cartesian product is unsupported\",\n\tErrPreparedStmtNotFound:                \"Prepared statement not found\",\n\tErrWrongParamCount:                     \"Wrong parameter count\",\n\tErrSchemaChanged:                       \"Schema has changed\",\n\tErrUnknownPlan:                         \"Unknown plan\",\n\tErrPrepareMulti:                        \"Can not prepare multiple statements\",\n\tErrPrepareDDL:                          \"Can not prepare DDL statements with parameters\",\n\tErrResultIsEmpty:                       \"Result is empty\",\n\tErrBuildExecutor:                       \"Failed to build executor\",\n\tErrBatchInsertFail:                     \"Batch insert failed, please clean the table and try again.\",\n\tErrGetStartTS:                          \"Can not get start ts\",\n\tErrPrivilegeCheckFail:                  \"privilege check fail\", // this error message should begin lowercased to be compatible with the test\n\tErrInvalidWildCard:                     \"Wildcard fields without any table name appears in wrong place\",\n\tErrMixOfGroupFuncAndFieldsIncompatible: \"In aggregated query without GROUP BY, expression #%d of SELECT list contains nonaggregated column '%s'; this is incompatible with sql_mode=only_full_group_by\",\n\n\t// TiKV/PD errors.\n\tErrPDServerTimeout:    \"PD server timeout\",\n\tErrTiKVServerTimeout:  \"TiKV server timeout\",\n\tErrTiKVServerBusy:     \"TiKV server is busy\",\n\tErrResolveLockTimeout: \"Resolve lock timeout\",\n\tErrRegionUnavailable:  \"Region is unavailable\",\n\tErrGCTooEarly:         \"GC life time is shorter than transaction duration, transaction starts at %v, GC safe point is %v\",\n\tErrWriteConflict:      \"Write conflict, txnStartTS=%d, conflictStartTS=%d, conflictCommitTS=%d, key=%s\",\n\tErrTiKVStoreLimit:     \"Store token is up to the limit, store id = %d\",\n}\n"
  },
  {
    "path": "pkg/parser/mysql/error.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// Portable analogs of some common call errors.\nvar (\n\tErrBadConn       = errors.New(\"connection was bad\")\n\tErrMalformPacket = errors.New(\"malform packet error\")\n)\n\n// SQLError records an error information, from executing SQL.\ntype SQLError struct {\n\tCode    uint16\n\tMessage string\n\tState   string\n}\n\n// Error prints errors, with a formatted string.\nfunc (e *SQLError) Error() string {\n\treturn fmt.Sprintf(\"ERROR %d (%s): %s\", e.Code, e.State, e.Message)\n}\n\n// NewErr generates a SQL error, with an error code and default format specifier defined in MySQLErrName.\nfunc NewErr(errCode uint16, args ...interface{}) *SQLError {\n\te := &SQLError{Code: errCode}\n\n\tif s, ok := MySQLState[errCode]; ok {\n\t\te.State = s\n\t} else {\n\t\te.State = DefaultMySQLState\n\t}\n\n\tif format, ok := MySQLErrName[errCode]; ok {\n\t\te.Message = fmt.Sprintf(format, args...)\n\t} else {\n\t\te.Message = fmt.Sprint(args...)\n\t}\n\n\treturn e\n}\n\n// NewErrf creates a SQL error, with an error code and a format specifier.\nfunc NewErrf(errCode uint16, format string, args ...interface{}) *SQLError {\n\te := &SQLError{Code: errCode}\n\n\tif s, ok := MySQLState[errCode]; ok {\n\t\te.State = s\n\t} else {\n\t\te.State = DefaultMySQLState\n\t}\n\n\te.Message = fmt.Sprintf(format, args...)\n\n\treturn e\n}\n"
  },
  {
    "path": "pkg/parser/mysql/error_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\nimport (\n\t. \"github.com/pingcap/check\"\n)\n\nvar _ = Suite(&testSQLErrorSuite{})\n\ntype testSQLErrorSuite struct {\n}\n\nfunc (s *testSQLErrorSuite) TestSQLError(c *C) {\n\te := NewErrf(ErrNoDB, \"no db error\")\n\tc.Assert(len(e.Error()), Greater, 0)\n\n\te = NewErrf(0, \"customized error\")\n\tc.Assert(len(e.Error()), Greater, 0)\n\n\te = NewErr(ErrNoDB)\n\tc.Assert(len(e.Error()), Greater, 0)\n\n\te = NewErr(0, \"customized error\")\n\tc.Assert(len(e.Error()), Greater, 0)\n}\n"
  },
  {
    "path": "pkg/parser/mysql/locale_format.go",
    "content": "package mysql\n\nimport (\n\t\"bytes\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/pingcap/errors\"\n)\n\nfunc formatENUS(number string, precision string) (string, error) {\n\tvar buffer bytes.Buffer\n\tif unicode.IsDigit(rune(precision[0])) {\n\t\tfor i, v := range precision {\n\t\t\tif unicode.IsDigit(v) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tprecision = precision[:i]\n\t\t\tbreak\n\t\t}\n\t} else {\n\t\tprecision = \"0\"\n\t}\n\tif number[0] == '-' && number[1] == '.' {\n\t\tnumber = strings.Replace(number, \"-\", \"-0\", 1)\n\t} else if number[0] == '.' {\n\t\tnumber = strings.Replace(number, \".\", \"0.\", 1)\n\t}\n\n\tif (number[:1] == \"-\" && !unicode.IsDigit(rune(number[1]))) ||\n\t\t(!unicode.IsDigit(rune(number[0])) && number[:1] != \"-\") {\n\t\tbuffer.Write([]byte{'0'})\n\t\tposition, err := strconv.ParseUint(precision, 10, 64)\n\t\tif err == nil && position > 0 {\n\t\t\tbuffer.Write([]byte{'.'})\n\t\t\tbuffer.WriteString(strings.Repeat(\"0\", int(position)))\n\t\t}\n\t\treturn buffer.String(), nil\n\t} else if number[:1] == \"-\" {\n\t\tbuffer.Write([]byte{'-'})\n\t\tnumber = number[1:]\n\t}\n\n\tfor i, v := range number {\n\t\tif unicode.IsDigit(v) {\n\t\t\tcontinue\n\t\t} else if i == 1 && number[1] == '.' {\n\t\t\tcontinue\n\t\t} else if v == '.' && number[1] != '.' {\n\t\t\tcontinue\n\t\t} else {\n\t\t\tnumber = number[:i]\n\t\t\tbreak\n\t\t}\n\t}\n\n\tcomma := []byte{','}\n\tparts := strings.Split(number, \".\")\n\tpos := 0\n\tif len(parts[0])%3 != 0 {\n\t\tpos += len(parts[0]) % 3\n\t\tbuffer.WriteString(parts[0][:pos])\n\t\tbuffer.Write(comma)\n\t}\n\tfor ; pos < len(parts[0]); pos += 3 {\n\t\tbuffer.WriteString(parts[0][pos : pos+3])\n\t\tbuffer.Write(comma)\n\t}\n\tbuffer.Truncate(buffer.Len() - 1)\n\n\tposition, err := strconv.ParseUint(precision, 10, 64)\n\tif err == nil {\n\t\tif position > 0 {\n\t\t\tbuffer.Write([]byte{'.'})\n\t\t\tif len(parts) == 2 {\n\t\t\t\tif uint64(len(parts[1])) >= position {\n\t\t\t\t\tbuffer.WriteString(parts[1][:position])\n\t\t\t\t} else {\n\t\t\t\t\tbuffer.WriteString(parts[1])\n\t\t\t\t\tbuffer.WriteString(strings.Repeat(\"0\", int(position)-len(parts[1])))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbuffer.WriteString(strings.Repeat(\"0\", int(position)))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn buffer.String(), nil\n}\n\nfunc formatZHCN(number string, precision string) (string, error) {\n\treturn \"\", errors.New(\"not implemented\")\n}\n\nfunc formatNotSupport(number string, precision string) (string, error) {\n\treturn \"\", errors.New(\"not support for the specific locale\")\n}\n"
  },
  {
    "path": "pkg/parser/mysql/state.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\nconst (\n\t// DefaultMySQLState is default state of the mySQL\n\tDefaultMySQLState = \"HY000\"\n)\n\n// MySQLState maps error code to MySQL SQLSTATE value.\n// The values are taken from ANSI SQL and ODBC and are more standardized.\nvar MySQLState = map[uint16]string{\n\tErrDupKey:                              \"23000\",\n\tErrOutofMemory:                         \"HY001\",\n\tErrOutOfSortMemory:                     \"HY001\",\n\tErrConCount:                            \"08004\",\n\tErrBadHost:                             \"08S01\",\n\tErrHandshake:                           \"08S01\",\n\tErrDBaccessDenied:                      \"42000\",\n\tErrAccessDenied:                        \"28000\",\n\tErrNoDB:                                \"3D000\",\n\tErrUnknownCom:                          \"08S01\",\n\tErrBadNull:                             \"23000\",\n\tErrBadDB:                               \"42000\",\n\tErrTableExists:                         \"42S01\",\n\tErrBadTable:                            \"42S02\",\n\tErrNonUniq:                             \"23000\",\n\tErrServerShutdown:                      \"08S01\",\n\tErrBadField:                            \"42S22\",\n\tErrFieldNotInGroupBy:                   \"42000\",\n\tErrWrongSumSelect:                      \"42000\",\n\tErrWrongGroupField:                     \"42000\",\n\tErrWrongValueCount:                     \"21S01\",\n\tErrTooLongIdent:                        \"42000\",\n\tErrDupFieldName:                        \"42S21\",\n\tErrDupKeyName:                          \"42000\",\n\tErrDupEntry:                            \"23000\",\n\tErrWrongFieldSpec:                      \"42000\",\n\tErrParse:                               \"42000\",\n\tErrEmptyQuery:                          \"42000\",\n\tErrNonuniqTable:                        \"42000\",\n\tErrInvalidDefault:                      \"42000\",\n\tErrMultiplePriKey:                      \"42000\",\n\tErrTooManyKeys:                         \"42000\",\n\tErrTooManyKeyParts:                     \"42000\",\n\tErrTooLongKey:                          \"42000\",\n\tErrKeyColumnDoesNotExits:               \"42000\",\n\tErrBlobUsedAsKey:                       \"42000\",\n\tErrTooBigFieldlength:                   \"42000\",\n\tErrWrongAutoKey:                        \"42000\",\n\tErrForcingClose:                        \"08S01\",\n\tErrIpsock:                              \"08S01\",\n\tErrNoSuchIndex:                         \"42S12\",\n\tErrWrongFieldTerminators:               \"42000\",\n\tErrBlobsAndNoTerminated:                \"42000\",\n\tErrCantRemoveAllFields:                 \"42000\",\n\tErrCantDropFieldOrKey:                  \"42000\",\n\tErrBlobCantHaveDefault:                 \"42000\",\n\tErrWrongDBName:                         \"42000\",\n\tErrWrongTableName:                      \"42000\",\n\tErrTooBigSelect:                        \"42000\",\n\tErrUnknownProcedure:                    \"42000\",\n\tErrWrongParamcountToProcedure:          \"42000\",\n\tErrUnknownTable:                        \"42S02\",\n\tErrFieldSpecifiedTwice:                 \"42000\",\n\tErrUnsupportedExtension:                \"42000\",\n\tErrTableMustHaveColumns:                \"42000\",\n\tErrUnknownCharacterSet:                 \"42000\",\n\tErrTooBigRowsize:                       \"42000\",\n\tErrWrongOuterJoin:                      \"42000\",\n\tErrNullColumnInIndex:                   \"42000\",\n\tErrPasswordAnonymousUser:               \"42000\",\n\tErrPasswordNotAllowed:                  \"42000\",\n\tErrPasswordNoMatch:                     \"42000\",\n\tErrWrongValueCountOnRow:                \"21S01\",\n\tErrInvalidUseOfNull:                    \"22004\",\n\tErrRegexp:                              \"42000\",\n\tErrMixOfGroupFuncAndFields:             \"42000\",\n\tErrNonexistingGrant:                    \"42000\",\n\tErrTableaccessDenied:                   \"42000\",\n\tErrColumnaccessDenied:                  \"42000\",\n\tErrIllegalGrantForTable:                \"42000\",\n\tErrGrantWrongHostOrUser:                \"42000\",\n\tErrNoSuchTable:                         \"42S02\",\n\tErrNonexistingTableGrant:               \"42000\",\n\tErrNotAllowedCommand:                   \"42000\",\n\tErrSyntax:                              \"42000\",\n\tErrAbortingConnection:                  \"08S01\",\n\tErrNetPacketTooLarge:                   \"08S01\",\n\tErrNetReadErrorFromPipe:                \"08S01\",\n\tErrNetFcntl:                            \"08S01\",\n\tErrNetPacketsOutOfOrder:                \"08S01\",\n\tErrNetUncompress:                       \"08S01\",\n\tErrNetRead:                             \"08S01\",\n\tErrNetReadInterrupted:                  \"08S01\",\n\tErrNetErrorOnWrite:                     \"08S01\",\n\tErrNetWriteInterrupted:                 \"08S01\",\n\tErrTooLongString:                       \"42000\",\n\tErrTableCantHandleBlob:                 \"42000\",\n\tErrTableCantHandleAutoIncrement:        \"42000\",\n\tErrWrongColumnName:                     \"42000\",\n\tErrWrongKeyColumn:                      \"42000\",\n\tErrDupUnique:                           \"23000\",\n\tErrBlobKeyWithoutLength:                \"42000\",\n\tErrPrimaryCantHaveNull:                 \"42000\",\n\tErrTooManyRows:                         \"42000\",\n\tErrRequiresPrimaryKey:                  \"42000\",\n\tErrKeyDoesNotExist:                     \"42000\",\n\tErrCheckNoSuchTable:                    \"42000\",\n\tErrCheckNotImplemented:                 \"42000\",\n\tErrCantDoThisDuringAnTransaction:       \"25000\",\n\tErrNewAbortingConnection:               \"08S01\",\n\tErrMasterNetRead:                       \"08S01\",\n\tErrMasterNetWrite:                      \"08S01\",\n\tErrTooManyUserConnections:              \"42000\",\n\tErrReadOnlyTransaction:                 \"25000\",\n\tErrNoPermissionToCreateUser:            \"42000\",\n\tErrLockDeadlock:                        \"40001\",\n\tErrNoReferencedRow:                     \"23000\",\n\tErrRowIsReferenced:                     \"23000\",\n\tErrConnectToMaster:                     \"08S01\",\n\tErrWrongNumberOfColumnsInSelect:        \"21000\",\n\tErrUserLimitReached:                    \"42000\",\n\tErrSpecificAccessDenied:                \"42000\",\n\tErrNoDefault:                           \"42000\",\n\tErrWrongValueForVar:                    \"42000\",\n\tErrWrongTypeForVar:                     \"42000\",\n\tErrCantUseOptionHere:                   \"42000\",\n\tErrNotSupportedYet:                     \"42000\",\n\tErrWrongFkDef:                          \"42000\",\n\tErrOperandColumns:                      \"21000\",\n\tErrSubqueryNo1Row:                      \"21000\",\n\tErrIllegalReference:                    \"42S22\",\n\tErrDerivedMustHaveAlias:                \"42000\",\n\tErrSelectReduced:                       \"01000\",\n\tErrTablenameNotAllowedHere:             \"42000\",\n\tErrNotSupportedAuthMode:                \"08004\",\n\tErrSpatialCantHaveNull:                 \"42000\",\n\tErrCollationCharsetMismatch:            \"42000\",\n\tErrWarnTooFewRecords:                   \"01000\",\n\tErrWarnTooManyRecords:                  \"01000\",\n\tErrWarnNullToNotnull:                   \"22004\",\n\tErrWarnDataOutOfRange:                  \"22003\",\n\tWarnDataTruncated:                      \"01000\",\n\tErrWrongNameForIndex:                   \"42000\",\n\tErrWrongNameForCatalog:                 \"42000\",\n\tErrUnknownStorageEngine:                \"42000\",\n\tErrTruncatedWrongValue:                 \"22007\",\n\tErrSpNoRecursiveCreate:                 \"2F003\",\n\tErrSpAlreadyExists:                     \"42000\",\n\tErrSpDoesNotExist:                      \"42000\",\n\tErrSpLilabelMismatch:                   \"42000\",\n\tErrSpLabelRedefine:                     \"42000\",\n\tErrSpLabelMismatch:                     \"42000\",\n\tErrSpUninitVar:                         \"01000\",\n\tErrSpBadselect:                         \"0A000\",\n\tErrSpBadreturn:                         \"42000\",\n\tErrSpBadstatement:                      \"0A000\",\n\tErrUpdateLogDeprecatedIgnored:          \"42000\",\n\tErrUpdateLogDeprecatedTranslated:       \"42000\",\n\tErrQueryInterrupted:                    \"70100\",\n\tErrSpWrongNoOfArgs:                     \"42000\",\n\tErrSpCondMismatch:                      \"42000\",\n\tErrSpNoreturn:                          \"42000\",\n\tErrSpNoreturnend:                       \"2F005\",\n\tErrSpBadCursorQuery:                    \"42000\",\n\tErrSpBadCursorSelect:                   \"42000\",\n\tErrSpCursorMismatch:                    \"42000\",\n\tErrSpCursorAlreadyOpen:                 \"24000\",\n\tErrSpCursorNotOpen:                     \"24000\",\n\tErrSpUndeclaredVar:                     \"42000\",\n\tErrSpFetchNoData:                       \"02000\",\n\tErrSpDupParam:                          \"42000\",\n\tErrSpDupVar:                            \"42000\",\n\tErrSpDupCond:                           \"42000\",\n\tErrSpDupCurs:                           \"42000\",\n\tErrSpSubselectNyi:                      \"0A000\",\n\tErrStmtNotAllowedInSfOrTrg:             \"0A000\",\n\tErrSpVarcondAfterCurshndlr:             \"42000\",\n\tErrSpCursorAfterHandler:                \"42000\",\n\tErrSpCaseNotFound:                      \"20000\",\n\tErrDivisionByZero:                      \"22012\",\n\tErrIllegalValueForType:                 \"22007\",\n\tErrProcaccessDenied:                    \"42000\",\n\tErrXaerNota:                            \"XAE04\",\n\tErrXaerInval:                           \"XAE05\",\n\tErrXaerRmfail:                          \"XAE07\",\n\tErrXaerOutside:                         \"XAE09\",\n\tErrXaerRmerr:                           \"XAE03\",\n\tErrXaRbrollback:                        \"XA100\",\n\tErrNonexistingProcGrant:                \"42000\",\n\tErrDataTooLong:                         \"22001\",\n\tErrSpBadSQLstate:                       \"42000\",\n\tErrCantCreateUserWithGrant:             \"42000\",\n\tErrSpDupHandler:                        \"42000\",\n\tErrSpNotVarArg:                         \"42000\",\n\tErrSpNoRetset:                          \"0A000\",\n\tErrCantCreateGeometryObject:            \"22003\",\n\tErrTooBigScale:                         \"42000\",\n\tErrTooBigPrecision:                     \"42000\",\n\tErrMBiggerThanD:                        \"42000\",\n\tErrTooLongBody:                         \"42000\",\n\tErrTooBigDisplaywidth:                  \"42000\",\n\tErrXaerDupid:                           \"XAE08\",\n\tErrDatetimeFunctionOverflow:            \"22008\",\n\tErrRowIsReferenced2:                    \"23000\",\n\tErrNoReferencedRow2:                    \"23000\",\n\tErrSpBadVarShadow:                      \"42000\",\n\tErrSpWrongName:                         \"42000\",\n\tErrSpNoAggregate:                       \"42000\",\n\tErrMaxPreparedStmtCountReached:         \"42000\",\n\tErrNonGroupingFieldUsed:                \"42000\",\n\tErrForeignDuplicateKeyOldUnused:        \"23000\",\n\tErrCantChangeTxCharacteristics:         \"25001\",\n\tErrWrongParamcountToNativeFct:          \"42000\",\n\tErrWrongParametersToNativeFct:          \"42000\",\n\tErrWrongParametersToStoredFct:          \"42000\",\n\tErrDupEntryWithKeyName:                 \"23000\",\n\tErrXaRbtimeout:                         \"XA106\",\n\tErrXaRbdeadlock:                        \"XA102\",\n\tErrFuncInexistentNameCollision:         \"42000\",\n\tErrDupSignalSet:                        \"42000\",\n\tErrSignalWarn:                          \"01000\",\n\tErrSignalNotFound:                      \"02000\",\n\tErrSignalException:                     \"HY000\",\n\tErrResignalWithoutActiveHandler:        \"0K000\",\n\tErrSpatialMustHaveGeomCol:              \"42000\",\n\tErrDataOutOfRange:                      \"22003\",\n\tErrAccessDeniedNoPassword:              \"28000\",\n\tErrTruncateIllegalFk:                   \"42000\",\n\tErrDaInvalidConditionNumber:            \"35000\",\n\tErrForeignDuplicateKeyWithChildInfo:    \"23000\",\n\tErrForeignDuplicateKeyWithoutChildInfo: \"23000\",\n\tErrCantExecuteInReadOnlyTransaction:    \"25006\",\n\tErrAlterOperationNotSupported:          \"0A000\",\n\tErrAlterOperationNotSupportedReason:    \"0A000\",\n\tErrDupUnknownInIndex:                   \"23000\",\n\tErrBadGeneratedColumn:                  \"HY000\",\n\tErrUnsupportedOnGeneratedColumn:        \"HY000\",\n\tErrGeneratedColumnNonPrior:             \"HY000\",\n\tErrDependentByGeneratedColumn:          \"HY000\",\n\tErrInvalidJSONText:                     \"22032\",\n\tErrInvalidJSONPath:                     \"42000\",\n\tErrInvalidJSONData:                     \"22032\",\n\tErrInvalidJSONPathWildcard:             \"42000\",\n\tErrJSONUsedAsKey:                       \"42000\",\n\tErrInvalidJSONPathArrayCell:            \"42000\",\n}\n"
  },
  {
    "path": "pkg/parser/mysql/type.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\n// MySQL type information.\nconst (\n\tTypeDecimal   byte = 0\n\tTypeTiny      byte = 1\n\tTypeShort     byte = 2\n\tTypeLong      byte = 3\n\tTypeFloat     byte = 4\n\tTypeDouble    byte = 5\n\tTypeNull      byte = 6\n\tTypeTimestamp byte = 7\n\tTypeLonglong  byte = 8\n\tTypeInt24     byte = 9\n\tTypeDate      byte = 10\n\t/* TypeDuration original name was TypeTime, renamed to TypeDuration to resolve the conflict with Go type Time.*/\n\tTypeDuration byte = 11\n\tTypeDatetime byte = 12\n\tTypeYear     byte = 13\n\tTypeNewDate  byte = 14\n\tTypeVarchar  byte = 15\n\tTypeBit      byte = 16\n\n\tTypeJSON       byte = 0xf5\n\tTypeNewDecimal byte = 0xf6\n\tTypeEnum       byte = 0xf7\n\tTypeSet        byte = 0xf8\n\tTypeTinyBlob   byte = 0xf9\n\tTypeMediumBlob byte = 0xfa\n\tTypeLongBlob   byte = 0xfb\n\tTypeBlob       byte = 0xfc\n\tTypeVarString  byte = 0xfd\n\tTypeString     byte = 0xfe\n\tTypeGeometry   byte = 0xff\n)\n\n// TypeUnspecified is an uninitialized type. TypeDecimal is not used in MySQL.\nconst TypeUnspecified = TypeDecimal\n\n// Flag information.\nconst (\n\tNotNullFlag        uint = 1 << 0  /* Field can't be NULL */\n\tPriKeyFlag         uint = 1 << 1  /* Field is part of a primary key */\n\tUniqueKeyFlag      uint = 1 << 2  /* Field is part of a unique key */\n\tMultipleKeyFlag    uint = 1 << 3  /* Field is part of a key */\n\tBlobFlag           uint = 1 << 4  /* Field is a blob */\n\tUnsignedFlag       uint = 1 << 5  /* Field is unsigned */\n\tZerofillFlag       uint = 1 << 6  /* Field is zerofill */\n\tBinaryFlag         uint = 1 << 7  /* Field is binary   */\n\tEnumFlag           uint = 1 << 8  /* Field is an enum */\n\tAutoIncrementFlag  uint = 1 << 9  /* Field is an auto increment field */\n\tTimestampFlag      uint = 1 << 10 /* Field is a timestamp */\n\tSetFlag            uint = 1 << 11 /* Field is a set */\n\tNoDefaultValueFlag uint = 1 << 12 /* Field doesn't have a default value */\n\tOnUpdateNowFlag    uint = 1 << 13 /* Field is set to NOW on UPDATE */\n\tPartKeyFlag        uint = 1 << 14 /* Intern: Part of some keys */\n\tNumFlag            uint = 1 << 15 /* Field is a num (for clients) */\n\n\tGroupFlag             uint = 1 << 15 /* Internal: Group field */\n\tUniqueFlag            uint = 1 << 16 /* Internal: Used by sql_yacc */\n\tBinCmpFlag            uint = 1 << 17 /* Internal: Used by sql_yacc */\n\tParseToJSONFlag       uint = 1 << 18 /* Internal: Used when we want to parse string to JSON in CAST */\n\tIsBooleanFlag         uint = 1 << 19 /* Internal: Used for telling boolean literal from integer */\n\tPreventNullInsertFlag uint = 1 << 20 /* Prevent this Field from inserting NULL values */\n)\n\n// TypeInt24 bounds.\nconst (\n\tMaxUint24 = 1<<24 - 1\n\tMaxInt24  = 1<<23 - 1\n\tMinInt24  = -1 << 23\n)\n\n// HasNotNullFlag checks if NotNullFlag is set.\nfunc HasNotNullFlag(flag uint) bool {\n\treturn (flag & NotNullFlag) > 0\n}\n\n// HasNoDefaultValueFlag checks if NoDefaultValueFlag is set.\nfunc HasNoDefaultValueFlag(flag uint) bool {\n\treturn (flag & NoDefaultValueFlag) > 0\n}\n\n// HasAutoIncrementFlag checks if AutoIncrementFlag is set.\nfunc HasAutoIncrementFlag(flag uint) bool {\n\treturn (flag & AutoIncrementFlag) > 0\n}\n\n// HasUnsignedFlag checks if UnsignedFlag is set.\nfunc HasUnsignedFlag(flag uint) bool {\n\treturn (flag & UnsignedFlag) > 0\n}\n\n// HasZerofillFlag checks if ZerofillFlag is set.\nfunc HasZerofillFlag(flag uint) bool {\n\treturn (flag & ZerofillFlag) > 0\n}\n\n// HasBinaryFlag checks if BinaryFlag is set.\nfunc HasBinaryFlag(flag uint) bool {\n\treturn (flag & BinaryFlag) > 0\n}\n\n// HasPriKeyFlag checks if PriKeyFlag is set.\nfunc HasPriKeyFlag(flag uint) bool {\n\treturn (flag & PriKeyFlag) > 0\n}\n\n// HasUniKeyFlag checks if UniqueKeyFlag is set.\nfunc HasUniKeyFlag(flag uint) bool {\n\treturn (flag & UniqueKeyFlag) > 0\n}\n\n// HasMultipleKeyFlag checks if MultipleKeyFlag is set.\nfunc HasMultipleKeyFlag(flag uint) bool {\n\treturn (flag & MultipleKeyFlag) > 0\n}\n\n// HasTimestampFlag checks if HasTimestampFlag is set.\nfunc HasTimestampFlag(flag uint) bool {\n\treturn (flag & TimestampFlag) > 0\n}\n\n// HasOnUpdateNowFlag checks if OnUpdateNowFlag is set.\nfunc HasOnUpdateNowFlag(flag uint) bool {\n\treturn (flag & OnUpdateNowFlag) > 0\n}\n\n// HasParseToJSONFlag checks if ParseToJSONFlag is set.\nfunc HasParseToJSONFlag(flag uint) bool {\n\treturn (flag & ParseToJSONFlag) > 0\n}\n\n// HasIsBooleanFlag checks if IsBooleanFlag is set.\nfunc HasIsBooleanFlag(flag uint) bool {\n\treturn (flag & IsBooleanFlag) > 0\n}\n\n// HasPreventNullInsertFlag checks if PreventNullInsertFlag is set.\nfunc HasPreventNullInsertFlag(flag uint) bool {\n\treturn (flag & PreventNullInsertFlag) > 0\n}\n"
  },
  {
    "path": "pkg/parser/mysql/type_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\nimport (\n\t. \"github.com/pingcap/check\"\n)\n\nvar _ = Suite(&testTypeSuite{})\n\ntype testTypeSuite struct{}\n\nfunc (s *testTypeSuite) TestFlags(c *C) {\n\tc.Assert(HasNotNullFlag(NotNullFlag), IsTrue)\n\tc.Assert(HasUniKeyFlag(UniqueKeyFlag), IsTrue)\n\tc.Assert(HasNotNullFlag(NotNullFlag), IsTrue)\n\tc.Assert(HasNoDefaultValueFlag(NoDefaultValueFlag), IsTrue)\n\tc.Assert(HasAutoIncrementFlag(AutoIncrementFlag), IsTrue)\n\tc.Assert(HasUnsignedFlag(UnsignedFlag), IsTrue)\n\tc.Assert(HasZerofillFlag(ZerofillFlag), IsTrue)\n\tc.Assert(HasBinaryFlag(BinaryFlag), IsTrue)\n\tc.Assert(HasPriKeyFlag(PriKeyFlag), IsTrue)\n\tc.Assert(HasMultipleKeyFlag(MultipleKeyFlag), IsTrue)\n\tc.Assert(HasTimestampFlag(TimestampFlag), IsTrue)\n\tc.Assert(HasOnUpdateNowFlag(OnUpdateNowFlag), IsTrue)\n}\n"
  },
  {
    "path": "pkg/parser/mysql/util.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mysql\n\ntype lengthAndDecimal struct {\n\tlength  int\n\tdecimal int\n}\n\n// defaultLengthAndDecimal provides default Flen and Decimal for fields\n// from CREATE TABLE when they are unspecified.\nvar defaultLengthAndDecimal = map[byte]lengthAndDecimal{\n\tTypeBit:        {1, 0},\n\tTypeTiny:       {4, 0},\n\tTypeShort:      {6, 0},\n\tTypeInt24:      {9, 0},\n\tTypeLong:       {11, 0},\n\tTypeLonglong:   {20, 0},\n\tTypeDouble:     {22, -1},\n\tTypeFloat:      {12, -1},\n\tTypeNewDecimal: {11, 0},\n\tTypeDuration:   {10, 0},\n\tTypeDate:       {10, 0},\n\tTypeTimestamp:  {19, 0},\n\tTypeDatetime:   {19, 0},\n\tTypeYear:       {4, 0},\n\tTypeString:     {1, 0},\n\tTypeVarchar:    {5, 0},\n\tTypeVarString:  {5, 0},\n\tTypeTinyBlob:   {255, 0},\n\tTypeBlob:       {65535, 0},\n\tTypeMediumBlob: {16777215, 0},\n\tTypeLongBlob:   {4294967295, 0},\n\tTypeJSON:       {4294967295, 0},\n\tTypeNull:       {0, 0},\n\tTypeSet:        {-1, 0},\n\tTypeEnum:       {-1, 0},\n}\n\n// IsIntegerType indicate whether tp is an integer type.\nfunc IsIntegerType(tp byte) bool {\n\tswitch tp {\n\tcase TypeTiny, TypeShort, TypeInt24, TypeLong, TypeLonglong:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// GetDefaultFieldLengthAndDecimal returns the default display length (flen) and decimal length for column.\n// Call this when no Flen assigned in ddl.\n// or column value is calculated from an expression.\n// For example: \"select count(*) from t;\", the column type is int64 and Flen in ResultField will be 21.\n// See https://dev.mysql.com/doc/refman/5.7/en/storage-requirements.html\nfunc GetDefaultFieldLengthAndDecimal(tp byte) (flen int, decimal int) {\n\tval, ok := defaultLengthAndDecimal[tp]\n\tif ok {\n\t\treturn val.length, val.decimal\n\t}\n\treturn -1, -1\n}\n\n// defaultLengthAndDecimal provides default Flen and Decimal for fields\n// from CAST when they are unspecified.\nvar defaultLengthAndDecimalForCast = map[byte]lengthAndDecimal{\n\tTypeString:     {0, -1}, // Flen & Decimal differs.\n\tTypeDate:       {10, 0},\n\tTypeDatetime:   {19, 0},\n\tTypeNewDecimal: {11, 0},\n\tTypeDuration:   {10, 0},\n\tTypeLonglong:   {22, 0},\n\tTypeDouble:     {22, -1},\n\tTypeFloat:      {12, -1},\n\tTypeJSON:       {4194304, 0}, // Flen differs.\n}\n\n// GetDefaultFieldLengthAndDecimalForCast returns the default display length (flen) and decimal length for casted column\n// when flen or decimal is not specified.\nfunc GetDefaultFieldLengthAndDecimalForCast(tp byte) (flen int, decimal int) {\n\tval, ok := defaultLengthAndDecimalForCast[tp]\n\tif ok {\n\t\treturn val.length, val.decimal\n\t}\n\treturn -1, -1\n}\n"
  },
  {
    "path": "pkg/parser/opcode/opcode.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage opcode\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/pingcap/errors\"\n\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n)\n\n// Op is opcode type.\ntype Op int\n\n// List operators.\nconst (\n\tLogicAnd Op = iota + 1\n\tLeftShift\n\tRightShift\n\tLogicOr\n\tGE\n\tLE\n\tEQ\n\tNE\n\tLT\n\tGT\n\tPlus\n\tMinus\n\tAnd\n\tOr\n\tMod\n\tXor\n\tDiv\n\tMul\n\tNot\n\tBitNeg\n\tIntDiv\n\tLogicXor\n\tNullEQ\n\tIn\n\tLike\n\tCase\n\tRegexp\n\tIsNull\n\tIsTruth\n\tIsFalsity\n)\n\n// Ops maps opcode to string.\nvar Ops = map[Op]string{\n\tLogicAnd:   \"and\",\n\tLogicOr:    \"or\",\n\tLogicXor:   \"xor\",\n\tLeftShift:  \"leftshift\",\n\tRightShift: \"rightshift\",\n\tGE:         \"ge\",\n\tLE:         \"le\",\n\tEQ:         \"eq\",\n\tNE:         \"ne\",\n\tLT:         \"lt\",\n\tGT:         \"gt\",\n\tPlus:       \"plus\",\n\tMinus:      \"minus\",\n\tAnd:        \"bitand\",\n\tOr:         \"bitor\",\n\tMod:        \"mod\",\n\tXor:        \"bitxor\",\n\tDiv:        \"div\",\n\tMul:        \"mul\",\n\tNot:        \"not\",\n\tBitNeg:     \"bitneg\",\n\tIntDiv:     \"intdiv\",\n\tNullEQ:     \"nulleq\",\n\tIn:         \"in\",\n\tLike:       \"like\",\n\tCase:       \"case\",\n\tRegexp:     \"regexp\",\n\tIsNull:     \"isnull\",\n\tIsTruth:    \"istrue\",\n\tIsFalsity:  \"isfalse\",\n}\n\n// String implements Stringer interface.\nfunc (o Op) String() string {\n\tstr, ok := Ops[o]\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"%d\", o))\n\t}\n\n\treturn str\n}\n\nvar opsLiteral = map[Op]string{\n\tLogicAnd:   \" AND \",\n\tLogicOr:    \" OR \",\n\tLogicXor:   \" XOR \",\n\tLeftShift:  \"<<\",\n\tRightShift: \">>\",\n\tGE:         \">=\",\n\tLE:         \"<=\",\n\tEQ:         \"=\",\n\tNE:         \"!=\",\n\tLT:         \"<\",\n\tGT:         \">\",\n\tPlus:       \"+\",\n\tMinus:      \"-\",\n\tAnd:        \"&\",\n\tOr:         \"|\",\n\tMod:        \"%\",\n\tXor:        \"^\",\n\tDiv:        \"/\",\n\tMul:        \"*\",\n\tNot:        \"not\",\n\tBitNeg:     \"~\",\n\tIntDiv:     \" DIV \",\n\tNullEQ:     \"<=>\",\n\tIn:         \"IN\",\n\tLike:       \"LIKE\",\n\tCase:       \"CASE\",\n\tRegexp:     \"REGEXP\",\n\tIsNull:     \"IS NULL\",\n\tIsTruth:    \"IS TRUE\",\n\tIsFalsity:  \"IS FALSE\",\n}\n\n// Format the ExprNode into a Writer.\nfunc (o Op) Format(w io.Writer) {\n\tfmt.Fprintf(w, \"%s\", opsLiteral[o])\n}\n\n// Restore the Op into a Writer\nfunc (o Op) Restore(ctx *RestoreCtx) error {\n\tif v, ok := opsLiteral[o]; ok {\n\t\tctx.WriteKeyWord(ctx.Dialect.GetOperator(v))\n\t\treturn nil\n\t}\n\treturn errors.Errorf(\"Invalid opcode type %d during restoring AST to SQL text\", o)\n}\n"
  },
  {
    "path": "pkg/parser/opcode/opcode_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage opcode\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc TestT(t *testing.T) {\n\top := Plus\n\tif op.String() != \"plus\" {\n\t\tt.Fatalf(\"invalid op code\")\n\t}\n\n\tif len(Ops) != len(opsLiteral) {\n\t\tt.Error(\"inconsistent count ops and opsliteral\")\n\t}\n\tvar buf bytes.Buffer\n\tfor op := range Ops {\n\t\top.Format(&buf)\n\t\tif buf.String() != opsLiteral[op] {\n\t\t\tt.Error(\"format op fail\", op)\n\t\t}\n\t\tbuf.Reset()\n\t}\n\n\t// Test invalid opcode\n\tdefer func() {\n\t\trecover()\n\t}()\n\n\top = 0\n\ts := op.String()\n\tif len(s) > 0 {\n\t\tt.Fail()\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/parser.go",
    "content": "// Code generated by goyacc DO NOT EDIT.\n\n// Copyright 2013 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Initial yacc source generated by ebnf2y[1]\n// at 2013-10-04 23:10:47.861401015 +0200 CEST\n//\n//  $ ebnf2y -o ql.y -oe ql.ebnf -start StatementList -pkg ql -p _\n//\n//   [1]: http://github.com/cznic/ebnf2y\n\n// Modified by Ant Group in 2023\n\npackage parser\n\nimport __yyfmt__ \"fmt\"\n\nimport (\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/auth\"\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\t\"github.com/secretflow/scql/pkg/parser/types\"\n)\n\ntype yySymType struct {\n\tyys       int\n\toffset    int // offset\n\titem      interface{}\n\tident     string\n\texpr      ast.ExprNode\n\tstatement ast.StmtNode\n}\n\ntype yyXError struct {\n\tstate, xsym int\n}\n\nconst (\n\tyyDefault                  = 57998\n\tyyEOFCode                  = 57344\n\taccount                    = 57572\n\taction                     = 57573\n\tadd                        = 57358\n\taddDate                    = 57850\n\tadmin                      = 57902\n\tadvise                     = 57574\n\tafter                      = 57575\n\tagainst                    = 57576\n\talgorithm                  = 57578\n\tall                        = 57359\n\talter                      = 57360\n\talways                     = 57577\n\tanalyze                    = 57361\n\tand                        = 57362\n\tandand                     = 57353\n\tandnot                     = 57965\n\tany                        = 57579\n\tas                         = 57363\n\tasc                        = 57364\n\tascii                      = 57580\n\tassignmentEq               = 57966\n\tautoIncrement              = 57581\n\tautoRandom                 = 57582\n\tavg                        = 57584\n\tavgRowLength               = 57583\n\tbegin                      = 57585\n\tbetween                    = 57365\n\tbigIntType                 = 57366\n\tbinaryType                 = 57367\n\tbinding                    = 57828\n\tbindings                   = 57829\n\tbinlog                     = 57586\n\tbitAnd                     = 57851\n\tbitLit                     = 57964\n\tbitOr                      = 57852\n\tbitType                    = 57587\n\tbitXor                     = 57853\n\tblobType                   = 57368\n\tblock                      = 57588\n\tboolType                   = 57590\n\tbooleanType                = 57589\n\tboth                       = 57369\n\tbound                      = 57854\n\tbtree                      = 57591\n\tbuckets                    = 57903\n\tbuiltinAddDate             = 57932\n\tbuiltinBitAnd              = 57933\n\tbuiltinBitOr               = 57934\n\tbuiltinBitXor              = 57935\n\tbuiltinCast                = 57936\n\tbuiltinCount               = 57937\n\tbuiltinCurDate             = 57938\n\tbuiltinCurTime             = 57939\n\tbuiltinDateAdd             = 57940\n\tbuiltinDateSub             = 57941\n\tbuiltinExtract             = 57942\n\tbuiltinGroupConcat         = 57943\n\tbuiltinMax                 = 57944\n\tbuiltinMedian              = 57959\n\tbuiltinMin                 = 57945\n\tbuiltinNow                 = 57946\n\tbuiltinPercentileDisc      = 57947\n\tbuiltinPosition            = 57948\n\tbuiltinStddevPop           = 57953\n\tbuiltinStddevSamp          = 57954\n\tbuiltinSubDate             = 57949\n\tbuiltinSubstring           = 57950\n\tbuiltinSum                 = 57951\n\tbuiltinSysDate             = 57952\n\tbuiltinTrim                = 57955\n\tbuiltinUser                = 57956\n\tbuiltinVarPop              = 57957\n\tbuiltinVarSamp             = 57958\n\tbuiltins                   = 57904\n\tby                         = 57370\n\tbyteType                   = 57592\n\tcache                      = 57593\n\tcancel                     = 57905\n\tcapture                    = 57595\n\tcascade                    = 57371\n\tcascaded                   = 57594\n\tcaseKwd                    = 57372\n\tcast                       = 57855\n\tchange                     = 57373\n\tcharType                   = 57375\n\tcharacter                  = 57374\n\tcharsetKwd                 = 57596\n\tcheck                      = 57376\n\tchecksum                   = 57597\n\tcipher                     = 57598\n\tcleanup                    = 57599\n\tclient                     = 57600\n\tcmSketch                   = 57906\n\tcoalesce                   = 57601\n\tcollate                    = 57377\n\tcollation                  = 57602\n\tcolumn                     = 57378\n\tcolumnFormat               = 57603\n\tcolumns                    = 57604\n\tcomment                    = 57605\n\tcommit                     = 57606\n\tcommitted                  = 57607\n\tcompact                    = 57608\n\tcompressed                 = 57609\n\tcompression                = 57610\n\tconnection                 = 57611\n\tconsistent                 = 57612\n\tconstraint                 = 57379\n\tcontext                    = 57613\n\tconvert                    = 57380\n\tcopyKwd                    = 57856\n\tcount                      = 57857\n\tcpu                        = 57614\n\tcreate                     = 57381\n\tcreateTableSelect          = 57985\n\tcross                      = 57382\n\tcumeDist                   = 57383\n\tcurTime                    = 57858\n\tcurrent                    = 57615\n\tcurrentDate                = 57384\n\tcurrentRole                = 57388\n\tcurrentTime                = 57385\n\tcurrentTs                  = 57386\n\tcurrentUser                = 57387\n\tcycle                      = 57616\n\tdata                       = 57618\n\tdatabase                   = 57389\n\tdatabases                  = 57390\n\tdateAdd                    = 57859\n\tdateSub                    = 57860\n\tdateType                   = 57619\n\tdatetimeType               = 57620\n\tday                        = 57617\n\tdayHour                    = 57391\n\tdayMicrosecond             = 57392\n\tdayMinute                  = 57393\n\tdaySecond                  = 57394\n\tdbType                     = 57849\n\tddl                        = 57907\n\tdeallocate                 = 57621\n\tdecLit                     = 57961\n\tdecimalType                = 57395\n\tdefaultKwd                 = 57396\n\tdefiner                    = 57622\n\tdelayKeyWrite              = 57623\n\tdelayed                    = 57397\n\tdeleteKwd                  = 57398\n\tdenseRank                  = 57399\n\tdepth                      = 57908\n\tdesc                       = 57400\n\tdescribe                   = 57401\n\tdirectory                  = 57624\n\tdisable                    = 57625\n\tdiscard                    = 57626\n\tdisk                       = 57627\n\tdistinct                   = 57402\n\tdistinctRow                = 57403\n\tdiv                        = 57404\n\tdo                         = 57628\n\tdoubleAtIdentifier         = 57350\n\tdoubleType                 = 57405\n\tdrainer                    = 57909\n\tdrop                       = 57406\n\tdual                       = 57407\n\tduplicate                  = 57629\n\tdynamic                    = 57630\n\telseKwd                    = 57408\n\tempty                      = 57978\n\tenable                     = 57631\n\tenclosed                   = 57409\n\tencryptedOnly              = 57845\n\tencryption                 = 57632\n\tend                        = 57633\n\tendpoint                   = 57847\n\tenforced                   = 57836\n\tengine                     = 57634\n\tengines                    = 57635\n\tenum                       = 57636\n\teq                         = 57967\n\tyyErrCode                  = 57345\n\terrorKwd                   = 57410\n\tescape                     = 57640\n\tescaped                    = 57411\n\tevent                      = 57637\n\tevents                     = 57638\n\tevolve                     = 57639\n\texact                      = 57861\n\texcept                     = 57414\n\texchange                   = 57641\n\texclusive                  = 57642\n\texecute                    = 57643\n\texists                     = 57412\n\texpansion                  = 57644\n\texpire                     = 57645\n\texplain                    = 57413\n\texprPushdownBlacklist      = 57900\n\textended                   = 57646\n\textract                    = 57862\n\tfalseKwd                   = 57415\n\tfaultsSym                  = 57647\n\tfields                     = 57648\n\tfile                       = 57649\n\tfirst                      = 57650\n\tfirstValue                 = 57416\n\tfixed                      = 57651\n\tflashback                  = 57863\n\tfloatLit                   = 57960\n\tfloatType                  = 57417\n\tflush                      = 57652\n\tfollowing                  = 57653\n\tforKwd                     = 57418\n\tforce                      = 57419\n\tforeign                    = 57420\n\tformat                     = 57654\n\tfrom                       = 57421\n\tfull                       = 57655\n\tfulltext                   = 57422\n\tfunction                   = 57656\n\tge                         = 57968\n\tgeneral                    = 57424\n\tgenerated                  = 57423\n\tgetFormat                  = 57864\n\tglobal                     = 57801\n\tgrant                      = 57425\n\tgrants                     = 57657\n\tgroup                      = 57426\n\tgroupConcat                = 57865\n\tgroups                     = 57427\n\thash                       = 57658\n\thaving                     = 57428\n\thexLit                     = 57963\n\thighPriority               = 57429\n\thigherThanComma            = 57997\n\thintComment                = 57352\n\thistory                    = 57659\n\thosts                      = 57660\n\thour                       = 57661\n\thourMicrosecond            = 57430\n\thourMinute                 = 57431\n\thourSecond                 = 57432\n\tidentSQLErrors             = 57832\n\tidentified                 = 57662\n\tidentifier                 = 57346\n\tifKwd                      = 57433\n\tignore                     = 57434\n\timportKwd                  = 57663\n\tin                         = 57435\n\tincrement                  = 57667\n\tincremental                = 57668\n\tindex                      = 57436\n\tindexes                    = 57669\n\tinfile                     = 57437\n\tinner                      = 57438\n\tinplace                    = 57867\n\tinsert                     = 57444\n\tinsertMethod               = 57664\n\tinsertValues               = 57983\n\tinstant                    = 57868\n\tint1Type                   = 57446\n\tint2Type                   = 57447\n\tint3Type                   = 57448\n\tint4Type                   = 57449\n\tint8Type                   = 57450\n\tintLit                     = 57962\n\tintType                    = 57445\n\tintegerType                = 57439\n\tinternal                   = 57869\n\tinterval                   = 57440\n\tinto                       = 57441\n\tinvalid                    = 57351\n\tinvisible                  = 57670\n\tinvoker                    = 57671\n\tio                         = 57672\n\tipc                        = 57673\n\tis                         = 57443\n\tisolation                  = 57665\n\tissuer                     = 57666\n\tjob                        = 57911\n\tjobs                       = 57910\n\tjoin                       = 57451\n\tjsonType                   = 57674\n\tjss                        = 57970\n\tjuss                       = 57971\n\tkey                        = 57452\n\tkeyBlockSize               = 57675\n\tkeys                       = 57453\n\tkill                       = 57454\n\tlabels                     = 57676\n\tlag                        = 57455\n\tlanguage                   = 57677\n\tlast                       = 57678\n\tlastValue                  = 57456\n\tle                         = 57969\n\tlead                       = 57457\n\tleading                    = 57458\n\tleft                       = 57459\n\tleftMarker                 = 57930\n\tless                       = 57679\n\tlevel                      = 57680\n\tlike                       = 57460\n\tlimit                      = 57461\n\tlinear                     = 57463\n\tlines                      = 57462\n\tlist                       = 57681\n\tload                       = 57464\n\tlocal                      = 57682\n\tlocalTime                  = 57465\n\tlocalTs                    = 57466\n\tlocation                   = 57683\n\tlock                       = 57467\n\tlogs                       = 57684\n\tlong                       = 57557\n\tlongblobType               = 57468\n\tlongtextType               = 57469\n\tlowPriority                = 57470\n\tlowerThanCharsetKwd        = 57986\n\tlowerThanComma             = 57996\n\tlowerThanCreateTableSelect = 57984\n\tlowerThanEq                = 57993\n\tlowerThanInsertValues      = 57982\n\tlowerThanIntervalKeyword   = 57979\n\tlowerThanKey               = 57987\n\tlowerThanLocal             = 57988\n\tlowerThanNot               = 57995\n\tlowerThanOn                = 57992\n\tlowerThanRemove            = 57989\n\tlowerThanSetKeyword        = 57981\n\tlowerThanStringLitToken    = 57980\n\tlowerThenOrder             = 57990\n\tlsh                        = 57972\n\tmaster                     = 57685\n\tmatch                      = 57471\n\tmax                        = 57871\n\tmaxConnectionsPerHour      = 57692\n\tmaxQueriesPerHour          = 57693\n\tmaxRows                    = 57691\n\tmaxUpdatesPerHour          = 57694\n\tmaxUserConnections         = 57695\n\tmaxValue                   = 57472\n\tmax_idxnum                 = 57701\n\tmax_minutes                = 57700\n\tmediumIntType              = 57474\n\tmediumblobType             = 57473\n\tmediumtextType             = 57475\n\tmemory                     = 57696\n\tmerge                      = 57697\n\tmicrosecond                = 57686\n\tmin                        = 57870\n\tminRows                    = 57698\n\tminValue                   = 57699\n\tminute                     = 57687\n\tminuteMicrosecond          = 57476\n\tminuteSecond               = 57477\n\tmod                        = 57478\n\tmode                       = 57688\n\tmodify                     = 57689\n\tmonth                      = 57690\n\tnames                      = 57702\n\tnational                   = 57703\n\tnatural                    = 57571\n\tncharType                  = 57704\n\tneg                        = 57994\n\tneq                        = 57973\n\tneqSynonym                 = 57974\n\tnever                      = 57705\n\tnext_row_id                = 57866\n\tno                         = 57706\n\tnoWriteToBinLog            = 57480\n\tnocache                    = 57707\n\tnocycle                    = 57708\n\tnodeID                     = 57912\n\tnodeState                  = 57913\n\tnodegroup                  = 57709\n\tnomaxvalue                 = 57710\n\tnominvalue                 = 57711\n\tnone                       = 57712\n\tnoorder                    = 57713\n\tnot                        = 57479\n\tnot2                       = 57977\n\tnow                        = 57872\n\tnowait                     = 57837\n\tnthValue                   = 57481\n\tntile                      = 57482\n\tnull                       = 57483\n\tnulleq                     = 57975\n\tnulls                      = 57714\n\tnumericType                = 57484\n\tnvarcharType               = 57485\n\todbcDateType               = 57355\n\todbcTimeType               = 57356\n\todbcTimestampType          = 57357\n\toffset                     = 57715\n\ton                         = 57486\n\tonly                       = 57716\n\topen                       = 57794\n\toptRuleBlacklist           = 57901\n\toptimistic                 = 57914\n\toptimize                   = 57487\n\toption                     = 57488\n\toptionally                 = 57489\n\tor                         = 57490\n\torder                      = 57491\n\touter                      = 57492\n\toutfile                    = 57442\n\tover                       = 57493\n\tpackKeys                   = 57494\n\tpageSym                    = 57717\n\tparser                     = 57496\n\tpartial                    = 57720\n\tpartition                  = 57495\n\tpartitioning               = 57721\n\tpartitions                 = 57722\n\tpartyCode                  = 57718\n\tpassword                   = 57719\n\tper_db                     = 57733\n\tper_table                  = 57732\n\tpercentRank                = 57497\n\tpercentileDisc             = 57873\n\tpessimistic                = 57915\n\tpipes                      = 57354\n\tpipesAsOr                  = 57723\n\tplaintext                  = 57838\n\tplaintextAfterAggregate    = 57844\n\tplaintextAfterCompare      = 57843\n\tplaintextAfterGroupBy      = 57842\n\tplaintextAfterJoin         = 57839\n\tplaintextAsJoinPayload     = 57840\n\tplugins                    = 57724\n\tposition                   = 57874\n\tpreSplitRegions            = 57502\n\tpreceding                  = 57725\n\tprecisionType              = 57498\n\tprepare                    = 57726\n\tprimary                    = 57499\n\tprivileges                 = 57727\n\tprocedure                  = 57500\n\tprocess                    = 57728\n\tprocesslist                = 57729\n\tprofile                    = 57730\n\tprofiles                   = 57731\n\tpump                       = 57916\n\tquarter                    = 57734\n\tqueries                    = 57736\n\tquery                      = 57735\n\tquick                      = 57737\n\trangeKwd                   = 57503\n\trank                       = 57504\n\tread                       = 57505\n\trealType                   = 57506\n\trebuild                    = 57738\n\trecent                     = 57875\n\trecover                    = 57739\n\tredundant                  = 57740\n\trefTable                   = 57848\n\treferences                 = 57507\n\tregexpKwd                  = 57508\n\tregion                     = 57929\n\tregions                    = 57928\n\treload                     = 57741\n\tremove                     = 57742\n\trename                     = 57509\n\treorganize                 = 57743\n\trepair                     = 57744\n\trepeat                     = 57510\n\trepeatable                 = 57745\n\treplace                    = 57511\n\treplica                    = 57747\n\treplication                = 57748\n\trequire                    = 57512\n\trespect                    = 57746\n\trestrict                   = 57513\n\trevealRank                 = 57841\n\treverse                    = 57749\n\trevoke                     = 57514\n\tright                      = 57515\n\trightMarker                = 57931\n\trlike                      = 57516\n\trole                       = 57750\n\trollback                   = 57751\n\troutine                    = 57752\n\trow                        = 57517\n\trowCount                   = 57753\n\trowFormat                  = 57754\n\trowNumber                  = 57519\n\trows                       = 57518\n\trsh                        = 57976\n\trtree                      = 57755\n\tsamples                    = 57917\n\tsecond                     = 57756\n\tsecondMicrosecond          = 57520\n\tsecondaryEngine            = 57757\n\tsecondaryLoad              = 57758\n\tsecondaryUnload            = 57759\n\tsecurity                   = 57760\n\tselectKwd                  = 57521\n\tseparator                  = 57761\n\tsequence                   = 57762\n\tserial                     = 57763\n\tserializable               = 57764\n\tsession                    = 57765\n\tset                        = 57522\n\tshardRowIDBits             = 57501\n\tshare                      = 57766\n\tshared                     = 57767\n\tshow                       = 57523\n\tshutdown                   = 57768\n\tsigned                     = 57769\n\tsimple                     = 57770\n\tsingleAtIdentifier         = 57349\n\tslave                      = 57771\n\tslow                       = 57772\n\tsmallIntType               = 57524\n\tsnapshot                   = 57773\n\tsome                       = 57800\n\tsource                     = 57795\n\tspatial                    = 57525\n\tsplit                      = 57926\n\tsql                        = 57526\n\tsqlBigResult               = 57527\n\tsqlBufferResult            = 57774\n\tsqlCache                   = 57775\n\tsqlCalcFoundRows           = 57528\n\tsqlNoCache                 = 57776\n\tsqlSmallResult             = 57529\n\tsqlTsiDay                  = 57777\n\tsqlTsiHour                 = 57778\n\tsqlTsiMinute               = 57779\n\tsqlTsiMonth                = 57780\n\tsqlTsiQuarter              = 57781\n\tsqlTsiSecond               = 57782\n\tsqlTsiWeek                 = 57783\n\tsqlTsiYear                 = 57784\n\tssl                        = 57530\n\tstaleness                  = 57876\n\tstart                      = 57785\n\tstarting                   = 57531\n\tstats                      = 57918\n\tstatsAutoRecalc            = 57786\n\tstatsBuckets               = 57921\n\tstatsHealthy               = 57922\n\tstatsHistograms            = 57920\n\tstatsMeta                  = 57919\n\tstatsPersistent            = 57787\n\tstatsSamplePages           = 57788\n\tstatus                     = 57789\n\tstd                        = 57877\n\tstddev                     = 57878\n\tstddevPop                  = 57879\n\tstddevSamp                 = 57880\n\tstorage                    = 57790\n\tstored                     = 57534\n\tstraightJoin               = 57532\n\tstringLit                  = 57348\n\tstrong                     = 57881\n\tsubDate                    = 57882\n\tsubject                    = 57796\n\tsubpartition               = 57797\n\tsubpartitions              = 57798\n\tsubstring                  = 57884\n\tsum                        = 57883\n\tsuper                      = 57799\n\tswaps                      = 57791\n\tswitchesSym                = 57792\n\tsystemTime                 = 57793\n\ttableChecksum              = 57802\n\ttableKwd                   = 57533\n\ttableRefPriority           = 57991\n\ttables                     = 57803\n\ttablespace                 = 57804\n\ttemporary                  = 57805\n\ttemptable                  = 57806\n\tterminated                 = 57535\n\ttextType                   = 57807\n\tthan                       = 57808\n\tthen                       = 57536\n\ttiFlash                    = 57924\n\ttidb                       = 57923\n\ttimeType                   = 57809\n\ttimestampAdd               = 57885\n\ttimestampDiff              = 57886\n\ttimestampType              = 57810\n\ttinyIntType                = 57538\n\ttinyblobType               = 57537\n\ttinytextType               = 57539\n\tto                         = 57540\n\ttokenWord                  = 57846\n\ttokudbDefault              = 57887\n\ttokudbFast                 = 57888\n\ttokudbLzma                 = 57889\n\ttokudbQuickLZ              = 57890\n\ttokudbSmall                = 57892\n\ttokudbSnappy               = 57891\n\ttokudbUncompressed         = 57893\n\ttokudbZlib                 = 57894\n\ttop                        = 57895\n\ttopn                       = 57925\n\ttp                         = 57816\n\ttrace                      = 57811\n\ttraditional                = 57812\n\ttrailing                   = 57541\n\ttransaction                = 57813\n\ttrigger                    = 57542\n\ttriggers                   = 57814\n\ttrim                       = 57896\n\ttrueKwd                    = 57543\n\ttruncate                   = 57815\n\tunbounded                  = 57817\n\tuncommitted                = 57818\n\tundefined                  = 57822\n\tunderscoreCS               = 57347\n\tunicodeSym                 = 57819\n\tunion                      = 57545\n\tunique                     = 57544\n\tunknown                    = 57820\n\tunlock                     = 57546\n\tunsigned                   = 57547\n\tuntil                      = 57548\n\tupdate                     = 57549\n\tusage                      = 57550\n\tuse                        = 57551\n\tuser                       = 57821\n\tusing                      = 57552\n\tutcDate                    = 57553\n\tutcTime                    = 57555\n\tutcTimestamp               = 57554\n\tvalidation                 = 57823\n\tvalue                      = 57824\n\tvalues                     = 57556\n\tvarPop                     = 57898\n\tvarSamp                    = 57899\n\tvarbinaryType              = 57560\n\tvarcharType                = 57558\n\tvarcharacter               = 57559\n\tvariables                  = 57825\n\tvariance                   = 57897\n\tvarying                    = 57561\n\tview                       = 57826\n\tvirtual                    = 57562\n\tvisible                    = 57827\n\twarnings                   = 57830\n\tweek                       = 57833\n\twhen                       = 57563\n\twhere                      = 57564\n\twidth                      = 57927\n\twindow                     = 57566\n\twith                       = 57567\n\twithout                    = 57831\n\twrite                      = 57565\n\tx509                       = 57835\n\txor                        = 57568\n\tyearMonth                  = 57569\n\tyearType                   = 57834\n\tzerofill                   = 57570\n\n\tyyMaxDepth = 200\n\tyyTabOfs   = -2023\n)\n\nvar (\n\tyyXLAT = map[int]int{\n\t\t57344: 0,    // $end (1648x)\n\t\t59:    1,    // ';' (1647x)\n\t\t57742: 2,    // remove (1463x)\n\t\t57605: 3,    // comment (1411x)\n\t\t57790: 4,    // storage (1388x)\n\t\t57581: 5,    // autoIncrement (1376x)\n\t\t57675: 6,    // keyBlockSize (1320x)\n\t\t57596: 7,    // charsetKwd (1318x)\n\t\t57804: 8,    // tablespace (1317x)\n\t\t44:    9,    // ',' (1316x)\n\t\t57634: 10,   // engine (1313x)\n\t\t57618: 11,   // data (1311x)\n\t\t57632: 12,   // encryption (1310x)\n\t\t57664: 13,   // insertMethod (1309x)\n\t\t57691: 14,   // maxRows (1309x)\n\t\t57698: 15,   // minRows (1309x)\n\t\t57709: 16,   // nodegroup (1309x)\n\t\t57611: 17,   // connection (1303x)\n\t\t57719: 18,   // password (1300x)\n\t\t57597: 19,   // checksum (1298x)\n\t\t57583: 20,   // avgRowLength (1297x)\n\t\t57610: 21,   // compression (1297x)\n\t\t57849: 22,   // dbType (1297x)\n\t\t57623: 23,   // delayKeyWrite (1297x)\n\t\t57848: 24,   // refTable (1297x)\n\t\t57754: 25,   // rowFormat (1297x)\n\t\t57757: 26,   // secondaryEngine (1297x)\n\t\t57786: 27,   // statsAutoRecalc (1297x)\n\t\t57787: 28,   // statsPersistent (1297x)\n\t\t57788: 29,   // statsSamplePages (1297x)\n\t\t57802: 30,   // tableChecksum (1297x)\n\t\t57650: 31,   // first (1284x)\n\t\t57575: 32,   // after (1283x)\n\t\t57582: 33,   // autoRandom (1279x)\n\t\t57603: 34,   // columnFormat (1279x)\n\t\t57763: 35,   // serial (1279x)\n\t\t57785: 36,   // start (1230x)\n\t\t57706: 37,   // no (1228x)\n\t\t57593: 38,   // cache (1227x)\n\t\t57616: 39,   // cycle (1227x)\n\t\t57699: 40,   // minValue (1227x)\n\t\t57578: 41,   // algorithm (1226x)\n\t\t57667: 42,   // increment (1226x)\n\t\t57707: 43,   // nocache (1226x)\n\t\t57708: 44,   // nocycle (1226x)\n\t\t57710: 45,   // nomaxvalue (1226x)\n\t\t57711: 46,   // nominvalue (1226x)\n\t\t57713: 47,   // noorder (1226x)\n\t\t57816: 48,   // tp (1226x)\n\t\t57670: 49,   // invisible (1225x)\n\t\t57827: 50,   // visible (1225x)\n\t\t57826: 51,   // view (1220x)\n\t\t57604: 52,   // columns (1218x)\n\t\t57648: 53,   // fields (1218x)\n\t\t57797: 54,   // subpartition (1216x)\n\t\t57722: 55,   // partitions (1215x)\n\t\t57718: 56,   // partyCode (1213x)\n\t\t57803: 57,   // tables (1212x)\n\t\t57761: 58,   // separator (1211x)\n\t\t57789: 59,   // status (1211x)\n\t\t57662: 60,   // identified (1210x)\n\t\t57725: 61,   // preceding (1210x)\n\t\t57617: 62,   // day (1209x)\n\t\t57661: 63,   // hour (1209x)\n\t\t57686: 64,   // microsecond (1209x)\n\t\t57687: 65,   // minute (1209x)\n\t\t57690: 66,   // month (1209x)\n\t\t57734: 67,   // quarter (1209x)\n\t\t57756: 68,   // second (1209x)\n\t\t57777: 69,   // sqlTsiDay (1209x)\n\t\t57778: 70,   // sqlTsiHour (1209x)\n\t\t57779: 71,   // sqlTsiMinute (1209x)\n\t\t57780: 72,   // sqlTsiMonth (1209x)\n\t\t57781: 73,   // sqlTsiQuarter (1209x)\n\t\t57782: 74,   // sqlTsiSecond (1209x)\n\t\t57783: 75,   // sqlTsiWeek (1209x)\n\t\t57784: 76,   // sqlTsiYear (1209x)\n\t\t57833: 77,   // week (1209x)\n\t\t57834: 78,   // yearType (1209x)\n\t\t57598: 79,   // cipher (1208x)\n\t\t57666: 80,   // issuer (1208x)\n\t\t57682: 81,   // local (1208x)\n\t\t57796: 82,   // subject (1208x)\n\t\t57622: 83,   // definer (1207x)\n\t\t57658: 84,   // hash (1207x)\n\t\t57684: 85,   // logs (1207x)\n\t\t57746: 86,   // respect (1207x)\n\t\t57829: 87,   // bindings (1206x)\n\t\t57615: 88,   // current (1206x)\n\t\t57653: 89,   // following (1206x)\n\t\t57828: 90,   // binding (1205x)\n\t\t57633: 91,   // end (1205x)\n\t\t57735: 92,   // query (1205x)\n\t\t57762: 93,   // sequence (1205x)\n\t\t57817: 94,   // unbounded (1205x)\n\t\t57836: 95,   // enforced (1204x)\n\t\t57715: 96,   // offset (1204x)\n\t\t57726: 97,   // prepare (1204x)\n\t\t57928: 98,   // regions (1204x)\n\t\t57750: 99,   // role (1204x)\n\t\t57810: 100,  // timestampType (1204x)\n\t\t57821: 101,  // user (1204x)\n\t\t57585: 102,  // begin (1203x)\n\t\t57591: 103,  // btree (1203x)\n\t\t57606: 104,  // commit (1203x)\n\t\t57665: 105,  // isolation (1203x)\n\t\t57701: 106,  // max_idxnum (1203x)\n\t\t57696: 107,  // memory (1203x)\n\t\t57733: 108,  // per_db (1203x)\n\t\t57727: 109,  // privileges (1203x)\n\t\t57751: 110,  // rollback (1203x)\n\t\t57755: 111,  // rtree (1203x)\n\t\t57805: 112,  // temporary (1203x)\n\t\t57815: 113,  // truncate (1203x)\n\t\t57823: 114,  // validation (1203x)\n\t\t57824: 115,  // value (1203x)\n\t\t57825: 116,  // variables (1203x)\n\t\t57620: 117,  // datetimeType (1202x)\n\t\t57619: 118,  // dateType (1202x)\n\t\t57625: 119,  // disable (1202x)\n\t\t57630: 120,  // dynamic (1202x)\n\t\t57631: 121,  // enable (1202x)\n\t\t57847: 122,  // endpoint (1202x)\n\t\t57643: 123,  // execute (1202x)\n\t\t57651: 124,  // fixed (1202x)\n\t\t57652: 125,  // flush (1202x)\n\t\t57655: 126,  // full (1202x)\n\t\t57801: 127,  // global (1202x)\n\t\t57674: 128,  // jsonType (1202x)\n\t\t57683: 129,  // location (1202x)\n\t\t57688: 130,  // mode (1202x)\n\t\t57866: 131,  // next_row_id (1202x)\n\t\t57724: 132,  // plugins (1202x)\n\t\t57729: 133,  // processlist (1202x)\n\t\t57739: 134,  // recover (1202x)\n\t\t57744: 135,  // repair (1202x)\n\t\t57765: 136,  // session (1202x)\n\t\t57768: 137,  // shutdown (1202x)\n\t\t57798: 138,  // subpartitions (1202x)\n\t\t57923: 139,  // tidb (1202x)\n\t\t57809: 140,  // timeType (1202x)\n\t\t57820: 141,  // unknown (1202x)\n\t\t57831: 142,  // without (1202x)\n\t\t57902: 143,  // admin (1201x)\n\t\t57586: 144,  // binlog (1201x)\n\t\t57588: 145,  // block (1201x)\n\t\t57903: 146,  // buckets (1201x)\n\t\t57600: 147,  // client (1201x)\n\t\t57906: 148,  // cmSketch (1201x)\n\t\t57601: 149,  // coalesce (1201x)\n\t\t57608: 150,  // compact (1201x)\n\t\t57609: 151,  // compressed (1201x)\n\t\t57613: 152,  // context (1201x)\n\t\t57856: 153,  // copyKwd (1201x)\n\t\t57614: 154,  // cpu (1201x)\n\t\t57621: 155,  // deallocate (1201x)\n\t\t57624: 156,  // directory (1201x)\n\t\t57626: 157,  // discard (1201x)\n\t\t57627: 158,  // disk (1201x)\n\t\t57628: 159,  // do (1201x)\n\t\t57909: 160,  // drainer (1201x)\n\t\t57641: 161,  // exchange (1201x)\n\t\t57644: 162,  // expansion (1201x)\n\t\t57863: 163,  // flashback (1201x)\n\t\t57660: 164,  // hosts (1201x)\n\t\t57346: 165,  // identifier (1201x)\n\t\t57663: 166,  // importKwd (1201x)\n\t\t57867: 167,  // inplace (1201x)\n\t\t57868: 168,  // instant (1201x)\n\t\t57673: 169,  // ipc (1201x)\n\t\t57911: 170,  // job (1201x)\n\t\t57910: 171,  // jobs (1201x)\n\t\t57689: 172,  // modify (1201x)\n\t\t57912: 173,  // nodeID (1201x)\n\t\t57913: 174,  // nodeState (1201x)\n\t\t57714: 175,  // nulls (1201x)\n\t\t57716: 176,  // only (1201x)\n\t\t57717: 177,  // pageSym (1201x)\n\t\t57916: 178,  // pump (1201x)\n\t\t57738: 179,  // rebuild (1201x)\n\t\t57740: 180,  // redundant (1201x)\n\t\t57741: 181,  // reload (1201x)\n\t\t57743: 182,  // reorganize (1201x)\n\t\t57752: 183,  // routine (1201x)\n\t\t57917: 184,  // samples (1201x)\n\t\t57758: 185,  // secondaryLoad (1201x)\n\t\t57759: 186,  // secondaryUnload (1201x)\n\t\t57769: 187,  // signed (1201x)\n\t\t57771: 188,  // slave (1201x)\n\t\t57772: 189,  // slow (1201x)\n\t\t57795: 190,  // source (1201x)\n\t\t57926: 191,  // split (1201x)\n\t\t57876: 192,  // staleness (1201x)\n\t\t57918: 193,  // stats (1201x)\n\t\t57791: 194,  // swaps (1201x)\n\t\t57887: 195,  // tokudbDefault (1201x)\n\t\t57888: 196,  // tokudbFast (1201x)\n\t\t57889: 197,  // tokudbLzma (1201x)\n\t\t57890: 198,  // tokudbQuickLZ (1201x)\n\t\t57892: 199,  // tokudbSmall (1201x)\n\t\t57891: 200,  // tokudbSnappy (1201x)\n\t\t57893: 201,  // tokudbUncompressed (1201x)\n\t\t57894: 202,  // tokudbZlib (1201x)\n\t\t57925: 203,  // topn (1201x)\n\t\t57811: 204,  // trace (1201x)\n\t\t57573: 205,  // action (1200x)\n\t\t57574: 206,  // advise (1200x)\n\t\t57576: 207,  // against (1200x)\n\t\t57577: 208,  // always (1200x)\n\t\t57589: 209,  // booleanType (1200x)\n\t\t57854: 210,  // bound (1200x)\n\t\t57904: 211,  // builtins (1200x)\n\t\t57905: 212,  // cancel (1200x)\n\t\t57595: 213,  // capture (1200x)\n\t\t57594: 214,  // cascaded (1200x)\n\t\t57599: 215,  // cleanup (1200x)\n\t\t57602: 216,  // collation (1200x)\n\t\t57607: 217,  // committed (1200x)\n\t\t57612: 218,  // consistent (1200x)\n\t\t57907: 219,  // ddl (1200x)\n\t\t57908: 220,  // depth (1200x)\n\t\t57629: 221,  // duplicate (1200x)\n\t\t57845: 222,  // encryptedOnly (1200x)\n\t\t57635: 223,  // engines (1200x)\n\t\t57637: 224,  // event (1200x)\n\t\t57638: 225,  // events (1200x)\n\t\t57639: 226,  // evolve (1200x)\n\t\t57861: 227,  // exact (1200x)\n\t\t57900: 228,  // exprPushdownBlacklist (1200x)\n\t\t57646: 229,  // extended (1200x)\n\t\t57647: 230,  // faultsSym (1200x)\n\t\t57649: 231,  // file (1200x)\n\t\t57654: 232,  // format (1200x)\n\t\t57656: 233,  // function (1200x)\n\t\t57657: 234,  // grants (1200x)\n\t\t57659: 235,  // history (1200x)\n\t\t57832: 236,  // identSQLErrors (1200x)\n\t\t57668: 237,  // incremental (1200x)\n\t\t57669: 238,  // indexes (1200x)\n\t\t57869: 239,  // internal (1200x)\n\t\t57671: 240,  // invoker (1200x)\n\t\t57672: 241,  // io (1200x)\n\t\t57676: 242,  // labels (1200x)\n\t\t57677: 243,  // language (1200x)\n\t\t57678: 244,  // last (1200x)\n\t\t57679: 245,  // less (1200x)\n\t\t57680: 246,  // level (1200x)\n\t\t57681: 247,  // list (1200x)\n\t\t57685: 248,  // master (1200x)\n\t\t57871: 249,  // max (1200x)\n\t\t57700: 250,  // max_minutes (1200x)\n\t\t57692: 251,  // maxConnectionsPerHour (1200x)\n\t\t57693: 252,  // maxQueriesPerHour (1200x)\n\t\t57694: 253,  // maxUpdatesPerHour (1200x)\n\t\t57695: 254,  // maxUserConnections (1200x)\n\t\t57697: 255,  // merge (1200x)\n\t\t57870: 256,  // min (1200x)\n\t\t57712: 257,  // none (1200x)\n\t\t57837: 258,  // nowait (1200x)\n\t\t57794: 259,  // open (1200x)\n\t\t57914: 260,  // optimistic (1200x)\n\t\t57901: 261,  // optRuleBlacklist (1200x)\n\t\t57720: 262,  // partial (1200x)\n\t\t57721: 263,  // partitioning (1200x)\n\t\t57732: 264,  // per_table (1200x)\n\t\t57915: 265,  // pessimistic (1200x)\n\t\t57838: 266,  // plaintext (1200x)\n\t\t57844: 267,  // plaintextAfterAggregate (1200x)\n\t\t57843: 268,  // plaintextAfterCompare (1200x)\n\t\t57842: 269,  // plaintextAfterGroupBy (1200x)\n\t\t57839: 270,  // plaintextAfterJoin (1200x)\n\t\t57840: 271,  // plaintextAsJoinPayload (1200x)\n\t\t57728: 272,  // process (1200x)\n\t\t57730: 273,  // profile (1200x)\n\t\t57731: 274,  // profiles (1200x)\n\t\t57736: 275,  // queries (1200x)\n\t\t57875: 276,  // recent (1200x)\n\t\t57929: 277,  // region (1200x)\n\t\t57745: 278,  // repeatable (1200x)\n\t\t57747: 279,  // replica (1200x)\n\t\t57748: 280,  // replication (1200x)\n\t\t57841: 281,  // revealRank (1200x)\n\t\t57760: 282,  // security (1200x)\n\t\t57764: 283,  // serializable (1200x)\n\t\t57766: 284,  // share (1200x)\n\t\t57770: 285,  // simple (1200x)\n\t\t57773: 286,  // snapshot (1200x)\n\t\t57921: 287,  // statsBuckets (1200x)\n\t\t57922: 288,  // statsHealthy (1200x)\n\t\t57920: 289,  // statsHistograms (1200x)\n\t\t57919: 290,  // statsMeta (1200x)\n\t\t57881: 291,  // strong (1200x)\n\t\t57799: 292,  // super (1200x)\n\t\t57792: 293,  // switchesSym (1200x)\n\t\t57793: 294,  // systemTime (1200x)\n\t\t57806: 295,  // temptable (1200x)\n\t\t57808: 296,  // than (1200x)\n\t\t57924: 297,  // tiFlash (1200x)\n\t\t57846: 298,  // tokenWord (1200x)\n\t\t57895: 299,  // top (1200x)\n\t\t57812: 300,  // traditional (1200x)\n\t\t57813: 301,  // transaction (1200x)\n\t\t57814: 302,  // triggers (1200x)\n\t\t57818: 303,  // uncommitted (1200x)\n\t\t57822: 304,  // undefined (1200x)\n\t\t57830: 305,  // warnings (1200x)\n\t\t57927: 306,  // width (1200x)\n\t\t57835: 307,  // x509 (1200x)\n\t\t57572: 308,  // account (1199x)\n\t\t57850: 309,  // addDate (1199x)\n\t\t57579: 310,  // any (1199x)\n\t\t57580: 311,  // ascii (1199x)\n\t\t57584: 312,  // avg (1199x)\n\t\t57851: 313,  // bitAnd (1199x)\n\t\t57852: 314,  // bitOr (1199x)\n\t\t57587: 315,  // bitType (1199x)\n\t\t57853: 316,  // bitXor (1199x)\n\t\t57590: 317,  // boolType (1199x)\n\t\t57592: 318,  // byteType (1199x)\n\t\t57855: 319,  // cast (1199x)\n\t\t57857: 320,  // count (1199x)\n\t\t57858: 321,  // curTime (1199x)\n\t\t57859: 322,  // dateAdd (1199x)\n\t\t57860: 323,  // dateSub (1199x)\n\t\t57636: 324,  // enum (1199x)\n\t\t57640: 325,  // escape (1199x)\n\t\t57642: 326,  // exclusive (1199x)\n\t\t57645: 327,  // expire (1199x)\n\t\t57862: 328,  // extract (1199x)\n\t\t57864: 329,  // getFormat (1199x)\n\t\t57865: 330,  // groupConcat (1199x)\n\t\t57702: 331,  // names (1199x)\n\t\t57703: 332,  // national (1199x)\n\t\t57704: 333,  // ncharType (1199x)\n\t\t57705: 334,  // never (1199x)\n\t\t57872: 335,  // now (1199x)\n\t\t57873: 336,  // percentileDisc (1199x)\n\t\t57874: 337,  // position (1199x)\n\t\t57737: 338,  // quick (1199x)\n\t\t57749: 339,  // reverse (1199x)\n\t\t57753: 340,  // rowCount (1199x)\n\t\t57767: 341,  // shared (1199x)\n\t\t57800: 342,  // some (1199x)\n\t\t57774: 343,  // sqlBufferResult (1199x)\n\t\t57775: 344,  // sqlCache (1199x)\n\t\t57776: 345,  // sqlNoCache (1199x)\n\t\t57877: 346,  // std (1199x)\n\t\t57878: 347,  // stddev (1199x)\n\t\t57879: 348,  // stddevPop (1199x)\n\t\t57880: 349,  // stddevSamp (1199x)\n\t\t57882: 350,  // subDate (1199x)\n\t\t57884: 351,  // substring (1199x)\n\t\t57883: 352,  // sum (1199x)\n\t\t57807: 353,  // textType (1199x)\n\t\t57885: 354,  // timestampAdd (1199x)\n\t\t57886: 355,  // timestampDiff (1199x)\n\t\t57896: 356,  // trim (1199x)\n\t\t57819: 357,  // unicodeSym (1199x)\n\t\t57897: 358,  // variance (1199x)\n\t\t57898: 359,  // varPop (1199x)\n\t\t57899: 360,  // varSamp (1199x)\n\t\t41:    361,  // ')' (1132x)\n\t\t40:    362,  // '(' (1045x)\n\t\t57348: 363,  // stringLit (982x)\n\t\t57486: 364,  // on (931x)\n\t\t57545: 365,  // union (875x)\n\t\t57459: 366,  // left (865x)\n\t\t57515: 367,  // right (865x)\n\t\t57567: 368,  // with (861x)\n\t\t57479: 369,  // not (851x)\n\t\t43:    370,  // '+' (833x)\n\t\t45:    371,  // '-' (833x)\n\t\t57478: 372,  // mod (818x)\n\t\t57396: 373,  // defaultKwd (814x)\n\t\t57363: 374,  // as (812x)\n\t\t57552: 375,  // using (803x)\n\t\t57377: 376,  // collate (757x)\n\t\t57418: 377,  // forKwd (755x)\n\t\t57491: 378,  // order (750x)\n\t\t57467: 379,  // lock (749x)\n\t\t57441: 380,  // into (743x)\n\t\t57461: 381,  // limit (740x)\n\t\t57362: 382,  // and (727x)\n\t\t57564: 383,  // where (715x)\n\t\t57511: 384,  // replace (712x)\n\t\t57490: 385,  // or (707x)\n\t\t57353: 386,  // andand (706x)\n\t\t57375: 387,  // charType (706x)\n\t\t57723: 388,  // pipesAsOr (706x)\n\t\t57568: 389,  // xor (706x)\n\t\t57421: 390,  // from (699x)\n\t\t57967: 391,  // eq (697x)\n\t\t57522: 392,  // set (694x)\n\t\t57962: 393,  // intLit (689x)\n\t\t57483: 394,  // null (683x)\n\t\t57495: 395,  // partition (680x)\n\t\t57532: 396,  // straightJoin (673x)\n\t\t57566: 397,  // window (665x)\n\t\t57428: 398,  // having (663x)\n\t\t57451: 399,  // join (660x)\n\t\t57426: 400,  // group (655x)\n\t\t57571: 401,  // natural (650x)\n\t\t57382: 402,  // cross (649x)\n\t\t57438: 403,  // inner (649x)\n\t\t125:   404,  // '}' (648x)\n\t\t57460: 405,  // like (646x)\n\t\t42:    406,  // '*' (645x)\n\t\t46:    407,  // '.' (641x)\n\t\t57503: 408,  // rangeKwd (631x)\n\t\t57427: 409,  // groups (630x)\n\t\t57518: 410,  // rows (630x)\n\t\t57400: 411,  // desc (629x)\n\t\t57364: 412,  // asc (627x)\n\t\t57391: 413,  // dayHour (625x)\n\t\t57392: 414,  // dayMicrosecond (625x)\n\t\t57393: 415,  // dayMinute (625x)\n\t\t57394: 416,  // daySecond (625x)\n\t\t57430: 417,  // hourMicrosecond (625x)\n\t\t57431: 418,  // hourMinute (625x)\n\t\t57432: 419,  // hourSecond (625x)\n\t\t57476: 420,  // minuteMicrosecond (625x)\n\t\t57477: 421,  // minuteSecond (625x)\n\t\t57520: 422,  // secondMicrosecond (625x)\n\t\t57569: 423,  // yearMonth (625x)\n\t\t57563: 424,  // when (624x)\n\t\t57435: 425,  // in (622x)\n\t\t57408: 426,  // elseKwd (621x)\n\t\t57536: 427,  // then (618x)\n\t\t60:    428,  // '<' (611x)\n\t\t62:    429,  // '>' (611x)\n\t\t57968: 430,  // ge (611x)\n\t\t57433: 431,  // ifKwd (611x)\n\t\t57443: 432,  // is (611x)\n\t\t57969: 433,  // le (611x)\n\t\t57973: 434,  // neq (611x)\n\t\t57974: 435,  // neqSynonym (611x)\n\t\t57975: 436,  // nulleq (611x)\n\t\t57365: 437,  // between (609x)\n\t\t57367: 438,  // binaryType (608x)\n\t\t37:    439,  // '%' (603x)\n\t\t38:    440,  // '&' (603x)\n\t\t47:    441,  // '/' (603x)\n\t\t94:    442,  // '^' (603x)\n\t\t124:   443,  // '|' (603x)\n\t\t57404: 444,  // div (603x)\n\t\t57972: 445,  // lsh (603x)\n\t\t57976: 446,  // rsh (603x)\n\t\t57349: 447,  // singleAtIdentifier (600x)\n\t\t57508: 448,  // regexpKwd (599x)\n\t\t57516: 449,  // rlike (599x)\n\t\t57387: 450,  // currentUser (595x)\n\t\t57444: 451,  // insert (592x)\n\t\t123:   452,  // '{' (587x)\n\t\t57961: 453,  // decLit (587x)\n\t\t57960: 454,  // floatLit (587x)\n\t\t57930: 455,  // leftMarker (587x)\n\t\t57440: 456,  // interval (584x)\n\t\t57964: 457,  // bitLit (582x)\n\t\t57963: 458,  // hexLit (582x)\n\t\t57556: 459,  // values (582x)\n\t\t57412: 460,  // exists (581x)\n\t\t57415: 461,  // falseKwd (581x)\n\t\t57543: 462,  // trueKwd (581x)\n\t\t57380: 463,  // convert (580x)\n\t\t57389: 464,  // database (580x)\n\t\t57350: 465,  // doubleAtIdentifier (579x)\n\t\t57946: 466,  // builtinNow (578x)\n\t\t57386: 467,  // currentTs (578x)\n\t\t57465: 468,  // localTime (578x)\n\t\t57466: 469,  // localTs (578x)\n\t\t57347: 470,  // underscoreCS (578x)\n\t\t57517: 471,  // row (577x)\n\t\t33:    472,  // '!' (576x)\n\t\t126:   473,  // '~' (576x)\n\t\t57932: 474,  // builtinAddDate (576x)\n\t\t57933: 475,  // builtinBitAnd (576x)\n\t\t57934: 476,  // builtinBitOr (576x)\n\t\t57935: 477,  // builtinBitXor (576x)\n\t\t57936: 478,  // builtinCast (576x)\n\t\t57937: 479,  // builtinCount (576x)\n\t\t57938: 480,  // builtinCurDate (576x)\n\t\t57939: 481,  // builtinCurTime (576x)\n\t\t57940: 482,  // builtinDateAdd (576x)\n\t\t57941: 483,  // builtinDateSub (576x)\n\t\t57942: 484,  // builtinExtract (576x)\n\t\t57943: 485,  // builtinGroupConcat (576x)\n\t\t57944: 486,  // builtinMax (576x)\n\t\t57959: 487,  // builtinMedian (576x)\n\t\t57945: 488,  // builtinMin (576x)\n\t\t57947: 489,  // builtinPercentileDisc (576x)\n\t\t57948: 490,  // builtinPosition (576x)\n\t\t57953: 491,  // builtinStddevPop (576x)\n\t\t57954: 492,  // builtinStddevSamp (576x)\n\t\t57949: 493,  // builtinSubDate (576x)\n\t\t57950: 494,  // builtinSubstring (576x)\n\t\t57951: 495,  // builtinSum (576x)\n\t\t57952: 496,  // builtinSysDate (576x)\n\t\t57955: 497,  // builtinTrim (576x)\n\t\t57956: 498,  // builtinUser (576x)\n\t\t57957: 499,  // builtinVarPop (576x)\n\t\t57958: 500,  // builtinVarSamp (576x)\n\t\t57372: 501,  // caseKwd (576x)\n\t\t57383: 502,  // cumeDist (576x)\n\t\t57384: 503,  // currentDate (576x)\n\t\t57388: 504,  // currentRole (576x)\n\t\t57385: 505,  // currentTime (576x)\n\t\t57399: 506,  // denseRank (576x)\n\t\t57416: 507,  // firstValue (576x)\n\t\t57455: 508,  // lag (576x)\n\t\t57456: 509,  // lastValue (576x)\n\t\t57457: 510,  // lead (576x)\n\t\t57977: 511,  // not2 (576x)\n\t\t57481: 512,  // nthValue (576x)\n\t\t57482: 513,  // ntile (576x)\n\t\t57497: 514,  // percentRank (576x)\n\t\t57504: 515,  // rank (576x)\n\t\t57510: 516,  // repeat (576x)\n\t\t57519: 517,  // rowNumber (576x)\n\t\t57553: 518,  // utcDate (576x)\n\t\t57555: 519,  // utcTime (576x)\n\t\t57554: 520,  // utcTimestamp (576x)\n\t\t57354: 521,  // pipes (559x)\n\t\t57434: 522,  // ignore (541x)\n\t\t57471: 523,  // match (533x)\n\t\t57521: 524,  // selectKwd (531x)\n\t\t57436: 525,  // index (515x)\n\t\t57374: 526,  // character (490x)\n\t\t57452: 527,  // key (480x)\n\t\t57376: 528,  // check (470x)\n\t\t57499: 529,  // primary (470x)\n\t\t57494: 530,  // packKeys (463x)\n\t\t57502: 531,  // preSplitRegions (463x)\n\t\t57501: 532,  // shardRowIDBits (463x)\n\t\t57544: 533,  // unique (463x)\n\t\t57507: 534,  // references (461x)\n\t\t57379: 535,  // constraint (458x)\n\t\t57423: 536,  // generated (457x)\n\t\t58173: 537,  // Identifier (416x)\n\t\t58242: 538,  // NotKeywordToken (416x)\n\t\t58428: 539,  // TiDBKeyword (416x)\n\t\t58440: 540,  // UnReservedKeyword (416x)\n\t\t57462: 541,  // lines (401x)\n\t\t57970: 542,  // jss (397x)\n\t\t57971: 543,  // juss (397x)\n\t\t57472: 544,  // maxValue (395x)\n\t\t57540: 545,  // to (394x)\n\t\t57370: 546,  // by (389x)\n\t\t57512: 547,  // require (387x)\n\t\t57966: 548,  // assignmentEq (383x)\n\t\t57419: 549,  // force (380x)\n\t\t57551: 550,  // use (380x)\n\t\t57526: 551,  // sql (378x)\n\t\t64:    552,  // '@' (377x)\n\t\t57371: 553,  // cascade (374x)\n\t\t57406: 554,  // drop (374x)\n\t\t57505: 555,  // read (374x)\n\t\t57513: 556,  // restrict (374x)\n\t\t57361: 557,  // analyze (371x)\n\t\t57360: 558,  // alter (370x)\n\t\t57381: 559,  // create (370x)\n\t\t57373: 560,  // change (367x)\n\t\t57405: 561,  // doubleType (367x)\n\t\t57417: 562,  // floatType (367x)\n\t\t57420: 563,  // foreign (367x)\n\t\t57422: 564,  // fulltext (367x)\n\t\t57445: 565,  // intType (367x)\n\t\t57509: 566,  // rename (367x)\n\t\t57565: 567,  // write (366x)\n\t\t57358: 568,  // add (365x)\n\t\t57557: 569,  // long (365x)\n\t\t57487: 570,  // optimize (365x)\n\t\t57931: 571,  // rightMarker (364x)\n\t\t57548: 572,  // until (364x)\n\t\t58282: 573,  // ParamMarker (159x)\n\t\t58400: 574,  // SubSelect (157x)\n\t\t58450: 575,  // UserVariable (156x)\n\t\t58380: 576,  // SimpleIdent (155x)\n\t\t58391: 577,  // StringLiteral (154x)\n\t\t58220: 578,  // Literal (153x)\n\t\t58155: 579,  // FunctionCallGeneric (151x)\n\t\t58156: 580,  // FunctionCallKeyword (151x)\n\t\t58157: 581,  // FunctionCallNonKeyword (151x)\n\t\t58158: 582,  // FunctionNameConflict (151x)\n\t\t58159: 583,  // FunctionNameDateArith (151x)\n\t\t58160: 584,  // FunctionNameDateArithMultiForms (151x)\n\t\t58161: 585,  // FunctionNameDatetimePrecision (151x)\n\t\t58162: 586,  // FunctionNameOptionalBraces (151x)\n\t\t58379: 587,  // SimpleExpr (151x)\n\t\t58401: 588,  // SumExpr (151x)\n\t\t58403: 589,  // SystemVariable (151x)\n\t\t58460: 590,  // Variable (151x)\n\t\t58483: 591,  // WindowFuncCall (151x)\n\t\t58026: 592,  // BitExpr (139x)\n\t\t58309: 593,  // PredicateExpr (122x)\n\t\t58029: 594,  // BoolPri (119x)\n\t\t58125: 595,  // Expression (119x)\n\t\t58494: 596,  // logAnd (91x)\n\t\t58495: 597,  // logOr (91x)\n\t\t58239: 598,  // NUM (70x)\n\t\t58413: 599,  // TableName (65x)\n\t\t57359: 600,  // all (50x)\n\t\t58392: 601,  // StringName (50x)\n\t\t58116: 602,  // EqOpt (45x)\n\t\t58048: 603,  // ColumnName (38x)\n\t\t57493: 604,  // over (38x)\n\t\t57533: 605,  // tableKwd (37x)\n\t\t58343: 606,  // SelectStmt (30x)\n\t\t58344: 607,  // SelectStmtBasic (30x)\n\t\t58347: 608,  // SelectStmtFromDualTable (30x)\n\t\t58348: 609,  // SelectStmtFromTable (30x)\n\t\t58488: 610,  // WindowingClause (28x)\n\t\t58211: 611,  // LengthNum (27x)\n\t\t57528: 612,  // sqlCalcFoundRows (22x)\n\t\t58443: 613,  // UnionSelect (22x)\n\t\t58441: 614,  // UnionClauseList (21x)\n\t\t58444: 615,  // UnionStmt (21x)\n\t\t57549: 616,  // update (21x)\n\t\t57398: 617,  // deleteKwd (18x)\n\t\t58275: 618,  // OptWindowingClause (17x)\n\t\t57535: 619,  // terminated (16x)\n\t\t57397: 620,  // delayed (15x)\n\t\t57402: 621,  // distinct (15x)\n\t\t57403: 622,  // distinctRow (15x)\n\t\t57429: 623,  // highPriority (15x)\n\t\t57470: 624,  // lowPriority (15x)\n\t\t57527: 625,  // sqlBigResult (15x)\n\t\t58452: 626,  // Username (15x)\n\t\t57409: 627,  // enclosed (14x)\n\t\t58126: 628,  // ExpressionList (14x)\n\t\t58092: 629,  // DefaultKwdOpt (13x)\n\t\t58096: 630,  // DistinctKwd (13x)\n\t\t57411: 631,  // escaped (13x)\n\t\t58205: 632,  // JoinTable (13x)\n\t\t57489: 633,  // optionally (13x)\n\t\t58291: 634,  // PartitionNameList (13x)\n\t\t57529: 635,  // sqlSmallResult (13x)\n\t\t58410: 636,  // TableFactor (13x)\n\t\t58421: 637,  // TableRef (13x)\n\t\t58097: 638,  // DistinctOpt (12x)\n\t\t58091: 639,  // DefaultFalseDistinctOpt (11x)\n\t\t58150: 640,  // FromOrIn (11x)\n\t\t58174: 641,  // IfExists (11x)\n\t\t58175: 642,  // IfNotExists (11x)\n\t\t58337: 643,  // Rolename (11x)\n\t\t58334: 644,  // RoleNameString (11x)\n\t\t58473: 645,  // WhereClause (11x)\n\t\t58474: 646,  // WhereClauseOptional (11x)\n\t\t58031: 647,  // BuggyDefaultFalseDistinctOpt (10x)\n\t\t58038: 648,  // CharsetName (10x)\n\t\t58279: 649,  // OrderBy (10x)\n\t\t58280: 650,  // OrderByOptional (10x)\n\t\t58414: 651,  // TableNameList (10x)\n\t\t58431: 652,  // TimestampUnit (10x)\n\t\t58037: 653,  // CharsetKw (9x)\n\t\t58124: 654,  // ExprOrDefault (9x)\n\t\t58206: 655,  // JoinType (9x)\n\t\t57480: 656,  // noWriteToBinLog (9x)\n\t\t58283: 657,  // PartDefOption (9x)\n\t\t58014: 658,  // AnalyzeOptionListOpt (8x)\n\t\t58049: 659,  // ColumnNameList (8x)\n\t\t58082: 660,  // CrossOpt (8x)\n\t\t58095: 661,  // DeleteFromStmt (8x)\n\t\t58134: 662,  // FieldLen (8x)\n\t\t58193: 663,  // IndexPartSpecification (8x)\n\t\t58199: 664,  // InsertIntoStmt (8x)\n\t\t58207: 665,  // KeyOrIndex (8x)\n\t\t58326: 666,  // ReplaceIntoStmt (8x)\n\t\t58338: 667,  // RolenameList (8x)\n\t\t58351: 668,  // SelectStmtLimit (8x)\n\t\t58429: 669,  // TimeUnit (8x)\n\t\t58446: 670,  // UpdateStmt (8x)\n\t\t58463: 671,  // VariableName (8x)\n\t\t58002: 672,  // AllOrPartitionNameList (7x)\n\t\t58083: 673,  // DBName (7x)\n\t\t58118: 674,  // EscapedTableRef (7x)\n\t\t58140: 675,  // FieldsOrColumns (7x)\n\t\t58194: 676,  // IndexPartSpecificationList (7x)\n\t\t58241: 677,  // NoWriteToBinLogAliasOpt (7x)\n\t\t58340: 678,  // RowFormat (7x)\n\t\t58366: 679,  // ShowDatabaseNameOpt (7x)\n\t\t58378: 680,  // SignedNum (7x)\n\t\t58418: 681,  // TableOption (7x)\n\t\t57378: 682,  // column (6x)\n\t\t58043: 683,  // ColumnDef (6x)\n\t\t58084: 684,  // DatabaseOption (6x)\n\t\t58117: 685,  // EqOrAssignmentEq (6x)\n\t\t57425: 686,  // grant (6x)\n\t\t58185: 687,  // IndexInvisible (6x)\n\t\t58190: 688,  // IndexNameList (6x)\n\t\t58196: 689,  // IndexType (6x)\n\t\t58247: 690,  // NumLiteral (6x)\n\t\t58261: 691,  // OptFieldLen (6x)\n\t\t58341: 692,  // RowValue (6x)\n\t\t58342: 693,  // SelectLockOpt (6x)\n\t\t58350: 694,  // SelectStmtIntoOption (6x)\n\t\t57523: 695,  // show (6x)\n\t\t58368: 696,  // ShowLikeOrWhereOpt (6x)\n\t\t58422: 697,  // TableRefs (6x)\n\t\t58001: 698,  // AlgorithmClause (5x)\n\t\t58032: 699,  // ByItem (5x)\n\t\t58046: 700,  // ColumnKeywordOpt (5x)\n\t\t57401: 701,  // describe (5x)\n\t\t58127: 702,  // ExpressionListOpt (5x)\n\t\t58188: 703,  // IndexName (5x)\n\t\t58191: 704,  // IndexOption (5x)\n\t\t58192: 705,  // IndexOptionList (5x)\n\t\t57437: 706,  // infile (5x)\n\t\t58228: 707,  // LockClause (5x)\n\t\t58268: 708,  // OptNullTreatment (5x)\n\t\t58313: 709,  // PriorityOpt (5x)\n\t\t58405: 710,  // TableAsName (5x)\n\t\t58453: 711,  // UsernameList (5x)\n\t\t58448: 712,  // UserSpec (5x)\n\t\t58018: 713,  // Assignment (4x)\n\t\t58022: 714,  // AuthString (4x)\n\t\t58023: 715,  // BeginTransactionStmt (4x)\n\t\t58033: 716,  // ByList (4x)\n\t\t58042: 717,  // CollationName (4x)\n\t\t58062: 718,  // CommitStmt (4x)\n\t\t57410: 719,  // errorKwd (4x)\n\t\t58123: 720,  // ExplainableStmt (4x)\n\t\t58138: 721,  // FieldTerminator (4x)\n\t\t57424: 722,  // general (4x)\n\t\t58177: 723,  // IgnoreOptional (4x)\n\t\t58197: 724,  // IndexTypeName (4x)\n\t\t58216: 725,  // LimitOption (4x)\n\t\t58218: 726,  // Lines (4x)\n\t\t57464: 727,  // load (4x)\n\t\t58224: 728,  // LoadDataStmt (4x)\n\t\t57488: 729,  // option (4x)\n\t\t58272: 730,  // OptWild (4x)\n\t\t58278: 731,  // Order (4x)\n\t\t57492: 732,  // outer (4x)\n\t\t58331: 733,  // RestrictOrCascadeOpt (4x)\n\t\t58339: 734,  // RollbackStmt (4x)\n\t\t58362: 735,  // SetExpr (4x)\n\t\t58365: 736,  // SetStmt (4x)\n\t\t58419: 737,  // TableOptionList (4x)\n\t\t58434: 738,  // TransactionChar (4x)\n\t\t58449: 739,  // UserSpecList (4x)\n\t\t58484: 740,  // WindowName (4x)\n\t\t58019: 741,  // AssignmentList (3x)\n\t\t58058: 742,  // ColumnPosition (3x)\n\t\t58069: 743,  // ConstraintKeywordOpt (3x)\n\t\t58078: 744,  // CreateTableStmt (3x)\n\t\t58085: 745,  // DatabaseOptionList (3x)\n\t\t58087: 746,  // DatabaseSym (3x)\n\t\t58112: 747,  // EnforcedOrNot (3x)\n\t\t58129: 748,  // Field (3x)\n\t\t58139: 749,  // Fields (3x)\n\t\t58165: 750,  // GlobalScope (3x)\n\t\t57352: 751,  // hintComment (3x)\n\t\t58180: 752,  // IndexHint (3x)\n\t\t58184: 753,  // IndexHintType (3x)\n\t\t58189: 754,  // IndexNameAndTypeOpt (3x)\n\t\t57453: 755,  // keys (3x)\n\t\t58236: 756,  // MaxValueOrExpression (3x)\n\t\t58271: 757,  // OptTemporary (3x)\n\t\t58286: 758,  // PartitionDefinition (3x)\n\t\t58307: 759,  // PluginNameList (3x)\n\t\t58314: 760,  // PrivElem (3x)\n\t\t58317: 761,  // PrivType (3x)\n\t\t58320: 762,  // ReferDef (3x)\n\t\t58327: 763,  // RequireClause (3x)\n\t\t58328: 764,  // RequireClauseOpt (3x)\n\t\t58330: 765,  // RequireListElement (3x)\n\t\t58390: 766,  // StringList (3x)\n\t\t58407: 767,  // TableElement (3x)\n\t\t58416: 768,  // TableNameOptWild (3x)\n\t\t58417: 769,  // TableOptimizerHints (3x)\n\t\t58435: 770,  // TransactionChars (3x)\n\t\t57542: 771,  // trigger (3x)\n\t\t57550: 772,  // usage (3x)\n\t\t58457: 773,  // ValuesList (3x)\n\t\t58455: 774,  // ValueSym (3x)\n\t\t58461: 775,  // VariableAssignment (3x)\n\t\t58481: 776,  // WindowFrameStart (3x)\n\t\t58000: 777,  // AdminStmt (2x)\n\t\t58003: 778,  // AlterDatabaseStmt (2x)\n\t\t58004: 779,  // AlterOrderItem (2x)\n\t\t58007: 780,  // AlterTableSpec (2x)\n\t\t58010: 781,  // AlterTableStmt (2x)\n\t\t58011: 782,  // AlterUserStmt (2x)\n\t\t58012: 783,  // AnalyzeOption (2x)\n\t\t58015: 784,  // AnalyzeTableStmt (2x)\n\t\t58025: 785,  // BinlogStmt (2x)\n\t\t58034: 786,  // CastType (2x)\n\t\t58035: 787,  // ChangeStmt (2x)\n\t\t58050: 788,  // ColumnNameListOpt (2x)\n\t\t58053: 789,  // ColumnNameOrUserVariable (2x)\n\t\t58055: 790,  // ColumnOption (2x)\n\t\t58059: 791,  // ColumnSetValue (2x)\n\t\t58070: 792,  // CreateBindingStmt (2x)\n\t\t58071: 793,  // CreateDatabaseStmt (2x)\n\t\t58072: 794,  // CreateIndexStmt (2x)\n\t\t58073: 795,  // CreateRoleStmt (2x)\n\t\t58075: 796,  // CreateSequenceStmt (2x)\n\t\t58076: 797,  // CreateTableOptionListOpt (2x)\n\t\t58079: 798,  // CreateUserStmt (2x)\n\t\t58081: 799,  // CreateViewStmt (2x)\n\t\t57390: 800,  // databases (2x)\n\t\t58089: 801,  // DeallocateStmt (2x)\n\t\t58090: 802,  // DeallocateSym (2x)\n\t\t57395: 803,  // decimalType (2x)\n\t\t58098: 804,  // DoStmt (2x)\n\t\t58099: 805,  // DropBindingStmt (2x)\n\t\t58100: 806,  // DropDatabaseStmt (2x)\n\t\t58101: 807,  // DropIndexStmt (2x)\n\t\t58102: 808,  // DropRoleStmt (2x)\n\t\t58103: 809,  // DropSequenceStmt (2x)\n\t\t58104: 810,  // DropStatsStmt (2x)\n\t\t58105: 811,  // DropTableStmt (2x)\n\t\t58106: 812,  // DropUserStmt (2x)\n\t\t58107: 813,  // DropViewStmt (2x)\n\t\t58108: 814,  // DuplicateOpt (2x)\n\t\t58110: 815,  // EmptyStmt (2x)\n\t\t58111: 816,  // EndpointOpt (2x)\n\t\t58113: 817,  // EnforcedOrNotOpt (2x)\n\t\t58115: 818,  // EngineOpt (2x)\n\t\t58119: 819,  // ExecuteStmt (2x)\n\t\t57413: 820,  // explain (2x)\n\t\t58121: 821,  // ExplainStmt (2x)\n\t\t58122: 822,  // ExplainSym (2x)\n\t\t58130: 823,  // FieldAsName (2x)\n\t\t58131: 824,  // FieldAsNameOpt (2x)\n\t\t58132: 825,  // FieldItem (2x)\n\t\t58135: 826,  // FieldList (2x)\n\t\t58142: 827,  // FlashbackTableStmt (2x)\n\t\t58145: 828,  // FloatOpt (2x)\n\t\t58148: 829,  // FlushStmt (2x)\n\t\t58149: 830,  // FromDual (2x)\n\t\t58153: 831,  // FuncDatetimePrecList (2x)\n\t\t58154: 832,  // FuncDatetimePrecListOpt (2x)\n\t\t58163: 833,  // GeneratedAlways (2x)\n\t\t58166: 834,  // GrantRoleStmt (2x)\n\t\t58167: 835,  // GrantStmt (2x)\n\t\t58169: 836,  // HandleRange (2x)\n\t\t58171: 837,  // HashString (2x)\n\t\t58179: 838,  // IndexAdviseStmt (2x)\n\t\t58181: 839,  // IndexHintList (2x)\n\t\t58182: 840,  // IndexHintListOpt (2x)\n\t\t58187: 841,  // IndexLockAndAlgorithmOpt (2x)\n\t\t58200: 842,  // InsertValues (2x)\n\t\t57439: 843,  // integerType (2x)\n\t\t58202: 844,  // IntoOpt (2x)\n\t\t58208: 845,  // KeyOrIndexOpt (2x)\n\t\t57454: 846,  // kill (2x)\n\t\t58209: 847,  // KillOrKillTiDB (2x)\n\t\t58210: 848,  // KillStmt (2x)\n\t\t58215: 849,  // LimitClause (2x)\n\t\t57463: 850,  // linear (2x)\n\t\t58217: 851,  // LinearOpt (2x)\n\t\t58221: 852,  // LoadDataSetItem (2x)\n\t\t58225: 853,  // LoadStatsStmt (2x)\n\t\t58226: 854,  // LocalOpt (2x)\n\t\t58229: 855,  // LockTablesStmt (2x)\n\t\t58237: 856,  // MaxValueOrExpressionList (2x)\n\t\t58243: 857,  // NowSym (2x)\n\t\t58244: 858,  // NowSymFunc (2x)\n\t\t58245: 859,  // NowSymOptionFraction (2x)\n\t\t58246: 860,  // NumList (2x)\n\t\t58250: 861,  // ObjectType (2x)\n\t\t58249: 862,  // ODBCDateTimeType (2x)\n\t\t57355: 863,  // odbcDateType (2x)\n\t\t57357: 864,  // odbcTimestampType (2x)\n\t\t57356: 865,  // odbcTimeType (2x)\n\t\t58251: 866,  // OnDelete (2x)\n\t\t58254: 867,  // OnUpdate (2x)\n\t\t58259: 868,  // OptCollate (2x)\n\t\t58263: 869,  // OptFull (2x)\n\t\t58265: 870,  // OptInteger (2x)\n\t\t58276: 871,  // OptionalBraces (2x)\n\t\t58267: 872,  // OptLeadLagInfo (2x)\n\t\t58266: 873,  // OptLLDefault (2x)\n\t\t58281: 874,  // OuterOpt (2x)\n\t\t58284: 875,  // PartDefOptionList (2x)\n\t\t58287: 876,  // PartitionDefinitionList (2x)\n\t\t58288: 877,  // PartitionDefinitionListOpt (2x)\n\t\t58292: 878,  // PartitionNameListOpt (2x)\n\t\t58294: 879,  // PartitionOpt (2x)\n\t\t58297: 880,  // PartyFile (2x)\n\t\t58301: 881,  // PasswordOpt (2x)\n\t\t58308: 882,  // Precision (2x)\n\t\t58311: 883,  // PreparedStmt (2x)\n\t\t58312: 884,  // PrimaryOpt (2x)\n\t\t58315: 885,  // PrivElemList (2x)\n\t\t58316: 886,  // PrivLevel (2x)\n\t\t57506: 887,  // realType (2x)\n\t\t58319: 888,  // RecoverTableStmt (2x)\n\t\t58321: 889,  // ReferOpt (2x)\n\t\t58323: 890,  // RegexpSym (2x)\n\t\t58324: 891,  // RenameTableStmt (2x)\n\t\t57514: 892,  // revoke (2x)\n\t\t58332: 893,  // RevokeRoleStmt (2x)\n\t\t58333: 894,  // RevokeStmt (2x)\n\t\t58335: 895,  // RoleSpec (2x)\n\t\t58358: 896,  // SequenceOption (2x)\n\t\t58360: 897,  // SetDefaultRoleOpt (2x)\n\t\t58361: 898,  // SetDefaultRoleStmt (2x)\n\t\t58364: 899,  // SetRoleStmt (2x)\n\t\t58370: 900,  // ShowProfileType (2x)\n\t\t58373: 901,  // ShowStmt (2x)\n\t\t58374: 902,  // ShowTableAliasOpt (2x)\n\t\t58376: 903,  // ShutdownStmt (2x)\n\t\t58377: 904,  // SignedLiteral (2x)\n\t\t58381: 905,  // SplitOption (2x)\n\t\t58382: 906,  // SplitRegionStmt (2x)\n\t\t58386: 907,  // Statement (2x)\n\t\t58388: 908,  // StatsPersistentVal (2x)\n\t\t58394: 909,  // SubPartDefinition (2x)\n\t\t58397: 910,  // SubPartitionMethod (2x)\n\t\t58402: 911,  // Symbol (2x)\n\t\t58404: 912,  // TableAliasRefList (2x)\n\t\t58406: 913,  // TableAsNameOpt (2x)\n\t\t58408: 914,  // TableElementList (2x)\n\t\t58411: 915,  // TableLock (2x)\n\t\t58415: 916,  // TableNameListOpt (2x)\n\t\t58420: 917,  // TableOrTables (2x)\n\t\t58426: 918,  // TablesTerminalSym (2x)\n\t\t58424: 919,  // TableToTable (2x)\n\t\t58433: 920,  // TraceableStmt (2x)\n\t\t58432: 921,  // TraceStmt (2x)\n\t\t58437: 922,  // TruncateTableStmt (2x)\n\t\t57546: 923,  // unlock (2x)\n\t\t58445: 924,  // UnlockTablesStmt (2x)\n\t\t57547: 925,  // unsigned (2x)\n\t\t58447: 926,  // UseStmt (2x)\n\t\t58462: 927,  // VariableAssignmentList (2x)\n\t\t58471: 928,  // WhenClause (2x)\n\t\t58476: 929,  // WindowDefinition (2x)\n\t\t58479: 930,  // WindowFrameBound (2x)\n\t\t58486: 931,  // WindowSpec (2x)\n\t\t61:    932,  // '=' (1x)\n\t\t57999: 933,  // AdminShowSlow (1x)\n\t\t58005: 934,  // AlterOrderList (1x)\n\t\t58006: 935,  // AlterTablePartitionOpt (1x)\n\t\t58008: 936,  // AlterTableSpecList (1x)\n\t\t58009: 937,  // AlterTableSpecListOpt (1x)\n\t\t58013: 938,  // AnalyzeOptionList (1x)\n\t\t58016: 939,  // AnyOrAll (1x)\n\t\t58017: 940,  // AsOpt (1x)\n\t\t58021: 941,  // AuthOption (1x)\n\t\t58024: 942,  // BetweenOrNotOp (1x)\n\t\t57369: 943,  // both (1x)\n\t\t58039: 944,  // CharsetNameOrDefault (1x)\n\t\t58040: 945,  // CharsetOpt (1x)\n\t\t58045: 946,  // ColumnFormat (1x)\n\t\t58047: 947,  // ColumnList (1x)\n\t\t58054: 948,  // ColumnNameOrUserVariableList (1x)\n\t\t58051: 949,  // ColumnNameOrUserVarListOpt (1x)\n\t\t58052: 950,  // ColumnNameOrUserVarListOptWithBrackets (1x)\n\t\t58056: 951,  // ColumnOptionList (1x)\n\t\t58057: 952,  // ColumnOptionListOpt (1x)\n\t\t58060: 953,  // ColumnSetValueList (1x)\n\t\t58063: 954,  // CompareOp (1x)\n\t\t58067: 955,  // Constraint (1x)\n\t\t58068: 956,  // ConstraintElem (1x)\n\t\t58074: 957,  // CreateSequenceOptionListOpt (1x)\n\t\t58077: 958,  // CreateTableSelectOpt (1x)\n\t\t58080: 959,  // CreateViewSelectOpt (1x)\n\t\t58086: 960,  // DatabaseOptionListOpt (1x)\n\t\t58093: 961,  // DefaultTrueDistinctOpt (1x)\n\t\t58094: 962,  // DefaultValueExpr (1x)\n\t\t57407: 963,  // dual (1x)\n\t\t58109: 964,  // ElseOpt (1x)\n\t\t58114: 965,  // EnforcedOrNotOrNotNullOpt (1x)\n\t\t57414: 966,  // except (1x)\n\t\t58120: 967,  // ExplainFormatType (1x)\n\t\t58128: 968,  // ExpressionOpt (1x)\n\t\t58133: 969,  // FieldItemList (1x)\n\t\t58143: 970,  // FlashbackToNewName (1x)\n\t\t58144: 971,  // FlashbackUntil (1x)\n\t\t58147: 972,  // FlushOption (1x)\n\t\t58151: 973,  // FulltextSearchModifierOpt (1x)\n\t\t58152: 974,  // FuncDatetimePrec (1x)\n\t\t58164: 975,  // GetFormatSelector (1x)\n\t\t58168: 976,  // GroupByClause (1x)\n\t\t58170: 977,  // HandleRangeList (1x)\n\t\t58172: 978,  // HavingClause (1x)\n\t\t58176: 979,  // IgnoreLines (1x)\n\t\t58183: 980,  // IndexHintScope (1x)\n\t\t58186: 981,  // IndexKeyTypeOpt (1x)\n\t\t58195: 982,  // IndexPartSpecificationListOpt (1x)\n\t\t58198: 983,  // IndexTypeOpt (1x)\n\t\t58178: 984,  // InOrNotOp (1x)\n\t\t58204: 985,  // IsolationLevel (1x)\n\t\t58203: 986,  // IsOrNotOp (1x)\n\t\t57458: 987,  // leading (1x)\n\t\t58212: 988,  // LikeEscapeOpt (1x)\n\t\t58213: 989,  // LikeOrNotOp (1x)\n\t\t58214: 990,  // LikeTableWithOrWithoutParen (1x)\n\t\t58219: 991,  // LinesTerminated (1x)\n\t\t58222: 992,  // LoadDataSetList (1x)\n\t\t58223: 993,  // LoadDataSetSpecOpt (1x)\n\t\t58227: 994,  // LocationLabelList (1x)\n\t\t58230: 995,  // LockType (1x)\n\t\t58231: 996,  // LogTypeOpt (1x)\n\t\t58232: 997,  // Match (1x)\n\t\t58233: 998,  // MatchOpt (1x)\n\t\t58234: 999,  // MaxIndexNumOpt (1x)\n\t\t58235: 1000, // MaxMinutesOpt (1x)\n\t\t58252: 1001, // OnDeleteUpdateOpt (1x)\n\t\t58253: 1002, // OnDuplicateKeyUpdate (1x)\n\t\t58256: 1003, // OptBinary (1x)\n\t\t58255: 1004, // OptBinMod (1x)\n\t\t58257: 1005, // OptCharset (1x)\n\t\t58260: 1006, // OptExistingWindowName (1x)\n\t\t58262: 1007, // OptFromFirstLast (1x)\n\t\t58264: 1008, // OptGConcatSeparator (1x)\n\t\t58269: 1009, // OptPartitionClause (1x)\n\t\t58270: 1010, // OptTable (1x)\n\t\t58273: 1011, // OptWindowFrameClause (1x)\n\t\t58274: 1012, // OptWindowOrderByClause (1x)\n\t\t58277: 1013, // OrReplace (1x)\n\t\t57442: 1014, // outfile (1x)\n\t\t57496: 1015, // parser (1x)\n\t\t58285: 1016, // PartDefValuesOpt (1x)\n\t\t58289: 1017, // PartitionKeyAlgorithmOpt (1x)\n\t\t58290: 1018, // PartitionMethod (1x)\n\t\t58293: 1019, // PartitionNumOpt (1x)\n\t\t58295: 1020, // PartyCodeOption (1x)\n\t\t58296: 1021, // PartyCodeString (1x)\n\t\t58298: 1022, // PartyFileList (1x)\n\t\t58299: 1023, // PartySelectFieldList (1x)\n\t\t58305: 1024, // PerDB (1x)\n\t\t58306: 1025, // PerTable (1x)\n\t\t58310: 1026, // PrepareSQL (1x)\n\t\t57500: 1027, // procedure (1x)\n\t\t58318: 1028, // QuickOptional (1x)\n\t\t58322: 1029, // RegexpOrNotOp (1x)\n\t\t58325: 1030, // ReorganizePartitionRuleOpt (1x)\n\t\t58329: 1031, // RequireList (1x)\n\t\t58336: 1032, // RoleSpecList (1x)\n\t\t58345: 1033, // SelectStmtCalcFoundRows (1x)\n\t\t58346: 1034, // SelectStmtFieldList (1x)\n\t\t58349: 1035, // SelectStmtGroup (1x)\n\t\t58352: 1036, // SelectStmtOpts (1x)\n\t\t58353: 1037, // SelectStmtSQLBigResult (1x)\n\t\t58354: 1038, // SelectStmtSQLBufferResult (1x)\n\t\t58355: 1039, // SelectStmtSQLCache (1x)\n\t\t58356: 1040, // SelectStmtSQLSmallResult (1x)\n\t\t58357: 1041, // SelectStmtStraightJoin (1x)\n\t\t58359: 1042, // SequenceOptionList (1x)\n\t\t58363: 1043, // SetRoleOpt (1x)\n\t\t58367: 1044, // ShowIndexKwd (1x)\n\t\t58369: 1045, // ShowProfileArgsOpt (1x)\n\t\t58371: 1046, // ShowProfileTypes (1x)\n\t\t58372: 1047, // ShowProfileTypesOpt (1x)\n\t\t58375: 1048, // ShowTargetFilterable (1x)\n\t\t57525: 1049, // spatial (1x)\n\t\t58383: 1050, // SplitSyntaxOption (1x)\n\t\t57530: 1051, // ssl (1x)\n\t\t58384: 1052, // Start (1x)\n\t\t58385: 1053, // Starting (1x)\n\t\t57531: 1054, // starting (1x)\n\t\t58387: 1055, // StatementList (1x)\n\t\t58389: 1056, // StorageMedia (1x)\n\t\t57534: 1057, // stored (1x)\n\t\t58395: 1058, // SubPartDefinitionList (1x)\n\t\t58396: 1059, // SubPartDefinitionListOpt (1x)\n\t\t58398: 1060, // SubPartitionNumOpt (1x)\n\t\t58399: 1061, // SubPartitionOpt (1x)\n\t\t58409: 1062, // TableElementListOpt (1x)\n\t\t58412: 1063, // TableLockList (1x)\n\t\t58423: 1064, // TableRefsClause (1x)\n\t\t58425: 1065, // TableToTableList (1x)\n\t\t58430: 1066, // TimestampBound (1x)\n\t\t57541: 1067, // trailing (1x)\n\t\t58436: 1068, // TrimDirection (1x)\n\t\t58439: 1069, // TypeName (1x)\n\t\t58442: 1070, // UnionOpt (1x)\n\t\t58451: 1071, // UserVariableList (1x)\n\t\t58454: 1072, // UsingRoles (1x)\n\t\t58456: 1073, // Values (1x)\n\t\t58458: 1074, // ValuesOpt (1x)\n\t\t58464: 1075, // ViewAlgorithm (1x)\n\t\t58465: 1076, // ViewCheckOption (1x)\n\t\t58466: 1077, // ViewDefiner (1x)\n\t\t58467: 1078, // ViewFieldList (1x)\n\t\t58468: 1079, // ViewName (1x)\n\t\t58469: 1080, // ViewSQLSecurity (1x)\n\t\t57562: 1081, // virtual (1x)\n\t\t58470: 1082, // VirtualOrStored (1x)\n\t\t58472: 1083, // WhenClauseList (1x)\n\t\t58475: 1084, // WindowClauseOptional (1x)\n\t\t58477: 1085, // WindowDefinitionList (1x)\n\t\t58478: 1086, // WindowFrameBetween (1x)\n\t\t58480: 1087, // WindowFrameExtent (1x)\n\t\t58482: 1088, // WindowFrameUnits (1x)\n\t\t58485: 1089, // WindowNameOrSpec (1x)\n\t\t58487: 1090, // WindowSpecDetails (1x)\n\t\t58489: 1091, // WithGrantOptionOpt (1x)\n\t\t58490: 1092, // WithReadLockOpt (1x)\n\t\t58491: 1093, // WithValidation (1x)\n\t\t58492: 1094, // WithValidationOpt (1x)\n\t\t57998: 1095, // $default (0x)\n\t\t57965: 1096, // andnot (0x)\n\t\t58020: 1097, // AssignmentListOpt (0x)\n\t\t57366: 1098, // bigIntType (0x)\n\t\t58027: 1099, // BitValueType (0x)\n\t\t58028: 1100, // BlobType (0x)\n\t\t57368: 1101, // blobType (0x)\n\t\t58030: 1102, // BooleanType (0x)\n\t\t58036: 1103, // Char (0x)\n\t\t58041: 1104, // ClearPasswordExpireOptions (0x)\n\t\t58044: 1105, // ColumnDefList (0x)\n\t\t58061: 1106, // CommaOpt (0x)\n\t\t58064: 1107, // ConnectionOption (0x)\n\t\t58065: 1108, // ConnectionOptionList (0x)\n\t\t58066: 1109, // ConnectionOptions (0x)\n\t\t57985: 1110, // createTableSelect (0x)\n\t\t58088: 1111, // DateAndTimeType (0x)\n\t\t57978: 1112, // empty (0x)\n\t\t57345: 1113, // error (0x)\n\t\t58136: 1114, // FieldOpt (0x)\n\t\t58137: 1115, // FieldOpts (0x)\n\t\t58141: 1116, // FixedPointType (0x)\n\t\t58146: 1117, // FloatingPointType (0x)\n\t\t57997: 1118, // higherThanComma (0x)\n\t\t57983: 1119, // insertValues (0x)\n\t\t57446: 1120, // int1Type (0x)\n\t\t57447: 1121, // int2Type (0x)\n\t\t57448: 1122, // int3Type (0x)\n\t\t57449: 1123, // int4Type (0x)\n\t\t57450: 1124, // int8Type (0x)\n\t\t58201: 1125, // IntegerType (0x)\n\t\t57351: 1126, // invalid (0x)\n\t\t57468: 1127, // longblobType (0x)\n\t\t57469: 1128, // longtextType (0x)\n\t\t57986: 1129, // lowerThanCharsetKwd (0x)\n\t\t57996: 1130, // lowerThanComma (0x)\n\t\t57984: 1131, // lowerThanCreateTableSelect (0x)\n\t\t57993: 1132, // lowerThanEq (0x)\n\t\t57982: 1133, // lowerThanInsertValues (0x)\n\t\t57979: 1134, // lowerThanIntervalKeyword (0x)\n\t\t57987: 1135, // lowerThanKey (0x)\n\t\t57988: 1136, // lowerThanLocal (0x)\n\t\t57995: 1137, // lowerThanNot (0x)\n\t\t57992: 1138, // lowerThanOn (0x)\n\t\t57989: 1139, // lowerThanRemove (0x)\n\t\t57981: 1140, // lowerThanSetKeyword (0x)\n\t\t57980: 1141, // lowerThanStringLitToken (0x)\n\t\t57990: 1142, // lowerThenOrder (0x)\n\t\t57473: 1143, // mediumblobType (0x)\n\t\t57474: 1144, // mediumIntType (0x)\n\t\t57475: 1145, // mediumtextType (0x)\n\t\t58238: 1146, // NChar (0x)\n\t\t57994: 1147, // neg (0x)\n\t\t58248: 1148, // NumericType (0x)\n\t\t57484: 1149, // numericType (0x)\n\t\t58240: 1150, // NVarchar (0x)\n\t\t57485: 1151, // nvarcharType (0x)\n\t\t58258: 1152, // OptCharsetWithOptBinary (0x)\n\t\t58300: 1153, // PasswordExpire (0x)\n\t\t58302: 1154, // PasswordOrLockOption (0x)\n\t\t58303: 1155, // PasswordOrLockOptionList (0x)\n\t\t58304: 1156, // PasswordOrLockOptions (0x)\n\t\t57498: 1157, // precisionType (0x)\n\t\t57524: 1158, // smallIntType (0x)\n\t\t58393: 1159, // StringType (0x)\n\t\t57991: 1160, // tableRefPriority (0x)\n\t\t58427: 1161, // TextType (0x)\n\t\t57537: 1162, // tinyblobType (0x)\n\t\t57538: 1163, // tinyIntType (0x)\n\t\t57539: 1164, // tinytextType (0x)\n\t\t58438: 1165, // Type (0x)\n\t\t57560: 1166, // varbinaryType (0x)\n\t\t58459: 1167, // Varchar (0x)\n\t\t57559: 1168, // varcharacter (0x)\n\t\t57558: 1169, // varcharType (0x)\n\t\t57561: 1170, // varying (0x)\n\t\t58493: 1171, // Year (0x)\n\t\t57570: 1172, // zerofill (0x)\n\t}\n\n\tyySymNames = []string{\n\t\t\"$end\",\n\t\t\"';'\",\n\t\t\"remove\",\n\t\t\"comment\",\n\t\t\"storage\",\n\t\t\"autoIncrement\",\n\t\t\"keyBlockSize\",\n\t\t\"charsetKwd\",\n\t\t\"tablespace\",\n\t\t\"','\",\n\t\t\"engine\",\n\t\t\"data\",\n\t\t\"encryption\",\n\t\t\"insertMethod\",\n\t\t\"maxRows\",\n\t\t\"minRows\",\n\t\t\"nodegroup\",\n\t\t\"connection\",\n\t\t\"password\",\n\t\t\"checksum\",\n\t\t\"avgRowLength\",\n\t\t\"compression\",\n\t\t\"dbType\",\n\t\t\"delayKeyWrite\",\n\t\t\"refTable\",\n\t\t\"rowFormat\",\n\t\t\"secondaryEngine\",\n\t\t\"statsAutoRecalc\",\n\t\t\"statsPersistent\",\n\t\t\"statsSamplePages\",\n\t\t\"tableChecksum\",\n\t\t\"first\",\n\t\t\"after\",\n\t\t\"autoRandom\",\n\t\t\"columnFormat\",\n\t\t\"serial\",\n\t\t\"start\",\n\t\t\"no\",\n\t\t\"cache\",\n\t\t\"cycle\",\n\t\t\"minValue\",\n\t\t\"algorithm\",\n\t\t\"increment\",\n\t\t\"nocache\",\n\t\t\"nocycle\",\n\t\t\"nomaxvalue\",\n\t\t\"nominvalue\",\n\t\t\"noorder\",\n\t\t\"tp\",\n\t\t\"invisible\",\n\t\t\"visible\",\n\t\t\"view\",\n\t\t\"columns\",\n\t\t\"fields\",\n\t\t\"subpartition\",\n\t\t\"partitions\",\n\t\t\"partyCode\",\n\t\t\"tables\",\n\t\t\"separator\",\n\t\t\"status\",\n\t\t\"identified\",\n\t\t\"preceding\",\n\t\t\"day\",\n\t\t\"hour\",\n\t\t\"microsecond\",\n\t\t\"minute\",\n\t\t\"month\",\n\t\t\"quarter\",\n\t\t\"second\",\n\t\t\"sqlTsiDay\",\n\t\t\"sqlTsiHour\",\n\t\t\"sqlTsiMinute\",\n\t\t\"sqlTsiMonth\",\n\t\t\"sqlTsiQuarter\",\n\t\t\"sqlTsiSecond\",\n\t\t\"sqlTsiWeek\",\n\t\t\"sqlTsiYear\",\n\t\t\"week\",\n\t\t\"yearType\",\n\t\t\"cipher\",\n\t\t\"issuer\",\n\t\t\"local\",\n\t\t\"subject\",\n\t\t\"definer\",\n\t\t\"hash\",\n\t\t\"logs\",\n\t\t\"respect\",\n\t\t\"bindings\",\n\t\t\"current\",\n\t\t\"following\",\n\t\t\"binding\",\n\t\t\"end\",\n\t\t\"query\",\n\t\t\"sequence\",\n\t\t\"unbounded\",\n\t\t\"enforced\",\n\t\t\"offset\",\n\t\t\"prepare\",\n\t\t\"regions\",\n\t\t\"role\",\n\t\t\"timestampType\",\n\t\t\"user\",\n\t\t\"begin\",\n\t\t\"btree\",\n\t\t\"commit\",\n\t\t\"isolation\",\n\t\t\"max_idxnum\",\n\t\t\"memory\",\n\t\t\"per_db\",\n\t\t\"privileges\",\n\t\t\"rollback\",\n\t\t\"rtree\",\n\t\t\"temporary\",\n\t\t\"truncate\",\n\t\t\"validation\",\n\t\t\"value\",\n\t\t\"variables\",\n\t\t\"datetimeType\",\n\t\t\"dateType\",\n\t\t\"disable\",\n\t\t\"dynamic\",\n\t\t\"enable\",\n\t\t\"endpoint\",\n\t\t\"execute\",\n\t\t\"fixed\",\n\t\t\"flush\",\n\t\t\"full\",\n\t\t\"global\",\n\t\t\"jsonType\",\n\t\t\"location\",\n\t\t\"mode\",\n\t\t\"next_row_id\",\n\t\t\"plugins\",\n\t\t\"processlist\",\n\t\t\"recover\",\n\t\t\"repair\",\n\t\t\"session\",\n\t\t\"shutdown\",\n\t\t\"subpartitions\",\n\t\t\"tidb\",\n\t\t\"timeType\",\n\t\t\"unknown\",\n\t\t\"without\",\n\t\t\"admin\",\n\t\t\"binlog\",\n\t\t\"block\",\n\t\t\"buckets\",\n\t\t\"client\",\n\t\t\"cmSketch\",\n\t\t\"coalesce\",\n\t\t\"compact\",\n\t\t\"compressed\",\n\t\t\"context\",\n\t\t\"copyKwd\",\n\t\t\"cpu\",\n\t\t\"deallocate\",\n\t\t\"directory\",\n\t\t\"discard\",\n\t\t\"disk\",\n\t\t\"do\",\n\t\t\"drainer\",\n\t\t\"exchange\",\n\t\t\"expansion\",\n\t\t\"flashback\",\n\t\t\"hosts\",\n\t\t\"identifier\",\n\t\t\"importKwd\",\n\t\t\"inplace\",\n\t\t\"instant\",\n\t\t\"ipc\",\n\t\t\"job\",\n\t\t\"jobs\",\n\t\t\"modify\",\n\t\t\"nodeID\",\n\t\t\"nodeState\",\n\t\t\"nulls\",\n\t\t\"only\",\n\t\t\"pageSym\",\n\t\t\"pump\",\n\t\t\"rebuild\",\n\t\t\"redundant\",\n\t\t\"reload\",\n\t\t\"reorganize\",\n\t\t\"routine\",\n\t\t\"samples\",\n\t\t\"secondaryLoad\",\n\t\t\"secondaryUnload\",\n\t\t\"signed\",\n\t\t\"slave\",\n\t\t\"slow\",\n\t\t\"source\",\n\t\t\"split\",\n\t\t\"staleness\",\n\t\t\"stats\",\n\t\t\"swaps\",\n\t\t\"tokudbDefault\",\n\t\t\"tokudbFast\",\n\t\t\"tokudbLzma\",\n\t\t\"tokudbQuickLZ\",\n\t\t\"tokudbSmall\",\n\t\t\"tokudbSnappy\",\n\t\t\"tokudbUncompressed\",\n\t\t\"tokudbZlib\",\n\t\t\"topn\",\n\t\t\"trace\",\n\t\t\"action\",\n\t\t\"advise\",\n\t\t\"against\",\n\t\t\"always\",\n\t\t\"booleanType\",\n\t\t\"bound\",\n\t\t\"builtins\",\n\t\t\"cancel\",\n\t\t\"capture\",\n\t\t\"cascaded\",\n\t\t\"cleanup\",\n\t\t\"collation\",\n\t\t\"committed\",\n\t\t\"consistent\",\n\t\t\"ddl\",\n\t\t\"depth\",\n\t\t\"duplicate\",\n\t\t\"encryptedOnly\",\n\t\t\"engines\",\n\t\t\"event\",\n\t\t\"events\",\n\t\t\"evolve\",\n\t\t\"exact\",\n\t\t\"exprPushdownBlacklist\",\n\t\t\"extended\",\n\t\t\"faultsSym\",\n\t\t\"file\",\n\t\t\"format\",\n\t\t\"function\",\n\t\t\"grants\",\n\t\t\"history\",\n\t\t\"identSQLErrors\",\n\t\t\"incremental\",\n\t\t\"indexes\",\n\t\t\"internal\",\n\t\t\"invoker\",\n\t\t\"io\",\n\t\t\"labels\",\n\t\t\"language\",\n\t\t\"last\",\n\t\t\"less\",\n\t\t\"level\",\n\t\t\"list\",\n\t\t\"master\",\n\t\t\"max\",\n\t\t\"max_minutes\",\n\t\t\"maxConnectionsPerHour\",\n\t\t\"maxQueriesPerHour\",\n\t\t\"maxUpdatesPerHour\",\n\t\t\"maxUserConnections\",\n\t\t\"merge\",\n\t\t\"min\",\n\t\t\"none\",\n\t\t\"nowait\",\n\t\t\"open\",\n\t\t\"optimistic\",\n\t\t\"optRuleBlacklist\",\n\t\t\"partial\",\n\t\t\"partitioning\",\n\t\t\"per_table\",\n\t\t\"pessimistic\",\n\t\t\"plaintext\",\n\t\t\"plaintextAfterAggregate\",\n\t\t\"plaintextAfterCompare\",\n\t\t\"plaintextAfterGroupBy\",\n\t\t\"plaintextAfterJoin\",\n\t\t\"plaintextAsJoinPayload\",\n\t\t\"process\",\n\t\t\"profile\",\n\t\t\"profiles\",\n\t\t\"queries\",\n\t\t\"recent\",\n\t\t\"region\",\n\t\t\"repeatable\",\n\t\t\"replica\",\n\t\t\"replication\",\n\t\t\"revealRank\",\n\t\t\"security\",\n\t\t\"serializable\",\n\t\t\"share\",\n\t\t\"simple\",\n\t\t\"snapshot\",\n\t\t\"statsBuckets\",\n\t\t\"statsHealthy\",\n\t\t\"statsHistograms\",\n\t\t\"statsMeta\",\n\t\t\"strong\",\n\t\t\"super\",\n\t\t\"switchesSym\",\n\t\t\"systemTime\",\n\t\t\"temptable\",\n\t\t\"than\",\n\t\t\"tiFlash\",\n\t\t\"tokenWord\",\n\t\t\"top\",\n\t\t\"traditional\",\n\t\t\"transaction\",\n\t\t\"triggers\",\n\t\t\"uncommitted\",\n\t\t\"undefined\",\n\t\t\"warnings\",\n\t\t\"width\",\n\t\t\"x509\",\n\t\t\"account\",\n\t\t\"addDate\",\n\t\t\"any\",\n\t\t\"ascii\",\n\t\t\"avg\",\n\t\t\"bitAnd\",\n\t\t\"bitOr\",\n\t\t\"bitType\",\n\t\t\"bitXor\",\n\t\t\"boolType\",\n\t\t\"byteType\",\n\t\t\"cast\",\n\t\t\"count\",\n\t\t\"curTime\",\n\t\t\"dateAdd\",\n\t\t\"dateSub\",\n\t\t\"enum\",\n\t\t\"escape\",\n\t\t\"exclusive\",\n\t\t\"expire\",\n\t\t\"extract\",\n\t\t\"getFormat\",\n\t\t\"groupConcat\",\n\t\t\"names\",\n\t\t\"national\",\n\t\t\"ncharType\",\n\t\t\"never\",\n\t\t\"now\",\n\t\t\"percentileDisc\",\n\t\t\"position\",\n\t\t\"quick\",\n\t\t\"reverse\",\n\t\t\"rowCount\",\n\t\t\"shared\",\n\t\t\"some\",\n\t\t\"sqlBufferResult\",\n\t\t\"sqlCache\",\n\t\t\"sqlNoCache\",\n\t\t\"std\",\n\t\t\"stddev\",\n\t\t\"stddevPop\",\n\t\t\"stddevSamp\",\n\t\t\"subDate\",\n\t\t\"substring\",\n\t\t\"sum\",\n\t\t\"textType\",\n\t\t\"timestampAdd\",\n\t\t\"timestampDiff\",\n\t\t\"trim\",\n\t\t\"unicodeSym\",\n\t\t\"variance\",\n\t\t\"varPop\",\n\t\t\"varSamp\",\n\t\t\"')'\",\n\t\t\"'('\",\n\t\t\"stringLit\",\n\t\t\"on\",\n\t\t\"union\",\n\t\t\"left\",\n\t\t\"right\",\n\t\t\"with\",\n\t\t\"not\",\n\t\t\"'+'\",\n\t\t\"'-'\",\n\t\t\"mod\",\n\t\t\"defaultKwd\",\n\t\t\"as\",\n\t\t\"using\",\n\t\t\"collate\",\n\t\t\"forKwd\",\n\t\t\"order\",\n\t\t\"lock\",\n\t\t\"into\",\n\t\t\"limit\",\n\t\t\"and\",\n\t\t\"where\",\n\t\t\"replace\",\n\t\t\"or\",\n\t\t\"andand\",\n\t\t\"charType\",\n\t\t\"pipesAsOr\",\n\t\t\"xor\",\n\t\t\"from\",\n\t\t\"eq\",\n\t\t\"set\",\n\t\t\"intLit\",\n\t\t\"null\",\n\t\t\"partition\",\n\t\t\"straightJoin\",\n\t\t\"window\",\n\t\t\"having\",\n\t\t\"join\",\n\t\t\"group\",\n\t\t\"natural\",\n\t\t\"cross\",\n\t\t\"inner\",\n\t\t\"'}'\",\n\t\t\"like\",\n\t\t\"'*'\",\n\t\t\"'.'\",\n\t\t\"rangeKwd\",\n\t\t\"groups\",\n\t\t\"rows\",\n\t\t\"desc\",\n\t\t\"asc\",\n\t\t\"dayHour\",\n\t\t\"dayMicrosecond\",\n\t\t\"dayMinute\",\n\t\t\"daySecond\",\n\t\t\"hourMicrosecond\",\n\t\t\"hourMinute\",\n\t\t\"hourSecond\",\n\t\t\"minuteMicrosecond\",\n\t\t\"minuteSecond\",\n\t\t\"secondMicrosecond\",\n\t\t\"yearMonth\",\n\t\t\"when\",\n\t\t\"in\",\n\t\t\"elseKwd\",\n\t\t\"then\",\n\t\t\"'<'\",\n\t\t\"'>'\",\n\t\t\"ge\",\n\t\t\"ifKwd\",\n\t\t\"is\",\n\t\t\"le\",\n\t\t\"neq\",\n\t\t\"neqSynonym\",\n\t\t\"nulleq\",\n\t\t\"between\",\n\t\t\"binaryType\",\n\t\t\"'%'\",\n\t\t\"'&'\",\n\t\t\"'/'\",\n\t\t\"'^'\",\n\t\t\"'|'\",\n\t\t\"div\",\n\t\t\"lsh\",\n\t\t\"rsh\",\n\t\t\"singleAtIdentifier\",\n\t\t\"regexpKwd\",\n\t\t\"rlike\",\n\t\t\"currentUser\",\n\t\t\"insert\",\n\t\t\"'{'\",\n\t\t\"decLit\",\n\t\t\"floatLit\",\n\t\t\"leftMarker\",\n\t\t\"interval\",\n\t\t\"bitLit\",\n\t\t\"hexLit\",\n\t\t\"values\",\n\t\t\"exists\",\n\t\t\"falseKwd\",\n\t\t\"trueKwd\",\n\t\t\"convert\",\n\t\t\"database\",\n\t\t\"doubleAtIdentifier\",\n\t\t\"builtinNow\",\n\t\t\"currentTs\",\n\t\t\"localTime\",\n\t\t\"localTs\",\n\t\t\"underscoreCS\",\n\t\t\"row\",\n\t\t\"'!'\",\n\t\t\"'~'\",\n\t\t\"builtinAddDate\",\n\t\t\"builtinBitAnd\",\n\t\t\"builtinBitOr\",\n\t\t\"builtinBitXor\",\n\t\t\"builtinCast\",\n\t\t\"builtinCount\",\n\t\t\"builtinCurDate\",\n\t\t\"builtinCurTime\",\n\t\t\"builtinDateAdd\",\n\t\t\"builtinDateSub\",\n\t\t\"builtinExtract\",\n\t\t\"builtinGroupConcat\",\n\t\t\"builtinMax\",\n\t\t\"builtinMedian\",\n\t\t\"builtinMin\",\n\t\t\"builtinPercentileDisc\",\n\t\t\"builtinPosition\",\n\t\t\"builtinStddevPop\",\n\t\t\"builtinStddevSamp\",\n\t\t\"builtinSubDate\",\n\t\t\"builtinSubstring\",\n\t\t\"builtinSum\",\n\t\t\"builtinSysDate\",\n\t\t\"builtinTrim\",\n\t\t\"builtinUser\",\n\t\t\"builtinVarPop\",\n\t\t\"builtinVarSamp\",\n\t\t\"caseKwd\",\n\t\t\"cumeDist\",\n\t\t\"currentDate\",\n\t\t\"currentRole\",\n\t\t\"currentTime\",\n\t\t\"denseRank\",\n\t\t\"firstValue\",\n\t\t\"lag\",\n\t\t\"lastValue\",\n\t\t\"lead\",\n\t\t\"not2\",\n\t\t\"nthValue\",\n\t\t\"ntile\",\n\t\t\"percentRank\",\n\t\t\"rank\",\n\t\t\"repeat\",\n\t\t\"rowNumber\",\n\t\t\"utcDate\",\n\t\t\"utcTime\",\n\t\t\"utcTimestamp\",\n\t\t\"pipes\",\n\t\t\"ignore\",\n\t\t\"match\",\n\t\t\"selectKwd\",\n\t\t\"index\",\n\t\t\"character\",\n\t\t\"key\",\n\t\t\"check\",\n\t\t\"primary\",\n\t\t\"packKeys\",\n\t\t\"preSplitRegions\",\n\t\t\"shardRowIDBits\",\n\t\t\"unique\",\n\t\t\"references\",\n\t\t\"constraint\",\n\t\t\"generated\",\n\t\t\"Identifier\",\n\t\t\"NotKeywordToken\",\n\t\t\"TiDBKeyword\",\n\t\t\"UnReservedKeyword\",\n\t\t\"lines\",\n\t\t\"jss\",\n\t\t\"juss\",\n\t\t\"maxValue\",\n\t\t\"to\",\n\t\t\"by\",\n\t\t\"require\",\n\t\t\"assignmentEq\",\n\t\t\"force\",\n\t\t\"use\",\n\t\t\"sql\",\n\t\t\"'@'\",\n\t\t\"cascade\",\n\t\t\"drop\",\n\t\t\"read\",\n\t\t\"restrict\",\n\t\t\"analyze\",\n\t\t\"alter\",\n\t\t\"create\",\n\t\t\"change\",\n\t\t\"doubleType\",\n\t\t\"floatType\",\n\t\t\"foreign\",\n\t\t\"fulltext\",\n\t\t\"intType\",\n\t\t\"rename\",\n\t\t\"write\",\n\t\t\"add\",\n\t\t\"long\",\n\t\t\"optimize\",\n\t\t\"rightMarker\",\n\t\t\"until\",\n\t\t\"ParamMarker\",\n\t\t\"SubSelect\",\n\t\t\"UserVariable\",\n\t\t\"SimpleIdent\",\n\t\t\"StringLiteral\",\n\t\t\"Literal\",\n\t\t\"FunctionCallGeneric\",\n\t\t\"FunctionCallKeyword\",\n\t\t\"FunctionCallNonKeyword\",\n\t\t\"FunctionNameConflict\",\n\t\t\"FunctionNameDateArith\",\n\t\t\"FunctionNameDateArithMultiForms\",\n\t\t\"FunctionNameDatetimePrecision\",\n\t\t\"FunctionNameOptionalBraces\",\n\t\t\"SimpleExpr\",\n\t\t\"SumExpr\",\n\t\t\"SystemVariable\",\n\t\t\"Variable\",\n\t\t\"WindowFuncCall\",\n\t\t\"BitExpr\",\n\t\t\"PredicateExpr\",\n\t\t\"BoolPri\",\n\t\t\"Expression\",\n\t\t\"logAnd\",\n\t\t\"logOr\",\n\t\t\"NUM\",\n\t\t\"TableName\",\n\t\t\"all\",\n\t\t\"StringName\",\n\t\t\"EqOpt\",\n\t\t\"ColumnName\",\n\t\t\"over\",\n\t\t\"tableKwd\",\n\t\t\"SelectStmt\",\n\t\t\"SelectStmtBasic\",\n\t\t\"SelectStmtFromDualTable\",\n\t\t\"SelectStmtFromTable\",\n\t\t\"WindowingClause\",\n\t\t\"LengthNum\",\n\t\t\"sqlCalcFoundRows\",\n\t\t\"UnionSelect\",\n\t\t\"UnionClauseList\",\n\t\t\"UnionStmt\",\n\t\t\"update\",\n\t\t\"deleteKwd\",\n\t\t\"OptWindowingClause\",\n\t\t\"terminated\",\n\t\t\"delayed\",\n\t\t\"distinct\",\n\t\t\"distinctRow\",\n\t\t\"highPriority\",\n\t\t\"lowPriority\",\n\t\t\"sqlBigResult\",\n\t\t\"Username\",\n\t\t\"enclosed\",\n\t\t\"ExpressionList\",\n\t\t\"DefaultKwdOpt\",\n\t\t\"DistinctKwd\",\n\t\t\"escaped\",\n\t\t\"JoinTable\",\n\t\t\"optionally\",\n\t\t\"PartitionNameList\",\n\t\t\"sqlSmallResult\",\n\t\t\"TableFactor\",\n\t\t\"TableRef\",\n\t\t\"DistinctOpt\",\n\t\t\"DefaultFalseDistinctOpt\",\n\t\t\"FromOrIn\",\n\t\t\"IfExists\",\n\t\t\"IfNotExists\",\n\t\t\"Rolename\",\n\t\t\"RoleNameString\",\n\t\t\"WhereClause\",\n\t\t\"WhereClauseOptional\",\n\t\t\"BuggyDefaultFalseDistinctOpt\",\n\t\t\"CharsetName\",\n\t\t\"OrderBy\",\n\t\t\"OrderByOptional\",\n\t\t\"TableNameList\",\n\t\t\"TimestampUnit\",\n\t\t\"CharsetKw\",\n\t\t\"ExprOrDefault\",\n\t\t\"JoinType\",\n\t\t\"noWriteToBinLog\",\n\t\t\"PartDefOption\",\n\t\t\"AnalyzeOptionListOpt\",\n\t\t\"ColumnNameList\",\n\t\t\"CrossOpt\",\n\t\t\"DeleteFromStmt\",\n\t\t\"FieldLen\",\n\t\t\"IndexPartSpecification\",\n\t\t\"InsertIntoStmt\",\n\t\t\"KeyOrIndex\",\n\t\t\"ReplaceIntoStmt\",\n\t\t\"RolenameList\",\n\t\t\"SelectStmtLimit\",\n\t\t\"TimeUnit\",\n\t\t\"UpdateStmt\",\n\t\t\"VariableName\",\n\t\t\"AllOrPartitionNameList\",\n\t\t\"DBName\",\n\t\t\"EscapedTableRef\",\n\t\t\"FieldsOrColumns\",\n\t\t\"IndexPartSpecificationList\",\n\t\t\"NoWriteToBinLogAliasOpt\",\n\t\t\"RowFormat\",\n\t\t\"ShowDatabaseNameOpt\",\n\t\t\"SignedNum\",\n\t\t\"TableOption\",\n\t\t\"column\",\n\t\t\"ColumnDef\",\n\t\t\"DatabaseOption\",\n\t\t\"EqOrAssignmentEq\",\n\t\t\"grant\",\n\t\t\"IndexInvisible\",\n\t\t\"IndexNameList\",\n\t\t\"IndexType\",\n\t\t\"NumLiteral\",\n\t\t\"OptFieldLen\",\n\t\t\"RowValue\",\n\t\t\"SelectLockOpt\",\n\t\t\"SelectStmtIntoOption\",\n\t\t\"show\",\n\t\t\"ShowLikeOrWhereOpt\",\n\t\t\"TableRefs\",\n\t\t\"AlgorithmClause\",\n\t\t\"ByItem\",\n\t\t\"ColumnKeywordOpt\",\n\t\t\"describe\",\n\t\t\"ExpressionListOpt\",\n\t\t\"IndexName\",\n\t\t\"IndexOption\",\n\t\t\"IndexOptionList\",\n\t\t\"infile\",\n\t\t\"LockClause\",\n\t\t\"OptNullTreatment\",\n\t\t\"PriorityOpt\",\n\t\t\"TableAsName\",\n\t\t\"UsernameList\",\n\t\t\"UserSpec\",\n\t\t\"Assignment\",\n\t\t\"AuthString\",\n\t\t\"BeginTransactionStmt\",\n\t\t\"ByList\",\n\t\t\"CollationName\",\n\t\t\"CommitStmt\",\n\t\t\"errorKwd\",\n\t\t\"ExplainableStmt\",\n\t\t\"FieldTerminator\",\n\t\t\"general\",\n\t\t\"IgnoreOptional\",\n\t\t\"IndexTypeName\",\n\t\t\"LimitOption\",\n\t\t\"Lines\",\n\t\t\"load\",\n\t\t\"LoadDataStmt\",\n\t\t\"option\",\n\t\t\"OptWild\",\n\t\t\"Order\",\n\t\t\"outer\",\n\t\t\"RestrictOrCascadeOpt\",\n\t\t\"RollbackStmt\",\n\t\t\"SetExpr\",\n\t\t\"SetStmt\",\n\t\t\"TableOptionList\",\n\t\t\"TransactionChar\",\n\t\t\"UserSpecList\",\n\t\t\"WindowName\",\n\t\t\"AssignmentList\",\n\t\t\"ColumnPosition\",\n\t\t\"ConstraintKeywordOpt\",\n\t\t\"CreateTableStmt\",\n\t\t\"DatabaseOptionList\",\n\t\t\"DatabaseSym\",\n\t\t\"EnforcedOrNot\",\n\t\t\"Field\",\n\t\t\"Fields\",\n\t\t\"GlobalScope\",\n\t\t\"hintComment\",\n\t\t\"IndexHint\",\n\t\t\"IndexHintType\",\n\t\t\"IndexNameAndTypeOpt\",\n\t\t\"keys\",\n\t\t\"MaxValueOrExpression\",\n\t\t\"OptTemporary\",\n\t\t\"PartitionDefinition\",\n\t\t\"PluginNameList\",\n\t\t\"PrivElem\",\n\t\t\"PrivType\",\n\t\t\"ReferDef\",\n\t\t\"RequireClause\",\n\t\t\"RequireClauseOpt\",\n\t\t\"RequireListElement\",\n\t\t\"StringList\",\n\t\t\"TableElement\",\n\t\t\"TableNameOptWild\",\n\t\t\"TableOptimizerHints\",\n\t\t\"TransactionChars\",\n\t\t\"trigger\",\n\t\t\"usage\",\n\t\t\"ValuesList\",\n\t\t\"ValueSym\",\n\t\t\"VariableAssignment\",\n\t\t\"WindowFrameStart\",\n\t\t\"AdminStmt\",\n\t\t\"AlterDatabaseStmt\",\n\t\t\"AlterOrderItem\",\n\t\t\"AlterTableSpec\",\n\t\t\"AlterTableStmt\",\n\t\t\"AlterUserStmt\",\n\t\t\"AnalyzeOption\",\n\t\t\"AnalyzeTableStmt\",\n\t\t\"BinlogStmt\",\n\t\t\"CastType\",\n\t\t\"ChangeStmt\",\n\t\t\"ColumnNameListOpt\",\n\t\t\"ColumnNameOrUserVariable\",\n\t\t\"ColumnOption\",\n\t\t\"ColumnSetValue\",\n\t\t\"CreateBindingStmt\",\n\t\t\"CreateDatabaseStmt\",\n\t\t\"CreateIndexStmt\",\n\t\t\"CreateRoleStmt\",\n\t\t\"CreateSequenceStmt\",\n\t\t\"CreateTableOptionListOpt\",\n\t\t\"CreateUserStmt\",\n\t\t\"CreateViewStmt\",\n\t\t\"databases\",\n\t\t\"DeallocateStmt\",\n\t\t\"DeallocateSym\",\n\t\t\"decimalType\",\n\t\t\"DoStmt\",\n\t\t\"DropBindingStmt\",\n\t\t\"DropDatabaseStmt\",\n\t\t\"DropIndexStmt\",\n\t\t\"DropRoleStmt\",\n\t\t\"DropSequenceStmt\",\n\t\t\"DropStatsStmt\",\n\t\t\"DropTableStmt\",\n\t\t\"DropUserStmt\",\n\t\t\"DropViewStmt\",\n\t\t\"DuplicateOpt\",\n\t\t\"EmptyStmt\",\n\t\t\"EndpointOpt\",\n\t\t\"EnforcedOrNotOpt\",\n\t\t\"EngineOpt\",\n\t\t\"ExecuteStmt\",\n\t\t\"explain\",\n\t\t\"ExplainStmt\",\n\t\t\"ExplainSym\",\n\t\t\"FieldAsName\",\n\t\t\"FieldAsNameOpt\",\n\t\t\"FieldItem\",\n\t\t\"FieldList\",\n\t\t\"FlashbackTableStmt\",\n\t\t\"FloatOpt\",\n\t\t\"FlushStmt\",\n\t\t\"FromDual\",\n\t\t\"FuncDatetimePrecList\",\n\t\t\"FuncDatetimePrecListOpt\",\n\t\t\"GeneratedAlways\",\n\t\t\"GrantRoleStmt\",\n\t\t\"GrantStmt\",\n\t\t\"HandleRange\",\n\t\t\"HashString\",\n\t\t\"IndexAdviseStmt\",\n\t\t\"IndexHintList\",\n\t\t\"IndexHintListOpt\",\n\t\t\"IndexLockAndAlgorithmOpt\",\n\t\t\"InsertValues\",\n\t\t\"integerType\",\n\t\t\"IntoOpt\",\n\t\t\"KeyOrIndexOpt\",\n\t\t\"kill\",\n\t\t\"KillOrKillTiDB\",\n\t\t\"KillStmt\",\n\t\t\"LimitClause\",\n\t\t\"linear\",\n\t\t\"LinearOpt\",\n\t\t\"LoadDataSetItem\",\n\t\t\"LoadStatsStmt\",\n\t\t\"LocalOpt\",\n\t\t\"LockTablesStmt\",\n\t\t\"MaxValueOrExpressionList\",\n\t\t\"NowSym\",\n\t\t\"NowSymFunc\",\n\t\t\"NowSymOptionFraction\",\n\t\t\"NumList\",\n\t\t\"ObjectType\",\n\t\t\"ODBCDateTimeType\",\n\t\t\"odbcDateType\",\n\t\t\"odbcTimestampType\",\n\t\t\"odbcTimeType\",\n\t\t\"OnDelete\",\n\t\t\"OnUpdate\",\n\t\t\"OptCollate\",\n\t\t\"OptFull\",\n\t\t\"OptInteger\",\n\t\t\"OptionalBraces\",\n\t\t\"OptLeadLagInfo\",\n\t\t\"OptLLDefault\",\n\t\t\"OuterOpt\",\n\t\t\"PartDefOptionList\",\n\t\t\"PartitionDefinitionList\",\n\t\t\"PartitionDefinitionListOpt\",\n\t\t\"PartitionNameListOpt\",\n\t\t\"PartitionOpt\",\n\t\t\"PartyFile\",\n\t\t\"PasswordOpt\",\n\t\t\"Precision\",\n\t\t\"PreparedStmt\",\n\t\t\"PrimaryOpt\",\n\t\t\"PrivElemList\",\n\t\t\"PrivLevel\",\n\t\t\"realType\",\n\t\t\"RecoverTableStmt\",\n\t\t\"ReferOpt\",\n\t\t\"RegexpSym\",\n\t\t\"RenameTableStmt\",\n\t\t\"revoke\",\n\t\t\"RevokeRoleStmt\",\n\t\t\"RevokeStmt\",\n\t\t\"RoleSpec\",\n\t\t\"SequenceOption\",\n\t\t\"SetDefaultRoleOpt\",\n\t\t\"SetDefaultRoleStmt\",\n\t\t\"SetRoleStmt\",\n\t\t\"ShowProfileType\",\n\t\t\"ShowStmt\",\n\t\t\"ShowTableAliasOpt\",\n\t\t\"ShutdownStmt\",\n\t\t\"SignedLiteral\",\n\t\t\"SplitOption\",\n\t\t\"SplitRegionStmt\",\n\t\t\"Statement\",\n\t\t\"StatsPersistentVal\",\n\t\t\"SubPartDefinition\",\n\t\t\"SubPartitionMethod\",\n\t\t\"Symbol\",\n\t\t\"TableAliasRefList\",\n\t\t\"TableAsNameOpt\",\n\t\t\"TableElementList\",\n\t\t\"TableLock\",\n\t\t\"TableNameListOpt\",\n\t\t\"TableOrTables\",\n\t\t\"TablesTerminalSym\",\n\t\t\"TableToTable\",\n\t\t\"TraceableStmt\",\n\t\t\"TraceStmt\",\n\t\t\"TruncateTableStmt\",\n\t\t\"unlock\",\n\t\t\"UnlockTablesStmt\",\n\t\t\"unsigned\",\n\t\t\"UseStmt\",\n\t\t\"VariableAssignmentList\",\n\t\t\"WhenClause\",\n\t\t\"WindowDefinition\",\n\t\t\"WindowFrameBound\",\n\t\t\"WindowSpec\",\n\t\t\"'='\",\n\t\t\"AdminShowSlow\",\n\t\t\"AlterOrderList\",\n\t\t\"AlterTablePartitionOpt\",\n\t\t\"AlterTableSpecList\",\n\t\t\"AlterTableSpecListOpt\",\n\t\t\"AnalyzeOptionList\",\n\t\t\"AnyOrAll\",\n\t\t\"AsOpt\",\n\t\t\"AuthOption\",\n\t\t\"BetweenOrNotOp\",\n\t\t\"both\",\n\t\t\"CharsetNameOrDefault\",\n\t\t\"CharsetOpt\",\n\t\t\"ColumnFormat\",\n\t\t\"ColumnList\",\n\t\t\"ColumnNameOrUserVariableList\",\n\t\t\"ColumnNameOrUserVarListOpt\",\n\t\t\"ColumnNameOrUserVarListOptWithBrackets\",\n\t\t\"ColumnOptionList\",\n\t\t\"ColumnOptionListOpt\",\n\t\t\"ColumnSetValueList\",\n\t\t\"CompareOp\",\n\t\t\"Constraint\",\n\t\t\"ConstraintElem\",\n\t\t\"CreateSequenceOptionListOpt\",\n\t\t\"CreateTableSelectOpt\",\n\t\t\"CreateViewSelectOpt\",\n\t\t\"DatabaseOptionListOpt\",\n\t\t\"DefaultTrueDistinctOpt\",\n\t\t\"DefaultValueExpr\",\n\t\t\"dual\",\n\t\t\"ElseOpt\",\n\t\t\"EnforcedOrNotOrNotNullOpt\",\n\t\t\"except\",\n\t\t\"ExplainFormatType\",\n\t\t\"ExpressionOpt\",\n\t\t\"FieldItemList\",\n\t\t\"FlashbackToNewName\",\n\t\t\"FlashbackUntil\",\n\t\t\"FlushOption\",\n\t\t\"FulltextSearchModifierOpt\",\n\t\t\"FuncDatetimePrec\",\n\t\t\"GetFormatSelector\",\n\t\t\"GroupByClause\",\n\t\t\"HandleRangeList\",\n\t\t\"HavingClause\",\n\t\t\"IgnoreLines\",\n\t\t\"IndexHintScope\",\n\t\t\"IndexKeyTypeOpt\",\n\t\t\"IndexPartSpecificationListOpt\",\n\t\t\"IndexTypeOpt\",\n\t\t\"InOrNotOp\",\n\t\t\"IsolationLevel\",\n\t\t\"IsOrNotOp\",\n\t\t\"leading\",\n\t\t\"LikeEscapeOpt\",\n\t\t\"LikeOrNotOp\",\n\t\t\"LikeTableWithOrWithoutParen\",\n\t\t\"LinesTerminated\",\n\t\t\"LoadDataSetList\",\n\t\t\"LoadDataSetSpecOpt\",\n\t\t\"LocationLabelList\",\n\t\t\"LockType\",\n\t\t\"LogTypeOpt\",\n\t\t\"Match\",\n\t\t\"MatchOpt\",\n\t\t\"MaxIndexNumOpt\",\n\t\t\"MaxMinutesOpt\",\n\t\t\"OnDeleteUpdateOpt\",\n\t\t\"OnDuplicateKeyUpdate\",\n\t\t\"OptBinary\",\n\t\t\"OptBinMod\",\n\t\t\"OptCharset\",\n\t\t\"OptExistingWindowName\",\n\t\t\"OptFromFirstLast\",\n\t\t\"OptGConcatSeparator\",\n\t\t\"OptPartitionClause\",\n\t\t\"OptTable\",\n\t\t\"OptWindowFrameClause\",\n\t\t\"OptWindowOrderByClause\",\n\t\t\"OrReplace\",\n\t\t\"outfile\",\n\t\t\"parser\",\n\t\t\"PartDefValuesOpt\",\n\t\t\"PartitionKeyAlgorithmOpt\",\n\t\t\"PartitionMethod\",\n\t\t\"PartitionNumOpt\",\n\t\t\"PartyCodeOption\",\n\t\t\"PartyCodeString\",\n\t\t\"PartyFileList\",\n\t\t\"PartySelectFieldList\",\n\t\t\"PerDB\",\n\t\t\"PerTable\",\n\t\t\"PrepareSQL\",\n\t\t\"procedure\",\n\t\t\"QuickOptional\",\n\t\t\"RegexpOrNotOp\",\n\t\t\"ReorganizePartitionRuleOpt\",\n\t\t\"RequireList\",\n\t\t\"RoleSpecList\",\n\t\t\"SelectStmtCalcFoundRows\",\n\t\t\"SelectStmtFieldList\",\n\t\t\"SelectStmtGroup\",\n\t\t\"SelectStmtOpts\",\n\t\t\"SelectStmtSQLBigResult\",\n\t\t\"SelectStmtSQLBufferResult\",\n\t\t\"SelectStmtSQLCache\",\n\t\t\"SelectStmtSQLSmallResult\",\n\t\t\"SelectStmtStraightJoin\",\n\t\t\"SequenceOptionList\",\n\t\t\"SetRoleOpt\",\n\t\t\"ShowIndexKwd\",\n\t\t\"ShowProfileArgsOpt\",\n\t\t\"ShowProfileTypes\",\n\t\t\"ShowProfileTypesOpt\",\n\t\t\"ShowTargetFilterable\",\n\t\t\"spatial\",\n\t\t\"SplitSyntaxOption\",\n\t\t\"ssl\",\n\t\t\"Start\",\n\t\t\"Starting\",\n\t\t\"starting\",\n\t\t\"StatementList\",\n\t\t\"StorageMedia\",\n\t\t\"stored\",\n\t\t\"SubPartDefinitionList\",\n\t\t\"SubPartDefinitionListOpt\",\n\t\t\"SubPartitionNumOpt\",\n\t\t\"SubPartitionOpt\",\n\t\t\"TableElementListOpt\",\n\t\t\"TableLockList\",\n\t\t\"TableRefsClause\",\n\t\t\"TableToTableList\",\n\t\t\"TimestampBound\",\n\t\t\"trailing\",\n\t\t\"TrimDirection\",\n\t\t\"TypeName\",\n\t\t\"UnionOpt\",\n\t\t\"UserVariableList\",\n\t\t\"UsingRoles\",\n\t\t\"Values\",\n\t\t\"ValuesOpt\",\n\t\t\"ViewAlgorithm\",\n\t\t\"ViewCheckOption\",\n\t\t\"ViewDefiner\",\n\t\t\"ViewFieldList\",\n\t\t\"ViewName\",\n\t\t\"ViewSQLSecurity\",\n\t\t\"virtual\",\n\t\t\"VirtualOrStored\",\n\t\t\"WhenClauseList\",\n\t\t\"WindowClauseOptional\",\n\t\t\"WindowDefinitionList\",\n\t\t\"WindowFrameBetween\",\n\t\t\"WindowFrameExtent\",\n\t\t\"WindowFrameUnits\",\n\t\t\"WindowNameOrSpec\",\n\t\t\"WindowSpecDetails\",\n\t\t\"WithGrantOptionOpt\",\n\t\t\"WithReadLockOpt\",\n\t\t\"WithValidation\",\n\t\t\"WithValidationOpt\",\n\t\t\"$default\",\n\t\t\"andnot\",\n\t\t\"AssignmentListOpt\",\n\t\t\"bigIntType\",\n\t\t\"BitValueType\",\n\t\t\"BlobType\",\n\t\t\"blobType\",\n\t\t\"BooleanType\",\n\t\t\"Char\",\n\t\t\"ClearPasswordExpireOptions\",\n\t\t\"ColumnDefList\",\n\t\t\"CommaOpt\",\n\t\t\"ConnectionOption\",\n\t\t\"ConnectionOptionList\",\n\t\t\"ConnectionOptions\",\n\t\t\"createTableSelect\",\n\t\t\"DateAndTimeType\",\n\t\t\"empty\",\n\t\t\"error\",\n\t\t\"FieldOpt\",\n\t\t\"FieldOpts\",\n\t\t\"FixedPointType\",\n\t\t\"FloatingPointType\",\n\t\t\"higherThanComma\",\n\t\t\"insertValues\",\n\t\t\"int1Type\",\n\t\t\"int2Type\",\n\t\t\"int3Type\",\n\t\t\"int4Type\",\n\t\t\"int8Type\",\n\t\t\"IntegerType\",\n\t\t\"invalid\",\n\t\t\"longblobType\",\n\t\t\"longtextType\",\n\t\t\"lowerThanCharsetKwd\",\n\t\t\"lowerThanComma\",\n\t\t\"lowerThanCreateTableSelect\",\n\t\t\"lowerThanEq\",\n\t\t\"lowerThanInsertValues\",\n\t\t\"lowerThanIntervalKeyword\",\n\t\t\"lowerThanKey\",\n\t\t\"lowerThanLocal\",\n\t\t\"lowerThanNot\",\n\t\t\"lowerThanOn\",\n\t\t\"lowerThanRemove\",\n\t\t\"lowerThanSetKeyword\",\n\t\t\"lowerThanStringLitToken\",\n\t\t\"lowerThenOrder\",\n\t\t\"mediumblobType\",\n\t\t\"mediumIntType\",\n\t\t\"mediumtextType\",\n\t\t\"NChar\",\n\t\t\"neg\",\n\t\t\"NumericType\",\n\t\t\"numericType\",\n\t\t\"NVarchar\",\n\t\t\"nvarcharType\",\n\t\t\"OptCharsetWithOptBinary\",\n\t\t\"PasswordExpire\",\n\t\t\"PasswordOrLockOption\",\n\t\t\"PasswordOrLockOptionList\",\n\t\t\"PasswordOrLockOptions\",\n\t\t\"precisionType\",\n\t\t\"smallIntType\",\n\t\t\"StringType\",\n\t\t\"tableRefPriority\",\n\t\t\"TextType\",\n\t\t\"tinyblobType\",\n\t\t\"tinyIntType\",\n\t\t\"tinytextType\",\n\t\t\"Type\",\n\t\t\"varbinaryType\",\n\t\t\"Varchar\",\n\t\t\"varcharacter\",\n\t\t\"varcharType\",\n\t\t\"varying\",\n\t\t\"Year\",\n\t\t\"zerofill\",\n\t}\n\n\tyyReductions = []struct{ xsym, components int }{\n\t\t{0, 1},\n\t\t{1052, 1},\n\t\t{781, 6},\n\t\t{781, 8},\n\t\t{781, 10},\n\t\t{935, 1},\n\t\t{935, 2},\n\t\t{994, 0},\n\t\t{994, 3},\n\t\t{780, 1},\n\t\t{780, 5},\n\t\t{780, 5},\n\t\t{780, 5},\n\t\t{780, 5},\n\t\t{780, 6},\n\t\t{780, 2},\n\t\t{780, 5},\n\t\t{780, 6},\n\t\t{780, 3},\n\t\t{780, 4},\n\t\t{780, 5},\n\t\t{780, 3},\n\t\t{780, 4},\n\t\t{780, 7},\n\t\t{780, 3},\n\t\t{780, 4},\n\t\t{780, 4},\n\t\t{780, 4},\n\t\t{780, 4},\n\t\t{780, 2},\n\t\t{780, 2},\n\t\t{780, 4},\n\t\t{780, 4},\n\t\t{780, 4},\n\t\t{780, 5},\n\t\t{780, 3},\n\t\t{780, 2},\n\t\t{780, 2},\n\t\t{780, 5},\n\t\t{780, 6},\n\t\t{780, 6},\n\t\t{780, 8},\n\t\t{780, 5},\n\t\t{780, 5},\n\t\t{780, 3},\n\t\t{780, 3},\n\t\t{780, 3},\n\t\t{780, 5},\n\t\t{780, 1},\n\t\t{780, 1},\n\t\t{780, 1},\n\t\t{780, 2},\n\t\t{780, 2},\n\t\t{780, 1},\n\t\t{780, 1},\n\t\t{780, 4},\n\t\t{780, 3},\n\t\t{780, 4},\n\t\t{1030, 0},\n\t\t{1030, 5},\n\t\t{672, 1},\n\t\t{672, 1},\n\t\t{1094, 0},\n\t\t{1094, 1},\n\t\t{1093, 2},\n\t\t{1093, 2},\n\t\t{698, 3},\n\t\t{698, 3},\n\t\t{698, 3},\n\t\t{698, 3},\n\t\t{698, 3},\n\t\t{707, 3},\n\t\t{707, 3},\n\t\t{665, 1},\n\t\t{665, 1},\n\t\t{845, 0},\n\t\t{845, 1},\n\t\t{700, 0},\n\t\t{700, 1},\n\t\t{742, 0},\n\t\t{742, 1},\n\t\t{742, 2},\n\t\t{937, 0},\n\t\t{937, 1},\n\t\t{936, 1},\n\t\t{936, 3},\n\t\t{634, 1},\n\t\t{634, 3},\n\t\t{743, 0},\n\t\t{743, 1},\n\t\t{743, 2},\n\t\t{911, 1},\n\t\t{891, 3},\n\t\t{1065, 1},\n\t\t{1065, 3},\n\t\t{919, 3},\n\t\t{888, 5},\n\t\t{888, 3},\n\t\t{888, 4},\n\t\t{827, 5},\n\t\t{971, 3},\n\t\t{970, 0},\n\t\t{970, 2},\n\t\t{906, 6},\n\t\t{906, 8},\n\t\t{905, 6},\n\t\t{905, 2},\n\t\t{1050, 0},\n\t\t{1050, 2},\n\t\t{1050, 1},\n\t\t{1050, 3},\n\t\t{784, 4},\n\t\t{784, 6},\n\t\t{784, 7},\n\t\t{784, 6},\n\t\t{784, 8},\n\t\t{784, 9},\n\t\t{658, 0},\n\t\t{658, 2},\n\t\t{938, 1},\n\t\t{938, 3},\n\t\t{783, 2},\n\t\t{783, 2},\n\t\t{783, 3},\n\t\t{783, 3},\n\t\t{783, 2},\n\t\t{713, 3},\n\t\t{741, 1},\n\t\t{741, 3},\n\t\t{1097, 0},\n\t\t{1097, 1},\n\t\t{715, 1},\n\t\t{715, 2},\n\t\t{715, 2},\n\t\t{715, 2},\n\t\t{715, 4},\n\t\t{715, 5},\n\t\t{715, 4},\n\t\t{715, 8},\n\t\t{1066, 1},\n\t\t{1066, 3},\n\t\t{1066, 4},\n\t\t{1066, 3},\n\t\t{1066, 3},\n\t\t{785, 2},\n\t\t{1105, 1},\n\t\t{1105, 3},\n\t\t{683, 3},\n\t\t{603, 1},\n\t\t{603, 3},\n\t\t{603, 5},\n\t\t{1069, 1},\n\t\t{1069, 1},\n\t\t{1069, 1},\n\t\t{1069, 1},\n\t\t{1069, 1},\n\t\t{1069, 1},\n\t\t{659, 1},\n\t\t{659, 3},\n\t\t{788, 0},\n\t\t{788, 1},\n\t\t{949, 0},\n\t\t{949, 1},\n\t\t{948, 1},\n\t\t{948, 3},\n\t\t{789, 1},\n\t\t{789, 1},\n\t\t{950, 0},\n\t\t{950, 3},\n\t\t{718, 1},\n\t\t{884, 0},\n\t\t{884, 1},\n\t\t{747, 1},\n\t\t{747, 2},\n\t\t{817, 0},\n\t\t{817, 1},\n\t\t{965, 2},\n\t\t{965, 1},\n\t\t{790, 2},\n\t\t{790, 1},\n\t\t{790, 1},\n\t\t{790, 2},\n\t\t{790, 1},\n\t\t{790, 2},\n\t\t{790, 2},\n\t\t{790, 3},\n\t\t{790, 3},\n\t\t{790, 2},\n\t\t{790, 6},\n\t\t{790, 6},\n\t\t{790, 1},\n\t\t{790, 2},\n\t\t{790, 2},\n\t\t{790, 2},\n\t\t{790, 2},\n\t\t{1056, 1},\n\t\t{1056, 1},\n\t\t{1056, 1},\n\t\t{946, 1},\n\t\t{946, 1},\n\t\t{946, 1},\n\t\t{833, 0},\n\t\t{833, 2},\n\t\t{1082, 0},\n\t\t{1082, 1},\n\t\t{1082, 1},\n\t\t{951, 1},\n\t\t{951, 2},\n\t\t{952, 0},\n\t\t{952, 1},\n\t\t{956, 7},\n\t\t{956, 7},\n\t\t{956, 7},\n\t\t{956, 7},\n\t\t{956, 8},\n\t\t{956, 5},\n\t\t{997, 2},\n\t\t{997, 2},\n\t\t{997, 2},\n\t\t{998, 0},\n\t\t{998, 1},\n\t\t{762, 5},\n\t\t{866, 3},\n\t\t{867, 3},\n\t\t{1001, 0},\n\t\t{1001, 1},\n\t\t{1001, 1},\n\t\t{1001, 2},\n\t\t{1001, 2},\n\t\t{889, 1},\n\t\t{889, 1},\n\t\t{889, 2},\n\t\t{889, 2},\n\t\t{889, 2},\n\t\t{962, 1},\n\t\t{962, 1},\n\t\t{859, 1},\n\t\t{859, 3},\n\t\t{859, 4},\n\t\t{858, 1},\n\t\t{858, 1},\n\t\t{858, 1},\n\t\t{858, 1},\n\t\t{857, 1},\n\t\t{857, 1},\n\t\t{857, 1},\n\t\t{904, 1},\n\t\t{904, 2},\n\t\t{904, 2},\n\t\t{690, 1},\n\t\t{690, 1},\n\t\t{690, 1},\n\t\t{794, 13},\n\t\t{982, 0},\n\t\t{982, 3},\n\t\t{676, 1},\n\t\t{676, 3},\n\t\t{663, 3},\n\t\t{663, 4},\n\t\t{841, 0},\n\t\t{841, 1},\n\t\t{841, 1},\n\t\t{841, 2},\n\t\t{841, 2},\n\t\t{981, 0},\n\t\t{981, 1},\n\t\t{981, 1},\n\t\t{981, 1},\n\t\t{778, 4},\n\t\t{778, 3},\n\t\t{793, 5},\n\t\t{673, 1},\n\t\t{684, 4},\n\t\t{684, 4},\n\t\t{684, 4},\n\t\t{960, 0},\n\t\t{960, 1},\n\t\t{745, 1},\n\t\t{745, 2},\n\t\t{744, 11},\n\t\t{744, 6},\n\t\t{629, 0},\n\t\t{629, 1},\n\t\t{879, 0},\n\t\t{879, 6},\n\t\t{910, 6},\n\t\t{910, 5},\n\t\t{1017, 0},\n\t\t{1017, 3},\n\t\t{1018, 1},\n\t\t{1018, 4},\n\t\t{1018, 5},\n\t\t{1018, 4},\n\t\t{1018, 5},\n\t\t{1018, 4},\n\t\t{1018, 3},\n\t\t{1018, 1},\n\t\t{851, 0},\n\t\t{851, 1},\n\t\t{1061, 0},\n\t\t{1061, 4},\n\t\t{1060, 0},\n\t\t{1060, 2},\n\t\t{1019, 0},\n\t\t{1019, 2},\n\t\t{877, 0},\n\t\t{877, 3},\n\t\t{876, 1},\n\t\t{876, 3},\n\t\t{758, 5},\n\t\t{1059, 0},\n\t\t{1059, 3},\n\t\t{1058, 1},\n\t\t{1058, 3},\n\t\t{909, 3},\n\t\t{875, 0},\n\t\t{875, 2},\n\t\t{657, 3},\n\t\t{657, 3},\n\t\t{657, 4},\n\t\t{657, 3},\n\t\t{657, 4},\n\t\t{657, 4},\n\t\t{657, 3},\n\t\t{657, 3},\n\t\t{657, 3},\n\t\t{657, 3},\n\t\t{1016, 0},\n\t\t{1016, 4},\n\t\t{1016, 6},\n\t\t{1016, 1},\n\t\t{1016, 5},\n\t\t{1016, 1},\n\t\t{1016, 1},\n\t\t{814, 0},\n\t\t{814, 1},\n\t\t{814, 1},\n\t\t{940, 0},\n\t\t{940, 1},\n\t\t{958, 0},\n\t\t{958, 1},\n\t\t{958, 1},\n\t\t{958, 1},\n\t\t{959, 1},\n\t\t{959, 1},\n\t\t{959, 3},\n\t\t{959, 3},\n\t\t{990, 2},\n\t\t{990, 4},\n\t\t{799, 11},\n\t\t{1013, 0},\n\t\t{1013, 2},\n\t\t{1075, 0},\n\t\t{1075, 3},\n\t\t{1075, 3},\n\t\t{1075, 3},\n\t\t{1077, 0},\n\t\t{1077, 3},\n\t\t{1080, 0},\n\t\t{1080, 3},\n\t\t{1080, 3},\n\t\t{1079, 1},\n\t\t{1078, 0},\n\t\t{1078, 3},\n\t\t{947, 1},\n\t\t{947, 3},\n\t\t{1076, 0},\n\t\t{1076, 4},\n\t\t{1076, 4},\n\t\t{804, 2},\n\t\t{661, 12},\n\t\t{661, 9},\n\t\t{661, 10},\n\t\t{746, 1},\n\t\t{806, 4},\n\t\t{807, 7},\n\t\t{811, 6},\n\t\t{757, 0},\n\t\t{757, 1},\n\t\t{813, 4},\n\t\t{813, 6},\n\t\t{812, 3},\n\t\t{812, 5},\n\t\t{808, 3},\n\t\t{808, 5},\n\t\t{810, 3},\n\t\t{733, 0},\n\t\t{733, 1},\n\t\t{733, 1},\n\t\t{917, 1},\n\t\t{917, 1},\n\t\t{602, 0},\n\t\t{602, 1},\n\t\t{815, 0},\n\t\t{921, 2},\n\t\t{921, 5},\n\t\t{822, 1},\n\t\t{822, 1},\n\t\t{822, 1},\n\t\t{821, 2},\n\t\t{821, 3},\n\t\t{821, 2},\n\t\t{821, 4},\n\t\t{821, 7},\n\t\t{821, 5},\n\t\t{821, 7},\n\t\t{821, 5},\n\t\t{821, 3},\n\t\t{967, 1},\n\t\t{967, 1},\n\t\t{611, 1},\n\t\t{598, 1},\n\t\t{595, 3},\n\t\t{595, 3},\n\t\t{595, 3},\n\t\t{595, 3},\n\t\t{595, 2},\n\t\t{595, 9},\n\t\t{595, 3},\n\t\t{595, 3},\n\t\t{595, 3},\n\t\t{595, 1},\n\t\t{756, 1},\n\t\t{756, 1},\n\t\t{973, 0},\n\t\t{973, 4},\n\t\t{973, 7},\n\t\t{973, 3},\n\t\t{973, 3},\n\t\t{597, 1},\n\t\t{597, 1},\n\t\t{596, 1},\n\t\t{596, 1},\n\t\t{628, 1},\n\t\t{628, 3},\n\t\t{856, 1},\n\t\t{856, 3},\n\t\t{702, 0},\n\t\t{702, 1},\n\t\t{832, 0},\n\t\t{832, 1},\n\t\t{831, 1},\n\t\t{594, 3},\n\t\t{594, 3},\n\t\t{594, 4},\n\t\t{594, 5},\n\t\t{594, 1},\n\t\t{954, 1},\n\t\t{954, 1},\n\t\t{954, 1},\n\t\t{954, 1},\n\t\t{954, 1},\n\t\t{954, 1},\n\t\t{954, 1},\n\t\t{954, 1},\n\t\t{942, 1},\n\t\t{942, 2},\n\t\t{986, 1},\n\t\t{986, 2},\n\t\t{984, 1},\n\t\t{984, 2},\n\t\t{989, 1},\n\t\t{989, 2},\n\t\t{1029, 1},\n\t\t{1029, 2},\n\t\t{939, 1},\n\t\t{939, 1},\n\t\t{939, 1},\n\t\t{593, 5},\n\t\t{593, 3},\n\t\t{593, 5},\n\t\t{593, 4},\n\t\t{593, 3},\n\t\t{593, 1},\n\t\t{890, 1},\n\t\t{890, 1},\n\t\t{988, 0},\n\t\t{988, 2},\n\t\t{748, 1},\n\t\t{748, 3},\n\t\t{748, 5},\n\t\t{748, 2},\n\t\t{748, 5},\n\t\t{824, 0},\n\t\t{824, 1},\n\t\t{823, 1},\n\t\t{823, 2},\n\t\t{823, 1},\n\t\t{823, 2},\n\t\t{826, 1},\n\t\t{826, 3},\n\t\t{976, 3},\n\t\t{978, 0},\n\t\t{978, 2},\n\t\t{641, 0},\n\t\t{641, 2},\n\t\t{642, 0},\n\t\t{642, 3},\n\t\t{723, 0},\n\t\t{723, 1},\n\t\t{703, 0},\n\t\t{703, 1},\n\t\t{705, 0},\n\t\t{705, 2},\n\t\t{704, 3},\n\t\t{704, 1},\n\t\t{704, 3},\n\t\t{704, 2},\n\t\t{704, 1},\n\t\t{754, 1},\n\t\t{754, 3},\n\t\t{754, 3},\n\t\t{983, 0},\n\t\t{983, 1},\n\t\t{689, 2},\n\t\t{689, 2},\n\t\t{724, 1},\n\t\t{724, 1},\n\t\t{724, 1},\n\t\t{687, 1},\n\t\t{687, 1},\n\t\t{537, 1},\n\t\t{537, 1},\n\t\t{537, 1},\n\t\t{537, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{540, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{539, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{538, 1},\n\t\t{664, 7},\n\t\t{844, 0},\n\t\t{844, 1},\n\t\t{842, 5},\n\t\t{842, 4},\n\t\t{842, 6},\n\t\t{842, 4},\n\t\t{842, 2},\n\t\t{842, 3},\n\t\t{842, 1},\n\t\t{842, 1},\n\t\t{842, 2},\n\t\t{774, 1},\n\t\t{774, 1},\n\t\t{773, 1},\n\t\t{773, 3},\n\t\t{692, 3},\n\t\t{1074, 0},\n\t\t{1074, 1},\n\t\t{1073, 3},\n\t\t{1073, 1},\n\t\t{654, 1},\n\t\t{654, 1},\n\t\t{791, 3},\n\t\t{953, 0},\n\t\t{953, 1},\n\t\t{953, 3},\n\t\t{1002, 0},\n\t\t{1002, 5},\n\t\t{666, 5},\n\t\t{862, 1},\n\t\t{862, 1},\n\t\t{862, 1},\n\t\t{578, 1},\n\t\t{578, 1},\n\t\t{578, 1},\n\t\t{578, 1},\n\t\t{578, 1},\n\t\t{578, 1},\n\t\t{578, 1},\n\t\t{578, 2},\n\t\t{578, 1},\n\t\t{578, 1},\n\t\t{577, 1},\n\t\t{577, 2},\n\t\t{934, 1},\n\t\t{934, 3},\n\t\t{779, 2},\n\t\t{649, 3},\n\t\t{716, 1},\n\t\t{716, 3},\n\t\t{699, 2},\n\t\t{731, 0},\n\t\t{731, 1},\n\t\t{731, 1},\n\t\t{650, 0},\n\t\t{650, 1},\n\t\t{592, 3},\n\t\t{592, 3},\n\t\t{592, 3},\n\t\t{592, 3},\n\t\t{592, 3},\n\t\t{592, 3},\n\t\t{592, 5},\n\t\t{592, 5},\n\t\t{592, 3},\n\t\t{592, 3},\n\t\t{592, 3},\n\t\t{592, 3},\n\t\t{592, 3},\n\t\t{592, 3},\n\t\t{592, 1},\n\t\t{576, 1},\n\t\t{576, 3},\n\t\t{576, 4},\n\t\t{576, 5},\n\t\t{573, 3},\n\t\t{587, 1},\n\t\t{587, 1},\n\t\t{587, 1},\n\t\t{587, 1},\n\t\t{587, 3},\n\t\t{587, 1},\n\t\t{587, 1},\n\t\t{587, 1},\n\t\t{587, 1},\n\t\t{587, 1},\n\t\t{587, 2},\n\t\t{587, 2},\n\t\t{587, 2},\n\t\t{587, 2},\n\t\t{587, 3},\n\t\t{587, 2},\n\t\t{587, 1},\n\t\t{587, 3},\n\t\t{587, 5},\n\t\t{587, 6},\n\t\t{587, 2},\n\t\t{587, 2},\n\t\t{587, 6},\n\t\t{587, 5},\n\t\t{587, 6},\n\t\t{587, 6},\n\t\t{587, 4},\n\t\t{587, 4},\n\t\t{587, 3},\n\t\t{587, 3},\n\t\t{630, 1},\n\t\t{630, 1},\n\t\t{638, 1},\n\t\t{638, 1},\n\t\t{639, 0},\n\t\t{639, 1},\n\t\t{961, 0},\n\t\t{961, 1},\n\t\t{647, 1},\n\t\t{647, 2},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{582, 1},\n\t\t{871, 0},\n\t\t{871, 2},\n\t\t{586, 1},\n\t\t{586, 1},\n\t\t{586, 1},\n\t\t{586, 1},\n\t\t{585, 1},\n\t\t{585, 1},\n\t\t{585, 1},\n\t\t{585, 1},\n\t\t{585, 1},\n\t\t{585, 1},\n\t\t{580, 4},\n\t\t{580, 4},\n\t\t{580, 2},\n\t\t{580, 3},\n\t\t{580, 2},\n\t\t{580, 4},\n\t\t{580, 6},\n\t\t{580, 2},\n\t\t{580, 2},\n\t\t{580, 2},\n\t\t{580, 4},\n\t\t{580, 6},\n\t\t{580, 4},\n\t\t{580, 4},\n\t\t{581, 4},\n\t\t{581, 4},\n\t\t{581, 6},\n\t\t{581, 8},\n\t\t{581, 8},\n\t\t{581, 6},\n\t\t{581, 6},\n\t\t{581, 6},\n\t\t{581, 6},\n\t\t{581, 6},\n\t\t{581, 8},\n\t\t{581, 8},\n\t\t{581, 8},\n\t\t{581, 8},\n\t\t{581, 4},\n\t\t{581, 6},\n\t\t{581, 6},\n\t\t{581, 7},\n\t\t{975, 1},\n\t\t{975, 1},\n\t\t{975, 1},\n\t\t{975, 1},\n\t\t{583, 1},\n\t\t{583, 1},\n\t\t{584, 1},\n\t\t{584, 1},\n\t\t{1068, 1},\n\t\t{1068, 1},\n\t\t{1068, 1},\n\t\t{588, 6},\n\t\t{588, 5},\n\t\t{588, 6},\n\t\t{588, 5},\n\t\t{588, 6},\n\t\t{588, 5},\n\t\t{588, 6},\n\t\t{588, 5},\n\t\t{588, 6},\n\t\t{588, 5},\n\t\t{588, 5},\n\t\t{588, 7},\n\t\t{588, 6},\n\t\t{588, 6},\n\t\t{588, 4},\n\t\t{588, 6},\n\t\t{588, 6},\n\t\t{588, 6},\n\t\t{588, 6},\n\t\t{588, 6},\n\t\t{588, 5},\n\t\t{1008, 0},\n\t\t{1008, 2},\n\t\t{579, 4},\n\t\t{974, 0},\n\t\t{974, 2},\n\t\t{974, 3},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{669, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{652, 1},\n\t\t{968, 0},\n\t\t{968, 1},\n\t\t{1083, 1},\n\t\t{1083, 2},\n\t\t{928, 4},\n\t\t{964, 0},\n\t\t{964, 2},\n\t\t{786, 2},\n\t\t{786, 3},\n\t\t{786, 1},\n\t\t{786, 2},\n\t\t{786, 2},\n\t\t{786, 2},\n\t\t{786, 2},\n\t\t{786, 2},\n\t\t{786, 1},\n\t\t{786, 1},\n\t\t{786, 2},\n\t\t{786, 1},\n\t\t{709, 0},\n\t\t{709, 1},\n\t\t{709, 1},\n\t\t{709, 1},\n\t\t{599, 1},\n\t\t{599, 3},\n\t\t{651, 1},\n\t\t{651, 3},\n\t\t{768, 2},\n\t\t{768, 4},\n\t\t{912, 1},\n\t\t{912, 3},\n\t\t{730, 0},\n\t\t{730, 2},\n\t\t{1028, 0},\n\t\t{1028, 1},\n\t\t{883, 4},\n\t\t{1026, 1},\n\t\t{1026, 1},\n\t\t{819, 2},\n\t\t{819, 4},\n\t\t{1071, 1},\n\t\t{1071, 3},\n\t\t{801, 3},\n\t\t{802, 1},\n\t\t{802, 1},\n\t\t{734, 1},\n\t\t{903, 1},\n\t\t{607, 3},\n\t\t{608, 3},\n\t\t{609, 7},\n\t\t{606, 5},\n\t\t{606, 5},\n\t\t{606, 5},\n\t\t{830, 2},\n\t\t{1084, 0},\n\t\t{1084, 2},\n\t\t{1085, 1},\n\t\t{1085, 3},\n\t\t{929, 3},\n\t\t{740, 1},\n\t\t{931, 3},\n\t\t{1090, 4},\n\t\t{1006, 0},\n\t\t{1006, 1},\n\t\t{1009, 0},\n\t\t{1009, 3},\n\t\t{1012, 0},\n\t\t{1012, 3},\n\t\t{1011, 0},\n\t\t{1011, 2},\n\t\t{1088, 1},\n\t\t{1088, 1},\n\t\t{1088, 1},\n\t\t{1087, 1},\n\t\t{1087, 1},\n\t\t{776, 2},\n\t\t{776, 2},\n\t\t{776, 2},\n\t\t{776, 4},\n\t\t{776, 2},\n\t\t{1086, 4},\n\t\t{930, 1},\n\t\t{930, 2},\n\t\t{930, 2},\n\t\t{930, 2},\n\t\t{930, 4},\n\t\t{618, 0},\n\t\t{618, 1},\n\t\t{610, 2},\n\t\t{1089, 1},\n\t\t{1089, 1},\n\t\t{591, 4},\n\t\t{591, 4},\n\t\t{591, 4},\n\t\t{591, 4},\n\t\t{591, 4},\n\t\t{591, 5},\n\t\t{591, 7},\n\t\t{591, 7},\n\t\t{591, 6},\n\t\t{591, 6},\n\t\t{591, 9},\n\t\t{872, 0},\n\t\t{872, 3},\n\t\t{872, 3},\n\t\t{873, 0},\n\t\t{873, 2},\n\t\t{708, 0},\n\t\t{708, 2},\n\t\t{708, 2},\n\t\t{1007, 0},\n\t\t{1007, 2},\n\t\t{1007, 2},\n\t\t{1064, 1},\n\t\t{697, 1},\n\t\t{697, 3},\n\t\t{674, 1},\n\t\t{674, 4},\n\t\t{637, 1},\n\t\t{637, 1},\n\t\t{636, 4},\n\t\t{636, 4},\n\t\t{636, 4},\n\t\t{636, 3},\n\t\t{878, 0},\n\t\t{878, 4},\n\t\t{913, 0},\n\t\t{913, 1},\n\t\t{710, 1},\n\t\t{710, 2},\n\t\t{753, 2},\n\t\t{753, 2},\n\t\t{753, 2},\n\t\t{980, 0},\n\t\t{980, 2},\n\t\t{980, 3},\n\t\t{980, 3},\n\t\t{752, 5},\n\t\t{688, 0},\n\t\t{688, 1},\n\t\t{688, 3},\n\t\t{688, 1},\n\t\t{688, 3},\n\t\t{839, 1},\n\t\t{839, 2},\n\t\t{840, 0},\n\t\t{840, 1},\n\t\t{632, 3},\n\t\t{632, 5},\n\t\t{632, 7},\n\t\t{632, 7},\n\t\t{632, 9},\n\t\t{632, 4},\n\t\t{632, 6},\n\t\t{632, 3},\n\t\t{632, 5},\n\t\t{655, 1},\n\t\t{655, 1},\n\t\t{874, 0},\n\t\t{874, 1},\n\t\t{660, 1},\n\t\t{660, 2},\n\t\t{660, 2},\n\t\t{849, 0},\n\t\t{849, 2},\n\t\t{725, 1},\n\t\t{725, 1},\n\t\t{668, 0},\n\t\t{668, 2},\n\t\t{668, 4},\n\t\t{668, 4},\n\t\t{1036, 9},\n\t\t{769, 0},\n\t\t{769, 1},\n\t\t{1033, 0},\n\t\t{1033, 1},\n\t\t{1037, 0},\n\t\t{1037, 1},\n\t\t{1038, 0},\n\t\t{1038, 1},\n\t\t{1039, 0},\n\t\t{1039, 1},\n\t\t{1039, 1},\n\t\t{1040, 0},\n\t\t{1040, 1},\n\t\t{1041, 0},\n\t\t{1041, 1},\n\t\t{1034, 1},\n\t\t{1035, 0},\n\t\t{1035, 1},\n\t\t{694, 0},\n\t\t{694, 5},\n\t\t{694, 5},\n\t\t{1023, 0},\n\t\t{1023, 3},\n\t\t{880, 4},\n\t\t{1022, 1},\n\t\t{1022, 2},\n\t\t{574, 3},\n\t\t{574, 3},\n\t\t{693, 0},\n\t\t{693, 2},\n\t\t{693, 3},\n\t\t{693, 4},\n\t\t{615, 7},\n\t\t{615, 7},\n\t\t{615, 7},\n\t\t{615, 8},\n\t\t{614, 1},\n\t\t{614, 4},\n\t\t{613, 1},\n\t\t{613, 3},\n\t\t{1070, 1},\n\t\t{787, 9},\n\t\t{787, 9},\n\t\t{736, 2},\n\t\t{736, 4},\n\t\t{736, 6},\n\t\t{736, 4},\n\t\t{736, 4},\n\t\t{736, 3},\n\t\t{899, 3},\n\t\t{898, 6},\n\t\t{897, 1},\n\t\t{897, 1},\n\t\t{897, 1},\n\t\t{1043, 3},\n\t\t{1043, 1},\n\t\t{1043, 1},\n\t\t{770, 1},\n\t\t{770, 3},\n\t\t{738, 3},\n\t\t{738, 2},\n\t\t{738, 2},\n\t\t{985, 2},\n\t\t{985, 2},\n\t\t{985, 2},\n\t\t{985, 1},\n\t\t{735, 1},\n\t\t{735, 1},\n\t\t{685, 1},\n\t\t{685, 1},\n\t\t{671, 1},\n\t\t{671, 3},\n\t\t{775, 3},\n\t\t{775, 4},\n\t\t{775, 4},\n\t\t{775, 4},\n\t\t{775, 3},\n\t\t{775, 3},\n\t\t{775, 2},\n\t\t{775, 4},\n\t\t{775, 4},\n\t\t{775, 2},\n\t\t{775, 2},\n\t\t{944, 1},\n\t\t{944, 1},\n\t\t{648, 1},\n\t\t{648, 1},\n\t\t{717, 1},\n\t\t{927, 0},\n\t\t{927, 1},\n\t\t{927, 3},\n\t\t{590, 1},\n\t\t{590, 1},\n\t\t{589, 1},\n\t\t{575, 1},\n\t\t{626, 1},\n\t\t{626, 3},\n\t\t{626, 2},\n\t\t{626, 2},\n\t\t{711, 1},\n\t\t{711, 3},\n\t\t{881, 1},\n\t\t{881, 4},\n\t\t{714, 1},\n\t\t{1021, 1},\n\t\t{644, 1},\n\t\t{644, 1},\n\t\t{643, 1},\n\t\t{643, 3},\n\t\t{643, 2},\n\t\t{667, 1},\n\t\t{667, 3},\n\t\t{777, 3},\n\t\t{777, 5},\n\t\t{777, 6},\n\t\t{777, 4},\n\t\t{777, 4},\n\t\t{777, 5},\n\t\t{777, 5},\n\t\t{777, 5},\n\t\t{777, 6},\n\t\t{777, 4},\n\t\t{777, 5},\n\t\t{777, 6},\n\t\t{777, 4},\n\t\t{777, 3},\n\t\t{777, 3},\n\t\t{777, 4},\n\t\t{777, 4},\n\t\t{777, 5},\n\t\t{777, 5},\n\t\t{777, 3},\n\t\t{777, 3},\n\t\t{777, 3},\n\t\t{933, 2},\n\t\t{933, 2},\n\t\t{933, 3},\n\t\t{933, 3},\n\t\t{977, 1},\n\t\t{977, 3},\n\t\t{836, 5},\n\t\t{860, 1},\n\t\t{860, 3},\n\t\t{901, 3},\n\t\t{901, 4},\n\t\t{901, 4},\n\t\t{901, 5},\n\t\t{901, 4},\n\t\t{901, 4},\n\t\t{901, 5},\n\t\t{901, 7},\n\t\t{901, 4},\n\t\t{901, 7},\n\t\t{901, 3},\n\t\t{901, 3},\n\t\t{901, 3},\n\t\t{901, 3},\n\t\t{901, 3},\n\t\t{901, 3},\n\t\t{901, 2},\n\t\t{901, 5},\n\t\t{901, 2},\n\t\t{901, 4},\n\t\t{901, 2},\n\t\t{1047, 0},\n\t\t{1047, 1},\n\t\t{1046, 1},\n\t\t{1046, 3},\n\t\t{900, 1},\n\t\t{900, 1},\n\t\t{900, 2},\n\t\t{900, 2},\n\t\t{900, 2},\n\t\t{900, 1},\n\t\t{900, 1},\n\t\t{900, 1},\n\t\t{900, 1},\n\t\t{1045, 0},\n\t\t{1045, 3},\n\t\t{1072, 0},\n\t\t{1072, 2},\n\t\t{1044, 1},\n\t\t{1044, 1},\n\t\t{1044, 1},\n\t\t{640, 1},\n\t\t{640, 1},\n\t\t{1048, 1},\n\t\t{1048, 1},\n\t\t{1048, 1},\n\t\t{1048, 3},\n\t\t{1048, 3},\n\t\t{1048, 3},\n\t\t{1048, 3},\n\t\t{1048, 5},\n\t\t{1048, 4},\n\t\t{1048, 5},\n\t\t{1048, 1},\n\t\t{1048, 1},\n\t\t{1048, 2},\n\t\t{1048, 2},\n\t\t{1048, 2},\n\t\t{1048, 1},\n\t\t{1048, 2},\n\t\t{1048, 2},\n\t\t{1048, 2},\n\t\t{1048, 2},\n\t\t{1048, 2},\n\t\t{1048, 2},\n\t\t{1048, 1},\n\t\t{696, 0},\n\t\t{696, 2},\n\t\t{696, 2},\n\t\t{750, 0},\n\t\t{750, 1},\n\t\t{750, 1},\n\t\t{869, 0},\n\t\t{869, 1},\n\t\t{679, 0},\n\t\t{679, 2},\n\t\t{902, 2},\n\t\t{829, 3},\n\t\t{759, 1},\n\t\t{759, 3},\n\t\t{972, 1},\n\t\t{972, 1},\n\t\t{972, 3},\n\t\t{972, 1},\n\t\t{972, 2},\n\t\t{972, 3},\n\t\t{996, 0},\n\t\t{996, 1},\n\t\t{996, 1},\n\t\t{996, 1},\n\t\t{996, 1},\n\t\t{996, 1},\n\t\t{677, 0},\n\t\t{677, 1},\n\t\t{677, 1},\n\t\t{916, 0},\n\t\t{916, 1},\n\t\t{1092, 0},\n\t\t{1092, 3},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{907, 1},\n\t\t{920, 1},\n\t\t{920, 1},\n\t\t{920, 1},\n\t\t{920, 1},\n\t\t{920, 1},\n\t\t{920, 1},\n\t\t{920, 1},\n\t\t{920, 1},\n\t\t{920, 1},\n\t\t{920, 1},\n\t\t{920, 1},\n\t\t{720, 1},\n\t\t{720, 1},\n\t\t{720, 1},\n\t\t{720, 1},\n\t\t{720, 1},\n\t\t{720, 1},\n\t\t{1055, 1},\n\t\t{1055, 3},\n\t\t{955, 2},\n\t\t{767, 1},\n\t\t{914, 1},\n\t\t{914, 3},\n\t\t{1062, 0},\n\t\t{1062, 3},\n\t\t{681, 1},\n\t\t{681, 4},\n\t\t{681, 4},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 1},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 2},\n\t\t{681, 2},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 5},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{681, 3},\n\t\t{908, 1},\n\t\t{908, 1},\n\t\t{797, 0},\n\t\t{797, 1},\n\t\t{737, 1},\n\t\t{737, 2},\n\t\t{737, 3},\n\t\t{1010, 0},\n\t\t{1010, 1},\n\t\t{922, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{678, 3},\n\t\t{1165, 1},\n\t\t{1165, 1},\n\t\t{1165, 1},\n\t\t{1148, 3},\n\t\t{1148, 2},\n\t\t{1148, 3},\n\t\t{1148, 3},\n\t\t{1148, 2},\n\t\t{1125, 1},\n\t\t{1125, 1},\n\t\t{1125, 1},\n\t\t{1125, 1},\n\t\t{1125, 1},\n\t\t{1125, 1},\n\t\t{1125, 1},\n\t\t{1125, 1},\n\t\t{1125, 1},\n\t\t{1125, 1},\n\t\t{1125, 1},\n\t\t{1102, 1},\n\t\t{1102, 1},\n\t\t{870, 0},\n\t\t{870, 1},\n\t\t{870, 1},\n\t\t{1116, 1},\n\t\t{1116, 1},\n\t\t{1116, 1},\n\t\t{1117, 1},\n\t\t{1117, 1},\n\t\t{1117, 1},\n\t\t{1117, 2},\n\t\t{1099, 1},\n\t\t{1159, 3},\n\t\t{1159, 2},\n\t\t{1159, 3},\n\t\t{1159, 2},\n\t\t{1159, 3},\n\t\t{1159, 3},\n\t\t{1159, 2},\n\t\t{1159, 2},\n\t\t{1159, 1},\n\t\t{1159, 2},\n\t\t{1159, 5},\n\t\t{1159, 5},\n\t\t{1159, 1},\n\t\t{1159, 3},\n\t\t{1159, 2},\n\t\t{1103, 1},\n\t\t{1103, 1},\n\t\t{1146, 1},\n\t\t{1146, 2},\n\t\t{1146, 2},\n\t\t{1167, 2},\n\t\t{1167, 2},\n\t\t{1167, 1},\n\t\t{1167, 1},\n\t\t{1150, 2},\n\t\t{1150, 2},\n\t\t{1150, 1},\n\t\t{1150, 2},\n\t\t{1150, 2},\n\t\t{1150, 3},\n\t\t{1150, 3},\n\t\t{1150, 2},\n\t\t{1171, 1},\n\t\t{1171, 1},\n\t\t{1100, 1},\n\t\t{1100, 2},\n\t\t{1100, 1},\n\t\t{1100, 1},\n\t\t{1100, 2},\n\t\t{1161, 1},\n\t\t{1161, 2},\n\t\t{1161, 1},\n\t\t{1161, 1},\n\t\t{1152, 1},\n\t\t{1152, 1},\n\t\t{1152, 1},\n\t\t{1152, 1},\n\t\t{1111, 1},\n\t\t{1111, 2},\n\t\t{1111, 2},\n\t\t{1111, 2},\n\t\t{1111, 3},\n\t\t{662, 3},\n\t\t{691, 0},\n\t\t{691, 1},\n\t\t{1114, 1},\n\t\t{1114, 1},\n\t\t{1114, 1},\n\t\t{1115, 0},\n\t\t{1115, 2},\n\t\t{828, 0},\n\t\t{828, 1},\n\t\t{828, 1},\n\t\t{882, 5},\n\t\t{1004, 0},\n\t\t{1004, 1},\n\t\t{1003, 0},\n\t\t{1003, 2},\n\t\t{1003, 3},\n\t\t{1005, 0},\n\t\t{1005, 2},\n\t\t{653, 2},\n\t\t{653, 1},\n\t\t{653, 2},\n\t\t{868, 0},\n\t\t{868, 2},\n\t\t{766, 1},\n\t\t{766, 3},\n\t\t{601, 1},\n\t\t{601, 1},\n\t\t{670, 10},\n\t\t{670, 8},\n\t\t{926, 2},\n\t\t{645, 2},\n\t\t{646, 0},\n\t\t{646, 1},\n\t\t{1106, 0},\n\t\t{1106, 1},\n\t\t{798, 6},\n\t\t{795, 4},\n\t\t{782, 6},\n\t\t{782, 9},\n\t\t{712, 3},\n\t\t{739, 1},\n\t\t{739, 3},\n\t\t{818, 0},\n\t\t{818, 4},\n\t\t{818, 5},\n\t\t{818, 3},\n\t\t{816, 0},\n\t\t{816, 2},\n\t\t{1109, 0},\n\t\t{1109, 2},\n\t\t{1108, 1},\n\t\t{1108, 2},\n\t\t{1107, 2},\n\t\t{1107, 2},\n\t\t{1107, 2},\n\t\t{1107, 2},\n\t\t{764, 0},\n\t\t{764, 1},\n\t\t{763, 2},\n\t\t{763, 2},\n\t\t{763, 2},\n\t\t{763, 2},\n\t\t{1031, 1},\n\t\t{1031, 3},\n\t\t{1031, 2},\n\t\t{765, 2},\n\t\t{765, 2},\n\t\t{765, 2},\n\t\t{1156, 0},\n\t\t{1156, 1},\n\t\t{1155, 1},\n\t\t{1155, 2},\n\t\t{1154, 2},\n\t\t{1154, 2},\n\t\t{1154, 1},\n\t\t{1154, 4},\n\t\t{1154, 2},\n\t\t{1154, 2},\n\t\t{1153, 3},\n\t\t{1104, 0},\n\t\t{941, 0},\n\t\t{941, 3},\n\t\t{941, 3},\n\t\t{941, 5},\n\t\t{941, 5},\n\t\t{941, 4},\n\t\t{1020, 0},\n\t\t{1020, 2},\n\t\t{837, 1},\n\t\t{895, 1},\n\t\t{1032, 1},\n\t\t{1032, 3},\n\t\t{792, 7},\n\t\t{805, 5},\n\t\t{805, 7},\n\t\t{835, 9},\n\t\t{834, 4},\n\t\t{1091, 0},\n\t\t{1091, 3},\n\t\t{1091, 3},\n\t\t{1091, 3},\n\t\t{1091, 3},\n\t\t{1091, 3},\n\t\t{760, 1},\n\t\t{760, 4},\n\t\t{885, 1},\n\t\t{885, 3},\n\t\t{761, 1},\n\t\t{761, 2},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 2},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 2},\n\t\t{761, 1},\n\t\t{761, 2},\n\t\t{761, 1},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 3},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 2},\n\t\t{761, 1},\n\t\t{761, 1},\n\t\t{861, 0},\n\t\t{861, 1},\n\t\t{886, 1},\n\t\t{886, 3},\n\t\t{886, 3},\n\t\t{886, 3},\n\t\t{886, 1},\n\t\t{894, 7},\n\t\t{893, 4},\n\t\t{728, 15},\n\t\t{979, 0},\n\t\t{979, 3},\n\t\t{945, 0},\n\t\t{945, 3},\n\t\t{854, 0},\n\t\t{854, 1},\n\t\t{749, 0},\n\t\t{749, 2},\n\t\t{675, 1},\n\t\t{675, 1},\n\t\t{969, 2},\n\t\t{969, 1},\n\t\t{825, 3},\n\t\t{825, 4},\n\t\t{825, 3},\n\t\t{825, 3},\n\t\t{721, 1},\n\t\t{721, 1},\n\t\t{721, 1},\n\t\t{726, 0},\n\t\t{726, 3},\n\t\t{1053, 0},\n\t\t{1053, 3},\n\t\t{991, 0},\n\t\t{991, 3},\n\t\t{993, 0},\n\t\t{993, 2},\n\t\t{992, 3},\n\t\t{992, 1},\n\t\t{852, 3},\n\t\t{924, 2},\n\t\t{855, 3},\n\t\t{918, 1},\n\t\t{918, 1},\n\t\t{915, 2},\n\t\t{995, 1},\n\t\t{995, 2},\n\t\t{995, 1},\n\t\t{995, 2},\n\t\t{1063, 1},\n\t\t{1063, 3},\n\t\t{848, 2},\n\t\t{848, 3},\n\t\t{848, 3},\n\t\t{847, 1},\n\t\t{847, 2},\n\t\t{853, 3},\n\t\t{796, 7},\n\t\t{957, 0},\n\t\t{957, 1},\n\t\t{1042, 1},\n\t\t{1042, 2},\n\t\t{896, 3},\n\t\t{896, 3},\n\t\t{896, 3},\n\t\t{896, 3},\n\t\t{896, 3},\n\t\t{896, 1},\n\t\t{896, 2},\n\t\t{896, 3},\n\t\t{896, 1},\n\t\t{896, 2},\n\t\t{896, 3},\n\t\t{896, 1},\n\t\t{896, 2},\n\t\t{896, 1},\n\t\t{896, 1},\n\t\t{896, 2},\n\t\t{896, 1},\n\t\t{896, 1},\n\t\t{896, 2},\n\t\t{680, 1},\n\t\t{680, 2},\n\t\t{680, 2},\n\t\t{809, 5},\n\t\t{838, 8},\n\t\t{1000, 0},\n\t\t{1000, 2},\n\t\t{999, 0},\n\t\t{999, 3},\n\t\t{1025, 0},\n\t\t{1025, 2},\n\t\t{1024, 0},\n\t\t{1024, 2},\n\t}\n\n\tyyXErrors = map[yyXError]string{}\n\n\tyyParseTab = [3302][]uint16{\n\t\t// 0\n\t\t{1630, 1630, 36: 2033, 97: 2047, 102: 2032, 104: 2035, 110: 2051, 113: 2129, 123: 2048, 125: 2065, 134: 2028, 137: 2052, 143: 2063, 2034, 155: 2050, 159: 2037, 163: 2029, 191: 2030, 204: 2040, 362: 2057, 379: 2136, 384: 2046, 392: 2062, 411: 2043, 451: 2045, 524: 2053, 2139, 550: 2131, 554: 2039, 557: 2031, 2026, 2036, 2061, 566: 2027, 574: 2120, 606: 2060, 2054, 2055, 2056, 613: 2059, 2058, 2114, 2130, 2038, 661: 2076, 664: 2102, 666: 2110, 670: 2123, 686: 2132, 695: 2064, 701: 2042, 715: 2072, 718: 2074, 727: 2134, 2105, 734: 2108, 736: 2115, 744: 2082, 777: 2067, 2068, 781: 2069, 2070, 784: 2071, 2073, 787: 2079, 792: 2086, 2080, 2081, 2085, 2087, 798: 2084, 2083, 801: 2075, 2049, 804: 2088, 2097, 2089, 2090, 2095, 2092, 2096, 2091, 2094, 2093, 815: 2066, 819: 2077, 2041, 2078, 2044, 827: 2099, 829: 2098, 834: 2101, 2100, 838: 2103, 846: 2138, 2137, 2104, 853: 2106, 855: 2126, 883: 2107, 888: 2111, 891: 2109, 2133, 2113, 2112, 898: 2117, 2116, 901: 2119, 903: 2127, 906: 2118, 2128, 921: 2121, 2122, 2135, 2125, 926: 2124, 1052: 2024, 1055: 2025},\n\t\t{2023},\n\t\t{2022, 5323},\n\t\t{101: 5064, 464: 4682, 522: 3574, 605: 1525, 723: 5062, 746: 5063},\n\t\t{605: 5054},\n\t\t// 5\n\t\t{605: 5048},\n\t\t{605: 5039},\n\t\t{277: 5020, 395: 5021, 605: 1916, 1050: 5019},\n\t\t{237: 4984, 605: 4983},\n\t\t{1892, 1892, 260: 4982, 265: 4981},\n\t\t// 10\n\t\t{301: 4956},\n\t\t{363: 4955},\n\t\t{1854, 1854},\n\t\t{41: 1673, 51: 1673, 83: 1673, 90: 500, 93: 1646, 99: 4787, 101: 4786, 112: 3895, 127: 3770, 136: 3771, 385: 4785, 464: 4682, 525: 1759, 533: 4779, 551: 1673, 564: 4781, 605: 1646, 746: 4782, 750: 4788, 757: 4783, 981: 4778, 1013: 4784, 1049: 4780},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 4777},\n\t\t// 15\n\t\t{2: 712, 712, 712, 712, 712, 712, 712, 10: 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 390: 712, 522: 712, 620: 712, 623: 712, 712, 751: 3568, 769: 4744},\n\t\t{51: 4686, 57: 1646, 90: 500, 93: 1646, 97: 840, 99: 4688, 101: 4687, 112: 3895, 127: 3770, 136: 3771, 193: 4689, 464: 4682, 525: 4684, 605: 1646, 746: 4683, 750: 4690, 757: 4685},\n\t\t{36: 2033, 102: 2032, 104: 2035, 110: 2051, 232: 4665, 362: 3239, 384: 2046, 392: 4667, 451: 2045, 524: 2053, 606: 4666, 2054, 2055, 2056, 613: 2059, 2058, 4672, 2130, 2038, 661: 4668, 664: 4670, 666: 4671, 670: 4669, 715: 4674, 718: 4675, 727: 4678, 4673, 734: 4676, 736: 4677, 920: 4664},\n\t\t{2: 1627, 1627, 1627, 1627, 1627, 1627, 1627, 10: 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 362: 1627, 377: 1627, 384: 1627, 451: 1627, 524: 1627, 557: 1627, 616: 1627, 1627},\n\t\t{2: 1626, 1626, 1626, 1626, 1626, 1626, 1626, 10: 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 362: 1626, 377: 1626, 384: 1626, 451: 1626, 524: 1626, 557: 1626, 616: 1626, 1626},\n\t\t// 20\n\t\t{2: 1625, 1625, 1625, 1625, 1625, 1625, 1625, 10: 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 362: 1625, 377: 1625, 384: 1625, 451: 1625, 524: 1625, 557: 1625, 616: 1625, 1625},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 4639, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3239, 377: 4638, 384: 2046, 451: 2045, 524: 2053, 537: 2537, 2178, 2179, 2177, 557: 4640, 599: 4636, 606: 4641, 2054, 2055, 2056, 613: 2059, 2058, 4646, 2130, 2038, 661: 4642, 664: 4644, 666: 4645, 670: 4643, 720: 4637},\n\t\t{2: 865, 865, 865, 865, 865, 865, 865, 10: 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 380: 865, 522: 865, 620: 3572, 623: 3571, 3570, 709: 4625},\n\t\t{2: 865, 865, 865, 865, 865, 865, 865, 10: 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 380: 865, 620: 3572, 623: 3571, 3570, 709: 4584},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4579, 2178, 2179, 2177},\n\t\t// 25\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4573, 2178, 2179, 2177},\n\t\t{97: 4571},\n\t\t{97: 841},\n\t\t{839, 839},\n\t\t{838, 838},\n\t\t// 30\n\t\t{2: 712, 712, 712, 712, 712, 712, 712, 10: 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 362: 712, 712, 366: 712, 712, 369: 712, 712, 712, 712, 712, 384: 712, 387: 712, 393: 712, 712, 396: 712, 406: 712, 712, 431: 712, 438: 712, 447: 712, 450: 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 523: 712, 600: 712, 612: 712, 620: 712, 712, 712, 712, 712, 712, 635: 712, 751: 3568, 769: 4553, 1036: 4552},\n\t\t{1086, 1086, 361: 1086, 364: 1086, 1086, 368: 1086, 375: 1086, 377: 1086, 2978, 1086, 1086, 1086, 390: 4516, 649: 2979, 4549, 830: 4515},\n\t\t{1086, 1086, 361: 1086, 364: 1086, 1086, 368: 1086, 375: 1086, 377: 1086, 2978, 1086, 1086, 1086, 649: 2979, 4546},\n\t\t{1086, 1086, 361: 1086, 364: 1086, 1086, 368: 1086, 375: 1086, 377: 1086, 2978, 1086, 1086, 1086, 649: 2979, 4543},\n\t\t{362: 3239, 524: 2053, 606: 3252, 2054, 2055, 2056, 613: 2059, 2058, 3238},\n\t\t// 35\n\t\t{365: 4445},\n\t\t{365: 676},\n\t\t{422, 422, 365: 674},\n\t\t{160: 4430, 178: 4429},\n\t\t{624, 624, 2391, 2276, 2393, 2183, 2281, 4336, 2256, 624, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 4340, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 4338, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 4341, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 4337, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 4342, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 4343, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 4339, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 373: 4345, 387: 3205, 447: 4349, 465: 4348, 526: 3203, 537: 4346, 2178, 2179, 2177, 653: 4350, 671: 4347, 775: 4351, 927: 4344},\n\t\t// 40\n\t\t{19: 3879, 125: 3884, 132: 3882, 134: 3877, 3883, 181: 3881, 212: 3880, 3885, 215: 3878, 226: 3886, 528: 3876, 695: 3875},\n\t\t{7: 3204, 52: 497, 497, 57: 497, 59: 500, 87: 500, 109: 3747, 116: 500, 126: 3772, 3770, 132: 3769, 497, 136: 3771, 160: 3766, 178: 3765, 211: 3749, 216: 3762, 223: 3753, 225: 3768, 229: 3758, 233: 3767, 3738, 236: 3760, 238: 3751, 248: 3739, 259: 3756, 273: 3746, 3745, 287: 3743, 3744, 3742, 3741, 302: 3763, 305: 3759, 387: 3205, 525: 3750, 3203, 557: 3748, 559: 3736, 605: 3737, 653: 3755, 750: 3761, 755: 3752, 800: 3754, 869: 3740, 1027: 3764, 1044: 3757, 1048: 3735},\n\t\t{10: 477, 57: 477, 59: 477, 81: 3705, 85: 477, 109: 477, 139: 477, 164: 477, 189: 477, 438: 477, 605: 477, 656: 3704, 677: 3703, 719: 477, 722: 477},\n\t\t{470, 470},\n\t\t{469, 469},\n\t\t// 45\n\t\t{468, 468},\n\t\t{467, 467},\n\t\t{466, 466},\n\t\t{465, 465},\n\t\t{464, 464},\n\t\t// 50\n\t\t{463, 463},\n\t\t{462, 462},\n\t\t{461, 461},\n\t\t{460, 460},\n\t\t{459, 459},\n\t\t// 55\n\t\t{458, 458},\n\t\t{457, 457},\n\t\t{456, 456},\n\t\t{455, 455},\n\t\t{454, 454},\n\t\t// 60\n\t\t{453, 453},\n\t\t{452, 452},\n\t\t{451, 451},\n\t\t{450, 450},\n\t\t{449, 449},\n\t\t// 65\n\t\t{448, 448},\n\t\t{447, 447},\n\t\t{446, 446},\n\t\t{445, 445},\n\t\t{444, 444},\n\t\t// 70\n\t\t{443, 443},\n\t\t{442, 442},\n\t\t{441, 441},\n\t\t{440, 440},\n\t\t{439, 439},\n\t\t// 75\n\t\t{438, 438},\n\t\t{437, 437},\n\t\t{436, 436},\n\t\t{435, 435},\n\t\t{434, 434},\n\t\t// 80\n\t\t{433, 433},\n\t\t{432, 432},\n\t\t{431, 431},\n\t\t{430, 430},\n\t\t{429, 429},\n\t\t// 85\n\t\t{428, 428},\n\t\t{427, 427},\n\t\t{426, 426},\n\t\t{425, 425},\n\t\t{424, 424},\n\t\t// 90\n\t\t{423, 423},\n\t\t{421, 421},\n\t\t{420, 420},\n\t\t{419, 419},\n\t\t{418, 418},\n\t\t// 95\n\t\t{417, 417},\n\t\t{416, 416},\n\t\t{415, 415},\n\t\t{414, 414},\n\t\t{413, 413},\n\t\t// 100\n\t\t{412, 412},\n\t\t{411, 411},\n\t\t{410, 410},\n\t\t{409, 409},\n\t\t{408, 408},\n\t\t// 105\n\t\t{390, 390},\n\t\t{2: 346, 346, 346, 346, 346, 346, 346, 10: 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 605: 3700, 1010: 3701},\n\t\t{2: 712, 712, 712, 712, 712, 712, 712, 10: 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 362: 712, 452: 712, 522: 712, 620: 712, 623: 712, 712, 751: 3568, 769: 3569},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3566, 2178, 2179, 2177, 673: 3567},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 3409, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 3411, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 3415, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 3416, 2318, 2218, 2533, 2530, 2220, 2378, 3410, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 3413, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 3414, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 3412, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 379: 3439, 451: 3432, 524: 3433, 3431, 534: 3437, 537: 2569, 2178, 2179, 2177, 554: 3430, 558: 3426, 3427, 600: 3425, 3419, 616: 3435, 3429, 643: 3420, 3418, 667: 3528, 686: 3436, 695: 3434, 701: 3440, 760: 3423, 3422, 771: 3428, 3438, 885: 3529},\n\t\t// 110\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 3409, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 3411, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 3415, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 3416, 2318, 2218, 2533, 2530, 2220, 2378, 3410, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 3413, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 3414, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 3412, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 379: 3439, 451: 3432, 524: 3433, 3431, 534: 3437, 537: 2569, 2178, 2179, 2177, 554: 3430, 558: 3426, 3427, 600: 3425, 3419, 616: 3435, 3429, 643: 3420, 3418, 667: 3421, 686: 3436, 695: 3434, 701: 3440, 760: 3423, 3422, 771: 3428, 3438, 885: 3424},\n\t\t{11: 2551, 193: 2552},\n\t\t{57: 2174, 605: 2175, 918: 2550},\n\t\t{57: 2174, 605: 2175, 918: 2173},\n\t\t{17: 2169, 92: 2170, 393: 2147, 598: 2168},\n\t\t// 115\n\t\t{17: 40, 92: 40, 139: 2167, 393: 40},\n\t\t{206: 2140},\n\t\t{81: 2141, 706: 80, 854: 2142},\n\t\t{706: 79},\n\t\t{706: 2143},\n\t\t// 120\n\t\t{363: 2144},\n\t\t{8, 8, 106: 8, 250: 2146, 541: 8, 1000: 2145},\n\t\t{6, 6, 106: 2150, 541: 6, 999: 2149},\n\t\t{393: 2147, 598: 2148},\n\t\t{1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 36: 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 54: 1612, 1612, 96: 1612, 106: 1612, 108: 1612, 129: 1612, 146: 1612, 148: 1612, 184: 1612, 203: 1612, 361: 1612, 1612, 364: 1612, 1612, 368: 1612, 373: 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612, 383: 1612, 1612, 387: 1612, 395: 1612, 522: 1612, 524: 1612, 1612, 1612, 530: 1612, 1612, 1612, 541: 1612, 544: 1612},\n\t\t// 125\n\t\t{7, 7, 106: 7, 541: 7},\n\t\t{65, 65, 541: 2157, 726: 2158},\n\t\t{4, 4, 108: 4, 264: 2152, 541: 4, 1025: 2151},\n\t\t{2, 2, 108: 2155, 541: 2, 1024: 2154},\n\t\t{393: 2147, 598: 2153},\n\t\t// 130\n\t\t{3, 3, 108: 3, 541: 3},\n\t\t{5, 5, 541: 5},\n\t\t{393: 2147, 598: 2156},\n\t\t{1, 1, 541: 1},\n\t\t{63, 63, 361: 63, 63, 364: 63, 63, 368: 63, 375: 63, 392: 63, 522: 63, 619: 63, 1053: 2159, 2160},\n\t\t// 135\n\t\t{9, 9},\n\t\t{61, 61, 361: 61, 61, 364: 61, 61, 368: 61, 375: 61, 392: 61, 522: 61, 619: 2164, 991: 2163},\n\t\t{546: 2161},\n\t\t{363: 2162},\n\t\t{62, 62, 361: 62, 62, 364: 62, 62, 368: 62, 375: 62, 392: 62, 522: 62, 619: 62},\n\t\t// 140\n\t\t{64, 64, 361: 64, 64, 364: 64, 64, 368: 64, 375: 64, 392: 64, 522: 64},\n\t\t{546: 2165},\n\t\t{363: 2166},\n\t\t{60, 60, 361: 60, 60, 364: 60, 60, 368: 60, 375: 60, 392: 60, 522: 60},\n\t\t{17: 39, 92: 39, 393: 39},\n\t\t// 145\n\t\t{43, 43},\n\t\t{393: 2147, 598: 2172},\n\t\t{393: 2147, 598: 2171},\n\t\t{41, 41},\n\t\t{42, 42},\n\t\t// 150\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 2539, 915: 2540, 1063: 2538},\n\t\t{52, 52, 52, 52, 52, 52, 52, 52, 52, 10: 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52},\n\t\t{51, 51, 51, 51, 51, 51, 51, 51, 51, 10: 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51},\n\t\t{1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 541: 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502},\n\t\t{1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 541: 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501},\n\t\t// 155\n\t\t{1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 541: 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500},\n\t\t{1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 541: 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499},\n\t\t{1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 541: 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498},\n\t\t{1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 541: 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497},\n\t\t{1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 541: 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496},\n\t\t// 160\n\t\t{1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 541: 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1495},\n\t\t{1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 541: 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494, 1494},\n\t\t{1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 541: 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493},\n\t\t{1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 541: 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492},\n\t\t{1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 541: 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491},\n\t\t// 165\n\t\t{1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 541: 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490, 1490},\n\t\t{1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 541: 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489},\n\t\t{1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 541: 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488},\n\t\t{1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 541: 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487},\n\t\t{1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 541: 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486, 1486},\n\t\t// 170\n\t\t{1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 541: 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1485},\n\t\t{1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 541: 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484},\n\t\t{1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 541: 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483},\n\t\t{1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 541: 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482},\n\t\t{1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 541: 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481},\n\t\t// 175\n\t\t{1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 541: 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480, 1480},\n\t\t{1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 541: 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479, 1479},\n\t\t{1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 541: 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478},\n\t\t{1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 541: 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477},\n\t\t{1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 541: 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476},\n\t\t// 180\n\t\t{1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 541: 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475},\n\t\t{1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 541: 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474, 1474},\n\t\t{1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 541: 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473},\n\t\t{1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 541: 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472, 1472},\n\t\t{1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 541: 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471, 1471},\n\t\t// 185\n\t\t{1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 541: 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470, 1470},\n\t\t{1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 541: 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469},\n\t\t{1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 541: 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468},\n\t\t{1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 541: 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467},\n\t\t{1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 541: 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466, 1466},\n\t\t// 190\n\t\t{1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 541: 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465, 1465},\n\t\t{1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 541: 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464, 1464},\n\t\t{1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 541: 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463, 1463},\n\t\t{1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 541: 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462, 1462},\n\t\t{1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 541: 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461, 1461},\n\t\t// 195\n\t\t{1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 541: 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460, 1460},\n\t\t{1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 541: 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459, 1459},\n\t\t{1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 541: 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458},\n\t\t{1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 541: 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457},\n\t\t{1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 541: 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456},\n\t\t// 200\n\t\t{1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 541: 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455, 1455},\n\t\t{1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 541: 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454},\n\t\t{1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 541: 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453},\n\t\t{1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 541: 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452, 1452},\n\t\t{1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 541: 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451},\n\t\t// 205\n\t\t{1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 541: 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450},\n\t\t{1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 541: 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449},\n\t\t{1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 541: 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448},\n\t\t{1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 541: 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447},\n\t\t{1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 541: 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1446},\n\t\t// 210\n\t\t{1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 541: 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1445},\n\t\t{1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 541: 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1444},\n\t\t{1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 541: 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443, 1443},\n\t\t{1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 541: 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442, 1442},\n\t\t{1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 541: 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441},\n\t\t// 215\n\t\t{1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 541: 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440},\n\t\t{1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 541: 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439},\n\t\t{1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 541: 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438, 1438},\n\t\t{1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 541: 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437},\n\t\t{1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 541: 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436, 1436},\n\t\t// 220\n\t\t{1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 541: 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435},\n\t\t{1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 541: 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434, 1434},\n\t\t{1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 541: 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433, 1433},\n\t\t{1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 541: 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432},\n\t\t{1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 541: 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431},\n\t\t// 225\n\t\t{1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 541: 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430, 1430},\n\t\t{1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 541: 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429, 1429},\n\t\t{1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 541: 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428, 1428},\n\t\t{1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 541: 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1427},\n\t\t{1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 541: 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426},\n\t\t// 230\n\t\t{1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 541: 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1425},\n\t\t{1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 541: 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424, 1424},\n\t\t{1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 541: 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423, 1423},\n\t\t{1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 541: 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422},\n\t\t{1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 541: 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421, 1421},\n\t\t// 235\n\t\t{1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 541: 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420},\n\t\t{1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 541: 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419},\n\t\t{1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 541: 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418},\n\t\t{1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 541: 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417},\n\t\t{1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 541: 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416},\n\t\t// 240\n\t\t{1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 541: 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415},\n\t\t{1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 541: 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414},\n\t\t{1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 541: 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413},\n\t\t{1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 541: 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412},\n\t\t{1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 541: 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411},\n\t\t// 245\n\t\t{1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 541: 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410},\n\t\t{1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 541: 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409},\n\t\t{1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 541: 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408},\n\t\t{1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 541: 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407},\n\t\t{1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 541: 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406},\n\t\t// 250\n\t\t{1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 541: 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405},\n\t\t{1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 541: 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404, 1404},\n\t\t{1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 541: 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403},\n\t\t{1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 541: 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402, 1402},\n\t\t{1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 541: 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401, 1401},\n\t\t// 255\n\t\t{1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 541: 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400, 1400},\n\t\t{1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 541: 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399, 1399},\n\t\t{1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 541: 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398, 1398},\n\t\t{1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 541: 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397, 1397},\n\t\t{1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 541: 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396, 1396},\n\t\t// 260\n\t\t{1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 541: 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395, 1395},\n\t\t{1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 541: 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394, 1394},\n\t\t{1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 541: 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393, 1393},\n\t\t{1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 541: 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392},\n\t\t{1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 541: 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391, 1391},\n\t\t// 265\n\t\t{1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 541: 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390},\n\t\t{1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 541: 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389, 1389},\n\t\t{1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 541: 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388},\n\t\t{1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 541: 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387},\n\t\t{1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 541: 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386},\n\t\t// 270\n\t\t{1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 541: 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385, 1385},\n\t\t{1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 541: 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384, 1384},\n\t\t{1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 541: 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383, 1383},\n\t\t{1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 541: 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382, 1382},\n\t\t{1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 541: 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381},\n\t\t// 275\n\t\t{1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 541: 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380},\n\t\t{1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 541: 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379},\n\t\t{1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 541: 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1378},\n\t\t{1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 541: 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377},\n\t\t{1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 541: 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376},\n\t\t// 280\n\t\t{1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 541: 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375, 1375},\n\t\t{1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 541: 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374, 1374},\n\t\t{1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 541: 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373},\n\t\t{1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 541: 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372},\n\t\t{1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 541: 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371},\n\t\t// 285\n\t\t{1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 541: 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370, 1370},\n\t\t{1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 541: 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369},\n\t\t{1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 541: 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368, 1368},\n\t\t{1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 541: 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367, 1367},\n\t\t{1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 541: 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366, 1366},\n\t\t// 290\n\t\t{1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 541: 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365},\n\t\t{1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 541: 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364},\n\t\t{1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 541: 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363},\n\t\t{1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 541: 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362, 1362},\n\t\t{1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 541: 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361},\n\t\t// 295\n\t\t{1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 541: 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360},\n\t\t{1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 541: 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359, 1359},\n\t\t{1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 541: 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358},\n\t\t{1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 541: 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357, 1357},\n\t\t{1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 541: 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356, 1356},\n\t\t// 300\n\t\t{1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 541: 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355},\n\t\t{1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 541: 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354, 1354},\n\t\t{1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 541: 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353},\n\t\t{1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 541: 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352},\n\t\t{1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 541: 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351},\n\t\t// 305\n\t\t{1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 541: 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350},\n\t\t{1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 541: 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349},\n\t\t{1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 541: 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348},\n\t\t{1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 541: 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347},\n\t\t{1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 541: 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346},\n\t\t// 310\n\t\t{1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 541: 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345},\n\t\t{1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 541: 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344},\n\t\t{1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 541: 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1343},\n\t\t{1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 541: 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342, 1342},\n\t\t{1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 541: 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341, 1341},\n\t\t// 315\n\t\t{1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 541: 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340},\n\t\t{1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 541: 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339, 1339},\n\t\t{1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 541: 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1338},\n\t\t{1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 541: 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337, 1337},\n\t\t{1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 541: 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336},\n\t\t// 320\n\t\t{1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 541: 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335},\n\t\t{1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 541: 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334, 1334},\n\t\t{1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 541: 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333, 1333},\n\t\t{1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 541: 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332},\n\t\t{1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 541: 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331},\n\t\t// 325\n\t\t{1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 541: 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1330},\n\t\t{1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 541: 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329},\n\t\t{1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 541: 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328},\n\t\t{1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 541: 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327},\n\t\t{1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 541: 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326, 1326},\n\t\t// 330\n\t\t{1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 541: 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325, 1325},\n\t\t{1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 541: 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324, 1324},\n\t\t{1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 541: 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323, 1323},\n\t\t{1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 541: 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322, 1322},\n\t\t{1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 541: 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321, 1321},\n\t\t// 335\n\t\t{1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 541: 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320, 1320},\n\t\t{1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 541: 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319, 1319},\n\t\t{1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 541: 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318, 1318},\n\t\t{1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 541: 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317, 1317},\n\t\t{1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 541: 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316},\n\t\t// 340\n\t\t{1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 541: 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315},\n\t\t{1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 541: 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1314},\n\t\t{1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 541: 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313},\n\t\t{1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 541: 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312, 1312},\n\t\t{1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 541: 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311, 1311},\n\t\t// 345\n\t\t{1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 541: 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310},\n\t\t{1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 541: 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309},\n\t\t{1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 541: 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1308},\n\t\t{1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 541: 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307},\n\t\t{1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 541: 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306, 1306},\n\t\t// 350\n\t\t{1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 541: 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305},\n\t\t{1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 541: 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304, 1304},\n\t\t{1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 541: 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303, 1303},\n\t\t{1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 541: 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302, 1302},\n\t\t{1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 541: 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301},\n\t\t// 355\n\t\t{1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 541: 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300, 1300},\n\t\t{1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 541: 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299, 1299},\n\t\t{1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 541: 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298, 1298},\n\t\t{1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 541: 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297, 1297},\n\t\t{1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 541: 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296, 1296},\n\t\t// 360\n\t\t{1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 541: 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295},\n\t\t{1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 541: 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294},\n\t\t{1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 541: 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293},\n\t\t{1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 541: 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292},\n\t\t{1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 541: 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291, 1291},\n\t\t// 365\n\t\t{1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 541: 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290, 1290},\n\t\t{1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 541: 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289, 1289},\n\t\t{1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 541: 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288, 1288},\n\t\t{1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 541: 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287},\n\t\t{1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 541: 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286, 1286},\n\t\t// 370\n\t\t{1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 541: 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285, 1285},\n\t\t{1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 541: 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284},\n\t\t{1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 541: 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283},\n\t\t{1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 541: 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282},\n\t\t{1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 541: 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281},\n\t\t// 375\n\t\t{1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 541: 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280},\n\t\t{1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 541: 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279},\n\t\t{1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 541: 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278},\n\t\t{1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 541: 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277, 1277},\n\t\t{1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 541: 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276, 1276},\n\t\t// 380\n\t\t{1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 541: 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275, 1275},\n\t\t{1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 541: 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274},\n\t\t{1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 541: 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273},\n\t\t{1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 541: 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272},\n\t\t{1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 541: 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271, 1271},\n\t\t// 385\n\t\t{1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 541: 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270},\n\t\t{1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 541: 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269, 1269},\n\t\t{1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 541: 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268},\n\t\t{1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 541: 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267},\n\t\t{1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 541: 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266},\n\t\t// 390\n\t\t{1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 541: 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265},\n\t\t{1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 541: 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264, 1264},\n\t\t{1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 541: 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263, 1263},\n\t\t{1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 541: 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262, 1262},\n\t\t{1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 541: 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261, 1261},\n\t\t// 395\n\t\t{1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 541: 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260},\n\t\t{1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 541: 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259},\n\t\t{1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 541: 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258},\n\t\t{1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 541: 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257, 1257},\n\t\t{1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 541: 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256, 1256},\n\t\t// 400\n\t\t{1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 541: 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255},\n\t\t{1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 541: 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254},\n\t\t{1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 541: 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253, 1253},\n\t\t{1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 541: 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252, 1252},\n\t\t{1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 541: 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251},\n\t\t// 405\n\t\t{1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 541: 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250},\n\t\t{1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 541: 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249},\n\t\t{1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 541: 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248},\n\t\t{1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 541: 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247},\n\t\t{1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 541: 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246},\n\t\t// 410\n\t\t{1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 541: 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245},\n\t\t{1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 541: 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1244},\n\t\t{1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 541: 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243},\n\t\t{1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 541: 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242},\n\t\t{1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 541: 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241, 1241},\n\t\t// 415\n\t\t{1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 541: 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240},\n\t\t{1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 541: 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239, 1239},\n\t\t{1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 541: 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238},\n\t\t{1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 541: 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237, 1237},\n\t\t{1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 541: 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236},\n\t\t// 420\n\t\t{1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 541: 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235},\n\t\t{1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 541: 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234},\n\t\t{1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 541: 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233},\n\t\t{1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 541: 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232},\n\t\t{1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 541: 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231},\n\t\t// 425\n\t\t{1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 541: 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230},\n\t\t{1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 541: 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229},\n\t\t{1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 541: 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228, 1228},\n\t\t{1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 541: 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227},\n\t\t{1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 541: 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226},\n\t\t// 430\n\t\t{1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 541: 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225, 1225},\n\t\t{1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 541: 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224, 1224},\n\t\t{1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 541: 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223},\n\t\t{1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 541: 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222, 1222},\n\t\t{1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 541: 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221, 1221},\n\t\t// 435\n\t\t{1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 541: 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220, 1220},\n\t\t{1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 541: 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219, 1219},\n\t\t{1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 541: 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218, 1218},\n\t\t{1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 541: 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217},\n\t\t{1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 541: 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216, 1216},\n\t\t// 440\n\t\t{1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 541: 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1215},\n\t\t{1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 541: 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214, 1214},\n\t\t{1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 541: 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213},\n\t\t{1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 541: 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212, 1212},\n\t\t{1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 541: 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211, 1211},\n\t\t// 445\n\t\t{1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 541: 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210},\n\t\t{1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 541: 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209},\n\t\t{1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 541: 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208},\n\t\t{1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 541: 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207},\n\t\t{1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 541: 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206, 1206},\n\t\t// 450\n\t\t{1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 541: 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1205},\n\t\t{1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 541: 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204},\n\t\t{1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 541: 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203},\n\t\t{1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 541: 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202},\n\t\t{1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 541: 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201},\n\t\t// 455\n\t\t{1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 541: 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200},\n\t\t{1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 541: 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199, 1199},\n\t\t{1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 541: 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198},\n\t\t{1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 541: 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197, 1197},\n\t\t{1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 541: 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196, 1196},\n\t\t// 460\n\t\t{1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 541: 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195},\n\t\t{1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 541: 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194, 1194},\n\t\t{1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 541: 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193},\n\t\t{1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 541: 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192},\n\t\t{1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 541: 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191},\n\t\t// 465\n\t\t{1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 541: 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190, 1190},\n\t\t{1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 541: 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189},\n\t\t{1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 541: 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188},\n\t\t{1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 541: 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187},\n\t\t{1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 541: 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186},\n\t\t// 470\n\t\t{1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 541: 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185},\n\t\t{1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 541: 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184, 1184},\n\t\t{1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 541: 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183},\n\t\t{1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 541: 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182},\n\t\t{1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 541: 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181},\n\t\t// 475\n\t\t{1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 541: 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180},\n\t\t{1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 541: 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179, 1179},\n\t\t{1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 541: 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178, 1178},\n\t\t{1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 541: 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177},\n\t\t{1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 541: 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176, 1176},\n\t\t// 480\n\t\t{1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 541: 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175},\n\t\t{1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 541: 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174},\n\t\t{1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 541: 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173, 1173},\n\t\t{1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 541: 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172, 1172},\n\t\t{1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 541: 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171, 1171},\n\t\t// 485\n\t\t{1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 541: 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170, 1170},\n\t\t{1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 541: 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169, 1169},\n\t\t{1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 541: 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168, 1168},\n\t\t{1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 541: 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167, 1167},\n\t\t{1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 541: 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166, 1166},\n\t\t// 490\n\t\t{1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 541: 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165, 1165},\n\t\t{1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 541: 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164, 1164},\n\t\t{1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 541: 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163, 1163},\n\t\t{1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 541: 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162},\n\t\t{1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 541: 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161},\n\t\t// 495\n\t\t{1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 541: 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160},\n\t\t{1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 541: 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159},\n\t\t{1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 541: 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158, 1158},\n\t\t{1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 541: 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157},\n\t\t{1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 541: 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156},\n\t\t// 500\n\t\t{1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 541: 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155, 1155},\n\t\t{1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 541: 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154},\n\t\t{1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 541: 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153},\n\t\t{1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 541: 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152},\n\t\t{1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 541: 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1151},\n\t\t// 505\n\t\t{1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 541: 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1150},\n\t\t{1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 541: 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149, 1149},\n\t\t{1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 541: 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148, 1148},\n\t\t{1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 541: 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147, 1147},\n\t\t{1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 541: 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146, 1146},\n\t\t// 510\n\t\t{1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 541: 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145, 1145},\n\t\t{1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 541: 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144, 1144},\n\t\t{1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 541: 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143, 1143},\n\t\t{1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 541: 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142, 1142},\n\t\t{861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 364: 861, 861, 861, 861, 861, 861, 373: 861, 861, 861, 861, 861, 861, 861, 861, 861, 383: 861, 861, 387: 861, 390: 861, 392: 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 407: 2548, 425: 861, 437: 861, 459: 861, 463: 861, 522: 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 541: 861, 544: 861, 861, 861, 549: 861, 861, 553: 861, 861, 861, 861, 861, 861, 861, 861, 566: 861, 861, 861, 570: 861, 572: 861},\n\t\t// 515\n\t\t{53, 53, 9: 2546},\n\t\t{555: 2542, 567: 2543, 995: 2541},\n\t\t{45, 45, 9: 45},\n\t\t{50, 50, 9: 50},\n\t\t{49, 49, 9: 49, 81: 2545},\n\t\t// 520\n\t\t{47, 47, 9: 47, 81: 2544},\n\t\t{46, 46, 9: 46},\n\t\t{48, 48, 9: 48},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 2539, 915: 2547},\n\t\t{44, 44, 9: 44},\n\t\t// 525\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2549, 2178, 2179, 2177},\n\t\t{860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 364: 860, 860, 860, 860, 860, 860, 373: 860, 860, 860, 860, 860, 860, 860, 860, 860, 383: 860, 860, 387: 860, 390: 860, 392: 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 425: 860, 437: 860, 459: 860, 463: 860, 522: 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 541: 860, 544: 860, 860, 860, 549: 860, 860, 553: 860, 860, 860, 860, 860, 860, 860, 860, 566: 860, 860, 860, 570: 860, 572: 860},\n\t\t{54, 54},\n\t\t{81: 2141, 706: 80, 854: 2554},\n\t\t{363: 2553},\n\t\t// 530\n\t\t{38, 38},\n\t\t{706: 2555},\n\t\t{363: 2556},\n\t\t{380: 1689, 384: 2558, 522: 2557, 814: 2559},\n\t\t{1688, 1688, 362: 1688, 374: 1688, 380: 1688, 524: 1688},\n\t\t// 535\n\t\t{1687, 1687, 362: 1687, 374: 1687, 380: 1687, 524: 1687},\n\t\t{380: 2560},\n\t\t{605: 2561},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 2562},\n\t\t{82, 82, 52: 82, 82, 362: 82, 392: 82, 522: 82, 526: 2564, 541: 82, 945: 2563},\n\t\t// 540\n\t\t{78, 78, 52: 2574, 2573, 362: 78, 392: 78, 522: 78, 541: 78, 675: 2572, 749: 2571},\n\t\t{392: 2565},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 438: 2567, 537: 2569, 2178, 2179, 2177, 601: 2566, 648: 2570},\n\t\t{627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 627, 52: 627, 627, 361: 627, 627, 365: 627, 373: 627, 627, 376: 627, 384: 627, 387: 627, 392: 627, 395: 627, 438: 627, 522: 627, 524: 627, 627, 627, 530: 627, 627, 627, 541: 627},\n\t\t{626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 52: 626, 626, 361: 626, 626, 365: 626, 373: 626, 626, 376: 626, 384: 626, 387: 626, 392: 626, 395: 626, 438: 626, 522: 626, 524: 626, 626, 626, 530: 626, 626, 626, 541: 626},\n\t\t// 545\n\t\t{219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 394: 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 408: 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 432: 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 521: 219, 219, 524: 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 541: 219, 545: 219, 219, 219, 551: 219, 219, 571: 219},\n\t\t{218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 394: 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 408: 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 432: 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 521: 218, 218, 524: 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 541: 218, 545: 218, 218, 218, 551: 218, 218, 571: 218},\n\t\t{81, 81, 52: 81, 81, 362: 81, 392: 81, 522: 81, 541: 81},\n\t\t{65, 65, 362: 65, 392: 65, 522: 65, 541: 2157, 726: 2594},\n\t\t{619: 2577, 627: 2579, 631: 2580, 633: 2578, 825: 2576, 969: 2575},\n\t\t// 550\n\t\t{362: 76, 390: 76, 425: 76, 619: 76, 627: 76, 631: 76, 633: 76},\n\t\t{362: 75, 390: 75, 425: 75, 619: 75, 627: 75, 631: 75, 633: 75},\n\t\t{77, 77, 361: 77, 77, 364: 77, 77, 368: 77, 375: 77, 392: 77, 522: 77, 541: 77, 619: 2577, 627: 2579, 631: 2580, 633: 2578, 825: 2593},\n\t\t{73, 73, 361: 73, 73, 364: 73, 73, 368: 73, 375: 73, 392: 73, 522: 73, 541: 73, 619: 73, 627: 73, 631: 73, 633: 73},\n\t\t{546: 2591},\n\t\t// 555\n\t\t{627: 2588},\n\t\t{546: 2586},\n\t\t{546: 2581},\n\t\t{363: 2583, 457: 2585, 2584, 721: 2582},\n\t\t{69, 69, 361: 69, 69, 364: 69, 69, 368: 69, 375: 69, 392: 69, 522: 69, 541: 69, 619: 69, 627: 69, 631: 69, 633: 69},\n\t\t// 560\n\t\t{68, 68, 361: 68, 68, 364: 68, 68, 368: 68, 375: 68, 392: 68, 522: 68, 541: 68, 619: 68, 627: 68, 631: 68, 633: 68},\n\t\t{67, 67, 361: 67, 67, 364: 67, 67, 368: 67, 375: 67, 392: 67, 522: 67, 541: 67, 619: 67, 627: 67, 631: 67, 633: 67},\n\t\t{66, 66, 361: 66, 66, 364: 66, 66, 368: 66, 375: 66, 392: 66, 522: 66, 541: 66, 619: 66, 627: 66, 631: 66, 633: 66},\n\t\t{363: 2583, 457: 2585, 2584, 721: 2587},\n\t\t{70, 70, 361: 70, 70, 364: 70, 70, 368: 70, 375: 70, 392: 70, 522: 70, 541: 70, 619: 70, 627: 70, 631: 70, 633: 70},\n\t\t// 565\n\t\t{546: 2589},\n\t\t{363: 2583, 457: 2585, 2584, 721: 2590},\n\t\t{71, 71, 361: 71, 71, 364: 71, 71, 368: 71, 375: 71, 392: 71, 522: 71, 541: 71, 619: 71, 627: 71, 631: 71, 633: 71},\n\t\t{363: 2583, 457: 2585, 2584, 721: 2592},\n\t\t{72, 72, 361: 72, 72, 364: 72, 72, 368: 72, 375: 72, 392: 72, 522: 72, 541: 72, 619: 72, 627: 72, 631: 72, 633: 72},\n\t\t// 570\n\t\t{74, 74, 361: 74, 74, 364: 74, 74, 368: 74, 375: 74, 392: 74, 522: 74, 541: 74, 619: 74, 627: 74, 631: 74, 633: 74},\n\t\t{84, 84, 362: 84, 392: 84, 522: 2596, 979: 2595},\n\t\t{1856, 1856, 362: 2599, 392: 1856, 950: 2600},\n\t\t{393: 2147, 598: 2597},\n\t\t{541: 2598},\n\t\t// 575\n\t\t{83, 83, 362: 83, 392: 83},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 1862, 447: 2763, 537: 3361, 2178, 2179, 2177, 575: 3403, 603: 3402, 789: 3401, 948: 3400, 3404},\n\t\t{59, 59, 392: 2602, 993: 2601},\n\t\t{85, 85},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 407: 2604, 537: 2603, 2178, 2179, 2177, 576: 2607, 852: 2606, 992: 2605},\n\t\t// 580\n\t\t{1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 363: 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 374: 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 385: 1069, 1069, 388: 1069, 1069, 1069, 1069, 1069, 396: 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 3396, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 432: 1069, 1069, 1069, 1069, 1069, 1069, 439: 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 448: 1069, 1069, 521: 1069, 542: 1069, 1069},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3393, 2178, 2179, 2177},\n\t\t{58, 58, 9: 3391},\n\t\t{56, 56, 9: 56},\n\t\t{391: 2608},\n\t\t// 585\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2643, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2610, 654: 2747},\n\t\t{618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 363: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 374: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 385: 618, 618, 388: 618, 618, 618, 618, 618, 396: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 408: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 432: 618, 618, 618, 618, 618, 618, 439: 618, 618, 618, 618, 618, 618, 618, 618, 448: 618, 618, 521: 618, 548: 3389},\n\t\t{1120, 1120, 9: 1120, 361: 1120, 364: 1120, 378: 1120, 381: 1120, 2760, 1120, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3388},\n\t\t{362: 3360},\n\t\t// 590\n\t\t{1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 363: 1602, 1602, 1602, 1602, 1602, 1602, 374: 1602, 1602, 377: 1602, 1602, 1602, 1602, 1602, 1602, 1602, 385: 1602, 1602, 388: 1602, 1602, 1602, 3343, 1602, 396: 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 408: 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602, 426: 1602, 1602, 3340, 3338, 3337, 432: 3345, 3339, 3341, 3342, 3344, 954: 3336, 986: 3335},\n\t\t{1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 363: 1577, 1577, 1577, 1577, 1577, 1577, 374: 1577, 1577, 377: 1577, 1577, 1577, 1577, 1577, 1577, 1577, 385: 1577, 1577, 388: 1577, 1577, 1577, 1577, 1577, 396: 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 408: 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 1577, 426: 1577, 1577, 1577, 1577, 1577, 432: 1577, 1577, 1577, 1577, 1577},\n\t\t{1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 363: 1550, 1550, 1550, 1550, 1550, 1550, 3309, 3062, 3063, 3068, 374: 1550, 1550, 377: 1550, 1550, 1550, 1550, 1550, 1550, 1550, 385: 1550, 1550, 388: 1550, 1550, 1550, 1550, 1550, 396: 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 3311, 3064, 408: 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 3310, 1550, 1550, 1550, 1550, 1550, 432: 1550, 1550, 1550, 1550, 1550, 3308, 439: 3066, 3059, 3065, 3069, 3058, 3067, 3060, 3061, 448: 3317, 3318, 890: 3312, 942: 3314, 984: 3313, 989: 3315, 1029: 3316},\n\t\t{1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 3305, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 374: 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 385: 1502, 1502, 388: 1502, 1502, 1502, 1502, 1502, 396: 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 432: 1502, 1502, 1502, 1502, 1502, 1502, 439: 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 448: 1502, 1502, 521: 1502, 542: 1502, 1502},\n\t\t{1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1024, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 374: 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 385: 1496, 1496, 388: 1496, 1496, 1496, 1496, 1496, 396: 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 432: 1496, 1496, 1496, 1496, 1496, 1496, 439: 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 448: 1496, 1496, 521: 1496, 542: 1496, 1496},\n\t\t// 595\n\t\t{1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 3300, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 374: 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 385: 1492, 1492, 388: 1492, 1492, 1492, 1492, 1492, 396: 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 432: 1492, 1492, 1492, 1492, 1492, 1492, 439: 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 448: 1492, 1492, 521: 1492, 542: 1492, 1492},\n\t\t{1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1023, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 374: 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 385: 1483, 1483, 388: 1483, 1483, 1483, 1483, 1483, 396: 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 432: 1483, 1483, 1483, 1483, 1483, 1483, 439: 1483, 1483, 1483, 1483, 1483, 1483, 1483, 1483, 448: 1483, 1483, 521: 1483, 542: 1483, 1483},\n\t\t{1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1020, 3299, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 374: 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 385: 1475, 1475, 388: 1475, 1475, 1475, 1475, 1475, 396: 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 432: 1475, 1475, 1475, 1475, 1475, 1475, 439: 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1475, 448: 1475, 1475, 521: 1475, 542: 1475, 1475},\n\t\t{1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1018, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 374: 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 385: 1473, 1473, 388: 1473, 1473, 1473, 1473, 1473, 396: 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 432: 1473, 1473, 1473, 1473, 1473, 1473, 439: 1473, 1473, 1473, 1473, 1473, 1473, 1473, 1473, 448: 1473, 1473, 521: 1473, 542: 1473, 1473},\n\t\t{1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1014, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 374: 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 385: 1451, 1451, 388: 1451, 1451, 1451, 1451, 1451, 396: 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 432: 1451, 1451, 1451, 1451, 1451, 1451, 439: 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 448: 1451, 1451, 521: 1451, 542: 1451, 1451},\n\t\t// 600\n\t\t{1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1017, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 374: 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 385: 1447, 1447, 388: 1447, 1447, 1447, 1447, 1447, 396: 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 432: 1447, 1447, 1447, 1447, 1447, 1447, 439: 1447, 1447, 1447, 1447, 1447, 1447, 1447, 1447, 448: 1447, 1447, 521: 1447, 542: 1447, 1447},\n\t\t{1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 3296, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 374: 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 385: 1440, 1440, 388: 1440, 1440, 1440, 1440, 1440, 396: 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 432: 1440, 1440, 1440, 1440, 1440, 1440, 439: 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 448: 1440, 1440, 521: 1440, 542: 1440, 1440},\n\t\t{1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1001, 3295, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 374: 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 385: 1419, 1419, 388: 1419, 1419, 1419, 1419, 1419, 396: 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 432: 1419, 1419, 1419, 1419, 1419, 1419, 439: 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 448: 1419, 1419, 521: 1419, 542: 1419, 1419},\n\t\t{1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1000, 3294, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 374: 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 385: 1418, 1418, 388: 1418, 1418, 1418, 1418, 1418, 396: 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 432: 1418, 1418, 1418, 1418, 1418, 1418, 439: 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1418, 448: 1418, 1418, 521: 1418, 542: 1418, 1418},\n\t\t{1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 999, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 374: 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 385: 1415, 1415, 388: 1415, 1415, 1415, 1415, 1415, 396: 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 432: 1415, 1415, 1415, 1415, 1415, 1415, 439: 1415, 1415, 1415, 1415, 1415, 1415, 1415, 1415, 448: 1415, 1415, 521: 1415, 542: 1415, 1415},\n\t\t// 605\n\t\t{1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 996, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 374: 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 385: 1410, 1410, 388: 1410, 1410, 1410, 1410, 1410, 396: 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 432: 1410, 1410, 1410, 1410, 1410, 1410, 439: 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 448: 1410, 1410, 521: 1410, 542: 1410, 1410},\n\t\t{1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 997, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 374: 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 385: 1408, 1408, 388: 1408, 1408, 1408, 1408, 1408, 396: 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 432: 1408, 1408, 1408, 1408, 1408, 1408, 439: 1408, 1408, 1408, 1408, 1408, 1408, 1408, 1408, 448: 1408, 1408, 521: 1408, 542: 1408, 1408},\n\t\t{1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 998, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 374: 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 385: 1405, 1405, 388: 1405, 1405, 1405, 1405, 1405, 396: 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 432: 1405, 1405, 1405, 1405, 1405, 1405, 439: 1405, 1405, 1405, 1405, 1405, 1405, 1405, 1405, 448: 1405, 1405, 521: 1405, 542: 1405, 1405},\n\t\t{1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1021, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 374: 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 385: 1403, 1403, 388: 1403, 1403, 1403, 1403, 1403, 396: 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 432: 1403, 1403, 1403, 1403, 1403, 1403, 439: 1403, 1403, 1403, 1403, 1403, 1403, 1403, 1403, 448: 1403, 1403, 521: 1403, 542: 1403, 1403},\n\t\t{1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1008, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 374: 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 385: 1390, 1390, 388: 1390, 1390, 1390, 1390, 1390, 396: 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 432: 1390, 1390, 1390, 1390, 1390, 1390, 439: 1390, 1390, 1390, 1390, 1390, 1390, 1390, 1390, 448: 1390, 1390, 521: 1390, 542: 1390, 1390},\n\t\t// 610\n\t\t{1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1005, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 374: 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 385: 1369, 1369, 388: 1369, 1369, 1369, 1369, 1369, 396: 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 432: 1369, 1369, 1369, 1369, 1369, 1369, 439: 1369, 1369, 1369, 1369, 1369, 1369, 1369, 1369, 448: 1369, 1369, 521: 1369, 542: 1369, 1369},\n\t\t{1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1003, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 374: 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 385: 1352, 1352, 388: 1352, 1352, 1352, 1352, 1352, 396: 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 432: 1352, 1352, 1352, 1352, 1352, 1352, 439: 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 448: 1352, 1352, 521: 1352, 542: 1352, 1352},\n\t\t{1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1022, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 374: 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 385: 1351, 1351, 388: 1351, 1351, 1351, 1351, 1351, 396: 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 432: 1351, 1351, 1351, 1351, 1351, 1351, 439: 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 448: 1351, 1351, 521: 1351, 542: 1351, 1351},\n\t\t{1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1010, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 374: 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 385: 1350, 1350, 388: 1350, 1350, 1350, 1350, 1350, 396: 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 432: 1350, 1350, 1350, 1350, 1350, 1350, 439: 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 448: 1350, 1350, 521: 1350, 542: 1350, 1350},\n\t\t{1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1012, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 374: 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 385: 1346, 1346, 388: 1346, 1346, 1346, 1346, 1346, 396: 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 432: 1346, 1346, 1346, 1346, 1346, 1346, 439: 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 448: 1346, 1346, 521: 1346, 542: 1346, 1346},\n\t\t// 615\n\t\t{1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1011, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 374: 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 385: 1345, 1345, 388: 1345, 1345, 1345, 1345, 1345, 396: 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 432: 1345, 1345, 1345, 1345, 1345, 1345, 439: 1345, 1345, 1345, 1345, 1345, 1345, 1345, 1345, 448: 1345, 1345, 521: 1345, 542: 1345, 1345},\n\t\t{1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1002, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 374: 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 385: 1340, 1340, 388: 1340, 1340, 1340, 1340, 1340, 396: 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 432: 1340, 1340, 1340, 1340, 1340, 1340, 439: 1340, 1340, 1340, 1340, 1340, 1340, 1340, 1340, 448: 1340, 1340, 521: 1340, 542: 1340, 1340},\n\t\t{1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 3285, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 374: 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 385: 1182, 1182, 388: 1182, 1182, 1182, 1182, 1182, 396: 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 432: 1182, 1182, 1182, 1182, 1182, 1182, 439: 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 448: 1182, 1182, 521: 1182, 542: 1182, 1182},\n\t\t{1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 3278, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 374: 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 385: 1161, 1161, 388: 1161, 1161, 1161, 1161, 1161, 396: 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 432: 1161, 1161, 1161, 1161, 1161, 1161, 439: 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 448: 1161, 1161, 521: 1161, 542: 1161, 1161},\n\t\t{1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 3271, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 374: 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 385: 1160, 1160, 388: 1160, 1160, 1160, 1160, 1160, 396: 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 432: 1160, 1160, 1160, 1160, 1160, 1160, 439: 1160, 1160, 1160, 1160, 1160, 1160, 1160, 1160, 448: 1160, 1160, 521: 1160, 542: 1160, 1160},\n\t\t// 620\n\t\t{1119, 1119, 9: 1119, 361: 1119, 2751, 364: 1119, 378: 1119, 381: 1119, 383: 1119},\n\t\t{1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 363: 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 385: 1108, 1108, 388: 1108, 1108, 1108, 1108, 1108, 394: 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 408: 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 432: 1108, 1108, 1108, 1108, 1108, 1108, 439: 1108, 1108, 1108, 1108, 1108, 1108, 1108, 1108, 448: 1108, 1108, 521: 1108, 527: 1108, 1108, 1108, 533: 1108, 1108, 1108, 1108},\n\t\t{1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 363: 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 385: 1107, 1107, 388: 1107, 1107, 1107, 1107, 1107, 394: 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 408: 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 432: 1107, 1107, 1107, 1107, 1107, 1107, 439: 1107, 1107, 1107, 1107, 1107, 1107, 1107, 1107, 448: 1107, 1107, 521: 1107, 527: 1107, 1107, 1107, 533: 1107, 1107, 1107, 1107},\n\t\t{1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 363: 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 385: 1106, 1106, 388: 1106, 1106, 1106, 1106, 1106, 394: 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 408: 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 432: 1106, 1106, 1106, 1106, 1106, 1106, 439: 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 448: 1106, 1106, 521: 1106, 527: 1106, 1106, 1106, 533: 1106, 1106, 1106, 1106},\n\t\t{1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 363: 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 385: 1105, 1105, 388: 1105, 1105, 1105, 1105, 1105, 394: 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 408: 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 432: 1105, 1105, 1105, 1105, 1105, 1105, 439: 1105, 1105, 1105, 1105, 1105, 1105, 1105, 1105, 448: 1105, 1105, 521: 1105, 527: 1105, 1105, 1105, 533: 1105, 1105, 1105, 1105},\n\t\t// 625\n\t\t{1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 363: 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 385: 1104, 1104, 388: 1104, 1104, 1104, 1104, 1104, 394: 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 408: 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 432: 1104, 1104, 1104, 1104, 1104, 1104, 439: 1104, 1104, 1104, 1104, 1104, 1104, 1104, 1104, 448: 1104, 1104, 521: 1104, 527: 1104, 1104, 1104, 533: 1104, 1104, 1104, 1104},\n\t\t{1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 363: 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 385: 1103, 1103, 388: 1103, 1103, 1103, 1103, 1103, 394: 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 408: 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 432: 1103, 1103, 1103, 1103, 1103, 1103, 439: 1103, 1103, 1103, 1103, 1103, 1103, 1103, 1103, 448: 1103, 1103, 521: 1103, 527: 1103, 1103, 1103, 533: 1103, 1103, 1103, 1103},\n\t\t{1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 363: 3270, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 385: 1102, 1102, 388: 1102, 1102, 1102, 1102, 1102, 394: 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 408: 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 432: 1102, 1102, 1102, 1102, 1102, 1102, 439: 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 448: 1102, 1102, 521: 1102, 527: 1102, 1102, 1102, 533: 1102, 1102, 1102, 1102},\n\t\t{363: 3269},\n\t\t{1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 363: 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 385: 1100, 1100, 388: 1100, 1100, 1100, 1100, 1100, 394: 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 408: 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 432: 1100, 1100, 1100, 1100, 1100, 1100, 439: 1100, 1100, 1100, 1100, 1100, 1100, 1100, 1100, 448: 1100, 1100, 521: 1100, 527: 1100, 1100, 1100, 533: 1100, 1100, 1100, 1100},\n\t\t// 630\n\t\t{1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 363: 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 385: 1099, 1099, 388: 1099, 1099, 1099, 1099, 1099, 394: 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 408: 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 432: 1099, 1099, 1099, 1099, 1099, 1099, 439: 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 448: 1099, 1099, 521: 1099, 527: 1099, 1099, 1099, 533: 1099, 1099, 1099, 1099},\n\t\t{1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 363: 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 385: 1098, 1098, 388: 1098, 1098, 1098, 1098, 1098, 394: 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 408: 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 432: 1098, 1098, 1098, 1098, 1098, 1098, 439: 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 448: 1098, 1098, 521: 1098, 527: 1098, 1098, 1098, 533: 1098, 1098, 1098, 1098, 545: 1098},\n\t\t{1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 363: 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 374: 1070, 1070, 2764, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 385: 1070, 1070, 388: 1070, 1070, 1070, 1070, 1070, 396: 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 408: 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 432: 1070, 1070, 1070, 1070, 1070, 1070, 439: 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 448: 1070, 1070, 521: 2765},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 3267},\n\t\t{1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 363: 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 374: 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 385: 1064, 1064, 388: 1064, 1064, 1064, 1064, 1064, 396: 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 408: 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 432: 1064, 1064, 1064, 1064, 1064, 1064, 439: 1064, 1064, 1064, 1064, 1064, 1064, 1064, 1064, 448: 1064, 1064, 521: 1064, 542: 3263, 3264},\n\t\t// 635\n\t\t{1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 363: 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 374: 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 385: 1063, 1063, 388: 1063, 1063, 1063, 1063, 1063, 396: 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 408: 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 432: 1063, 1063, 1063, 1063, 1063, 1063, 439: 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 448: 1063, 1063, 521: 1063},\n\t\t{1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 363: 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 374: 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 385: 1062, 1062, 388: 1062, 1062, 1062, 1062, 1062, 396: 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 408: 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 432: 1062, 1062, 1062, 1062, 1062, 1062, 439: 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 448: 1062, 1062, 521: 1062},\n\t\t{1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 363: 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 374: 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 385: 1061, 1061, 388: 1061, 1061, 1061, 1061, 1061, 396: 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 408: 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 432: 1061, 1061, 1061, 1061, 1061, 1061, 439: 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061, 448: 1061, 1061, 521: 1061},\n\t\t{1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 363: 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 374: 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 385: 1059, 1059, 388: 1059, 1059, 1059, 1059, 1059, 396: 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 408: 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 432: 1059, 1059, 1059, 1059, 1059, 1059, 439: 1059, 1059, 1059, 1059, 1059, 1059, 1059, 1059, 448: 1059, 1059, 521: 1059},\n\t\t{1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 363: 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 374: 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 385: 1058, 1058, 388: 1058, 1058, 1058, 1058, 1058, 396: 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 408: 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 432: 1058, 1058, 1058, 1058, 1058, 1058, 439: 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 448: 1058, 1058, 521: 1058},\n\t\t// 640\n\t\t{1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 363: 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 374: 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 385: 1057, 1057, 388: 1057, 1057, 1057, 1057, 1057, 396: 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 408: 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 432: 1057, 1057, 1057, 1057, 1057, 1057, 439: 1057, 1057, 1057, 1057, 1057, 1057, 1057, 1057, 448: 1057, 1057, 521: 1057},\n\t\t{1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 363: 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 374: 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 385: 1056, 1056, 388: 1056, 1056, 1056, 1056, 1056, 396: 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 408: 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 432: 1056, 1056, 1056, 1056, 1056, 1056, 439: 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 448: 1056, 1056, 521: 1056},\n\t\t{1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 363: 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 374: 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 385: 1055, 1055, 388: 1055, 1055, 1055, 1055, 1055, 396: 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 408: 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 432: 1055, 1055, 1055, 1055, 1055, 1055, 439: 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1055, 448: 1055, 1055, 521: 1055},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 3262, 2665, 2744, 2664, 2661},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 3261, 2665, 2744, 2664, 2661},\n\t\t// 645\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 3260, 2665, 2744, 2664, 2661},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 3259, 2665, 2744, 2664, 2661},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 3258, 2665, 2744, 2664, 2661},\n\t\t{1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 363: 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 374: 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 385: 1048, 1048, 388: 1048, 1048, 1048, 1048, 1048, 396: 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 408: 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 432: 1048, 1048, 1048, 1048, 1048, 1048, 439: 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 448: 1048, 1048, 521: 1048},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 3251, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 2053, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3249, 606: 3237, 2054, 2055, 2056, 613: 2059, 2058, 3238, 628: 3250},\n\t\t// 650\n\t\t{362: 3244},\n\t\t{362: 3236, 574: 3235},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 3234, 2665, 2744, 2664, 2661},\n\t\t{362: 3229},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 424: 884, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3216, 968: 3217},\n\t\t// 655\n\t\t{362: 3160},\n\t\t{362: 3157},\n\t\t{362: 1019},\n\t\t{362: 1016},\n\t\t{362: 1015},\n\t\t// 660\n\t\t{362: 1013},\n\t\t{362: 1009},\n\t\t{362: 1007},\n\t\t{362: 1006},\n\t\t{362: 1004},\n\t\t// 665\n\t\t{993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 374: 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 385: 993, 993, 388: 993, 993, 993, 993, 993, 396: 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 408: 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 993, 432: 993, 993, 993, 993, 993, 993, 439: 993, 993, 993, 993, 993, 993, 993, 993, 448: 993, 993, 521: 993},\n\t\t{992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 374: 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 385: 992, 992, 388: 992, 992, 992, 992, 992, 396: 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 408: 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 992, 432: 992, 992, 992, 992, 992, 992, 439: 992, 992, 992, 992, 992, 992, 992, 992, 448: 992, 992, 521: 992},\n\t\t{991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 374: 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 385: 991, 991, 388: 991, 991, 991, 991, 991, 396: 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 408: 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 991, 432: 991, 991, 991, 991, 991, 991, 439: 991, 991, 991, 991, 991, 991, 991, 991, 448: 991, 991, 521: 991},\n\t\t{990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 374: 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 385: 990, 990, 388: 990, 990, 990, 990, 990, 396: 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 408: 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 990, 432: 990, 990, 990, 990, 990, 990, 439: 990, 990, 990, 990, 990, 990, 990, 990, 448: 990, 990, 521: 990},\n\t\t{989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 374: 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 385: 989, 989, 388: 989, 989, 989, 989, 989, 396: 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 408: 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 989, 432: 989, 989, 989, 989, 989, 989, 439: 989, 989, 989, 989, 989, 989, 989, 989, 448: 989, 989, 521: 989},\n\t\t// 670\n\t\t{988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 374: 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 385: 988, 988, 388: 988, 988, 988, 988, 988, 396: 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 408: 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 988, 432: 988, 988, 988, 988, 988, 988, 439: 988, 988, 988, 988, 988, 988, 988, 988, 448: 988, 988, 521: 988},\n\t\t{987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 374: 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 385: 987, 987, 388: 987, 987, 987, 987, 987, 396: 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 408: 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 432: 987, 987, 987, 987, 987, 987, 439: 987, 987, 987, 987, 987, 987, 987, 987, 448: 987, 987, 521: 987},\n\t\t{986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 374: 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 385: 986, 986, 388: 986, 986, 986, 986, 986, 396: 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 408: 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 986, 432: 986, 986, 986, 986, 986, 986, 439: 986, 986, 986, 986, 986, 986, 986, 986, 448: 986, 986, 521: 986},\n\t\t{985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 374: 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 385: 985, 985, 388: 985, 985, 985, 985, 985, 396: 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 408: 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 985, 432: 985, 985, 985, 985, 985, 985, 439: 985, 985, 985, 985, 985, 985, 985, 985, 448: 985, 985, 521: 985},\n\t\t{984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 374: 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 385: 984, 984, 388: 984, 984, 984, 984, 984, 396: 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 408: 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, 432: 984, 984, 984, 984, 984, 984, 439: 984, 984, 984, 984, 984, 984, 984, 984, 448: 984, 984, 521: 984},\n\t\t// 675\n\t\t{362: 3154},\n\t\t{362: 3151},\n\t\t{995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 3148, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 374: 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 385: 995, 995, 388: 995, 995, 995, 995, 995, 396: 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 408: 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 432: 995, 995, 995, 995, 995, 995, 439: 995, 995, 995, 995, 995, 995, 995, 995, 448: 995, 995, 521: 995, 871: 3149},\n\t\t{362: 3146},\n\t\t{916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 3142, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 374: 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 385: 916, 916, 388: 916, 916, 916, 916, 916, 396: 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 408: 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 916, 432: 916, 916, 916, 916, 916, 916, 439: 916, 916, 916, 916, 916, 916, 916, 916, 448: 916, 916, 521: 916, 974: 3141},\n\t\t// 680\n\t\t{362: 3135},\n\t\t{362: 3131},\n\t\t{362: 3126},\n\t\t{862: 3123, 3120, 3122, 3121},\n\t\t{362: 3117},\n\t\t// 685\n\t\t{362: 3112},\n\t\t{362: 3103},\n\t\t{362: 3096},\n\t\t{362: 3091},\n\t\t{362: 3056},\n\t\t// 690\n\t\t{362: 3042},\n\t\t{362: 3025},\n\t\t{362: 947},\n\t\t{362: 946},\n\t\t{362: 945},\n\t\t// 695\n\t\t{362: 944},\n\t\t{362: 3017},\n\t\t{362: 3009},\n\t\t{362: 3001},\n\t\t{362: 2987},\n\t\t// 700\n\t\t{362: 2975},\n\t\t{362: 2970},\n\t\t{362: 2965},\n\t\t{362: 2959},\n\t\t{362: 2954},\n\t\t// 705\n\t\t{362: 2949},\n\t\t{362: 2944},\n\t\t{362: 2939},\n\t\t{362: 2933},\n\t\t{362: 2922},\n\t\t// 710\n\t\t{362: 2919},\n\t\t{362: 2916},\n\t\t{362: 2913},\n\t\t{362: 2910},\n\t\t{362: 2907},\n\t\t// 715\n\t\t{362: 2903},\n\t\t{362: 2897},\n\t\t{362: 2884},\n\t\t{362: 2879},\n\t\t{362: 2874},\n\t\t// 720\n\t\t{362: 2748},\n\t\t{621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 363: 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 374: 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 385: 621, 621, 388: 621, 621, 621, 621, 621, 396: 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 408: 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, 432: 621, 621, 621, 621, 621, 621, 439: 621, 621, 621, 621, 621, 621, 621, 621, 448: 621, 621, 521: 621},\n\t\t{620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 363: 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 374: 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 385: 620, 620, 388: 620, 620, 620, 620, 620, 396: 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 408: 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, 432: 620, 620, 620, 620, 620, 620, 439: 620, 620, 620, 620, 620, 620, 620, 620, 448: 620, 620, 521: 620},\n\t\t{619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 363: 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 374: 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 385: 619, 619, 388: 619, 619, 619, 619, 619, 396: 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 408: 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 432: 619, 619, 619, 619, 619, 619, 439: 619, 619, 619, 619, 619, 619, 619, 619, 448: 619, 619, 521: 619},\n\t\t{55, 55, 9: 55},\n\t\t// 725\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2749},\n\t\t{9: 2761, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{362: 2751},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 407: 2604, 537: 2603, 2178, 2179, 2177, 576: 2752},\n\t\t{361: 2753},\n\t\t// 730\n\t\t{1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 363: 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 374: 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 385: 1038, 1038, 388: 1038, 1038, 1038, 1038, 1038, 396: 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 408: 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 432: 1038, 1038, 1038, 1038, 1038, 1038, 439: 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 448: 1038, 1038, 521: 1038},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2873},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2872},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2871},\n\t\t{2: 1594, 1594, 1594, 1594, 1594, 1594, 1594, 10: 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 362: 1594, 1594, 366: 1594, 1594, 369: 1594, 1594, 1594, 1594, 1594, 384: 1594, 387: 1594, 393: 1594, 1594, 407: 1594, 431: 1594, 438: 1594, 447: 1594, 450: 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 523: 1594},\n\t\t// 735\n\t\t{2: 1593, 1593, 1593, 1593, 1593, 1593, 1593, 10: 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 362: 1593, 1593, 366: 1593, 1593, 369: 1593, 1593, 1593, 1593, 1593, 384: 1593, 387: 1593, 393: 1593, 1593, 407: 1593, 431: 1593, 438: 1593, 447: 1593, 450: 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 523: 1593},\n\t\t{2: 1592, 1592, 1592, 1592, 1592, 1592, 1592, 10: 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 362: 1592, 1592, 366: 1592, 1592, 369: 1592, 1592, 1592, 1592, 1592, 384: 1592, 387: 1592, 393: 1592, 1592, 407: 1592, 431: 1592, 438: 1592, 447: 1592, 450: 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 523: 1592},\n\t\t{2: 1591, 1591, 1591, 1591, 1591, 1591, 1591, 10: 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 362: 1591, 1591, 366: 1591, 1591, 369: 1591, 1591, 1591, 1591, 1591, 384: 1591, 387: 1591, 393: 1591, 1591, 407: 1591, 431: 1591, 438: 1591, 447: 1591, 450: 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 523: 1591},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2762, 2665, 2744, 2664, 2661},\n\t\t{361: 2766, 376: 2764, 521: 2765},\n\t\t// 740\n\t\t{618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 363: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 374: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 385: 618, 618, 388: 618, 618, 618, 618, 618, 396: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 408: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 432: 618, 618, 618, 618, 618, 618, 439: 618, 618, 618, 618, 618, 618, 618, 618, 448: 618, 618, 521: 618},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 2870},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2869, 2665, 2744, 2664, 2661},\n\t\t{86: 774, 390: 2768, 522: 774, 604: 774, 1007: 2767},\n\t\t{86: 2772, 522: 2773, 604: 777, 708: 2771},\n\t\t// 745\n\t\t{31: 2769, 244: 2770},\n\t\t{86: 773, 522: 773, 604: 773},\n\t\t{86: 772, 522: 772, 604: 772},\n\t\t{604: 2776, 610: 2777},\n\t\t{175: 2775},\n\t\t// 750\n\t\t{175: 2774},\n\t\t{604: 775},\n\t\t{604: 776},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 2779, 537: 2778, 2178, 2179, 2177, 740: 2781, 931: 2782, 1089: 2780},\n\t\t{783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 363: 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 374: 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 385: 783, 783, 388: 783, 783, 783, 783, 783, 396: 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 408: 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 432: 783, 783, 783, 783, 783, 783, 439: 783, 783, 783, 783, 783, 783, 783, 783, 448: 783, 783, 521: 783},\n\t\t// 755\n\t\t{825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 363: 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 374: 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 385: 825, 825, 388: 825, 825, 825, 825, 825, 395: 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 408: 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, 432: 825, 825, 825, 825, 825, 825, 439: 825, 825, 825, 825, 825, 825, 825, 825, 448: 825, 825, 521: 825},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 822, 378: 822, 395: 822, 408: 822, 822, 822, 537: 2778, 2178, 2179, 2177, 740: 2785, 1006: 2784, 1090: 2783},\n\t\t{796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 363: 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 374: 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 385: 796, 796, 388: 796, 796, 796, 796, 796, 396: 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 408: 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 432: 796, 796, 796, 796, 796, 796, 439: 796, 796, 796, 796, 796, 796, 796, 796, 448: 796, 796, 521: 796},\n\t\t{795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 363: 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 374: 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 385: 795, 795, 388: 795, 795, 795, 795, 795, 396: 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 408: 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 795, 432: 795, 795, 795, 795, 795, 795, 439: 795, 795, 795, 795, 795, 795, 795, 795, 448: 795, 795, 521: 795},\n\t\t{794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 363: 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 374: 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 385: 794, 794, 388: 794, 794, 794, 794, 794, 396: 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 408: 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 432: 794, 794, 794, 794, 794, 794, 439: 794, 794, 794, 794, 794, 794, 794, 794, 448: 794, 794, 521: 794},\n\t\t// 760\n\t\t{361: 2868},\n\t\t{361: 820, 378: 820, 395: 2787, 408: 820, 820, 820, 1009: 2786},\n\t\t{361: 821, 378: 821, 395: 821, 408: 821, 821, 821},\n\t\t{361: 818, 378: 2798, 408: 818, 818, 818, 1012: 2797},\n\t\t{546: 2788},\n\t\t// 765\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2789, 699: 2790, 716: 2791},\n\t\t{1089, 1089, 9: 1089, 58: 1089, 361: 1089, 364: 1089, 1089, 368: 1089, 375: 1089, 377: 1089, 1089, 1089, 1089, 1089, 2760, 385: 2758, 2759, 388: 2757, 2755, 397: 1089, 1089, 408: 1089, 1089, 1089, 2796, 2795, 596: 2756, 2754, 731: 2794},\n\t\t{1092, 1092, 9: 1092, 58: 1092, 361: 1092, 364: 1092, 1092, 368: 1092, 375: 1092, 377: 1092, 1092, 1092, 1092, 1092, 397: 1092, 1092, 408: 1092, 1092, 1092},\n\t\t{9: 2792, 361: 819, 378: 819, 408: 819, 819, 819},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2789, 699: 2793},\n\t\t// 770\n\t\t{1091, 1091, 9: 1091, 58: 1091, 361: 1091, 364: 1091, 1091, 368: 1091, 375: 1091, 377: 1091, 1091, 1091, 1091, 1091, 397: 1091, 1091, 408: 1091, 1091, 1091},\n\t\t{1090, 1090, 9: 1090, 58: 1090, 361: 1090, 364: 1090, 1090, 368: 1090, 375: 1090, 377: 1090, 1090, 1090, 1090, 1090, 397: 1090, 1090, 408: 1090, 1090, 1090},\n\t\t{1088, 1088, 1088, 9: 1088, 58: 1088, 361: 1088, 364: 1088, 1088, 368: 1088, 375: 1088, 377: 1088, 1088, 1088, 1088, 1088, 395: 1088, 397: 1088, 1088, 408: 1088, 1088, 1088},\n\t\t{1087, 1087, 1087, 9: 1087, 58: 1087, 361: 1087, 364: 1087, 1087, 368: 1087, 375: 1087, 377: 1087, 1087, 1087, 1087, 1087, 395: 1087, 397: 1087, 1087, 408: 1087, 1087, 1087},\n\t\t{361: 816, 408: 2804, 2805, 2803, 1011: 2801, 1088: 2802},\n\t\t// 775\n\t\t{546: 2799},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2789, 699: 2790, 716: 2800},\n\t\t{9: 2792, 361: 817, 408: 817, 817, 817},\n\t\t{361: 823},\n\t\t{88: 2816, 94: 2812, 393: 2806, 437: 2817, 453: 2808, 2807, 2656, 2815, 573: 2814, 690: 2813, 776: 2810, 1086: 2811, 2809},\n\t\t// 780\n\t\t{88: 814, 94: 814, 393: 814, 437: 814, 453: 814, 814, 814, 814},\n\t\t{88: 813, 94: 813, 393: 813, 437: 813, 453: 813, 813, 813, 813},\n\t\t{88: 812, 94: 812, 393: 812, 437: 812, 453: 812, 812, 812, 812},\n\t\t{1774, 1774, 1774, 1774, 1774, 1774, 9: 1774, 31: 1774, 1774, 1774, 1774, 1774, 61: 1774, 89: 1774, 361: 1774, 364: 1774, 369: 1774, 373: 1774, 1774, 376: 1774, 394: 1774, 1774, 527: 1774, 1774, 1774, 533: 1774, 1774, 1774, 1774},\n\t\t{1773, 1773, 1773, 1773, 1773, 1773, 9: 1773, 31: 1773, 1773, 1773, 1773, 1773, 61: 1773, 89: 1773, 361: 1773, 364: 1773, 369: 1773, 373: 1773, 1773, 376: 1773, 394: 1773, 1773, 527: 1773, 1773, 1773, 533: 1773, 1773, 1773, 1773},\n\t\t// 785\n\t\t{1772, 1772, 1772, 1772, 1772, 1772, 9: 1772, 31: 1772, 1772, 1772, 1772, 1772, 61: 1772, 89: 1772, 361: 1772, 364: 1772, 369: 1772, 373: 1772, 1772, 376: 1772, 394: 1772, 1772, 527: 1772, 1772, 1772, 533: 1772, 1772, 1772, 1772},\n\t\t{361: 815},\n\t\t{361: 811},\n\t\t{361: 810},\n\t\t{61: 2863},\n\t\t// 790\n\t\t{61: 2861},\n\t\t{61: 2859},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2866},\n\t\t{471: 2865},\n\t\t{88: 2816, 94: 2818, 393: 2806, 453: 2808, 2807, 2656, 2821, 573: 2820, 690: 2819, 776: 2823, 930: 2822},\n\t\t// 795\n\t\t{61: 2863, 89: 2864},\n\t\t{61: 2861, 89: 2862},\n\t\t{61: 2859, 89: 2860},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2826},\n\t\t{382: 2824},\n\t\t// 800\n\t\t{361: 803, 382: 803},\n\t\t{88: 2816, 94: 2818, 393: 2806, 453: 2808, 2807, 2656, 2821, 573: 2820, 690: 2819, 776: 2823, 930: 2825},\n\t\t{361: 804},\n\t\t{62: 2843, 2842, 2839, 2841, 2845, 2846, 2840, 2851, 2850, 2849, 2853, 2854, 2848, 2852, 2855, 2844, 2847, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 413: 2837, 2834, 2836, 2835, 2831, 2833, 2832, 2829, 2830, 2828, 2838, 596: 2756, 2754, 652: 2827, 669: 2856},\n\t\t{913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 374: 913, 913, 377: 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 388: 913, 913, 913, 913, 913, 396: 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 408: 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 913, 432: 913, 913, 913, 913, 913, 913, 439: 913, 913, 913, 913, 913, 913, 913, 913, 448: 913, 913, 522: 913, 524: 913},\n\t\t// 805\n\t\t{912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 374: 912, 912, 377: 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 388: 912, 912, 912, 912, 912, 396: 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 408: 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 912, 432: 912, 912, 912, 912, 912, 912, 439: 912, 912, 912, 912, 912, 912, 912, 912, 448: 912, 912, 522: 912, 524: 912},\n\t\t{911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 374: 911, 911, 377: 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 388: 911, 911, 911, 911, 911, 396: 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 408: 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 911, 432: 911, 911, 911, 911, 911, 911, 439: 911, 911, 911, 911, 911, 911, 911, 911, 448: 911, 911, 522: 911, 524: 911},\n\t\t{910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 374: 910, 910, 377: 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 388: 910, 910, 910, 910, 910, 396: 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 408: 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 910, 432: 910, 910, 910, 910, 910, 910, 439: 910, 910, 910, 910, 910, 910, 910, 910, 448: 910, 910, 522: 910, 524: 910},\n\t\t{909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 374: 909, 909, 377: 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 388: 909, 909, 909, 909, 909, 396: 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 408: 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 909, 432: 909, 909, 909, 909, 909, 909, 439: 909, 909, 909, 909, 909, 909, 909, 909, 448: 909, 909, 522: 909, 524: 909},\n\t\t{908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 374: 908, 908, 377: 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 388: 908, 908, 908, 908, 908, 396: 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 408: 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 908, 432: 908, 908, 908, 908, 908, 908, 439: 908, 908, 908, 908, 908, 908, 908, 908, 448: 908, 908, 522: 908, 524: 908},\n\t\t// 810\n\t\t{907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 374: 907, 907, 377: 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 388: 907, 907, 907, 907, 907, 396: 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 408: 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 432: 907, 907, 907, 907, 907, 907, 439: 907, 907, 907, 907, 907, 907, 907, 907, 448: 907, 907, 522: 907, 524: 907},\n\t\t{906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 374: 906, 906, 377: 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 388: 906, 906, 906, 906, 906, 396: 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 408: 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 906, 432: 906, 906, 906, 906, 906, 906, 439: 906, 906, 906, 906, 906, 906, 906, 906, 448: 906, 906, 522: 906, 524: 906},\n\t\t{905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 374: 905, 905, 377: 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 388: 905, 905, 905, 905, 905, 396: 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 408: 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 905, 432: 905, 905, 905, 905, 905, 905, 439: 905, 905, 905, 905, 905, 905, 905, 905, 448: 905, 905, 522: 905, 524: 905},\n\t\t{904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 374: 904, 904, 377: 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 388: 904, 904, 904, 904, 904, 396: 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 408: 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 904, 432: 904, 904, 904, 904, 904, 904, 439: 904, 904, 904, 904, 904, 904, 904, 904, 448: 904, 904, 522: 904, 524: 904},\n\t\t{903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 374: 903, 903, 377: 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 388: 903, 903, 903, 903, 903, 396: 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 408: 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 903, 432: 903, 903, 903, 903, 903, 903, 439: 903, 903, 903, 903, 903, 903, 903, 903, 448: 903, 903, 522: 903, 524: 903},\n\t\t// 815\n\t\t{902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 374: 902, 902, 377: 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 388: 902, 902, 902, 902, 902, 396: 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 408: 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 902, 432: 902, 902, 902, 902, 902, 902, 439: 902, 902, 902, 902, 902, 902, 902, 902, 448: 902, 902, 522: 902, 524: 902},\n\t\t{901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 374: 901, 901, 377: 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 388: 901, 901, 901, 901, 901, 396: 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 408: 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 901, 432: 901, 901, 901, 901, 901, 901, 439: 901, 901, 901, 901, 901, 901, 901, 901, 448: 901, 901, 522: 901, 524: 901},\n\t\t{900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 374: 900, 900, 377: 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 388: 900, 900, 900, 900, 900, 396: 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 408: 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 432: 900, 900, 900, 900, 900, 900, 439: 900, 900, 900, 900, 900, 900, 900, 900, 448: 900, 900, 522: 900, 524: 900},\n\t\t{899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 374: 899, 899, 377: 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 388: 899, 899, 899, 899, 899, 396: 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 408: 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 432: 899, 899, 899, 899, 899, 899, 439: 899, 899, 899, 899, 899, 899, 899, 899, 448: 899, 899, 522: 899, 524: 899},\n\t\t{898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 374: 898, 898, 377: 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 388: 898, 898, 898, 898, 898, 396: 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 408: 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 432: 898, 898, 898, 898, 898, 898, 439: 898, 898, 898, 898, 898, 898, 898, 898, 448: 898, 898, 522: 898, 524: 898},\n\t\t// 820\n\t\t{897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 374: 897, 897, 377: 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 388: 897, 897, 897, 897, 897, 396: 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 408: 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 432: 897, 897, 897, 897, 897, 897, 439: 897, 897, 897, 897, 897, 897, 897, 897, 448: 897, 897, 522: 897, 524: 897},\n\t\t{896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 374: 896, 896, 377: 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 388: 896, 896, 896, 896, 896, 396: 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 408: 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 432: 896, 896, 896, 896, 896, 896, 439: 896, 896, 896, 896, 896, 896, 896, 896, 448: 896, 896, 522: 896, 524: 896},\n\t\t{895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 374: 895, 895, 377: 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 388: 895, 895, 895, 895, 895, 396: 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 408: 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 895, 432: 895, 895, 895, 895, 895, 895, 439: 895, 895, 895, 895, 895, 895, 895, 895, 448: 895, 895, 522: 895, 524: 895},\n\t\t{894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 374: 894, 894, 377: 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 388: 894, 894, 894, 894, 894, 396: 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 408: 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 894, 432: 894, 894, 894, 894, 894, 894, 439: 894, 894, 894, 894, 894, 894, 894, 894, 448: 894, 894, 522: 894, 524: 894},\n\t\t{893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 374: 893, 893, 377: 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 388: 893, 893, 893, 893, 893, 396: 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 408: 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 893, 432: 893, 893, 893, 893, 893, 893, 439: 893, 893, 893, 893, 893, 893, 893, 893, 448: 893, 893, 522: 893, 524: 893},\n\t\t// 825\n\t\t{892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 374: 892, 892, 377: 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 388: 892, 892, 892, 892, 892, 396: 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 408: 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, 432: 892, 892, 892, 892, 892, 892, 439: 892, 892, 892, 892, 892, 892, 892, 892, 448: 892, 892, 522: 892, 524: 892},\n\t\t{891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 374: 891, 891, 377: 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 388: 891, 891, 891, 891, 891, 396: 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 408: 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 432: 891, 891, 891, 891, 891, 891, 439: 891, 891, 891, 891, 891, 891, 891, 891, 448: 891, 891, 522: 891, 524: 891},\n\t\t{890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 374: 890, 890, 377: 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 388: 890, 890, 890, 890, 890, 396: 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 408: 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 432: 890, 890, 890, 890, 890, 890, 439: 890, 890, 890, 890, 890, 890, 890, 890, 448: 890, 890, 522: 890, 524: 890},\n\t\t{889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 374: 889, 889, 377: 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 388: 889, 889, 889, 889, 889, 396: 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 408: 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 889, 432: 889, 889, 889, 889, 889, 889, 439: 889, 889, 889, 889, 889, 889, 889, 889, 448: 889, 889, 522: 889, 524: 889},\n\t\t{888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 374: 888, 888, 377: 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 388: 888, 888, 888, 888, 888, 396: 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 408: 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 888, 432: 888, 888, 888, 888, 888, 888, 439: 888, 888, 888, 888, 888, 888, 888, 888, 448: 888, 888, 522: 888, 524: 888},\n\t\t// 830\n\t\t{887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 374: 887, 887, 377: 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 388: 887, 887, 887, 887, 887, 396: 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 408: 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 887, 432: 887, 887, 887, 887, 887, 887, 439: 887, 887, 887, 887, 887, 887, 887, 887, 448: 887, 887, 522: 887, 524: 887},\n\t\t{886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 374: 886, 886, 377: 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 388: 886, 886, 886, 886, 886, 396: 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 408: 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 886, 432: 886, 886, 886, 886, 886, 886, 439: 886, 886, 886, 886, 886, 886, 886, 886, 448: 886, 886, 522: 886, 524: 886},\n\t\t{885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 374: 885, 885, 377: 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 388: 885, 885, 885, 885, 885, 396: 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 408: 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 432: 885, 885, 885, 885, 885, 885, 439: 885, 885, 885, 885, 885, 885, 885, 885, 448: 885, 885, 522: 885, 524: 885},\n\t\t{61: 2857, 89: 2858},\n\t\t{361: 806, 382: 806},\n\t\t// 835\n\t\t{361: 799, 382: 799},\n\t\t{361: 807, 382: 807},\n\t\t{361: 800, 382: 800},\n\t\t{361: 808, 382: 808},\n\t\t{361: 801, 382: 801},\n\t\t// 840\n\t\t{361: 809, 382: 809},\n\t\t{361: 802, 382: 802},\n\t\t{361: 805, 382: 805},\n\t\t{62: 2843, 2842, 2839, 2841, 2845, 2846, 2840, 2851, 2850, 2849, 2853, 2854, 2848, 2852, 2855, 2844, 2847, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 413: 2837, 2834, 2836, 2835, 2831, 2833, 2832, 2829, 2830, 2828, 2838, 596: 2756, 2754, 652: 2827, 669: 2867},\n\t\t{61: 2857},\n\t\t// 845\n\t\t{824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 363: 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 374: 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 385: 824, 824, 388: 824, 824, 824, 824, 824, 396: 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 408: 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 432: 824, 824, 824, 824, 824, 824, 439: 824, 824, 824, 824, 824, 824, 824, 824, 448: 824, 824, 521: 824},\n\t\t{1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 363: 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 374: 1050, 1050, 2764, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 385: 1050, 1050, 388: 1050, 1050, 1050, 1050, 1050, 396: 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 408: 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 432: 1050, 1050, 1050, 1050, 1050, 1050, 439: 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 448: 1050, 1050, 521: 1050},\n\t\t{1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 363: 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 374: 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 385: 1060, 1060, 388: 1060, 1060, 1060, 1060, 1060, 396: 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 408: 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 432: 1060, 1060, 1060, 1060, 1060, 1060, 439: 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 448: 1060, 1060, 521: 1060},\n\t\t{1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 363: 1608, 1608, 1608, 1608, 1608, 1608, 374: 1608, 1608, 377: 1608, 1608, 1608, 1608, 1608, 1608, 1608, 385: 1608, 1608, 388: 1608, 1608, 1608, 392: 1608, 396: 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 408: 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 426: 1608, 1608, 596: 2756, 2754},\n\t\t{1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 363: 1609, 1609, 1609, 1609, 1609, 1609, 374: 1609, 1609, 377: 1609, 1609, 1609, 1609, 1609, 2760, 1609, 385: 1609, 2759, 388: 1609, 1609, 1609, 392: 1609, 396: 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 408: 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609, 426: 1609, 1609, 596: 2756, 2754},\n\t\t// 850\n\t\t{1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 363: 1610, 1610, 1610, 1610, 1610, 1610, 374: 1610, 1610, 377: 1610, 1610, 1610, 1610, 1610, 2760, 1610, 385: 1610, 2759, 388: 1610, 2755, 1610, 392: 1610, 396: 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 408: 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 426: 1610, 1610, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2875},\n\t\t{361: 2876, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{86: 2772, 522: 2773, 604: 777, 708: 2877},\n\t\t{604: 2776, 610: 2878},\n\t\t// 855\n\t\t{784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 363: 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 374: 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 385: 784, 784, 388: 784, 784, 784, 784, 784, 396: 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 408: 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 432: 784, 784, 784, 784, 784, 784, 439: 784, 784, 784, 784, 784, 784, 784, 784, 448: 784, 784, 521: 784},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2880},\n\t\t{361: 2881, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{86: 2772, 522: 2773, 604: 777, 708: 2882},\n\t\t{604: 2776, 610: 2883},\n\t\t// 860\n\t\t{785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 363: 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 374: 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 385: 785, 785, 388: 785, 785, 785, 785, 785, 396: 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 408: 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 785, 432: 785, 785, 785, 785, 785, 785, 439: 785, 785, 785, 785, 785, 785, 785, 785, 448: 785, 785, 521: 785},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2885},\n\t\t{9: 2887, 361: 782, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754, 872: 2886},\n\t\t{361: 2894},\n\t\t{393: 2806, 453: 2808, 2807, 2656, 573: 2889, 690: 2888},\n\t\t// 865\n\t\t{9: 2891, 361: 779, 873: 2893},\n\t\t{9: 2891, 361: 779, 873: 2890},\n\t\t{361: 780},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2892},\n\t\t{361: 778, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 870\n\t\t{361: 781},\n\t\t{86: 2772, 522: 2773, 604: 777, 708: 2895},\n\t\t{604: 2776, 610: 2896},\n\t\t{786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 363: 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 374: 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 385: 786, 786, 388: 786, 786, 786, 786, 786, 396: 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 408: 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 786, 432: 786, 786, 786, 786, 786, 786, 439: 786, 786, 786, 786, 786, 786, 786, 786, 448: 786, 786, 521: 786},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2898},\n\t\t// 875\n\t\t{9: 2887, 361: 782, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754, 872: 2899},\n\t\t{361: 2900},\n\t\t{86: 2772, 522: 2773, 604: 777, 708: 2901},\n\t\t{604: 2776, 610: 2902},\n\t\t{787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 363: 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 374: 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 385: 787, 787, 388: 787, 787, 787, 787, 787, 396: 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 408: 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 787, 432: 787, 787, 787, 787, 787, 787, 439: 787, 787, 787, 787, 787, 787, 787, 787, 448: 787, 787, 521: 787},\n\t\t// 880\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2904, 2665, 2744, 2664, 2661},\n\t\t{361: 2905, 376: 2764, 521: 2765},\n\t\t{604: 2776, 610: 2906},\n\t\t{788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 363: 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 374: 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 385: 788, 788, 388: 788, 788, 788, 788, 788, 396: 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 408: 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 432: 788, 788, 788, 788, 788, 788, 439: 788, 788, 788, 788, 788, 788, 788, 788, 448: 788, 788, 521: 788},\n\t\t{361: 2908},\n\t\t// 885\n\t\t{604: 2776, 610: 2909},\n\t\t{789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 363: 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 374: 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 385: 789, 789, 388: 789, 789, 789, 789, 789, 396: 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 408: 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 432: 789, 789, 789, 789, 789, 789, 439: 789, 789, 789, 789, 789, 789, 789, 789, 448: 789, 789, 521: 789},\n\t\t{361: 2911},\n\t\t{604: 2776, 610: 2912},\n\t\t{790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 363: 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 374: 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 385: 790, 790, 388: 790, 790, 790, 790, 790, 396: 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 408: 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 432: 790, 790, 790, 790, 790, 790, 439: 790, 790, 790, 790, 790, 790, 790, 790, 448: 790, 790, 521: 790},\n\t\t// 890\n\t\t{361: 2914},\n\t\t{604: 2776, 610: 2915},\n\t\t{791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 363: 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 374: 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 385: 791, 791, 388: 791, 791, 791, 791, 791, 396: 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 408: 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 432: 791, 791, 791, 791, 791, 791, 439: 791, 791, 791, 791, 791, 791, 791, 791, 448: 791, 791, 521: 791},\n\t\t{361: 2917},\n\t\t{604: 2776, 610: 2918},\n\t\t// 895\n\t\t{792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 363: 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 374: 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 385: 792, 792, 388: 792, 792, 792, 792, 792, 396: 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 408: 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 792, 432: 792, 792, 792, 792, 792, 792, 439: 792, 792, 792, 792, 792, 792, 792, 792, 448: 792, 792, 521: 792},\n\t\t{361: 2920},\n\t\t{604: 2776, 610: 2921},\n\t\t{793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 363: 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 374: 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 385: 793, 793, 388: 793, 793, 793, 793, 793, 396: 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 408: 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 793, 432: 793, 793, 793, 793, 793, 793, 439: 793, 793, 793, 793, 793, 793, 793, 793, 448: 793, 793, 521: 793},\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 407: 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 621: 2923, 2924, 630: 2926, 638: 2927, 2928, 647: 2929},\n\t\t// 900\n\t\t{2: 1034, 1034, 1034, 1034, 1034, 1034, 1034, 10: 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 362: 1034, 1034, 366: 1034, 1034, 369: 1034, 1034, 1034, 1034, 1034, 384: 1034, 387: 1034, 393: 1034, 1034, 396: 1034, 406: 1034, 1034, 431: 1034, 438: 1034, 447: 1034, 450: 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 523: 1034, 1034, 600: 1034, 612: 1034, 620: 1034, 623: 1034, 1034, 1034, 635: 1034},\n\t\t{2: 1033, 1033, 1033, 1033, 1033, 1033, 1033, 10: 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 362: 1033, 1033, 366: 1033, 1033, 369: 1033, 1033, 1033, 1033, 1033, 384: 1033, 387: 1033, 393: 1033, 1033, 396: 1033, 406: 1033, 1033, 431: 1033, 438: 1033, 447: 1033, 450: 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 1033, 523: 1033, 1033, 600: 1033, 612: 1033, 620: 1033, 623: 1033, 1033, 1033, 635: 1033},\n\t\t{2: 1032, 1032, 1032, 1032, 1032, 1032, 1032, 10: 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 362: 1032, 1032, 366: 1032, 1032, 369: 1032, 1032, 1032, 1032, 1032, 384: 1032, 387: 1032, 393: 1032, 1032, 396: 1032, 406: 1032, 1032, 431: 1032, 438: 1032, 447: 1032, 450: 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 523: 1032, 1032, 612: 1032, 620: 1032, 623: 1032, 1032, 1032, 635: 1032},\n\t\t{2: 1031, 1031, 1031, 1031, 1031, 1031, 1031, 10: 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 362: 1031, 1031, 366: 1031, 1031, 369: 1031, 1031, 1031, 1031, 1031, 384: 1031, 387: 1031, 393: 1031, 1031, 407: 1031, 431: 1031, 438: 1031, 447: 1031, 450: 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 523: 1031, 600: 2932},\n\t\t{2: 1029, 1029, 1029, 1029, 1029, 1029, 1029, 10: 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 362: 1029, 1029, 366: 1029, 1029, 369: 1029, 1029, 1029, 1029, 1029, 384: 1029, 387: 1029, 393: 1029, 1029, 396: 1029, 406: 1029, 1029, 431: 1029, 438: 1029, 447: 1029, 450: 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 523: 1029, 612: 1029, 620: 1029, 623: 1029, 1029, 1029, 635: 1029},\n\t\t// 905\n\t\t{2: 1026, 1026, 1026, 1026, 1026, 1026, 1026, 10: 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 362: 1026, 1026, 366: 1026, 1026, 369: 1026, 1026, 1026, 1026, 1026, 384: 1026, 387: 1026, 393: 1026, 1026, 407: 1026, 431: 1026, 438: 1026, 447: 1026, 450: 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 523: 1026},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2930},\n\t\t{361: 2931, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 363: 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 374: 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 385: 920, 920, 388: 920, 920, 920, 920, 920, 396: 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 408: 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 920, 432: 920, 920, 920, 920, 920, 920, 439: 920, 920, 920, 920, 920, 920, 920, 920, 448: 920, 920, 521: 920},\n\t\t{2: 1025, 1025, 1025, 1025, 1025, 1025, 1025, 10: 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 362: 1025, 1025, 366: 1025, 1025, 369: 1025, 1025, 1025, 1025, 1025, 384: 1025, 387: 1025, 393: 1025, 1025, 407: 1025, 431: 1025, 438: 1025, 447: 1025, 450: 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 523: 1025},\n\t\t// 910\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 407: 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 621: 2923, 2924, 630: 2926, 638: 2927, 2928, 647: 2934},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2935},\n\t\t{361: 2936, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 2937},\n\t\t{921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 363: 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 374: 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 385: 921, 921, 388: 921, 921, 921, 921, 921, 396: 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 408: 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 432: 921, 921, 921, 921, 921, 921, 439: 921, 921, 921, 921, 921, 921, 921, 921, 448: 921, 921, 521: 921},\n\t\t// 915\n\t\t{797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 363: 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 374: 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 385: 797, 797, 388: 797, 797, 797, 797, 797, 396: 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 408: 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, 432: 797, 797, 797, 797, 797, 797, 439: 797, 797, 797, 797, 797, 797, 797, 797, 448: 797, 797, 521: 797},\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 407: 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 621: 2923, 2924, 630: 2926, 638: 2927, 2928, 647: 2940},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2941},\n\t\t{361: 2942, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 2943},\n\t\t// 920\n\t\t{922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 363: 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 374: 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 385: 922, 922, 388: 922, 922, 922, 922, 922, 396: 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 408: 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 432: 922, 922, 922, 922, 922, 922, 439: 922, 922, 922, 922, 922, 922, 922, 922, 448: 922, 922, 521: 922},\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 407: 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 621: 2923, 2924, 630: 2926, 638: 2927, 2928, 647: 2945},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2946},\n\t\t{361: 2947, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 2948},\n\t\t// 925\n\t\t{923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 363: 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 374: 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 385: 923, 923, 388: 923, 923, 923, 923, 923, 396: 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 408: 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 923, 432: 923, 923, 923, 923, 923, 923, 439: 923, 923, 923, 923, 923, 923, 923, 923, 448: 923, 923, 521: 923},\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 407: 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 621: 2923, 2924, 630: 2926, 638: 2927, 2928, 647: 2950},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2951},\n\t\t{361: 2952, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 2953},\n\t\t// 930\n\t\t{924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 363: 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 374: 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 385: 924, 924, 388: 924, 924, 924, 924, 924, 396: 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 408: 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, 432: 924, 924, 924, 924, 924, 924, 439: 924, 924, 924, 924, 924, 924, 924, 924, 448: 924, 924, 521: 924},\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 407: 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 621: 2923, 2924, 630: 2926, 638: 2927, 2928, 647: 2955},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2956},\n\t\t{361: 2957, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 2958},\n\t\t// 935\n\t\t{925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 363: 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 374: 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 385: 925, 925, 388: 925, 925, 925, 925, 925, 396: 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 408: 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, 432: 925, 925, 925, 925, 925, 925, 439: 925, 925, 925, 925, 925, 925, 925, 925, 448: 925, 925, 521: 925},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 2961},\n\t\t{1590, 1590, 9: 1590, 58: 1590, 361: 1590, 375: 1590, 378: 1590, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{9: 2962, 361: 2963},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2964},\n\t\t// 940\n\t\t{926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 363: 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 374: 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 385: 926, 926, 388: 926, 926, 926, 926, 926, 396: 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 408: 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 432: 926, 926, 926, 926, 926, 926, 439: 926, 926, 926, 926, 926, 926, 926, 926, 448: 926, 926, 521: 926},\n\t\t{1589, 1589, 9: 1589, 58: 1589, 361: 1589, 375: 1589, 378: 1589, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 407: 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 621: 2923, 2924, 630: 2926, 638: 2927, 2928, 647: 2966},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2967},\n\t\t{361: 2968, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 945\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 2969},\n\t\t{927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 363: 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 374: 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 385: 927, 927, 388: 927, 927, 927, 927, 927, 396: 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 408: 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 927, 432: 927, 927, 927, 927, 927, 927, 439: 927, 927, 927, 927, 927, 927, 927, 927, 448: 927, 927, 521: 927},\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 407: 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 621: 2923, 2924, 630: 2926, 638: 2927, 2928, 647: 2971},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2972},\n\t\t{361: 2973, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 950\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 2974},\n\t\t{928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 363: 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 374: 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 385: 928, 928, 388: 928, 928, 928, 928, 928, 396: 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 408: 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 928, 432: 928, 928, 928, 928, 928, 928, 439: 928, 928, 928, 928, 928, 928, 928, 928, 448: 928, 928, 521: 928},\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 407: 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 621: 2923, 2924, 630: 2926, 638: 2927, 2928, 647: 2976},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 2977},\n\t\t{9: 2962, 58: 1086, 361: 1086, 378: 2978, 649: 2979, 2980},\n\t\t// 955\n\t\t{546: 2985},\n\t\t{1085, 1085, 58: 1085, 361: 1085, 364: 1085, 1085, 368: 1085, 375: 1085, 377: 1085, 379: 1085, 1085, 1085},\n\t\t{58: 2982, 361: 919, 1008: 2981},\n\t\t{361: 2984},\n\t\t{363: 2983},\n\t\t// 960\n\t\t{361: 918},\n\t\t{929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 363: 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 374: 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 385: 929, 929, 388: 929, 929, 929, 929, 929, 396: 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 408: 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 929, 432: 929, 929, 929, 929, 929, 929, 439: 929, 929, 929, 929, 929, 929, 929, 929, 448: 929, 929, 521: 929},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2789, 699: 2790, 716: 2986},\n\t\t{1093, 1093, 9: 2792, 58: 1093, 361: 1093, 364: 1093, 1093, 368: 1093, 375: 1093, 377: 1093, 379: 1093, 1093, 1093},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 406: 2991, 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2988, 600: 2990, 621: 2923, 2924, 630: 2989},\n\t\t// 965\n\t\t{361: 2999, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 2997},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2994},\n\t\t{361: 2992},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 2993},\n\t\t// 970\n\t\t{930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 363: 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 374: 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 385: 930, 930, 388: 930, 930, 930, 930, 930, 396: 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 408: 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 432: 930, 930, 930, 930, 930, 930, 439: 930, 930, 930, 930, 930, 930, 930, 930, 448: 930, 930, 521: 930},\n\t\t{361: 2995, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 2996},\n\t\t{932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 363: 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 374: 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 385: 932, 932, 388: 932, 932, 932, 932, 932, 396: 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 408: 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 932, 432: 932, 932, 932, 932, 932, 932, 439: 932, 932, 932, 932, 932, 932, 932, 932, 448: 932, 932, 521: 932},\n\t\t{9: 2962, 361: 2998},\n\t\t// 975\n\t\t{933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 363: 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 374: 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 385: 933, 933, 388: 933, 933, 933, 933, 933, 396: 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 408: 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 432: 933, 933, 933, 933, 933, 933, 439: 933, 933, 933, 933, 933, 933, 933, 933, 448: 933, 933, 521: 933},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 3000},\n\t\t{931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 363: 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 374: 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 385: 931, 931, 388: 931, 931, 931, 931, 931, 396: 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 408: 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 931, 432: 931, 931, 931, 931, 931, 931, 439: 931, 931, 931, 931, 931, 931, 931, 931, 448: 931, 931, 521: 931},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3002, 600: 3003},\n\t\t{361: 3007, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 980\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3004},\n\t\t{361: 3005, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 3006},\n\t\t{934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 363: 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 374: 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 385: 934, 934, 388: 934, 934, 934, 934, 934, 396: 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 408: 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 934, 432: 934, 934, 934, 934, 934, 934, 439: 934, 934, 934, 934, 934, 934, 934, 934, 448: 934, 934, 521: 934},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 3008},\n\t\t// 985\n\t\t{935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 363: 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 374: 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 385: 935, 935, 388: 935, 935, 935, 935, 935, 396: 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 408: 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 935, 432: 935, 935, 935, 935, 935, 935, 439: 935, 935, 935, 935, 935, 935, 935, 935, 448: 935, 935, 521: 935},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3010, 600: 3011},\n\t\t{361: 3015, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3012},\n\t\t{361: 3013, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 990\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 3014},\n\t\t{936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 363: 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 374: 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 385: 936, 936, 388: 936, 936, 936, 936, 936, 396: 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 408: 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 936, 432: 936, 936, 936, 936, 936, 936, 439: 936, 936, 936, 936, 936, 936, 936, 936, 448: 936, 936, 521: 936},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 3016},\n\t\t{937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 363: 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 374: 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 385: 937, 937, 388: 937, 937, 937, 937, 937, 396: 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 408: 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 937, 432: 937, 937, 937, 937, 937, 937, 439: 937, 937, 937, 937, 937, 937, 937, 937, 448: 937, 937, 521: 937},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3018, 600: 3019},\n\t\t// 995\n\t\t{361: 3023, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3020},\n\t\t{361: 3021, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 3022},\n\t\t{938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 363: 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 374: 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 385: 938, 938, 388: 938, 938, 938, 938, 938, 396: 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 408: 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 938, 432: 938, 938, 938, 938, 938, 938, 439: 938, 938, 938, 938, 938, 938, 938, 938, 448: 938, 938, 521: 938},\n\t\t// 1000\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 3024},\n\t\t{939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 363: 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 374: 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 385: 939, 939, 388: 939, 939, 939, 939, 939, 396: 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 408: 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 939, 432: 939, 939, 939, 939, 939, 939, 439: 939, 939, 939, 939, 939, 939, 939, 939, 448: 939, 939, 521: 939},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3026, 943: 3028, 987: 3029, 1067: 3030, 3027},\n\t\t{361: 3038, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 3039, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 390: 3032, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3031},\n\t\t// 1005\n\t\t{2: 943, 943, 943, 943, 943, 943, 943, 10: 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 362: 943, 943, 366: 943, 943, 369: 943, 943, 943, 943, 943, 384: 943, 387: 943, 390: 943, 393: 943, 943, 407: 943, 431: 943, 438: 943, 447: 943, 450: 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 943, 523: 943},\n\t\t{2: 942, 942, 942, 942, 942, 942, 942, 10: 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 362: 942, 942, 366: 942, 942, 369: 942, 942, 942, 942, 942, 384: 942, 387: 942, 390: 942, 393: 942, 942, 407: 942, 431: 942, 438: 942, 447: 942, 450: 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 523: 942},\n\t\t{2: 941, 941, 941, 941, 941, 941, 941, 10: 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 362: 941, 941, 366: 941, 941, 369: 941, 941, 941, 941, 941, 384: 941, 387: 941, 390: 941, 393: 941, 941, 407: 941, 431: 941, 438: 941, 447: 941, 450: 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 941, 523: 941},\n\t\t{382: 2760, 385: 2758, 2759, 388: 2757, 2755, 3035, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3033},\n\t\t// 1010\n\t\t{361: 3034, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 363: 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 374: 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 385: 953, 953, 388: 953, 953, 953, 953, 953, 396: 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 408: 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, 432: 953, 953, 953, 953, 953, 953, 439: 953, 953, 953, 953, 953, 953, 953, 953, 448: 953, 953, 521: 953},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3036},\n\t\t{361: 3037, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 363: 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 374: 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 385: 952, 952, 388: 952, 952, 952, 952, 952, 396: 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 408: 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 952, 432: 952, 952, 952, 952, 952, 952, 439: 952, 952, 952, 952, 952, 952, 952, 952, 448: 952, 952, 521: 952},\n\t\t// 1015\n\t\t{955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 363: 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 374: 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 385: 955, 955, 388: 955, 955, 955, 955, 955, 396: 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 408: 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 432: 955, 955, 955, 955, 955, 955, 439: 955, 955, 955, 955, 955, 955, 955, 955, 448: 955, 955, 521: 955},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3040},\n\t\t{361: 3041, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 363: 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 374: 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 385: 954, 954, 388: 954, 954, 954, 954, 954, 396: 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 408: 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 432: 954, 954, 954, 954, 954, 954, 439: 954, 954, 954, 954, 954, 954, 954, 954, 448: 954, 954, 521: 954},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3043},\n\t\t// 1020\n\t\t{9: 3044, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 3045, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3051},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3046},\n\t\t{361: 3047, 377: 3048, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 363: 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 374: 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 385: 960, 960, 388: 960, 960, 960, 960, 960, 396: 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 408: 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 432: 960, 960, 960, 960, 960, 960, 439: 960, 960, 960, 960, 960, 960, 960, 960, 448: 960, 960, 521: 960},\n\t\t// 1025\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3049},\n\t\t{361: 3050, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 363: 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 374: 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 385: 958, 958, 388: 958, 958, 958, 958, 958, 396: 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 408: 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 432: 958, 958, 958, 958, 958, 958, 439: 958, 958, 958, 958, 958, 958, 958, 958, 448: 958, 958, 521: 958},\n\t\t{9: 3053, 361: 3052, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 363: 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 374: 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 385: 961, 961, 388: 961, 961, 961, 961, 961, 396: 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 408: 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 961, 432: 961, 961, 961, 961, 961, 961, 439: 961, 961, 961, 961, 961, 961, 961, 961, 448: 961, 961, 521: 961},\n\t\t// 1030\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3054},\n\t\t{361: 3055, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 363: 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 374: 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 385: 959, 959, 388: 959, 959, 959, 959, 959, 396: 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 408: 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, 432: 959, 959, 959, 959, 959, 959, 439: 959, 959, 959, 959, 959, 959, 959, 959, 448: 959, 959, 521: 959},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3057},\n\t\t{370: 3062, 3063, 3068, 406: 3064, 425: 3070, 439: 3066, 3059, 3065, 3069, 3058, 3067, 3060, 3061},\n\t\t// 1035\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3090},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3089},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3088},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3087},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 3084, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3083},\n\t\t// 1040\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 3080, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3079},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3078},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3077},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3076},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3075},\n\t\t// 1045\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3074},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3073},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3071},\n\t\t{361: 3072, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 363: 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 374: 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 385: 962, 962, 388: 962, 962, 962, 962, 962, 396: 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 408: 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 962, 432: 962, 962, 962, 962, 962, 962, 439: 962, 962, 962, 962, 962, 962, 962, 962, 448: 962, 962, 521: 962},\n\t\t// 1050\n\t\t{1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 363: 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 374: 1071, 1071, 377: 1071, 1071, 1071, 1071, 1071, 1071, 1071, 385: 1071, 1071, 388: 1071, 1071, 1071, 1071, 1071, 396: 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 408: 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 432: 1071, 1071, 1071, 1071, 1071, 1071, 439: 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 448: 1071, 1071},\n\t\t{1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 363: 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 374: 1072, 1072, 377: 1072, 1072, 1072, 1072, 1072, 1072, 1072, 385: 1072, 1072, 388: 1072, 1072, 1072, 1072, 1072, 396: 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 408: 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 1072, 432: 1072, 1072, 1072, 1072, 1072, 1072, 439: 1072, 1072, 1072, 3069, 1072, 1072, 1072, 1072, 448: 1072, 1072},\n\t\t{1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 363: 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 374: 1073, 1073, 377: 1073, 1073, 1073, 1073, 1073, 1073, 1073, 385: 1073, 1073, 388: 1073, 1073, 1073, 1073, 1073, 396: 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 408: 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 1073, 432: 1073, 1073, 1073, 1073, 1073, 1073, 439: 1073, 1073, 1073, 3069, 1073, 1073, 1073, 1073, 448: 1073, 1073},\n\t\t{1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 363: 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 374: 1074, 1074, 377: 1074, 1074, 1074, 1074, 1074, 1074, 1074, 385: 1074, 1074, 388: 1074, 1074, 1074, 1074, 1074, 396: 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 408: 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 1074, 432: 1074, 1074, 1074, 1074, 1074, 1074, 439: 1074, 1074, 1074, 3069, 1074, 1074, 1074, 1074, 448: 1074, 1074},\n\t\t{1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 363: 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 374: 1075, 1075, 377: 1075, 1075, 1075, 1075, 1075, 1075, 1075, 385: 1075, 1075, 388: 1075, 1075, 1075, 1075, 1075, 396: 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 408: 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 1075, 432: 1075, 1075, 1075, 1075, 1075, 1075, 439: 1075, 1075, 1075, 3069, 1075, 1075, 1075, 1075, 448: 1075, 1075},\n\t\t// 1055\n\t\t{1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 363: 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 374: 1076, 1076, 377: 1076, 1076, 1076, 1076, 1076, 1076, 1076, 385: 1076, 1076, 388: 1076, 1076, 1076, 1076, 1076, 396: 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 408: 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 1076, 432: 1076, 1076, 1076, 1076, 1076, 1076, 439: 1076, 1076, 1076, 3069, 1076, 1076, 1076, 1076, 448: 1076, 1076},\n\t\t{1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 363: 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 3068, 374: 1079, 1079, 377: 1079, 1079, 1079, 1079, 1079, 1079, 1079, 385: 1079, 1079, 388: 1079, 1079, 1079, 1079, 1079, 396: 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 3064, 408: 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 1079, 432: 1079, 1079, 1079, 1079, 1079, 1079, 439: 3066, 1079, 3065, 3069, 1079, 3067, 1079, 1079, 448: 1079, 1079},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3081},\n\t\t{62: 2843, 2842, 2839, 2841, 2845, 2846, 2840, 2851, 2850, 2849, 2853, 2854, 2848, 2852, 2855, 2844, 2847, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 413: 2837, 2834, 2836, 2835, 2831, 2833, 2832, 2829, 2830, 2828, 2838, 596: 2756, 2754, 652: 2827, 669: 3082},\n\t\t{1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 363: 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 374: 1077, 1077, 377: 1077, 1077, 1077, 1077, 1077, 1077, 1077, 385: 1077, 1077, 388: 1077, 1077, 1077, 1077, 1077, 396: 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 408: 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 432: 1077, 1077, 1077, 1077, 1077, 1077, 439: 1077, 1077, 1077, 1077, 1077, 1077, 1077, 1077, 448: 1077, 1077},\n\t\t// 1060\n\t\t{1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 363: 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 3068, 374: 1080, 1080, 377: 1080, 1080, 1080, 1080, 1080, 1080, 1080, 385: 1080, 1080, 388: 1080, 1080, 1080, 1080, 1080, 396: 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 3064, 408: 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 432: 1080, 1080, 1080, 1080, 1080, 1080, 439: 3066, 1080, 3065, 3069, 1080, 3067, 1080, 1080, 448: 1080, 1080},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3085},\n\t\t{62: 2843, 2842, 2839, 2841, 2845, 2846, 2840, 2851, 2850, 2849, 2853, 2854, 2848, 2852, 2855, 2844, 2847, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 413: 2837, 2834, 2836, 2835, 2831, 2833, 2832, 2829, 2830, 2828, 2838, 596: 2756, 2754, 652: 2827, 669: 3086},\n\t\t{1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 363: 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 374: 1078, 1078, 377: 1078, 1078, 1078, 1078, 1078, 1078, 1078, 385: 1078, 1078, 388: 1078, 1078, 1078, 1078, 1078, 396: 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 408: 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 432: 1078, 1078, 1078, 1078, 1078, 1078, 439: 1078, 1078, 1078, 1078, 1078, 1078, 1078, 1078, 448: 1078, 1078},\n\t\t{1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 363: 1081, 1081, 1081, 1081, 1081, 1081, 1081, 3062, 3063, 3068, 374: 1081, 1081, 377: 1081, 1081, 1081, 1081, 1081, 1081, 1081, 385: 1081, 1081, 388: 1081, 1081, 1081, 1081, 1081, 396: 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 3064, 408: 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 432: 1081, 1081, 1081, 1081, 1081, 1081, 439: 3066, 1081, 3065, 3069, 1081, 3067, 1081, 1081, 448: 1081, 1081},\n\t\t// 1065\n\t\t{1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 363: 1082, 1082, 1082, 1082, 1082, 1082, 1082, 3062, 3063, 3068, 374: 1082, 1082, 377: 1082, 1082, 1082, 1082, 1082, 1082, 1082, 385: 1082, 1082, 388: 1082, 1082, 1082, 1082, 1082, 396: 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 3064, 408: 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 432: 1082, 1082, 1082, 1082, 1082, 1082, 439: 3066, 1082, 3065, 3069, 1082, 3067, 1082, 1082, 448: 1082, 1082},\n\t\t{1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 363: 1083, 1083, 1083, 1083, 1083, 1083, 1083, 3062, 3063, 3068, 374: 1083, 1083, 377: 1083, 1083, 1083, 1083, 1083, 1083, 1083, 385: 1083, 1083, 388: 1083, 1083, 1083, 1083, 1083, 396: 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 3064, 408: 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 1083, 432: 1083, 1083, 1083, 1083, 1083, 1083, 439: 3066, 1083, 3065, 3069, 1083, 3067, 3060, 3061, 448: 1083, 1083},\n\t\t{1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 363: 1084, 1084, 1084, 1084, 1084, 1084, 1084, 3062, 3063, 3068, 374: 1084, 1084, 377: 1084, 1084, 1084, 1084, 1084, 1084, 1084, 385: 1084, 1084, 388: 1084, 1084, 1084, 1084, 1084, 396: 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 3064, 408: 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 1084, 432: 1084, 1084, 1084, 1084, 1084, 1084, 439: 3066, 3059, 3065, 3069, 1084, 3067, 3060, 3061, 448: 1084, 1084},\n\t\t{62: 2843, 2842, 2839, 2841, 2845, 2846, 2840, 2851, 2850, 2849, 2853, 2854, 2848, 2852, 2855, 2844, 2847, 413: 2837, 2834, 2836, 2835, 2831, 2833, 2832, 2829, 2830, 2828, 2838, 652: 2827, 669: 3092},\n\t\t{390: 3093},\n\t\t// 1070\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3094},\n\t\t{361: 3095, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 363: 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 374: 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 385: 964, 964, 388: 964, 964, 964, 964, 964, 396: 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 408: 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 964, 432: 964, 964, 964, 964, 964, 964, 439: 964, 964, 964, 964, 964, 964, 964, 964, 448: 964, 964, 521: 964},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3097},\n\t\t{9: 3098, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 1075\n\t\t{456: 3099},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3100},\n\t\t{62: 2843, 2842, 2839, 2841, 2845, 2846, 2840, 2851, 2850, 2849, 2853, 2854, 2848, 2852, 2855, 2844, 2847, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 413: 2837, 2834, 2836, 2835, 2831, 2833, 2832, 2829, 2830, 2828, 2838, 596: 2756, 2754, 652: 2827, 669: 3101},\n\t\t{361: 3102},\n\t\t{965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 363: 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 374: 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 385: 965, 965, 388: 965, 965, 965, 965, 965, 396: 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 408: 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 432: 965, 965, 965, 965, 965, 965, 439: 965, 965, 965, 965, 965, 965, 965, 965, 448: 965, 965, 521: 965},\n\t\t// 1080\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3104},\n\t\t{9: 3105, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 3107, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3106},\n\t\t{361: 3111, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3108},\n\t\t// 1085\n\t\t{62: 2843, 2842, 2839, 2841, 2845, 2846, 2840, 2851, 2850, 2849, 2853, 2854, 2848, 2852, 2855, 2844, 2847, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 413: 2837, 2834, 2836, 2835, 2831, 2833, 2832, 2829, 2830, 2828, 2838, 596: 2756, 2754, 652: 2827, 669: 3109},\n\t\t{361: 3110},\n\t\t{966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 363: 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 374: 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 385: 966, 966, 388: 966, 966, 966, 966, 966, 396: 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 408: 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 966, 432: 966, 966, 966, 966, 966, 966, 439: 966, 966, 966, 966, 966, 966, 966, 966, 448: 966, 966, 521: 966},\n\t\t{967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 363: 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 374: 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 385: 967, 967, 388: 967, 967, 967, 967, 967, 396: 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 408: 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 967, 432: 967, 967, 967, 967, 967, 967, 439: 967, 967, 967, 967, 967, 967, 967, 967, 448: 967, 967, 521: 967},\n\t\t{361: 1584, 393: 3114, 831: 3113, 3115},\n\t\t// 1090\n\t\t{361: 1583},\n\t\t{361: 1582},\n\t\t{361: 3116},\n\t\t{968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 363: 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 374: 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 385: 968, 968, 388: 968, 968, 968, 968, 968, 396: 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 408: 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 432: 968, 968, 968, 968, 968, 968, 439: 968, 968, 968, 968, 968, 968, 968, 968, 448: 968, 968, 521: 968},\n\t\t{361: 1584, 393: 3114, 831: 3113, 3118},\n\t\t// 1095\n\t\t{361: 3119},\n\t\t{969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 363: 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 374: 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 385: 969, 969, 388: 969, 969, 969, 969, 969, 396: 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 408: 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 432: 969, 969, 969, 969, 969, 969, 439: 969, 969, 969, 969, 969, 969, 969, 969, 448: 969, 969, 521: 969},\n\t\t{363: 1111},\n\t\t{363: 1110},\n\t\t{363: 1109},\n\t\t// 1100\n\t\t{363: 3124},\n\t\t{404: 3125},\n\t\t{970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 363: 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 374: 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 385: 970, 970, 388: 970, 970, 970, 970, 970, 396: 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 408: 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 432: 970, 970, 970, 970, 970, 970, 439: 970, 970, 970, 970, 970, 970, 970, 970, 448: 970, 970, 521: 970},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3127},\n\t\t{9: 3128, 370: 3062, 3063, 3068, 406: 3064, 439: 3066, 3059, 3065, 3069, 3058, 3067, 3060, 3061},\n\t\t// 1105\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3129},\n\t\t{361: 3130, 370: 3062, 3063, 3068, 406: 3064, 439: 3066, 3059, 3065, 3069, 3058, 3067, 3060, 3061},\n\t\t{972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 363: 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 374: 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 385: 972, 972, 388: 972, 972, 972, 972, 972, 396: 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 408: 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 972, 432: 972, 972, 972, 972, 972, 972, 439: 972, 972, 972, 972, 972, 972, 972, 972, 448: 972, 972, 521: 972},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 1586, 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 3132, 702: 3133},\n\t\t{9: 2962, 361: 1585},\n\t\t// 1110\n\t\t{361: 3134},\n\t\t{973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 363: 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 374: 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 385: 973, 973, 388: 973, 973, 973, 973, 973, 396: 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 408: 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 973, 432: 973, 973, 973, 973, 973, 973, 439: 973, 973, 973, 973, 973, 973, 973, 973, 448: 973, 973, 521: 973},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 3136},\n\t\t{9: 2962, 361: 3137, 375: 3138},\n\t\t{978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 363: 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 374: 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 385: 978, 978, 388: 978, 978, 978, 978, 978, 396: 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 408: 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 978, 432: 978, 978, 978, 978, 978, 978, 439: 978, 978, 978, 978, 978, 978, 978, 978, 448: 978, 978, 521: 978},\n\t\t// 1115\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 438: 2567, 537: 2569, 2178, 2179, 2177, 601: 2566, 648: 3139},\n\t\t{361: 3140},\n\t\t{977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 363: 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 374: 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 385: 977, 977, 388: 977, 977, 977, 977, 977, 396: 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 408: 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, 432: 977, 977, 977, 977, 977, 977, 439: 977, 977, 977, 977, 977, 977, 977, 977, 448: 977, 977, 521: 977},\n\t\t{979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 363: 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 374: 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 385: 979, 979, 388: 979, 979, 979, 979, 979, 396: 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 408: 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 432: 979, 979, 979, 979, 979, 979, 439: 979, 979, 979, 979, 979, 979, 979, 979, 448: 979, 979, 521: 979},\n\t\t{361: 3143, 393: 3144},\n\t\t// 1120\n\t\t{915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 363: 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 374: 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 385: 915, 915, 388: 915, 915, 915, 915, 915, 396: 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 408: 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 915, 432: 915, 915, 915, 915, 915, 915, 439: 915, 915, 915, 915, 915, 915, 915, 915, 448: 915, 915, 521: 915},\n\t\t{361: 3145},\n\t\t{914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 363: 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 374: 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 385: 914, 914, 388: 914, 914, 914, 914, 914, 396: 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 408: 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 432: 914, 914, 914, 914, 914, 914, 439: 914, 914, 914, 914, 914, 914, 914, 914, 448: 914, 914, 521: 914},\n\t\t{361: 3147},\n\t\t{980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 363: 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 374: 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 385: 980, 980, 388: 980, 980, 980, 980, 980, 396: 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 408: 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 432: 980, 980, 980, 980, 980, 980, 439: 980, 980, 980, 980, 980, 980, 980, 980, 448: 980, 980, 521: 980},\n\t\t// 1125\n\t\t{361: 3150},\n\t\t{981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 363: 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 374: 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 385: 981, 981, 388: 981, 981, 981, 981, 981, 396: 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 408: 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, 432: 981, 981, 981, 981, 981, 981, 439: 981, 981, 981, 981, 981, 981, 981, 981, 448: 981, 981, 521: 981},\n\t\t{994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 363: 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 374: 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 385: 994, 994, 388: 994, 994, 994, 994, 994, 396: 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 408: 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 994, 432: 994, 994, 994, 994, 994, 994, 439: 994, 994, 994, 994, 994, 994, 994, 994, 448: 994, 994, 521: 994, 547: 994, 551: 994},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 1586, 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 3132, 702: 3152},\n\t\t{361: 3153},\n\t\t// 1130\n\t\t{982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 363: 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 374: 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 385: 982, 982, 388: 982, 982, 982, 982, 982, 396: 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 408: 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 982, 432: 982, 982, 982, 982, 982, 982, 439: 982, 982, 982, 982, 982, 982, 982, 982, 448: 982, 982, 521: 982},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 1586, 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 3132, 702: 3155},\n\t\t{361: 3156},\n\t\t{983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 363: 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 374: 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 385: 983, 983, 388: 983, 983, 983, 983, 983, 396: 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 408: 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 432: 983, 983, 983, 983, 983, 983, 439: 983, 983, 983, 983, 983, 983, 983, 983, 448: 983, 983, 521: 983},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 407: 2604, 537: 2603, 2178, 2179, 2177, 576: 3158},\n\t\t// 1135\n\t\t{361: 3159},\n\t\t{1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 363: 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 374: 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 385: 1037, 1037, 388: 1037, 1037, 1037, 1037, 1037, 396: 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 408: 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 432: 1037, 1037, 1037, 1037, 1037, 1037, 439: 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 448: 1037, 1037, 521: 1037},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3161},\n\t\t{9: 3162, 375: 3163, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{117: 3170, 3169, 128: 3175, 140: 3172, 187: 3173, 387: 3168, 438: 3167, 561: 3176, 3177, 786: 3166, 803: 3171, 887: 3178, 925: 3174},\n\t\t// 1140\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 438: 2567, 537: 2569, 2178, 2179, 2177, 601: 2566, 648: 3164},\n\t\t{361: 3165},\n\t\t{1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 363: 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 374: 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 385: 1039, 1039, 388: 1039, 1039, 1039, 1039, 1039, 396: 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 408: 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 432: 1039, 1039, 1039, 1039, 1039, 1039, 439: 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 448: 1039, 1039, 521: 1039},\n\t\t{361: 3215},\n\t\t{361: 244, 3194, 662: 3195, 691: 3214},\n\t\t// 1145\n\t\t{7: 244, 361: 244, 3194, 387: 244, 438: 244, 526: 244, 662: 3195, 691: 3199},\n\t\t{361: 875},\n\t\t{361: 244, 3194, 662: 3195, 691: 3198},\n\t\t{361: 237, 3180, 662: 3181, 828: 3197, 882: 3182},\n\t\t{361: 244, 3194, 662: 3195, 691: 3193},\n\t\t// 1150\n\t\t{361: 308, 565: 3191, 843: 3190, 870: 3192},\n\t\t{361: 308, 565: 3191, 843: 3190, 870: 3189},\n\t\t{361: 869},\n\t\t{361: 868},\n\t\t{361: 237, 3180, 662: 3181, 828: 3179, 882: 3182},\n\t\t// 1155\n\t\t{361: 866},\n\t\t{361: 867},\n\t\t{393: 2147, 598: 3183, 611: 3184},\n\t\t{361: 236},\n\t\t{361: 235},\n\t\t// 1160\n\t\t{1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 41: 1613, 48: 1613, 1613, 1613, 54: 1613, 1613, 96: 1613, 129: 1613, 361: 1613, 1613, 364: 1613, 1613, 368: 1613, 373: 1613, 1613, 1613, 1613, 1613, 379: 1613, 1613, 384: 1613, 387: 1613, 395: 1613, 522: 1613, 524: 1613, 1613, 1613, 530: 1613, 1613, 1613},\n\t\t{9: 3186, 361: 3185},\n\t\t{245, 245, 245, 245, 245, 245, 7: 245, 9: 245, 31: 245, 245, 245, 245, 245, 361: 245, 364: 245, 369: 245, 373: 245, 245, 376: 245, 387: 245, 394: 245, 245, 411: 245, 245, 438: 245, 526: 245, 245, 245, 245, 533: 245, 245, 245, 245},\n\t\t{393: 2147, 598: 3183, 611: 3187},\n\t\t{361: 3188},\n\t\t// 1165\n\t\t{361: 234},\n\t\t{361: 870},\n\t\t{361: 307},\n\t\t{361: 306},\n\t\t{361: 871},\n\t\t// 1170\n\t\t{361: 872},\n\t\t{393: 2147, 598: 3183, 611: 3196},\n\t\t{243, 243, 243, 243, 243, 243, 7: 243, 9: 243, 31: 243, 243, 243, 243, 243, 361: 243, 364: 243, 369: 243, 373: 243, 243, 376: 243, 387: 243, 394: 243, 243, 411: 243, 243, 438: 243, 526: 243, 243, 243, 243, 533: 243, 243, 243, 243},\n\t\t{361: 3185},\n\t\t{361: 873},\n\t\t// 1175\n\t\t{361: 874},\n\t\t{7: 3204, 361: 231, 387: 3205, 438: 3201, 526: 3203, 653: 3202, 1003: 3200},\n\t\t{361: 876},\n\t\t{7: 3204, 361: 228, 387: 3205, 526: 3203, 653: 3212, 1005: 3211},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 438: 2567, 537: 2569, 2178, 2179, 2177, 601: 2566, 648: 3208},\n\t\t// 1180\n\t\t{392: 3207},\n\t\t{225, 225, 225, 225, 225, 225, 225, 225, 225, 10: 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 363: 225, 373: 225, 383: 225, 391: 225, 405: 225, 438: 225},\n\t\t{392: 3206},\n\t\t{224, 224, 224, 224, 224, 224, 224, 224, 224, 10: 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 363: 224, 373: 224, 383: 224, 391: 224, 405: 224, 438: 224},\n\t\t{226, 226, 226, 226, 226, 226, 226, 226, 226, 10: 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 363: 226, 373: 226, 383: 226, 391: 226, 405: 226, 438: 226},\n\t\t// 1185\n\t\t{361: 233, 438: 3209, 1004: 3210},\n\t\t{361: 232},\n\t\t{361: 229},\n\t\t{361: 230},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 438: 2567, 537: 2569, 2178, 2179, 2177, 601: 2566, 648: 3213},\n\t\t// 1190\n\t\t{361: 227},\n\t\t{361: 877},\n\t\t{1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 363: 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 374: 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 385: 1040, 1040, 388: 1040, 1040, 1040, 1040, 1040, 396: 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 408: 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 432: 1040, 1040, 1040, 1040, 1040, 1040, 439: 1040, 1040, 1040, 1040, 1040, 1040, 1040, 1040, 448: 1040, 1040, 521: 1040},\n\t\t{382: 2760, 385: 2758, 2759, 388: 2757, 2755, 424: 883, 596: 2756, 2754},\n\t\t{424: 3220, 928: 3219, 1083: 3218},\n\t\t// 1195\n\t\t{91: 879, 424: 3220, 426: 3226, 928: 3225, 964: 3224},\n\t\t{91: 882, 424: 882, 426: 882},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3221},\n\t\t{382: 2760, 385: 2758, 2759, 388: 2757, 2755, 427: 3222, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3223},\n\t\t// 1200\n\t\t{91: 880, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 424: 880, 426: 880, 596: 2756, 2754},\n\t\t{91: 3228},\n\t\t{91: 881, 424: 881, 426: 881},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3227},\n\t\t{91: 878, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 1205\n\t\t{1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 363: 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 374: 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 385: 1041, 1041, 388: 1041, 1041, 1041, 1041, 1041, 396: 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 408: 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 432: 1041, 1041, 1041, 1041, 1041, 1041, 439: 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 448: 1041, 1041, 521: 1041},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3230},\n\t\t{374: 3231, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{117: 3170, 3169, 128: 3175, 140: 3172, 187: 3173, 387: 3168, 438: 3167, 561: 3176, 3177, 786: 3232, 803: 3171, 887: 3178, 925: 3174},\n\t\t{361: 3233},\n\t\t// 1210\n\t\t{1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 363: 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 374: 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 385: 1042, 1042, 388: 1042, 1042, 1042, 1042, 1042, 396: 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 408: 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 432: 1042, 1042, 1042, 1042, 1042, 1042, 439: 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 448: 1042, 1042, 521: 1042},\n\t\t{1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 363: 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 374: 1043, 1043, 2764, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 385: 1043, 1043, 388: 1043, 1043, 1043, 1043, 1043, 396: 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 408: 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 432: 1043, 1043, 1043, 1043, 1043, 1043, 439: 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 448: 1043, 1043, 521: 1043},\n\t\t{1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 363: 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 374: 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 385: 1044, 1044, 388: 1044, 1044, 1044, 1044, 1044, 396: 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 408: 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 432: 1044, 1044, 1044, 1044, 1044, 1044, 439: 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 448: 1044, 1044, 521: 1044},\n\t\t{362: 3239, 524: 2053, 606: 3237, 2054, 2055, 2056, 613: 2059, 2058, 3238},\n\t\t{361: 3243, 365: 674},\n\t\t// 1215\n\t\t{361: 3242},\n\t\t{524: 2053, 606: 3240, 2054, 2055, 2056},\n\t\t{361: 3241},\n\t\t{365: 673},\n\t\t{685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 363: 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 374: 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 385: 685, 685, 388: 685, 685, 685, 685, 685, 396: 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 408: 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 685, 432: 685, 685, 685, 685, 685, 685, 439: 685, 685, 685, 685, 685, 685, 685, 685, 448: 685, 685, 521: 685},\n\t\t// 1220\n\t\t{686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 363: 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 374: 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 385: 686, 686, 388: 686, 686, 686, 686, 686, 396: 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 408: 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 686, 432: 686, 686, 686, 686, 686, 686, 439: 686, 686, 686, 686, 686, 686, 686, 686, 448: 686, 686, 521: 686},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 3245},\n\t\t{9: 3246},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3247},\n\t\t{9: 1589, 361: 3248, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 1225\n\t\t{1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 363: 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 374: 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 385: 1045, 1045, 388: 1045, 1045, 1045, 1045, 1045, 396: 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 408: 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 432: 1045, 1045, 1045, 1045, 1045, 1045, 439: 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 448: 1045, 1045, 521: 1045},\n\t\t{9: 1590, 361: 3257, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{9: 3254},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 3251, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 2053, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3249, 606: 3252, 2054, 2055, 2056, 613: 2059, 2058, 3238, 628: 3250},\n\t\t{361: 3253, 365: 674},\n\t\t// 1230\n\t\t{686, 686, 9: 686, 361: 686, 365: 673, 369: 686, 686, 686, 686, 376: 686, 382: 686, 385: 686, 686, 388: 686, 686, 391: 686, 405: 686, 686, 425: 686, 428: 686, 686, 686, 432: 686, 686, 686, 686, 686, 686, 439: 686, 686, 686, 686, 686, 686, 686, 686, 448: 686, 686, 521: 686},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3255},\n\t\t{9: 1589, 361: 3256, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 363: 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 374: 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 385: 1046, 1046, 388: 1046, 1046, 1046, 1046, 1046, 396: 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 408: 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 432: 1046, 1046, 1046, 1046, 1046, 1046, 439: 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 448: 1046, 1046, 521: 1046},\n\t\t{1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 363: 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 374: 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 385: 1047, 1047, 388: 1047, 1047, 1047, 1047, 1047, 396: 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 408: 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 432: 1047, 1047, 1047, 1047, 1047, 1047, 439: 1047, 1047, 1047, 1047, 1047, 1047, 1047, 1047, 448: 1047, 1047, 521: 1047},\n\t\t// 1235\n\t\t{1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 363: 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 374: 1049, 1049, 2764, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 385: 1049, 1049, 388: 1049, 1049, 1049, 1049, 1049, 396: 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 408: 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 432: 1049, 1049, 1049, 1049, 1049, 1049, 439: 1049, 1049, 1049, 1049, 1049, 1049, 1049, 1049, 448: 1049, 1049, 521: 1049},\n\t\t{1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 363: 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 374: 1051, 1051, 2764, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 385: 1051, 1051, 388: 1051, 1051, 1051, 1051, 1051, 396: 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 408: 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 432: 1051, 1051, 1051, 1051, 1051, 1051, 439: 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 448: 1051, 1051, 521: 1051},\n\t\t{1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 363: 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 374: 1052, 1052, 2764, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 385: 1052, 1052, 388: 1052, 1052, 1052, 1052, 1052, 396: 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 408: 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 432: 1052, 1052, 1052, 1052, 1052, 1052, 439: 1052, 1052, 1052, 1052, 1052, 1052, 1052, 1052, 448: 1052, 1052, 521: 1052},\n\t\t{1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 363: 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 374: 1053, 1053, 2764, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 385: 1053, 1053, 388: 1053, 1053, 1053, 1053, 1053, 396: 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 408: 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 432: 1053, 1053, 1053, 1053, 1053, 1053, 439: 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 448: 1053, 1053, 521: 1053},\n\t\t{1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 363: 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 374: 1054, 1054, 2764, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 385: 1054, 1054, 388: 1054, 1054, 1054, 1054, 1054, 396: 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 408: 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 432: 1054, 1054, 1054, 1054, 1054, 1054, 439: 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 448: 1054, 1054, 521: 1054},\n\t\t// 1240\n\t\t{363: 3266},\n\t\t{363: 3265},\n\t\t{1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 363: 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 374: 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 385: 1035, 1035, 388: 1035, 1035, 1035, 1035, 1035, 396: 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 408: 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 432: 1035, 1035, 1035, 1035, 1035, 1035, 439: 1035, 1035, 1035, 1035, 1035, 1035, 1035, 1035, 448: 1035, 1035, 521: 1035},\n\t\t{1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 363: 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 374: 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 385: 1036, 1036, 388: 1036, 1036, 1036, 1036, 1036, 396: 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 408: 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 432: 1036, 1036, 1036, 1036, 1036, 1036, 439: 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 448: 1036, 1036, 521: 1036},\n\t\t{571: 3268},\n\t\t// 1245\n\t\t{1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 363: 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 374: 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 385: 1065, 1065, 388: 1065, 1065, 1065, 1065, 1065, 396: 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 408: 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 432: 1065, 1065, 1065, 1065, 1065, 1065, 439: 1065, 1065, 1065, 1065, 1065, 1065, 1065, 1065, 448: 1065, 1065, 521: 1065},\n\t\t{1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 363: 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 385: 1101, 1101, 388: 1101, 1101, 1101, 1101, 1101, 394: 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 408: 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 432: 1101, 1101, 1101, 1101, 1101, 1101, 439: 1101, 1101, 1101, 1101, 1101, 1101, 1101, 1101, 448: 1101, 1101, 521: 1101, 527: 1101, 1101, 1101, 533: 1101, 1101, 1101, 1101},\n\t\t{1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 363: 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 385: 1097, 1097, 388: 1097, 1097, 1097, 1097, 1097, 394: 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 408: 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 432: 1097, 1097, 1097, 1097, 1097, 1097, 439: 1097, 1097, 1097, 1097, 1097, 1097, 1097, 1097, 448: 1097, 1097, 521: 1097, 527: 1097, 1097, 1097, 533: 1097, 1097, 1097, 1097, 545: 1097},\n\t\t{62: 2843, 2842, 2839, 2841, 2845, 2846, 2840, 2851, 2850, 2849, 2853, 2854, 2848, 2852, 2855, 2844, 2847, 652: 3272},\n\t\t{9: 3273},\n\t\t// 1250\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3274},\n\t\t{9: 3275, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3276},\n\t\t{361: 3277, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 363: 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 374: 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 385: 956, 956, 388: 956, 956, 956, 956, 956, 396: 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 408: 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 956, 432: 956, 956, 956, 956, 956, 956, 439: 956, 956, 956, 956, 956, 956, 956, 956, 448: 956, 956, 521: 956},\n\t\t// 1255\n\t\t{62: 2843, 2842, 2839, 2841, 2845, 2846, 2840, 2851, 2850, 2849, 2853, 2854, 2848, 2852, 2855, 2844, 2847, 652: 3279},\n\t\t{9: 3280},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3281},\n\t\t{9: 3282, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3283},\n\t\t// 1260\n\t\t{361: 3284, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 363: 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 374: 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 385: 957, 957, 388: 957, 957, 957, 957, 957, 396: 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 408: 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, 432: 957, 957, 957, 957, 957, 957, 439: 957, 957, 957, 957, 957, 957, 957, 957, 448: 957, 957, 521: 957},\n\t\t{100: 3290, 117: 3288, 3287, 140: 3289, 975: 3286},\n\t\t{9: 3291},\n\t\t{9: 951},\n\t\t// 1265\n\t\t{9: 950},\n\t\t{9: 949},\n\t\t{9: 948},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3292},\n\t\t{361: 3293, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 1270\n\t\t{963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 363: 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 374: 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 385: 963, 963, 388: 963, 963, 963, 963, 963, 396: 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 408: 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 963, 432: 963, 963, 963, 963, 963, 963, 439: 963, 963, 963, 963, 963, 963, 963, 963, 448: 963, 963, 521: 963},\n\t\t{974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 363: 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 374: 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 385: 974, 974, 388: 974, 974, 974, 974, 974, 396: 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 408: 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 974, 432: 974, 974, 974, 974, 974, 974, 439: 974, 974, 974, 974, 974, 974, 974, 974, 448: 974, 974, 521: 974},\n\t\t{975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 363: 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 374: 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 385: 975, 975, 388: 975, 975, 975, 975, 975, 396: 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 408: 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 432: 975, 975, 975, 975, 975, 975, 439: 975, 975, 975, 975, 975, 975, 975, 975, 448: 975, 975, 521: 975},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 1586, 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 3132, 702: 3297},\n\t\t{361: 3298},\n\t\t// 1275\n\t\t{971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 363: 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 374: 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 385: 971, 971, 388: 971, 971, 971, 971, 971, 396: 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 408: 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 971, 432: 971, 971, 971, 971, 971, 971, 439: 971, 971, 971, 971, 971, 971, 971, 971, 448: 971, 971, 521: 971},\n\t\t{976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 363: 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 374: 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 385: 976, 976, 388: 976, 976, 976, 976, 976, 396: 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 408: 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 976, 432: 976, 976, 976, 976, 976, 976, 439: 976, 976, 976, 976, 976, 976, 976, 976, 448: 976, 976, 521: 976},\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 407: 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 621: 2923, 2924, 630: 2926, 638: 2927, 2928, 647: 3301},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3302},\n\t\t{361: 3303, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 1280\n\t\t{798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 363: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 374: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 385: 798, 798, 388: 798, 798, 798, 798, 798, 396: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 408: 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, 432: 798, 798, 798, 798, 798, 798, 439: 798, 798, 798, 798, 798, 798, 798, 798, 448: 798, 798, 521: 798, 604: 2776, 610: 2938, 618: 3304},\n\t\t{940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 363: 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 374: 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 385: 940, 940, 388: 940, 940, 940, 940, 940, 396: 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 408: 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 940, 432: 940, 940, 940, 940, 940, 940, 439: 940, 940, 940, 940, 940, 940, 940, 940, 448: 940, 940, 521: 940},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 1586, 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 628: 3132, 702: 3306},\n\t\t{361: 3307},\n\t\t{917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 363: 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 374: 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 385: 917, 917, 388: 917, 917, 917, 917, 917, 396: 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 408: 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 917, 432: 917, 917, 917, 917, 917, 917, 439: 917, 917, 917, 917, 917, 917, 917, 917, 448: 917, 917, 521: 917},\n\t\t// 1285\n\t\t{2: 1568, 1568, 1568, 1568, 1568, 1568, 1568, 10: 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 362: 1568, 1568, 366: 1568, 1568, 370: 1568, 1568, 1568, 1568, 384: 1568, 387: 1568, 393: 1568, 1568, 407: 1568, 431: 1568, 438: 1568, 447: 1568, 450: 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568, 1568},\n\t\t{405: 3333, 425: 3332, 437: 3331, 448: 3317, 3318, 890: 3334},\n\t\t{362: 1564},\n\t\t{2: 1562, 1562, 1562, 1562, 1562, 1562, 1562, 10: 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 362: 1562, 1562, 366: 1562, 1562, 370: 1562, 1562, 1562, 1562, 384: 1562, 387: 1562, 393: 1562, 1562, 407: 1562, 431: 1562, 438: 1562, 447: 1562, 450: 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562, 1562},\n\t\t{2: 1560, 1560, 1560, 1560, 1560, 1560, 1560, 10: 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 362: 1560, 1560, 366: 1560, 1560, 370: 1560, 1560, 1560, 1560, 384: 1560, 387: 1560, 393: 1560, 1560, 407: 1560, 431: 1560, 438: 1560, 447: 1560, 450: 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560, 1560},\n\t\t// 1290\n\t\t{362: 3327, 574: 3328},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3324},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 3320, 2665, 2744, 2664, 2661},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 3319, 2665, 2744, 2664, 2661},\n\t\t{2: 1549, 1549, 1549, 1549, 1549, 1549, 1549, 10: 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 362: 1549, 1549, 366: 1549, 1549, 370: 1549, 1549, 1549, 1549, 384: 1549, 387: 1549, 393: 1549, 1549, 407: 1549, 431: 1549, 438: 1549, 447: 1549, 450: 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549},\n\t\t// 1295\n\t\t{2: 1548, 1548, 1548, 1548, 1548, 1548, 1548, 10: 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 362: 1548, 1548, 366: 1548, 1548, 370: 1548, 1548, 1548, 1548, 384: 1548, 387: 1548, 393: 1548, 1548, 407: 1548, 431: 1548, 438: 1548, 447: 1548, 450: 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548},\n\t\t{1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 363: 1551, 1551, 1551, 1551, 1551, 1551, 374: 1551, 1551, 2764, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 385: 1551, 1551, 388: 1551, 1551, 1551, 1551, 1551, 396: 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 408: 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 426: 1551, 1551, 1551, 1551, 1551, 432: 1551, 1551, 1551, 1551, 1551, 521: 2765},\n\t\t{1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 3322, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 363: 1547, 1547, 1547, 1547, 1547, 1547, 374: 1547, 1547, 2764, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 385: 1547, 1547, 388: 1547, 1547, 1547, 1547, 1547, 396: 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 408: 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 426: 1547, 1547, 1547, 1547, 1547, 432: 1547, 1547, 1547, 1547, 1547, 521: 2765, 988: 3321},\n\t\t{1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 363: 1552, 1552, 1552, 1552, 1552, 1552, 374: 1552, 1552, 377: 1552, 1552, 1552, 1552, 1552, 1552, 1552, 385: 1552, 1552, 388: 1552, 1552, 1552, 1552, 1552, 396: 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 408: 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 426: 1552, 1552, 1552, 1552, 1552, 432: 1552, 1552, 1552, 1552, 1552},\n\t\t{363: 3323},\n\t\t// 1300\n\t\t{1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 363: 1546, 1546, 1546, 1546, 1546, 1546, 374: 1546, 1546, 377: 1546, 1546, 1546, 1546, 1546, 1546, 1546, 385: 1546, 1546, 388: 1546, 1546, 1546, 1546, 1546, 396: 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 408: 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 426: 1546, 1546, 1546, 1546, 1546, 432: 1546, 1546, 1546, 1546, 1546},\n\t\t{370: 3062, 3063, 3068, 382: 3325, 406: 3064, 439: 3066, 3059, 3065, 3069, 3058, 3067, 3060, 3061},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 3326},\n\t\t{1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 363: 1553, 1553, 1553, 1553, 1553, 1553, 374: 1553, 1553, 377: 1553, 1553, 1553, 1553, 1553, 1553, 1553, 385: 1553, 1553, 388: 1553, 1553, 1553, 1553, 1553, 396: 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 408: 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 1553, 426: 1553, 1553, 1553, 1553, 1553, 432: 1553, 1553, 1553, 1553, 1553},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 3251, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 2053, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2960, 606: 3237, 2054, 2055, 2056, 613: 2059, 2058, 3238, 628: 3329},\n\t\t// 1305\n\t\t{1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 363: 1554, 1554, 1554, 1554, 1554, 1554, 374: 1554, 1554, 377: 1554, 1554, 1554, 1554, 1554, 1554, 1554, 385: 1554, 1554, 388: 1554, 1554, 1554, 1554, 1554, 396: 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 408: 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 1554, 426: 1554, 1554, 1554, 1554, 1554, 432: 1554, 1554, 1554, 1554, 1554},\n\t\t{9: 2962, 361: 3330},\n\t\t{1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 363: 1555, 1555, 1555, 1555, 1555, 1555, 374: 1555, 1555, 377: 1555, 1555, 1555, 1555, 1555, 1555, 1555, 385: 1555, 1555, 388: 1555, 1555, 1555, 1555, 1555, 396: 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 408: 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1555, 426: 1555, 1555, 1555, 1555, 1555, 432: 1555, 1555, 1555, 1555, 1555},\n\t\t{2: 1567, 1567, 1567, 1567, 1567, 1567, 1567, 10: 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 362: 1567, 1567, 366: 1567, 1567, 370: 1567, 1567, 1567, 1567, 384: 1567, 387: 1567, 393: 1567, 1567, 407: 1567, 431: 1567, 438: 1567, 447: 1567, 450: 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567, 1567},\n\t\t{362: 1563},\n\t\t// 1310\n\t\t{2: 1561, 1561, 1561, 1561, 1561, 1561, 1561, 10: 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 362: 1561, 1561, 366: 1561, 1561, 370: 1561, 1561, 1561, 1561, 384: 1561, 387: 1561, 393: 1561, 1561, 407: 1561, 431: 1561, 438: 1561, 447: 1561, 450: 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561},\n\t\t{2: 1559, 1559, 1559, 1559, 1559, 1559, 1559, 10: 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 362: 1559, 1559, 366: 1559, 1559, 370: 1559, 1559, 1559, 1559, 384: 1559, 387: 1559, 393: 1559, 1559, 407: 1559, 431: 1559, 438: 1559, 447: 1559, 450: 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559},\n\t\t{141: 3358, 394: 3359, 461: 3357, 3356},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 3350, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 3351, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 3349, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 3347, 600: 3352, 939: 3348},\n\t\t{2: 1576, 1576, 1576, 1576, 1576, 1576, 1576, 10: 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 362: 1576, 1576, 366: 1576, 1576, 370: 1576, 1576, 1576, 1576, 384: 1576, 387: 1576, 393: 1576, 1576, 407: 1576, 431: 1576, 438: 1576, 447: 1576, 450: 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 600: 1576},\n\t\t// 1315\n\t\t{2: 1575, 1575, 1575, 1575, 1575, 1575, 1575, 10: 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 362: 1575, 1575, 366: 1575, 1575, 370: 1575, 1575, 1575, 1575, 384: 1575, 387: 1575, 393: 1575, 1575, 407: 1575, 431: 1575, 438: 1575, 447: 1575, 450: 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 1575, 600: 1575},\n\t\t{2: 1574, 1574, 1574, 1574, 1574, 1574, 1574, 10: 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 362: 1574, 1574, 366: 1574, 1574, 370: 1574, 1574, 1574, 1574, 384: 1574, 387: 1574, 393: 1574, 1574, 407: 1574, 431: 1574, 438: 1574, 447: 1574, 450: 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 600: 1574},\n\t\t{2: 1573, 1573, 1573, 1573, 1573, 1573, 1573, 10: 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 362: 1573, 1573, 366: 1573, 1573, 370: 1573, 1573, 1573, 1573, 384: 1573, 387: 1573, 393: 1573, 1573, 407: 1573, 431: 1573, 438: 1573, 447: 1573, 450: 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 600: 1573},\n\t\t{2: 1572, 1572, 1572, 1572, 1572, 1572, 1572, 10: 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 362: 1572, 1572, 366: 1572, 1572, 370: 1572, 1572, 1572, 1572, 384: 1572, 387: 1572, 393: 1572, 1572, 407: 1572, 431: 1572, 438: 1572, 447: 1572, 450: 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1572, 600: 1572},\n\t\t{2: 1571, 1571, 1571, 1571, 1571, 1571, 1571, 10: 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 362: 1571, 1571, 366: 1571, 1571, 370: 1571, 1571, 1571, 1571, 384: 1571, 387: 1571, 393: 1571, 1571, 407: 1571, 431: 1571, 438: 1571, 447: 1571, 450: 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 1571, 600: 1571},\n\t\t// 1320\n\t\t{2: 1570, 1570, 1570, 1570, 1570, 1570, 1570, 10: 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 362: 1570, 1570, 366: 1570, 1570, 370: 1570, 1570, 1570, 1570, 384: 1570, 387: 1570, 393: 1570, 1570, 407: 1570, 431: 1570, 438: 1570, 447: 1570, 450: 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 1570, 600: 1570},\n\t\t{2: 1569, 1569, 1569, 1569, 1569, 1569, 1569, 10: 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 362: 1569, 1569, 366: 1569, 1569, 370: 1569, 1569, 1569, 1569, 384: 1569, 387: 1569, 393: 1569, 1569, 407: 1569, 431: 1569, 438: 1569, 447: 1569, 450: 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 1569, 600: 1569},\n\t\t{141: 1566, 369: 3346, 394: 1566, 461: 1566, 1566},\n\t\t{141: 1565, 394: 1565, 461: 1565, 1565},\n\t\t{1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 363: 1580, 1580, 1580, 1580, 1580, 1580, 374: 1580, 1580, 377: 1580, 1580, 1580, 1580, 1580, 1580, 1580, 385: 1580, 1580, 388: 1580, 1580, 1580, 1580, 1580, 396: 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 408: 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 1580, 426: 1580, 1580, 1580, 1580, 1580, 432: 1580, 1580, 1580, 1580, 1580},\n\t\t// 1325\n\t\t{362: 3236, 574: 3355},\n\t\t{618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 363: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 374: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 385: 618, 618, 388: 618, 618, 618, 618, 618, 396: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 408: 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 432: 618, 618, 618, 618, 618, 618, 439: 618, 618, 618, 618, 618, 618, 618, 618, 448: 618, 618, 521: 618, 548: 3353},\n\t\t{1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1558, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 374: 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 385: 1407, 1407, 388: 1407, 1407, 1407, 1407, 1407, 396: 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 432: 1407, 1407, 1407, 1407, 1407, 1407, 439: 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 448: 1407, 1407, 521: 1407, 542: 1407, 1407},\n\t\t{1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1557, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 374: 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 385: 1406, 1406, 388: 1406, 1406, 1406, 1406, 1406, 396: 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 432: 1406, 1406, 1406, 1406, 1406, 1406, 439: 1406, 1406, 1406, 1406, 1406, 1406, 1406, 1406, 448: 1406, 1406, 521: 1406, 542: 1406, 1406},\n\t\t{362: 1556},\n\t\t// 1330\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 3354},\n\t\t{1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 363: 1578, 1578, 1578, 1578, 1578, 1578, 374: 1578, 1578, 377: 1578, 1578, 1578, 1578, 1578, 1578, 1578, 385: 1578, 1578, 388: 1578, 1578, 1578, 1578, 1578, 396: 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 408: 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 426: 1578, 1578, 1578, 1578, 1578, 432: 1578, 1578, 1578, 1578, 1578},\n\t\t{1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 363: 1579, 1579, 1579, 1579, 1579, 1579, 374: 1579, 1579, 377: 1579, 1579, 1579, 1579, 1579, 1579, 1579, 385: 1579, 1579, 388: 1579, 1579, 1579, 1579, 1579, 396: 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 408: 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 426: 1579, 1579, 1579, 1579, 1579, 432: 1579, 1579, 1579, 1579, 1579},\n\t\t{1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 363: 1605, 1605, 1605, 1605, 1605, 1605, 374: 1605, 1605, 377: 1605, 1605, 1605, 1605, 1605, 1605, 1605, 385: 1605, 1605, 388: 1605, 1605, 1605, 392: 1605, 396: 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 408: 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605, 426: 1605, 1605},\n\t\t{1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 363: 1604, 1604, 1604, 1604, 1604, 1604, 374: 1604, 1604, 377: 1604, 1604, 1604, 1604, 1604, 1604, 1604, 385: 1604, 1604, 388: 1604, 1604, 1604, 392: 1604, 396: 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 408: 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 1604, 426: 1604, 1604},\n\t\t// 1335\n\t\t{1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 363: 1603, 1603, 1603, 1603, 1603, 1603, 374: 1603, 1603, 377: 1603, 1603, 1603, 1603, 1603, 1603, 1603, 385: 1603, 1603, 388: 1603, 1603, 1603, 392: 1603, 396: 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 408: 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 1603, 426: 1603, 1603},\n\t\t{1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 363: 1581, 1581, 1581, 1581, 1581, 1581, 374: 1581, 1581, 377: 1581, 1581, 1581, 1581, 1581, 1581, 1581, 385: 1581, 1581, 388: 1581, 1581, 1581, 1581, 1581, 396: 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 408: 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 1581, 426: 1581, 1581, 1581, 1581, 1581, 432: 1581, 1581, 1581, 1581, 1581},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3362, 659: 3363},\n\t\t{1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 391: 1875, 1875, 395: 1875, 407: 3384, 411: 1875, 1875, 553: 1875, 1875, 556: 1875, 561: 1875, 1875, 565: 1875, 569: 1875},\n\t\t{9: 1866, 361: 1866},\n\t\t// 1340\n\t\t{9: 3364, 361: 3365},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3383},\n\t\t{207: 3366},\n\t\t{362: 3367},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 3368},\n\t\t// 1345\n\t\t{361: 1599, 368: 3371, 370: 3062, 3063, 3068, 406: 3064, 425: 3370, 439: 3066, 3059, 3065, 3069, 3058, 3067, 3060, 3061, 973: 3369},\n\t\t{361: 3382},\n\t\t{209: 3375, 401: 3374},\n\t\t{92: 3372},\n\t\t{162: 3373},\n\t\t// 1350\n\t\t{361: 1595},\n\t\t{243: 3377},\n\t\t{130: 3376},\n\t\t{361: 1596},\n\t\t{130: 3378},\n\t\t// 1355\n\t\t{361: 1598, 368: 3379},\n\t\t{92: 3380},\n\t\t{162: 3381},\n\t\t{361: 1597},\n\t\t{1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 363: 1606, 1606, 1606, 1606, 1606, 1606, 374: 1606, 1606, 377: 1606, 1606, 1606, 1606, 1606, 1606, 1606, 385: 1606, 1606, 388: 1606, 1606, 1606, 392: 1606, 396: 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 408: 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 426: 1606, 1606},\n\t\t// 1360\n\t\t{9: 1865, 361: 1865},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3385, 2178, 2179, 2177},\n\t\t{1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874, 391: 1874, 1874, 395: 1874, 407: 3386, 411: 1874, 1874, 553: 1874, 1874, 556: 1874, 561: 1874, 1874, 565: 1874, 569: 1874},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3387, 2178, 2179, 2177},\n\t\t{1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 1873, 391: 1873, 1873, 395: 1873, 411: 1873, 1873, 553: 1873, 1873, 556: 1873, 561: 1873, 1873, 565: 1873, 569: 1873},\n\t\t// 1365\n\t\t{1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 363: 1607, 1607, 1607, 1607, 1607, 1607, 374: 1607, 1607, 377: 1607, 1607, 1607, 1607, 1607, 1607, 1607, 385: 1607, 1607, 388: 1607, 1607, 1607, 392: 1607, 396: 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 408: 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 426: 1607, 1607, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3390},\n\t\t{1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 363: 1611, 1611, 1611, 1611, 1611, 1611, 374: 1611, 1611, 377: 1611, 1611, 1611, 1611, 1611, 2760, 1611, 385: 2758, 2759, 388: 2757, 2755, 1611, 392: 1611, 396: 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 408: 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611, 426: 1611, 1611, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 407: 2604, 537: 2603, 2178, 2179, 2177, 576: 2607, 852: 3392},\n\t\t{57, 57, 9: 57},\n\t\t// 1370\n\t\t{407: 3394},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3395, 2178, 2179, 2177},\n\t\t{1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 363: 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 374: 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 385: 1067, 1067, 388: 1067, 1067, 1067, 1067, 1067, 396: 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 408: 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 432: 1067, 1067, 1067, 1067, 1067, 1067, 439: 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067, 448: 1067, 1067, 521: 1067, 542: 1067, 1067},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3397, 2178, 2179, 2177},\n\t\t{1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 363: 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 374: 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 385: 1068, 1068, 388: 1068, 1068, 1068, 1068, 1068, 396: 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 3398, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 432: 1068, 1068, 1068, 1068, 1068, 1068, 439: 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 448: 1068, 1068, 521: 1068, 542: 1068, 1068},\n\t\t// 1375\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3399, 2178, 2179, 2177},\n\t\t{1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 363: 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 374: 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 385: 1066, 1066, 388: 1066, 1066, 1066, 1066, 1066, 396: 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 408: 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 432: 1066, 1066, 1066, 1066, 1066, 1066, 439: 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 448: 1066, 1066, 521: 1066, 542: 1066, 1066},\n\t\t{9: 3406, 361: 1861},\n\t\t{9: 1860, 361: 1860},\n\t\t{9: 1858, 361: 1858},\n\t\t// 1380\n\t\t{9: 1857, 361: 1857},\n\t\t{361: 3405},\n\t\t{1855, 1855, 392: 1855},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 447: 2763, 537: 3361, 2178, 2179, 2177, 575: 3403, 603: 3402, 789: 3407},\n\t\t{9: 1859, 361: 1859},\n\t\t// 1385\n\t\t{606, 606, 9: 606, 390: 606, 447: 1502, 545: 606, 552: 1502},\n\t\t{9: 128, 362: 128, 364: 128, 447: 1459, 552: 1459},\n\t\t{9: 115, 362: 115, 364: 115, 447: 1456, 552: 1456},\n\t\t{9: 105, 362: 105, 364: 105, 447: 1430, 552: 1430},\n\t\t{9: 124, 362: 124, 364: 124, 447: 1356, 552: 1356},\n\t\t// 1390\n\t\t{9: 129, 362: 129, 364: 129, 447: 1349, 552: 1349},\n\t\t{147: 3514, 188: 3513, 447: 1331, 552: 1331},\n\t\t{9: 116, 362: 116, 364: 116, 447: 1328, 552: 1328},\n\t\t{9: 106, 362: 106, 364: 106, 447: 1325, 552: 1325},\n\t\t{607, 607, 9: 607, 390: 607, 447: 219, 545: 607, 552: 219},\n\t\t// 1395\n\t\t{605, 605, 9: 605, 390: 605, 545: 605},\n\t\t{447: 3526, 552: 3525},\n\t\t{602, 602, 9: 602, 390: 602, 545: 602},\n\t\t{9: 3518, 390: 3519},\n\t\t{9: 141, 362: 3515, 364: 141},\n\t\t// 1400\n\t\t{9: 139, 364: 139},\n\t\t{9: 3462, 364: 3463},\n\t\t{9: 137, 109: 3461, 362: 137, 364: 137},\n\t\t{9: 135, 183: 3460, 362: 135, 364: 135},\n\t\t{9: 134, 51: 3456, 99: 3457, 101: 3454, 112: 3455, 183: 3458, 362: 134, 364: 134},\n\t\t// 1405\n\t\t{9: 132, 362: 132, 364: 132},\n\t\t{9: 131, 362: 131, 364: 131},\n\t\t{9: 130, 99: 3453, 362: 130, 364: 130},\n\t\t{9: 127, 362: 127, 364: 127},\n\t\t{9: 126, 362: 126, 364: 126},\n\t\t// 1410\n\t\t{9: 125, 222: 3452, 266: 3445, 3451, 3450, 3449, 3446, 3447, 281: 3448, 362: 125, 364: 125},\n\t\t{9: 96, 51: 3444, 362: 96, 364: 96, 800: 3443},\n\t\t{9: 122, 362: 122, 364: 122},\n\t\t{729: 3442},\n\t\t{9: 120, 362: 120, 364: 120},\n\t\t// 1415\n\t\t{9: 117, 362: 117, 364: 117},\n\t\t{57: 3441},\n\t\t{9: 95, 362: 95, 364: 95},\n\t\t{9: 113, 362: 113, 364: 113},\n\t\t{9: 121, 362: 121, 364: 121},\n\t\t// 1420\n\t\t{9: 123, 362: 123, 364: 123},\n\t\t{9: 111, 362: 111, 364: 111},\n\t\t{9: 104, 362: 104, 364: 104},\n\t\t{9: 103, 362: 103, 364: 103},\n\t\t{9: 102, 362: 102, 364: 102},\n\t\t// 1425\n\t\t{9: 101, 362: 101, 364: 101},\n\t\t{9: 100, 362: 100, 364: 100},\n\t\t{9: 99, 362: 99, 364: 99},\n\t\t{9: 98, 362: 98, 364: 98},\n\t\t{9: 97, 362: 97, 364: 97},\n\t\t// 1430\n\t\t{9: 109, 362: 109, 364: 109},\n\t\t{9: 133, 362: 133, 364: 133},\n\t\t{57: 3459},\n\t\t{9: 112, 362: 112, 364: 112},\n\t\t{9: 110, 362: 110, 364: 110},\n\t\t// 1435\n\t\t{9: 108, 362: 108, 364: 108},\n\t\t{9: 114, 362: 114, 364: 114},\n\t\t{9: 107, 362: 107, 364: 107},\n\t\t{9: 136, 362: 136, 364: 136},\n\t\t{123: 3506, 137: 3512, 181: 3509, 224: 3511, 231: 3510, 272: 3505, 280: 3508, 292: 3507, 379: 3439, 451: 3432, 524: 3433, 3431, 534: 3437, 554: 3430, 558: 3426, 3427, 600: 3425, 616: 3435, 3429, 686: 3436, 695: 3434, 701: 3440, 760: 3504, 3422, 771: 3428, 3438},\n\t\t// 1440\n\t\t{2: 94, 94, 94, 94, 94, 94, 94, 10: 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 406: 94, 605: 3464, 861: 3465},\n\t\t{2: 93, 93, 93, 93, 93, 93, 93, 10: 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 406: 93},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 406: 3466, 537: 3467, 2178, 2179, 2177, 886: 3468},\n\t\t{390: 92, 407: 3502, 545: 92},\n\t\t{390: 88, 407: 3499, 545: 88},\n\t\t// 1445\n\t\t{390: 3469},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3472, 712: 3473, 739: 3474},\n\t\t{617, 617, 9: 617, 51: 617, 56: 617, 60: 617, 368: 617, 375: 617, 391: 617, 447: 3497, 547: 617, 551: 617, 3496},\n\t\t{995, 995, 9: 995, 51: 995, 56: 995, 60: 995, 362: 3148, 368: 995, 375: 995, 391: 995, 547: 995, 551: 995, 871: 3495},\n\t\t{158, 158, 9: 158, 56: 3478, 60: 158, 368: 158, 547: 158, 1020: 3477},\n\t\t// 1450\n\t\t{204, 204, 9: 204, 368: 204, 547: 204},\n\t\t{87, 87, 9: 3475},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3472, 712: 3476},\n\t\t{203, 203, 9: 203, 368: 203, 547: 203},\n\t\t{164, 164, 9: 164, 60: 3482, 368: 164, 547: 164, 941: 3481},\n\t\t// 1455\n\t\t{363: 3479, 1021: 3480},\n\t\t{608, 608, 9: 608, 60: 608, 368: 608, 547: 608},\n\t\t{157, 157, 9: 157, 60: 157, 368: 157, 547: 157},\n\t\t{205, 205, 9: 205, 368: 205, 547: 205},\n\t\t{368: 3484, 546: 3483},\n\t\t// 1460\n\t\t{18: 3493, 363: 3490, 714: 3492},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 3485},\n\t\t{162, 162, 9: 162, 368: 162, 374: 3487, 546: 3486, 162},\n\t\t{363: 3490, 714: 3491},\n\t\t{363: 3489, 837: 3488},\n\t\t// 1465\n\t\t{160, 160, 9: 160, 368: 160, 547: 160},\n\t\t{156, 156, 9: 156, 368: 156, 547: 156},\n\t\t{609, 609, 9: 609, 361: 609, 368: 609, 547: 609},\n\t\t{161, 161, 9: 161, 368: 161, 547: 161},\n\t\t{163, 163, 9: 163, 368: 163, 547: 163},\n\t\t// 1470\n\t\t{363: 3489, 837: 3494},\n\t\t{159, 159, 9: 159, 368: 159, 547: 159},\n\t\t{614, 614, 9: 614, 51: 614, 56: 614, 60: 614, 368: 614, 375: 614, 391: 614, 547: 614, 551: 614},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 3498},\n\t\t{615, 615, 9: 615, 51: 615, 56: 615, 60: 615, 368: 615, 375: 615, 391: 615, 547: 615, 551: 615},\n\t\t// 1475\n\t\t{616, 616, 9: 616, 51: 616, 56: 616, 60: 616, 368: 616, 375: 616, 391: 616, 547: 616, 551: 616},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 406: 3500, 537: 3501, 2178, 2179, 2177},\n\t\t{390: 90, 545: 90},\n\t\t{390: 89, 545: 89},\n\t\t{406: 3503},\n\t\t// 1480\n\t\t{390: 91, 545: 91},\n\t\t{9: 138, 364: 138},\n\t\t{9: 129, 362: 129, 364: 129},\n\t\t{9: 128, 362: 128, 364: 128},\n\t\t{9: 124, 362: 124, 364: 124},\n\t\t// 1485\n\t\t{147: 3514, 188: 3513},\n\t\t{9: 116, 362: 116, 364: 116},\n\t\t{9: 115, 362: 115, 364: 115},\n\t\t{9: 106, 362: 106, 364: 106},\n\t\t{9: 105, 362: 105, 364: 105},\n\t\t// 1490\n\t\t{9: 119, 362: 119, 364: 119},\n\t\t{9: 118, 362: 118, 364: 118},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3362, 659: 3516},\n\t\t{9: 3364, 361: 3517},\n\t\t{9: 140, 364: 140},\n\t\t// 1495\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 537: 2569, 2178, 2179, 2177, 601: 3419, 643: 3524, 3418},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3520, 711: 3521},\n\t\t{613, 613, 9: 613},\n\t\t{86, 86, 9: 3522},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3523},\n\t\t// 1500\n\t\t{612, 612, 9: 612},\n\t\t{601, 601, 9: 601, 390: 601, 545: 601},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 3527},\n\t\t{603, 603, 9: 603, 390: 603, 545: 603},\n\t\t{604, 604, 9: 604, 390: 604, 545: 604},\n\t\t// 1505\n\t\t{9: 3518, 545: 3564},\n\t\t{9: 3462, 364: 3530},\n\t\t{2: 94, 94, 94, 94, 94, 94, 94, 10: 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 406: 94, 605: 3464, 861: 3531},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 406: 3466, 537: 3467, 2178, 2179, 2177, 886: 3532},\n\t\t{545: 3533},\n\t\t// 1510\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3472, 712: 3473, 739: 3534},\n\t\t{188, 188, 9: 3475, 368: 188, 547: 3536, 763: 3535, 3537},\n\t\t{187, 187, 368: 187},\n\t\t{79: 3557, 3555, 82: 3556, 257: 3550, 307: 3552, 765: 3554, 1031: 3553, 1051: 3551},\n\t\t{147, 147, 368: 3539, 1091: 3538},\n\t\t// 1515\n\t\t{149, 149},\n\t\t{251: 3543, 3541, 3542, 3544, 686: 3540},\n\t\t{729: 3549},\n\t\t{393: 2147, 598: 3548},\n\t\t{393: 2147, 598: 3547},\n\t\t// 1520\n\t\t{393: 2147, 598: 3546},\n\t\t{393: 2147, 598: 3545},\n\t\t{142, 142},\n\t\t{143, 143},\n\t\t{144, 144},\n\t\t// 1525\n\t\t{145, 145},\n\t\t{146, 146},\n\t\t{186, 186, 368: 186},\n\t\t{185, 185, 368: 185},\n\t\t{184, 184, 368: 184},\n\t\t// 1530\n\t\t{183, 183, 79: 3557, 3555, 82: 3556, 368: 183, 382: 3561, 765: 3562},\n\t\t{182, 182, 79: 182, 182, 82: 182, 368: 182, 382: 182},\n\t\t{363: 3560},\n\t\t{363: 3559},\n\t\t{363: 3558},\n\t\t// 1535\n\t\t{177, 177, 79: 177, 177, 82: 177, 368: 177, 382: 177},\n\t\t{178, 178, 79: 178, 178, 82: 178, 368: 178, 382: 178},\n\t\t{179, 179, 79: 179, 179, 82: 179, 368: 179, 382: 179},\n\t\t{79: 3557, 3555, 82: 3556, 765: 3563},\n\t\t{180, 180, 79: 180, 180, 82: 180, 368: 180, 382: 180},\n\t\t// 1540\n\t\t{181, 181, 79: 181, 181, 82: 181, 368: 181, 382: 181},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3520, 711: 3565},\n\t\t{148, 148, 9: 3522},\n\t\t{1752, 1752, 7: 1752, 12: 1752, 373: 1752, 376: 1752, 1752, 383: 1752, 387: 1752, 405: 1752, 526: 1752},\n\t\t{215, 215},\n\t\t// 1545\n\t\t{2: 711, 711, 711, 711, 711, 711, 711, 10: 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 362: 711, 711, 366: 711, 711, 369: 711, 711, 711, 711, 711, 384: 711, 387: 711, 390: 711, 393: 711, 711, 396: 711, 406: 711, 711, 431: 711, 438: 711, 447: 711, 450: 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 711, 522: 711, 711, 600: 711, 612: 711, 620: 711, 711, 711, 711, 711, 711, 635: 711},\n\t\t{2: 865, 865, 865, 865, 865, 865, 865, 10: 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 362: 865, 452: 865, 522: 865, 620: 3572, 623: 3571, 3570, 709: 3573},\n\t\t{2: 864, 864, 864, 864, 864, 864, 864, 10: 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 362: 864, 864, 366: 864, 864, 369: 864, 864, 864, 864, 864, 380: 864, 384: 864, 387: 864, 390: 864, 393: 864, 864, 396: 864, 406: 864, 864, 431: 864, 438: 864, 447: 864, 450: 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 522: 864, 864, 612: 864, 625: 864, 635: 864},\n\t\t{2: 863, 863, 863, 863, 863, 863, 863, 10: 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 362: 863, 863, 366: 863, 863, 369: 863, 863, 863, 863, 863, 380: 863, 384: 863, 387: 863, 390: 863, 393: 863, 863, 396: 863, 406: 863, 863, 431: 863, 438: 863, 447: 863, 450: 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 863, 522: 863, 863, 612: 863, 625: 863, 635: 863},\n\t\t{2: 862, 862, 862, 862, 862, 862, 862, 10: 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 362: 862, 862, 366: 862, 862, 369: 862, 862, 862, 862, 862, 380: 862, 384: 862, 387: 862, 390: 862, 393: 862, 862, 396: 862, 406: 862, 862, 431: 862, 438: 862, 447: 862, 450: 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 522: 862, 862, 612: 862, 625: 862, 635: 862},\n\t\t// 1550\n\t\t{2: 1525, 1525, 1525, 1525, 1525, 1525, 1525, 10: 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 362: 1525, 452: 1525, 522: 3574, 723: 3575},\n\t\t{2: 1524, 1524, 1524, 1524, 1524, 1524, 1524, 10: 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 362: 1524, 380: 1524, 390: 1524, 452: 1524, 605: 1524},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 452: 3579, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3578, 674: 3576, 697: 3577},\n\t\t{770, 770, 9: 770, 361: 770, 364: 770, 770, 368: 770, 375: 770, 377: 770, 770, 770, 770, 770, 383: 770, 392: 770, 397: 770, 770, 400: 770},\n\t\t{9: 3635, 392: 3697},\n\t\t// 1555\n\t\t{9: 768, 366: 3602, 3603, 392: 3679, 396: 3601, 399: 3604, 401: 3600, 3605, 3606, 655: 3599, 660: 3598},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3676, 2178, 2179, 2177},\n\t\t{766, 766, 9: 766, 361: 766, 364: 766, 766, 766, 766, 766, 375: 766, 377: 766, 766, 766, 766, 766, 383: 766, 392: 766, 396: 766, 766, 766, 766, 766, 766, 766, 766, 766},\n\t\t{765, 765, 9: 765, 361: 765, 364: 765, 765, 765, 765, 765, 375: 765, 377: 765, 765, 765, 765, 765, 383: 765, 392: 765, 396: 765, 765, 765, 765, 765, 765, 765, 765, 765},\n\t\t{760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, 364: 760, 760, 760, 760, 760, 374: 760, 760, 377: 760, 760, 760, 760, 760, 383: 760, 392: 760, 395: 3639, 760, 760, 760, 760, 760, 760, 760, 760, 760, 522: 760, 549: 760, 760, 878: 3638},\n\t\t// 1560\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3586, 452: 3579, 524: 2053, 537: 2537, 2178, 2179, 2177, 599: 3582, 606: 3587, 2054, 2055, 2056, 613: 2059, 2058, 3588, 632: 3581, 636: 3580, 3585, 674: 3576, 697: 3584},\n\t\t{9: 3635, 361: 3636},\n\t\t{768, 768, 9: 768, 361: 768, 364: 768, 768, 3602, 3603, 768, 375: 768, 377: 768, 768, 768, 768, 768, 383: 768, 392: 768, 396: 3601, 768, 768, 3604, 768, 3600, 3605, 3606, 655: 3599, 660: 3598},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3586, 452: 3579, 524: 2053, 537: 2537, 2178, 2179, 2177, 599: 3582, 606: 3596, 2054, 2055, 2056, 613: 2059, 2058, 3588, 632: 3581, 636: 3580, 3585, 674: 3576, 697: 3584},\n\t\t{361: 3594, 365: 674},\n\t\t// 1565\n\t\t{361: 3589},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 374: 3592, 537: 3591, 2178, 2179, 2177, 710: 3590},\n\t\t{762, 762, 9: 762, 361: 762, 364: 762, 762, 762, 762, 762, 375: 762, 377: 762, 762, 762, 762, 762, 383: 762, 392: 762, 396: 762, 762, 762, 762, 762, 762, 762, 762, 762},\n\t\t{756, 756, 9: 756, 361: 756, 364: 756, 756, 756, 756, 756, 375: 756, 377: 756, 756, 756, 756, 756, 383: 756, 392: 756, 396: 756, 756, 756, 756, 756, 756, 756, 756, 756, 522: 756, 549: 756, 756},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3593, 2178, 2179, 2177},\n\t\t// 1570\n\t\t{755, 755, 9: 755, 361: 755, 364: 755, 755, 755, 755, 755, 375: 755, 377: 755, 755, 755, 755, 755, 383: 755, 392: 755, 396: 755, 755, 755, 755, 755, 755, 755, 755, 755, 522: 755, 549: 755, 755},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 374: 3592, 537: 3591, 2178, 2179, 2177, 710: 3595},\n\t\t{763, 763, 9: 763, 361: 763, 364: 763, 763, 763, 763, 763, 375: 763, 377: 763, 763, 763, 763, 763, 383: 763, 392: 763, 396: 763, 763, 763, 763, 763, 763, 763, 763, 763},\n\t\t{361: 3597, 365: 674},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 365: 673, 374: 3592, 537: 3591, 2178, 2179, 2177, 710: 3595},\n\t\t// 1575\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3628},\n\t\t{399: 726, 732: 3615, 874: 3619},\n\t\t{366: 3602, 3603, 399: 3612, 655: 3613},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3609},\n\t\t{399: 728, 732: 728},\n\t\t// 1580\n\t\t{399: 727, 732: 727},\n\t\t{2: 724, 724, 724, 724, 724, 724, 724, 10: 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 362: 724},\n\t\t{399: 3608},\n\t\t{399: 3607},\n\t\t{2: 722, 722, 722, 722, 722, 722, 722, 10: 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 362: 722},\n\t\t// 1585\n\t\t{2: 723, 723, 723, 723, 723, 723, 723, 10: 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 723, 362: 723},\n\t\t{730, 730, 9: 730, 361: 730, 364: 3610, 730, 730, 730, 730, 375: 730, 377: 730, 730, 730, 730, 730, 383: 730, 392: 730, 396: 730, 730, 730, 730, 730, 730, 730, 730, 730, 655: 3599, 660: 3598},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3611},\n\t\t{729, 729, 9: 729, 361: 729, 364: 729, 729, 729, 729, 729, 375: 729, 377: 729, 729, 729, 729, 729, 2760, 729, 385: 2758, 2759, 388: 2757, 2755, 392: 729, 396: 729, 729, 729, 729, 729, 729, 729, 729, 729, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3618},\n\t\t// 1590\n\t\t{399: 726, 732: 3615, 874: 3614},\n\t\t{399: 3616},\n\t\t{399: 725},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3617},\n\t\t{731, 731, 9: 731, 361: 731, 364: 731, 731, 731, 731, 731, 375: 731, 377: 731, 731, 731, 731, 731, 383: 731, 392: 731, 396: 731, 731, 731, 731, 731, 731, 731, 731, 731, 655: 3599, 660: 3598},\n\t\t// 1595\n\t\t{732, 732, 9: 732, 361: 732, 364: 732, 732, 732, 732, 732, 375: 732, 377: 732, 732, 732, 732, 732, 383: 732, 392: 732, 396: 732, 732, 732, 732, 732, 732, 732, 732, 732, 655: 3599, 660: 3598},\n\t\t{399: 3620},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3621},\n\t\t{364: 3622, 366: 3602, 3603, 375: 3623, 396: 3601, 399: 3604, 401: 3600, 3605, 3606, 655: 3599, 660: 3598},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3627},\n\t\t// 1600\n\t\t{362: 3624},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3362, 659: 3625},\n\t\t{9: 3364, 361: 3626},\n\t\t{733, 733, 9: 733, 361: 733, 364: 733, 733, 733, 733, 733, 375: 733, 377: 733, 733, 733, 733, 733, 383: 733, 392: 733, 396: 733, 733, 733, 733, 733, 733, 733, 733, 733},\n\t\t{734, 734, 9: 734, 361: 734, 364: 734, 734, 734, 734, 734, 375: 734, 377: 734, 734, 734, 734, 734, 2760, 734, 385: 2758, 2759, 388: 2757, 2755, 392: 734, 396: 734, 734, 734, 734, 734, 734, 734, 734, 734, 596: 2756, 2754},\n\t\t// 1605\n\t\t{737, 737, 9: 737, 361: 737, 364: 3629, 737, 737, 737, 737, 375: 3630, 377: 737, 737, 737, 737, 737, 383: 737, 392: 737, 396: 737, 737, 737, 737, 737, 737, 737, 737, 737, 655: 3599, 660: 3598},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3634},\n\t\t{362: 3631},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3362, 659: 3632},\n\t\t{9: 3364, 361: 3633},\n\t\t// 1610\n\t\t{735, 735, 9: 735, 361: 735, 364: 735, 735, 735, 735, 735, 375: 735, 377: 735, 735, 735, 735, 735, 383: 735, 392: 735, 396: 735, 735, 735, 735, 735, 735, 735, 735, 735},\n\t\t{736, 736, 9: 736, 361: 736, 364: 736, 736, 736, 736, 736, 375: 736, 377: 736, 736, 736, 736, 736, 2760, 736, 385: 2758, 2759, 388: 2757, 2755, 392: 736, 396: 736, 736, 736, 736, 736, 736, 736, 736, 736, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 452: 3579, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3585, 674: 3637},\n\t\t{761, 761, 9: 761, 361: 761, 364: 761, 761, 761, 761, 761, 375: 761, 377: 761, 761, 761, 761, 761, 383: 761, 392: 761, 396: 761, 761, 761, 761, 761, 761, 761, 761, 761},\n\t\t{769, 769, 9: 769, 361: 769, 364: 769, 769, 368: 769, 375: 769, 377: 769, 769, 769, 769, 769, 383: 769, 392: 769, 397: 769, 769, 400: 769},\n\t\t// 1615\n\t\t{758, 758, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 758, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 758, 364: 758, 758, 758, 758, 758, 374: 3592, 758, 377: 758, 758, 758, 758, 758, 383: 758, 392: 758, 396: 758, 758, 758, 758, 758, 758, 758, 758, 758, 522: 758, 537: 3591, 2178, 2179, 2177, 549: 758, 758, 710: 3647, 913: 3646},\n\t\t{362: 3640},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 634: 3642},\n\t\t{1937, 1937, 1937, 8: 1937, 1937, 361: 1937, 368: 1937, 380: 1937, 395: 1937, 525: 1937},\n\t\t{9: 3643, 361: 3644},\n\t\t// 1620\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3645, 2178, 2179, 2177},\n\t\t{759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 364: 759, 759, 759, 759, 759, 374: 759, 759, 377: 759, 759, 759, 759, 759, 383: 759, 392: 759, 396: 759, 759, 759, 759, 759, 759, 759, 759, 759, 437: 759, 522: 759, 525: 759, 546: 759, 549: 759, 759},\n\t\t{1936, 1936, 1936, 8: 1936, 1936, 361: 1936, 368: 1936, 380: 1936, 395: 1936, 525: 1936},\n\t\t{739, 739, 9: 739, 361: 739, 364: 739, 739, 739, 739, 739, 375: 739, 377: 739, 739, 739, 739, 739, 383: 739, 392: 739, 396: 739, 739, 739, 739, 739, 739, 739, 739, 739, 522: 3650, 549: 3651, 3649, 752: 3653, 3652, 839: 3654, 3648},\n\t\t{757, 757, 9: 757, 361: 757, 364: 757, 757, 757, 757, 757, 375: 757, 377: 757, 757, 757, 757, 757, 383: 757, 392: 757, 396: 757, 757, 757, 757, 757, 757, 757, 757, 757, 522: 757, 549: 757, 757},\n\t\t// 1625\n\t\t{764, 764, 9: 764, 361: 764, 364: 764, 764, 764, 764, 764, 375: 764, 377: 764, 764, 764, 764, 764, 383: 764, 392: 764, 396: 764, 764, 764, 764, 764, 764, 764, 764, 764},\n\t\t{525: 3672, 527: 3671, 665: 3675},\n\t\t{525: 3672, 527: 3671, 665: 3674},\n\t\t{525: 3672, 527: 3671, 665: 3673},\n\t\t{362: 751, 377: 3656, 980: 3657},\n\t\t// 1630\n\t\t{741, 741, 9: 741, 361: 741, 364: 741, 741, 741, 741, 741, 375: 741, 377: 741, 741, 741, 741, 741, 383: 741, 392: 741, 396: 741, 741, 741, 741, 741, 741, 741, 741, 741, 522: 741, 549: 741, 741},\n\t\t{738, 738, 9: 738, 361: 738, 364: 738, 738, 738, 738, 738, 375: 738, 377: 738, 738, 738, 738, 738, 383: 738, 392: 738, 396: 738, 738, 738, 738, 738, 738, 738, 738, 738, 522: 3650, 549: 3651, 3649, 752: 3655, 3652},\n\t\t{740, 740, 9: 740, 361: 740, 364: 740, 740, 740, 740, 740, 375: 740, 377: 740, 740, 740, 740, 740, 383: 740, 392: 740, 396: 740, 740, 740, 740, 740, 740, 740, 740, 740, 522: 740, 549: 740, 740},\n\t\t{378: 3667, 399: 3666, 3668},\n\t\t{362: 3658},\n\t\t// 1635\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 746, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 746, 529: 3661, 537: 3660, 2178, 2179, 2177, 688: 3659},\n\t\t{9: 3663, 361: 3662},\n\t\t{745, 745, 9: 745, 361: 745, 368: 745},\n\t\t{743, 743, 9: 743, 361: 743, 368: 743},\n\t\t{747, 747, 9: 747, 361: 747, 364: 747, 747, 747, 747, 747, 375: 747, 377: 747, 747, 747, 747, 747, 383: 747, 392: 747, 396: 747, 747, 747, 747, 747, 747, 747, 747, 747, 522: 747, 549: 747, 747},\n\t\t// 1640\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 529: 3665, 537: 3664, 2178, 2179, 2177},\n\t\t{744, 744, 9: 744, 361: 744, 368: 744},\n\t\t{742, 742, 9: 742, 361: 742, 368: 742},\n\t\t{362: 750},\n\t\t{546: 3670},\n\t\t// 1645\n\t\t{546: 3669},\n\t\t{362: 748},\n\t\t{362: 749},\n\t\t{2: 1950, 1950, 1950, 1950, 1950, 1950, 1950, 10: 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 1950, 362: 1950, 375: 1950, 377: 1950, 431: 1950},\n\t\t{2: 1949, 1949, 1949, 1949, 1949, 1949, 1949, 10: 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949, 362: 1949, 375: 1949, 377: 1949, 431: 1949},\n\t\t// 1650\n\t\t{362: 752, 377: 752},\n\t\t{362: 753, 377: 753},\n\t\t{362: 754, 377: 754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3677},\n\t\t{366: 3602, 3603, 396: 3601, 399: 3604, 401: 3600, 3605, 3606, 3678, 655: 3599, 660: 3598},\n\t\t// 1655\n\t\t{767, 767, 9: 767, 361: 767, 364: 767, 767, 368: 767, 375: 767, 377: 767, 767, 767, 767, 767, 383: 767, 392: 767, 397: 767, 767, 400: 767},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3680, 713: 3681, 741: 3682},\n\t\t{391: 3695},\n\t\t{1896, 1896, 9: 1896, 378: 1896, 381: 1896, 383: 1896},\n\t\t{213, 213, 9: 3683, 378: 213, 381: 213, 383: 3685, 645: 3686, 3684},\n\t\t// 1660\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3680, 713: 3694},\n\t\t{1086, 1086, 378: 2978, 381: 1086, 649: 2979, 3688},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3687},\n\t\t{212, 212, 361: 212, 364: 212, 212, 368: 212, 375: 212, 377: 212, 212, 212, 212, 212, 397: 212, 212, 400: 212},\n\t\t{214, 214, 361: 214, 364: 214, 214, 368: 214, 375: 214, 377: 214, 214, 214, 214, 214, 2760, 385: 2758, 2759, 388: 2757, 2755, 397: 214, 214, 400: 214, 596: 2756, 2754},\n\t\t// 1665\n\t\t{721, 721, 381: 3689, 849: 3690},\n\t\t{393: 2147, 455: 2656, 573: 3693, 598: 3183, 611: 3692, 725: 3691},\n\t\t{217, 217},\n\t\t{720, 720},\n\t\t{719, 719, 9: 719, 96: 719, 361: 719, 364: 719, 719, 368: 719, 375: 719, 377: 719, 379: 719, 719},\n\t\t// 1670\n\t\t{718, 718, 9: 718, 96: 718, 361: 718, 364: 718, 718, 368: 718, 375: 718, 377: 718, 379: 718, 718},\n\t\t{1895, 1895, 9: 1895, 378: 1895, 381: 1895, 383: 1895},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2643, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2610, 654: 3696},\n\t\t{1897, 1897, 9: 1897, 378: 1897, 381: 1897, 383: 1897},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3680, 713: 3681, 741: 3698},\n\t\t// 1675\n\t\t{213, 213, 9: 3683, 383: 3685, 645: 3686, 3699},\n\t\t{216, 216},\n\t\t{2: 345, 345, 345, 345, 345, 345, 345, 10: 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345, 345},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3702},\n\t\t{344, 344},\n\t\t// 1680\n\t\t{10: 3716, 57: 3707, 59: 3710, 85: 483, 109: 3709, 139: 3711, 164: 3712, 189: 3719, 438: 3715, 605: 3706, 719: 3717, 722: 3718, 917: 3714, 972: 3708, 996: 3713},\n\t\t{476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 476, 362: 476, 393: 476, 395: 476, 438: 476, 600: 476, 605: 476, 719: 476, 722: 476},\n\t\t{475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 362: 475, 393: 475, 395: 475, 438: 475, 600: 475, 605: 475, 719: 475, 722: 475},\n\t\t{1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 10: 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 368: 1634, 431: 1634},\n\t\t{1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 10: 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 1633, 368: 1633, 431: 1633},\n\t\t// 1685\n\t\t{492, 492},\n\t\t{489, 489},\n\t\t{488, 488},\n\t\t{132: 3730},\n\t\t{486, 486},\n\t\t// 1690\n\t\t{85: 3729},\n\t\t{474, 474, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 368: 474, 537: 2537, 2178, 2179, 2177, 599: 3720, 651: 3721, 916: 3722},\n\t\t{85: 482},\n\t\t{85: 481},\n\t\t{85: 480},\n\t\t// 1695\n\t\t{85: 479},\n\t\t{85: 478},\n\t\t{859, 859, 9: 859, 361: 859, 368: 859, 553: 859, 556: 859},\n\t\t{473, 473, 9: 3727, 361: 473, 368: 473},\n\t\t{472, 472, 368: 3724, 1092: 3723},\n\t\t// 1700\n\t\t{484, 484},\n\t\t{555: 3725},\n\t\t{379: 3726},\n\t\t{471, 471},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3728},\n\t\t// 1705\n\t\t{858, 858, 9: 858, 361: 858, 368: 858, 553: 858, 556: 858},\n\t\t{485, 485},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3731, 2178, 2179, 2177, 759: 3732},\n\t\t{491, 491, 9: 491},\n\t\t{487, 487, 9: 3733},\n\t\t// 1710\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3734, 2178, 2179, 2177},\n\t\t{490, 490, 9: 490},\n\t\t{503, 503, 383: 3802, 405: 3801, 696: 3874},\n\t\t{51: 3861, 93: 3863, 101: 3864, 464: 3862, 605: 3860},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 3851, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3852},\n\t\t// 1715\n\t\t{364: 3844},\n\t\t{59: 3843},\n\t\t{52: 2574, 2573, 57: 3838, 133: 3837, 675: 3839},\n\t\t{503, 503, 383: 3802, 405: 3801, 696: 3836},\n\t\t{503, 503, 383: 3802, 405: 3801, 696: 3835},\n\t\t// 1720\n\t\t{503, 503, 383: 3802, 405: 3801, 696: 3834},\n\t\t{503, 503, 383: 3802, 405: 3801, 696: 3833},\n\t\t{553, 553},\n\t\t{548, 548, 107: 3809, 145: 3810, 152: 3811, 154: 3808, 169: 3813, 177: 3812, 190: 3815, 194: 3814, 377: 548, 381: 548, 600: 3816, 900: 3807, 1046: 3806, 3805},\n\t\t{551, 551},\n\t\t// 1725\n\t\t{59: 3799},\n\t\t{549, 549},\n\t\t{390: 531, 425: 531},\n\t\t{390: 530, 425: 530},\n\t\t{390: 529, 425: 529},\n\t\t// 1730\n\t\t{526, 526, 383: 526, 405: 526},\n\t\t{525, 525, 383: 525, 405: 525},\n\t\t{524, 524, 383: 524, 405: 524},\n\t\t{57: 3797},\n\t\t{390: 3773, 425: 3774, 640: 3792},\n\t\t// 1735\n\t\t{52: 497, 497, 126: 3772, 869: 3786},\n\t\t{516, 516, 383: 516, 405: 516},\n\t\t{515, 515, 383: 515, 405: 515},\n\t\t{59: 3784, 87: 3785, 116: 3783},\n\t\t{511, 511, 383: 511, 405: 511},\n\t\t// 1740\n\t\t{495, 495, 383: 495, 390: 3773, 405: 495, 425: 3774, 640: 3776, 679: 3782},\n\t\t{59: 3781},\n\t\t{59: 3780},\n\t\t{59: 3779},\n\t\t{59: 3778},\n\t\t// 1745\n\t\t{495, 495, 383: 495, 390: 3773, 405: 495, 425: 3774, 640: 3776, 679: 3775},\n\t\t{504, 504, 383: 504, 405: 504},\n\t\t{59: 499, 87: 499, 90: 499, 116: 499},\n\t\t{59: 498, 87: 498, 90: 498, 116: 498},\n\t\t{52: 496, 496, 57: 496, 133: 496},\n\t\t// 1750\n\t\t{2: 528, 528, 528, 528, 528, 528, 528, 10: 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528},\n\t\t{2: 527, 527, 527, 527, 527, 527, 527, 10: 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527},\n\t\t{505, 505, 383: 505, 405: 505},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3566, 2178, 2179, 2177, 673: 3777},\n\t\t{494, 494, 383: 494, 405: 494},\n\t\t// 1755\n\t\t{506, 506, 383: 506, 405: 506},\n\t\t{507, 507, 383: 507, 405: 507},\n\t\t{508, 508, 383: 508, 405: 508},\n\t\t{509, 509, 383: 509, 405: 509},\n\t\t{510, 510, 383: 510, 405: 510},\n\t\t// 1760\n\t\t{514, 514, 383: 514, 405: 514},\n\t\t{513, 513, 383: 513, 405: 513},\n\t\t{512, 512, 383: 512, 405: 512},\n\t\t{52: 2574, 2573, 675: 3787},\n\t\t{390: 3773, 425: 3774, 640: 3789, 902: 3788},\n\t\t// 1765\n\t\t{495, 495, 383: 495, 390: 3773, 405: 495, 425: 3774, 640: 3776, 679: 3791},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3790},\n\t\t{493, 493, 383: 493, 390: 493, 405: 493, 425: 493},\n\t\t{517, 517, 383: 517, 405: 517},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3793, 2178, 2179, 2177, 599: 3794},\n\t\t// 1770\n\t\t{861, 861, 383: 861, 390: 3773, 405: 861, 407: 2548, 425: 3774, 640: 3795},\n\t\t{520, 520, 383: 520, 405: 520},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3796, 2178, 2179, 2177},\n\t\t{519, 519, 383: 519, 405: 519},\n\t\t{495, 495, 383: 495, 390: 3773, 405: 495, 425: 3774, 640: 3776, 679: 3798},\n\t\t// 1775\n\t\t{522, 522, 383: 522, 405: 522},\n\t\t{503, 503, 383: 3802, 405: 3801, 696: 3800},\n\t\t{550, 550},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 370: 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2763, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 3804, 2665, 2744, 2664, 2661},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3803},\n\t\t// 1780\n\t\t{501, 501, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{502, 502, 376: 2764, 521: 2765},\n\t\t{535, 535, 377: 3823, 381: 535, 1045: 3822},\n\t\t{547, 547, 9: 3820, 377: 547, 381: 547},\n\t\t{546, 546, 9: 546, 377: 546, 381: 546},\n\t\t// 1785\n\t\t{544, 544, 9: 544, 377: 544, 381: 544},\n\t\t{543, 543, 9: 543, 377: 543, 381: 543},\n\t\t{241: 3819},\n\t\t{293: 3818},\n\t\t{230: 3817},\n\t\t// 1790\n\t\t{539, 539, 9: 539, 377: 539, 381: 539},\n\t\t{538, 538, 9: 538, 377: 538, 381: 538},\n\t\t{537, 537, 9: 537, 377: 537, 381: 537},\n\t\t{536, 536, 9: 536, 377: 536, 381: 536},\n\t\t{540, 540, 9: 540, 377: 540, 381: 540},\n\t\t// 1795\n\t\t{541, 541, 9: 541, 377: 541, 381: 541},\n\t\t{542, 542, 9: 542, 377: 542, 381: 542},\n\t\t{107: 3809, 145: 3810, 152: 3811, 154: 3808, 169: 3813, 177: 3812, 190: 3815, 194: 3814, 600: 3816, 900: 3821},\n\t\t{545, 545, 9: 545, 377: 545, 381: 545},\n\t\t{717, 717, 381: 3826, 668: 3827},\n\t\t// 1800\n\t\t{92: 3824},\n\t\t{393: 2147, 598: 3825},\n\t\t{534, 534, 381: 534},\n\t\t{393: 2147, 455: 2656, 573: 3693, 598: 3183, 611: 3692, 725: 3828},\n\t\t{552, 552},\n\t\t// 1805\n\t\t{716, 716, 9: 3829, 96: 3830, 361: 716, 364: 716, 716, 368: 716, 375: 716, 377: 716, 379: 716, 716},\n\t\t{393: 2147, 455: 2656, 573: 3693, 598: 3183, 611: 3692, 725: 3832},\n\t\t{393: 2147, 455: 2656, 573: 3693, 598: 3183, 611: 3692, 725: 3831},\n\t\t{714, 714, 361: 714, 364: 714, 714, 368: 714, 375: 714, 377: 714, 379: 714, 714},\n\t\t{715, 715, 361: 715, 364: 715, 715, 368: 715, 375: 715, 377: 715, 379: 715, 715},\n\t\t// 1810\n\t\t{554, 554},\n\t\t{555, 555},\n\t\t{556, 556},\n\t\t{557, 557},\n\t\t{558, 558},\n\t\t// 1815\n\t\t{495, 495, 383: 495, 390: 3773, 405: 495, 425: 3774, 640: 3776, 679: 3842},\n\t\t{390: 3773, 425: 3774, 640: 3789, 902: 3840},\n\t\t{495, 495, 383: 495, 390: 3773, 405: 495, 425: 3774, 640: 3776, 679: 3841},\n\t\t{518, 518, 383: 518, 405: 518},\n\t\t{523, 523, 383: 523, 405: 523},\n\t\t// 1820\n\t\t{559, 559},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3566, 2178, 2179, 2177, 673: 3845},\n\t\t{561, 561, 377: 3846},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3847},\n\t\t{533, 533, 375: 3849, 1072: 3848},\n\t\t// 1825\n\t\t{560, 560},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 537: 2569, 2178, 2179, 2177, 601: 3419, 643: 3420, 3418, 667: 3850},\n\t\t{532, 532, 9: 3518},\n\t\t{495, 495, 98: 1427, 383: 495, 390: 3773, 405: 495, 407: 1427, 425: 3774, 525: 1427, 640: 3776, 679: 3859},\n\t\t{98: 3853, 525: 3854},\n\t\t// 1830\n\t\t{213, 213, 383: 3685, 645: 3686, 3858},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3855, 2178, 2179, 2177},\n\t\t{98: 3856},\n\t\t{213, 213, 383: 3685, 645: 3686, 3857},\n\t\t{562, 562},\n\t\t// 1835\n\t\t{563, 563},\n\t\t{521, 521, 383: 521, 405: 521},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3873},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3872},\n\t\t{2: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 10: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 431: 3867, 642: 3868},\n\t\t// 1840\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3866},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3865},\n\t\t{564, 564},\n\t\t{565, 565},\n\t\t{369: 3870},\n\t\t// 1845\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3566, 2178, 2179, 2177, 673: 3869},\n\t\t{566, 566},\n\t\t{460: 3871},\n\t\t{1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 362: 1526, 1526, 375: 1526, 395: 1526, 450: 1526, 656: 1526},\n\t\t{567, 567},\n\t\t// 1850\n\t\t{568, 568},\n\t\t{569, 569},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 4316, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 4317, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4318},\n\t\t{525: 4303, 605: 4302},\n\t\t{525: 4299},\n\t\t// 1855\n\t\t{525: 4293, 605: 4294},\n\t\t{605: 4291},\n\t\t{219: 4285},\n\t\t{228: 4283, 261: 4284},\n\t\t{119: 4280, 121: 4279},\n\t\t// 1860\n\t\t{605: 3890},\n\t\t{87: 3889},\n\t\t{87: 3888},\n\t\t{87: 3887},\n\t\t{579, 579},\n\t\t// 1865\n\t\t{580, 580},\n\t\t{581, 581},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3891},\n\t\t{559: 3892, 744: 3893},\n\t\t{112: 3895, 605: 1646, 757: 3894},\n\t\t// 1870\n\t\t{582, 582},\n\t\t{605: 3896},\n\t\t{57: 1645, 93: 1645, 605: 1645},\n\t\t{2: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 10: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 431: 3867, 642: 3897},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3898},\n\t\t// 1875\n\t\t{384, 384, 3: 384, 384, 384, 384, 384, 384, 10: 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 362: 3902, 365: 384, 373: 384, 384, 376: 384, 384: 384, 387: 384, 395: 384, 405: 3901, 522: 384, 524: 384, 384, 384, 530: 384, 384, 384, 990: 3900, 1062: 3899},\n\t\t{351, 351, 3: 4045, 4047, 4057, 4064, 1742, 4053, 10: 4046, 4049, 4075, 4048, 4051, 4052, 4054, 4059, 4062, 4060, 4058, 4063, 4077, 4065, 4076, 4080, 4073, 4068, 4067, 4069, 4061, 362: 351, 365: 4074, 373: 4044, 351, 376: 1742, 384: 351, 387: 1742, 395: 351, 522: 351, 524: 351, 4050, 1742, 530: 4072, 4071, 4070, 629: 4056, 657: 4055, 678: 4066, 681: 4079, 737: 4078, 797: 4043},\n\t\t{1743, 1743},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4042},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 405: 3904, 537: 3361, 2178, 2179, 2177, 603: 3903, 683: 3905, 767: 3906, 914: 3907},\n\t\t// 1880\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3915, 537: 3914, 2178, 2179, 2177, 561: 3919, 3918, 565: 3917, 569: 3916, 1069: 3913},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3911},\n\t\t{9: 387, 361: 387},\n\t\t{9: 386, 361: 386},\n\t\t{9: 3908, 361: 3909},\n\t\t// 1885\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3903, 683: 3905, 767: 3910},\n\t\t{383, 383, 3: 383, 383, 383, 383, 383, 383, 10: 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 362: 383, 365: 383, 373: 383, 383, 376: 383, 384: 383, 387: 383, 395: 383, 522: 383, 524: 383, 383, 383, 530: 383, 383, 383},\n\t\t{9: 385, 361: 385},\n\t\t{361: 3912},\n\t\t{1675, 1675},\n\t\t// 1890\n\t\t{1815, 1815, 1815, 3931, 3937, 3925, 9: 1815, 31: 1815, 1815, 3938, 3936, 3929, 361: 1815, 364: 3930, 369: 3923, 373: 3928, 1822, 376: 3935, 394: 3924, 1815, 527: 1853, 1935, 3922, 533: 3927, 3942, 3920, 3939, 743: 3932, 762: 3934, 790: 3940, 833: 3933, 884: 3926, 951: 3941, 3921},\n\t\t{1872, 1872, 1872, 1872, 1872, 1872, 9: 1872, 31: 1872, 1872, 1872, 1872, 1872, 361: 1872, 364: 1872, 369: 1872, 373: 1872, 1872, 376: 1872, 394: 1872, 1872, 527: 1872, 1872, 1872, 533: 1872, 1872, 1872, 1872},\n\t\t{1871, 1871, 1871, 1871, 1871, 1871, 9: 1871, 31: 1871, 1871, 1871, 1871, 1871, 361: 1871, 364: 1871, 369: 1871, 373: 1871, 1871, 376: 1871, 394: 1871, 1871, 527: 1871, 1871, 1871, 533: 1871, 1871, 1871, 1871},\n\t\t{1870, 1870, 1870, 1870, 1870, 1870, 9: 1870, 31: 1870, 1870, 1870, 1870, 1870, 361: 1870, 364: 1870, 369: 1870, 373: 1870, 1870, 376: 1870, 394: 1870, 1870, 527: 1870, 1870, 1870, 533: 1870, 1870, 1870, 1870},\n\t\t{1869, 1869, 1869, 1869, 1869, 1869, 9: 1869, 31: 1869, 1869, 1869, 1869, 1869, 361: 1869, 364: 1869, 369: 1869, 373: 1869, 1869, 376: 1869, 394: 1869, 1869, 527: 1869, 1869, 1869, 533: 1869, 1869, 1869, 1869},\n\t\t// 1895\n\t\t{1868, 1868, 1868, 1868, 1868, 1868, 9: 1868, 31: 1868, 1868, 1868, 1868, 1868, 361: 1868, 364: 1868, 369: 1868, 373: 1868, 1868, 376: 1868, 394: 1868, 1868, 527: 1868, 1868, 1868, 533: 1868, 1868, 1868, 1868},\n\t\t{1867, 1867, 1867, 1867, 1867, 1867, 9: 1867, 31: 1867, 1867, 1867, 1867, 1867, 361: 1867, 364: 1867, 369: 1867, 373: 1867, 1867, 376: 1867, 394: 1867, 1867, 527: 1867, 1867, 1867, 533: 1867, 1867, 1867, 1867},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 525: 1934, 527: 1934, 1934, 1934, 533: 1934, 537: 4041, 2178, 2179, 2177, 563: 1934, 1934, 911: 4040},\n\t\t{1876, 1876, 1876, 9: 1876, 31: 1876, 1876, 361: 1876, 395: 1876},\n\t\t{527: 1852},\n\t\t// 1900\n\t\t{394: 4039},\n\t\t{1844, 1844, 1844, 1844, 1844, 1844, 9: 1844, 31: 1844, 1844, 1844, 1844, 1844, 361: 1844, 364: 1844, 369: 1844, 373: 1844, 1844, 376: 1844, 394: 1844, 1844, 527: 1844, 1844, 1844, 533: 1844, 1844, 1844, 1844},\n\t\t{1843, 1843, 1843, 1843, 1843, 1843, 9: 1843, 31: 1843, 1843, 1843, 1843, 1843, 361: 1843, 364: 1843, 369: 1843, 373: 1843, 1843, 376: 1843, 394: 1843, 1843, 527: 1843, 1843, 1843, 533: 1843, 1843, 1843, 1843},\n\t\t{527: 4038},\n\t\t{1841, 1841, 1841, 1841, 1841, 1841, 9: 1841, 31: 1841, 1841, 1841, 1841, 1841, 361: 1841, 364: 1841, 369: 1841, 373: 1841, 1841, 376: 1841, 394: 1841, 1841, 527: 4037, 1841, 1841, 533: 1841, 1841, 1841, 1841},\n\t\t// 1905\n\t\t{363: 2654, 370: 4033, 4034, 393: 2649, 2645, 453: 2648, 2647, 457: 2653, 2652, 461: 2644, 2646, 466: 4022, 4019, 4020, 4021, 2651, 577: 2650, 4032, 857: 4017, 4018, 4030, 904: 4031, 962: 4029},\n\t\t{373: 4027},\n\t\t{616: 4015},\n\t\t{363: 4014},\n\t\t{528: 4003},\n\t\t// 1910\n\t\t{374: 3996},\n\t\t{1833, 1833, 1833, 1833, 1833, 1833, 9: 1833, 31: 1833, 1833, 1833, 1833, 1833, 361: 1833, 364: 1833, 369: 1833, 373: 1833, 1833, 376: 1833, 394: 1833, 1833, 527: 1833, 1833, 1833, 533: 1833, 1833, 1833, 1833},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 3995, 717: 3994},\n\t\t{120: 3993, 124: 3992, 373: 3991, 946: 3990},\n\t\t{107: 3989, 158: 3988, 373: 3987, 1056: 3986},\n\t\t// 1915\n\t\t{244, 244, 244, 244, 244, 244, 9: 244, 31: 244, 244, 244, 244, 244, 361: 244, 3194, 364: 244, 369: 244, 373: 244, 244, 376: 244, 394: 244, 244, 527: 244, 244, 244, 533: 244, 244, 244, 244, 662: 3195, 691: 3985},\n\t\t{208: 3984},\n\t\t{1817, 1817, 1817, 1817, 1817, 1817, 9: 1817, 31: 1817, 1817, 1817, 1817, 1817, 361: 1817, 364: 1817, 369: 1817, 373: 1817, 1817, 376: 1817, 394: 1817, 1817, 527: 1817, 1817, 1817, 533: 1817, 1817, 1817, 1817},\n\t\t{1814, 1814, 1814, 3931, 3937, 3925, 9: 1814, 31: 1814, 1814, 3938, 3936, 3929, 361: 1814, 364: 3930, 369: 3923, 373: 3928, 1822, 376: 3935, 394: 3924, 1814, 527: 1853, 1935, 3922, 533: 3927, 3942, 3920, 3939, 743: 3932, 762: 3934, 790: 3983, 833: 3933, 884: 3926},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3943},\n\t\t// 1920\n\t\t{1770, 1770, 1770, 1770, 1770, 1770, 9: 1770, 31: 1770, 1770, 1770, 1770, 1770, 361: 1770, 3945, 364: 1770, 369: 1770, 373: 1770, 1770, 376: 1770, 394: 1770, 1770, 523: 1770, 527: 1770, 1770, 1770, 533: 1770, 1770, 1770, 1770, 982: 3944},\n\t\t{1804, 1804, 1804, 1804, 1804, 1804, 9: 1804, 31: 1804, 1804, 1804, 1804, 1804, 361: 1804, 364: 1804, 369: 1804, 373: 1804, 1804, 376: 1804, 394: 1804, 1804, 523: 3958, 527: 1804, 1804, 1804, 533: 1804, 1804, 1804, 1804, 997: 3959, 3960},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3949, 537: 3361, 2178, 2179, 2177, 603: 3948, 663: 3947, 676: 3946},\n\t\t{9: 3956, 361: 3955},\n\t\t{9: 1768, 361: 1768},\n\t\t// 1925\n\t\t{9: 244, 361: 244, 3194, 411: 244, 244, 662: 3195, 691: 3953},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3950},\n\t\t{361: 3951, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{9: 1089, 361: 1089, 411: 2796, 2795, 731: 3952},\n\t\t{9: 1765, 361: 1765},\n\t\t// 1930\n\t\t{9: 1089, 361: 1089, 411: 2796, 2795, 731: 3954},\n\t\t{9: 1766, 361: 1766},\n\t\t{1769, 1769, 1769, 1769, 1769, 1769, 9: 1769, 31: 1769, 1769, 1769, 1769, 1769, 361: 1769, 364: 1769, 369: 1769, 373: 1769, 1769, 376: 1769, 394: 1769, 1769, 523: 1769, 527: 1769, 1769, 1769, 533: 1769, 1769, 1769, 1769},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3949, 537: 3361, 2178, 2179, 2177, 603: 3948, 663: 3957},\n\t\t{9: 1767, 361: 1767},\n\t\t// 1935\n\t\t{126: 3980, 262: 3981, 285: 3982},\n\t\t{1803, 1803, 1803, 1803, 1803, 1803, 9: 1803, 31: 1803, 1803, 1803, 1803, 1803, 361: 1803, 364: 1803, 369: 1803, 373: 1803, 1803, 376: 1803, 394: 1803, 1803, 527: 1803, 1803, 1803, 533: 1803, 1803, 1803, 1803},\n\t\t{1799, 1799, 1799, 1799, 1799, 1799, 9: 1799, 31: 1799, 1799, 1799, 1799, 1799, 361: 1799, 364: 3962, 369: 1799, 373: 1799, 1799, 376: 1799, 394: 1799, 1799, 527: 1799, 1799, 1799, 533: 1799, 1799, 1799, 1799, 866: 3963, 3964, 1001: 3961},\n\t\t{1802, 1802, 1802, 1802, 1802, 1802, 9: 1802, 31: 1802, 1802, 1802, 1802, 1802, 361: 1802, 364: 1802, 369: 1802, 373: 1802, 1802, 376: 1802, 394: 1802, 1802, 527: 1802, 1802, 1802, 533: 1802, 1802, 1802, 1802},\n\t\t{616: 3978, 3967},\n\t\t// 1940\n\t\t{1798, 1798, 1798, 1798, 1798, 1798, 9: 1798, 31: 1798, 1798, 1798, 1798, 1798, 361: 1798, 364: 3976, 369: 1798, 373: 1798, 1798, 376: 1798, 394: 1798, 1798, 527: 1798, 1798, 1798, 533: 1798, 1798, 1798, 1798, 867: 3977},\n\t\t{1797, 1797, 1797, 1797, 1797, 1797, 9: 1797, 31: 1797, 1797, 1797, 1797, 1797, 361: 1797, 364: 3965, 369: 1797, 373: 1797, 1797, 376: 1797, 394: 1797, 1797, 527: 1797, 1797, 1797, 533: 1797, 1797, 1797, 1797, 866: 3966},\n\t\t{617: 3967},\n\t\t{1795, 1795, 1795, 1795, 1795, 1795, 9: 1795, 31: 1795, 1795, 1795, 1795, 1795, 361: 1795, 364: 1795, 369: 1795, 373: 1795, 1795, 376: 1795, 394: 1795, 1795, 527: 1795, 1795, 1795, 533: 1795, 1795, 1795, 1795},\n\t\t{37: 3972, 392: 3971, 553: 3970, 556: 3969, 889: 3968},\n\t\t// 1945\n\t\t{1801, 1801, 1801, 1801, 1801, 1801, 9: 1801, 31: 1801, 1801, 1801, 1801, 1801, 361: 1801, 364: 1801, 369: 1801, 373: 1801, 1801, 376: 1801, 394: 1801, 1801, 527: 1801, 1801, 1801, 533: 1801, 1801, 1801, 1801},\n\t\t{1794, 1794, 1794, 1794, 1794, 1794, 9: 1794, 31: 1794, 1794, 1794, 1794, 1794, 361: 1794, 364: 1794, 369: 1794, 373: 1794, 1794, 376: 1794, 394: 1794, 1794, 527: 1794, 1794, 1794, 533: 1794, 1794, 1794, 1794},\n\t\t{1793, 1793, 1793, 1793, 1793, 1793, 9: 1793, 31: 1793, 1793, 1793, 1793, 1793, 361: 1793, 364: 1793, 369: 1793, 373: 1793, 1793, 376: 1793, 394: 1793, 1793, 527: 1793, 1793, 1793, 533: 1793, 1793, 1793, 1793},\n\t\t{373: 3975, 394: 3974},\n\t\t{205: 3973},\n\t\t// 1950\n\t\t{1791, 1791, 1791, 1791, 1791, 1791, 9: 1791, 31: 1791, 1791, 1791, 1791, 1791, 361: 1791, 364: 1791, 369: 1791, 373: 1791, 1791, 376: 1791, 394: 1791, 1791, 527: 1791, 1791, 1791, 533: 1791, 1791, 1791, 1791},\n\t\t{1792, 1792, 1792, 1792, 1792, 1792, 9: 1792, 31: 1792, 1792, 1792, 1792, 1792, 361: 1792, 364: 1792, 369: 1792, 373: 1792, 1792, 376: 1792, 394: 1792, 1792, 527: 1792, 1792, 1792, 533: 1792, 1792, 1792, 1792},\n\t\t{1790, 1790, 1790, 1790, 1790, 1790, 9: 1790, 31: 1790, 1790, 1790, 1790, 1790, 361: 1790, 364: 1790, 369: 1790, 373: 1790, 1790, 376: 1790, 394: 1790, 1790, 527: 1790, 1790, 1790, 533: 1790, 1790, 1790, 1790},\n\t\t{616: 3978},\n\t\t{1796, 1796, 1796, 1796, 1796, 1796, 9: 1796, 31: 1796, 1796, 1796, 1796, 1796, 361: 1796, 364: 1796, 369: 1796, 373: 1796, 1796, 376: 1796, 394: 1796, 1796, 527: 1796, 1796, 1796, 533: 1796, 1796, 1796, 1796},\n\t\t// 1955\n\t\t{37: 3972, 392: 3971, 553: 3970, 556: 3969, 889: 3979},\n\t\t{1800, 1800, 1800, 1800, 1800, 1800, 9: 1800, 31: 1800, 1800, 1800, 1800, 1800, 361: 1800, 364: 1800, 369: 1800, 373: 1800, 1800, 376: 1800, 394: 1800, 1800, 527: 1800, 1800, 1800, 533: 1800, 1800, 1800, 1800},\n\t\t{1807, 1807, 1807, 1807, 1807, 1807, 9: 1807, 31: 1807, 1807, 1807, 1807, 1807, 361: 1807, 364: 1807, 369: 1807, 373: 1807, 1807, 376: 1807, 394: 1807, 1807, 527: 1807, 1807, 1807, 533: 1807, 1807, 1807, 1807},\n\t\t{1806, 1806, 1806, 1806, 1806, 1806, 9: 1806, 31: 1806, 1806, 1806, 1806, 1806, 361: 1806, 364: 1806, 369: 1806, 373: 1806, 1806, 376: 1806, 394: 1806, 1806, 527: 1806, 1806, 1806, 533: 1806, 1806, 1806, 1806},\n\t\t{1805, 1805, 1805, 1805, 1805, 1805, 9: 1805, 31: 1805, 1805, 1805, 1805, 1805, 361: 1805, 364: 1805, 369: 1805, 373: 1805, 1805, 376: 1805, 394: 1805, 1805, 527: 1805, 1805, 1805, 533: 1805, 1805, 1805, 1805},\n\t\t// 1960\n\t\t{1816, 1816, 1816, 1816, 1816, 1816, 9: 1816, 31: 1816, 1816, 1816, 1816, 1816, 361: 1816, 364: 1816, 369: 1816, 373: 1816, 1816, 376: 1816, 394: 1816, 1816, 527: 1816, 1816, 1816, 533: 1816, 1816, 1816, 1816},\n\t\t{374: 1821},\n\t\t{1829, 1829, 1829, 1829, 1829, 1829, 9: 1829, 31: 1829, 1829, 1829, 1829, 1829, 361: 1829, 364: 1829, 369: 1829, 373: 1829, 1829, 376: 1829, 394: 1829, 1829, 527: 1829, 1829, 1829, 533: 1829, 1829, 1829, 1829},\n\t\t{1830, 1830, 1830, 1830, 1830, 1830, 9: 1830, 31: 1830, 1830, 1830, 1830, 1830, 361: 1830, 364: 1830, 369: 1830, 373: 1830, 1830, 376: 1830, 394: 1830, 1830, 527: 1830, 1830, 1830, 533: 1830, 1830, 1830, 1830},\n\t\t{1828, 1828, 1828, 1828, 1828, 1828, 9: 1828, 31: 1828, 1828, 1828, 1828, 1828, 361: 1828, 364: 1828, 369: 1828, 373: 1828, 1828, 376: 1828, 394: 1828, 1828, 527: 1828, 1828, 1828, 533: 1828, 1828, 1828, 1828},\n\t\t// 1965\n\t\t{1827, 1827, 1827, 1827, 1827, 1827, 9: 1827, 31: 1827, 1827, 1827, 1827, 1827, 361: 1827, 364: 1827, 369: 1827, 373: 1827, 1827, 376: 1827, 394: 1827, 1827, 527: 1827, 1827, 1827, 533: 1827, 1827, 1827, 1827},\n\t\t{1826, 1826, 1826, 1826, 1826, 1826, 9: 1826, 31: 1826, 1826, 1826, 1826, 1826, 361: 1826, 364: 1826, 369: 1826, 373: 1826, 1826, 376: 1826, 394: 1826, 1826, 527: 1826, 1826, 1826, 533: 1826, 1826, 1826, 1826},\n\t\t{1831, 1831, 1831, 1831, 1831, 1831, 9: 1831, 31: 1831, 1831, 1831, 1831, 1831, 361: 1831, 364: 1831, 369: 1831, 373: 1831, 1831, 376: 1831, 394: 1831, 1831, 527: 1831, 1831, 1831, 533: 1831, 1831, 1831, 1831},\n\t\t{1825, 1825, 1825, 1825, 1825, 1825, 9: 1825, 31: 1825, 1825, 1825, 1825, 1825, 361: 1825, 364: 1825, 369: 1825, 373: 1825, 1825, 376: 1825, 394: 1825, 1825, 527: 1825, 1825, 1825, 533: 1825, 1825, 1825, 1825},\n\t\t{1824, 1824, 1824, 1824, 1824, 1824, 9: 1824, 31: 1824, 1824, 1824, 1824, 1824, 361: 1824, 364: 1824, 369: 1824, 373: 1824, 1824, 376: 1824, 394: 1824, 1824, 527: 1824, 1824, 1824, 533: 1824, 1824, 1824, 1824},\n\t\t// 1970\n\t\t{1823, 1823, 1823, 1823, 1823, 1823, 9: 1823, 31: 1823, 1823, 1823, 1823, 1823, 361: 1823, 364: 1823, 369: 1823, 373: 1823, 1823, 376: 1823, 394: 1823, 1823, 527: 1823, 1823, 1823, 533: 1823, 1823, 1823, 1823},\n\t\t{1832, 1832, 1832, 1832, 1832, 1832, 9: 1832, 31: 1832, 1832, 1832, 1832, 1832, 361: 1832, 364: 1832, 369: 1832, 373: 1832, 1832, 376: 1832, 394: 1832, 1832, 527: 1832, 1832, 1832, 533: 1832, 1832, 1832, 1832},\n\t\t{625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 361: 625, 625, 364: 625, 625, 369: 625, 373: 625, 625, 376: 625, 384: 625, 387: 625, 394: 625, 625, 522: 625, 524: 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625},\n\t\t{362: 3997},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 3998},\n\t\t// 1975\n\t\t{361: 3999, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{1820, 1820, 1820, 1820, 1820, 1820, 9: 1820, 31: 1820, 1820, 1820, 1820, 1820, 361: 1820, 364: 1820, 369: 1820, 373: 1820, 1820, 376: 1820, 394: 1820, 1820, 527: 1820, 1820, 1820, 533: 1820, 1820, 1820, 1820, 1057: 4002, 1081: 4001, 4000},\n\t\t{1834, 1834, 1834, 1834, 1834, 1834, 9: 1834, 31: 1834, 1834, 1834, 1834, 1834, 361: 1834, 364: 1834, 369: 1834, 373: 1834, 1834, 376: 1834, 394: 1834, 1834, 527: 1834, 1834, 1834, 533: 1834, 1834, 1834, 1834},\n\t\t{1819, 1819, 1819, 1819, 1819, 1819, 9: 1819, 31: 1819, 1819, 1819, 1819, 1819, 361: 1819, 364: 1819, 369: 1819, 373: 1819, 1819, 376: 1819, 394: 1819, 1819, 527: 1819, 1819, 1819, 533: 1819, 1819, 1819, 1819},\n\t\t{1818, 1818, 1818, 1818, 1818, 1818, 9: 1818, 31: 1818, 1818, 1818, 1818, 1818, 361: 1818, 364: 1818, 369: 1818, 373: 1818, 1818, 376: 1818, 394: 1818, 1818, 527: 1818, 1818, 1818, 533: 1818, 1818, 1818, 1818},\n\t\t// 1980\n\t\t{362: 4004},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4005},\n\t\t{361: 4006, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{1849, 1849, 1849, 1849, 1849, 1849, 9: 1849, 31: 1849, 1849, 1849, 1849, 1849, 95: 4007, 361: 1849, 364: 1849, 369: 4008, 373: 1849, 1849, 376: 1849, 394: 1849, 1849, 527: 1849, 1849, 1849, 533: 1849, 1849, 1849, 1849, 747: 4009, 817: 4010, 965: 4011},\n\t\t{1851, 1851, 1851, 1851, 1851, 1851, 9: 1851, 31: 1851, 1851, 1851, 1851, 1851, 361: 1851, 364: 1851, 369: 1851, 373: 1851, 1851, 376: 1851, 394: 1851, 1851, 527: 1851, 1851, 1851, 533: 1851, 1851, 1851, 1851},\n\t\t// 1985\n\t\t{95: 4012, 394: 4013},\n\t\t{1848, 1848, 1848, 1848, 1848, 1848, 9: 1848, 31: 1848, 1848, 1848, 1848, 1848, 361: 1848, 364: 1848, 369: 1848, 373: 1848, 1848, 376: 1848, 394: 1848, 1848, 527: 1848, 1848, 1848, 533: 1848, 1848, 1848, 1848},\n\t\t{1846, 1846, 1846, 1846, 1846, 1846, 9: 1846, 31: 1846, 1846, 1846, 1846, 1846, 361: 1846, 364: 1846, 369: 1846, 373: 1846, 1846, 376: 1846, 394: 1846, 1846, 527: 1846, 1846, 1846, 533: 1846, 1846, 1846, 1846},\n\t\t{1835, 1835, 1835, 1835, 1835, 1835, 9: 1835, 31: 1835, 1835, 1835, 1835, 1835, 361: 1835, 364: 1835, 369: 1835, 373: 1835, 1835, 376: 1835, 394: 1835, 1835, 527: 1835, 1835, 1835, 533: 1835, 1835, 1835, 1835},\n\t\t{1850, 1850, 1850, 1850, 1850, 1850, 9: 1850, 31: 1850, 1850, 1850, 1850, 1850, 361: 1850, 364: 1850, 369: 1850, 373: 1850, 1850, 376: 1850, 394: 1850, 1850, 527: 1850, 1850, 1850, 533: 1850, 1850, 1850, 1850},\n\t\t// 1990\n\t\t{1847, 1847, 1847, 1847, 1847, 1847, 9: 1847, 31: 1847, 1847, 1847, 1847, 1847, 361: 1847, 364: 1847, 369: 1847, 373: 1847, 1847, 376: 1847, 394: 1847, 1847, 527: 1847, 1847, 1847, 533: 1847, 1847, 1847, 1847},\n\t\t{1836, 1836, 1836, 1836, 1836, 1836, 9: 1836, 31: 1836, 1836, 1836, 1836, 1836, 361: 1836, 364: 1836, 369: 1836, 373: 1836, 1836, 376: 1836, 394: 1836, 1836, 527: 1836, 1836, 1836, 533: 1836, 1836, 1836, 1836},\n\t\t{466: 4022, 4019, 4020, 4021, 857: 4017, 4018, 4016},\n\t\t{1837, 1837, 1837, 1837, 1837, 1837, 9: 1837, 31: 1837, 1837, 1837, 1837, 1837, 361: 1837, 364: 1837, 369: 1837, 373: 1837, 1837, 376: 1837, 394: 1837, 1837, 527: 1837, 1837, 1837, 533: 1837, 1837, 1837, 1837},\n\t\t{1787, 1787, 1787, 1787, 1787, 1787, 9: 1787, 31: 1787, 1787, 1787, 1787, 1787, 361: 1787, 364: 1787, 369: 1787, 373: 1787, 1787, 376: 1787, 394: 1787, 1787, 527: 1787, 1787, 1787, 533: 1787, 1787, 1787, 1787},\n\t\t// 1995\n\t\t{362: 4023},\n\t\t{1780, 1780, 1780, 1780, 1780, 1780, 9: 1780, 31: 1780, 1780, 1780, 1780, 1780, 361: 1780, 1784, 364: 1780, 369: 1780, 373: 1780, 1780, 376: 1780, 394: 1780, 1780, 527: 1780, 1780, 1780, 533: 1780, 1780, 1780, 1780},\n\t\t{1779, 1779, 1779, 1779, 1779, 1779, 9: 1779, 31: 1779, 1779, 1779, 1779, 1779, 361: 1779, 1783, 364: 1779, 369: 1779, 373: 1779, 1779, 376: 1779, 394: 1779, 1779, 527: 1779, 1779, 1779, 533: 1779, 1779, 1779, 1779},\n\t\t{1778, 1778, 1778, 1778, 1778, 1778, 9: 1778, 31: 1778, 1778, 1778, 1778, 1778, 361: 1778, 1782, 364: 1778, 369: 1778, 373: 1778, 1778, 376: 1778, 394: 1778, 1778, 527: 1778, 1778, 1778, 533: 1778, 1778, 1778, 1778},\n\t\t{362: 1781},\n\t\t// 2000\n\t\t{361: 4024, 393: 2147, 598: 4025},\n\t\t{1786, 1786, 1786, 1786, 1786, 1786, 9: 1786, 31: 1786, 1786, 1786, 1786, 1786, 361: 1786, 364: 1786, 369: 1786, 373: 1786, 1786, 376: 1786, 394: 1786, 1786, 527: 1786, 1786, 1786, 533: 1786, 1786, 1786, 1786},\n\t\t{361: 4026},\n\t\t{1785, 1785, 1785, 1785, 1785, 1785, 9: 1785, 31: 1785, 1785, 1785, 1785, 1785, 361: 1785, 364: 1785, 369: 1785, 373: 1785, 1785, 376: 1785, 394: 1785, 1785, 527: 1785, 1785, 1785, 533: 1785, 1785, 1785, 1785},\n\t\t{115: 4028},\n\t\t// 2005\n\t\t{1838, 1838, 1838, 1838, 1838, 1838, 9: 1838, 31: 1838, 1838, 1838, 1838, 1838, 361: 1838, 364: 1838, 369: 1838, 373: 1838, 1838, 376: 1838, 394: 1838, 1838, 527: 1838, 1838, 1838, 533: 1838, 1838, 1838, 1838},\n\t\t{1839, 1839, 1839, 1839, 1839, 1839, 9: 1839, 31: 1839, 1839, 1839, 1839, 1839, 361: 1839, 364: 1839, 369: 1839, 373: 1839, 1839, 376: 1839, 394: 1839, 1839, 527: 1839, 1839, 1839, 533: 1839, 1839, 1839, 1839},\n\t\t{1789, 1789, 1789, 1789, 1789, 1789, 9: 1789, 31: 1789, 1789, 1789, 1789, 1789, 361: 1789, 364: 1789, 369: 1789, 373: 1789, 1789, 376: 1789, 394: 1789, 1789, 527: 1789, 1789, 1789, 533: 1789, 1789, 1789, 1789},\n\t\t{1788, 1788, 1788, 1788, 1788, 1788, 9: 1788, 31: 1788, 1788, 1788, 1788, 1788, 361: 1788, 364: 1788, 369: 1788, 373: 1788, 1788, 376: 1788, 394: 1788, 1788, 527: 1788, 1788, 1788, 533: 1788, 1788, 1788, 1788},\n\t\t{1777, 1777, 1777, 1777, 1777, 1777, 9: 1777, 31: 1777, 1777, 1777, 1777, 1777, 361: 1777, 364: 1777, 369: 1777, 373: 1777, 1777, 376: 1777, 394: 1777, 1777, 527: 1777, 1777, 1777, 533: 1777, 1777, 1777, 1777},\n\t\t// 2010\n\t\t{393: 2806, 453: 2808, 2807, 690: 4036},\n\t\t{393: 2806, 453: 2808, 2807, 690: 4035},\n\t\t{1775, 1775, 1775, 1775, 1775, 1775, 9: 1775, 31: 1775, 1775, 1775, 1775, 1775, 361: 1775, 364: 1775, 369: 1775, 373: 1775, 1775, 376: 1775, 394: 1775, 1775, 527: 1775, 1775, 1775, 533: 1775, 1775, 1775, 1775},\n\t\t{1776, 1776, 1776, 1776, 1776, 1776, 9: 1776, 31: 1776, 1776, 1776, 1776, 1776, 361: 1776, 364: 1776, 369: 1776, 373: 1776, 1776, 376: 1776, 394: 1776, 1776, 527: 1776, 1776, 1776, 533: 1776, 1776, 1776, 1776},\n\t\t{1840, 1840, 1840, 1840, 1840, 1840, 9: 1840, 31: 1840, 1840, 1840, 1840, 1840, 361: 1840, 364: 1840, 369: 1840, 373: 1840, 1840, 376: 1840, 394: 1840, 1840, 527: 1840, 1840, 1840, 533: 1840, 1840, 1840, 1840},\n\t\t// 2015\n\t\t{1842, 1842, 1842, 1842, 1842, 1842, 9: 1842, 31: 1842, 1842, 1842, 1842, 1842, 361: 1842, 364: 1842, 369: 1842, 373: 1842, 1842, 376: 1842, 394: 1842, 1842, 527: 1842, 1842, 1842, 533: 1842, 1842, 1842, 1842},\n\t\t{1845, 1845, 1845, 1845, 1845, 1845, 9: 1845, 31: 1845, 1845, 1845, 1845, 1845, 361: 1845, 364: 1845, 369: 1845, 373: 1845, 1845, 376: 1845, 394: 1845, 1845, 527: 1845, 1845, 1845, 533: 1845, 1845, 1845, 1845},\n\t\t{525: 1933, 527: 1933, 1933, 1933, 533: 1933, 563: 1933, 1933},\n\t\t{1932, 1932, 1932, 9: 1932, 395: 1932, 525: 1932, 527: 1932, 1932, 1932, 533: 1932, 563: 1932, 1932},\n\t\t{1676, 1676},\n\t\t// 2020\n\t\t{1740, 1740, 362: 1740, 374: 1740, 384: 1740, 395: 4179, 522: 1740, 524: 1740, 879: 4178},\n\t\t{7: 1741, 12: 1741, 376: 1741, 387: 1741, 526: 1741},\n\t\t{363: 1632, 391: 4081, 602: 4176},\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 363: 1632, 391: 4081, 602: 4174},\n\t\t{10: 4169, 107: 4170, 158: 4171},\n\t\t// 2025\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 363: 1632, 391: 4081, 602: 4167},\n\t\t{156: 4164},\n\t\t{156: 4161},\n\t\t{391: 4081, 393: 1632, 602: 4159},\n\t\t{391: 4081, 393: 1632, 602: 4157},\n\t\t// 2030\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 391: 4081, 602: 4155},\n\t\t{391: 4081, 393: 1632, 602: 4153},\n\t\t{382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 362: 382, 365: 382, 373: 382, 382, 376: 382, 384: 382, 387: 382, 395: 382, 522: 382, 524: 382, 382, 382, 530: 382, 382, 382},\n\t\t{7: 3204, 376: 4148, 387: 3205, 526: 3203, 653: 4147},\n\t\t{391: 4081, 393: 1632, 602: 4145},\n\t\t// 2035\n\t\t{391: 4081, 393: 1632, 602: 4143},\n\t\t{363: 1632, 391: 4081, 602: 4141},\n\t\t{391: 4081, 393: 1632, 602: 4139},\n\t\t{391: 4081, 393: 1632, 602: 4137},\n\t\t{363: 1632, 391: 4081, 602: 4135},\n\t\t// 2040\n\t\t{363: 1632, 391: 4081, 602: 4133},\n\t\t{391: 4081, 393: 1632, 602: 4131},\n\t\t{391: 4081, 393: 1632, 602: 4129},\n\t\t{370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 362: 370, 365: 370, 373: 370, 370, 376: 370, 384: 370, 387: 370, 395: 370, 522: 370, 524: 370, 370, 370, 530: 370, 370, 370},\n\t\t{373: 1632, 391: 4081, 393: 1632, 602: 4127},\n\t\t// 2045\n\t\t{373: 1632, 391: 4081, 393: 1632, 602: 4124},\n\t\t{373: 1632, 391: 4081, 393: 1632, 602: 4121},\n\t\t{391: 4081, 393: 1632, 602: 4119},\n\t\t{391: 4081, 393: 1632, 602: 4117},\n\t\t{373: 1632, 391: 4081, 393: 1632, 602: 4113},\n\t\t// 2050\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 363: 1632, 391: 4081, 394: 1632, 602: 4110},\n\t\t{362: 1632, 391: 4081, 602: 4106},\n\t\t{363: 1632, 391: 4081, 602: 4104},\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 391: 4081, 602: 4102},\n\t\t{363: 1632, 391: 4081, 602: 4100},\n\t\t// 2055\n\t\t{350, 350, 3: 4045, 4047, 4057, 4064, 1742, 4053, 4098, 4046, 4049, 4075, 4048, 4051, 4052, 4054, 4059, 4062, 4060, 4058, 4063, 4077, 4065, 4076, 4080, 4073, 4068, 4067, 4069, 4061, 362: 350, 365: 4074, 373: 4044, 350, 376: 1742, 384: 350, 387: 1742, 395: 350, 522: 350, 524: 350, 4050, 1742, 530: 4072, 4071, 4070, 629: 4056, 657: 4055, 678: 4066, 681: 4097},\n\t\t{349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 362: 349, 365: 349, 373: 349, 349, 376: 349, 384: 349, 387: 349, 395: 349, 522: 349, 524: 349, 349, 349, 530: 349, 349, 349},\n\t\t{120: 1632, 124: 1632, 150: 1632, 1632, 180: 1632, 195: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 373: 1632, 391: 4081, 602: 4082},\n\t\t{2: 1631, 1631, 1631, 1631, 1631, 1631, 1631, 10: 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 1631, 362: 1631, 1631, 370: 1631, 1631, 373: 1631, 393: 1631, 1631, 438: 1631},\n\t\t{120: 4084, 124: 4085, 150: 4088, 4086, 180: 4087, 195: 4089, 4090, 4094, 4093, 4091, 4095, 4096, 4092, 373: 4083},\n\t\t// 2060\n\t\t{343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, 362: 343, 365: 343, 373: 343, 343, 376: 343, 384: 343, 387: 343, 395: 343, 522: 343, 524: 343, 343, 343, 530: 343, 343, 343},\n\t\t{342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 342, 362: 342, 365: 342, 373: 342, 342, 376: 342, 384: 342, 387: 342, 395: 342, 522: 342, 524: 342, 342, 342, 530: 342, 342, 342},\n\t\t{341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 341, 362: 341, 365: 341, 373: 341, 341, 376: 341, 384: 341, 387: 341, 395: 341, 522: 341, 524: 341, 341, 341, 530: 341, 341, 341},\n\t\t{340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 362: 340, 365: 340, 373: 340, 340, 376: 340, 384: 340, 387: 340, 395: 340, 522: 340, 524: 340, 340, 340, 530: 340, 340, 340},\n\t\t{339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 362: 339, 365: 339, 373: 339, 339, 376: 339, 384: 339, 387: 339, 395: 339, 522: 339, 524: 339, 339, 339, 530: 339, 339, 339},\n\t\t// 2065\n\t\t{338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 338, 362: 338, 365: 338, 373: 338, 338, 376: 338, 384: 338, 387: 338, 395: 338, 522: 338, 524: 338, 338, 338, 530: 338, 338, 338},\n\t\t{337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 337, 362: 337, 365: 337, 373: 337, 337, 376: 337, 384: 337, 387: 337, 395: 337, 522: 337, 524: 337, 337, 337, 530: 337, 337, 337},\n\t\t{336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 362: 336, 365: 336, 373: 336, 336, 376: 336, 384: 336, 387: 336, 395: 336, 522: 336, 524: 336, 336, 336, 530: 336, 336, 336},\n\t\t{335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 362: 335, 365: 335, 373: 335, 335, 376: 335, 384: 335, 387: 335, 395: 335, 522: 335, 524: 335, 335, 335, 530: 335, 335, 335},\n\t\t{334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 362: 334, 365: 334, 373: 334, 334, 376: 334, 384: 334, 387: 334, 395: 334, 522: 334, 524: 334, 334, 334, 530: 334, 334, 334},\n\t\t// 2070\n\t\t{333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 362: 333, 365: 333, 373: 333, 333, 376: 333, 384: 333, 387: 333, 395: 333, 522: 333, 524: 333, 333, 333, 530: 333, 333, 333},\n\t\t{332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 332, 362: 332, 365: 332, 373: 332, 332, 376: 332, 384: 332, 387: 332, 395: 332, 522: 332, 524: 332, 332, 332, 530: 332, 332, 332},\n\t\t{331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 362: 331, 365: 331, 373: 331, 331, 376: 331, 384: 331, 387: 331, 395: 331, 522: 331, 524: 331, 331, 331, 530: 331, 331, 331},\n\t\t{330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 362: 330, 365: 330, 373: 330, 330, 376: 330, 384: 330, 387: 330, 395: 330, 522: 330, 524: 330, 330, 330, 530: 330, 330, 330},\n\t\t{348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 362: 348, 365: 348, 373: 348, 348, 376: 348, 384: 348, 387: 348, 395: 348, 522: 348, 524: 348, 348, 348, 530: 348, 348, 348},\n\t\t// 2075\n\t\t{3: 4045, 4047, 4057, 4064, 1742, 4053, 10: 4046, 4049, 4075, 4048, 4051, 4052, 4054, 4059, 4062, 4060, 4058, 4063, 4077, 4065, 4076, 4080, 4073, 4068, 4067, 4069, 4061, 365: 4074, 373: 4044, 376: 1742, 387: 1742, 525: 4050, 1742, 530: 4072, 4071, 4070, 629: 4056, 657: 4055, 678: 4066, 681: 4099},\n\t\t{347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 362: 347, 365: 347, 373: 347, 347, 376: 347, 384: 347, 387: 347, 395: 347, 522: 347, 524: 347, 347, 347, 530: 347, 347, 347},\n\t\t{363: 4101},\n\t\t{354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 362: 354, 365: 354, 373: 354, 354, 376: 354, 384: 354, 387: 354, 395: 354, 522: 354, 524: 354, 354, 354, 530: 354, 354, 354},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4103},\n\t\t// 2080\n\t\t{355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, 362: 355, 365: 355, 373: 355, 355, 376: 355, 384: 355, 387: 355, 395: 355, 522: 355, 524: 355, 355, 355, 530: 355, 355, 355},\n\t\t{363: 4105},\n\t\t{356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 362: 356, 365: 356, 373: 356, 356, 376: 356, 384: 356, 387: 356, 395: 356, 522: 356, 524: 356, 356, 356, 530: 356, 356, 356},\n\t\t{362: 4107},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 474, 537: 2537, 2178, 2179, 2177, 599: 3720, 651: 3721, 916: 4108},\n\t\t// 2085\n\t\t{361: 4109},\n\t\t{357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 357, 362: 357, 365: 357, 373: 357, 357, 376: 357, 384: 357, 387: 357, 395: 357, 522: 357, 524: 357, 357, 357, 530: 357, 357, 357},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 394: 4111, 537: 2569, 2178, 2179, 2177, 601: 4112},\n\t\t{359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, 362: 359, 365: 359, 373: 359, 359, 376: 359, 384: 359, 387: 359, 395: 359, 522: 359, 524: 359, 359, 359, 530: 359, 359, 359},\n\t\t{358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, 362: 358, 365: 358, 373: 358, 358, 376: 358, 384: 358, 387: 358, 395: 358, 522: 358, 524: 358, 358, 358, 530: 358, 358, 358},\n\t\t// 2090\n\t\t{373: 4115, 393: 2147, 598: 3183, 611: 4116, 908: 4114},\n\t\t{362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362: 362, 365: 362, 373: 362, 362, 376: 362, 384: 362, 387: 362, 395: 362, 522: 362, 524: 362, 362, 362, 530: 362, 362, 362},\n\t\t{353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 353, 362: 353, 365: 353, 373: 353, 353, 376: 353, 384: 353, 387: 353, 395: 353, 522: 353, 524: 353, 353, 353, 530: 353, 353, 353},\n\t\t{352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, 362: 352, 365: 352, 373: 352, 352, 376: 352, 384: 352, 387: 352, 395: 352, 522: 352, 524: 352, 352, 352, 530: 352, 352, 352},\n\t\t{393: 2147, 598: 3183, 611: 4118},\n\t\t// 2095\n\t\t{363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 362: 363, 365: 363, 373: 363, 363, 376: 363, 384: 363, 387: 363, 395: 363, 522: 363, 524: 363, 363, 363, 530: 363, 363, 363},\n\t\t{393: 2147, 598: 3183, 611: 4120},\n\t\t{364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 362: 364, 365: 364, 373: 364, 364, 376: 364, 384: 364, 387: 364, 395: 364, 522: 364, 524: 364, 364, 364, 530: 364, 364, 364},\n\t\t{373: 4123, 393: 2147, 598: 3183, 611: 4122},\n\t\t{366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, 362: 366, 365: 366, 373: 366, 366, 376: 366, 384: 366, 387: 366, 395: 366, 522: 366, 524: 366, 366, 366, 530: 366, 366, 366},\n\t\t// 2100\n\t\t{365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, 362: 365, 365: 365, 373: 365, 365, 376: 365, 384: 365, 387: 365, 395: 365, 522: 365, 524: 365, 365, 365, 530: 365, 365, 365},\n\t\t{373: 4126, 393: 2147, 598: 3183, 611: 4125},\n\t\t{368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 362: 368, 365: 368, 373: 368, 368, 376: 368, 384: 368, 387: 368, 395: 368, 522: 368, 524: 368, 368, 368, 530: 368, 368, 368},\n\t\t{367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 362: 367, 365: 367, 373: 367, 367, 376: 367, 384: 367, 387: 367, 395: 367, 522: 367, 524: 367, 367, 367, 530: 367, 367, 367},\n\t\t{373: 4115, 393: 2147, 598: 3183, 611: 4116, 908: 4128},\n\t\t// 2105\n\t\t{369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 362: 369, 365: 369, 373: 369, 369, 376: 369, 384: 369, 387: 369, 395: 369, 522: 369, 524: 369, 369, 369, 530: 369, 369, 369},\n\t\t{393: 2147, 598: 3183, 611: 4130},\n\t\t{371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 371, 362: 371, 365: 371, 373: 371, 371, 376: 371, 384: 371, 387: 371, 395: 371, 522: 371, 524: 371, 371, 371, 530: 371, 371, 371},\n\t\t{393: 2147, 598: 3183, 611: 4132},\n\t\t{372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 362: 372, 365: 372, 373: 372, 372, 376: 372, 384: 372, 387: 372, 395: 372, 522: 372, 524: 372, 372, 372, 530: 372, 372, 372},\n\t\t// 2110\n\t\t{363: 4134},\n\t\t{373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 373, 362: 373, 365: 373, 373: 373, 373, 376: 373, 384: 373, 387: 373, 395: 373, 522: 373, 524: 373, 373, 373, 530: 373, 373, 373},\n\t\t{363: 4136},\n\t\t{374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 362: 374, 365: 374, 373: 374, 374, 376: 374, 384: 374, 387: 374, 395: 374, 522: 374, 524: 374, 374, 374, 530: 374, 374, 374},\n\t\t{393: 2147, 598: 3183, 611: 4138},\n\t\t// 2115\n\t\t{375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 362: 375, 365: 375, 373: 375, 375, 376: 375, 384: 375, 387: 375, 395: 375, 522: 375, 524: 375, 375, 375, 530: 375, 375, 375},\n\t\t{393: 2147, 598: 3183, 611: 4140},\n\t\t{376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 362: 376, 365: 376, 373: 376, 376, 376: 376, 384: 376, 387: 376, 395: 376, 522: 376, 524: 376, 376, 376, 530: 376, 376, 376},\n\t\t{363: 4142},\n\t\t{377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 377, 362: 377, 365: 377, 373: 377, 377, 376: 377, 384: 377, 387: 377, 395: 377, 522: 377, 524: 377, 377, 377, 530: 377, 377, 377},\n\t\t// 2120\n\t\t{393: 2147, 598: 3183, 611: 4144},\n\t\t{378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 362: 378, 365: 378, 373: 378, 378, 376: 378, 384: 378, 387: 378, 395: 378, 522: 378, 524: 378, 378, 378, 530: 378, 378, 378},\n\t\t{393: 2147, 598: 3183, 611: 4146},\n\t\t{379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 379, 362: 379, 365: 379, 373: 379, 379, 376: 379, 384: 379, 387: 379, 395: 379, 522: 379, 524: 379, 379, 379, 530: 379, 379, 379},\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 363: 1632, 391: 4081, 438: 1632, 602: 4151},\n\t\t// 2125\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 363: 1632, 391: 4081, 602: 4149},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 3995, 717: 4150},\n\t\t{380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 362: 380, 365: 380, 373: 380, 380, 376: 380, 384: 380, 387: 380, 395: 380, 522: 380, 524: 380, 380, 380, 530: 380, 380, 380},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 438: 2567, 537: 2569, 2178, 2179, 2177, 601: 2566, 648: 4152},\n\t\t{381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 381, 362: 381, 365: 381, 373: 381, 381, 376: 381, 384: 381, 387: 381, 395: 381, 522: 381, 524: 381, 381, 381, 530: 381, 381, 381},\n\t\t// 2130\n\t\t{393: 2147, 598: 3183, 611: 4154},\n\t\t{1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 361: 1697, 1697, 365: 1697, 373: 1697, 1697, 376: 1697, 384: 1697, 387: 1697, 395: 1697, 522: 1697, 524: 1697, 1697, 1697, 530: 1697, 1697, 1697},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4156, 2178, 2179, 2177},\n\t\t{1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 361: 1698, 1698, 365: 1698, 373: 1698, 1698, 376: 1698, 384: 1698, 387: 1698, 395: 1698, 522: 1698, 524: 1698, 1698, 1698, 530: 1698, 1698, 1698},\n\t\t{393: 2147, 598: 3183, 611: 4158},\n\t\t// 2135\n\t\t{1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 1699, 361: 1699, 1699, 365: 1699, 373: 1699, 1699, 376: 1699, 384: 1699, 387: 1699, 395: 1699, 522: 1699, 524: 1699, 1699, 1699, 530: 1699, 1699, 1699},\n\t\t{393: 2147, 598: 3183, 611: 4160},\n\t\t{1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 361: 1700, 1700, 365: 1700, 373: 1700, 1700, 376: 1700, 384: 1700, 387: 1700, 395: 1700, 522: 1700, 524: 1700, 1700, 1700, 530: 1700, 1700, 1700},\n\t\t{363: 1632, 391: 4081, 602: 4162},\n\t\t{363: 4163},\n\t\t// 2140\n\t\t{1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 1701, 361: 1701, 1701, 365: 1701, 373: 1701, 1701, 376: 1701, 384: 1701, 387: 1701, 395: 1701, 522: 1701, 524: 1701, 1701, 1701, 530: 1701, 1701, 1701},\n\t\t{363: 1632, 391: 4081, 602: 4165},\n\t\t{363: 4166},\n\t\t{1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 1702, 361: 1702, 1702, 365: 1702, 373: 1702, 1702, 376: 1702, 384: 1702, 387: 1702, 395: 1702, 522: 1702, 524: 1702, 1702, 1702, 530: 1702, 1702, 1702},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 4168},\n\t\t// 2145\n\t\t{1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 1703, 361: 1703, 1703, 365: 1703, 373: 1703, 1703, 376: 1703, 384: 1703, 387: 1703, 395: 1703, 522: 1703, 524: 1703, 1703, 1703, 530: 1703, 1703, 1703},\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 363: 1632, 391: 4081, 602: 4172},\n\t\t{361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 361, 362: 361, 365: 361, 373: 361, 361, 376: 361, 384: 361, 387: 361, 395: 361, 522: 361, 524: 361, 361, 361, 530: 361, 361, 361},\n\t\t{360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 362: 360, 365: 360, 373: 360, 360, 376: 360, 384: 360, 387: 360, 395: 360, 522: 360, 524: 360, 360, 360, 530: 360, 360, 360},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 4173},\n\t\t// 2150\n\t\t{1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 361: 1704, 1704, 365: 1704, 373: 1704, 1704, 376: 1704, 384: 1704, 387: 1704, 395: 1704, 522: 1704, 524: 1704, 1704, 1704, 530: 1704, 1704, 1704},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 4175},\n\t\t{1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1705, 361: 1705, 1705, 365: 1705, 373: 1705, 1705, 376: 1705, 384: 1705, 387: 1705, 395: 1705, 522: 1705, 524: 1705, 1705, 1705, 530: 1705, 1705, 1705},\n\t\t{363: 4177},\n\t\t{1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 361: 1706, 1706, 365: 1706, 373: 1706, 1706, 376: 1706, 384: 1706, 387: 1706, 395: 1706, 522: 1706, 524: 1706, 1706, 1706, 530: 1706, 1706, 1706},\n\t\t// 2155\n\t\t{1689, 1689, 362: 1689, 374: 1689, 384: 2558, 522: 2557, 524: 1689, 814: 4272},\n\t\t{546: 4180},\n\t\t{84: 1726, 247: 4185, 294: 4186, 408: 4184, 527: 1726, 850: 4187, 4182, 910: 4183, 1018: 4181},\n\t\t{1720, 1720, 54: 1720, 4221, 362: 1720, 374: 1720, 384: 1720, 522: 1720, 524: 1720, 1019: 4220},\n\t\t{84: 4208, 527: 4207},\n\t\t// 2160\n\t\t{1734, 1734, 54: 1734, 1734, 362: 1734, 374: 1734, 384: 1734, 522: 1734, 524: 1734},\n\t\t{52: 2574, 2573, 362: 4200, 675: 4201},\n\t\t{52: 2574, 2573, 362: 4193, 675: 4194},\n\t\t{1727, 1727, 54: 1727, 1727, 362: 1727, 374: 1727, 381: 4189, 384: 1727, 456: 4188, 522: 1727, 524: 1727},\n\t\t{84: 1725, 527: 1725},\n\t\t// 2165\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4191},\n\t\t{393: 2147, 598: 3183, 611: 4190},\n\t\t{1728, 1728, 54: 1728, 1728, 362: 1728, 374: 1728, 384: 1728, 522: 1728, 524: 1728},\n\t\t{62: 2843, 2842, 2839, 2841, 2845, 2846, 2840, 2851, 2850, 2849, 2853, 2854, 2848, 2852, 2855, 2844, 2847, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 413: 2837, 2834, 2836, 2835, 2831, 2833, 2832, 2829, 2830, 2828, 2838, 596: 2756, 2754, 652: 2827, 669: 4192},\n\t\t{1729, 1729, 54: 1729, 1729, 362: 1729, 374: 1729, 384: 1729, 522: 1729, 524: 1729},\n\t\t// 2170\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4198},\n\t\t{362: 4195},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3362, 659: 4196},\n\t\t{9: 3364, 361: 4197},\n\t\t{1730, 1730, 54: 1730, 1730, 362: 1730, 374: 1730, 384: 1730, 522: 1730, 524: 1730},\n\t\t// 2175\n\t\t{361: 4199, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{1731, 1731, 54: 1731, 1731, 362: 1731, 374: 1731, 384: 1731, 522: 1731, 524: 1731},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4205},\n\t\t{362: 4202},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3362, 659: 4203},\n\t\t// 2180\n\t\t{9: 3364, 361: 4204},\n\t\t{1732, 1732, 54: 1732, 1732, 362: 1732, 374: 1732, 384: 1732, 522: 1732, 524: 1732},\n\t\t{361: 4206, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{1733, 1733, 54: 1733, 1733, 362: 1733, 374: 1733, 384: 1733, 522: 1733, 524: 1733},\n\t\t{41: 4213, 362: 1736, 1017: 4212},\n\t\t// 2185\n\t\t{362: 4209},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4210},\n\t\t{361: 4211, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{1737, 1737, 54: 1737, 1737, 138: 1737, 362: 1737, 374: 1737, 384: 1737, 522: 1737, 524: 1737},\n\t\t{362: 4216},\n\t\t// 2190\n\t\t{932: 4214},\n\t\t{393: 2147, 598: 4215},\n\t\t{362: 1735},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 1864, 537: 3361, 2178, 2179, 2177, 603: 3362, 659: 4217, 788: 4218},\n\t\t{9: 3364, 361: 1863},\n\t\t// 2195\n\t\t{361: 4219},\n\t\t{1738, 1738, 54: 1738, 1738, 138: 1738, 362: 1738, 374: 1738, 384: 1738, 522: 1738, 524: 1738},\n\t\t{1724, 1724, 54: 4224, 362: 1724, 374: 1724, 384: 1724, 522: 1724, 524: 1724, 1061: 4223},\n\t\t{393: 2147, 598: 3183, 611: 4222},\n\t\t{1719, 1719, 54: 1719, 362: 1719, 374: 1719, 384: 1719, 522: 1719, 524: 1719},\n\t\t// 2200\n\t\t{1718, 1718, 362: 4231, 374: 1718, 384: 1718, 522: 1718, 524: 1718, 877: 4230},\n\t\t{546: 4225},\n\t\t{84: 1726, 527: 1726, 850: 4187, 4182, 910: 4226},\n\t\t{1722, 1722, 138: 4228, 362: 1722, 374: 1722, 384: 1722, 522: 1722, 524: 1722, 1060: 4227},\n\t\t{1723, 1723, 362: 1723, 374: 1723, 384: 1723, 522: 1723, 524: 1723},\n\t\t// 2205\n\t\t{393: 2147, 598: 3183, 611: 4229},\n\t\t{1721, 1721, 362: 1721, 374: 1721, 384: 1721, 522: 1721, 524: 1721},\n\t\t{1739, 1739, 362: 1739, 374: 1739, 384: 1739, 522: 1739, 524: 1739},\n\t\t{395: 4234, 758: 4233, 876: 4232},\n\t\t{9: 4270, 361: 4269},\n\t\t// 2210\n\t\t{9: 1716, 361: 1716},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4235, 2178, 2179, 2177},\n\t\t{3: 1696, 1696, 8: 1696, 1696, 1696, 1696, 13: 1696, 1696, 1696, 1696, 88: 4240, 235: 4239, 361: 1696, 1696, 373: 4238, 459: 4237, 525: 1696, 1016: 4236},\n\t\t{3: 1708, 1708, 8: 1708, 1708, 1708, 1708, 13: 1708, 1708, 1708, 1708, 361: 1708, 1708, 525: 1708, 875: 4256},\n\t\t{245: 4241, 425: 4242},\n\t\t// 2215\n\t\t{3: 1693, 1693, 8: 1693, 1693, 1693, 1693, 13: 1693, 1693, 1693, 1693, 361: 1693, 1693, 525: 1693},\n\t\t{3: 1691, 1691, 8: 1691, 1691, 1691, 1691, 13: 1691, 1691, 1691, 1691, 361: 1691, 1691, 525: 1691},\n\t\t{3: 1690, 1690, 8: 1690, 1690, 1690, 1690, 13: 1690, 1690, 1690, 1690, 361: 1690, 1690, 525: 1690},\n\t\t{296: 4251},\n\t\t{362: 4243},\n\t\t// 2220\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 544: 4246, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4245, 756: 4247, 856: 4244},\n\t\t{9: 4249, 361: 4248},\n\t\t{9: 1600, 361: 1600, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{9: 1601, 361: 1601},\n\t\t{9: 1588, 361: 1588},\n\t\t// 2225\n\t\t{3: 1692, 1692, 8: 1692, 1692, 1692, 1692, 13: 1692, 1692, 1692, 1692, 361: 1692, 1692, 525: 1692},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 544: 4246, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4245, 756: 4250},\n\t\t{9: 1587, 361: 1587},\n\t\t{362: 4253, 544: 4252},\n\t\t{3: 1695, 1695, 8: 1695, 1695, 1695, 1695, 13: 1695, 1695, 1695, 1695, 361: 1695, 1695, 525: 1695},\n\t\t// 2230\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 544: 4246, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4245, 756: 4247, 856: 4254},\n\t\t{9: 4249, 361: 4255},\n\t\t{3: 1694, 1694, 8: 1694, 1694, 1694, 1694, 13: 1694, 1694, 1694, 1694, 361: 1694, 1694, 525: 1694},\n\t\t{3: 4045, 4260, 8: 4053, 1713, 4046, 4049, 13: 4048, 4051, 4052, 4054, 361: 1713, 4258, 525: 4050, 657: 4259, 1059: 4257},\n\t\t{9: 1714, 361: 1714},\n\t\t// 2235\n\t\t{54: 4263, 909: 4262, 1058: 4261},\n\t\t{3: 1707, 1707, 8: 1707, 1707, 1707, 1707, 13: 1707, 1707, 1707, 1707, 361: 1707, 1707, 525: 1707},\n\t\t{10: 4169},\n\t\t{9: 4267, 361: 4266},\n\t\t{9: 1711, 361: 1711},\n\t\t// 2240\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4264, 2178, 2179, 2177},\n\t\t{3: 1708, 1708, 8: 1708, 1708, 1708, 1708, 13: 1708, 1708, 1708, 1708, 361: 1708, 525: 1708, 875: 4265},\n\t\t{3: 4045, 4260, 8: 4053, 1709, 4046, 4049, 13: 4048, 4051, 4052, 4054, 361: 1709, 525: 4050, 657: 4259},\n\t\t{9: 1712, 361: 1712},\n\t\t{54: 4263, 909: 4268},\n\t\t// 2245\n\t\t{9: 1710, 361: 1710},\n\t\t{1717, 1717, 1717, 9: 1717, 362: 1717, 374: 1717, 384: 1717, 395: 1717, 522: 1717, 524: 1717},\n\t\t{395: 4234, 758: 4271},\n\t\t{9: 1715, 361: 1715},\n\t\t{1686, 1686, 362: 1686, 374: 4274, 524: 1686, 940: 4273},\n\t\t// 2250\n\t\t{1684, 1684, 362: 2057, 524: 2053, 574: 4278, 606: 4276, 2054, 2055, 2056, 613: 2059, 2058, 4277, 958: 4275},\n\t\t{1685, 1685, 362: 1685, 524: 1685},\n\t\t{1744, 1744},\n\t\t{1683, 1683, 365: 674},\n\t\t{1682, 1682},\n\t\t// 2255\n\t\t{1681, 1681},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3731, 2178, 2179, 2177, 759: 4282},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3731, 2178, 2179, 2177, 759: 4281},\n\t\t{584, 584, 9: 3733},\n\t\t{585, 585, 9: 3733},\n\t\t// 2260\n\t\t{587, 587},\n\t\t{586, 586},\n\t\t{171: 4286},\n\t\t{393: 2147, 598: 4288, 860: 4287},\n\t\t{590, 590, 9: 4289},\n\t\t// 2265\n\t\t{571, 571, 9: 571},\n\t\t{393: 2147, 598: 4290},\n\t\t{570, 570, 9: 570},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3720, 651: 4292},\n\t\t{591, 591, 9: 3727},\n\t\t// 2270\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4297},\n\t\t{379: 4295},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3720, 651: 4296},\n\t\t{583, 583, 9: 3727},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4298, 2178, 2179, 2177},\n\t\t// 2275\n\t\t{593, 593},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4300},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4301, 2178, 2179, 2177},\n\t\t{594, 594},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3720, 651: 4315},\n\t\t// 2280\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4304},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4305, 2178, 2179, 2177},\n\t\t{595, 595, 362: 4308, 836: 4307, 977: 4306},\n\t\t{592, 592, 9: 4313},\n\t\t{574, 574, 9: 574},\n\t\t// 2285\n\t\t{393: 2147, 598: 4309},\n\t\t{9: 4310},\n\t\t{393: 2147, 598: 4311},\n\t\t{361: 4312},\n\t\t{572, 572, 9: 572},\n\t\t// 2290\n\t\t{362: 4308, 836: 4314},\n\t\t{573, 573, 9: 573},\n\t\t{596, 596, 9: 3727},\n\t\t{131: 1336, 276: 4328, 299: 4329, 407: 1336, 933: 4327},\n\t\t{600, 600, 131: 1216, 170: 4321, 4320, 407: 1216},\n\t\t// 2295\n\t\t{131: 4319},\n\t\t{597, 597},\n\t\t{213, 213, 383: 3685, 393: 2147, 598: 4325, 645: 3686, 4324},\n\t\t{275: 4322},\n\t\t{393: 2147, 598: 4288, 860: 4323},\n\t\t// 2300\n\t\t{589, 589, 9: 4289},\n\t\t{599, 599},\n\t\t{213, 213, 383: 3685, 645: 3686, 4326},\n\t\t{598, 598},\n\t\t{588, 588},\n\t\t// 2305\n\t\t{393: 2147, 598: 4335},\n\t\t{239: 4331, 393: 2147, 598: 4330, 600: 4332},\n\t\t{577, 577},\n\t\t{393: 2147, 598: 4334},\n\t\t{393: 2147, 598: 4333},\n\t\t// 2310\n\t\t{575, 575},\n\t\t{576, 576},\n\t\t{578, 578},\n\t\t{2: 225, 225, 225, 225, 225, 225, 225, 10: 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 363: 225, 373: 225, 391: 1483, 407: 1483, 438: 225, 548: 1483},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 4427, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 391: 1449, 407: 1449, 537: 4346, 2178, 2179, 2177, 548: 1449, 671: 4381},\n\t\t// 2315\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 391: 1444, 407: 1444, 537: 4346, 2178, 2179, 2177, 548: 1444, 671: 4424},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 373: 4420, 391: 1442, 407: 1442, 438: 2567, 537: 2569, 2178, 2179, 2177, 548: 1442, 601: 2566, 648: 4419},\n\t\t{377: 4409, 391: 4408, 407: 1440, 548: 1440},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 4368, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 373: 4405, 391: 1434, 407: 1434, 537: 2569, 2178, 2179, 2177, 548: 1434, 600: 4403, 3419, 643: 3420, 3418, 667: 4371, 897: 4404, 1043: 4402},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 4400, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 391: 1432, 407: 1432, 537: 4346, 2178, 2179, 2177, 548: 1432, 671: 4378},\n\t\t// 2320\n\t\t{105: 4386, 391: 1416, 407: 1416, 548: 1416, 555: 4387, 738: 4385, 770: 4384},\n\t\t{669, 669, 9: 4374},\n\t\t{99: 4367},\n\t\t{391: 642, 407: 4365, 548: 642},\n\t\t{391: 4355, 548: 4356, 685: 4363},\n\t\t// 2325\n\t\t{391: 4355, 548: 4356, 685: 4359},\n\t\t{391: 4355, 548: 4356, 685: 4357},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 373: 4354, 438: 2567, 537: 2569, 2178, 2179, 2177, 601: 2566, 648: 4353, 944: 4352},\n\t\t{623, 623, 9: 623},\n\t\t{630, 630, 9: 630},\n\t\t// 2330\n\t\t{629, 629, 9: 629},\n\t\t{628, 628, 9: 628},\n\t\t{2: 644, 644, 644, 644, 644, 644, 644, 10: 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 362: 644, 644, 644, 366: 644, 644, 369: 644, 644, 644, 644, 644, 384: 644, 387: 644, 393: 644, 644, 407: 644, 431: 644, 438: 644, 447: 644, 450: 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 523: 644},\n\t\t{2: 643, 643, 643, 643, 643, 643, 643, 10: 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 362: 643, 643, 643, 366: 643, 643, 369: 643, 643, 643, 643, 643, 384: 643, 387: 643, 393: 643, 643, 407: 643, 431: 643, 438: 643, 447: 643, 450: 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 643, 523: 643},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4358},\n\t\t// 2335\n\t\t{635, 635, 9: 635, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 4360, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2643, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2610, 654: 4361, 735: 4362},\n\t\t{646, 646, 9: 646},\n\t\t{645, 645, 9: 645},\n\t\t{636, 636, 9: 636},\n\t\t// 2340\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 4360, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2643, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2610, 654: 4361, 735: 4364},\n\t\t{640, 640, 9: 640},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4366, 2178, 2179, 2177},\n\t\t{391: 641, 548: 641},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 4368, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 537: 2569, 2178, 2179, 2177, 600: 4370, 3419, 643: 3420, 3418, 667: 4371, 897: 4369},\n\t\t// 2345\n\t\t{661, 661, 447: 1358, 545: 661, 552: 1358},\n\t\t{545: 4372},\n\t\t{545: 660},\n\t\t{659, 659, 9: 3518, 545: 659},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3520, 711: 4373},\n\t\t// 2350\n\t\t{662, 662, 9: 3522},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 4336, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 4338, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 4375, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 4376, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 4339, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 387: 3205, 447: 4349, 465: 4348, 526: 3203, 537: 4346, 2178, 2179, 2177, 653: 4350, 671: 4347, 775: 4377},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 391: 1449, 407: 1449, 537: 4346, 2178, 2179, 2177, 548: 1449, 671: 4381},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 391: 1432, 407: 1432, 537: 4346, 2178, 2179, 2177, 548: 1432, 671: 4378},\n\t\t{622, 622, 9: 622},\n\t\t// 2355\n\t\t{391: 4355, 548: 4356, 685: 4379},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 4360, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2643, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2610, 654: 4361, 735: 4380},\n\t\t{638, 638, 9: 638},\n\t\t{391: 4355, 548: 4356, 685: 4382},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 4360, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2643, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2610, 654: 4361, 735: 4383},\n\t\t// 2360\n\t\t{639, 639, 9: 639},\n\t\t{664, 664, 9: 4398},\n\t\t{655, 655, 9: 655},\n\t\t{246: 4390},\n\t\t{176: 4389, 567: 4388},\n\t\t// 2365\n\t\t{652, 652, 9: 652},\n\t\t{651, 651, 9: 651},\n\t\t{278: 4392, 283: 4394, 555: 4393, 985: 4391},\n\t\t{653, 653, 9: 653},\n\t\t{555: 4397},\n\t\t// 2370\n\t\t{217: 4395, 303: 4396},\n\t\t{647, 647, 9: 647},\n\t\t{649, 649, 9: 649},\n\t\t{648, 648, 9: 648},\n\t\t{650, 650, 9: 650},\n\t\t// 2375\n\t\t{105: 4386, 555: 4387, 738: 4399},\n\t\t{654, 654, 9: 654},\n\t\t{105: 4386, 391: 1416, 407: 1416, 548: 1416, 555: 4387, 738: 4385, 770: 4401},\n\t\t{665, 665, 9: 4398},\n\t\t{663, 663},\n\t\t// 2380\n\t\t{660, 660, 966: 4406},\n\t\t{657, 657},\n\t\t{656, 656},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 537: 2569, 2178, 2179, 2177, 601: 3419, 643: 3420, 3418, 667: 4407},\n\t\t{658, 658, 9: 3518},\n\t\t// 2385\n\t\t{18: 4414, 363: 4413, 881: 4418},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 4410},\n\t\t{391: 4411},\n\t\t{18: 4414, 363: 4413, 881: 4412},\n\t\t{667, 667},\n\t\t// 2390\n\t\t{611, 611},\n\t\t{362: 4415},\n\t\t{363: 3490, 714: 4416},\n\t\t{361: 4417},\n\t\t{610, 610},\n\t\t// 2395\n\t\t{668, 668},\n\t\t{634, 634, 9: 634, 376: 4421},\n\t\t{631, 631, 9: 631},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 373: 4422, 537: 2569, 2178, 2179, 2177, 601: 4423},\n\t\t{633, 633, 9: 633},\n\t\t// 2400\n\t\t{632, 632, 9: 632},\n\t\t{391: 4355, 548: 4356, 685: 4425},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4426},\n\t\t{637, 637, 9: 637, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{105: 4386, 391: 1416, 407: 1416, 548: 1416, 555: 4387, 738: 4385, 770: 4428},\n\t\t// 2405\n\t\t{666, 666, 9: 4398},\n\t\t{545: 4438},\n\t\t{545: 4431},\n\t\t{174: 4432},\n\t\t{391: 4433},\n\t\t// 2410\n\t\t{363: 4434},\n\t\t{377: 4435},\n\t\t{173: 4436},\n\t\t{363: 4437},\n\t\t{670, 670},\n\t\t// 2415\n\t\t{174: 4439},\n\t\t{391: 4440},\n\t\t{363: 4441},\n\t\t{377: 4442},\n\t\t{173: 4443},\n\t\t// 2420\n\t\t{363: 4444},\n\t\t{671, 671},\n\t\t{362: 1028, 524: 1028, 600: 2925, 621: 2923, 2924, 630: 4446, 638: 4447, 961: 4449, 1070: 4448},\n\t\t{2: 1031, 1031, 1031, 1031, 1031, 1031, 1031, 10: 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 362: 1031, 1031, 366: 1031, 1031, 369: 1031, 1031, 1031, 1031, 1031, 384: 1031, 387: 1031, 393: 1031, 1031, 396: 1031, 406: 1031, 1031, 431: 1031, 438: 1031, 447: 1031, 450: 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 523: 1031, 1031, 612: 1031, 620: 1031, 623: 1031, 1031, 1031, 635: 1031},\n\t\t{362: 1027, 524: 1027},\n\t\t// 2425\n\t\t{362: 4453, 524: 2053, 606: 4455, 4450, 4451, 4452, 613: 4454},\n\t\t{362: 672, 524: 672},\n\t\t{1086, 1086, 361: 1086, 364: 1086, 1086, 368: 1086, 377: 1086, 2978, 1086, 1086, 1086, 390: 4516, 649: 2979, 4517, 830: 4515},\n\t\t{1086, 1086, 361: 1086, 364: 1086, 1086, 368: 1086, 377: 1086, 2978, 1086, 1086, 1086, 649: 2979, 4511},\n\t\t{1086, 1086, 361: 1086, 364: 1086, 1086, 368: 1086, 377: 1086, 2978, 1086, 1086, 1086, 649: 2979, 4460},\n\t\t// 2430\n\t\t{524: 2053, 606: 4456, 2054, 2055, 2056},\n\t\t{365: 675},\n\t\t{365: 674},\n\t\t{361: 4457},\n\t\t{1086, 1086, 361: 1086, 364: 1086, 673, 368: 1086, 378: 2978, 381: 1086, 649: 2979, 4458},\n\t\t// 2435\n\t\t{717, 717, 361: 717, 364: 717, 368: 717, 381: 3826, 668: 4459},\n\t\t{677, 677, 361: 677, 364: 677, 368: 677},\n\t\t{717, 717, 361: 717, 364: 717, 717, 368: 717, 377: 717, 379: 717, 717, 3826, 668: 4461},\n\t\t{684, 684, 361: 684, 364: 684, 684, 368: 684, 377: 4463, 379: 4464, 684, 693: 4462},\n\t\t{678, 678, 361: 678, 364: 678, 694, 368: 678, 380: 4471, 694: 4470},\n\t\t// 2440\n\t\t{616: 4468},\n\t\t{425: 4465},\n\t\t{284: 4466},\n\t\t{130: 4467},\n\t\t{681, 681, 361: 681, 364: 681, 681, 368: 681, 375: 681, 380: 681},\n\t\t// 2445\n\t\t{683, 683, 258: 4469, 361: 683, 364: 683, 683, 368: 683, 375: 683, 380: 683},\n\t\t{682, 682, 361: 682, 364: 682, 682, 368: 682, 375: 682, 380: 682},\n\t\t{832, 832, 361: 832, 364: 832, 832, 368: 832, 375: 832},\n\t\t{1014: 4472},\n\t\t{56: 4475, 363: 4473, 880: 4476, 1022: 4474},\n\t\t// 2450\n\t\t{78, 78, 52: 2574, 2573, 361: 78, 364: 78, 78, 368: 78, 375: 78, 541: 78, 675: 2572, 749: 4509},\n\t\t{78, 78, 52: 2574, 2573, 56: 4475, 361: 78, 364: 78, 78, 368: 78, 375: 78, 541: 78, 675: 2572, 749: 4506, 880: 4507},\n\t\t{363: 4477},\n\t\t{688, 688, 52: 688, 688, 56: 688, 361: 688, 364: 688, 688, 368: 688, 375: 688, 541: 688},\n\t\t{363: 4478},\n\t\t// 2455\n\t\t{691, 691, 52: 691, 691, 56: 691, 361: 691, 4479, 364: 691, 691, 368: 691, 375: 691, 541: 691, 1023: 4480},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 406: 4482, 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 4484, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 4483, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4481, 748: 4485, 826: 4486},\n\t\t{689, 689, 52: 689, 689, 56: 689, 361: 689, 364: 689, 689, 368: 689, 375: 689, 541: 689},\n\t\t{1540, 1540, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 1540, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 1540, 363: 4497, 1540, 1540, 368: 1540, 374: 4496, 1540, 377: 1540, 1540, 1540, 1540, 1540, 2760, 385: 2758, 2759, 388: 2757, 2755, 1540, 537: 4495, 2178, 2179, 2177, 596: 2756, 2754, 823: 4494, 4505},\n\t\t{1545, 1545, 9: 1545, 361: 1545, 364: 1545, 1545, 368: 1545, 375: 1545, 377: 1545, 1545, 1545, 1545, 1545, 390: 1545},\n\t\t// 2460\n\t\t{1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 363: 1069, 1069, 1069, 368: 1069, 1069, 1069, 1069, 1069, 374: 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 385: 1069, 1069, 388: 1069, 1069, 1069, 1069, 405: 1069, 1069, 4500, 425: 1069, 428: 1069, 1069, 1069, 432: 1069, 1069, 1069, 1069, 1069, 1069, 439: 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 448: 1069, 1069, 521: 1069, 542: 1069, 1069},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4490, 2178, 2179, 2177, 862: 3123, 3120, 3122, 3121},\n\t\t{1534, 1534, 9: 1534, 361: 1534, 364: 1534, 1534, 368: 1534, 375: 1534, 377: 1534, 1534, 1534, 1534, 1534, 390: 1534},\n\t\t{9: 4487, 361: 4488},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 406: 4482, 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 4484, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 4483, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4481, 748: 4489},\n\t\t// 2465\n\t\t{690, 690, 52: 690, 690, 56: 690, 361: 690, 364: 690, 690, 368: 690, 375: 690, 541: 690},\n\t\t{1533, 1533, 9: 1533, 361: 1533, 364: 1533, 1533, 368: 1533, 375: 1533, 377: 1533, 1533, 1533, 1533, 1533, 390: 1533},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4491},\n\t\t{382: 2760, 385: 2758, 2759, 388: 2757, 2755, 404: 4492, 596: 2756, 2754},\n\t\t{1540, 1540, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 1540, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 1540, 363: 4497, 1540, 1540, 368: 1540, 374: 4496, 1540, 377: 1540, 1540, 1540, 1540, 1540, 390: 1540, 537: 4495, 2178, 2179, 2177, 823: 4494, 4493},\n\t\t// 2470\n\t\t{1541, 1541, 9: 1541, 361: 1541, 364: 1541, 1541, 368: 1541, 375: 1541, 377: 1541, 1541, 1541, 1541, 1541, 390: 1541},\n\t\t{1539, 1539, 9: 1539, 361: 1539, 364: 1539, 1539, 368: 1539, 375: 1539, 377: 1539, 1539, 1539, 1539, 1539, 390: 1539},\n\t\t{1538, 1538, 9: 1538, 361: 1538, 364: 1538, 1538, 368: 1538, 375: 1538, 377: 1538, 1538, 1538, 1538, 1538, 390: 1538},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 4499, 537: 4498, 2178, 2179, 2177},\n\t\t{1536, 1536, 9: 1536, 361: 1536, 364: 1536, 1536, 368: 1536, 375: 1536, 377: 1536, 1536, 1536, 1536, 1536, 390: 1536},\n\t\t// 2475\n\t\t{1537, 1537, 9: 1537, 361: 1537, 364: 1537, 1537, 368: 1537, 375: 1537, 377: 1537, 1537, 1537, 1537, 1537, 390: 1537},\n\t\t{1535, 1535, 9: 1535, 361: 1535, 364: 1535, 1535, 368: 1535, 375: 1535, 377: 1535, 1535, 1535, 1535, 1535, 390: 1535},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 406: 4501, 537: 4502, 2178, 2179, 2177},\n\t\t{1544, 1544, 9: 1544, 361: 1544, 364: 1544, 1544, 368: 1544, 375: 1544, 377: 1544, 1544, 1544, 1544, 1544, 390: 1544},\n\t\t{1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 363: 1068, 1068, 1068, 368: 1068, 1068, 1068, 1068, 1068, 374: 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 385: 1068, 1068, 388: 1068, 1068, 1068, 1068, 405: 1068, 1068, 4503, 425: 1068, 428: 1068, 1068, 1068, 432: 1068, 1068, 1068, 1068, 1068, 1068, 439: 1068, 1068, 1068, 1068, 1068, 1068, 1068, 1068, 448: 1068, 1068, 521: 1068, 542: 1068, 1068},\n\t\t// 2480\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 406: 4504, 537: 3399, 2178, 2179, 2177},\n\t\t{1543, 1543, 9: 1543, 361: 1543, 364: 1543, 1543, 368: 1543, 375: 1543, 377: 1543, 1543, 1543, 1543, 1543, 390: 1543},\n\t\t{1542, 1542, 9: 1542, 361: 1542, 364: 1542, 1542, 368: 1542, 375: 1542, 377: 1542, 1542, 1542, 1542, 1542, 390: 1542},\n\t\t{65, 65, 361: 65, 364: 65, 65, 368: 65, 375: 65, 541: 2157, 726: 4508},\n\t\t{687, 687, 52: 687, 687, 56: 687, 361: 687, 364: 687, 687, 368: 687, 375: 687, 541: 687},\n\t\t// 2485\n\t\t{692, 692, 361: 692, 364: 692, 692, 368: 692, 375: 692},\n\t\t{65, 65, 361: 65, 364: 65, 65, 368: 65, 375: 65, 541: 2157, 726: 4510},\n\t\t{693, 693, 361: 693, 364: 693, 693, 368: 693, 375: 693},\n\t\t{717, 717, 361: 717, 364: 717, 717, 368: 717, 377: 717, 379: 717, 717, 3826, 668: 4512},\n\t\t{684, 684, 361: 684, 364: 684, 684, 368: 684, 377: 4463, 379: 4464, 684, 693: 4513},\n\t\t// 2490\n\t\t{679, 679, 361: 679, 364: 679, 694, 368: 679, 380: 4471, 694: 4514},\n\t\t{833, 833, 361: 833, 364: 833, 833, 368: 833, 375: 833},\n\t\t{213, 213, 361: 213, 364: 213, 213, 368: 213, 375: 213, 377: 213, 213, 213, 213, 213, 383: 3685, 645: 3686, 4542},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 452: 3579, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3585, 674: 3576, 697: 4523, 963: 4522, 1064: 4521},\n\t\t{717, 717, 361: 717, 364: 717, 717, 368: 717, 377: 717, 379: 717, 717, 3826, 668: 4518},\n\t\t// 2495\n\t\t{684, 684, 361: 684, 364: 684, 684, 368: 684, 377: 4463, 379: 4464, 684, 693: 4519},\n\t\t{680, 680, 361: 680, 364: 680, 694, 368: 680, 380: 4471, 694: 4520},\n\t\t{834, 834, 361: 834, 364: 834, 834, 368: 834, 375: 834},\n\t\t{213, 213, 361: 213, 364: 213, 213, 368: 213, 375: 213, 377: 213, 213, 213, 213, 213, 383: 3685, 397: 213, 213, 400: 213, 645: 3686, 4524},\n\t\t{831, 831, 361: 831, 364: 831, 831, 368: 831, 375: 831, 377: 831, 831, 831, 831, 831, 383: 831},\n\t\t// 2500\n\t\t{771, 771, 9: 3635, 361: 771, 364: 771, 771, 368: 771, 375: 771, 377: 771, 771, 771, 771, 771, 383: 771, 397: 771, 771, 400: 771},\n\t\t{696, 696, 361: 696, 364: 696, 696, 368: 696, 375: 696, 377: 696, 696, 696, 696, 696, 397: 696, 696, 400: 4525, 976: 4527, 1035: 4526},\n\t\t{546: 4540},\n\t\t{1531, 1531, 361: 1531, 364: 1531, 1531, 368: 1531, 375: 1531, 377: 1531, 1531, 1531, 1531, 1531, 397: 1531, 4528, 978: 4529},\n\t\t{695, 695, 361: 695, 364: 695, 695, 368: 695, 375: 695, 377: 695, 695, 695, 695, 695, 397: 695, 695},\n\t\t// 2505\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4539},\n\t\t{830, 830, 361: 830, 364: 830, 830, 368: 830, 375: 830, 377: 830, 830, 830, 830, 830, 397: 4531, 1084: 4530},\n\t\t{835, 835, 361: 835, 364: 835, 835, 368: 835, 375: 835, 377: 835, 835, 835, 835, 835},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2778, 2178, 2179, 2177, 740: 4534, 929: 4533, 1085: 4532},\n\t\t{829, 829, 9: 4537, 361: 829, 364: 829, 829, 368: 829, 375: 829, 377: 829, 829, 829, 829, 829},\n\t\t// 2510\n\t\t{828, 828, 9: 828, 361: 828, 364: 828, 828, 368: 828, 375: 828, 377: 828, 828, 828, 828, 828},\n\t\t{374: 4535},\n\t\t{362: 2779, 931: 4536},\n\t\t{826, 826, 9: 826, 361: 826, 364: 826, 826, 368: 826, 375: 826, 377: 826, 826, 826, 826, 826},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2778, 2178, 2179, 2177, 740: 4534, 929: 4538},\n\t\t// 2515\n\t\t{827, 827, 9: 827, 361: 827, 364: 827, 827, 368: 827, 375: 827, 377: 827, 827, 827, 827, 827},\n\t\t{1530, 1530, 361: 1530, 364: 1530, 1530, 368: 1530, 375: 1530, 377: 1530, 1530, 1530, 1530, 1530, 2760, 385: 2758, 2759, 388: 2757, 2755, 397: 1530, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2789, 699: 2790, 716: 4541},\n\t\t{1532, 1532, 9: 2792, 361: 1532, 364: 1532, 1532, 368: 1532, 375: 1532, 377: 1532, 1532, 1532, 1532, 1532, 397: 1532, 1532},\n\t\t{836, 836, 361: 836, 364: 836, 836, 368: 836, 375: 836, 377: 836, 836, 836, 836, 836},\n\t\t// 2520\n\t\t{717, 717, 361: 717, 364: 717, 717, 368: 717, 375: 717, 377: 717, 379: 717, 717, 3826, 668: 4544},\n\t\t{684, 684, 361: 684, 364: 684, 684, 368: 684, 375: 684, 377: 4463, 379: 4464, 684, 693: 4545},\n\t\t{694, 694, 361: 694, 364: 694, 694, 368: 694, 375: 694, 380: 4471, 694: 4470},\n\t\t{717, 717, 361: 717, 364: 717, 717, 368: 717, 375: 717, 377: 717, 379: 717, 717, 3826, 668: 4547},\n\t\t{684, 684, 361: 684, 364: 684, 684, 368: 684, 375: 684, 377: 4463, 379: 4464, 684, 693: 4548},\n\t\t// 2525\n\t\t{694, 694, 361: 694, 364: 694, 694, 368: 694, 375: 694, 380: 4471, 694: 4514},\n\t\t{717, 717, 361: 717, 364: 717, 717, 368: 717, 375: 717, 377: 717, 379: 717, 717, 3826, 668: 4550},\n\t\t{684, 684, 361: 684, 364: 684, 684, 368: 684, 375: 684, 377: 4463, 379: 4464, 684, 693: 4551},\n\t\t{694, 694, 361: 694, 364: 694, 694, 368: 694, 375: 694, 380: 4471, 694: 4520},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 406: 4482, 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 4484, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 4483, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4481, 748: 4485, 826: 4569, 1034: 4570},\n\t\t// 2530\n\t\t{2: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 10: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 362: 1030, 1030, 366: 1030, 1030, 369: 1030, 1030, 1030, 1030, 1030, 384: 1030, 387: 1030, 393: 1030, 1030, 396: 1030, 406: 1030, 1030, 431: 1030, 438: 1030, 447: 1030, 450: 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 1030, 523: 1030, 600: 2925, 612: 1030, 620: 1030, 2923, 2924, 1030, 1030, 1030, 630: 4446, 635: 1030, 638: 2927, 4554},\n\t\t{2: 865, 865, 865, 865, 865, 865, 865, 10: 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 362: 865, 865, 366: 865, 865, 369: 865, 865, 865, 865, 865, 384: 865, 387: 865, 393: 865, 865, 396: 865, 406: 865, 865, 431: 865, 438: 865, 447: 865, 450: 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 523: 865, 612: 865, 620: 3572, 623: 3571, 3570, 865, 635: 865, 709: 4555},\n\t\t{2: 701, 701, 701, 701, 701, 701, 701, 10: 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 362: 701, 701, 366: 701, 701, 369: 701, 701, 701, 701, 701, 384: 701, 387: 701, 393: 701, 701, 396: 701, 406: 701, 701, 431: 701, 438: 701, 447: 701, 450: 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 523: 701, 612: 701, 625: 701, 635: 4557, 1040: 4556},\n\t\t{2: 708, 708, 708, 708, 708, 708, 708, 10: 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 362: 708, 708, 366: 708, 708, 369: 708, 708, 708, 708, 708, 384: 708, 387: 708, 393: 708, 708, 396: 708, 406: 708, 708, 431: 708, 438: 708, 447: 708, 450: 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 523: 708, 612: 708, 625: 4559, 1037: 4558},\n\t\t{2: 700, 700, 700, 700, 700, 700, 700, 10: 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 362: 700, 700, 366: 700, 700, 369: 700, 700, 700, 700, 700, 384: 700, 387: 700, 393: 700, 700, 396: 700, 406: 700, 700, 431: 700, 438: 700, 447: 700, 450: 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 700, 523: 700, 612: 700, 625: 700},\n\t\t// 2535\n\t\t{2: 706, 706, 706, 706, 706, 706, 706, 10: 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 4561, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 362: 706, 706, 366: 706, 706, 369: 706, 706, 706, 706, 706, 384: 706, 387: 706, 393: 706, 706, 396: 706, 406: 706, 706, 431: 706, 438: 706, 447: 706, 450: 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 523: 706, 612: 706, 1038: 4560},\n\t\t{2: 707, 707, 707, 707, 707, 707, 707, 10: 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 362: 707, 707, 366: 707, 707, 369: 707, 707, 707, 707, 707, 384: 707, 387: 707, 393: 707, 707, 396: 707, 406: 707, 707, 431: 707, 438: 707, 447: 707, 450: 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 707, 523: 707, 612: 707},\n\t\t{2: 704, 704, 704, 704, 704, 704, 704, 10: 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 4563, 4564, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 362: 704, 704, 366: 704, 704, 369: 704, 704, 704, 704, 704, 384: 704, 387: 704, 393: 704, 704, 396: 704, 406: 704, 704, 431: 704, 438: 704, 447: 704, 450: 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 704, 523: 704, 612: 704, 1039: 4562},\n\t\t{2: 705, 705, 705, 705, 705, 705, 705, 10: 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 362: 705, 705, 366: 705, 705, 369: 705, 705, 705, 705, 705, 384: 705, 387: 705, 393: 705, 705, 396: 705, 406: 705, 705, 431: 705, 438: 705, 447: 705, 450: 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 523: 705, 612: 705},\n\t\t{2: 710, 710, 710, 710, 710, 710, 710, 10: 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 362: 710, 710, 366: 710, 710, 369: 710, 710, 710, 710, 710, 384: 710, 387: 710, 393: 710, 710, 396: 710, 406: 710, 710, 431: 710, 438: 710, 447: 710, 450: 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 523: 710, 612: 4566, 1033: 4565},\n\t\t// 2540\n\t\t{2: 703, 703, 703, 703, 703, 703, 703, 10: 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 362: 703, 703, 366: 703, 703, 369: 703, 703, 703, 703, 703, 384: 703, 387: 703, 393: 703, 703, 396: 703, 406: 703, 703, 431: 703, 438: 703, 447: 703, 450: 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 703, 523: 703, 612: 703},\n\t\t{2: 702, 702, 702, 702, 702, 702, 702, 10: 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 362: 702, 702, 366: 702, 702, 369: 702, 702, 702, 702, 702, 384: 702, 387: 702, 393: 702, 702, 396: 702, 406: 702, 702, 431: 702, 438: 702, 447: 702, 450: 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, 523: 702, 612: 702},\n\t\t{2: 699, 699, 699, 699, 699, 699, 699, 10: 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 362: 699, 699, 366: 699, 699, 369: 699, 699, 699, 699, 699, 384: 699, 387: 699, 393: 699, 699, 396: 4568, 406: 699, 699, 431: 699, 438: 699, 447: 699, 450: 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 699, 523: 699, 1041: 4567},\n\t\t{2: 709, 709, 709, 709, 709, 709, 709, 10: 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 362: 709, 709, 366: 709, 709, 369: 709, 709, 709, 709, 709, 384: 709, 387: 709, 393: 709, 709, 396: 709, 406: 709, 709, 431: 709, 438: 709, 447: 709, 450: 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 523: 709},\n\t\t{2: 713, 713, 713, 713, 713, 713, 713, 10: 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 362: 713, 713, 366: 713, 713, 369: 713, 713, 713, 713, 713, 384: 713, 387: 713, 393: 713, 713, 406: 713, 713, 431: 713, 438: 713, 447: 713, 450: 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, 523: 713},\n\t\t// 2545\n\t\t{2: 698, 698, 698, 698, 698, 698, 698, 10: 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 362: 698, 698, 366: 698, 698, 369: 698, 698, 698, 698, 698, 384: 698, 387: 698, 393: 698, 698, 406: 698, 698, 431: 698, 438: 698, 447: 698, 450: 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 523: 698},\n\t\t{697, 697, 9: 4487, 361: 697, 364: 697, 697, 368: 697, 375: 697, 377: 697, 697, 697, 697, 697, 390: 697},\n\t\t{837, 837, 361: 837, 364: 837, 837, 368: 837, 375: 837, 377: 837, 837, 837, 837, 837, 390: 837},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4572, 2178, 2179, 2177},\n\t\t{842, 842},\n\t\t// 2550\n\t\t{846, 846, 375: 4574},\n\t\t{447: 2763, 575: 4576, 1071: 4575},\n\t\t{845, 845, 9: 4577},\n\t\t{844, 844, 9: 844},\n\t\t{447: 2763, 575: 4578},\n\t\t// 2555\n\t\t{843, 843, 9: 843},\n\t\t{390: 4580},\n\t\t{363: 4582, 447: 2763, 575: 4583, 1026: 4581},\n\t\t{849, 849},\n\t\t{848, 848},\n\t\t// 2560\n\t\t{847, 847},\n\t\t{2: 1140, 1140, 1140, 1140, 1140, 1140, 1140, 10: 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 380: 4585, 844: 4586},\n\t\t{2: 1139, 1139, 1139, 1139, 1139, 1139, 1139, 10: 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4587},\n\t\t{115: 4593, 362: 4588, 392: 4592, 459: 4594, 524: 2053, 606: 4590, 2054, 2055, 2056, 613: 2059, 2058, 4591, 774: 4589, 842: 4595},\n\t\t// 2565\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 1864, 524: 2053, 537: 3361, 2178, 2179, 2177, 603: 3362, 606: 4615, 2054, 2055, 2056, 659: 4217, 788: 4614},\n\t\t{362: 4605, 692: 4604, 773: 4603},\n\t\t{1132, 1132, 364: 1132, 674},\n\t\t{1131, 1131, 364: 1131},\n\t\t{1117, 1117, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 1117, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 364: 1117, 537: 3361, 2178, 2179, 2177, 603: 4597, 791: 4598, 953: 4596},\n\t\t// 2570\n\t\t{362: 1129},\n\t\t{362: 1128},\n\t\t{1112, 1112},\n\t\t{1130, 1130, 9: 4601, 364: 1130},\n\t\t{391: 4599},\n\t\t// 2575\n\t\t{1116, 1116, 9: 1116, 364: 1116},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2643, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2610, 654: 4600},\n\t\t{1118, 1118, 9: 1118, 364: 1118},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 4597, 791: 4602},\n\t\t{1115, 1115, 9: 1115, 364: 1115},\n\t\t// 2580\n\t\t{1134, 1134, 9: 4612, 364: 1134},\n\t\t{1127, 1127, 9: 1127, 364: 1127},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 1124, 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2643, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2610, 654: 4608, 1073: 4607, 4606},\n\t\t{361: 4611},\n\t\t{9: 4609, 361: 1123},\n\t\t// 2585\n\t\t{9: 1121, 361: 1121},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2643, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 2610, 654: 4610},\n\t\t{9: 1122, 361: 1122},\n\t\t{1125, 1125, 9: 1125, 98: 1125, 364: 1125, 382: 1125},\n\t\t{362: 4605, 692: 4613},\n\t\t// 2590\n\t\t{1126, 1126, 9: 1126, 364: 1126},\n\t\t{361: 4617},\n\t\t{361: 4616},\n\t\t{1133, 1133, 364: 1133, 673},\n\t\t{115: 4593, 362: 4620, 459: 4594, 524: 2053, 606: 4619, 2054, 2055, 2056, 613: 2059, 2058, 4621, 774: 4618},\n\t\t// 2595\n\t\t{362: 4605, 692: 4604, 773: 4624},\n\t\t{1137, 1137, 364: 1137, 674},\n\t\t{524: 2053, 606: 4622, 2054, 2055, 2056},\n\t\t{1135, 1135, 364: 1135},\n\t\t{361: 4623},\n\t\t// 2600\n\t\t{1136, 1136, 364: 1136, 673},\n\t\t{1138, 1138, 9: 4612, 364: 1138},\n\t\t{2: 1525, 1525, 1525, 1525, 1525, 1525, 1525, 10: 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 380: 1525, 522: 3574, 723: 4626},\n\t\t{2: 1140, 1140, 1140, 1140, 1140, 1140, 1140, 10: 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 1140, 380: 4585, 844: 4627},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4628},\n\t\t// 2605\n\t\t{115: 4593, 362: 4588, 392: 4592, 459: 4594, 524: 2053, 606: 4590, 2054, 2055, 2056, 613: 2059, 2058, 4591, 774: 4589, 842: 4629},\n\t\t{1114, 1114, 364: 4631, 1002: 4630},\n\t\t{1141, 1141},\n\t\t{221: 4632},\n\t\t{527: 4633},\n\t\t// 2610\n\t\t{616: 4634},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3680, 713: 3681, 741: 4635},\n\t\t{1113, 1113, 9: 3683},\n\t\t{1624, 1624, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 4663},\n\t\t{1622, 1622},\n\t\t// 2615\n\t\t{17: 4661},\n\t\t{1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 10: 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 1451, 391: 4648, 407: 1451},\n\t\t{362: 3239, 384: 2046, 451: 2045, 524: 2053, 606: 4641, 2054, 2055, 2056, 613: 2059, 2058, 4646, 2130, 2038, 661: 4642, 664: 4644, 666: 4645, 670: 4643, 720: 4647},\n\t\t{396, 396, 365: 674},\n\t\t{395, 395},\n\t\t// 2620\n\t\t{394, 394},\n\t\t{393, 393},\n\t\t{392, 392},\n\t\t{391, 391},\n\t\t{1616, 1616},\n\t\t// 2625\n\t\t{128: 4652, 300: 4651, 363: 4649, 967: 4650},\n\t\t{362: 3239, 377: 4657, 384: 2046, 451: 2045, 524: 2053, 606: 4641, 2054, 2055, 2056, 613: 2059, 2058, 4646, 2130, 2038, 661: 4642, 664: 4644, 666: 4645, 670: 4643, 720: 4658},\n\t\t{362: 3239, 377: 4653, 384: 2046, 451: 2045, 524: 2053, 606: 4641, 2054, 2055, 2056, 613: 2059, 2058, 4646, 2130, 2038, 661: 4642, 664: 4644, 666: 4645, 670: 4643, 720: 4654},\n\t\t{362: 1615, 377: 1615, 384: 1615, 451: 1615, 524: 1615, 616: 1615, 1615},\n\t\t{362: 1614, 377: 1614, 384: 1614, 451: 1614, 524: 1614, 616: 1614, 1614},\n\t\t// 2630\n\t\t{17: 4655},\n\t\t{1617, 1617},\n\t\t{393: 2147, 598: 4656},\n\t\t{1618, 1618},\n\t\t{17: 4659},\n\t\t// 2635\n\t\t{1619, 1619},\n\t\t{393: 2147, 598: 4660},\n\t\t{1620, 1620},\n\t\t{393: 2147, 598: 4662},\n\t\t{1621, 1621},\n\t\t// 2640\n\t\t{1623, 1623},\n\t\t{1629, 1629},\n\t\t{391: 4679},\n\t\t{407, 407, 365: 674},\n\t\t{624, 624, 2391, 2276, 2393, 2183, 2281, 4336, 2256, 624, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 4340, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 4338, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 4337, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 4342, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 4343, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 4339, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 387: 3205, 447: 4349, 465: 4348, 526: 3203, 537: 4346, 2178, 2179, 2177, 653: 4350, 671: 4347, 775: 4351, 927: 4344},\n\t\t// 2645\n\t\t{406, 406},\n\t\t{405, 405},\n\t\t{404, 404},\n\t\t{403, 403},\n\t\t{402, 402},\n\t\t// 2650\n\t\t{401, 401},\n\t\t{400, 400},\n\t\t{399, 399},\n\t\t{398, 398},\n\t\t{397, 397},\n\t\t// 2655\n\t\t{11: 2551},\n\t\t{363: 4680},\n\t\t{36: 2033, 102: 2032, 104: 2035, 110: 2051, 362: 3239, 384: 2046, 392: 4667, 451: 2045, 524: 2053, 606: 4666, 2054, 2055, 2056, 613: 2059, 2058, 4672, 2130, 2038, 661: 4668, 664: 4670, 666: 4671, 670: 4669, 715: 4674, 718: 4675, 727: 4678, 4673, 734: 4676, 736: 4677, 920: 4681},\n\t\t{1628, 1628},\n\t\t{2: 1650, 1650, 1650, 1650, 1650, 1650, 1650, 10: 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 373: 1650, 376: 1650, 387: 1650, 431: 1650, 526: 1650},\n\t\t// 2660\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 431: 4715, 641: 4742},\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 431: 4715, 641: 4722},\n\t\t{57: 3707, 93: 4714, 605: 3706, 917: 4713},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 431: 4706, 537: 2537, 2178, 2179, 2177, 599: 3720, 651: 4705},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 431: 4702, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3520, 711: 4701},\n\t\t// 2665\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 431: 4698, 537: 2569, 2178, 2179, 2177, 601: 3419, 643: 3420, 3418, 667: 4697},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4696},\n\t\t{90: 4691},\n\t\t{377: 4692},\n\t\t{524: 2053, 606: 4693, 2054, 2055, 2056},\n\t\t// 2670\n\t\t{151, 151, 375: 4694},\n\t\t{524: 2053, 606: 4695, 2054, 2055, 2056},\n\t\t{150, 150},\n\t\t{1638, 1638},\n\t\t{1640, 1640, 9: 3518},\n\t\t// 2675\n\t\t{460: 4699},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 537: 2569, 2178, 2179, 2177, 601: 3419, 643: 3420, 3418, 667: 4700},\n\t\t{1639, 1639, 9: 3518},\n\t\t{1642, 1642, 9: 3522},\n\t\t{460: 4703},\n\t\t// 2680\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3520, 711: 4704},\n\t\t{1641, 1641, 9: 3522},\n\t\t{1637, 1637, 9: 3727, 553: 4711, 556: 4710, 733: 4712},\n\t\t{460: 4707},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3720, 651: 4708},\n\t\t// 2685\n\t\t{1637, 1637, 9: 3727, 553: 4711, 556: 4710, 733: 4709},\n\t\t{1643, 1643},\n\t\t{1636, 1636, 1636, 9: 1636, 395: 1636},\n\t\t{1635, 1635, 1635, 9: 1635, 395: 1635},\n\t\t{1644, 1644},\n\t\t// 2690\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 431: 4715, 641: 4719},\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 431: 4715, 641: 4716},\n\t\t{460: 4718},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3720, 651: 4717},\n\t\t{10, 10, 9: 3727},\n\t\t// 2695\n\t\t{2: 1528, 1528, 1528, 1528, 1528, 1528, 1528, 10: 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 363: 1528, 450: 1528},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 3720, 651: 4720},\n\t\t{1637, 1637, 9: 3727, 553: 4711, 556: 4710, 733: 4721},\n\t\t{1647, 1647},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4723, 2178, 2179, 2177},\n\t\t// 2700\n\t\t{364: 4724},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4725},\n\t\t{1764, 1764, 41: 4726, 379: 4727, 698: 4729, 707: 4728, 841: 4730},\n\t\t{153: 1632, 165: 1632, 167: 1632, 1632, 373: 1632, 391: 4081, 602: 4736},\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 373: 1632, 391: 4081, 602: 4733},\n\t\t// 2705\n\t\t{1763, 1763, 41: 4726, 698: 4732},\n\t\t{1762, 1762, 379: 4727, 707: 4731},\n\t\t{1648, 1648},\n\t\t{1760, 1760},\n\t\t{1761, 1761},\n\t\t// 2710\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 373: 4734, 537: 4735, 2178, 2179, 2177},\n\t\t{1952, 1952, 1952, 9: 1952, 41: 1952, 395: 1952},\n\t\t{1951, 1951, 1951, 9: 1951, 41: 1951, 395: 1951},\n\t\t{153: 4738, 165: 4741, 167: 4739, 4740, 373: 4737},\n\t\t{1957, 1957, 1957, 9: 1957, 379: 1957, 395: 1957},\n\t\t// 2715\n\t\t{1956, 1956, 1956, 9: 1956, 379: 1956, 395: 1956},\n\t\t{1955, 1955, 1955, 9: 1955, 379: 1955, 395: 1955},\n\t\t{1954, 1954, 1954, 9: 1954, 379: 1954, 395: 1954},\n\t\t{1953, 1953, 1953, 9: 1953, 379: 1953, 395: 1953},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3566, 2178, 2179, 2177, 673: 4743},\n\t\t// 2720\n\t\t{1649, 1649},\n\t\t{2: 865, 865, 865, 865, 865, 865, 865, 10: 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 390: 865, 522: 865, 620: 3572, 623: 3571, 3570, 709: 4745},\n\t\t{2: 851, 851, 851, 851, 851, 851, 851, 10: 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 4747, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 851, 390: 851, 522: 851, 1028: 4746},\n\t\t{2: 1525, 1525, 1525, 1525, 1525, 1525, 1525, 10: 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1525, 390: 1525, 522: 3574, 723: 4748},\n\t\t{2: 850, 850, 850, 850, 850, 850, 850, 10: 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 390: 850, 522: 850},\n\t\t// 2725\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 390: 4749, 537: 4751, 2178, 2179, 2177, 768: 4752, 912: 4750},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4766, 2178, 2179, 2177, 599: 4764, 768: 4752, 912: 4765},\n\t\t{9: 4760, 390: 4759},\n\t\t{9: 853, 375: 853, 390: 853, 407: 4754, 730: 4753},\n\t\t{9: 855, 375: 855, 390: 855},\n\t\t// 2730\n\t\t{9: 857, 375: 857, 390: 857},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 406: 4756, 537: 4755, 2178, 2179, 2177},\n\t\t{9: 853, 375: 853, 390: 853, 407: 4758, 730: 4757},\n\t\t{9: 852, 375: 852, 390: 852},\n\t\t{9: 856, 375: 856, 390: 856},\n\t\t// 2735\n\t\t{406: 4756},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 452: 3579, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3585, 674: 3576, 697: 4762},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4751, 2178, 2179, 2177, 768: 4761},\n\t\t{9: 854, 375: 854, 390: 854},\n\t\t{213, 213, 9: 3635, 383: 3685, 645: 3686, 4763},\n\t\t// 2740\n\t\t{1652, 1652},\n\t\t{758, 758, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 374: 3592, 378: 758, 381: 758, 383: 758, 522: 758, 537: 3591, 2178, 2179, 2177, 549: 758, 758, 710: 3647, 913: 4772},\n\t\t{9: 4760, 375: 4769},\n\t\t{861, 861, 861, 861, 861, 861, 861, 861, 861, 853, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 861, 374: 861, 853, 378: 861, 381: 861, 383: 861, 407: 4767, 522: 861, 549: 861, 861, 730: 4753},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 406: 4756, 537: 4768, 2178, 2179, 2177},\n\t\t// 2745\n\t\t{860, 860, 860, 860, 860, 860, 860, 860, 860, 853, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 860, 374: 860, 853, 378: 860, 381: 860, 383: 860, 407: 4758, 522: 860, 549: 860, 860, 730: 4757},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3583, 452: 3579, 537: 2537, 2178, 2179, 2177, 599: 3582, 632: 3581, 636: 3580, 3585, 674: 3576, 697: 4770},\n\t\t{213, 213, 9: 3635, 383: 3685, 645: 3686, 4771},\n\t\t{1651, 1651},\n\t\t{739, 739, 378: 739, 381: 739, 383: 739, 522: 3650, 549: 3651, 3649, 752: 3653, 3652, 839: 3654, 4773},\n\t\t// 2750\n\t\t{213, 213, 378: 213, 381: 213, 383: 3685, 645: 3686, 4774},\n\t\t{1086, 1086, 378: 2978, 381: 1086, 649: 2979, 4775},\n\t\t{721, 721, 381: 3689, 849: 4776},\n\t\t{1653, 1653},\n\t\t{1654, 1654, 9: 2962},\n\t\t// 2755\n\t\t{525: 4923},\n\t\t{525: 1758},\n\t\t{525: 1757},\n\t\t{525: 1756},\n\t\t{2: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 10: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 431: 3867, 642: 4907},\n\t\t// 2760\n\t\t{93: 4862, 605: 3896},\n\t\t{41: 4821, 51: 1671, 83: 1671, 551: 1671, 1075: 4820},\n\t\t{384: 4819},\n\t\t{2: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 10: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 363: 1527, 431: 3867, 450: 1527, 642: 4800},\n\t\t{2: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 10: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 363: 1527, 431: 3867, 642: 4794},\n\t\t// 2765\n\t\t{90: 4789},\n\t\t{377: 4790},\n\t\t{524: 2053, 606: 4791, 2054, 2055, 2056},\n\t\t{375: 4792},\n\t\t{524: 2053, 606: 4793, 2054, 2055, 2056},\n\t\t// 2770\n\t\t{152, 152},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 537: 2569, 2178, 2179, 2177, 601: 3419, 643: 4796, 3418, 895: 4797, 1032: 4795},\n\t\t{208, 208, 9: 4798},\n\t\t{155, 155, 9: 155},\n\t\t{154, 154, 9: 154},\n\t\t// 2775\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 3408, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 3417, 537: 2569, 2178, 2179, 2177, 601: 3419, 643: 4796, 3418, 895: 4799},\n\t\t{153, 153, 9: 153},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3472, 712: 3473, 739: 4801},\n\t\t{188, 188, 9: 3475, 368: 188, 547: 3536, 763: 3535, 4802},\n\t\t{202, 202, 368: 4804, 818: 4803},\n\t\t// 2780\n\t\t{209, 209},\n\t\t{122: 4807, 298: 4805, 363: 4806},\n\t\t{363: 4817},\n\t\t{363: 4812},\n\t\t{363: 4808, 766: 4809},\n\t\t// 2785\n\t\t{221, 221, 221, 9: 221, 395: 221},\n\t\t{199, 199, 9: 4810},\n\t\t{363: 4811},\n\t\t{220, 220, 220, 9: 220, 395: 220},\n\t\t{363: 4813},\n\t\t// 2790\n\t\t{198, 198, 122: 4815, 816: 4814},\n\t\t{200, 200},\n\t\t{363: 4808, 766: 4816},\n\t\t{197, 197, 9: 4810},\n\t\t{198, 198, 122: 4815, 816: 4818},\n\t\t// 2795\n\t\t{201, 201},\n\t\t{41: 1672, 51: 1672, 83: 1672, 551: 1672},\n\t\t{51: 1667, 83: 4827, 551: 1667, 1077: 4826},\n\t\t{391: 4822},\n\t\t{255: 4824, 295: 4825, 304: 4823},\n\t\t// 2800\n\t\t{51: 1670, 83: 1670, 551: 1670},\n\t\t{51: 1669, 83: 1669, 551: 1669},\n\t\t{51: 1668, 83: 1668, 551: 1668},\n\t\t{51: 1665, 551: 4831, 1080: 4830},\n\t\t{391: 4828},\n\t\t// 2805\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 4829},\n\t\t{51: 1666, 551: 1666},\n\t\t{51: 4835},\n\t\t{282: 4832},\n\t\t{83: 4833, 240: 4834},\n\t\t// 2810\n\t\t{51: 1664},\n\t\t{51: 1663},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4837, 1079: 4836},\n\t\t{362: 4839, 374: 1661, 1078: 4838},\n\t\t{362: 1662, 374: 1662},\n\t\t// 2815\n\t\t{374: 4845},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4841, 2178, 2179, 2177, 947: 4840},\n\t\t{9: 4843, 361: 4842},\n\t\t{9: 1659, 361: 1659},\n\t\t{374: 1660},\n\t\t// 2820\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4844, 2178, 2179, 2177},\n\t\t{9: 1658, 361: 1658},\n\t\t{362: 4848, 524: 2053, 606: 4846, 2054, 2055, 2056, 613: 2059, 2058, 4847, 959: 4849},\n\t\t{1680, 1680, 365: 674, 368: 1680},\n\t\t{1679, 1679, 368: 1679},\n\t\t// 2825\n\t\t{362: 3239, 524: 2053, 606: 4858, 2054, 2055, 2056, 613: 2059, 2058, 4859},\n\t\t{1657, 1657, 368: 4851, 1076: 4850},\n\t\t{1674, 1674},\n\t\t{81: 4853, 214: 4852},\n\t\t{528: 4856},\n\t\t// 2830\n\t\t{528: 4854},\n\t\t{729: 4855},\n\t\t{1655, 1655},\n\t\t{729: 4857},\n\t\t{1656, 1656},\n\t\t// 2835\n\t\t{361: 4861, 365: 674},\n\t\t{361: 4860},\n\t\t{1677, 1677, 368: 1677},\n\t\t{1678, 1678, 365: 673, 368: 1678},\n\t\t{2: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 10: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 431: 3867, 642: 4863},\n\t\t// 2840\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4864},\n\t\t{36, 36, 3: 36, 36, 36, 36, 36, 36, 10: 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36: 4869, 4872, 4875, 4877, 4870, 42: 4868, 4876, 4878, 4874, 4871, 4880, 365: 36, 373: 36, 376: 36, 378: 4879, 387: 36, 525: 36, 36, 530: 36, 36, 36, 544: 4873, 896: 4867, 957: 4865, 1042: 4866},\n\t\t{351, 351, 3: 4045, 4047, 4057, 4064, 1742, 4053, 10: 4046, 4049, 4075, 4048, 4051, 4052, 4054, 4059, 4062, 4060, 4058, 4063, 4077, 4065, 4076, 4080, 4073, 4068, 4067, 4069, 4061, 365: 4074, 373: 4044, 376: 1742, 387: 1742, 525: 4050, 1742, 530: 4072, 4071, 4070, 629: 4056, 657: 4055, 678: 4066, 681: 4079, 737: 4078, 797: 4906},\n\t\t{35, 35, 3: 35, 35, 35, 35, 35, 35, 10: 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36: 4869, 4872, 4875, 4877, 4870, 42: 4868, 4876, 4878, 4874, 4871, 4880, 365: 35, 373: 35, 376: 35, 378: 4879, 387: 35, 525: 35, 35, 530: 35, 35, 35, 544: 4873, 896: 4905},\n\t\t{34, 34, 3: 34, 34, 34, 34, 34, 34, 10: 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 36: 34, 34, 34, 34, 34, 42: 34, 34, 34, 34, 34, 34, 365: 34, 373: 34, 376: 34, 378: 34, 387: 34, 525: 34, 34, 530: 34, 34, 34, 544: 34},\n\t\t// 2845\n\t\t{370: 1632, 1632, 391: 4081, 393: 1632, 546: 4902, 602: 4901},\n\t\t{368: 4898, 370: 1632, 1632, 391: 4081, 393: 1632, 602: 4897},\n\t\t{370: 1632, 1632, 391: 4081, 393: 1632, 602: 4895},\n\t\t{27, 27, 3: 27, 27, 27, 27, 27, 27, 10: 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 36: 27, 27, 27, 27, 27, 42: 27, 27, 27, 27, 27, 27, 365: 27, 373: 27, 376: 27, 378: 27, 387: 27, 525: 27, 27, 530: 27, 27, 27, 544: 27},\n\t\t{38: 4892, 4893, 4890, 378: 4894, 544: 4891},\n\t\t// 2850\n\t\t{370: 1632, 1632, 391: 4081, 393: 1632, 602: 4888},\n\t\t{24, 24, 3: 24, 24, 24, 24, 24, 24, 10: 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 36: 24, 24, 24, 24, 24, 42: 24, 24, 24, 24, 24, 24, 365: 24, 373: 24, 376: 24, 378: 24, 387: 24, 525: 24, 24, 530: 24, 24, 24, 544: 24},\n\t\t{370: 1632, 1632, 391: 4081, 393: 1632, 602: 4881},\n\t\t{21, 21, 3: 21, 21, 21, 21, 21, 21, 10: 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 36: 21, 21, 21, 21, 21, 42: 21, 21, 21, 21, 21, 21, 365: 21, 373: 21, 376: 21, 378: 21, 387: 21, 525: 21, 21, 530: 21, 21, 21, 544: 21},\n\t\t{19, 19, 3: 19, 19, 19, 19, 19, 19, 10: 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 36: 19, 19, 19, 19, 19, 42: 19, 19, 19, 19, 19, 19, 365: 19, 373: 19, 376: 19, 378: 19, 387: 19, 525: 19, 19, 530: 19, 19, 19, 544: 19},\n\t\t// 2855\n\t\t{18, 18, 3: 18, 18, 18, 18, 18, 18, 10: 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 36: 18, 18, 18, 18, 18, 42: 18, 18, 18, 18, 18, 18, 365: 18, 373: 18, 376: 18, 378: 18, 387: 18, 525: 18, 18, 530: 18, 18, 18, 544: 18},\n\t\t{16, 16, 3: 16, 16, 16, 16, 16, 16, 10: 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 36: 16, 16, 16, 16, 16, 42: 16, 16, 16, 16, 16, 16, 365: 16, 373: 16, 376: 16, 378: 16, 387: 16, 525: 16, 16, 530: 16, 16, 16, 544: 16},\n\t\t{15, 15, 3: 15, 15, 15, 15, 15, 15, 10: 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 36: 15, 15, 15, 15, 15, 42: 15, 15, 15, 15, 15, 15, 365: 15, 373: 15, 376: 15, 378: 15, 387: 15, 525: 15, 15, 530: 15, 15, 15, 544: 15},\n\t\t{370: 4884, 4885, 393: 2147, 598: 4883, 680: 4882},\n\t\t{22, 22, 3: 22, 22, 22, 22, 22, 22, 10: 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 36: 22, 22, 22, 22, 22, 42: 22, 22, 22, 22, 22, 22, 365: 22, 373: 22, 376: 22, 378: 22, 387: 22, 525: 22, 22, 530: 22, 22, 22, 544: 22},\n\t\t// 2860\n\t\t{13, 13, 3: 13, 13, 13, 13, 13, 13, 10: 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 36: 13, 13, 13, 13, 13, 42: 13, 13, 13, 13, 13, 13, 365: 13, 373: 13, 376: 13, 378: 13, 387: 13, 525: 13, 13, 530: 13, 13, 13, 544: 13},\n\t\t{393: 2147, 598: 4887},\n\t\t{393: 2147, 598: 4886},\n\t\t{11, 11, 3: 11, 11, 11, 11, 11, 11, 10: 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 36: 11, 11, 11, 11, 11, 42: 11, 11, 11, 11, 11, 11, 365: 11, 373: 11, 376: 11, 378: 11, 387: 11, 525: 11, 11, 530: 11, 11, 11, 544: 11},\n\t\t{12, 12, 3: 12, 12, 12, 12, 12, 12, 10: 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36: 12, 12, 12, 12, 12, 42: 12, 12, 12, 12, 12, 12, 365: 12, 373: 12, 376: 12, 378: 12, 387: 12, 525: 12, 12, 530: 12, 12, 12, 544: 12},\n\t\t// 2865\n\t\t{370: 4884, 4885, 393: 2147, 598: 4883, 680: 4889},\n\t\t{25, 25, 3: 25, 25, 25, 25, 25, 25, 10: 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 36: 25, 25, 25, 25, 25, 42: 25, 25, 25, 25, 25, 25, 365: 25, 373: 25, 376: 25, 378: 25, 387: 25, 525: 25, 25, 530: 25, 25, 25, 544: 25},\n\t\t{26, 26, 3: 26, 26, 26, 26, 26, 26, 10: 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 36: 26, 26, 26, 26, 26, 42: 26, 26, 26, 26, 26, 26, 365: 26, 373: 26, 376: 26, 378: 26, 387: 26, 525: 26, 26, 530: 26, 26, 26, 544: 26},\n\t\t{23, 23, 3: 23, 23, 23, 23, 23, 23, 10: 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 36: 23, 23, 23, 23, 23, 42: 23, 23, 23, 23, 23, 23, 365: 23, 373: 23, 376: 23, 378: 23, 387: 23, 525: 23, 23, 530: 23, 23, 23, 544: 23},\n\t\t{20, 20, 3: 20, 20, 20, 20, 20, 20, 10: 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 36: 20, 20, 20, 20, 20, 42: 20, 20, 20, 20, 20, 20, 365: 20, 373: 20, 376: 20, 378: 20, 387: 20, 525: 20, 20, 530: 20, 20, 20, 544: 20},\n\t\t// 2870\n\t\t{17, 17, 3: 17, 17, 17, 17, 17, 17, 10: 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 36: 17, 17, 17, 17, 17, 42: 17, 17, 17, 17, 17, 17, 365: 17, 373: 17, 376: 17, 378: 17, 387: 17, 525: 17, 17, 530: 17, 17, 17, 544: 17},\n\t\t{14, 14, 3: 14, 14, 14, 14, 14, 14, 10: 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 36: 14, 14, 14, 14, 14, 42: 14, 14, 14, 14, 14, 14, 365: 14, 373: 14, 376: 14, 378: 14, 387: 14, 525: 14, 14, 530: 14, 14, 14, 544: 14},\n\t\t{370: 4884, 4885, 393: 2147, 598: 4883, 680: 4896},\n\t\t{28, 28, 3: 28, 28, 28, 28, 28, 28, 10: 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 36: 28, 28, 28, 28, 28, 42: 28, 28, 28, 28, 28, 28, 365: 28, 373: 28, 376: 28, 378: 28, 387: 28, 525: 28, 28, 530: 28, 28, 28, 544: 28},\n\t\t{370: 4884, 4885, 393: 2147, 598: 4883, 680: 4900},\n\t\t// 2875\n\t\t{370: 4884, 4885, 393: 2147, 598: 4883, 680: 4899},\n\t\t{29, 29, 3: 29, 29, 29, 29, 29, 29, 10: 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 36: 29, 29, 29, 29, 29, 42: 29, 29, 29, 29, 29, 29, 365: 29, 373: 29, 376: 29, 378: 29, 387: 29, 525: 29, 29, 530: 29, 29, 29, 544: 29},\n\t\t{30, 30, 3: 30, 30, 30, 30, 30, 30, 10: 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 36: 30, 30, 30, 30, 30, 42: 30, 30, 30, 30, 30, 30, 365: 30, 373: 30, 376: 30, 378: 30, 387: 30, 525: 30, 30, 530: 30, 30, 30, 544: 30},\n\t\t{370: 4884, 4885, 393: 2147, 598: 4883, 680: 4904},\n\t\t{370: 4884, 4885, 393: 2147, 598: 4883, 680: 4903},\n\t\t// 2880\n\t\t{31, 31, 3: 31, 31, 31, 31, 31, 31, 10: 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 36: 31, 31, 31, 31, 31, 42: 31, 31, 31, 31, 31, 31, 365: 31, 373: 31, 376: 31, 378: 31, 387: 31, 525: 31, 31, 530: 31, 31, 31, 544: 31},\n\t\t{32, 32, 3: 32, 32, 32, 32, 32, 32, 10: 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 36: 32, 32, 32, 32, 32, 42: 32, 32, 32, 32, 32, 32, 365: 32, 373: 32, 376: 32, 378: 32, 387: 32, 525: 32, 32, 530: 32, 32, 32, 544: 32},\n\t\t{33, 33, 3: 33, 33, 33, 33, 33, 33, 10: 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 36: 33, 33, 33, 33, 33, 42: 33, 33, 33, 33, 33, 33, 365: 33, 373: 33, 376: 33, 378: 33, 387: 33, 525: 33, 33, 530: 33, 33, 33, 544: 33},\n\t\t{37, 37},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3566, 2178, 2179, 2177, 673: 4908},\n\t\t// 2885\n\t\t{1748, 1748, 7: 1742, 12: 1742, 373: 4044, 376: 1742, 387: 1742, 526: 1742, 629: 4910, 684: 4912, 745: 4911, 960: 4909},\n\t\t{1753, 1753},\n\t\t{7: 3204, 12: 4916, 376: 4915, 387: 3205, 526: 3203, 653: 4914},\n\t\t{1747, 1747, 7: 1742, 12: 1742, 373: 4044, 376: 1742, 387: 1742, 526: 1742, 629: 4910, 684: 4913},\n\t\t{1746, 1746, 7: 1746, 12: 1746, 373: 1746, 376: 1746, 387: 1746, 526: 1746},\n\t\t// 2890\n\t\t{1745, 1745, 7: 1745, 12: 1745, 373: 1745, 376: 1745, 387: 1745, 526: 1745},\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 363: 1632, 391: 4081, 438: 1632, 602: 4921},\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 363: 1632, 391: 4081, 602: 4919},\n\t\t{363: 1632, 391: 4081, 602: 4917},\n\t\t{363: 4918},\n\t\t// 2895\n\t\t{1749, 1749, 7: 1749, 12: 1749, 373: 1749, 376: 1749, 387: 1749, 526: 1749},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 3995, 717: 4920},\n\t\t{1750, 1750, 7: 1750, 12: 1750, 373: 1750, 376: 1750, 387: 1750, 526: 1750},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 438: 2567, 537: 2569, 2178, 2179, 2177, 601: 2566, 648: 4922},\n\t\t{1751, 1751, 7: 1751, 12: 1751, 373: 1751, 376: 1751, 387: 1751, 526: 1751},\n\t\t// 2900\n\t\t{2: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 10: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 431: 3867, 642: 4924},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4925, 2178, 2179, 2177},\n\t\t{48: 4929, 364: 1511, 375: 4928, 689: 4927, 983: 4926},\n\t\t{364: 4935},\n\t\t{364: 1510},\n\t\t// 2905\n\t\t{84: 4932, 103: 4931, 111: 4933, 724: 4934},\n\t\t{84: 4932, 103: 4931, 111: 4933, 724: 4930},\n\t\t{1508, 1508, 1508, 1508, 6: 1508, 9: 1508, 41: 1508, 48: 1508, 1508, 1508, 364: 1508, 368: 1508, 375: 1508, 379: 1508, 395: 1508},\n\t\t{1507, 1507, 1507, 1507, 6: 1507, 9: 1507, 41: 1507, 48: 1507, 1507, 1507, 362: 1507, 364: 1507, 368: 1507, 375: 1507, 379: 1507, 395: 1507},\n\t\t{1506, 1506, 1506, 1506, 6: 1506, 9: 1506, 41: 1506, 48: 1506, 1506, 1506, 362: 1506, 364: 1506, 368: 1506, 375: 1506, 379: 1506, 395: 1506},\n\t\t// 2910\n\t\t{1505, 1505, 1505, 1505, 6: 1505, 9: 1505, 41: 1505, 48: 1505, 1505, 1505, 362: 1505, 364: 1505, 368: 1505, 375: 1505, 379: 1505, 395: 1505},\n\t\t{1509, 1509, 1509, 1509, 6: 1509, 9: 1509, 41: 1509, 48: 1509, 1509, 1509, 364: 1509, 368: 1509, 375: 1509, 379: 1509, 395: 1509},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4936},\n\t\t{362: 4937},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3949, 537: 3361, 2178, 2179, 2177, 603: 3948, 663: 3947, 676: 4938},\n\t\t// 2915\n\t\t{9: 3956, 361: 4939},\n\t\t{1521, 1521, 3: 1521, 6: 1521, 41: 1521, 48: 1521, 1521, 1521, 368: 1521, 375: 1521, 379: 1521, 705: 4940},\n\t\t{1764, 1764, 3: 4946, 6: 4943, 41: 4726, 48: 4929, 4949, 4948, 368: 4945, 375: 4928, 379: 4727, 687: 4947, 689: 4944, 698: 4729, 704: 4942, 707: 4728, 841: 4941},\n\t\t{1771, 1771},\n\t\t{1520, 1520, 1520, 1520, 6: 1520, 9: 1520, 41: 1520, 48: 1520, 1520, 1520, 368: 1520, 375: 1520, 379: 1520, 395: 1520},\n\t\t// 2920\n\t\t{391: 4081, 393: 1632, 602: 4953},\n\t\t{1518, 1518, 1518, 1518, 6: 1518, 9: 1518, 41: 1518, 48: 1518, 1518, 1518, 368: 1518, 375: 1518, 379: 1518, 395: 1518},\n\t\t{1015: 4951},\n\t\t{363: 4950},\n\t\t{1515, 1515, 1515, 1515, 6: 1515, 9: 1515, 41: 1515, 48: 1515, 1515, 1515, 368: 1515, 375: 1515, 379: 1515, 395: 1515},\n\t\t// 2925\n\t\t{1504, 1504, 1504, 1504, 6: 1504, 9: 1504, 41: 1504, 48: 1504, 1504, 1504, 368: 1504, 375: 1504, 379: 1504, 395: 1504},\n\t\t{1503, 1503, 1503, 1503, 6: 1503, 9: 1503, 41: 1503, 48: 1503, 1503, 1503, 368: 1503, 375: 1503, 379: 1503, 395: 1503},\n\t\t{1516, 1516, 1516, 1516, 6: 1516, 9: 1516, 41: 1516, 48: 1516, 1516, 1516, 368: 1516, 375: 1516, 379: 1516, 395: 1516},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4952, 2178, 2179, 2177},\n\t\t{1517, 1517, 1517, 1517, 6: 1517, 9: 1517, 41: 1517, 48: 1517, 1517, 1517, 368: 1517, 375: 1517, 379: 1517, 395: 1517},\n\t\t// 2930\n\t\t{393: 2147, 598: 3183, 611: 4954},\n\t\t{1519, 1519, 1519, 1519, 6: 1519, 9: 1519, 41: 1519, 48: 1519, 1519, 1519, 368: 1519, 375: 1519, 379: 1519, 395: 1519},\n\t\t{1879, 1879},\n\t\t{1889, 1889, 368: 4958, 555: 4957},\n\t\t{176: 4962, 567: 4961},\n\t\t// 2935\n\t\t{218: 4959},\n\t\t{286: 4960},\n\t\t{1887, 1887},\n\t\t{1888, 1888},\n\t\t{1886, 1886, 368: 4963},\n\t\t// 2940\n\t\t{100: 4964},\n\t\t{210: 4965},\n\t\t{227: 4971, 249: 4970, 256: 4969, 291: 4967, 555: 4968, 1066: 4966},\n\t\t{1885, 1885},\n\t\t{1884, 1884},\n\t\t// 2945\n\t\t{100: 4979},\n\t\t{555: 4976},\n\t\t{192: 4974},\n\t\t{192: 4972},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4973},\n\t\t// 2950\n\t\t{1880, 1880, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4975},\n\t\t{1881, 1881, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{100: 4977},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4978},\n\t\t// 2955\n\t\t{1882, 1882, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 4980},\n\t\t{1883, 1883, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{1891, 1891},\n\t\t{1890, 1890},\n\t\t// 2960\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5008, 651: 5007},\n\t\t{605: 4985},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 4986},\n\t\t{395: 4988, 525: 4987},\n\t\t{746, 746, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 746, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 368: 746, 529: 3661, 537: 3660, 2178, 2179, 2177, 688: 5005},\n\t\t// 2965\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 634: 4989},\n\t\t{9: 3643, 525: 4990},\n\t\t{746, 746, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 746, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 368: 746, 529: 3661, 537: 3660, 2178, 2179, 2177, 688: 4991},\n\t\t{1906, 1906, 9: 3663, 368: 4993, 658: 4992},\n\t\t{1907, 1907},\n\t\t// 2970\n\t\t{393: 2147, 598: 4996, 783: 4995, 938: 4994},\n\t\t{1905, 1905, 9: 5003},\n\t\t{1904, 1904, 9: 1904},\n\t\t{146: 4997, 148: 4999, 184: 5000, 203: 4998},\n\t\t{1902, 1902, 9: 1902},\n\t\t// 2975\n\t\t{1901, 1901, 9: 1901},\n\t\t{220: 5001, 306: 5002},\n\t\t{1898, 1898, 9: 1898},\n\t\t{1900, 1900, 9: 1900},\n\t\t{1899, 1899, 9: 1899},\n\t\t// 2980\n\t\t{393: 2147, 598: 4996, 783: 5004},\n\t\t{1903, 1903, 9: 1903},\n\t\t{1906, 1906, 9: 3663, 368: 4993, 658: 5006},\n\t\t{1910, 1910},\n\t\t{1906, 1906, 9: 3727, 368: 4993, 658: 5018},\n\t\t// 2985\n\t\t{859, 859, 9: 859, 368: 859, 395: 5010, 525: 5009},\n\t\t{746, 746, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 746, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 368: 746, 529: 3661, 537: 3660, 2178, 2179, 2177, 688: 5016},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 634: 5011},\n\t\t{1906, 1906, 9: 3643, 368: 4993, 525: 5013, 658: 5012},\n\t\t{1909, 1909},\n\t\t// 2990\n\t\t{746, 746, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 746, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 368: 746, 529: 3661, 537: 3660, 2178, 2179, 2177, 688: 5014},\n\t\t{1906, 1906, 9: 3663, 368: 4993, 658: 5015},\n\t\t{1908, 1908},\n\t\t{1906, 1906, 9: 3663, 368: 4993, 658: 5017},\n\t\t{1911, 1911},\n\t\t// 2995\n\t\t{1912, 1912},\n\t\t{605: 5024},\n\t\t{377: 5022},\n\t\t{605: 1914},\n\t\t{395: 5023, 605: 1915},\n\t\t// 3000\n\t\t{605: 1913},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5025},\n\t\t{395: 3639, 437: 760, 525: 760, 546: 760, 878: 5026},\n\t\t{437: 5029, 525: 5028, 546: 5030, 905: 5027},\n\t\t{1920, 1920},\n\t\t// 3005\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5037, 2178, 2179, 2177},\n\t\t{362: 4605, 692: 5032},\n\t\t{362: 4605, 692: 4604, 773: 5031},\n\t\t{1917, 1917, 9: 4612},\n\t\t{382: 5033},\n\t\t// 3010\n\t\t{362: 4605, 692: 5034},\n\t\t{98: 5035},\n\t\t{393: 2147, 598: 5036},\n\t\t{1918, 1918},\n\t\t{437: 5029, 546: 5030, 905: 5038},\n\t\t// 3015\n\t\t{1919, 1919},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5040},\n\t\t{572: 5042, 971: 5041},\n\t\t{1922, 1922, 545: 5046, 970: 5045},\n\t\t{100: 5043},\n\t\t// 3020\n\t\t{363: 2654, 577: 5044},\n\t\t{1923, 1923, 363: 3270, 545: 1923},\n\t\t{1924, 1924},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5047, 2178, 2179, 2177},\n\t\t{1921, 1921},\n\t\t// 3025\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 546: 5049, 599: 5050},\n\t\t{170: 5052},\n\t\t{1926, 1926, 393: 2147, 598: 5051},\n\t\t{1925, 1925},\n\t\t{393: 2147, 598: 5053},\n\t\t// 3030\n\t\t{1927, 1927},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5057, 919: 5056, 1065: 5055},\n\t\t{1931, 1931, 9: 5060},\n\t\t{1930, 1930, 9: 1930},\n\t\t{545: 5058},\n\t\t// 3035\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5059},\n\t\t{1928, 1928, 9: 1928},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5057, 919: 5061},\n\t\t{1929, 1929, 9: 1929},\n\t\t{605: 5078},\n\t\t// 3040\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 373: 4044, 376: 1742, 387: 1742, 526: 1742, 537: 3566, 2178, 2179, 2177, 629: 4910, 673: 5075, 684: 4912, 745: 5076},\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 363: 1529, 431: 4715, 450: 1529, 641: 5065},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 5066, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 450: 3471, 537: 2569, 2178, 2179, 2177, 601: 3470, 626: 3472, 712: 3473, 739: 5067},\n\t\t{1405, 1405, 9: 1405, 56: 1405, 60: 1405, 362: 5070, 368: 1405, 447: 1405, 547: 1405, 552: 1405},\n\t\t{188, 188, 9: 3475, 368: 188, 547: 3536, 763: 3535, 5068},\n\t\t// 3045\n\t\t{202, 202, 368: 4804, 818: 5069},\n\t\t{207, 207},\n\t\t{361: 5071},\n\t\t{60: 5072},\n\t\t{546: 5073},\n\t\t// 3050\n\t\t{363: 3490, 714: 5074},\n\t\t{206, 206},\n\t\t{7: 1742, 12: 1742, 373: 4044, 376: 1742, 387: 1742, 526: 1742, 629: 4910, 684: 4912, 745: 5077},\n\t\t{1754, 1754, 7: 1742, 12: 1742, 373: 4044, 376: 1742, 387: 1742, 526: 1742, 629: 4910, 684: 4913},\n\t\t{1755, 1755, 7: 1742, 12: 1742, 373: 4044, 376: 1742, 387: 1742, 526: 1742, 629: 4910, 684: 4913},\n\t\t// 3055\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5079},\n\t\t{1941, 1941, 1941, 4045, 4047, 4057, 4064, 1742, 4053, 10: 4046, 4049, 4075, 4048, 4051, 4052, 4054, 4059, 4062, 4060, 4058, 4063, 4077, 4065, 4076, 4080, 4073, 4068, 4067, 4069, 4061, 41: 4726, 113: 5090, 119: 5098, 121: 5099, 135: 5092, 142: 5108, 149: 5087, 157: 5094, 161: 5089, 166: 5093, 172: 5100, 179: 5095, 182: 5096, 185: 5109, 5110, 365: 4074, 368: 5107, 373: 4044, 376: 1742, 378: 5097, 4727, 387: 1742, 392: 5083, 395: 1941, 463: 5084, 525: 4050, 1742, 528: 5086, 530: 4072, 4071, 4070, 549: 5106, 554: 5088, 557: 5081, 5102, 560: 5101, 566: 5103, 568: 5085, 570: 5091, 629: 4056, 657: 4055, 678: 4066, 681: 4079, 698: 5105, 707: 5104, 737: 5082, 780: 5112, 936: 5111, 5080},\n\t\t{1740, 1740, 5321, 395: 4179, 879: 5320, 935: 5319},\n\t\t{395: 5313},\n\t\t{2014, 2014, 2014, 4045, 4047, 4057, 4064, 1742, 4053, 2014, 4046, 4049, 4075, 4048, 4051, 4052, 4054, 4059, 4062, 4060, 4058, 4063, 4077, 4065, 4076, 4080, 4073, 4068, 4067, 4069, 4061, 365: 4074, 373: 4044, 376: 1742, 387: 1742, 395: 2014, 525: 4050, 1742, 530: 4072, 4071, 4070, 629: 4056, 657: 4055, 678: 4066, 681: 4097},\n\t\t// 3060\n\t\t{297: 5306},\n\t\t{545: 5298},\n\t\t{2: 1946, 1946, 1946, 1946, 1946, 1946, 1946, 10: 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 362: 1946, 395: 5235, 431: 1946, 525: 1935, 527: 1935, 1935, 1935, 533: 1935, 535: 3920, 563: 1935, 1935, 682: 5134, 700: 5233, 743: 5236, 955: 5234},\n\t\t{395: 5231},\n\t\t{395: 5228},\n\t\t// 3065\n\t\t{2: 1946, 1946, 1946, 1946, 1946, 1946, 1946, 10: 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 395: 5212, 431: 1946, 525: 3672, 527: 3671, 5215, 5211, 563: 5214, 665: 5213, 682: 5134, 700: 5210},\n\t\t{395: 5199},\n\t\t{395: 5197},\n\t\t{395: 5194},\n\t\t{395: 5191},\n\t\t// 3070\n\t\t{8: 5188, 395: 5187},\n\t\t{8: 5184, 395: 5183},\n\t\t{395: 5178},\n\t\t{395: 5170},\n\t\t{546: 5163},\n\t\t// 3075\n\t\t{755: 5162},\n\t\t{755: 5161},\n\t\t{2: 1946, 1946, 1946, 1946, 1946, 1946, 1946, 10: 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 431: 1946, 682: 5134, 700: 5157},\n\t\t{2: 1946, 1946, 1946, 1946, 1946, 1946, 1946, 10: 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 431: 1946, 682: 5134, 700: 5149},\n\t\t{2: 1946, 1946, 1946, 1946, 1946, 1946, 1946, 10: 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946, 525: 5133, 528: 5132, 682: 5134, 700: 5131},\n\t\t// 3080\n\t\t{2: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 10: 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 374: 5120, 391: 4081, 525: 3672, 527: 3671, 545: 5118, 602: 5119, 665: 5121, 682: 5117},\n\t\t{1975, 1975, 1975, 9: 1975, 395: 1975},\n\t\t{1974, 1974, 1974, 9: 1974, 395: 1974},\n\t\t{1973, 1973, 1973, 9: 1973, 395: 1973},\n\t\t{114: 5116},\n\t\t// 3085\n\t\t{114: 5115},\n\t\t{1970, 1970, 1970, 9: 1970, 395: 1970},\n\t\t{1969, 1969, 1969, 9: 1969, 395: 1969},\n\t\t{1940, 1940, 1940, 9: 5113, 395: 1940},\n\t\t{1939, 1939, 1939, 9: 1939, 395: 1939},\n\t\t// 3090\n\t\t{3: 4045, 4047, 4057, 4064, 1742, 4053, 10: 4046, 4049, 4075, 4048, 4051, 4052, 4054, 4059, 4062, 4060, 4058, 4063, 4077, 4065, 4076, 4080, 4073, 4068, 4067, 4069, 4061, 41: 4726, 113: 5090, 119: 5098, 121: 5099, 135: 5092, 142: 5108, 149: 5087, 157: 5094, 161: 5089, 166: 5093, 172: 5100, 179: 5095, 182: 5096, 185: 5109, 5110, 365: 4074, 368: 5107, 373: 4044, 376: 1742, 378: 5097, 4727, 387: 1742, 392: 5083, 463: 5084, 525: 4050, 1742, 528: 5086, 530: 4072, 4071, 4070, 549: 5106, 554: 5088, 558: 5102, 560: 5101, 566: 5103, 568: 5085, 570: 5091, 629: 4056, 657: 4055, 678: 4066, 681: 4079, 698: 5105, 707: 5104, 737: 5082, 780: 5114},\n\t\t{1938, 1938, 1938, 9: 1938, 395: 1938},\n\t\t{1971, 1971, 1971, 9: 1971, 395: 1971},\n\t\t{1972, 1972, 1972, 9: 1972, 395: 1972},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5128, 2178, 2179, 2177},\n\t\t// 3095\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5127},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5126},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5125},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5122, 2178, 2179, 2177},\n\t\t{545: 5123},\n\t\t// 3100\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5124, 2178, 2179, 2177},\n\t\t{1976, 1976, 1976, 9: 1976, 395: 1976},\n\t\t{1977, 1977, 1977, 9: 1977, 395: 1977},\n\t\t{1978, 1978, 1978, 9: 1978, 395: 1978},\n\t\t{1979, 1979, 1979, 9: 1979, 395: 1979},\n\t\t// 3105\n\t\t{545: 5129},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5130, 2178, 2179, 2177},\n\t\t{1980, 1980, 1980, 9: 1980, 395: 1980},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 5140},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5137, 2178, 2179, 2177},\n\t\t// 3110\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5135, 2178, 2179, 2177},\n\t\t{2: 1945, 1945, 1945, 1945, 1945, 1945, 1945, 10: 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 1945, 362: 1945, 431: 1945},\n\t\t{49: 4949, 4948, 687: 5136},\n\t\t{1966, 1966, 1966, 9: 1966, 395: 1966},\n\t\t{95: 4007, 369: 5139, 747: 5138},\n\t\t// 3115\n\t\t{1968, 1968, 1968, 9: 1968, 395: 1968},\n\t\t{95: 4012},\n\t\t{392: 5141, 554: 5142},\n\t\t{373: 5144},\n\t\t{373: 5143},\n\t\t// 3120\n\t\t{1981, 1981, 1981, 9: 1981, 395: 1981},\n\t\t{362: 5146, 2654, 370: 4033, 4034, 393: 2649, 2645, 453: 2648, 2647, 457: 2653, 2652, 461: 2644, 2646, 470: 2651, 577: 2650, 4032, 904: 5145},\n\t\t{1983, 1983, 1983, 9: 1983, 395: 1983},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 5147},\n\t\t{361: 5148, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t// 3125\n\t\t{1982, 1982, 1982, 9: 1982, 395: 1982},\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 431: 4715, 641: 5150},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 5151},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3903, 683: 5152},\n\t\t{1944, 1944, 1944, 9: 1944, 31: 5154, 5155, 395: 1944, 742: 5153},\n\t\t// 3130\n\t\t{1984, 1984, 1984, 9: 1984, 395: 1984},\n\t\t{1943, 1943, 1943, 9: 1943, 395: 1943},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 5156},\n\t\t{1942, 1942, 1942, 9: 1942, 395: 1942},\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 431: 4715, 641: 5158},\n\t\t// 3135\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3903, 683: 5159},\n\t\t{1944, 1944, 1944, 9: 1944, 31: 5154, 5155, 395: 1944, 742: 5160},\n\t\t{1985, 1985, 1985, 9: 1985, 395: 1985},\n\t\t{1986, 1986, 1986, 9: 1986, 395: 1986},\n\t\t{1987, 1987, 1987, 9: 1987, 395: 1987},\n\t\t// 3140\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 5166, 779: 5165, 934: 5164},\n\t\t{1988, 1988, 1988, 9: 5168, 395: 1988},\n\t\t{1096, 1096, 1096, 9: 1096, 395: 1096},\n\t\t{1089, 1089, 1089, 9: 1089, 395: 1089, 411: 2796, 2795, 731: 5167},\n\t\t{1094, 1094, 1094, 9: 1094, 395: 1094},\n\t\t// 3145\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 5166, 779: 5169},\n\t\t{1095, 1095, 1095, 9: 1095, 395: 1095},\n\t\t{477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 3705, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 395: 477, 656: 3704, 677: 5171},\n\t\t{1965, 1965, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 1965, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 395: 1965, 537: 3641, 2178, 2179, 2177, 634: 5173, 1030: 5172},\n\t\t{1991, 1991, 1991, 9: 1991, 395: 1991},\n\t\t// 3150\n\t\t{9: 3643, 380: 5174},\n\t\t{362: 5175},\n\t\t{395: 4234, 758: 4233, 876: 5176},\n\t\t{9: 4270, 361: 5177},\n\t\t{1964, 1964, 1964, 9: 1964, 395: 1964},\n\t\t// 3155\n\t\t{2: 477, 477, 477, 477, 477, 477, 477, 10: 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 3705, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 600: 477, 656: 3704, 677: 5179},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 600: 5181, 634: 5182, 672: 5180},\n\t\t{1992, 1992, 1992, 9: 1992, 395: 1992},\n\t\t{1963, 1963, 1963, 8: 1963, 1963, 395: 1963},\n\t\t{1962, 1962, 1962, 8: 1962, 3643, 395: 1962},\n\t\t// 3160\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 600: 5181, 634: 5182, 672: 5185},\n\t\t{1993, 1993, 1993, 9: 1993, 395: 1993},\n\t\t{8: 5186},\n\t\t{1995, 1995, 1995, 9: 1995, 395: 1995},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 600: 5181, 634: 5182, 672: 5189},\n\t\t// 3165\n\t\t{1994, 1994, 1994, 9: 1994, 395: 1994},\n\t\t{8: 5190},\n\t\t{1996, 1996, 1996, 9: 1996, 395: 1996},\n\t\t{2: 477, 477, 477, 477, 477, 477, 477, 10: 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 3705, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 600: 477, 656: 3704, 677: 5192},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 600: 5181, 634: 5182, 672: 5193},\n\t\t// 3170\n\t\t{1997, 1997, 1997, 9: 1997, 395: 1997},\n\t\t{2: 477, 477, 477, 477, 477, 477, 477, 10: 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 3705, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 600: 477, 656: 3704, 677: 5195},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 600: 5181, 634: 5182, 672: 5196},\n\t\t{1998, 1998, 1998, 9: 1998, 395: 1998},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 600: 5181, 634: 5182, 672: 5198},\n\t\t// 3175\n\t\t{1999, 1999, 1999, 9: 1999, 395: 1999},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5200, 2178, 2179, 2177},\n\t\t{368: 5201},\n\t\t{605: 5202},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 2537, 2178, 2179, 2177, 599: 5203},\n\t\t// 3180\n\t\t{1961, 1961, 1961, 9: 1961, 142: 5207, 368: 5206, 395: 1961, 1093: 5205, 5204},\n\t\t{2000, 2000, 2000, 9: 2000, 395: 2000},\n\t\t{1960, 1960, 1960, 9: 1960, 395: 1960},\n\t\t{114: 5209},\n\t\t{114: 5208},\n\t\t// 3185\n\t\t{1958, 1958, 1958, 9: 1958, 395: 1958},\n\t\t{1959, 1959, 1959, 9: 1959, 395: 1959},\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 431: 4715, 641: 5225},\n\t\t{527: 5224},\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 431: 4715, 641: 5222},\n\t\t// 3190\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 431: 4715, 641: 5220},\n\t\t{527: 5217},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5216, 2178, 2179, 2177},\n\t\t{1967, 1967, 1967, 9: 1967, 395: 1967},\n\t\t{2: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 10: 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 1529, 431: 4715, 641: 5218},\n\t\t// 3195\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 4041, 2178, 2179, 2177, 911: 5219},\n\t\t{1989, 1989, 1989, 9: 1989, 395: 1989},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 5221, 2178, 2179, 2177},\n\t\t{1990, 1990, 1990, 9: 1990, 395: 1990},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 634: 5223},\n\t\t// 3200\n\t\t{2001, 2001, 2001, 9: 3643, 395: 2001},\n\t\t{2002, 2002, 2002, 9: 2002, 395: 2002},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 5226},\n\t\t{1637, 1637, 1637, 9: 1637, 395: 1637, 553: 4711, 556: 4710, 733: 5227},\n\t\t{2003, 2003, 2003, 9: 2003, 395: 2003},\n\t\t// 3205\n\t\t{81: 3705, 393: 477, 656: 3704, 677: 5229},\n\t\t{393: 2147, 598: 5230},\n\t\t{2004, 2004, 2004, 9: 2004, 395: 2004},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 600: 5181, 634: 5182, 672: 5232},\n\t\t{2005, 2005, 2005, 9: 2005, 395: 2005},\n\t\t// 3210\n\t\t{2: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 10: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 362: 1527, 431: 3867, 642: 5292},\n\t\t{2008, 2008, 2008, 9: 2008, 395: 2008},\n\t\t{1527, 1527, 1527, 9: 1527, 55: 1527, 81: 1527, 362: 1527, 395: 1527, 431: 3867, 642: 5287, 656: 1527},\n\t\t{525: 3672, 527: 3671, 5242, 5237, 533: 5240, 563: 5241, 5238, 665: 5239, 956: 5243},\n\t\t{527: 5281},\n\t\t// 3215\n\t\t{2: 1948, 1948, 1948, 1948, 1948, 1948, 1948, 10: 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 362: 1948, 525: 3672, 527: 3671, 665: 5256, 845: 5275},\n\t\t{2: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 10: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 362: 1527, 375: 1527, 431: 3867, 642: 5269},\n\t\t{2: 1948, 1948, 1948, 1948, 1948, 1948, 1948, 10: 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948, 362: 1948, 375: 1948, 525: 3672, 527: 3671, 665: 5256, 845: 5257},\n\t\t{527: 5248},\n\t\t{362: 5244},\n\t\t// 3220\n\t\t{388, 388, 388, 9: 388, 395: 388},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2619, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2624, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2621, 2623, 2637, 2638, 2636, 2632, 2639, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2629, 2628, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2626, 2630, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2627, 2399, 2266, 2302, 2204, 2620, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2625, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2635, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2616, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2631, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2622, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2617, 2618, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2640, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2633, 2634, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2641, 2642, 2528, 2408, 2514, 2515, 2516, 362: 2672, 2654, 366: 2683, 2687, 369: 2611, 2669, 2668, 2705, 2750, 384: 2686, 387: 2703, 393: 2649, 2645, 407: 2604, 431: 2681, 438: 2675, 447: 2609, 450: 2688, 2704, 2706, 2648, 2647, 2656, 2682, 2653, 2652, 2679, 2674, 2644, 2646, 2678, 2680, 2746, 2684, 2693, 2694, 2695, 2651, 2673, 2666, 2667, 2717, 2719, 2720, 2721, 2676, 2722, 2701, 2707, 2715, 2716, 2711, 2723, 2724, 2732, 2725, 2726, 2712, 2728, 2729, 2718, 2713, 2727, 2708, 2714, 2699, 2730, 2731, 2677, 2736, 2689, 2690, 2692, 2735, 2741, 2740, 2742, 2739, 2670, 2743, 2738, 2737, 2734, 2685, 2733, 2691, 2696, 2697, 523: 2612, 537: 2603, 2178, 2179, 2177, 573: 2663, 2671, 2745, 2657, 2650, 2662, 2660, 2658, 2659, 2698, 2710, 2709, 2702, 2700, 2655, 2665, 2744, 2664, 2661, 2615, 2614, 2613, 5245},\n\t\t{361: 5246, 382: 2760, 385: 2758, 2759, 388: 2757, 2755, 596: 2756, 2754},\n\t\t{1849, 1849, 1849, 9: 1849, 95: 4007, 369: 5139, 395: 1849, 747: 4009, 817: 5247},\n\t\t{1808, 1808, 1808, 9: 1808, 395: 1808},\n\t\t// 3225\n\t\t{2: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 10: 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 362: 1527, 431: 3867, 642: 5249},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 1523, 537: 5251, 2178, 2179, 2177, 703: 5250},\n\t\t{362: 5252},\n\t\t{362: 1522},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3949, 537: 3361, 2178, 2179, 2177, 603: 3948, 663: 3947, 676: 5253},\n\t\t// 3230\n\t\t{9: 3956, 361: 5254},\n\t\t{534: 3942, 762: 5255},\n\t\t{1809, 1809, 1809, 9: 1809, 395: 1809},\n\t\t{2: 1947, 1947, 1947, 1947, 1947, 1947, 1947, 10: 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947, 362: 1947, 375: 1947},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 1523, 375: 1523, 537: 5259, 2178, 2179, 2177, 703: 5260, 754: 5258},\n\t\t// 3235\n\t\t{362: 5265},\n\t\t{48: 5263, 362: 1522, 375: 1522},\n\t\t{362: 1514, 375: 5261},\n\t\t{84: 4932, 103: 4931, 111: 4933, 724: 5262},\n\t\t{362: 1513},\n\t\t// 3240\n\t\t{84: 4932, 103: 4931, 111: 4933, 724: 5264},\n\t\t{362: 1512},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3949, 537: 3361, 2178, 2179, 2177, 603: 3948, 663: 3947, 676: 5266},\n\t\t{9: 3956, 361: 5267},\n\t\t{1521, 1521, 1521, 1521, 6: 1521, 9: 1521, 48: 1521, 1521, 1521, 368: 1521, 375: 1521, 395: 1521, 705: 5268},\n\t\t// 3245\n\t\t{1810, 1810, 1810, 4946, 6: 4943, 9: 1810, 48: 4929, 4949, 4948, 368: 4945, 375: 4928, 395: 1810, 687: 4947, 689: 4944, 704: 4942},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 1523, 375: 1523, 537: 5259, 2178, 2179, 2177, 703: 5260, 754: 5270},\n\t\t{362: 5271},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3949, 537: 3361, 2178, 2179, 2177, 603: 3948, 663: 3947, 676: 5272},\n\t\t{9: 3956, 361: 5273},\n\t\t// 3250\n\t\t{1521, 1521, 1521, 1521, 6: 1521, 9: 1521, 48: 1521, 1521, 1521, 368: 1521, 375: 1521, 395: 1521, 705: 5274},\n\t\t{1811, 1811, 1811, 4946, 6: 4943, 9: 1811, 48: 4929, 4949, 4948, 368: 4945, 375: 4928, 395: 1811, 687: 4947, 689: 4944, 704: 4942},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 1523, 537: 5251, 2178, 2179, 2177, 703: 5276},\n\t\t{362: 5277},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3949, 537: 3361, 2178, 2179, 2177, 603: 3948, 663: 3947, 676: 5278},\n\t\t// 3255\n\t\t{9: 3956, 361: 5279},\n\t\t{1521, 1521, 1521, 1521, 6: 1521, 9: 1521, 48: 1521, 1521, 1521, 368: 1521, 375: 1521, 395: 1521, 705: 5280},\n\t\t{1812, 1812, 1812, 4946, 6: 4943, 9: 1812, 48: 4929, 4949, 4948, 368: 4945, 375: 4928, 395: 1812, 687: 4947, 689: 4944, 704: 4942},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 1523, 375: 1523, 537: 5259, 2178, 2179, 2177, 703: 5260, 754: 5282},\n\t\t{362: 5283},\n\t\t// 3260\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 3949, 537: 3361, 2178, 2179, 2177, 603: 3948, 663: 3947, 676: 5284},\n\t\t{9: 3956, 361: 5285},\n\t\t{1521, 1521, 1521, 1521, 6: 1521, 9: 1521, 48: 1521, 1521, 1521, 368: 1521, 375: 1521, 395: 1521, 705: 5286},\n\t\t{1813, 1813, 1813, 4946, 6: 4943, 9: 1813, 48: 4929, 4949, 4948, 368: 4945, 375: 4928, 395: 1813, 687: 4947, 689: 4944, 704: 4942},\n\t\t{477, 477, 477, 9: 477, 55: 477, 81: 3705, 362: 477, 395: 477, 656: 3704, 677: 5288},\n\t\t// 3265\n\t\t{1718, 1718, 1718, 9: 1718, 55: 5290, 362: 4231, 395: 1718, 877: 5289},\n\t\t{2007, 2007, 2007, 9: 2007, 395: 2007},\n\t\t{393: 2147, 598: 5291},\n\t\t{2006, 2006, 2006, 9: 2006, 395: 2006},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 362: 5294, 537: 3361, 2178, 2179, 2177, 603: 3903, 683: 5293},\n\t\t// 3270\n\t\t{1944, 1944, 1944, 9: 1944, 31: 5154, 5155, 395: 1944, 742: 5297},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3361, 2178, 2179, 2177, 603: 3903, 683: 3905, 767: 3906, 914: 5295},\n\t\t{9: 3908, 361: 5296},\n\t\t{2009, 2009, 2009, 9: 2009, 395: 2009},\n\t\t{2010, 2010, 2010, 9: 2010, 395: 2010},\n\t\t// 3275\n\t\t{7: 3204, 387: 3205, 526: 3203, 653: 5299},\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 373: 5301, 438: 2567, 537: 2569, 2178, 2179, 2177, 601: 2566, 648: 5300},\n\t\t{223, 223, 223, 9: 223, 376: 5303, 395: 223, 868: 5305},\n\t\t{223, 223, 223, 9: 223, 376: 5303, 395: 223, 868: 5302},\n\t\t{2011, 2011, 2011, 9: 2011, 395: 2011},\n\t\t// 3280\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 363: 2568, 537: 2569, 2178, 2179, 2177, 601: 3995, 717: 5304},\n\t\t{222, 222, 222, 9: 222, 395: 222},\n\t\t{2012, 2012, 2012, 9: 2012, 395: 2012},\n\t\t{279: 5307},\n\t\t{393: 2147, 598: 3183, 611: 5308},\n\t\t// 3285\n\t\t{2016, 2016, 2016, 9: 2016, 129: 5309, 395: 2016, 994: 5310},\n\t\t{242: 5311},\n\t\t{2013, 2013, 2013, 9: 2013, 395: 2013},\n\t\t{363: 4808, 766: 5312},\n\t\t{2015, 2015, 2015, 9: 4810, 395: 2015},\n\t\t// 3290\n\t\t{2: 2391, 2276, 2393, 2183, 2281, 2195, 2256, 10: 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 537: 3641, 2178, 2179, 2177, 634: 5314},\n\t\t{1906, 1906, 9: 3643, 368: 4993, 525: 5316, 658: 5315},\n\t\t{2020, 2020},\n\t\t{746, 746, 2391, 2276, 2393, 2183, 2281, 2195, 2256, 746, 2213, 2202, 2210, 2232, 2283, 2284, 2387, 2278, 2238, 2279, 2277, 2280, 2456, 2291, 2455, 2287, 2396, 2325, 2324, 2395, 2407, 2223, 2184, 2409, 2403, 2299, 2250, 2311, 2435, 2436, 2431, 2354, 2430, 2434, 2437, 2432, 2433, 2438, 2421, 2419, 2420, 2314, 2196, 2221, 2254, 2319, 2452, 2255, 2339, 2251, 2274, 2335, 2205, 2231, 2332, 2333, 2328, 2288, 2338, 2410, 2411, 2412, 2413, 2414, 2415, 2417, 2418, 2270, 2268, 2363, 2365, 2234, 2364, 2355, 2230, 2426, 2295, 2316, 2201, 2226, 2315, 2211, 2336, 2439, 2264, 2212, 2237, 2239, 2483, 2244, 2260, 2273, 2187, 2191, 2197, 2292, 2441, 2372, 2443, 2310, 2245, 2401, 2351, 2263, 2399, 2266, 2302, 2204, 2203, 2307, 2209, 2308, 2454, 2219, 2224, 2225, 2228, 2229, 2293, 2424, 2269, 2529, 2334, 2305, 2362, 2404, 2246, 2248, 2253, 2476, 2259, 2265, 2400, 2457, 2312, 2373, 2458, 2348, 2461, 2327, 2198, 2199, 2375, 2490, 2371, 2206, 2384, 2406, 2394, 2207, 2464, 2402, 2429, 2536, 2427, 2176, 2405, 2498, 2499, 2379, 2466, 2465, 2317, 2467, 2468, 2321, 2298, 2377, 2469, 2241, 2242, 2350, 2243, 2352, 2470, 2397, 2398, 2247, 2349, 2342, 2381, 2479, 2534, 2471, 2380, 2519, 2520, 2521, 2522, 2524, 2523, 2525, 2526, 2478, 2261, 2180, 2181, 2428, 2185, 2190, 2532, 2459, 2460, 2193, 2361, 2194, 2275, 2296, 2200, 2462, 2463, 2208, 2451, 2214, 2353, 2318, 2218, 2533, 2530, 2220, 2378, 2222, 2227, 2313, 2289, 2385, 2216, 2370, 2304, 2500, 2356, 2374, 2425, 2416, 2235, 2233, 2301, 2386, 2282, 2502, 2440, 2343, 2344, 2345, 2346, 2357, 2501, 2320, 2422, 2252, 2480, 2531, 2389, 2392, 2442, 2481, 2444, 2450, 2449, 2448, 2445, 2446, 2329, 2330, 2331, 2337, 2504, 2484, 2294, 2423, 2347, 2447, 2360, 2300, 2340, 2390, 2249, 2474, 2475, 2473, 2472, 2535, 2322, 2376, 2388, 2358, 2258, 2477, 2453, 2527, 2382, 2262, 2290, 2297, 2359, 2267, 2482, 2366, 2369, 2485, 2271, 2182, 2186, 2486, 2487, 2188, 2488, 2189, 2192, 2489, 2491, 2492, 2493, 2494, 2215, 2217, 2323, 2368, 2495, 2496, 2497, 2236, 2285, 2286, 2367, 2503, 2505, 2506, 2240, 2309, 2326, 2341, 2272, 2383, 2303, 2306, 2510, 2511, 2512, 2513, 2507, 2508, 2509, 2257, 2517, 2518, 2528, 2408, 2514, 2515, 2516, 368: 746, 529: 3661, 537: 3660, 2178, 2179, 2177, 688: 5317},\n\t\t{1906, 1906, 9: 3663, 368: 4993, 658: 5318},\n\t\t// 3295\n\t\t{2019, 2019},\n\t\t{2021, 2021},\n\t\t{2018, 2018},\n\t\t{263: 5322},\n\t\t{2017, 2017},\n\t\t// 3300\n\t\t{1630, 1630, 36: 2033, 97: 2047, 102: 2032, 104: 2035, 110: 2051, 113: 2129, 123: 2048, 125: 2065, 134: 2028, 137: 2052, 143: 2063, 2034, 155: 2050, 159: 2037, 163: 2029, 191: 2030, 204: 2040, 362: 2057, 379: 2136, 384: 2046, 392: 2062, 411: 2043, 451: 2045, 524: 2053, 2139, 550: 2131, 554: 2039, 557: 2031, 2026, 2036, 2061, 566: 2027, 574: 2120, 606: 2060, 2054, 2055, 2056, 613: 2059, 2058, 2114, 2130, 2038, 661: 2076, 664: 2102, 666: 2110, 670: 2123, 686: 2132, 695: 2064, 701: 2042, 715: 2072, 718: 2074, 727: 2134, 2105, 734: 2108, 736: 2115, 744: 2082, 777: 2067, 2068, 781: 2069, 2070, 784: 2071, 2073, 787: 2079, 792: 2086, 2080, 2081, 2085, 2087, 798: 2084, 2083, 801: 2075, 2049, 804: 2088, 2097, 2089, 2090, 2095, 2092, 2096, 2091, 2094, 2093, 815: 2066, 819: 2077, 2041, 2078, 2044, 827: 2099, 829: 2098, 834: 2101, 2100, 838: 2103, 846: 2138, 2137, 2104, 853: 2106, 855: 2126, 883: 2107, 888: 2111, 891: 2109, 2133, 2113, 2112, 898: 2117, 2116, 901: 2119, 903: 2127, 906: 2118, 5324, 921: 2121, 2122, 2135, 2125, 926: 2124},\n\t\t{389, 389},\n\t}\n)\n\nvar yyDebug = 0\n\ntype yyLexer interface {\n\tLex(lval *yySymType) int\n\tErrorf(format string, a ...interface{}) error\n\tAppendError(err error)\n\tErrors() (warns []error, errs []error)\n}\n\ntype yyLexerEx interface {\n\tyyLexer\n\tReduced(rule, state int, lval *yySymType) bool\n}\n\nfunc yySymName(c int) (s string) {\n\tx, ok := yyXLAT[c]\n\tif ok {\n\t\treturn yySymNames[x]\n\t}\n\n\treturn __yyfmt__.Sprintf(\"%d\", c)\n}\n\nfunc yylex1(yylex yyLexer, lval *yySymType) (n int) {\n\tn = yylex.Lex(lval)\n\tif n <= 0 {\n\t\tn = yyEOFCode\n\t}\n\tif yyDebug >= 3 {\n\t\t__yyfmt__.Printf(\"\\nlex %s(%#x %d), lval: %+v\\n\", yySymName(n), n, n, lval)\n\t}\n\treturn n\n}\n\nfunc yyParse(yylex yyLexer, parser *Parser) int {\n\tconst yyError = 1113\n\n\tyyEx, _ := yylex.(yyLexerEx)\n\tvar yyn int\n\tparser.yylval = yySymType{}\n\tyyS := parser.cache\n\n\tNerrs := 0   /* number of errors */\n\tErrflag := 0 /* error recovery flag */\n\tyyerrok := func() {\n\t\tif yyDebug >= 2 {\n\t\t\t__yyfmt__.Printf(\"yyerrok()\\n\")\n\t\t}\n\t\tErrflag = 0\n\t}\n\t_ = yyerrok\n\tyystate := 0\n\tyychar := -1\n\tvar yyxchar int\n\tvar yyshift int\n\tyyp := -1\n\tgoto yystack\n\nret0:\n\treturn 0\n\nret1:\n\treturn 1\n\nyystack:\n\t/* put a state and value onto the stack */\n\tyyp++\n\tif yyp+1 >= len(yyS) {\n\t\tnyys := make([]yySymType, len(yyS)*2)\n\t\tcopy(nyys, yyS)\n\t\tyyS = nyys\n\t\tparser.cache = yyS\n\t}\n\tparser.yyVAL = &yyS[yyp+1]\n\tyyS[yyp].yys = yystate\n\nyynewstate:\n\tif yychar < 0 {\n\t\tyychar = yylex1(yylex, &parser.yylval)\n\t\tvar ok bool\n\t\tif yyxchar, ok = yyXLAT[yychar]; !ok {\n\t\t\tyyxchar = len(yySymNames) // > tab width\n\t\t}\n\t}\n\tif yyDebug >= 4 {\n\t\tvar a []int\n\t\tfor _, v := range yyS[:yyp+1] {\n\t\t\ta = append(a, v.yys)\n\t\t}\n\t\t__yyfmt__.Printf(\"state stack %v\\n\", a)\n\t}\n\trow := yyParseTab[yystate]\n\tyyn = 0\n\tif yyxchar < len(row) {\n\t\tif yyn = int(row[yyxchar]); yyn != 0 {\n\t\t\tyyn += yyTabOfs\n\t\t}\n\t}\n\tswitch {\n\tcase yyn > 0: // shift\n\t\tyychar = -1\n\t\t*parser.yyVAL = parser.yylval\n\t\tyystate = yyn\n\t\tyyshift = yyn\n\t\tif yyDebug >= 2 {\n\t\t\t__yyfmt__.Printf(\"shift, and goto state %d\\n\", yystate)\n\t\t}\n\t\tif Errflag > 0 {\n\t\t\tErrflag--\n\t\t}\n\t\tgoto yystack\n\tcase yyn < 0: // reduce\n\tcase yystate == 1: // accept\n\t\tif yyDebug >= 2 {\n\t\t\t__yyfmt__.Println(\"accept\")\n\t\t}\n\t\tgoto ret0\n\t}\n\n\tif yyn == 0 {\n\t\t/* error ... attempt to resume parsing */\n\t\tswitch Errflag {\n\t\tcase 0: /* brand new error */\n\t\t\tif yyDebug >= 1 {\n\t\t\t\t__yyfmt__.Printf(\"no action for %s in state %d\\n\", yySymName(yychar), yystate)\n\t\t\t}\n\t\t\tmsg, ok := yyXErrors[yyXError{yystate, yyxchar}]\n\t\t\tif !ok {\n\t\t\t\tmsg, ok = yyXErrors[yyXError{yystate, -1}]\n\t\t\t}\n\t\t\tif !ok && yyshift != 0 {\n\t\t\t\tmsg, ok = yyXErrors[yyXError{yyshift, yyxchar}]\n\t\t\t}\n\t\t\tif !ok {\n\t\t\t\tmsg, ok = yyXErrors[yyXError{yyshift, -1}]\n\t\t\t}\n\t\t\tif !ok || msg == \"\" {\n\t\t\t\tmsg = \"syntax error\"\n\t\t\t}\n\t\t\t// ignore goyacc error message\n\t\t\tyylex.AppendError(yylex.Errorf(\"\"))\n\t\t\tNerrs++\n\t\t\tfallthrough\n\n\t\tcase 1, 2: /* incompletely recovered error ... try again */\n\t\t\tErrflag = 3\n\n\t\t\t/* find a state where \"error\" is a legal shift action */\n\t\t\tfor yyp >= 0 {\n\t\t\t\trow := yyParseTab[yyS[yyp].yys]\n\t\t\t\tif yyError < len(row) {\n\t\t\t\t\tyyn = int(row[yyError]) + yyTabOfs\n\t\t\t\t\tif yyn > 0 { // hit\n\t\t\t\t\t\tif yyDebug >= 2 {\n\t\t\t\t\t\t\t__yyfmt__.Printf(\"error recovery found error shift in state %d\\n\", yyS[yyp].yys)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyystate = yyn /* simulate a shift of \"error\" */\n\t\t\t\t\t\tgoto yystack\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* the current p has no shift on \"error\", pop stack */\n\t\t\t\tif yyDebug >= 2 {\n\t\t\t\t\t__yyfmt__.Printf(\"error recovery pops state %d\\n\", yyS[yyp].yys)\n\t\t\t\t}\n\t\t\t\tyyp--\n\t\t\t}\n\t\t\t/* there is no state on the stack with an error shift ... abort */\n\t\t\tif yyDebug >= 2 {\n\t\t\t\t__yyfmt__.Printf(\"error recovery failed\\n\")\n\t\t\t}\n\t\t\tgoto ret1\n\n\t\tcase 3: /* no shift yet; clobber input char */\n\t\t\tif yyDebug >= 2 {\n\t\t\t\t__yyfmt__.Printf(\"error recovery discards %s\\n\", yySymName(yychar))\n\t\t\t}\n\t\t\tif yychar == yyEOFCode {\n\t\t\t\tgoto ret1\n\t\t\t}\n\n\t\t\tyychar = -1\n\t\t\tgoto yynewstate /* try again in the same state */\n\t\t}\n\t}\n\n\tr := -yyn\n\tx0 := yyReductions[r]\n\tx, n := x0.xsym, x0.components\n\tyypt := yyp\n\t_ = yypt // guard against \"declared and not used\"\n\n\tyyp -= n\n\tif yyp+1 >= len(yyS) {\n\t\tnyys := make([]yySymType, len(yyS)*2)\n\t\tcopy(nyys, yyS)\n\t\tyyS = nyys\n\t\tparser.cache = yyS\n\t}\n\tparser.yyVAL = &yyS[yyp+1]\n\n\t/* consult goto table to find next state */\n\texState := yystate\n\tyystate = int(yyParseTab[yyS[yyp].yys][x]) + yyTabOfs\n\t/* reduction by production r */\n\tif yyDebug >= 2 {\n\t\t__yyfmt__.Printf(\"reduce using rule %v (%s), and goto state %d\\n\", r, yySymNames[x], yystate)\n\t}\n\n\tswitch r {\n\tcase 2:\n\t\t{\n\t\t\tspecs := yyS[yypt-1].item.([]*ast.AlterTableSpec)\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tspecs = append(specs, yyS[yypt-0].item.(*ast.AlterTableSpec))\n\t\t\t}\n\t\t\tparser.yyVAL.statement = &ast.AlterTableStmt{\n\t\t\t\tTable: yyS[yypt-2].item.(*ast.TableName),\n\t\t\t\tSpecs: specs,\n\t\t\t}\n\t\t}\n\tcase 3:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AnalyzeTableStmt{TableNames: []*ast.TableName{yyS[yypt-4].item.(*ast.TableName)}, PartitionNames: yyS[yypt-1].item.([]model.CIStr), AnalyzeOpts: yyS[yypt-0].item.([]ast.AnalyzeOpt)}\n\t\t}\n\tcase 4:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AnalyzeTableStmt{\n\t\t\t\tTableNames:     []*ast.TableName{yyS[yypt-6].item.(*ast.TableName)},\n\t\t\t\tPartitionNames: yyS[yypt-3].item.([]model.CIStr),\n\t\t\t\tIndexNames:     yyS[yypt-1].item.([]model.CIStr),\n\t\t\t\tIndexFlag:      true,\n\t\t\t\tAnalyzeOpts:    yyS[yypt-0].item.([]ast.AnalyzeOpt),\n\t\t\t}\n\t\t}\n\tcase 5:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\t\tTp:        ast.AlterTablePartition,\n\t\t\t\t\tPartition: yyS[yypt-0].item.(*ast.PartitionOptions),\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.item = nil\n\t\t\t}\n\t\t}\n\tcase 6:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableRemovePartitioning,\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The REMOVE PARTITIONING clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 7:\n\t\t{\n\t\t\tparser.yyVAL.item = []string{}\n\t\t}\n\tcase 8:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 9:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:      ast.AlterTableOption,\n\t\t\t\tOptions: yyS[yypt-0].item.([]*ast.TableOption),\n\t\t\t}\n\t\t}\n\tcase 10:\n\t\t{\n\t\t\ttiflashReplicaSpec := &ast.TiFlashReplicaSpec{\n\t\t\t\tCount:  yyS[yypt-1].item.(uint64),\n\t\t\t\tLabels: yyS[yypt-0].item.([]string),\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:             ast.AlterTableSetTiFlashReplica,\n\t\t\t\tTiFlashReplica: tiflashReplicaSpec,\n\t\t\t}\n\t\t}\n\tcase 11:\n\t\t{\n\t\t\top := &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableOption,\n\t\t\t\tOptions: []*ast.TableOption{{Tp: ast.TableOptionCharset, StrValue: yyS[yypt-1].item.(string),\n\t\t\t\t\tUintValue: ast.TableOptionCharsetWithConvertTo}},\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != \"\" {\n\t\t\t\top.Options = append(op.Options, &ast.TableOption{Tp: ast.TableOptionCollate, StrValue: yyS[yypt-0].item.(string)})\n\t\t\t}\n\t\t\tparser.yyVAL.item = op\n\t\t}\n\tcase 12:\n\t\t{\n\t\t\top := &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableOption,\n\t\t\t\tOptions: []*ast.TableOption{{Tp: ast.TableOptionCharset, Default: true,\n\t\t\t\t\tUintValue: ast.TableOptionCharsetWithConvertTo}},\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != \"\" {\n\t\t\t\top.Options = append(op.Options, &ast.TableOption{Tp: ast.TableOptionCollate, StrValue: yyS[yypt-0].item.(string)})\n\t\t\t}\n\t\t\tparser.yyVAL.item = op\n\t\t}\n\tcase 13:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tIfNotExists: yyS[yypt-2].item.(bool),\n\t\t\t\tTp:          ast.AlterTableAddColumns,\n\t\t\t\tNewColumns:  []*ast.ColumnDef{yyS[yypt-1].item.(*ast.ColumnDef)},\n\t\t\t\tPosition:    yyS[yypt-0].item.(*ast.ColumnPosition),\n\t\t\t}\n\t\t}\n\tcase 14:\n\t\t{\n\t\t\ttes := yyS[yypt-1].item.([]interface{})\n\t\t\tvar columnDefs []*ast.ColumnDef\n\t\t\tvar constraints []*ast.Constraint\n\t\t\tfor _, te := range tes {\n\t\t\t\tswitch te := te.(type) {\n\t\t\t\tcase *ast.ColumnDef:\n\t\t\t\t\tcolumnDefs = append(columnDefs, te)\n\t\t\t\tcase *ast.Constraint:\n\t\t\t\t\tconstraints = append(constraints, te)\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tIfNotExists:    yyS[yypt-3].item.(bool),\n\t\t\t\tTp:             ast.AlterTableAddColumns,\n\t\t\t\tNewColumns:     columnDefs,\n\t\t\t\tNewConstraints: constraints,\n\t\t\t}\n\t\t}\n\tcase 15:\n\t\t{\n\t\t\tconstraint := yyS[yypt-0].item.(*ast.Constraint)\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:         ast.AlterTableAddConstraint,\n\t\t\t\tConstraint: constraint,\n\t\t\t}\n\t\t}\n\tcase 16:\n\t\t{\n\t\t\tvar defs []*ast.PartitionDefinition\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tdefs = yyS[yypt-0].item.([]*ast.PartitionDefinition)\n\t\t\t}\n\t\t\tnoWriteToBinlog := yyS[yypt-1].item.(bool)\n\t\t\tif noWriteToBinlog {\n\t\t\t\tyylex.AppendError(yylex.Errorf(\"The NO_WRITE_TO_BINLOG option is parsed but ignored for now.\"))\n\t\t\t\tparser.lastErrorAsWarn()\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tIfNotExists:     yyS[yypt-2].item.(bool),\n\t\t\t\tNoWriteToBinlog: noWriteToBinlog,\n\t\t\t\tTp:              ast.AlterTableAddPartitions,\n\t\t\t\tPartDefinitions: defs,\n\t\t\t}\n\t\t}\n\tcase 17:\n\t\t{\n\t\t\tnoWriteToBinlog := yyS[yypt-2].item.(bool)\n\t\t\tif noWriteToBinlog {\n\t\t\t\tyylex.AppendError(yylex.Errorf(\"The NO_WRITE_TO_BINLOG option is parsed but ignored for now.\"))\n\t\t\t\tparser.lastErrorAsWarn()\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tIfNotExists:     yyS[yypt-3].item.(bool),\n\t\t\t\tNoWriteToBinlog: noWriteToBinlog,\n\t\t\t\tTp:              ast.AlterTableAddPartitions,\n\t\t\t\tNum:             getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t}\n\t\t}\n\tcase 18:\n\t\t{\n\t\t\tyylex.AppendError(yylex.Errorf(\"The CHECK PARTITIONING clause is parsed but not implement yet.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableCheckPartitions,\n\t\t\t}\n\t\t\tif yyS[yypt-0].item == nil {\n\t\t\t\tret.OnAllPartitions = true\n\t\t\t} else {\n\t\t\t\tret.PartitionNames = yyS[yypt-0].item.([]model.CIStr)\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t}\n\tcase 19:\n\t\t{\n\t\t\tnoWriteToBinlog := yyS[yypt-1].item.(bool)\n\t\t\tif noWriteToBinlog {\n\t\t\t\tyylex.AppendError(yylex.Errorf(\"The NO_WRITE_TO_BINLOG option is parsed but ignored for now.\"))\n\t\t\t\tparser.lastErrorAsWarn()\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:              ast.AlterTableCoalescePartitions,\n\t\t\t\tNoWriteToBinlog: noWriteToBinlog,\n\t\t\t\tNum:             getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t}\n\t\t}\n\tcase 20:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tIfExists:      yyS[yypt-2].item.(bool),\n\t\t\t\tTp:            ast.AlterTableDropColumn,\n\t\t\t\tOldColumnName: yyS[yypt-1].item.(*ast.ColumnName),\n\t\t\t}\n\t\t}\n\tcase 21:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{Tp: ast.AlterTableDropPrimaryKey}\n\t\t}\n\tcase 22:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tIfExists:       yyS[yypt-1].item.(bool),\n\t\t\t\tTp:             ast.AlterTableDropPartition,\n\t\t\t\tPartitionNames: yyS[yypt-0].item.([]model.CIStr),\n\t\t\t}\n\t\t}\n\tcase 23:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:             ast.AlterTableExchangePartition,\n\t\t\t\tPartitionNames: []model.CIStr{model.NewCIStr(yyS[yypt-4].ident)},\n\t\t\t\tNewTable:       yyS[yypt-1].item.(*ast.TableName),\n\t\t\t\tWithValidation: yyS[yypt-0].item.(bool),\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"TiDB does not support EXCHANGE PARTITION now, it would be parsed but ignored.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 24:\n\t\t{\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableTruncatePartition,\n\t\t\t}\n\t\t\tif yyS[yypt-0].item == nil {\n\t\t\t\tret.OnAllPartitions = true\n\t\t\t\tyylex.AppendError(yylex.Errorf(\"The TRUNCATE PARTITION ALL clause is parsed but ignored by all storage engines.\"))\n\t\t\t\tparser.lastErrorAsWarn()\n\t\t\t} else {\n\t\t\t\tret.PartitionNames = yyS[yypt-0].item.([]model.CIStr)\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t}\n\tcase 25:\n\t\t{\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tNoWriteToBinlog: yyS[yypt-1].item.(bool),\n\t\t\t\tTp:              ast.AlterTableOptimizePartition,\n\t\t\t}\n\t\t\tif yyS[yypt-0].item == nil {\n\t\t\t\tret.OnAllPartitions = true\n\t\t\t} else {\n\t\t\t\tret.PartitionNames = yyS[yypt-0].item.([]model.CIStr)\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t\tyylex.AppendError(yylex.Errorf(\"The OPTIMIZE PARTITION clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 26:\n\t\t{\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tNoWriteToBinlog: yyS[yypt-1].item.(bool),\n\t\t\t\tTp:              ast.AlterTableRepairPartition,\n\t\t\t}\n\t\t\tif yyS[yypt-0].item == nil {\n\t\t\t\tret.OnAllPartitions = true\n\t\t\t} else {\n\t\t\t\tret.PartitionNames = yyS[yypt-0].item.([]model.CIStr)\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t\tyylex.AppendError(yylex.Errorf(\"The REPAIR PARTITION clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 27:\n\t\t{\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableImportPartitionTablespace,\n\t\t\t}\n\t\t\tif yyS[yypt-1].item == nil {\n\t\t\t\tret.OnAllPartitions = true\n\t\t\t} else {\n\t\t\t\tret.PartitionNames = yyS[yypt-1].item.([]model.CIStr)\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t\tyylex.AppendError(yylex.Errorf(\"The IMPORT PARTITION TABLESPACE clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 28:\n\t\t{\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableDiscardPartitionTablespace,\n\t\t\t}\n\t\t\tif yyS[yypt-1].item == nil {\n\t\t\t\tret.OnAllPartitions = true\n\t\t\t} else {\n\t\t\t\tret.PartitionNames = yyS[yypt-1].item.([]model.CIStr)\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t\tyylex.AppendError(yylex.Errorf(\"The DISCARD PARTITION TABLESPACE clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 29:\n\t\t{\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableImportTablespace,\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t\tyylex.AppendError(yylex.Errorf(\"The IMPORT TABLESPACE clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 30:\n\t\t{\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableDiscardTablespace,\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t\tyylex.AppendError(yylex.Errorf(\"The DISCARD TABLESPACE clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 31:\n\t\t{\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tTp:              ast.AlterTableRebuildPartition,\n\t\t\t\tNoWriteToBinlog: yyS[yypt-1].item.(bool),\n\t\t\t}\n\t\t\tif yyS[yypt-0].item == nil {\n\t\t\t\tret.OnAllPartitions = true\n\t\t\t} else {\n\t\t\t\tret.PartitionNames = yyS[yypt-0].item.([]model.CIStr)\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t\tyylex.AppendError(yylex.Errorf(\"REBUILD PARTITION syntax is parsed but not implement for now.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 32:\n\t\t{\n\t\t\tret := yyS[yypt-0].item.(*ast.AlterTableSpec)\n\t\t\tret.NoWriteToBinlog = yyS[yypt-1].item.(bool)\n\t\t\tparser.yyVAL.item = ret\n\t\t\tyylex.AppendError(yylex.Errorf(\"REORGANIZE PARTITION syntax is parsed but not implement for now.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 33:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tIfExists: yyS[yypt-1].item.(bool),\n\t\t\t\tTp:       ast.AlterTableDropIndex,\n\t\t\t\tName:     yyS[yypt-0].ident,\n\t\t\t}\n\t\t}\n\tcase 34:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tIfExists: yyS[yypt-1].item.(bool),\n\t\t\t\tTp:       ast.AlterTableDropForeignKey,\n\t\t\t\tName:     yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 35:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:          ast.AlterTableOrderByColumns,\n\t\t\t\tOrderByList: yyS[yypt-0].item.([]*ast.AlterOrderItem),\n\t\t\t}\n\t\t}\n\tcase 36:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableDisableKeys,\n\t\t\t}\n\t\t}\n\tcase 37:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableEnableKeys,\n\t\t\t}\n\t\t}\n\tcase 38:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tIfExists:   yyS[yypt-2].item.(bool),\n\t\t\t\tTp:         ast.AlterTableModifyColumn,\n\t\t\t\tNewColumns: []*ast.ColumnDef{yyS[yypt-1].item.(*ast.ColumnDef)},\n\t\t\t\tPosition:   yyS[yypt-0].item.(*ast.ColumnPosition),\n\t\t\t}\n\t\t}\n\tcase 39:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tIfExists:      yyS[yypt-3].item.(bool),\n\t\t\t\tTp:            ast.AlterTableChangeColumn,\n\t\t\t\tOldColumnName: yyS[yypt-2].item.(*ast.ColumnName),\n\t\t\t\tNewColumns:    []*ast.ColumnDef{yyS[yypt-1].item.(*ast.ColumnDef)},\n\t\t\t\tPosition:      yyS[yypt-0].item.(*ast.ColumnPosition),\n\t\t\t}\n\t\t}\n\tcase 40:\n\t\t{\n\t\t\toption := &ast.ColumnOption{Expr: yyS[yypt-0].expr}\n\t\t\tcolDef := &ast.ColumnDef{\n\t\t\t\tName:    yyS[yypt-3].item.(*ast.ColumnName),\n\t\t\t\tOptions: []*ast.ColumnOption{option},\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:         ast.AlterTableAlterColumn,\n\t\t\t\tNewColumns: []*ast.ColumnDef{colDef},\n\t\t\t}\n\t\t}\n\tcase 41:\n\t\t{\n\t\t\toption := &ast.ColumnOption{Expr: yyS[yypt-1].expr}\n\t\t\tcolDef := &ast.ColumnDef{\n\t\t\t\tName:    yyS[yypt-5].item.(*ast.ColumnName),\n\t\t\t\tOptions: []*ast.ColumnOption{option},\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:         ast.AlterTableAlterColumn,\n\t\t\t\tNewColumns: []*ast.ColumnDef{colDef},\n\t\t\t}\n\t\t}\n\tcase 42:\n\t\t{\n\t\t\tcolDef := &ast.ColumnDef{\n\t\t\t\tName: yyS[yypt-2].item.(*ast.ColumnName),\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:         ast.AlterTableAlterColumn,\n\t\t\t\tNewColumns: []*ast.ColumnDef{colDef},\n\t\t\t}\n\t\t}\n\tcase 43:\n\t\t{\n\t\t\toldColName := &ast.ColumnName{Name: model.NewCIStr(yyS[yypt-2].ident)}\n\t\t\tnewColName := &ast.ColumnName{Name: model.NewCIStr(yyS[yypt-0].ident)}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:            ast.AlterTableRenameColumn,\n\t\t\t\tOldColumnName: oldColName,\n\t\t\t\tNewColumnName: newColName,\n\t\t\t}\n\t\t}\n\tcase 44:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:       ast.AlterTableRenameTable,\n\t\t\t\tNewTable: yyS[yypt-0].item.(*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 45:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:       ast.AlterTableRenameTable,\n\t\t\t\tNewTable: yyS[yypt-0].item.(*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 46:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:       ast.AlterTableRenameTable,\n\t\t\t\tNewTable: yyS[yypt-0].item.(*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 47:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:      ast.AlterTableRenameIndex,\n\t\t\t\tFromKey: model.NewCIStr(yyS[yypt-2].ident),\n\t\t\t\tToKey:   model.NewCIStr(yyS[yypt-0].ident),\n\t\t\t}\n\t\t}\n\tcase 48:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:       ast.AlterTableLock,\n\t\t\t\tLockType: yyS[yypt-0].item.(ast.LockType),\n\t\t\t}\n\t\t}\n\tcase 49:\n\t\t{\n\t\t\t// Parse it and ignore it. Just for compatibility.\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:        ast.AlterTableAlgorithm,\n\t\t\t\tAlgorithm: yyS[yypt-0].item.(ast.AlgorithmType),\n\t\t\t}\n\t\t}\n\tcase 50:\n\t\t{\n\t\t\t// Parse it and ignore it. Just for compatibility.\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableForce,\n\t\t\t}\n\t\t}\n\tcase 51:\n\t\t{\n\t\t\t// Parse it and ignore it. Just for compatibility.\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableWithValidation,\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The WITH/WITHOUT VALIDATION clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 52:\n\t\t{\n\t\t\t// Parse it and ignore it. Just for compatibility.\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableWithoutValidation,\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The WITH/WITHOUT VALIDATION clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 53:\n\t\t{\n\t\t\t// Parse it and ignore it. Just for compatibility.\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableSecondaryLoad,\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The SECONDARY_LOAD clause is parsed but not implement yet.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 54:\n\t\t{\n\t\t\t// Parse it and ignore it. Just for compatibility.\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp: ast.AlterTableSecondaryUnload,\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The SECONDARY_UNLOAD VALIDATION clause is parsed but not implement yet.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 55:\n\t\t{\n\t\t\t// Parse it and ignore it. Just for compatibility.\n\t\t\tc := &ast.Constraint{\n\t\t\t\tName:     yyS[yypt-1].ident,\n\t\t\t\tEnforced: yyS[yypt-0].item.(bool),\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:         ast.AlterTableAlterCheck,\n\t\t\t\tConstraint: c,\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The ALTER CHECK clause is parsed but not implemented yet.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 56:\n\t\t{\n\t\t\t// Parse it and ignore it. Just for compatibility.\n\t\t\tc := &ast.Constraint{\n\t\t\t\tName: yyS[yypt-0].ident,\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:         ast.AlterTableDropCheck,\n\t\t\t\tConstraint: c,\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The DROP CHECK clause is parsed but not implemented yet.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 57:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterTableSpec{\n\t\t\t\tTp:         ast.AlterTableIndexInvisible,\n\t\t\t\tName:       yyS[yypt-1].ident,\n\t\t\t\tVisibility: yyS[yypt-0].item.(ast.IndexVisibility),\n\t\t\t}\n\t\t}\n\tcase 58:\n\t\t{\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tTp:              ast.AlterTableReorganizePartition,\n\t\t\t\tOnAllPartitions: true,\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t}\n\tcase 59:\n\t\t{\n\t\t\tret := &ast.AlterTableSpec{\n\t\t\t\tTp:              ast.AlterTableReorganizePartition,\n\t\t\t\tPartitionNames:  yyS[yypt-4].item.([]model.CIStr),\n\t\t\t\tPartDefinitions: yyS[yypt-1].item.([]*ast.PartitionDefinition),\n\t\t\t}\n\t\t\tparser.yyVAL.item = ret\n\t\t}\n\tcase 60:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 61:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 62:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 63:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 64:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 65:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 66:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.AlgorithmTypeDefault\n\t\t}\n\tcase 67:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.AlgorithmTypeCopy\n\t\t}\n\tcase 68:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.AlgorithmTypeInplace\n\t\t}\n\tcase 69:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.AlgorithmTypeInstant\n\t\t}\n\tcase 70:\n\t\t{\n\t\t\tyylex.AppendError(ErrUnknownAlterAlgorithm.GenWithStackByArgs(yyS[yypt-2].ident))\n\t\t\treturn 1\n\t\t}\n\tcase 71:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.LockTypeDefault\n\t\t}\n\tcase 72:\n\t\t{\n\t\t\tid := strings.ToUpper(yyS[yypt-0].ident)\n\n\t\t\tif id == \"NONE\" {\n\t\t\t\tparser.yyVAL.item = ast.LockTypeNone\n\t\t\t} else if id == \"SHARED\" {\n\t\t\t\tparser.yyVAL.item = ast.LockTypeShared\n\t\t\t} else if id == \"EXCLUSIVE\" {\n\t\t\t\tparser.yyVAL.item = ast.LockTypeExclusive\n\t\t\t} else {\n\t\t\t\tyylex.AppendError(ErrUnknownAlterLock.GenWithStackByArgs(yyS[yypt-0].ident))\n\t\t\t\treturn 1\n\t\t\t}\n\t\t}\n\tcase 79:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnPosition{Tp: ast.ColumnPositionNone}\n\t\t}\n\tcase 80:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnPosition{Tp: ast.ColumnPositionFirst}\n\t\t}\n\tcase 81:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnPosition{\n\t\t\t\tTp:             ast.ColumnPositionAfter,\n\t\t\t\tRelativeColumn: yyS[yypt-0].item.(*ast.ColumnName),\n\t\t\t}\n\t\t}\n\tcase 82:\n\t\t{\n\t\t\tparser.yyVAL.item = make([]*ast.AlterTableSpec, 0, 1)\n\t\t}\n\tcase 83:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 84:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.AlterTableSpec{yyS[yypt-0].item.(*ast.AlterTableSpec)}\n\t\t}\n\tcase 85:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.AlterTableSpec), yyS[yypt-0].item.(*ast.AlterTableSpec))\n\t\t}\n\tcase 86:\n\t\t{\n\t\t\tparser.yyVAL.item = []model.CIStr{model.NewCIStr(yyS[yypt-0].ident)}\n\t\t}\n\tcase 87:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]model.CIStr), model.NewCIStr(yyS[yypt-0].ident))\n\t\t}\n\tcase 88:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 89:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 90:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(string)\n\t\t}\n\tcase 91:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 92:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.RenameTableStmt{\n\t\t\t\tOldTable:      yyS[yypt-0].item.([]*ast.TableToTable)[0].OldTable,\n\t\t\t\tNewTable:      yyS[yypt-0].item.([]*ast.TableToTable)[0].NewTable,\n\t\t\t\tTableToTables: yyS[yypt-0].item.([]*ast.TableToTable),\n\t\t\t}\n\t\t}\n\tcase 93:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.TableToTable{yyS[yypt-0].item.(*ast.TableToTable)}\n\t\t}\n\tcase 94:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.TableToTable), yyS[yypt-0].item.(*ast.TableToTable))\n\t\t}\n\tcase 95:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableToTable{\n\t\t\t\tOldTable: yyS[yypt-2].item.(*ast.TableName),\n\t\t\t\tNewTable: yyS[yypt-0].item.(*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 96:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.RecoverTableStmt{\n\t\t\t\tJobID: yyS[yypt-0].item.(int64),\n\t\t\t}\n\t\t}\n\tcase 97:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.RecoverTableStmt{\n\t\t\t\tTable: yyS[yypt-0].item.(*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 98:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.RecoverTableStmt{\n\t\t\t\tTable:  yyS[yypt-1].item.(*ast.TableName),\n\t\t\t\tJobNum: yyS[yypt-0].item.(int64),\n\t\t\t}\n\t\t}\n\tcase 99:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.FlashBackTableStmt{\n\t\t\t\tTable:     yyS[yypt-2].item.(*ast.TableName),\n\t\t\t\tTimestamp: yyS[yypt-1].item.(ast.ValueExpr),\n\t\t\t\tNewName:   yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 100:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].expr\n\t\t}\n\tcase 101:\n\t\t{\n\t\t\tparser.yyVAL.item = \"\"\n\t\t}\n\tcase 102:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 103:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.SplitRegionStmt{\n\t\t\t\tSplitSyntaxOpt: yyS[yypt-4].item.(*ast.SplitSyntaxOption),\n\t\t\t\tTable:          yyS[yypt-2].item.(*ast.TableName),\n\t\t\t\tPartitionNames: yyS[yypt-1].item.([]model.CIStr),\n\t\t\t\tSplitOpt:       yyS[yypt-0].item.(*ast.SplitOption),\n\t\t\t}\n\t\t}\n\tcase 104:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.SplitRegionStmt{\n\t\t\t\tSplitSyntaxOpt: yyS[yypt-6].item.(*ast.SplitSyntaxOption),\n\t\t\t\tTable:          yyS[yypt-4].item.(*ast.TableName),\n\t\t\t\tPartitionNames: yyS[yypt-3].item.([]model.CIStr),\n\t\t\t\tIndexName:      model.NewCIStr(yyS[yypt-1].ident),\n\t\t\t\tSplitOpt:       yyS[yypt-0].item.(*ast.SplitOption),\n\t\t\t}\n\t\t}\n\tcase 105:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SplitOption{\n\t\t\t\tLower: yyS[yypt-4].item.([]ast.ExprNode),\n\t\t\t\tUpper: yyS[yypt-2].item.([]ast.ExprNode),\n\t\t\t\tNum:   yyS[yypt-0].item.(int64),\n\t\t\t}\n\t\t}\n\tcase 106:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SplitOption{\n\t\t\t\tValueLists: yyS[yypt-0].item.([][]ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 107:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SplitSyntaxOption{}\n\t\t}\n\tcase 108:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SplitSyntaxOption{\n\t\t\t\tHasRegionFor: true,\n\t\t\t}\n\t\t}\n\tcase 109:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SplitSyntaxOption{\n\t\t\t\tHasPartition: true,\n\t\t\t}\n\t\t}\n\tcase 110:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SplitSyntaxOption{\n\t\t\t\tHasRegionFor: true,\n\t\t\t\tHasPartition: true,\n\t\t\t}\n\t\t}\n\tcase 111:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AnalyzeTableStmt{TableNames: yyS[yypt-1].item.([]*ast.TableName), AnalyzeOpts: yyS[yypt-0].item.([]ast.AnalyzeOpt)}\n\t\t}\n\tcase 112:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AnalyzeTableStmt{TableNames: []*ast.TableName{yyS[yypt-3].item.(*ast.TableName)}, IndexNames: yyS[yypt-1].item.([]model.CIStr), IndexFlag: true, AnalyzeOpts: yyS[yypt-0].item.([]ast.AnalyzeOpt)}\n\t\t}\n\tcase 113:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AnalyzeTableStmt{TableNames: []*ast.TableName{yyS[yypt-3].item.(*ast.TableName)}, IndexNames: yyS[yypt-1].item.([]model.CIStr), IndexFlag: true, Incremental: true, AnalyzeOpts: yyS[yypt-0].item.([]ast.AnalyzeOpt)}\n\t\t}\n\tcase 114:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AnalyzeTableStmt{TableNames: []*ast.TableName{yyS[yypt-3].item.(*ast.TableName)}, PartitionNames: yyS[yypt-1].item.([]model.CIStr), AnalyzeOpts: yyS[yypt-0].item.([]ast.AnalyzeOpt)}\n\t\t}\n\tcase 115:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AnalyzeTableStmt{\n\t\t\t\tTableNames:     []*ast.TableName{yyS[yypt-5].item.(*ast.TableName)},\n\t\t\t\tPartitionNames: yyS[yypt-3].item.([]model.CIStr),\n\t\t\t\tIndexNames:     yyS[yypt-1].item.([]model.CIStr),\n\t\t\t\tIndexFlag:      true,\n\t\t\t\tAnalyzeOpts:    yyS[yypt-0].item.([]ast.AnalyzeOpt),\n\t\t\t}\n\t\t}\n\tcase 116:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AnalyzeTableStmt{\n\t\t\t\tTableNames:     []*ast.TableName{yyS[yypt-5].item.(*ast.TableName)},\n\t\t\t\tPartitionNames: yyS[yypt-3].item.([]model.CIStr),\n\t\t\t\tIndexNames:     yyS[yypt-1].item.([]model.CIStr),\n\t\t\t\tIndexFlag:      true,\n\t\t\t\tIncremental:    true,\n\t\t\t\tAnalyzeOpts:    yyS[yypt-0].item.([]ast.AnalyzeOpt),\n\t\t\t}\n\t\t}\n\tcase 117:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.AnalyzeOpt{}\n\t\t}\n\tcase 118:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.([]ast.AnalyzeOpt)\n\t\t}\n\tcase 119:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.AnalyzeOpt{yyS[yypt-0].item.(ast.AnalyzeOpt)}\n\t\t}\n\tcase 120:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]ast.AnalyzeOpt), yyS[yypt-0].item.(ast.AnalyzeOpt))\n\t\t}\n\tcase 121:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.AnalyzeOpt{Type: ast.AnalyzeOptNumBuckets, Value: getUint64FromNUM(yyS[yypt-1].item)}\n\t\t}\n\tcase 122:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.AnalyzeOpt{Type: ast.AnalyzeOptNumTopN, Value: getUint64FromNUM(yyS[yypt-1].item)}\n\t\t}\n\tcase 123:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.AnalyzeOpt{Type: ast.AnalyzeOptCMSketchDepth, Value: getUint64FromNUM(yyS[yypt-2].item)}\n\t\t}\n\tcase 124:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.AnalyzeOpt{Type: ast.AnalyzeOptCMSketchWidth, Value: getUint64FromNUM(yyS[yypt-2].item)}\n\t\t}\n\tcase 125:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.AnalyzeOpt{Type: ast.AnalyzeOptNumSamples, Value: getUint64FromNUM(yyS[yypt-1].item)}\n\t\t}\n\tcase 126:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Assignment{Column: yyS[yypt-2].item.(*ast.ColumnName), Expr: yyS[yypt-0].expr}\n\t\t}\n\tcase 127:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.Assignment{yyS[yypt-0].item.(*ast.Assignment)}\n\t\t}\n\tcase 128:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.Assignment), yyS[yypt-0].item.(*ast.Assignment))\n\t\t}\n\tcase 129:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.Assignment{}\n\t\t}\n\tcase 131:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.BeginStmt{}\n\t\t}\n\tcase 132:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.BeginStmt{\n\t\t\t\tMode: ast.Pessimistic,\n\t\t\t}\n\t\t}\n\tcase 133:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.BeginStmt{\n\t\t\t\tMode: ast.Optimistic,\n\t\t\t}\n\t\t}\n\tcase 134:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.BeginStmt{}\n\t\t}\n\tcase 135:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.BeginStmt{}\n\t\t}\n\tcase 136:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.BeginStmt{}\n\t\t}\n\tcase 137:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.BeginStmt{\n\t\t\t\tReadOnly: true,\n\t\t\t}\n\t\t}\n\tcase 138:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.BeginStmt{\n\t\t\t\tReadOnly: true,\n\t\t\t\tBound:    yyS[yypt-0].item.(*ast.TimestampBound),\n\t\t\t}\n\t\t}\n\tcase 139:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TimestampBound{\n\t\t\t\tMode: ast.TimestampBoundStrong,\n\t\t\t}\n\t\t}\n\tcase 140:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TimestampBound{\n\t\t\t\tMode:      ast.TimestampBoundReadTimestamp,\n\t\t\t\tTimestamp: yyS[yypt-0].expr.(ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 141:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TimestampBound{\n\t\t\t\tMode:      ast.TimestampBoundMinReadTimestamp,\n\t\t\t\tTimestamp: yyS[yypt-0].expr.(ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 142:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TimestampBound{\n\t\t\t\tMode:      ast.TimestampBoundMaxStaleness,\n\t\t\t\tTimestamp: yyS[yypt-0].expr.(ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 143:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TimestampBound{\n\t\t\t\tMode:      ast.TimestampBoundExactStaleness,\n\t\t\t\tTimestamp: yyS[yypt-0].expr.(ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 144:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.BinlogStmt{Str: yyS[yypt-0].ident}\n\t\t}\n\tcase 145:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.ColumnDef{yyS[yypt-0].item.(*ast.ColumnDef)}\n\t\t}\n\tcase 146:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.ColumnDef), yyS[yypt-0].item.(*ast.ColumnDef))\n\t\t}\n\tcase 147:\n\t\t{\n\t\t\tcolDef := &ast.ColumnDef{Name: yyS[yypt-2].item.(*ast.ColumnName), Type: yyS[yypt-1].item.(string), Options: yyS[yypt-0].item.([]*ast.ColumnOption)}\n\t\t\tif !colDef.Validate() {\n\t\t\t\tyylex.AppendError(yylex.Errorf(\"Invalid column definition\"))\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = colDef\n\t\t}\n\tcase 148:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnName{Name: model.NewCIStr(yyS[yypt-0].ident)}\n\t\t}\n\tcase 149:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnName{Table: model.NewCIStr(yyS[yypt-2].ident), Name: model.NewCIStr(yyS[yypt-0].ident)}\n\t\t}\n\tcase 150:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnName{Schema: model.NewCIStr(yyS[yypt-4].ident), Table: model.NewCIStr(yyS[yypt-2].ident), Name: model.NewCIStr(yyS[yypt-0].ident)}\n\t\t}\n\tcase 151:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 152:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 153:\n\t\t{\n\t\t\tparser.yyVAL.item = \"LONG\"\n\t\t}\n\tcase 154:\n\t\t{\n\t\t\tparser.yyVAL.item = \"INT\"\n\t\t}\n\tcase 155:\n\t\t{\n\t\t\tparser.yyVAL.item = \"FLOAT\"\n\t\t}\n\tcase 156:\n\t\t{\n\t\t\tparser.yyVAL.item = \"DOUBLE\"\n\t\t}\n\tcase 157:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.ColumnName{yyS[yypt-0].item.(*ast.ColumnName)}\n\t\t}\n\tcase 158:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.ColumnName), yyS[yypt-0].item.(*ast.ColumnName))\n\t\t}\n\tcase 159:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.ColumnName{}\n\t\t}\n\tcase 160:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.([]*ast.ColumnName)\n\t\t}\n\tcase 161:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.ColumnNameOrUserVar{}\n\t\t}\n\tcase 162:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.([]*ast.ColumnNameOrUserVar)\n\t\t}\n\tcase 163:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.ColumnNameOrUserVar{yyS[yypt-0].item.(*ast.ColumnNameOrUserVar)}\n\t\t}\n\tcase 164:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.ColumnNameOrUserVar), yyS[yypt-0].item.(*ast.ColumnNameOrUserVar))\n\t\t}\n\tcase 165:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnNameOrUserVar{ColumnName: yyS[yypt-0].item.(*ast.ColumnName)}\n\t\t}\n\tcase 166:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnNameOrUserVar{UserVar: yyS[yypt-0].expr.(*ast.VariableExpr)}\n\t\t}\n\tcase 167:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.ColumnNameOrUserVar{}\n\t\t}\n\tcase 168:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item.([]*ast.ColumnNameOrUserVar)\n\t\t}\n\tcase 169:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.CommitStmt{}\n\t\t}\n\tcase 172:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 173:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 174:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 175:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 176:\n\t\t{\n\t\t\tparser.yyVAL.item = 0\n\t\t}\n\tcase 177:\n\t\t{\n\t\t\tif yyS[yypt-0].item.(bool) {\n\t\t\t\tparser.yyVAL.item = 1\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.item = 2\n\t\t\t}\n\t\t}\n\tcase 178:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionNotNull}\n\t\t}\n\tcase 179:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionNull}\n\t\t}\n\tcase 180:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionAutoIncrement}\n\t\t}\n\tcase 181:\n\t\t{\n\t\t\t// KEY is normally a synonym for INDEX. The key attribute PRIMARY KEY\n\t\t\t// can also be specified as just KEY when given in a column definition.\n\t\t\t// See http://dev.mysql.com/doc/refman/5.7/en/create-table.html\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionPrimaryKey}\n\t\t}\n\tcase 182:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionUniqKey}\n\t\t}\n\tcase 183:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionUniqKey}\n\t\t}\n\tcase 184:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionDefaultValue, Expr: yyS[yypt-0].expr}\n\t\t}\n\tcase 185:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.ColumnOption{{Tp: ast.ColumnOptionNotNull}, {Tp: ast.ColumnOptionAutoIncrement}, {Tp: ast.ColumnOptionUniqKey}}\n\t\t}\n\tcase 186:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionOnUpdate, Expr: yyS[yypt-0].expr}\n\t\t}\n\tcase 187:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionComment, Expr: ast.NewValueExpr(yyS[yypt-0].ident)}\n\t\t}\n\tcase 188:\n\t\t{\n\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/create-table.html\n\t\t\t// The CHECK clause is parsed but ignored by all storage engines.\n\t\t\t// See the branch named `EnforcedOrNotOrNotNullOpt`.\n\n\t\t\toptionCheck := &ast.ColumnOption{\n\t\t\t\tTp:       ast.ColumnOptionCheck,\n\t\t\t\tExpr:     yyS[yypt-2].expr,\n\t\t\t\tEnforced: true,\n\t\t\t}\n\t\t\tswitch yyS[yypt-0].item.(int) {\n\t\t\tcase 0:\n\t\t\t\tparser.yyVAL.item = []*ast.ColumnOption{optionCheck, {Tp: ast.ColumnOptionNotNull}}\n\t\t\tcase 1:\n\t\t\t\toptionCheck.Enforced = true\n\t\t\t\tparser.yyVAL.item = optionCheck\n\t\t\tcase 2:\n\t\t\t\toptionCheck.Enforced = false\n\t\t\t\tparser.yyVAL.item = optionCheck\n\t\t\tdefault:\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The CHECK clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 189:\n\t\t{\n\t\t\tstartOffset := parser.startOffset(&yyS[yypt-2])\n\t\t\tendOffset := parser.endOffset(&yyS[yypt-1])\n\t\t\texpr := yyS[yypt-2].expr\n\t\t\texpr.SetText(parser.src[startOffset:endOffset])\n\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{\n\t\t\t\tTp:     ast.ColumnOptionGenerated,\n\t\t\t\tExpr:   expr,\n\t\t\t\tStored: yyS[yypt-0].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 190:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{\n\t\t\t\tTp:    ast.ColumnOptionReference,\n\t\t\t\tRefer: yyS[yypt-0].item.(*ast.ReferenceDef),\n\t\t\t}\n\t\t}\n\tcase 191:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionCollate, StrValue: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 192:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionColumnFormat, StrValue: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 193:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionStorage, StrValue: yyS[yypt-0].ident}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The STORAGE clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 194:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionAutoRandom, AutoRandomBitLength: yyS[yypt-0].item.(int)}\n\t\t}\n\tcase 198:\n\t\t{\n\t\t\tparser.yyVAL.item = \"DEFAULT\"\n\t\t}\n\tcase 199:\n\t\t{\n\t\t\tparser.yyVAL.item = \"FIXED\"\n\t\t}\n\tcase 200:\n\t\t{\n\t\t\tparser.yyVAL.item = \"DYNAMIC\"\n\t\t}\n\tcase 203:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 204:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 205:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 206:\n\t\t{\n\t\t\tif columnOption, ok := yyS[yypt-0].item.(*ast.ColumnOption); ok {\n\t\t\t\tparser.yyVAL.item = []*ast.ColumnOption{columnOption}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t\t}\n\t\t}\n\tcase 207:\n\t\t{\n\t\t\tif columnOption, ok := yyS[yypt-0].item.(*ast.ColumnOption); ok {\n\t\t\t\tparser.yyVAL.item = append(yyS[yypt-1].item.([]*ast.ColumnOption), columnOption)\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.item = append(yyS[yypt-1].item.([]*ast.ColumnOption), yyS[yypt-0].item.([]*ast.ColumnOption)...)\n\t\t\t}\n\t\t}\n\tcase 208:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.ColumnOption{}\n\t\t}\n\tcase 209:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.([]*ast.ColumnOption)\n\t\t}\n\tcase 210:\n\t\t{\n\t\t\tc := &ast.Constraint{\n\t\t\t\tTp:   ast.ConstraintPrimaryKey,\n\t\t\t\tKeys: yyS[yypt-2].item.([]*ast.IndexPartSpecification),\n\t\t\t\tName: yyS[yypt-4].item.([]interface{})[0].(string),\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tc.Option = yyS[yypt-0].item.(*ast.IndexOption)\n\t\t\t}\n\t\t\tif indexType := yyS[yypt-4].item.([]interface{})[1]; indexType != nil {\n\t\t\t\tif c.Option == nil {\n\t\t\t\t\tc.Option = &ast.IndexOption{}\n\t\t\t\t}\n\t\t\t\tc.Option.Tp = indexType.(model.IndexType)\n\t\t\t}\n\t\t\tparser.yyVAL.item = c\n\t\t}\n\tcase 211:\n\t\t{\n\t\t\tc := &ast.Constraint{\n\t\t\t\tTp:   ast.ConstraintFulltext,\n\t\t\t\tKeys: yyS[yypt-2].item.([]*ast.IndexPartSpecification),\n\t\t\t\tName: yyS[yypt-4].item.(string),\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tc.Option = yyS[yypt-0].item.(*ast.IndexOption)\n\t\t\t}\n\t\t\tparser.yyVAL.item = c\n\t\t}\n\tcase 212:\n\t\t{\n\t\t\tc := &ast.Constraint{\n\t\t\t\tIfNotExists: yyS[yypt-5].item.(bool),\n\t\t\t\tTp:          ast.ConstraintIndex,\n\t\t\t\tKeys:        yyS[yypt-2].item.([]*ast.IndexPartSpecification),\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tc.Option = yyS[yypt-0].item.(*ast.IndexOption)\n\t\t\t}\n\t\t\tc.Name = yyS[yypt-4].item.([]interface{})[0].(string)\n\t\t\tif indexType := yyS[yypt-4].item.([]interface{})[1]; indexType != nil {\n\t\t\t\tif c.Option == nil {\n\t\t\t\t\tc.Option = &ast.IndexOption{}\n\t\t\t\t}\n\t\t\t\tc.Option.Tp = indexType.(model.IndexType)\n\t\t\t}\n\t\t\tparser.yyVAL.item = c\n\t\t}\n\tcase 213:\n\t\t{\n\t\t\tc := &ast.Constraint{\n\t\t\t\tTp:   ast.ConstraintUniq,\n\t\t\t\tKeys: yyS[yypt-2].item.([]*ast.IndexPartSpecification),\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tc.Option = yyS[yypt-0].item.(*ast.IndexOption)\n\t\t\t}\n\t\t\tc.Name = yyS[yypt-4].item.([]interface{})[0].(string)\n\t\t\tif indexType := yyS[yypt-4].item.([]interface{})[1]; indexType != nil {\n\t\t\t\tif c.Option == nil {\n\t\t\t\t\tc.Option = &ast.IndexOption{}\n\t\t\t\t}\n\t\t\t\tc.Option.Tp = indexType.(model.IndexType)\n\t\t\t}\n\t\t\tparser.yyVAL.item = c\n\t\t}\n\tcase 214:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Constraint{\n\t\t\t\tIfNotExists: yyS[yypt-5].item.(bool),\n\t\t\t\tTp:          ast.ConstraintForeignKey,\n\t\t\t\tKeys:        yyS[yypt-2].item.([]*ast.IndexPartSpecification),\n\t\t\t\tName:        yyS[yypt-4].item.(string),\n\t\t\t\tRefer:       yyS[yypt-0].item.(*ast.ReferenceDef),\n\t\t\t}\n\t\t}\n\tcase 215:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Constraint{\n\t\t\t\tTp:       ast.ConstraintCheck,\n\t\t\t\tExpr:     yyS[yypt-2].expr.(ast.ExprNode),\n\t\t\t\tEnforced: yyS[yypt-0].item.(bool),\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The CHECK clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 216:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.MatchFull\n\t\t}\n\tcase 217:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.MatchPartial\n\t\t}\n\tcase 218:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.MatchSimple\n\t\t}\n\tcase 219:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.MatchNone\n\t\t}\n\tcase 220:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t\tyylex.AppendError(yylex.Errorf(\"The MATCH clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 221:\n\t\t{\n\t\t\tonDeleteUpdate := yyS[yypt-0].item.([2]interface{})\n\t\t\tparser.yyVAL.item = &ast.ReferenceDef{\n\t\t\t\tTable:                   yyS[yypt-3].item.(*ast.TableName),\n\t\t\t\tIndexPartSpecifications: yyS[yypt-2].item.([]*ast.IndexPartSpecification),\n\t\t\t\tOnDelete:                onDeleteUpdate[0].(*ast.OnDeleteOpt),\n\t\t\t\tOnUpdate:                onDeleteUpdate[1].(*ast.OnUpdateOpt),\n\t\t\t\tMatch:                   yyS[yypt-1].item.(ast.MatchType),\n\t\t\t}\n\t\t}\n\tcase 222:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.OnDeleteOpt{ReferOpt: yyS[yypt-0].item.(ast.ReferOptionType)}\n\t\t}\n\tcase 223:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.OnUpdateOpt{ReferOpt: yyS[yypt-0].item.(ast.ReferOptionType)}\n\t\t}\n\tcase 224:\n\t\t{\n\t\t\tparser.yyVAL.item = [2]interface{}{&ast.OnDeleteOpt{}, &ast.OnUpdateOpt{}}\n\t\t}\n\tcase 225:\n\t\t{\n\t\t\tparser.yyVAL.item = [2]interface{}{yyS[yypt-0].item, &ast.OnUpdateOpt{}}\n\t\t}\n\tcase 226:\n\t\t{\n\t\t\tparser.yyVAL.item = [2]interface{}{&ast.OnDeleteOpt{}, yyS[yypt-0].item}\n\t\t}\n\tcase 227:\n\t\t{\n\t\t\tparser.yyVAL.item = [2]interface{}{yyS[yypt-1].item, yyS[yypt-0].item}\n\t\t}\n\tcase 228:\n\t\t{\n\t\t\tparser.yyVAL.item = [2]interface{}{yyS[yypt-0].item, yyS[yypt-1].item}\n\t\t}\n\tcase 229:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ReferOptionRestrict\n\t\t}\n\tcase 230:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ReferOptionCascade\n\t\t}\n\tcase 231:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ReferOptionSetNull\n\t\t}\n\tcase 232:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ReferOptionNoAction\n\t\t}\n\tcase 233:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ReferOptionSetDefault\n\t\t\tyylex.AppendError(yylex.Errorf(\"The SET DEFAULT clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 236:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(\"CURRENT_TIMESTAMP\")}\n\t\t}\n\tcase 237:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(\"CURRENT_TIMESTAMP\")}\n\t\t}\n\tcase 238:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(\"CURRENT_TIMESTAMP\"), Args: []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].item)}}\n\t\t}\n\tcase 246:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].expr)\n\t\t}\n\tcase 247:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Plus, V: ast.NewValueExpr(yyS[yypt-0].item)}\n\t\t}\n\tcase 248:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr(yyS[yypt-0].item)}\n\t\t}\n\tcase 252:\n\t\t{\n\t\t\tvar indexOption *ast.IndexOption\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tindexOption = yyS[yypt-1].item.(*ast.IndexOption)\n\t\t\t\tif indexOption.Tp == model.IndexTypeInvalid {\n\t\t\t\t\tif yyS[yypt-7].item != nil {\n\t\t\t\t\t\tindexOption.Tp = yyS[yypt-7].item.(model.IndexType)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tindexOption = &ast.IndexOption{}\n\t\t\t\tif yyS[yypt-7].item != nil {\n\t\t\t\t\tindexOption.Tp = yyS[yypt-7].item.(model.IndexType)\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar indexLockAndAlgorithm *ast.IndexLockAndAlgorithm\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tindexLockAndAlgorithm = yyS[yypt-0].item.(*ast.IndexLockAndAlgorithm)\n\t\t\t\tif indexLockAndAlgorithm.LockTp == ast.LockTypeDefault && indexLockAndAlgorithm.AlgorithmTp == ast.AlgorithmTypeDefault {\n\t\t\t\t\tindexLockAndAlgorithm = nil\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.statement = &ast.CreateIndexStmt{\n\t\t\t\tIfNotExists:             yyS[yypt-9].item.(bool),\n\t\t\t\tIndexName:               yyS[yypt-8].ident,\n\t\t\t\tTable:                   yyS[yypt-5].item.(*ast.TableName),\n\t\t\t\tIndexPartSpecifications: yyS[yypt-3].item.([]*ast.IndexPartSpecification),\n\t\t\t\tIndexOption:             indexOption,\n\t\t\t\tKeyType:                 yyS[yypt-11].item.(ast.IndexKeyType),\n\t\t\t\tLockAlg:                 indexLockAndAlgorithm,\n\t\t\t}\n\t\t}\n\tcase 253:\n\t\t{\n\t\t\tparser.yyVAL.item = ([]*ast.IndexPartSpecification)(nil)\n\t\t}\n\tcase 254:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item\n\t\t}\n\tcase 255:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.IndexPartSpecification{yyS[yypt-0].item.(*ast.IndexPartSpecification)}\n\t\t}\n\tcase 256:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.IndexPartSpecification), yyS[yypt-0].item.(*ast.IndexPartSpecification))\n\t\t}\n\tcase 257:\n\t\t{\n\t\t\t// Order is parsed but just ignored as MySQL did.\n\t\t\tparser.yyVAL.item = &ast.IndexPartSpecification{Column: yyS[yypt-2].item.(*ast.ColumnName), Length: yyS[yypt-1].item.(int)}\n\t\t}\n\tcase 258:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexPartSpecification{Expr: yyS[yypt-2].expr}\n\t\t}\n\tcase 259:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 260:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexLockAndAlgorithm{\n\t\t\t\tLockTp:      yyS[yypt-0].item.(ast.LockType),\n\t\t\t\tAlgorithmTp: ast.AlgorithmTypeDefault,\n\t\t\t}\n\t\t}\n\tcase 261:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexLockAndAlgorithm{\n\t\t\t\tLockTp:      ast.LockTypeDefault,\n\t\t\t\tAlgorithmTp: yyS[yypt-0].item.(ast.AlgorithmType),\n\t\t\t}\n\t\t}\n\tcase 262:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexLockAndAlgorithm{\n\t\t\t\tLockTp:      yyS[yypt-1].item.(ast.LockType),\n\t\t\t\tAlgorithmTp: yyS[yypt-0].item.(ast.AlgorithmType),\n\t\t\t}\n\t\t}\n\tcase 263:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexLockAndAlgorithm{\n\t\t\t\tLockTp:      yyS[yypt-0].item.(ast.LockType),\n\t\t\t\tAlgorithmTp: yyS[yypt-1].item.(ast.AlgorithmType),\n\t\t\t}\n\t\t}\n\tcase 264:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.IndexKeyTypeNone\n\t\t}\n\tcase 265:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.IndexKeyTypeUnique\n\t\t}\n\tcase 266:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.IndexKeyTypeSpatial\n\t\t}\n\tcase 267:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.IndexKeyTypeFullText\n\t\t}\n\tcase 268:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AlterDatabaseStmt{\n\t\t\t\tName:                 yyS[yypt-1].item.(string),\n\t\t\t\tAlterDefaultDatabase: false,\n\t\t\t\tOptions:              yyS[yypt-0].item.([]*ast.DatabaseOption),\n\t\t\t}\n\t\t}\n\tcase 269:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AlterDatabaseStmt{\n\t\t\t\tName:                 \"\",\n\t\t\t\tAlterDefaultDatabase: true,\n\t\t\t\tOptions:              yyS[yypt-0].item.([]*ast.DatabaseOption),\n\t\t\t}\n\t\t}\n\tcase 270:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.CreateDatabaseStmt{\n\t\t\t\tIfNotExists: yyS[yypt-2].item.(bool),\n\t\t\t\tName:        yyS[yypt-1].item.(string),\n\t\t\t\tOptions:     yyS[yypt-0].item.([]*ast.DatabaseOption),\n\t\t\t}\n\t\t}\n\tcase 271:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 272:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.DatabaseOption{Tp: ast.DatabaseOptionCharset, Value: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 273:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.DatabaseOption{Tp: ast.DatabaseOptionCollate, Value: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 274:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.DatabaseOption{Tp: ast.DatabaseOptionEncryption, Value: yyS[yypt-0].ident}\n\t\t}\n\tcase 275:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.DatabaseOption{}\n\t\t}\n\tcase 277:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.DatabaseOption{yyS[yypt-0].item.(*ast.DatabaseOption)}\n\t\t}\n\tcase 278:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-1].item.([]*ast.DatabaseOption), yyS[yypt-0].item.(*ast.DatabaseOption))\n\t\t}\n\tcase 279:\n\t\t{\n\t\t\tstmt := yyS[yypt-5].item.(*ast.CreateTableStmt)\n\t\t\tstmt.Table = yyS[yypt-6].item.(*ast.TableName)\n\t\t\tstmt.IfNotExists = yyS[yypt-7].item.(bool)\n\t\t\tstmt.IsTemporary = yyS[yypt-9].item.(bool)\n\t\t\tstmt.Options = yyS[yypt-4].item.([]*ast.TableOption)\n\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\tstmt.Partition = yyS[yypt-3].item.(*ast.PartitionOptions)\n\t\t\t}\n\t\t\tstmt.OnDuplicate = yyS[yypt-2].item.(ast.OnDuplicateKeyHandlingType)\n\t\t\tstmt.Select = yyS[yypt-0].item.(*ast.CreateTableStmt).Select\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 280:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.CreateTableStmt{\n\t\t\t\tTable:       yyS[yypt-1].item.(*ast.TableName),\n\t\t\t\tReferTable:  yyS[yypt-0].item.(*ast.TableName),\n\t\t\t\tIfNotExists: yyS[yypt-2].item.(bool),\n\t\t\t\tIsTemporary: yyS[yypt-4].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 283:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 284:\n\t\t{\n\t\t\tmethod := yyS[yypt-3].item.(*ast.PartitionMethod)\n\t\t\tmethod.Num = yyS[yypt-2].item.(uint64)\n\t\t\tsub, _ := yyS[yypt-1].item.(*ast.PartitionMethod)\n\t\t\tdefs, _ := yyS[yypt-0].item.([]*ast.PartitionDefinition)\n\t\t\topt := &ast.PartitionOptions{\n\t\t\t\tPartitionMethod: *method,\n\t\t\t\tSub:             sub,\n\t\t\t\tDefinitions:     defs,\n\t\t\t}\n\t\t\tif err := opt.Validate(); err != nil {\n\t\t\t\tyylex.AppendError(err)\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = opt\n\t\t}\n\tcase 285:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionMethod{\n\t\t\t\tTp:          model.PartitionTypeKey,\n\t\t\t\tLinear:      len(yyS[yypt-5].ident) != 0,\n\t\t\t\tColumnNames: yyS[yypt-1].item.([]*ast.ColumnName),\n\t\t\t}\n\t\t}\n\tcase 286:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionMethod{\n\t\t\t\tTp:     model.PartitionTypeHash,\n\t\t\t\tLinear: len(yyS[yypt-4].ident) != 0,\n\t\t\t\tExpr:   yyS[yypt-1].expr.(ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 289:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 290:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionMethod{\n\t\t\t\tTp:   model.PartitionTypeRange,\n\t\t\t\tExpr: yyS[yypt-1].expr.(ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 291:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionMethod{\n\t\t\t\tTp:          model.PartitionTypeRange,\n\t\t\t\tColumnNames: yyS[yypt-1].item.([]*ast.ColumnName),\n\t\t\t}\n\t\t}\n\tcase 292:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionMethod{\n\t\t\t\tTp:   model.PartitionTypeList,\n\t\t\t\tExpr: yyS[yypt-1].expr.(ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 293:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionMethod{\n\t\t\t\tTp:          model.PartitionTypeList,\n\t\t\t\tColumnNames: yyS[yypt-1].item.([]*ast.ColumnName),\n\t\t\t}\n\t\t}\n\tcase 294:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionMethod{\n\t\t\t\tTp:   model.PartitionTypeSystemTime,\n\t\t\t\tExpr: yyS[yypt-1].expr.(ast.ExprNode),\n\t\t\t\tUnit: yyS[yypt-0].item.(ast.TimeUnitType),\n\t\t\t}\n\t\t}\n\tcase 295:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionMethod{\n\t\t\t\tTp:    model.PartitionTypeSystemTime,\n\t\t\t\tLimit: yyS[yypt-0].item.(uint64),\n\t\t\t}\n\t\t}\n\tcase 296:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionMethod{\n\t\t\t\tTp: model.PartitionTypeSystemTime,\n\t\t\t}\n\t\t}\n\tcase 297:\n\t\t{\n\t\t\tparser.yyVAL.ident = \"\"\n\t\t}\n\tcase 298:\n\t\t{\n\t\t\tparser.yyVAL.ident = yyS[yypt-0].ident\n\t\t}\n\tcase 299:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 300:\n\t\t{\n\t\t\tmethod := yyS[yypt-1].item.(*ast.PartitionMethod)\n\t\t\tmethod.Num = yyS[yypt-0].item.(uint64)\n\t\t\tparser.yyVAL.item = method\n\t\t}\n\tcase 301:\n\t\t{\n\t\t\tparser.yyVAL.item = uint64(0)\n\t\t}\n\tcase 302:\n\t\t{\n\t\t\tres := yyS[yypt-0].item.(uint64)\n\t\t\tif res == 0 {\n\t\t\t\tyylex.AppendError(ast.ErrNoParts.GenWithStackByArgs(\"subpartitions\"))\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = res\n\t\t}\n\tcase 303:\n\t\t{\n\t\t\tparser.yyVAL.item = uint64(0)\n\t\t}\n\tcase 304:\n\t\t{\n\t\t\tres := yyS[yypt-0].item.(uint64)\n\t\t\tif res == 0 {\n\t\t\t\tyylex.AppendError(ast.ErrNoParts.GenWithStackByArgs(\"partitions\"))\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = res\n\t\t}\n\tcase 305:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 306:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item.([]*ast.PartitionDefinition)\n\t\t}\n\tcase 307:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.PartitionDefinition{yyS[yypt-0].item.(*ast.PartitionDefinition)}\n\t\t}\n\tcase 308:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.PartitionDefinition), yyS[yypt-0].item.(*ast.PartitionDefinition))\n\t\t}\n\tcase 309:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionDefinition{\n\t\t\t\tName:    model.NewCIStr(yyS[yypt-3].ident),\n\t\t\t\tClause:  yyS[yypt-2].item.(ast.PartitionDefinitionClause),\n\t\t\t\tOptions: yyS[yypt-1].item.([]*ast.TableOption),\n\t\t\t\tSub:     yyS[yypt-0].item.([]*ast.SubPartitionDefinition),\n\t\t\t}\n\t\t}\n\tcase 310:\n\t\t{\n\t\t\tparser.yyVAL.item = make([]*ast.SubPartitionDefinition, 0)\n\t\t}\n\tcase 311:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item\n\t\t}\n\tcase 312:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.SubPartitionDefinition{yyS[yypt-0].item.(*ast.SubPartitionDefinition)}\n\t\t}\n\tcase 313:\n\t\t{\n\t\t\tlist := yyS[yypt-2].item.([]*ast.SubPartitionDefinition)\n\t\t\tparser.yyVAL.item = append(list, yyS[yypt-0].item.(*ast.SubPartitionDefinition))\n\t\t}\n\tcase 314:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SubPartitionDefinition{\n\t\t\t\tName:    model.NewCIStr(yyS[yypt-1].ident),\n\t\t\t\tOptions: yyS[yypt-0].item.([]*ast.TableOption),\n\t\t\t}\n\t\t}\n\tcase 315:\n\t\t{\n\t\t\tparser.yyVAL.item = make([]*ast.TableOption, 0)\n\t\t}\n\tcase 316:\n\t\t{\n\t\t\tlist := yyS[yypt-1].item.([]*ast.TableOption)\n\t\t\tparser.yyVAL.item = append(list, yyS[yypt-0].item.(*ast.TableOption))\n\t\t}\n\tcase 317:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionComment, StrValue: yyS[yypt-0].ident}\n\t\t}\n\tcase 318:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionEngine, StrValue: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 319:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionEngine, StrValue: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 320:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionInsertMethod, StrValue: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 321:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionDataDirectory, StrValue: yyS[yypt-0].ident}\n\t\t}\n\tcase 322:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionIndexDirectory, StrValue: yyS[yypt-0].ident}\n\t\t}\n\tcase 323:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionMaxRows, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 324:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionMinRows, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 325:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionTablespace, StrValue: yyS[yypt-0].ident}\n\t\t}\n\tcase 326:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionNodegroup, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 327:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionDefinitionClauseNone{}\n\t\t}\n\tcase 328:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionDefinitionClauseLessThan{\n\t\t\t\tExprs: []ast.ExprNode{&ast.MaxValueExpr{}},\n\t\t\t}\n\t\t}\n\tcase 329:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionDefinitionClauseLessThan{\n\t\t\t\tExprs: yyS[yypt-1].item.([]ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 330:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionDefinitionClauseIn{}\n\t\t}\n\tcase 331:\n\t\t{\n\t\t\texprs := yyS[yypt-1].item.([]ast.ExprNode)\n\t\t\tvalues := make([][]ast.ExprNode, 0, len(exprs))\n\t\t\tfor _, expr := range exprs {\n\t\t\t\tif row, ok := expr.(*ast.RowExpr); ok {\n\t\t\t\t\tvalues = append(values, row.Values)\n\t\t\t\t} else {\n\t\t\t\t\tvalues = append(values, []ast.ExprNode{expr})\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.PartitionDefinitionClauseIn{Values: values}\n\t\t}\n\tcase 332:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionDefinitionClauseHistory{Current: false}\n\t\t}\n\tcase 333:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionDefinitionClauseHistory{Current: true}\n\t\t}\n\tcase 334:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.OnDuplicateKeyHandlingError\n\t\t}\n\tcase 335:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.OnDuplicateKeyHandlingIgnore\n\t\t}\n\tcase 336:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.OnDuplicateKeyHandlingReplace\n\t\t}\n\tcase 339:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.CreateTableStmt{}\n\t\t}\n\tcase 340:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.CreateTableStmt{Select: yyS[yypt-0].statement}\n\t\t}\n\tcase 341:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.CreateTableStmt{Select: yyS[yypt-0].statement}\n\t\t}\n\tcase 342:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.CreateTableStmt{Select: yyS[yypt-0].expr}\n\t\t}\n\tcase 343:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].statement.(*ast.SelectStmt)\n\t\t}\n\tcase 344:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].statement.(*ast.UnionStmt)\n\t\t}\n\tcase 345:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].statement.(*ast.SelectStmt)\n\t\t}\n\tcase 346:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].statement.(*ast.UnionStmt)\n\t\t}\n\tcase 347:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 348:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item\n\t\t}\n\tcase 349:\n\t\t{\n\t\t\tstartOffset := parser.startOffset(&yyS[yypt-1])\n\t\t\tselStmt := yyS[yypt-1].item.(ast.StmtNode)\n\t\t\tselStmt.SetText(strings.TrimSpace(parser.src[startOffset:]))\n\t\t\tx := &ast.CreateViewStmt{\n\t\t\t\tOrReplace: yyS[yypt-9].item.(bool),\n\t\t\t\tViewName:  yyS[yypt-4].item.(*ast.TableName),\n\t\t\t\tSelect:    selStmt,\n\t\t\t\tAlgorithm: yyS[yypt-8].item.(model.ViewAlgorithm),\n\t\t\t\tDefiner:   yyS[yypt-7].item.(*auth.UserIdentity),\n\t\t\t\tSecurity:  yyS[yypt-6].item.(model.ViewSecurity),\n\t\t\t}\n\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\tx.Cols = yyS[yypt-3].item.([]model.CIStr)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tx.CheckOption = yyS[yypt-0].item.(model.ViewCheckOption)\n\t\t\t\tendOffset := parser.startOffset(&yyS[yypt])\n\t\t\t\tselStmt.SetText(strings.TrimSpace(parser.src[startOffset:endOffset]))\n\t\t\t} else {\n\t\t\t\tx.CheckOption = model.CheckOptionCascaded\n\t\t\t}\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 350:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 351:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 352:\n\t\t{\n\t\t\tparser.yyVAL.item = model.AlgorithmUndefined\n\t\t}\n\tcase 353:\n\t\t{\n\t\t\tparser.yyVAL.item = model.AlgorithmUndefined\n\t\t}\n\tcase 354:\n\t\t{\n\t\t\tparser.yyVAL.item = model.AlgorithmMerge\n\t\t}\n\tcase 355:\n\t\t{\n\t\t\tparser.yyVAL.item = model.AlgorithmTemptable\n\t\t}\n\tcase 356:\n\t\t{\n\t\t\tparser.yyVAL.item = &auth.UserIdentity{CurrentUser: true}\n\t\t}\n\tcase 357:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 358:\n\t\t{\n\t\t\tparser.yyVAL.item = model.SecurityDefiner\n\t\t}\n\tcase 359:\n\t\t{\n\t\t\tparser.yyVAL.item = model.SecurityDefiner\n\t\t}\n\tcase 360:\n\t\t{\n\t\t\tparser.yyVAL.item = model.SecurityInvoker\n\t\t}\n\tcase 361:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(*ast.TableName)\n\t\t}\n\tcase 362:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 363:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item.([]model.CIStr)\n\t\t}\n\tcase 364:\n\t\t{\n\t\t\tparser.yyVAL.item = []model.CIStr{model.NewCIStr(yyS[yypt-0].ident)}\n\t\t}\n\tcase 365:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]model.CIStr), model.NewCIStr(yyS[yypt-0].ident))\n\t\t}\n\tcase 366:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 367:\n\t\t{\n\t\t\tparser.yyVAL.item = model.CheckOptionCascaded\n\t\t}\n\tcase 368:\n\t\t{\n\t\t\tparser.yyVAL.item = model.CheckOptionLocal\n\t\t}\n\tcase 369:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.DoStmt{\n\t\t\t\tExprs: yyS[yypt-0].item.([]ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 370:\n\t\t{\n\t\t\t// Single Table\n\t\t\ttn := yyS[yypt-5].item.(*ast.TableName)\n\t\t\ttn.IndexHints = yyS[yypt-3].item.([]*ast.IndexHint)\n\t\t\tjoin := &ast.Join{Left: &ast.TableSource{Source: tn, AsName: yyS[yypt-4].item.(model.CIStr)}, Right: nil}\n\t\t\tx := &ast.DeleteStmt{\n\t\t\t\tTableRefs: &ast.TableRefsClause{TableRefs: join},\n\t\t\t\tPriority:  yyS[yypt-9].item.(mysql.PriorityEnum),\n\t\t\t\tQuick:     yyS[yypt-8].item.(bool),\n\t\t\t\tIgnoreErr: yyS[yypt-7].item.(bool),\n\t\t\t}\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tx.Where = yyS[yypt-2].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tx.Order = yyS[yypt-1].item.(*ast.OrderByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tx.Limit = yyS[yypt-0].item.(*ast.Limit)\n\t\t\t}\n\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 371:\n\t\t{\n\t\t\t// Multiple Table\n\t\t\tx := &ast.DeleteStmt{\n\t\t\t\tPriority:     yyS[yypt-6].item.(mysql.PriorityEnum),\n\t\t\t\tQuick:        yyS[yypt-5].item.(bool),\n\t\t\t\tIgnoreErr:    yyS[yypt-4].item.(bool),\n\t\t\t\tIsMultiTable: true,\n\t\t\t\tBeforeFrom:   true,\n\t\t\t\tTables:       &ast.DeleteTableList{Tables: yyS[yypt-3].item.([]*ast.TableName)},\n\t\t\t\tTableRefs:    &ast.TableRefsClause{TableRefs: yyS[yypt-1].item.(*ast.Join)},\n\t\t\t}\n\t\t\tif yyS[yypt-7].item != nil {\n\t\t\t\tx.TableHints = yyS[yypt-7].item.([]*ast.TableOptimizerHint)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tx.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 372:\n\t\t{\n\t\t\t// Multiple Table\n\t\t\tx := &ast.DeleteStmt{\n\t\t\t\tPriority:     yyS[yypt-7].item.(mysql.PriorityEnum),\n\t\t\t\tQuick:        yyS[yypt-6].item.(bool),\n\t\t\t\tIgnoreErr:    yyS[yypt-5].item.(bool),\n\t\t\t\tIsMultiTable: true,\n\t\t\t\tTables:       &ast.DeleteTableList{Tables: yyS[yypt-3].item.([]*ast.TableName)},\n\t\t\t\tTableRefs:    &ast.TableRefsClause{TableRefs: yyS[yypt-1].item.(*ast.Join)},\n\t\t\t}\n\t\t\tif yyS[yypt-8].item != nil {\n\t\t\t\tx.TableHints = yyS[yypt-8].item.([]*ast.TableOptimizerHint)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tx.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 374:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.DropDatabaseStmt{IfExists: yyS[yypt-1].item.(bool), Name: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 375:\n\t\t{\n\t\t\tvar indexLockAndAlgorithm *ast.IndexLockAndAlgorithm\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tindexLockAndAlgorithm = yyS[yypt-0].item.(*ast.IndexLockAndAlgorithm)\n\t\t\t\tif indexLockAndAlgorithm.LockTp == ast.LockTypeDefault && indexLockAndAlgorithm.AlgorithmTp == ast.AlgorithmTypeDefault {\n\t\t\t\t\tindexLockAndAlgorithm = nil\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.statement = &ast.DropIndexStmt{IfExists: yyS[yypt-4].item.(bool), IndexName: yyS[yypt-3].ident, Table: yyS[yypt-1].item.(*ast.TableName), LockAlg: indexLockAndAlgorithm}\n\t\t}\n\tcase 376:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.DropTableStmt{IfExists: yyS[yypt-2].item.(bool), Tables: yyS[yypt-1].item.([]*ast.TableName), IsView: false, IsTemporary: yyS[yypt-4].item.(bool)}\n\t\t}\n\tcase 377:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 378:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t\tyylex.AppendError(yylex.Errorf(\"TiDB doesn't support TEMPORARY TABLE, TEMPORARY will be parsed but ignored.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 379:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.DropTableStmt{Tables: yyS[yypt-1].item.([]*ast.TableName), IsView: true}\n\t\t}\n\tcase 380:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.DropTableStmt{IfExists: true, Tables: yyS[yypt-1].item.([]*ast.TableName), IsView: true}\n\t\t}\n\tcase 381:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.DropUserStmt{IsDropRole: false, IfExists: false, UserList: yyS[yypt-0].item.([]*auth.UserIdentity)}\n\t\t}\n\tcase 382:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.DropUserStmt{IsDropRole: false, IfExists: true, UserList: yyS[yypt-0].item.([]*auth.UserIdentity)}\n\t\t}\n\tcase 383:\n\t\t{\n\t\t\ttmp := make([]*auth.UserIdentity, 0, 10)\n\t\t\troleList := yyS[yypt-0].item.([]*auth.RoleIdentity)\n\t\t\tfor _, r := range roleList {\n\t\t\t\ttmp = append(tmp, &auth.UserIdentity{Username: r.Username, Hostname: r.Hostname})\n\t\t\t}\n\t\t\tparser.yyVAL.statement = &ast.DropUserStmt{IsDropRole: true, IfExists: false, UserList: tmp}\n\t\t}\n\tcase 384:\n\t\t{\n\t\t\ttmp := make([]*auth.UserIdentity, 0, 10)\n\t\t\troleList := yyS[yypt-0].item.([]*auth.RoleIdentity)\n\t\t\tfor _, r := range roleList {\n\t\t\t\ttmp = append(tmp, &auth.UserIdentity{Username: r.Username, Hostname: r.Hostname})\n\t\t\t}\n\t\t\tparser.yyVAL.statement = &ast.DropUserStmt{IsDropRole: true, IfExists: true, UserList: tmp}\n\t\t}\n\tcase 385:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.DropStatsStmt{Table: yyS[yypt-0].item.(*ast.TableName)}\n\t\t}\n\tcase 393:\n\t\t{\n\t\t\tparser.yyVAL.statement = nil\n\t\t}\n\tcase 394:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.TraceStmt{\n\t\t\t\tStmt:   yyS[yypt-0].statement,\n\t\t\t\tFormat: \"json\",\n\t\t\t}\n\t\t\tstartOffset := parser.startOffset(&yyS[yypt])\n\t\t\tyyS[yypt-0].statement.SetText(string(parser.src[startOffset:]))\n\t\t}\n\tcase 395:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.TraceStmt{\n\t\t\t\tStmt:   yyS[yypt-0].statement,\n\t\t\t\tFormat: yyS[yypt-1].ident,\n\t\t\t}\n\t\t\tstartOffset := parser.startOffset(&yyS[yypt])\n\t\t\tyyS[yypt-0].statement.SetText(string(parser.src[startOffset:]))\n\t\t}\n\tcase 399:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExplainStmt{\n\t\t\t\tStmt: &ast.ShowStmt{\n\t\t\t\t\tTp:    ast.ShowColumns,\n\t\t\t\t\tTable: yyS[yypt-0].item.(*ast.TableName),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\tcase 400:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExplainStmt{\n\t\t\t\tStmt: &ast.ShowStmt{\n\t\t\t\t\tTp:     ast.ShowColumns,\n\t\t\t\t\tTable:  yyS[yypt-1].item.(*ast.TableName),\n\t\t\t\t\tColumn: yyS[yypt-0].item.(*ast.ColumnName),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\tcase 401:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExplainStmt{\n\t\t\t\tStmt:   yyS[yypt-0].statement,\n\t\t\t\tFormat: \"row\",\n\t\t\t}\n\t\t}\n\tcase 402:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExplainForStmt{\n\t\t\t\tFormat:       \"row\",\n\t\t\t\tConnectionID: getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t}\n\t\t}\n\tcase 403:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExplainForStmt{\n\t\t\t\tFormat:       yyS[yypt-3].ident,\n\t\t\t\tConnectionID: getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t}\n\t\t}\n\tcase 404:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExplainStmt{\n\t\t\t\tStmt:   yyS[yypt-0].statement,\n\t\t\t\tFormat: yyS[yypt-1].ident,\n\t\t\t}\n\t\t}\n\tcase 405:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExplainForStmt{\n\t\t\t\tFormat:       yyS[yypt-3].item.(string),\n\t\t\t\tConnectionID: getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t}\n\t\t}\n\tcase 406:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExplainStmt{\n\t\t\t\tStmt:   yyS[yypt-0].statement,\n\t\t\t\tFormat: yyS[yypt-1].item.(string),\n\t\t\t}\n\t\t}\n\tcase 407:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExplainStmt{\n\t\t\t\tStmt:    yyS[yypt-0].statement,\n\t\t\t\tFormat:  \"row\",\n\t\t\t\tAnalyze: true,\n\t\t\t}\n\t\t}\n\tcase 408:\n\t\t{\n\t\t\tparser.yyVAL.item = \"row\"\n\t\t}\n\tcase 409:\n\t\t{\n\t\t\tparser.yyVAL.item = \"json\"\n\t\t}\n\tcase 410:\n\t\t{\n\t\t\tparser.yyVAL.item = getUint64FromNUM(yyS[yypt-0].item)\n\t\t}\n\tcase 412:\n\t\t{\n\t\t\tv := yyS[yypt-2].ident\n\t\t\tv = strings.TrimPrefix(v, \"@\")\n\t\t\tparser.yyVAL.expr = &ast.VariableExpr{\n\t\t\t\tName:     v,\n\t\t\t\tIsGlobal: false,\n\t\t\t\tIsSystem: false,\n\t\t\t\tValue:    yyS[yypt-0].expr,\n\t\t\t}\n\t\t}\n\tcase 413:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.LogicOr, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 414:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.LogicXor, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 415:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.LogicAnd, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 416:\n\t\t{\n\t\t\texpr, ok := yyS[yypt-0].expr.(*ast.ExistsSubqueryExpr)\n\t\t\tif ok {\n\t\t\t\texpr.Not = true\n\t\t\t\tparser.yyVAL.expr = yyS[yypt-0].expr\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Not, V: yyS[yypt-0].expr}\n\t\t\t}\n\t\t}\n\tcase 417:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.MatchAgainst{\n\t\t\t\tColumnNames: yyS[yypt-6].item.([]*ast.ColumnName),\n\t\t\t\tAgainst:     yyS[yypt-2].expr,\n\t\t\t\tModifier:    ast.FulltextSearchModifier(yyS[yypt-1].item.(int)),\n\t\t\t}\n\t\t}\n\tcase 418:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.IsTruthExpr{Expr: yyS[yypt-2].expr, Not: !yyS[yypt-1].item.(bool), True: int64(1)}\n\t\t}\n\tcase 419:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.IsTruthExpr{Expr: yyS[yypt-2].expr, Not: !yyS[yypt-1].item.(bool), True: int64(0)}\n\t\t}\n\tcase 420:\n\t\t{\n\t\t\t/* https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_is */\n\t\t\tparser.yyVAL.expr = &ast.IsNullExpr{Expr: yyS[yypt-2].expr, Not: !yyS[yypt-1].item.(bool)}\n\t\t}\n\tcase 422:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.MaxValueExpr{}\n\t\t}\n\tcase 423:\n\t\t{\n\t\t\tparser.yyVAL.expr = yyS[yypt-0].expr\n\t\t}\n\tcase 424:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FulltextSearchModifierNaturalLanguageMode\n\t\t}\n\tcase 425:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FulltextSearchModifierNaturalLanguageMode\n\t\t}\n\tcase 426:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FulltextSearchModifierNaturalLanguageMode | ast.FulltextSearchModifierWithQueryExpansion\n\t\t}\n\tcase 427:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FulltextSearchModifierBooleanMode\n\t\t}\n\tcase 428:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FulltextSearchModifierWithQueryExpansion\n\t\t}\n\tcase 433:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.ExprNode{yyS[yypt-0].expr}\n\t\t}\n\tcase 434:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]ast.ExprNode), yyS[yypt-0].expr)\n\t\t}\n\tcase 435:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.ExprNode{yyS[yypt-0].expr}\n\t\t}\n\tcase 436:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]ast.ExprNode), yyS[yypt-0].expr)\n\t\t}\n\tcase 437:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.ExprNode{}\n\t\t}\n\tcase 439:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.ExprNode{}\n\t\t}\n\tcase 440:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 441:\n\t\t{\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-0].item)\n\t\t\tparser.yyVAL.item = []ast.ExprNode{expr}\n\t\t}\n\tcase 442:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.IsNullExpr{Expr: yyS[yypt-2].expr, Not: !yyS[yypt-1].item.(bool)}\n\t\t}\n\tcase 443:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: yyS[yypt-1].item.(opcode.Op), L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 444:\n\t\t{\n\t\t\tsq := yyS[yypt-0].expr.(*ast.SubqueryExpr)\n\t\t\tsq.MultiRows = true\n\t\t\tparser.yyVAL.expr = &ast.CompareSubqueryExpr{Op: yyS[yypt-2].item.(opcode.Op), L: yyS[yypt-3].expr, R: sq, All: yyS[yypt-1].item.(bool)}\n\t\t}\n\tcase 445:\n\t\t{\n\t\t\tv := yyS[yypt-2].ident\n\t\t\tv = strings.TrimPrefix(v, \"@\")\n\t\t\tvariable := &ast.VariableExpr{\n\t\t\t\tName:     v,\n\t\t\t\tIsGlobal: false,\n\t\t\t\tIsSystem: false,\n\t\t\t\tValue:    yyS[yypt-0].expr,\n\t\t\t}\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: yyS[yypt-3].item.(opcode.Op), L: yyS[yypt-4].expr, R: variable}\n\t\t}\n\tcase 447:\n\t\t{\n\t\t\tparser.yyVAL.item = opcode.GE\n\t\t}\n\tcase 448:\n\t\t{\n\t\t\tparser.yyVAL.item = opcode.GT\n\t\t}\n\tcase 449:\n\t\t{\n\t\t\tparser.yyVAL.item = opcode.LE\n\t\t}\n\tcase 450:\n\t\t{\n\t\t\tparser.yyVAL.item = opcode.LT\n\t\t}\n\tcase 451:\n\t\t{\n\t\t\tparser.yyVAL.item = opcode.NE\n\t\t}\n\tcase 452:\n\t\t{\n\t\t\tparser.yyVAL.item = opcode.NE\n\t\t}\n\tcase 453:\n\t\t{\n\t\t\tparser.yyVAL.item = opcode.EQ\n\t\t}\n\tcase 454:\n\t\t{\n\t\t\tparser.yyVAL.item = opcode.NullEQ\n\t\t}\n\tcase 455:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 456:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 457:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 458:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 459:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 460:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 461:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 462:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 463:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 464:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 465:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 466:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 467:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 468:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.PatternInExpr{Expr: yyS[yypt-4].expr, Not: !yyS[yypt-3].item.(bool), List: yyS[yypt-1].item.([]ast.ExprNode)}\n\t\t}\n\tcase 469:\n\t\t{\n\t\t\tsq := yyS[yypt-0].expr.(*ast.SubqueryExpr)\n\t\t\tsq.MultiRows = true\n\t\t\tparser.yyVAL.expr = &ast.PatternInExpr{Expr: yyS[yypt-2].expr, Not: !yyS[yypt-1].item.(bool), Sel: sq}\n\t\t}\n\tcase 470:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BetweenExpr{\n\t\t\t\tExpr:  yyS[yypt-4].expr,\n\t\t\t\tLeft:  yyS[yypt-2].expr,\n\t\t\t\tRight: yyS[yypt-0].expr,\n\t\t\t\tNot:   !yyS[yypt-3].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 471:\n\t\t{\n\t\t\tescape := yyS[yypt-0].item.(string)\n\t\t\tif len(escape) > 1 {\n\t\t\t\tyylex.AppendError(ErrWrongArguments.GenWithStackByArgs(\"ESCAPE\"))\n\t\t\t\treturn 1\n\t\t\t} else if len(escape) == 0 {\n\t\t\t\tescape = \"\\\\\"\n\t\t\t}\n\t\t\tparser.yyVAL.expr = &ast.PatternLikeExpr{\n\t\t\t\tExpr:    yyS[yypt-3].expr,\n\t\t\t\tPattern: yyS[yypt-1].expr,\n\t\t\t\tNot:     !yyS[yypt-2].item.(bool),\n\t\t\t\tEscape:  escape[0],\n\t\t\t}\n\t\t}\n\tcase 472:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.PatternRegexpExpr{Expr: yyS[yypt-2].expr, Pattern: yyS[yypt-0].expr, Not: !yyS[yypt-1].item.(bool)}\n\t\t}\n\tcase 476:\n\t\t{\n\t\t\tparser.yyVAL.item = \"\\\\\"\n\t\t}\n\tcase 477:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 478:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SelectField{WildCard: &ast.WildCardField{}}\n\t\t}\n\tcase 479:\n\t\t{\n\t\t\twildCard := &ast.WildCardField{Table: model.NewCIStr(yyS[yypt-2].ident)}\n\t\t\tparser.yyVAL.item = &ast.SelectField{WildCard: wildCard}\n\t\t}\n\tcase 480:\n\t\t{\n\t\t\twildCard := &ast.WildCardField{Schema: model.NewCIStr(yyS[yypt-4].ident), Table: model.NewCIStr(yyS[yypt-2].ident)}\n\t\t\tparser.yyVAL.item = &ast.SelectField{WildCard: wildCard}\n\t\t}\n\tcase 481:\n\t\t{\n\t\t\texpr := yyS[yypt-1].expr\n\t\t\tasName := yyS[yypt-0].item.(string)\n\t\t\tparser.yyVAL.item = &ast.SelectField{Expr: expr, AsName: model.NewCIStr(asName)}\n\t\t}\n\tcase 482:\n\t\t{\n\t\t\t/*\n\t\t\t * ODBC escape syntax.\n\t\t\t * See https://dev.mysql.com/doc/refman/5.7/en/expressions.html\n\t\t\t */\n\t\t\texpr := yyS[yypt-2].expr\n\t\t\tasName := yyS[yypt-0].item.(string)\n\t\t\tparser.yyVAL.item = &ast.SelectField{Expr: expr, AsName: model.NewCIStr(asName)}\n\t\t}\n\tcase 483:\n\t\t{\n\t\t\tparser.yyVAL.item = \"\"\n\t\t}\n\tcase 484:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 485:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 486:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 487:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 488:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 489:\n\t\t{\n\t\t\tfield := yyS[yypt-0].item.(*ast.SelectField)\n\t\t\tfield.Offset = parser.startOffset(&yyS[yypt])\n\t\t\tparser.yyVAL.item = []*ast.SelectField{field}\n\t\t}\n\tcase 490:\n\t\t{\n\t\t\tfl := yyS[yypt-2].item.([]*ast.SelectField)\n\t\t\tlast := fl[len(fl)-1]\n\t\t\tif last.Expr != nil && last.AsName.O == \"\" {\n\t\t\t\tlastEnd := parser.endOffset(&yyS[yypt-1])\n\t\t\t\tlast.SetText(parser.src[last.Offset:lastEnd])\n\t\t\t}\n\t\t\tnewField := yyS[yypt-0].item.(*ast.SelectField)\n\t\t\tnewField.Offset = parser.startOffset(&yyS[yypt])\n\t\t\tparser.yyVAL.item = append(fl, newField)\n\t\t}\n\tcase 491:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.GroupByClause{Items: yyS[yypt-0].item.([]*ast.ByItem)}\n\t\t}\n\tcase 492:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 493:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.HavingClause{Expr: yyS[yypt-0].expr}\n\t\t}\n\tcase 494:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 495:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 496:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 497:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 498:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 499:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 500:\n\t\t{\n\t\t\tparser.yyVAL.item = \"\"\n\t\t}\n\tcase 501:\n\t\t{\n\t\t\t// \"index name\"\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 502:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 503:\n\t\t{\n\t\t\t// Merge the options\n\t\t\tif yyS[yypt-1].item == nil {\n\t\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t\t} else {\n\t\t\t\topt1 := yyS[yypt-1].item.(*ast.IndexOption)\n\t\t\t\topt2 := yyS[yypt-0].item.(*ast.IndexOption)\n\t\t\t\tif len(opt2.Comment) > 0 {\n\t\t\t\t\topt1.Comment = opt2.Comment\n\t\t\t\t} else if opt2.Tp != 0 {\n\t\t\t\t\topt1.Tp = opt2.Tp\n\t\t\t\t} else if opt2.KeyBlockSize > 0 {\n\t\t\t\t\topt1.KeyBlockSize = opt2.KeyBlockSize\n\t\t\t\t} else if len(opt2.ParserName.O) > 0 {\n\t\t\t\t\topt1.ParserName = opt2.ParserName\n\t\t\t\t} else if opt2.Visibility != ast.IndexVisibilityDefault {\n\t\t\t\t\topt1.Visibility = opt2.Visibility\n\t\t\t\t}\n\t\t\t\tparser.yyVAL.item = opt1\n\t\t\t}\n\t\t}\n\tcase 504:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexOption{\n\t\t\t\tKeyBlockSize: yyS[yypt-0].item.(uint64),\n\t\t\t}\n\t\t}\n\tcase 505:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexOption{\n\t\t\t\tTp: yyS[yypt-0].item.(model.IndexType),\n\t\t\t}\n\t\t}\n\tcase 506:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexOption{\n\t\t\t\tParserName: model.NewCIStr(yyS[yypt-0].ident),\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The WITH PARASER clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 507:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexOption{\n\t\t\t\tComment: yyS[yypt-0].ident,\n\t\t\t}\n\t\t}\n\tcase 508:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexOption{\n\t\t\t\tVisibility: yyS[yypt-0].item.(ast.IndexVisibility),\n\t\t\t}\n\t\t}\n\tcase 509:\n\t\t{\n\t\t\tparser.yyVAL.item = []interface{}{yyS[yypt-0].item, nil}\n\t\t}\n\tcase 510:\n\t\t{\n\t\t\tparser.yyVAL.item = []interface{}{yyS[yypt-2].item, yyS[yypt-0].item}\n\t\t}\n\tcase 511:\n\t\t{\n\t\t\tparser.yyVAL.item = []interface{}{yyS[yypt-2].ident, yyS[yypt-0].item}\n\t\t}\n\tcase 512:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 513:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 514:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 515:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 516:\n\t\t{\n\t\t\tparser.yyVAL.item = model.IndexTypeBtree\n\t\t}\n\tcase 517:\n\t\t{\n\t\t\tparser.yyVAL.item = model.IndexTypeHash\n\t\t}\n\tcase 518:\n\t\t{\n\t\t\tparser.yyVAL.item = model.IndexTypeRtree\n\t\t}\n\tcase 519:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.IndexVisibilityVisible\n\t\t}\n\tcase 520:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.IndexVisibilityInvisible\n\t\t}\n\tcase 882:\n\t\t{\n\t\t\tx := yyS[yypt-1].item.(*ast.InsertStmt)\n\t\t\tx.Priority = yyS[yypt-5].item.(mysql.PriorityEnum)\n\t\t\tx.IgnoreErr = yyS[yypt-4].item.(bool)\n\t\t\t// Wraps many layers here so that it can be processed the same way as select statement.\n\t\t\tts := &ast.TableSource{Source: yyS[yypt-2].item.(*ast.TableName)}\n\t\t\tx.Table = &ast.TableRefsClause{TableRefs: &ast.Join{Left: ts}}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tx.OnDuplicate = yyS[yypt-0].item.([]*ast.Assignment)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 885:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.InsertStmt{\n\t\t\t\tColumns: yyS[yypt-3].item.([]*ast.ColumnName),\n\t\t\t\tLists:   yyS[yypt-0].item.([][]ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 886:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.InsertStmt{Columns: yyS[yypt-2].item.([]*ast.ColumnName), Select: yyS[yypt-0].statement.(*ast.SelectStmt)}\n\t\t}\n\tcase 887:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.InsertStmt{Columns: yyS[yypt-4].item.([]*ast.ColumnName), Select: yyS[yypt-1].statement.(*ast.SelectStmt)}\n\t\t}\n\tcase 888:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.InsertStmt{Columns: yyS[yypt-2].item.([]*ast.ColumnName), Select: yyS[yypt-0].statement.(*ast.UnionStmt)}\n\t\t}\n\tcase 889:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.InsertStmt{Lists: yyS[yypt-0].item.([][]ast.ExprNode)}\n\t\t}\n\tcase 890:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.InsertStmt{Select: yyS[yypt-1].statement.(*ast.SelectStmt)}\n\t\t}\n\tcase 891:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.InsertStmt{Select: yyS[yypt-0].statement.(*ast.SelectStmt)}\n\t\t}\n\tcase 892:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.InsertStmt{Select: yyS[yypt-0].statement.(*ast.UnionStmt)}\n\t\t}\n\tcase 893:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.InsertStmt{Setlist: yyS[yypt-0].item.([]*ast.Assignment)}\n\t\t}\n\tcase 896:\n\t\t{\n\t\t\tparser.yyVAL.item = [][]ast.ExprNode{yyS[yypt-0].item.([]ast.ExprNode)}\n\t\t}\n\tcase 897:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([][]ast.ExprNode), yyS[yypt-0].item.([]ast.ExprNode))\n\t\t}\n\tcase 898:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item\n\t\t}\n\tcase 899:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.ExprNode{}\n\t\t}\n\tcase 901:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]ast.ExprNode), yyS[yypt-0].expr)\n\t\t}\n\tcase 902:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.ExprNode{yyS[yypt-0].expr}\n\t\t}\n\tcase 904:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.DefaultExpr{}\n\t\t}\n\tcase 905:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Assignment{\n\t\t\t\tColumn: yyS[yypt-2].item.(*ast.ColumnName),\n\t\t\t\tExpr:   yyS[yypt-0].expr,\n\t\t\t}\n\t\t}\n\tcase 906:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.Assignment{}\n\t\t}\n\tcase 907:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.Assignment{yyS[yypt-0].item.(*ast.Assignment)}\n\t\t}\n\tcase 908:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.Assignment), yyS[yypt-0].item.(*ast.Assignment))\n\t\t}\n\tcase 909:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 910:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 911:\n\t\t{\n\t\t\tx := yyS[yypt-0].item.(*ast.InsertStmt)\n\t\t\tx.IsReplace = true\n\t\t\tx.Priority = yyS[yypt-3].item.(mysql.PriorityEnum)\n\t\t\tts := &ast.TableSource{Source: yyS[yypt-1].item.(*ast.TableName)}\n\t\t\tx.Table = &ast.TableRefsClause{TableRefs: &ast.Join{Left: ts}}\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 912:\n\t\t{\n\t\t\tparser.yyVAL.ident = ast.DateLiteral\n\t\t}\n\tcase 913:\n\t\t{\n\t\t\tparser.yyVAL.ident = ast.TimeLiteral\n\t\t}\n\tcase 914:\n\t\t{\n\t\t\tparser.yyVAL.ident = ast.TimestampLiteral\n\t\t}\n\tcase 915:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(false)\n\t\t}\n\tcase 916:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(nil)\n\t\t}\n\tcase 917:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(true)\n\t\t}\n\tcase 918:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item)\n\t\t}\n\tcase 919:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item)\n\t\t}\n\tcase 920:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item)\n\t\t}\n\tcase 921:\n\t\t{\n\t\t\tparser.yyVAL.expr = yyS[yypt-0].expr\n\t\t}\n\tcase 922:\n\t\t{\n\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/charset-literal.html\n\t\t\tco, err := charset.GetDefaultCollation(yyS[yypt-1].ident)\n\t\t\tif err != nil {\n\t\t\t\tyylex.AppendError(yylex.Errorf(\"Get collation error for charset: %s\", yyS[yypt-1].ident))\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-0].ident)\n\t\t\ttp := expr.GetType()\n\t\t\ttp.Charset = yyS[yypt-1].ident\n\t\t\ttp.Collate = co\n\t\t\tif tp.Collate == charset.CollationBin {\n\t\t\t\ttp.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tparser.yyVAL.expr = expr\n\t\t}\n\tcase 923:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item)\n\t\t}\n\tcase 924:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item)\n\t\t}\n\tcase 925:\n\t\t{\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-0].ident)\n\t\t\tparser.yyVAL.expr = expr\n\t\t}\n\tcase 926:\n\t\t{\n\t\t\tvalExpr := yyS[yypt-1].expr.(ast.ValueExpr)\n\t\t\tstrLit := valExpr.GetString()\n\t\t\texpr := ast.NewValueExpr(strLit + yyS[yypt-0].ident)\n\t\t\t// Fix #4239, use first string literal as projection name.\n\t\t\tif valExpr.GetProjectionOffset() >= 0 {\n\t\t\t\texpr.SetProjectionOffset(valExpr.GetProjectionOffset())\n\t\t\t} else {\n\t\t\t\texpr.SetProjectionOffset(len(strLit))\n\t\t\t}\n\t\t\tparser.yyVAL.expr = expr\n\t\t}\n\tcase 927:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.AlterOrderItem{yyS[yypt-0].item.(*ast.AlterOrderItem)}\n\t\t}\n\tcase 928:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.AlterOrderItem), yyS[yypt-0].item.(*ast.AlterOrderItem))\n\t\t}\n\tcase 929:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AlterOrderItem{Column: yyS[yypt-1].item.(*ast.ColumnName), Desc: yyS[yypt-0].item.(bool)}\n\t\t}\n\tcase 930:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.OrderByClause{Items: yyS[yypt-0].item.([]*ast.ByItem)}\n\t\t}\n\tcase 931:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.ByItem{yyS[yypt-0].item.(*ast.ByItem)}\n\t\t}\n\tcase 932:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.ByItem), yyS[yypt-0].item.(*ast.ByItem))\n\t\t}\n\tcase 933:\n\t\t{\n\t\t\texpr := yyS[yypt-1].expr\n\t\t\tvalueExpr, ok := expr.(ast.ValueExpr)\n\t\t\tif ok {\n\t\t\t\tposition, isPosition := valueExpr.GetValue().(int64)\n\t\t\t\tif isPosition {\n\t\t\t\t\texpr = &ast.PositionExpr{N: int(position)}\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.ByItem{Expr: expr, Desc: yyS[yypt-0].item.(bool)}\n\t\t}\n\tcase 934:\n\t\t{\n\t\t\tparser.yyVAL.item = false // ASC by default\n\t\t}\n\tcase 935:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 936:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 937:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 938:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 939:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.Or, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 940:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.And, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 941:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.LeftShift, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 942:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.RightShift, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 943:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.Plus, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 944:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.Minus, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 945:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(\"DATE_ADD\"),\n\t\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t\tyyS[yypt-4].expr,\n\t\t\t\t\tyyS[yypt-1].expr,\n\t\t\t\t\t&ast.TimeUnitExpr{Unit: yyS[yypt-0].item.(ast.TimeUnitType)},\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\tcase 946:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(\"DATE_SUB\"),\n\t\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t\tyyS[yypt-4].expr,\n\t\t\t\t\tyyS[yypt-1].expr,\n\t\t\t\t\t&ast.TimeUnitExpr{Unit: yyS[yypt-0].item.(ast.TimeUnitType)},\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\tcase 947:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.Mul, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 948:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.Div, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 949:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.Mod, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 950:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.IntDiv, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 951:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.Mod, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 952:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.BinaryOperationExpr{Op: opcode.Xor, L: yyS[yypt-2].expr, R: yyS[yypt-0].expr}\n\t\t}\n\tcase 954:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.ColumnNameExpr{Name: &ast.ColumnName{\n\t\t\t\tName: model.NewCIStr(yyS[yypt-0].ident),\n\t\t\t}}\n\t\t}\n\tcase 955:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.ColumnNameExpr{Name: &ast.ColumnName{\n\t\t\t\tTable: model.NewCIStr(yyS[yypt-2].ident),\n\t\t\t\tName:  model.NewCIStr(yyS[yypt-0].ident),\n\t\t\t}}\n\t\t}\n\tcase 956:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.ColumnNameExpr{Name: &ast.ColumnName{\n\t\t\t\tTable: model.NewCIStr(yyS[yypt-2].ident),\n\t\t\t\tName:  model.NewCIStr(yyS[yypt-0].ident),\n\t\t\t}}\n\t\t}\n\tcase 957:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.ColumnNameExpr{Name: &ast.ColumnName{\n\t\t\t\tSchema: model.NewCIStr(yyS[yypt-4].ident),\n\t\t\t\tTable:  model.NewCIStr(yyS[yypt-2].ident),\n\t\t\t\tName:   model.NewCIStr(yyS[yypt-0].ident),\n\t\t\t}}\n\t\t}\n\tcase 958:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewParamMarkerExpr(yyS[yypt].offset, yyS[yypt-1].item.(string))\n\t\t}\n\tcase 963:\n\t\t{\n\t\t\t// TODO: Create a builtin function hold expr and collation. When do evaluation, convert expr result using the collation.\n\t\t\tparser.yyVAL.expr = yyS[yypt-2].expr\n\t\t}\n\tcase 964:\n\t\t{\n\t\t\tparser.yyVAL.expr = yyS[yypt-0].item.(*ast.WindowFuncExpr)\n\t\t}\n\tcase 966:\n\t\t{\n\t\t\tparser.yyVAL.expr = yyS[yypt-0].expr\n\t\t}\n\tcase 969:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Not, V: yyS[yypt-0].expr}\n\t\t}\n\tcase 970:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.BitNeg, V: yyS[yypt-0].expr}\n\t\t}\n\tcase 971:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Minus, V: yyS[yypt-0].expr}\n\t\t}\n\tcase 972:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Plus, V: yyS[yypt-0].expr}\n\t\t}\n\tcase 973:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Concat), Args: []ast.ExprNode{yyS[yypt-2].expr, yyS[yypt-0].expr}}\n\t\t}\n\tcase 974:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Not, V: yyS[yypt-0].expr}\n\t\t}\n\tcase 976:\n\t\t{\n\t\t\tstartOffset := parser.startOffset(&yyS[yypt-1])\n\t\t\tendOffset := parser.endOffset(&yyS[yypt])\n\t\t\texpr := yyS[yypt-1].expr\n\t\t\texpr.SetText(parser.src[startOffset:endOffset])\n\t\t\tparser.yyVAL.expr = &ast.ParenthesesExpr{Expr: expr}\n\t\t}\n\tcase 977:\n\t\t{\n\t\t\tvalues := append(yyS[yypt-3].item.([]ast.ExprNode), yyS[yypt-1].expr)\n\t\t\tparser.yyVAL.expr = &ast.RowExpr{Values: values}\n\t\t}\n\tcase 978:\n\t\t{\n\t\t\tvalues := append(yyS[yypt-3].item.([]ast.ExprNode), yyS[yypt-1].expr)\n\t\t\tparser.yyVAL.expr = &ast.RowExpr{Values: values}\n\t\t}\n\tcase 979:\n\t\t{\n\t\t\tsq := yyS[yypt-0].expr.(*ast.SubqueryExpr)\n\t\t\tsq.Exists = true\n\t\t\tparser.yyVAL.expr = &ast.ExistsSubqueryExpr{Sel: sq}\n\t\t}\n\tcase 980:\n\t\t{\n\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#operator_binary\n\t\t\tx := types.NewFieldType(mysql.TypeString)\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CharsetBin\n\t\t\tparser.yyVAL.expr = &ast.FuncCastExpr{\n\t\t\t\tExpr:         yyS[yypt-0].expr,\n\t\t\t\tTp:           x,\n\t\t\t\tFunctionType: ast.CastBinaryOperator,\n\t\t\t}\n\t\t}\n\tcase 981:\n\t\t{\n\t\t\t/* See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_cast */\n\t\t\ttp := yyS[yypt-1].item.(*types.FieldType)\n\t\t\tdefaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimalForCast(tp.Tp)\n\t\t\tif tp.Flen == types.UnspecifiedLength {\n\t\t\t\ttp.Flen = defaultFlen\n\t\t\t}\n\t\t\tif tp.Decimal == types.UnspecifiedLength {\n\t\t\t\ttp.Decimal = defaultDecimal\n\t\t\t}\n\t\t\tparser.yyVAL.expr = &ast.FuncCastExpr{\n\t\t\t\tExpr:         yyS[yypt-3].expr,\n\t\t\t\tTp:           tp,\n\t\t\t\tFunctionType: ast.CastFunction,\n\t\t\t}\n\t\t}\n\tcase 982:\n\t\t{\n\t\t\tx := &ast.CaseExpr{WhenClauses: yyS[yypt-2].item.([]*ast.WhenClause)}\n\t\t\tif yyS[yypt-3].expr != nil {\n\t\t\t\tx.Value = yyS[yypt-3].expr\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tx.ElseClause = yyS[yypt-1].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tparser.yyVAL.expr = x\n\t\t}\n\tcase 983:\n\t\t{\n\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert\n\t\t\ttp := yyS[yypt-1].item.(*types.FieldType)\n\t\t\tdefaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimalForCast(tp.Tp)\n\t\t\tif tp.Flen == types.UnspecifiedLength {\n\t\t\t\ttp.Flen = defaultFlen\n\t\t\t}\n\t\t\tif tp.Decimal == types.UnspecifiedLength {\n\t\t\t\ttp.Decimal = defaultDecimal\n\t\t\t}\n\t\t\tparser.yyVAL.expr = &ast.FuncCastExpr{\n\t\t\t\tExpr:         yyS[yypt-3].expr,\n\t\t\t\tTp:           tp,\n\t\t\t\tFunctionType: ast.CastConvertFunction,\n\t\t\t}\n\t\t}\n\tcase 984:\n\t\t{\n\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert\n\t\t\tcharset1 := ast.NewValueExpr(yyS[yypt-1].item)\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-5].ident),\n\t\t\t\tArgs:   []ast.ExprNode{yyS[yypt-3].expr, charset1},\n\t\t\t}\n\t\t}\n\tcase 985:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.DefaultExpr{Name: yyS[yypt-1].expr.(*ast.ColumnNameExpr).Name}\n\t\t}\n\tcase 986:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.ValuesExpr{Column: yyS[yypt-1].expr.(*ast.ColumnNameExpr)}\n\t\t}\n\tcase 987:\n\t\t{\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-0].ident)\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONExtract), Args: []ast.ExprNode{yyS[yypt-2].expr, expr}}\n\t\t}\n\tcase 988:\n\t\t{\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-0].ident)\n\t\t\textract := &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONExtract), Args: []ast.ExprNode{yyS[yypt-2].expr, expr}}\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONUnquote), Args: []ast.ExprNode{extract}}\n\t\t}\n\tcase 991:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 992:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 993:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 995:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 998:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1040:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-3].ident), Args: yyS[yypt-1].item.([]ast.ExprNode)}\n\t\t}\n\tcase 1041:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-3].ident), Args: yyS[yypt-1].item.([]ast.ExprNode)}\n\t\t}\n\tcase 1042:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-1].ident)}\n\t\t}\n\tcase 1043:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-2].ident)}\n\t\t}\n\tcase 1044:\n\t\t{\n\t\t\targs := []ast.ExprNode{}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\targs = append(args, yyS[yypt-0].item.(ast.ExprNode))\n\t\t\t}\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-1].ident), Args: args}\n\t\t}\n\tcase 1045:\n\t\t{\n\t\t\tnilVal := ast.NewValueExpr(nil)\n\t\t\targs := yyS[yypt-1].item.([]ast.ExprNode)\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(ast.CharFunc),\n\t\t\t\tArgs:   append(args, nilVal),\n\t\t\t}\n\t\t}\n\tcase 1046:\n\t\t{\n\t\t\tcharset1 := ast.NewValueExpr(yyS[yypt-1].item)\n\t\t\targs := yyS[yypt-3].item.([]ast.ExprNode)\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(ast.CharFunc),\n\t\t\t\tArgs:   append(args, charset1),\n\t\t\t}\n\t\t}\n\tcase 1047:\n\t\t{\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-0].ident)\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.DateLiteral), Args: []ast.ExprNode{expr}}\n\t\t}\n\tcase 1048:\n\t\t{\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-0].ident)\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.TimeLiteral), Args: []ast.ExprNode{expr}}\n\t\t}\n\tcase 1049:\n\t\t{\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-0].ident)\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.TimestampLiteral), Args: []ast.ExprNode{expr}}\n\t\t}\n\tcase 1050:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.InsertFunc), Args: yyS[yypt-1].item.([]ast.ExprNode)}\n\t\t}\n\tcase 1051:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Mod), Args: []ast.ExprNode{yyS[yypt-3].expr, yyS[yypt-1].expr}}\n\t\t}\n\tcase 1052:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.PasswordFunc), Args: yyS[yypt-1].item.([]ast.ExprNode)}\n\t\t}\n\tcase 1053:\n\t\t{\n\t\t\t// This is ODBC syntax for date and time literals.\n\t\t\t// See: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-1].ident)\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-2].ident), Args: []ast.ExprNode{expr}}\n\t\t}\n\tcase 1054:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-3].ident), Args: yyS[yypt-1].item.([]ast.ExprNode)}\n\t\t}\n\tcase 1055:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-3].ident), Args: yyS[yypt-1].item.([]ast.ExprNode)}\n\t\t}\n\tcase 1056:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-5].ident),\n\t\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t\tyyS[yypt-3].expr,\n\t\t\t\t\tyyS[yypt-1].expr,\n\t\t\t\t\t&ast.TimeUnitExpr{Unit: ast.TimeUnitDay},\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\tcase 1057:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-7].ident),\n\t\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t\tyyS[yypt-5].expr,\n\t\t\t\t\tyyS[yypt-2].expr,\n\t\t\t\t\t&ast.TimeUnitExpr{Unit: yyS[yypt-1].item.(ast.TimeUnitType)},\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\tcase 1058:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-7].ident),\n\t\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t\tyyS[yypt-5].expr,\n\t\t\t\t\tyyS[yypt-2].expr,\n\t\t\t\t\t&ast.TimeUnitExpr{Unit: yyS[yypt-1].item.(ast.TimeUnitType)},\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\tcase 1059:\n\t\t{\n\t\t\ttimeUnit := &ast.TimeUnitExpr{Unit: yyS[yypt-3].item.(ast.TimeUnitType)}\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-5].ident),\n\t\t\t\tArgs:   []ast.ExprNode{timeUnit, yyS[yypt-1].expr},\n\t\t\t}\n\t\t}\n\tcase 1060:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-5].ident),\n\t\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t\t&ast.GetFormatSelectorExpr{Selector: yyS[yypt-3].item.(ast.GetFormatSelectorType)},\n\t\t\t\t\tyyS[yypt-1].expr,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\tcase 1061:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-5].ident), Args: []ast.ExprNode{yyS[yypt-3].expr, yyS[yypt-1].expr}}\n\t\t}\n\tcase 1062:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-5].ident),\n\t\t\t\tArgs:   []ast.ExprNode{yyS[yypt-3].expr, yyS[yypt-1].expr},\n\t\t\t}\n\t\t}\n\tcase 1063:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-5].ident),\n\t\t\t\tArgs:   []ast.ExprNode{yyS[yypt-3].expr, yyS[yypt-1].expr},\n\t\t\t}\n\t\t}\n\tcase 1064:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-7].ident),\n\t\t\t\tArgs:   []ast.ExprNode{yyS[yypt-5].expr, yyS[yypt-3].expr, yyS[yypt-1].expr},\n\t\t\t}\n\t\t}\n\tcase 1065:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-7].ident),\n\t\t\t\tArgs:   []ast.ExprNode{yyS[yypt-5].expr, yyS[yypt-3].expr, yyS[yypt-1].expr},\n\t\t\t}\n\t\t}\n\tcase 1066:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-7].ident),\n\t\t\t\tArgs:   []ast.ExprNode{&ast.TimeUnitExpr{Unit: yyS[yypt-5].item.(ast.TimeUnitType)}, yyS[yypt-3].expr, yyS[yypt-1].expr},\n\t\t\t}\n\t\t}\n\tcase 1067:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-7].ident),\n\t\t\t\tArgs:   []ast.ExprNode{&ast.TimeUnitExpr{Unit: yyS[yypt-5].item.(ast.TimeUnitType)}, yyS[yypt-3].expr, yyS[yypt-1].expr},\n\t\t\t}\n\t\t}\n\tcase 1068:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-3].ident),\n\t\t\t\tArgs:   []ast.ExprNode{yyS[yypt-1].expr},\n\t\t\t}\n\t\t}\n\tcase 1069:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-5].ident),\n\t\t\t\tArgs:   []ast.ExprNode{yyS[yypt-1].expr, yyS[yypt-3].expr},\n\t\t\t}\n\t\t}\n\tcase 1070:\n\t\t{\n\t\t\tnilVal := ast.NewValueExpr(nil)\n\t\t\tdirection := &ast.TrimDirectionExpr{Direction: yyS[yypt-3].item.(ast.TrimDirectionType)}\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-5].ident),\n\t\t\t\tArgs:   []ast.ExprNode{yyS[yypt-1].expr, nilVal, direction},\n\t\t\t}\n\t\t}\n\tcase 1071:\n\t\t{\n\t\t\tdirection := &ast.TrimDirectionExpr{Direction: yyS[yypt-4].item.(ast.TrimDirectionType)}\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{\n\t\t\t\tFnName: model.NewCIStr(yyS[yypt-6].ident),\n\t\t\t\tArgs:   []ast.ExprNode{yyS[yypt-1].expr, yyS[yypt-3].expr, direction},\n\t\t\t}\n\t\t}\n\tcase 1072:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.GetFormatSelectorDate\n\t\t}\n\tcase 1073:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.GetFormatSelectorDatetime\n\t\t}\n\tcase 1074:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.GetFormatSelectorTime\n\t\t}\n\tcase 1075:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.GetFormatSelectorDatetime\n\t\t}\n\tcase 1080:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TrimBoth\n\t\t}\n\tcase 1081:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TrimLeading\n\t\t}\n\tcase 1082:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TrimTrailing\n\t\t}\n\tcase 1083:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)}\n\t\t\t}\n\t\t}\n\tcase 1084:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}}\n\t\t\t}\n\t\t}\n\tcase 1085:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}}\n\t\t\t}\n\t\t}\n\tcase 1086:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}}\n\t\t\t}\n\t\t}\n\tcase 1087:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}}\n\t\t\t}\n\t\t}\n\tcase 1088:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}}\n\t\t\t}\n\t\t}\n\tcase 1089:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}}\n\t\t\t}\n\t\t}\n\tcase 1090:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: yyS[yypt-1].item.([]ast.ExprNode), Distinct: true}\n\t\t}\n\tcase 1091:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}}\n\t\t\t}\n\t\t}\n\tcase 1092:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}}\n\t\t\t}\n\t\t}\n\tcase 1093:\n\t\t{\n\t\t\targs := []ast.ExprNode{ast.NewValueExpr(1)}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: args, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: args}\n\t\t\t}\n\t\t}\n\tcase 1094:\n\t\t{\n\t\t\targs := yyS[yypt-3].item.([]ast.ExprNode)\n\t\t\targs = append(args, yyS[yypt-1].item.(ast.ExprNode))\n\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-6].ident, Args: args, Distinct: yyS[yypt-4].item.(bool)}\n\t\t}\n\tcase 1095:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)}\n\t\t\t}\n\t\t}\n\tcase 1096:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)}\n\t\t\t}\n\t\t}\n\tcase 1097:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-3].ident, Args: yyS[yypt-1].item.([]ast.ExprNode)}\n\t\t}\n\tcase 1098:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)}\n\t\t\t}\n\t\t}\n\tcase 1099:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: ast.AggFuncStddevPop, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: ast.AggFuncStddevPop, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)}\n\t\t\t}\n\t\t}\n\tcase 1100:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)}\n\t\t\t}\n\t\t}\n\tcase 1101:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.expr = &ast.WindowFuncExpr{F: ast.AggFuncVarPop, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool), Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: ast.AggFuncVarPop, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)}\n\t\t\t}\n\t\t}\n\tcase 1102:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Distinct: yyS[yypt-3].item.(bool)}\n\t\t}\n\tcase 1103:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.AggregateFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-1].expr}, Distinct: yyS[yypt-2].item.(bool)}\n\t\t}\n\tcase 1104:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.NewValueExpr(\",\")\n\t\t}\n\tcase 1105:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.NewValueExpr(yyS[yypt-0].ident)\n\t\t}\n\tcase 1106:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-3].ident), Args: yyS[yypt-1].item.([]ast.ExprNode)}\n\t\t}\n\tcase 1107:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1108:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1109:\n\t\t{\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-1].item)\n\t\t\tparser.yyVAL.item = expr\n\t\t}\n\tcase 1110:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1111:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitSecondMicrosecond\n\t\t}\n\tcase 1112:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitMinuteMicrosecond\n\t\t}\n\tcase 1113:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitMinuteSecond\n\t\t}\n\tcase 1114:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitHourMicrosecond\n\t\t}\n\tcase 1115:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitHourSecond\n\t\t}\n\tcase 1116:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitHourMinute\n\t\t}\n\tcase 1117:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitDayMicrosecond\n\t\t}\n\tcase 1118:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitDaySecond\n\t\t}\n\tcase 1119:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitDayMinute\n\t\t}\n\tcase 1120:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitDayHour\n\t\t}\n\tcase 1121:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitYearMonth\n\t\t}\n\tcase 1122:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitMicrosecond\n\t\t}\n\tcase 1123:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitSecond\n\t\t}\n\tcase 1124:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitMinute\n\t\t}\n\tcase 1125:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitHour\n\t\t}\n\tcase 1126:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitDay\n\t\t}\n\tcase 1127:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitWeek\n\t\t}\n\tcase 1128:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitMonth\n\t\t}\n\tcase 1129:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitQuarter\n\t\t}\n\tcase 1130:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitYear\n\t\t}\n\tcase 1131:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitSecond\n\t\t}\n\tcase 1132:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitMinute\n\t\t}\n\tcase 1133:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitHour\n\t\t}\n\tcase 1134:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitDay\n\t\t}\n\tcase 1135:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitWeek\n\t\t}\n\tcase 1136:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitMonth\n\t\t}\n\tcase 1137:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitQuarter\n\t\t}\n\tcase 1138:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TimeUnitYear\n\t\t}\n\tcase 1139:\n\t\t{\n\t\t\tparser.yyVAL.expr = nil\n\t\t}\n\tcase 1140:\n\t\t{\n\t\t\tparser.yyVAL.expr = yyS[yypt-0].expr\n\t\t}\n\tcase 1141:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.WhenClause{yyS[yypt-0].item.(*ast.WhenClause)}\n\t\t}\n\tcase 1142:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-1].item.([]*ast.WhenClause), yyS[yypt-0].item.(*ast.WhenClause))\n\t\t}\n\tcase 1143:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.WhenClause{\n\t\t\t\tExpr:   yyS[yypt-2].expr,\n\t\t\t\tResult: yyS[yypt-0].expr,\n\t\t\t}\n\t\t}\n\tcase 1144:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1145:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].expr\n\t\t}\n\tcase 1146:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeVarString)\n\t\t\tx.Flen = yyS[yypt-0].item.(int) // TODO: Flen should be the flen of expression\n\t\t\tif x.Flen != types.UnspecifiedLength {\n\t\t\t\tx.Tp = mysql.TypeString\n\t\t\t}\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1147:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeVarString)\n\t\t\tx.Flen = yyS[yypt-1].item.(int) // TODO: Flen should be the flen of expression\n\t\t\tx.Charset = yyS[yypt-0].item.(*ast.OptBinary).Charset\n\t\t\tif yyS[yypt-0].item.(*ast.OptBinary).IsBinary {\n\t\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tif x.Charset == \"\" {\n\t\t\t\tx.Charset = mysql.DefaultCharset\n\t\t\t\tx.Collate = mysql.DefaultCollationName\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1148:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeDate)\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1149:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeDatetime)\n\t\t\tx.Flen, _ = mysql.GetDefaultFieldLengthAndDecimalForCast(mysql.TypeDatetime)\n\t\t\tx.Decimal = yyS[yypt-0].item.(int)\n\t\t\tif x.Decimal > 0 {\n\t\t\t\tx.Flen = x.Flen + 1 + x.Decimal\n\t\t\t}\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1150:\n\t\t{\n\t\t\tfopt := yyS[yypt-0].item.(*ast.FloatOpt)\n\t\t\tx := types.NewFieldType(mysql.TypeNewDecimal)\n\t\t\tx.Flen = fopt.Flen\n\t\t\tx.Decimal = fopt.Decimal\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1151:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeDuration)\n\t\t\tx.Flen, _ = mysql.GetDefaultFieldLengthAndDecimalForCast(mysql.TypeDuration)\n\t\t\tx.Decimal = yyS[yypt-0].item.(int)\n\t\t\tif x.Decimal > 0 {\n\t\t\t\tx.Flen = x.Flen + 1 + x.Decimal\n\t\t\t}\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1152:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeLonglong)\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1153:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeLonglong)\n\t\t\tx.Flag |= mysql.UnsignedFlag | mysql.BinaryFlag\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1154:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeJSON)\n\t\t\tx.Flag |= mysql.BinaryFlag | (mysql.ParseToJSONFlag)\n\t\t\tx.Charset = mysql.DefaultCharset\n\t\t\tx.Collate = mysql.DefaultCollationName\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1155:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeDouble)\n\t\t\tx.Flen, x.Decimal = mysql.GetDefaultFieldLengthAndDecimalForCast(mysql.TypeDouble)\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1156:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeFloat)\n\t\t\tfopt := yyS[yypt-0].item.(*ast.FloatOpt)\n\t\t\tif fopt.Flen >= 54 {\n\t\t\t\tyylex.AppendError(ErrTooBigPrecision.GenWithStackByArgs(fopt.Flen, \"CAST\", 53))\n\t\t\t} else if fopt.Flen >= 25 {\n\t\t\t\tx = types.NewFieldType(mysql.TypeDouble)\n\t\t\t}\n\t\t\tx.Flen, x.Decimal = mysql.GetDefaultFieldLengthAndDecimalForCast(x.Tp)\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1157:\n\t\t{\n\t\t\tvar x *types.FieldType\n\t\t\tif parser.lexer.GetSQLMode().HasRealAsFloatMode() {\n\t\t\t\tx = types.NewFieldType(mysql.TypeFloat)\n\t\t\t} else {\n\t\t\t\tx = types.NewFieldType(mysql.TypeDouble)\n\t\t\t}\n\t\t\tx.Flen, x.Decimal = mysql.GetDefaultFieldLengthAndDecimalForCast(x.Tp)\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1158:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.NoPriority\n\t\t}\n\tcase 1159:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.LowPriority\n\t\t}\n\tcase 1160:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.HighPriority\n\t\t}\n\tcase 1161:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.DelayedPriority\n\t\t}\n\tcase 1162:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableName{Name: model.NewCIStr(yyS[yypt-0].ident)}\n\t\t}\n\tcase 1163:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableName{Schema: model.NewCIStr(yyS[yypt-2].ident), Name: model.NewCIStr(yyS[yypt-0].ident)}\n\t\t}\n\tcase 1164:\n\t\t{\n\t\t\ttbl := []*ast.TableName{yyS[yypt-0].item.(*ast.TableName)}\n\t\t\tparser.yyVAL.item = tbl\n\t\t}\n\tcase 1165:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.TableName), yyS[yypt-0].item.(*ast.TableName))\n\t\t}\n\tcase 1166:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableName{Name: model.NewCIStr(yyS[yypt-1].ident)}\n\t\t}\n\tcase 1167:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableName{Schema: model.NewCIStr(yyS[yypt-3].ident), Name: model.NewCIStr(yyS[yypt-1].ident)}\n\t\t}\n\tcase 1168:\n\t\t{\n\t\t\ttbl := []*ast.TableName{yyS[yypt-0].item.(*ast.TableName)}\n\t\t\tparser.yyVAL.item = tbl\n\t\t}\n\tcase 1169:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.TableName), yyS[yypt-0].item.(*ast.TableName))\n\t\t}\n\tcase 1172:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1173:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1174:\n\t\t{\n\t\t\tvar sqlText string\n\t\t\tvar sqlVar *ast.VariableExpr\n\t\t\tswitch yyS[yypt-0].item.(type) {\n\t\t\tcase string:\n\t\t\t\tsqlText = yyS[yypt-0].item.(string)\n\t\t\tcase *ast.VariableExpr:\n\t\t\t\tsqlVar = yyS[yypt-0].item.(*ast.VariableExpr)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = &ast.PrepareStmt{\n\t\t\t\tName:    yyS[yypt-2].ident,\n\t\t\t\tSQLText: sqlText,\n\t\t\t\tSQLVar:  sqlVar,\n\t\t\t}\n\t\t}\n\tcase 1175:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1176:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].expr.(interface{})\n\t\t}\n\tcase 1177:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExecuteStmt{Name: yyS[yypt-0].ident}\n\t\t}\n\tcase 1178:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ExecuteStmt{\n\t\t\t\tName:      yyS[yypt-2].ident,\n\t\t\t\tUsingVars: yyS[yypt-0].item.([]ast.ExprNode),\n\t\t\t}\n\t\t}\n\tcase 1179:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.ExprNode{yyS[yypt-0].expr}\n\t\t}\n\tcase 1180:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]ast.ExprNode), yyS[yypt-0].expr)\n\t\t}\n\tcase 1181:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.DeallocateStmt{Name: yyS[yypt-0].ident}\n\t\t}\n\tcase 1184:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.RollbackStmt{}\n\t\t}\n\tcase 1185:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ShutdownStmt{}\n\t\t}\n\tcase 1186:\n\t\t{\n\t\t\tst := &ast.SelectStmt{\n\t\t\t\tSelectStmtOpts: yyS[yypt-1].item.(*ast.SelectStmtOpts),\n\t\t\t\tDistinct:       yyS[yypt-1].item.(*ast.SelectStmtOpts).Distinct,\n\t\t\t\tFields:         yyS[yypt-0].item.(*ast.FieldList),\n\t\t\t}\n\t\t\tif st.SelectStmtOpts.TableHints != nil {\n\t\t\t\tst.TableHints = st.SelectStmtOpts.TableHints\n\t\t\t}\n\t\t\tparser.yyVAL.item = st\n\t\t}\n\tcase 1187:\n\t\t{\n\t\t\tst := yyS[yypt-2].item.(*ast.SelectStmt)\n\t\t\tlastField := st.Fields.Fields[len(st.Fields.Fields)-1]\n\t\t\tif lastField.Expr != nil && lastField.AsName.O == \"\" {\n\t\t\t\tlastEnd := yyS[yypt-1].offset - 1\n\t\t\t\tlastField.SetText(parser.src[lastField.Offset:lastEnd])\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tst.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t}\n\t\t}\n\tcase 1188:\n\t\t{\n\t\t\tst := yyS[yypt-6].item.(*ast.SelectStmt)\n\t\t\tst.From = yyS[yypt-4].item.(*ast.TableRefsClause)\n\t\t\tlastField := st.Fields.Fields[len(st.Fields.Fields)-1]\n\t\t\tif lastField.Expr != nil && lastField.AsName.O == \"\" {\n\t\t\t\tlastEnd := parser.endOffset(&yyS[yypt-5])\n\t\t\t\tlastField.SetText(parser.src[lastField.Offset:lastEnd])\n\t\t\t}\n\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\tst.Where = yyS[yypt-3].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tst.GroupBy = yyS[yypt-2].item.(*ast.GroupByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tst.Having = yyS[yypt-1].item.(*ast.HavingClause)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tst.WindowSpecs = (yyS[yypt-0].item.([]ast.WindowSpec))\n\t\t\t}\n\t\t\tparser.yyVAL.item = st\n\t\t}\n\tcase 1189:\n\t\t{\n\t\t\tst := yyS[yypt-4].item.(*ast.SelectStmt)\n\t\t\tst.LockTp = yyS[yypt-1].item.(ast.SelectLockType)\n\t\t\tlastField := st.Fields.Fields[len(st.Fields.Fields)-1]\n\t\t\tif lastField.Expr != nil && lastField.AsName.O == \"\" {\n\t\t\t\tsrc := parser.src\n\t\t\t\tvar lastEnd int\n\t\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\t\tlastEnd = yyS[yypt-3].offset - 1\n\t\t\t\t} else if yyS[yypt-2].item != nil {\n\t\t\t\t\tlastEnd = yyS[yypt-2].offset - 1\n\t\t\t\t} else if yyS[yypt-1].item != ast.SelectLockNone {\n\t\t\t\t\tlastEnd = yyS[yypt-1].offset - 1\n\t\t\t\t} else if yyS[yypt-0].item != nil {\n\t\t\t\t\tlastEnd = yyS[yypt].offset - 1\n\t\t\t\t} else {\n\t\t\t\t\tlastEnd = len(src)\n\t\t\t\t\tif src[lastEnd-1] == ';' {\n\t\t\t\t\t\tlastEnd--\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlastField.SetText(src[lastField.Offset:lastEnd])\n\t\t\t}\n\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\tst.OrderBy = yyS[yypt-3].item.(*ast.OrderByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tst.Limit = yyS[yypt-2].item.(*ast.Limit)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tst.SelectIntoOpt = yyS[yypt-0].item.(*ast.SelectIntoOption)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = st\n\t\t}\n\tcase 1190:\n\t\t{\n\t\t\tst := yyS[yypt-4].item.(*ast.SelectStmt)\n\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\tst.OrderBy = yyS[yypt-3].item.(*ast.OrderByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tst.Limit = yyS[yypt-2].item.(*ast.Limit)\n\t\t\t}\n\t\t\tst.LockTp = yyS[yypt-1].item.(ast.SelectLockType)\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tst.SelectIntoOpt = yyS[yypt-0].item.(*ast.SelectIntoOption)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = st\n\t\t}\n\tcase 1191:\n\t\t{\n\t\t\tst := yyS[yypt-4].item.(*ast.SelectStmt)\n\t\t\tst.LockTp = yyS[yypt-1].item.(ast.SelectLockType)\n\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\tst.OrderBy = yyS[yypt-3].item.(*ast.OrderByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tst.Limit = yyS[yypt-2].item.(*ast.Limit)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tst.SelectIntoOpt = yyS[yypt-0].item.(*ast.SelectIntoOption)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = st\n\t\t}\n\tcase 1193:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1194:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.([]ast.WindowSpec)\n\t\t}\n\tcase 1195:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.WindowSpec{yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1196:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]ast.WindowSpec), yyS[yypt-0].item.(ast.WindowSpec))\n\t\t}\n\tcase 1197:\n\t\t{\n\t\t\tvar spec = yyS[yypt-0].item.(ast.WindowSpec)\n\t\t\tspec.Name = yyS[yypt-2].item.(model.CIStr)\n\t\t\tparser.yyVAL.item = spec\n\t\t}\n\tcase 1198:\n\t\t{\n\t\t\tparser.yyVAL.item = model.NewCIStr(yyS[yypt-0].ident)\n\t\t}\n\tcase 1199:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item.(ast.WindowSpec)\n\t\t}\n\tcase 1200:\n\t\t{\n\t\t\tspec := ast.WindowSpec{Ref: yyS[yypt-3].item.(model.CIStr)}\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tspec.PartitionBy = yyS[yypt-2].item.(*ast.PartitionByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tspec.OrderBy = yyS[yypt-1].item.(*ast.OrderByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tspec.Frame = yyS[yypt-0].item.(*ast.FrameClause)\n\t\t\t}\n\t\t\tparser.yyVAL.item = spec\n\t\t}\n\tcase 1201:\n\t\t{\n\t\t\tparser.yyVAL.item = model.CIStr{}\n\t\t}\n\tcase 1202:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(model.CIStr)\n\t\t}\n\tcase 1203:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1204:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartitionByClause{Items: yyS[yypt-0].item.([]*ast.ByItem)}\n\t\t}\n\tcase 1205:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1206:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.OrderByClause{Items: yyS[yypt-0].item.([]*ast.ByItem)}\n\t\t}\n\tcase 1207:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1208:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FrameClause{\n\t\t\t\tType:   yyS[yypt-1].item.(ast.FrameType),\n\t\t\t\tExtent: yyS[yypt-0].item.(ast.FrameExtent),\n\t\t\t}\n\t\t}\n\tcase 1209:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameType(ast.Rows)\n\t\t}\n\tcase 1210:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameType(ast.Ranges)\n\t\t}\n\tcase 1211:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameType(ast.Groups)\n\t\t}\n\tcase 1212:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameExtent{\n\t\t\t\tStart: yyS[yypt-0].item.(ast.FrameBound),\n\t\t\t\tEnd:   ast.FrameBound{Type: ast.CurrentRow},\n\t\t\t}\n\t\t}\n\tcase 1213:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(ast.FrameExtent)\n\t\t}\n\tcase 1214:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameBound{Type: ast.Preceding, UnBounded: true}\n\t\t}\n\tcase 1215:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr(yyS[yypt-1].item)}\n\t\t}\n\tcase 1216:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameBound{Type: ast.Preceding, Expr: yyS[yypt-1].expr}\n\t\t}\n\tcase 1217:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameBound{Type: ast.Preceding, Expr: yyS[yypt-2].expr, Unit: yyS[yypt-1].item.(ast.TimeUnitType)}\n\t\t}\n\tcase 1218:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameBound{Type: ast.CurrentRow}\n\t\t}\n\tcase 1219:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameExtent{Start: yyS[yypt-2].item.(ast.FrameBound), End: yyS[yypt-0].item.(ast.FrameBound)}\n\t\t}\n\tcase 1220:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(ast.FrameBound)\n\t\t}\n\tcase 1221:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameBound{Type: ast.Following, UnBounded: true}\n\t\t}\n\tcase 1222:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr(yyS[yypt-1].item)}\n\t\t}\n\tcase 1223:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameBound{Type: ast.Following, Expr: yyS[yypt-1].expr}\n\t\t}\n\tcase 1224:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.FrameBound{Type: ast.Following, Expr: yyS[yypt-2].expr, Unit: yyS[yypt-1].item.(ast.TimeUnitType)}\n\t\t}\n\tcase 1225:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1226:\n\t\t{\n\t\t\tspec := yyS[yypt-0].item.(ast.WindowSpec)\n\t\t\tparser.yyVAL.item = &spec\n\t\t}\n\tcase 1227:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(ast.WindowSpec)\n\t\t}\n\tcase 1228:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.WindowSpec{Name: yyS[yypt-0].item.(model.CIStr), OnlyAlias: true}\n\t\t}\n\tcase 1229:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(ast.WindowSpec)\n\t\t}\n\tcase 1230:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-3].ident, Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1231:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-3].ident, Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1232:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-3].ident, Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1233:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-3].ident, Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1234:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-3].ident, Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1235:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: []ast.ExprNode{yyS[yypt-2].expr}, Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1236:\n\t\t{\n\t\t\targs := []ast.ExprNode{yyS[yypt-4].expr}\n\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\targs = append(args, yyS[yypt-3].item.([]ast.ExprNode)...)\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-6].ident, Args: args, IgnoreNull: yyS[yypt-1].item.(bool), Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1237:\n\t\t{\n\t\t\targs := []ast.ExprNode{yyS[yypt-4].expr}\n\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\targs = append(args, yyS[yypt-3].item.([]ast.ExprNode)...)\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-6].ident, Args: args, IgnoreNull: yyS[yypt-1].item.(bool), Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1238:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-3].expr}, IgnoreNull: yyS[yypt-1].item.(bool), Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1239:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-5].ident, Args: []ast.ExprNode{yyS[yypt-3].expr}, IgnoreNull: yyS[yypt-1].item.(bool), Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1240:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.WindowFuncExpr{F: yyS[yypt-8].ident, Args: []ast.ExprNode{yyS[yypt-6].expr, yyS[yypt-4].expr}, FromLast: yyS[yypt-2].item.(bool), IgnoreNull: yyS[yypt-1].item.(bool), Spec: yyS[yypt-0].item.(ast.WindowSpec)}\n\t\t}\n\tcase 1241:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1242:\n\t\t{\n\t\t\targs := []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].item)}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\targs = append(args, yyS[yypt-0].item.(ast.ExprNode))\n\t\t\t}\n\t\t\tparser.yyVAL.item = args\n\t\t}\n\tcase 1243:\n\t\t{\n\t\t\targs := []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].expr)}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\targs = append(args, yyS[yypt-0].item.(ast.ExprNode))\n\t\t\t}\n\t\t\tparser.yyVAL.item = args\n\t\t}\n\tcase 1244:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1245:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].expr\n\t\t}\n\tcase 1246:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1247:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1248:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1249:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1250:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1251:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1252:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableRefsClause{TableRefs: yyS[yypt-0].item.(*ast.Join)}\n\t\t}\n\tcase 1253:\n\t\t{\n\t\t\tif j, ok := yyS[yypt-0].item.(*ast.Join); ok {\n\t\t\t\t// if $1 is Join, use it directly\n\t\t\t\tparser.yyVAL.item = j\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-0].item.(ast.ResultSetNode), Right: nil}\n\t\t\t}\n\t\t}\n\tcase 1254:\n\t\t{\n\t\t\t/* from a, b is default cross join */\n\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-2].item.(ast.ResultSetNode), Right: yyS[yypt-0].item.(ast.ResultSetNode), Tp: ast.CrossJoin}\n\t\t}\n\tcase 1255:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1256:\n\t\t{\n\t\t\t/*\n\t\t\t * ODBC escape syntax for outer join is { OJ join_table }\n\t\t\t * Use an Identifier for OJ\n\t\t\t */\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item\n\t\t}\n\tcase 1257:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1258:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1259:\n\t\t{\n\t\t\ttn := yyS[yypt-3].item.(*ast.TableName)\n\t\t\ttn.PartitionNames = yyS[yypt-2].item.([]model.CIStr)\n\t\t\ttn.IndexHints = yyS[yypt-0].item.([]*ast.IndexHint)\n\t\t\tparser.yyVAL.item = &ast.TableSource{Source: tn, AsName: yyS[yypt-1].item.(model.CIStr)}\n\t\t}\n\tcase 1260:\n\t\t{\n\t\t\tst := yyS[yypt-2].statement.(*ast.SelectStmt)\n\t\t\tendOffset := parser.endOffset(&yyS[yypt-1])\n\t\t\tparser.setLastSelectFieldText(st, endOffset)\n\t\t\tparser.yyVAL.item = &ast.TableSource{Source: yyS[yypt-2].statement.(*ast.SelectStmt), AsName: yyS[yypt-0].item.(model.CIStr)}\n\t\t}\n\tcase 1261:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableSource{Source: yyS[yypt-2].statement.(*ast.UnionStmt), AsName: yyS[yypt-0].item.(model.CIStr)}\n\t\t}\n\tcase 1262:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item\n\t\t}\n\tcase 1263:\n\t\t{\n\t\t\tparser.yyVAL.item = []model.CIStr{}\n\t\t}\n\tcase 1264:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item\n\t\t}\n\tcase 1265:\n\t\t{\n\t\t\tparser.yyVAL.item = model.CIStr{}\n\t\t}\n\tcase 1266:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1267:\n\t\t{\n\t\t\tparser.yyVAL.item = model.NewCIStr(yyS[yypt-0].ident)\n\t\t}\n\tcase 1268:\n\t\t{\n\t\t\tparser.yyVAL.item = model.NewCIStr(yyS[yypt-0].ident)\n\t\t}\n\tcase 1269:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.HintUse\n\t\t}\n\tcase 1270:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.HintIgnore\n\t\t}\n\tcase 1271:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.HintForce\n\t\t}\n\tcase 1272:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.HintForScan\n\t\t}\n\tcase 1273:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.HintForJoin\n\t\t}\n\tcase 1274:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.HintForOrderBy\n\t\t}\n\tcase 1275:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.HintForGroupBy\n\t\t}\n\tcase 1276:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.IndexHint{\n\t\t\t\tIndexNames: yyS[yypt-1].item.([]model.CIStr),\n\t\t\t\tHintType:   yyS[yypt-4].item.(ast.IndexHintType),\n\t\t\t\tHintScope:  yyS[yypt-3].item.(ast.IndexHintScope),\n\t\t\t}\n\t\t}\n\tcase 1277:\n\t\t{\n\t\t\tvar nameList []model.CIStr\n\t\t\tparser.yyVAL.item = nameList\n\t\t}\n\tcase 1278:\n\t\t{\n\t\t\tparser.yyVAL.item = []model.CIStr{model.NewCIStr(yyS[yypt-0].ident)}\n\t\t}\n\tcase 1279:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]model.CIStr), model.NewCIStr(yyS[yypt-0].ident))\n\t\t}\n\tcase 1280:\n\t\t{\n\t\t\tparser.yyVAL.item = []model.CIStr{model.NewCIStr(yyS[yypt-0].ident)}\n\t\t}\n\tcase 1281:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]model.CIStr), model.NewCIStr(yyS[yypt-0].ident))\n\t\t}\n\tcase 1282:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.IndexHint{yyS[yypt-0].item.(*ast.IndexHint)}\n\t\t}\n\tcase 1283:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-1].item.([]*ast.IndexHint), yyS[yypt-0].item.(*ast.IndexHint))\n\t\t}\n\tcase 1284:\n\t\t{\n\t\t\tvar hintList []*ast.IndexHint\n\t\t\tparser.yyVAL.item = hintList\n\t\t}\n\tcase 1285:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1286:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-2].item.(ast.ResultSetNode), Right: yyS[yypt-0].item.(ast.ResultSetNode), Tp: ast.CrossJoin}\n\t\t}\n\tcase 1287:\n\t\t{\n\t\t\ton := &ast.OnCondition{Expr: yyS[yypt-0].expr}\n\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-4].item.(ast.ResultSetNode), Right: yyS[yypt-2].item.(ast.ResultSetNode), Tp: ast.CrossJoin, On: on}\n\t\t}\n\tcase 1288:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-6].item.(ast.ResultSetNode), Right: yyS[yypt-4].item.(ast.ResultSetNode), Tp: ast.CrossJoin, Using: yyS[yypt-1].item.([]*ast.ColumnName)}\n\t\t}\n\tcase 1289:\n\t\t{\n\t\t\ton := &ast.OnCondition{Expr: yyS[yypt-0].expr}\n\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-6].item.(ast.ResultSetNode), Right: yyS[yypt-2].item.(ast.ResultSetNode), Tp: yyS[yypt-5].item.(ast.JoinType), On: on}\n\t\t}\n\tcase 1290:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-8].item.(ast.ResultSetNode), Right: yyS[yypt-4].item.(ast.ResultSetNode), Tp: yyS[yypt-7].item.(ast.JoinType), Using: yyS[yypt-1].item.([]*ast.ColumnName)}\n\t\t}\n\tcase 1291:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-3].item.(ast.ResultSetNode), Right: yyS[yypt-0].item.(ast.ResultSetNode), NaturalJoin: true}\n\t\t}\n\tcase 1292:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-5].item.(ast.ResultSetNode), Right: yyS[yypt-0].item.(ast.ResultSetNode), Tp: yyS[yypt-3].item.(ast.JoinType), NaturalJoin: true}\n\t\t}\n\tcase 1293:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-2].item.(ast.ResultSetNode), Right: yyS[yypt-0].item.(ast.ResultSetNode), StraightJoin: true}\n\t\t}\n\tcase 1294:\n\t\t{\n\t\t\ton := &ast.OnCondition{Expr: yyS[yypt-0].expr}\n\t\t\tparser.yyVAL.item = &ast.Join{Left: yyS[yypt-4].item.(ast.ResultSetNode), Right: yyS[yypt-2].item.(ast.ResultSetNode), StraightJoin: true, On: on}\n\t\t}\n\tcase 1295:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.LeftJoin\n\t\t}\n\tcase 1296:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.RightJoin\n\t\t}\n\tcase 1302:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1303:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Limit{Count: yyS[yypt-0].item.(ast.ValueExpr)}\n\t\t}\n\tcase 1304:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.NewValueExpr(yyS[yypt-0].item)\n\t\t}\n\tcase 1305:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].expr\n\t\t}\n\tcase 1306:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1307:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Limit{Count: yyS[yypt-0].item.(ast.ExprNode)}\n\t\t}\n\tcase 1308:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Limit{Offset: yyS[yypt-2].item.(ast.ExprNode), Count: yyS[yypt-0].item.(ast.ExprNode)}\n\t\t}\n\tcase 1309:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Limit{Offset: yyS[yypt-0].item.(ast.ExprNode), Count: yyS[yypt-2].item.(ast.ExprNode)}\n\t\t}\n\tcase 1310:\n\t\t{\n\t\t\topt := &ast.SelectStmtOpts{}\n\t\t\tif yyS[yypt-8].item != nil {\n\t\t\t\topt.TableHints = yyS[yypt-8].item.([]*ast.TableOptimizerHint)\n\t\t\t}\n\t\t\tif yyS[yypt-7].item != nil {\n\t\t\t\topt.Distinct = yyS[yypt-7].item.(bool)\n\t\t\t}\n\t\t\tif yyS[yypt-6].item != nil {\n\t\t\t\topt.Priority = yyS[yypt-6].item.(mysql.PriorityEnum)\n\t\t\t}\n\t\t\tif yyS[yypt-5].item != nil {\n\t\t\t\topt.SQLSmallResult = yyS[yypt-5].item.(bool)\n\t\t\t}\n\t\t\tif yyS[yypt-4].item != nil {\n\t\t\t\topt.SQLBigResult = yyS[yypt-4].item.(bool)\n\t\t\t}\n\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\topt.SQLBufferResult = yyS[yypt-3].item.(bool)\n\t\t\t}\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\topt.SQLCache = yyS[yypt-2].item.(bool)\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\topt.CalcFoundRows = yyS[yypt-1].item.(bool)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\topt.StraightJoin = yyS[yypt-0].item.(bool)\n\t\t\t}\n\n\t\t\tparser.yyVAL.item = opt\n\t\t}\n\tcase 1311:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1312:\n\t\t{\n\t\t\thints, warns := parser.parseHint(yyS[yypt-0].ident)\n\t\t\tfor _, w := range warns {\n\t\t\t\tyylex.AppendError(w)\n\t\t\t\tparser.lastErrorAsWarn()\n\t\t\t}\n\t\t\tparser.yyVAL.item = hints\n\t\t}\n\tcase 1313:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1314:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1315:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1316:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1317:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1318:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1319:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1320:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1321:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1322:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1323:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1324:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1325:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1326:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FieldList{Fields: yyS[yypt-0].item.([]*ast.SelectField)}\n\t\t}\n\tcase 1327:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1329:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1330:\n\t\t{\n\t\t\tpartyFiles := []*ast.PartyFile{}\n\t\t\tpartyFile := &ast.PartyFile{\n\t\t\t\tFileName: yyS[yypt-2].ident,\n\t\t\t}\n\t\t\tx := &ast.SelectIntoOption{\n\t\t\t\tTp:         ast.SelectIntoOutfile,\n\t\t\t\tPartyFiles: append(partyFiles, partyFile),\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tx.FieldsInfo = yyS[yypt-1].item.(*ast.FieldsClause)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tx.LinesInfo = yyS[yypt-0].item.(*ast.LinesClause)\n\t\t\t}\n\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1331:\n\t\t{\n\t\t\tx := &ast.SelectIntoOption{\n\t\t\t\tTp:         ast.SelectIntoOutfile,\n\t\t\t\tPartyFiles: yyS[yypt-2].item.([]*ast.PartyFile),\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tx.FieldsInfo = yyS[yypt-1].item.(*ast.FieldsClause)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tx.LinesInfo = yyS[yypt-0].item.(*ast.LinesClause)\n\t\t\t}\n\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1332:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.SelectField{}\n\t\t}\n\tcase 1333:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item.([]*ast.SelectField)\n\t\t}\n\tcase 1334:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PartyFile{\n\t\t\t\tPartyCode: yyS[yypt-2].ident,\n\t\t\t\tFileName:  yyS[yypt-1].ident,\n\t\t\t\tFieldList: yyS[yypt-0].item.([]*ast.SelectField),\n\t\t\t}\n\t\t}\n\tcase 1335:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.PartyFile{yyS[yypt-0].item.(*ast.PartyFile)}\n\t\t}\n\tcase 1336:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-1].item.([]*ast.PartyFile), yyS[yypt-0].item.(*ast.PartyFile))\n\t\t}\n\tcase 1337:\n\t\t{\n\t\t\ts := yyS[yypt-1].statement.(*ast.SelectStmt)\n\t\t\tendOffset := parser.endOffset(&yyS[yypt])\n\t\t\tparser.setLastSelectFieldText(s, endOffset)\n\t\t\tsrc := parser.src\n\t\t\t// See the implementation of yyParse function\n\t\t\ts.SetText(src[yyS[yypt-1].offset:yyS[yypt].offset])\n\t\t\tparser.yyVAL.expr = &ast.SubqueryExpr{Query: s}\n\t\t}\n\tcase 1338:\n\t\t{\n\t\t\ts := yyS[yypt-1].statement.(*ast.UnionStmt)\n\t\t\tsrc := parser.src\n\t\t\t// See the implementation of yyParse function\n\t\t\ts.SetText(src[yyS[yypt-1].offset:yyS[yypt].offset])\n\t\t\tparser.yyVAL.expr = &ast.SubqueryExpr{Query: s}\n\t\t}\n\tcase 1339:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.SelectLockNone\n\t\t}\n\tcase 1340:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.SelectLockForUpdate\n\t\t}\n\tcase 1341:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.SelectLockForUpdateNoWait\n\t\t}\n\tcase 1342:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.SelectLockInShareMode\n\t\t}\n\tcase 1343:\n\t\t{\n\t\t\tst := yyS[yypt-3].item.(*ast.SelectStmt)\n\t\t\tunion := yyS[yypt-6].item.(*ast.UnionStmt)\n\t\t\tst.IsAfterUnionDistinct = yyS[yypt-4].item.(bool)\n\t\t\tlastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]\n\t\t\tendOffset := parser.endOffset(&yyS[yypt-5])\n\t\t\tparser.setLastSelectFieldText(lastSelect, endOffset)\n\t\t\tunion.SelectList.Selects = append(union.SelectList.Selects, st)\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tunion.OrderBy = yyS[yypt-2].item.(*ast.OrderByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tunion.Limit = yyS[yypt-1].item.(*ast.Limit)\n\t\t\t}\n\t\t\tif yyS[yypt-2].item == nil && yyS[yypt-1].item == nil {\n\t\t\t\tst.LockTp = yyS[yypt-0].item.(ast.SelectLockType)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = union\n\t\t}\n\tcase 1344:\n\t\t{\n\t\t\tst := yyS[yypt-3].item.(*ast.SelectStmt)\n\t\t\tunion := yyS[yypt-6].item.(*ast.UnionStmt)\n\t\t\tst.IsAfterUnionDistinct = yyS[yypt-4].item.(bool)\n\t\t\tlastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]\n\t\t\tendOffset := parser.endOffset(&yyS[yypt-5])\n\t\t\tparser.setLastSelectFieldText(lastSelect, endOffset)\n\t\t\tunion.SelectList.Selects = append(union.SelectList.Selects, st)\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tunion.OrderBy = yyS[yypt-2].item.(*ast.OrderByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tunion.Limit = yyS[yypt-1].item.(*ast.Limit)\n\t\t\t}\n\t\t\tif yyS[yypt-2].item == nil && yyS[yypt-1].item == nil {\n\t\t\t\tst.LockTp = yyS[yypt-0].item.(ast.SelectLockType)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = union\n\t\t}\n\tcase 1345:\n\t\t{\n\t\t\tst := yyS[yypt-3].item.(*ast.SelectStmt)\n\t\t\tunion := yyS[yypt-6].item.(*ast.UnionStmt)\n\t\t\tst.IsAfterUnionDistinct = yyS[yypt-4].item.(bool)\n\t\t\tlastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]\n\t\t\tendOffset := parser.endOffset(&yyS[yypt-5])\n\t\t\tparser.setLastSelectFieldText(lastSelect, endOffset)\n\t\t\tunion.SelectList.Selects = append(union.SelectList.Selects, st)\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tunion.OrderBy = yyS[yypt-2].item.(*ast.OrderByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tunion.Limit = yyS[yypt-1].item.(*ast.Limit)\n\t\t\t}\n\t\t\tif yyS[yypt-2].item == nil && yyS[yypt-1].item == nil {\n\t\t\t\tst.LockTp = yyS[yypt-0].item.(ast.SelectLockType)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = union\n\t\t}\n\tcase 1346:\n\t\t{\n\t\t\tunion := yyS[yypt-7].item.(*ast.UnionStmt)\n\t\t\tlastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]\n\t\t\tendOffset := parser.endOffset(&yyS[yypt-6])\n\t\t\tparser.setLastSelectFieldText(lastSelect, endOffset)\n\t\t\tst := yyS[yypt-3].statement.(*ast.SelectStmt)\n\t\t\tst.IsInBraces = true\n\t\t\tst.IsAfterUnionDistinct = yyS[yypt-5].item.(bool)\n\t\t\tendOffset = parser.endOffset(&yyS[yypt-2])\n\t\t\tparser.setLastSelectFieldText(st, endOffset)\n\t\t\tunion.SelectList.Selects = append(union.SelectList.Selects, st)\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tunion.OrderBy = yyS[yypt-1].item.(*ast.OrderByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tunion.Limit = yyS[yypt-0].item.(*ast.Limit)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = union\n\t\t}\n\tcase 1347:\n\t\t{\n\t\t\tselectList := &ast.UnionSelectList{Selects: []*ast.SelectStmt{yyS[yypt-0].item.(*ast.SelectStmt)}}\n\t\t\tparser.yyVAL.item = &ast.UnionStmt{\n\t\t\t\tSelectList: selectList,\n\t\t\t}\n\t\t}\n\tcase 1348:\n\t\t{\n\t\t\tunion := yyS[yypt-3].item.(*ast.UnionStmt)\n\t\t\tst := yyS[yypt-0].item.(*ast.SelectStmt)\n\t\t\tst.IsAfterUnionDistinct = yyS[yypt-1].item.(bool)\n\t\t\tlastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]\n\t\t\tendOffset := parser.endOffset(&yyS[yypt-2])\n\t\t\tparser.setLastSelectFieldText(lastSelect, endOffset)\n\t\t\tunion.SelectList.Selects = append(union.SelectList.Selects, st)\n\t\t\tparser.yyVAL.item = union\n\t\t}\n\tcase 1349:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].statement.(interface{})\n\t\t}\n\tcase 1350:\n\t\t{\n\t\t\tst := yyS[yypt-1].statement.(*ast.SelectStmt)\n\t\t\tst.IsInBraces = true\n\t\t\tendOffset := parser.endOffset(&yyS[yypt])\n\t\t\tparser.setLastSelectFieldText(st, endOffset)\n\t\t\tparser.yyVAL.item = yyS[yypt-1].statement\n\t\t}\n\tcase 1352:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ChangeStmt{\n\t\t\t\tNodeType: ast.PumpType,\n\t\t\t\tState:    yyS[yypt-3].ident,\n\t\t\t\tNodeID:   yyS[yypt-0].ident,\n\t\t\t}\n\t\t}\n\tcase 1353:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ChangeStmt{\n\t\t\t\tNodeType: ast.DrainerType,\n\t\t\t\tState:    yyS[yypt-3].ident,\n\t\t\t\tNodeID:   yyS[yypt-0].ident,\n\t\t\t}\n\t\t}\n\tcase 1354:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.SetStmt{Variables: yyS[yypt-0].item.([]*ast.VariableAssignment)}\n\t\t}\n\tcase 1355:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.SetPwdStmt{Password: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 1356:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.SetPwdStmt{User: yyS[yypt-2].item.(*auth.UserIdentity), Password: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 1357:\n\t\t{\n\t\t\tvars := yyS[yypt-0].item.([]*ast.VariableAssignment)\n\t\t\tfor _, v := range vars {\n\t\t\t\tv.IsGlobal = true\n\t\t\t}\n\t\t\tparser.yyVAL.statement = &ast.SetStmt{Variables: vars}\n\t\t}\n\tcase 1358:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.SetStmt{Variables: yyS[yypt-0].item.([]*ast.VariableAssignment)}\n\t\t}\n\tcase 1359:\n\t\t{\n\t\t\tassigns := yyS[yypt-0].item.([]*ast.VariableAssignment)\n\t\t\tfor i := 0; i < len(assigns); i++ {\n\t\t\t\tif assigns[i].Name == \"tx_isolation\" {\n\t\t\t\t\t// A special session variable that make setting tx_isolation take effect one time.\n\t\t\t\t\tassigns[i].Name = \"tx_isolation_one_shot\"\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.statement = &ast.SetStmt{Variables: assigns}\n\t\t}\n\tcase 1360:\n\t\t{\n\t\t\tparser.yyVAL.statement = yyS[yypt-0].item.(*ast.SetRoleStmt)\n\t\t}\n\tcase 1361:\n\t\t{\n\t\t\ttmp := yyS[yypt-2].item.(*ast.SetRoleStmt)\n\t\t\tparser.yyVAL.statement = &ast.SetDefaultRoleStmt{\n\t\t\t\tSetRoleOpt: tmp.SetRoleOpt,\n\t\t\t\tRoleList:   tmp.RoleList,\n\t\t\t\tUserList:   yyS[yypt-0].item.([]*auth.UserIdentity),\n\t\t\t}\n\t\t}\n\tcase 1362:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SetRoleStmt{SetRoleOpt: ast.SetRoleNone, RoleList: nil}\n\t\t}\n\tcase 1363:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SetRoleStmt{SetRoleOpt: ast.SetRoleAll, RoleList: nil}\n\t\t}\n\tcase 1364:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SetRoleStmt{SetRoleOpt: ast.SetRoleRegular, RoleList: yyS[yypt-0].item.([]*auth.RoleIdentity)}\n\t\t}\n\tcase 1365:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SetRoleStmt{SetRoleOpt: ast.SetRoleAllExcept, RoleList: yyS[yypt-0].item.([]*auth.RoleIdentity)}\n\t\t}\n\tcase 1366:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1367:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SetRoleStmt{SetRoleOpt: ast.SetRoleDefault, RoleList: nil}\n\t\t}\n\tcase 1368:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.item = []*ast.VariableAssignment{}\n\t\t\t}\n\t\t}\n\tcase 1369:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tvarAssigns := yyS[yypt-0].item.([]*ast.VariableAssignment)\n\t\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.VariableAssignment), varAssigns...)\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.item = yyS[yypt-2].item\n\t\t\t}\n\t\t}\n\tcase 1370:\n\t\t{\n\t\t\tvarAssigns := []*ast.VariableAssignment{}\n\t\t\texpr := ast.NewValueExpr(yyS[yypt-0].ident)\n\t\t\tvarAssigns = append(varAssigns, &ast.VariableAssignment{Name: \"tx_isolation\", Value: expr, IsSystem: true})\n\t\t\tparser.yyVAL.item = varAssigns\n\t\t}\n\tcase 1371:\n\t\t{\n\t\t\tvarAssigns := []*ast.VariableAssignment{}\n\t\t\texpr := ast.NewValueExpr(\"0\")\n\t\t\tvarAssigns = append(varAssigns, &ast.VariableAssignment{Name: \"tx_read_only\", Value: expr, IsSystem: true})\n\t\t\tparser.yyVAL.item = varAssigns\n\t\t}\n\tcase 1372:\n\t\t{\n\t\t\tvarAssigns := []*ast.VariableAssignment{}\n\t\t\texpr := ast.NewValueExpr(\"1\")\n\t\t\tvarAssigns = append(varAssigns, &ast.VariableAssignment{Name: \"tx_read_only\", Value: expr, IsSystem: true})\n\t\t\tparser.yyVAL.item = varAssigns\n\t\t}\n\tcase 1373:\n\t\t{\n\t\t\tparser.yyVAL.ident = ast.RepeatableRead\n\t\t}\n\tcase 1374:\n\t\t{\n\t\t\tparser.yyVAL.ident = ast.ReadCommitted\n\t\t}\n\tcase 1375:\n\t\t{\n\t\t\tparser.yyVAL.ident = ast.ReadUncommitted\n\t\t}\n\tcase 1376:\n\t\t{\n\t\t\tparser.yyVAL.ident = ast.Serializable\n\t\t}\n\tcase 1377:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(\"ON\")\n\t\t}\n\tcase 1382:\n\t\t{\n\t\t\tparser.yyVAL.ident = yyS[yypt-2].ident + \".\" + yyS[yypt-0].ident\n\t\t}\n\tcase 1383:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{Name: yyS[yypt-2].ident, Value: yyS[yypt-0].expr, IsSystem: true}\n\t\t}\n\tcase 1384:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{Name: yyS[yypt-2].ident, Value: yyS[yypt-0].expr, IsGlobal: true, IsSystem: true}\n\t\t}\n\tcase 1385:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{Name: yyS[yypt-2].ident, Value: yyS[yypt-0].expr, IsSystem: true}\n\t\t}\n\tcase 1386:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{Name: yyS[yypt-2].ident, Value: yyS[yypt-0].expr, IsSystem: true}\n\t\t}\n\tcase 1387:\n\t\t{\n\t\t\tv := strings.ToLower(yyS[yypt-2].ident)\n\t\t\tvar isGlobal bool\n\t\t\tif strings.HasPrefix(v, \"@@global.\") {\n\t\t\t\tisGlobal = true\n\t\t\t\tv = strings.TrimPrefix(v, \"@@global.\")\n\t\t\t} else if strings.HasPrefix(v, \"@@session.\") {\n\t\t\t\tv = strings.TrimPrefix(v, \"@@session.\")\n\t\t\t} else if strings.HasPrefix(v, \"@@local.\") {\n\t\t\t\tv = strings.TrimPrefix(v, \"@@local.\")\n\t\t\t} else if strings.HasPrefix(v, \"@@\") {\n\t\t\t\tv = strings.TrimPrefix(v, \"@@\")\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{Name: v, Value: yyS[yypt-0].expr, IsGlobal: isGlobal, IsSystem: true}\n\t\t}\n\tcase 1388:\n\t\t{\n\t\t\tv := yyS[yypt-2].ident\n\t\t\tv = strings.TrimPrefix(v, \"@\")\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{Name: v, Value: yyS[yypt-0].expr}\n\t\t}\n\tcase 1389:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{\n\t\t\t\tName:  ast.SetNames,\n\t\t\t\tValue: ast.NewValueExpr(yyS[yypt-0].item.(string)),\n\t\t\t}\n\t\t}\n\tcase 1390:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{\n\t\t\t\tName:  ast.SetNames,\n\t\t\t\tValue: ast.NewValueExpr(yyS[yypt-2].item.(string)),\n\t\t\t}\n\t\t}\n\tcase 1391:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{\n\t\t\t\tName:        ast.SetNames,\n\t\t\t\tValue:       ast.NewValueExpr(yyS[yypt-2].item.(string)),\n\t\t\t\tExtendValue: ast.NewValueExpr(yyS[yypt-0].item.(string)),\n\t\t\t}\n\t\t}\n\tcase 1392:\n\t\t{\n\t\t\tv := &ast.DefaultExpr{}\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{Name: ast.SetNames, Value: v}\n\t\t}\n\tcase 1393:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.VariableAssignment{Name: ast.SetNames, Value: yyS[yypt-0].expr}\n\t\t}\n\tcase 1394:\n\t\t{\n\t\t\tparser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item.(string))\n\t\t}\n\tcase 1395:\n\t\t{\n\t\t\tparser.yyVAL.expr = &ast.DefaultExpr{}\n\t\t}\n\tcase 1396:\n\t\t{\n\t\t\t// Validate input charset name to keep the same behavior as parser of MySQL.\n\t\t\tname, _, err := charset.GetCharsetInfo(yyS[yypt-0].item.(string))\n\t\t\tif err != nil {\n\t\t\t\tyylex.AppendError(ErrUnknownCharacterSet.GenWithStackByArgs(yyS[yypt-0].item))\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\t// Use charset name returned from charset.GetCharsetInfo(),\n\t\t\t// to keep lower case of input for generated column restore.\n\t\t\tparser.yyVAL.item = name\n\t\t}\n\tcase 1397:\n\t\t{\n\t\t\tparser.yyVAL.item = charset.CharsetBin\n\t\t}\n\tcase 1398:\n\t\t{\n\t\t\tinfo, err := charset.GetCollationByName(yyS[yypt-0].item.(string))\n\t\t\tif err != nil {\n\t\t\t\tyylex.AppendError(err)\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = info.Name\n\t\t}\n\tcase 1399:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.VariableAssignment{}\n\t\t}\n\tcase 1400:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.VariableAssignment{yyS[yypt-0].item.(*ast.VariableAssignment)}\n\t\t}\n\tcase 1401:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.VariableAssignment), yyS[yypt-0].item.(*ast.VariableAssignment))\n\t\t}\n\tcase 1404:\n\t\t{\n\t\t\tv := strings.ToLower(yyS[yypt-0].ident)\n\t\t\tvar isGlobal bool\n\t\t\texplicitScope := true\n\t\t\tif strings.HasPrefix(v, \"@@global.\") {\n\t\t\t\tisGlobal = true\n\t\t\t\tv = strings.TrimPrefix(v, \"@@global.\")\n\t\t\t} else if strings.HasPrefix(v, \"@@session.\") {\n\t\t\t\tv = strings.TrimPrefix(v, \"@@session.\")\n\t\t\t} else if strings.HasPrefix(v, \"@@local.\") {\n\t\t\t\tv = strings.TrimPrefix(v, \"@@local.\")\n\t\t\t} else if strings.HasPrefix(v, \"@@\") {\n\t\t\t\tv, explicitScope = strings.TrimPrefix(v, \"@@\"), false\n\t\t\t}\n\t\t\tparser.yyVAL.expr = &ast.VariableExpr{Name: v, IsGlobal: isGlobal, IsSystem: true, ExplicitScope: explicitScope}\n\t\t}\n\tcase 1405:\n\t\t{\n\t\t\tv := yyS[yypt-0].ident\n\t\t\tv = strings.TrimPrefix(v, \"@\")\n\t\t\tparser.yyVAL.expr = &ast.VariableExpr{Name: v, IsGlobal: false, IsSystem: false}\n\t\t}\n\tcase 1406:\n\t\t{\n\t\t\tparser.yyVAL.item = &auth.UserIdentity{Username: yyS[yypt-0].item.(string), Hostname: \"%\"}\n\t\t}\n\tcase 1407:\n\t\t{\n\t\t\tparser.yyVAL.item = &auth.UserIdentity{Username: yyS[yypt-2].item.(string), Hostname: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 1408:\n\t\t{\n\t\t\tparser.yyVAL.item = &auth.UserIdentity{Username: yyS[yypt-1].item.(string), Hostname: strings.TrimPrefix(yyS[yypt-0].ident, \"@\")}\n\t\t}\n\tcase 1409:\n\t\t{\n\t\t\tparser.yyVAL.item = &auth.UserIdentity{CurrentUser: true}\n\t\t}\n\tcase 1410:\n\t\t{\n\t\t\tparser.yyVAL.item = []*auth.UserIdentity{yyS[yypt-0].item.(*auth.UserIdentity)}\n\t\t}\n\tcase 1411:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*auth.UserIdentity), yyS[yypt-0].item.(*auth.UserIdentity))\n\t\t}\n\tcase 1412:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1413:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-1].item.(string)\n\t\t}\n\tcase 1414:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1415:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1416:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1417:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1418:\n\t\t{\n\t\t\tparser.yyVAL.item = &auth.RoleIdentity{Username: yyS[yypt-0].item.(string), Hostname: \"%\"}\n\t\t}\n\tcase 1419:\n\t\t{\n\t\t\tparser.yyVAL.item = &auth.RoleIdentity{Username: yyS[yypt-2].item.(string), Hostname: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 1420:\n\t\t{\n\t\t\tparser.yyVAL.item = &auth.RoleIdentity{Username: yyS[yypt-1].item.(string), Hostname: strings.TrimPrefix(yyS[yypt-0].ident, \"@\")}\n\t\t}\n\tcase 1421:\n\t\t{\n\t\t\tparser.yyVAL.item = []*auth.RoleIdentity{yyS[yypt-0].item.(*auth.RoleIdentity)}\n\t\t}\n\tcase 1422:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*auth.RoleIdentity), yyS[yypt-0].item.(*auth.RoleIdentity))\n\t\t}\n\tcase 1423:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{Tp: ast.AdminShowDDL}\n\t\t}\n\tcase 1424:\n\t\t{\n\t\t\tstmt := &ast.AdminStmt{Tp: ast.AdminShowDDLJobs}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tstmt.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 1425:\n\t\t{\n\t\t\tstmt := &ast.AdminStmt{\n\t\t\t\tTp:        ast.AdminShowDDLJobs,\n\t\t\t\tJobNumber: yyS[yypt-1].item.(int64),\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tstmt.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 1426:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:     ast.AdminShowNextRowID,\n\t\t\t\tTables: []*ast.TableName{yyS[yypt-1].item.(*ast.TableName)},\n\t\t\t}\n\t\t}\n\tcase 1427:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:     ast.AdminCheckTable,\n\t\t\t\tTables: yyS[yypt-0].item.([]*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 1428:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:     ast.AdminCheckIndex,\n\t\t\t\tTables: []*ast.TableName{yyS[yypt-1].item.(*ast.TableName)},\n\t\t\t\tIndex:  string(yyS[yypt-0].ident),\n\t\t\t}\n\t\t}\n\tcase 1429:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:     ast.AdminRecoverIndex,\n\t\t\t\tTables: []*ast.TableName{yyS[yypt-1].item.(*ast.TableName)},\n\t\t\t\tIndex:  string(yyS[yypt-0].ident),\n\t\t\t}\n\t\t}\n\tcase 1430:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:     ast.AdminCleanupIndex,\n\t\t\t\tTables: []*ast.TableName{yyS[yypt-1].item.(*ast.TableName)},\n\t\t\t\tIndex:  string(yyS[yypt-0].ident),\n\t\t\t}\n\t\t}\n\tcase 1431:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:           ast.AdminCheckIndexRange,\n\t\t\t\tTables:       []*ast.TableName{yyS[yypt-2].item.(*ast.TableName)},\n\t\t\t\tIndex:        string(yyS[yypt-1].ident),\n\t\t\t\tHandleRanges: yyS[yypt-0].item.([]ast.HandleRange),\n\t\t\t}\n\t\t}\n\tcase 1432:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:     ast.AdminChecksumTable,\n\t\t\t\tTables: yyS[yypt-0].item.([]*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 1433:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:     ast.AdminCancelDDLJobs,\n\t\t\t\tJobIDs: yyS[yypt-0].item.([]int64),\n\t\t\t}\n\t\t}\n\tcase 1434:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:     ast.AdminShowDDLJobQueries,\n\t\t\t\tJobIDs: yyS[yypt-0].item.([]int64),\n\t\t\t}\n\t\t}\n\tcase 1435:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:       ast.AdminShowSlow,\n\t\t\t\tShowSlow: yyS[yypt-0].item.(*ast.ShowSlow),\n\t\t\t}\n\t\t}\n\tcase 1436:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp: ast.AdminReloadExprPushdownBlacklist,\n\t\t\t}\n\t\t}\n\tcase 1437:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp: ast.AdminReloadOptRuleBlacklist,\n\t\t\t}\n\t\t}\n\tcase 1438:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:      ast.AdminPluginEnable,\n\t\t\t\tPlugins: yyS[yypt-0].item.([]string),\n\t\t\t}\n\t\t}\n\tcase 1439:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp:      ast.AdminPluginDisable,\n\t\t\t\tPlugins: yyS[yypt-0].item.([]string),\n\t\t\t}\n\t\t}\n\tcase 1440:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.CleanupTableLockStmt{\n\t\t\t\tTables: yyS[yypt-0].item.([]*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 1441:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.RepairTableStmt{\n\t\t\t\tTable:      yyS[yypt-1].item.(*ast.TableName),\n\t\t\t\tCreateStmt: yyS[yypt-0].statement.(*ast.CreateTableStmt),\n\t\t\t}\n\t\t}\n\tcase 1442:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp: ast.AdminFlushBindings,\n\t\t\t}\n\t\t}\n\tcase 1443:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp: ast.AdminCaptureBindings,\n\t\t\t}\n\t\t}\n\tcase 1444:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AdminStmt{\n\t\t\t\tTp: ast.AdminEvolveBindings,\n\t\t\t}\n\t\t}\n\tcase 1445:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowSlow{\n\t\t\t\tTp:    ast.ShowSlowRecent,\n\t\t\t\tCount: getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t}\n\t\t}\n\tcase 1446:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowSlow{\n\t\t\t\tTp:    ast.ShowSlowTop,\n\t\t\t\tKind:  ast.ShowSlowKindDefault,\n\t\t\t\tCount: getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t}\n\t\t}\n\tcase 1447:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowSlow{\n\t\t\t\tTp:    ast.ShowSlowTop,\n\t\t\t\tKind:  ast.ShowSlowKindInternal,\n\t\t\t\tCount: getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t}\n\t\t}\n\tcase 1448:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowSlow{\n\t\t\t\tTp:    ast.ShowSlowTop,\n\t\t\t\tKind:  ast.ShowSlowKindAll,\n\t\t\t\tCount: getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t}\n\t\t}\n\tcase 1449:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.HandleRange{yyS[yypt-0].item.(ast.HandleRange)}\n\t\t}\n\tcase 1450:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]ast.HandleRange), yyS[yypt-0].item.(ast.HandleRange))\n\t\t}\n\tcase 1451:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.HandleRange{Begin: yyS[yypt-3].item.(int64), End: yyS[yypt-1].item.(int64)}\n\t\t}\n\tcase 1452:\n\t\t{\n\t\t\tparser.yyVAL.item = []int64{yyS[yypt-0].item.(int64)}\n\t\t}\n\tcase 1453:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]int64), yyS[yypt-0].item.(int64))\n\t\t}\n\tcase 1454:\n\t\t{\n\t\t\tstmt := yyS[yypt-1].item.(*ast.ShowStmt)\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tif x, ok := yyS[yypt-0].item.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\t\tstmt.Pattern = x\n\t\t\t\t} else {\n\t\t\t\t\tstmt.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 1455:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp:    ast.ShowCreateTable,\n\t\t\t\tTable: yyS[yypt-0].item.(*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 1456:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp:    ast.ShowCreateView,\n\t\t\t\tTable: yyS[yypt-0].item.(*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 1457:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp:          ast.ShowCreateDatabase,\n\t\t\t\tIfNotExists: yyS[yypt-1].item.(bool),\n\t\t\t\tDBName:      yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1458:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp:    ast.ShowCreateSequence,\n\t\t\t\tTable: yyS[yypt-0].item.(*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 1459:\n\t\t{\n\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/show-create-user.html\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp:   ast.ShowCreateUser,\n\t\t\t\tUser: yyS[yypt-0].item.(*auth.UserIdentity),\n\t\t\t}\n\t\t}\n\tcase 1460:\n\t\t{\n\t\t\tstmt := &ast.ShowStmt{\n\t\t\t\tTp:    ast.ShowRegions,\n\t\t\t\tTable: yyS[yypt-2].item.(*ast.TableName),\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tstmt.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 1461:\n\t\t{\n\t\t\tstmt := &ast.ShowStmt{\n\t\t\t\tTp:        ast.ShowRegions,\n\t\t\t\tTable:     yyS[yypt-4].item.(*ast.TableName),\n\t\t\t\tIndexName: model.NewCIStr(yyS[yypt-2].ident),\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tstmt.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 1462:\n\t\t{\n\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/show-grants.html\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp:     ast.ShowGrants,\n\t\t\t\tDBName: yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1463:\n\t\t{\n\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/show-grants.html\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\t\tTp:     ast.ShowGrants,\n\t\t\t\t\tDBName: yyS[yypt-3].item.(string),\n\t\t\t\t\tUser:   yyS[yypt-1].item.(*auth.UserIdentity),\n\t\t\t\t\tRoles:  yyS[yypt-0].item.([]*auth.RoleIdentity),\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\t\tTp:     ast.ShowGrants,\n\t\t\t\t\tDBName: yyS[yypt-3].item.(string),\n\t\t\t\t\tUser:   yyS[yypt-1].item.(*auth.UserIdentity),\n\t\t\t\t\tRoles:  nil,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase 1464:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowMasterStatus,\n\t\t\t}\n\t\t}\n\tcase 1465:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp:   ast.ShowProcessList,\n\t\t\t\tFull: yyS[yypt-1].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1466:\n\t\t{\n\t\t\tstmt := &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowStatsMeta,\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tif x, ok := yyS[yypt-0].item.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\t\tstmt.Pattern = x\n\t\t\t\t} else {\n\t\t\t\t\tstmt.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 1467:\n\t\t{\n\t\t\tstmt := &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowStatsHistograms,\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tif x, ok := yyS[yypt-0].item.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\t\tstmt.Pattern = x\n\t\t\t\t} else {\n\t\t\t\t\tstmt.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 1468:\n\t\t{\n\t\t\tstmt := &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowStatsBuckets,\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tif x, ok := yyS[yypt-0].item.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\t\tstmt.Pattern = x\n\t\t\t\t} else {\n\t\t\t\t\tstmt.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 1469:\n\t\t{\n\t\t\tstmt := &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowStatsHealthy,\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tif x, ok := yyS[yypt-0].item.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\t\tstmt.Pattern = x\n\t\t\t\t} else {\n\t\t\t\t\tstmt.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 1470:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowProfiles,\n\t\t\t}\n\t\t}\n\tcase 1471:\n\t\t{\n\t\t\tv := &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowProfile,\n\t\t\t}\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tv.ShowProfileTypes = yyS[yypt-2].item.([]int)\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tv.ShowProfileArgs = yyS[yypt-1].item.(*int64)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tv.ShowProfileLimit = yyS[yypt-0].item.(*ast.Limit)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = v\n\t\t}\n\tcase 1472:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowPrivileges,\n\t\t\t}\n\t\t}\n\tcase 1473:\n\t\t{\n\t\t\tstmt := &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowAnalyzeStatus,\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tif x, ok := yyS[yypt-0].item.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\t\tstmt.Pattern = x\n\t\t\t\t} else {\n\t\t\t\t\tstmt.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.statement = stmt\n\t\t}\n\tcase 1474:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowBuiltins,\n\t\t\t}\n\t\t}\n\tcase 1475:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1476:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1477:\n\t\t{\n\t\t\tparser.yyVAL.item = []int{yyS[yypt-0].item.(int)}\n\t\t}\n\tcase 1478:\n\t\t{\n\t\t\tl := yyS[yypt-2].item.([]int)\n\t\t\tl = append(l, yyS[yypt-0].item.(int))\n\t\t\tparser.yyVAL.item = l\n\t\t}\n\tcase 1479:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ProfileTypeCPU\n\t\t}\n\tcase 1480:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ProfileTypeMemory\n\t\t}\n\tcase 1481:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ProfileTypeBlockIo\n\t\t}\n\tcase 1482:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ProfileTypeContextSwitch\n\t\t}\n\tcase 1483:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ProfileTypePageFaults\n\t\t}\n\tcase 1484:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ProfileTypeIpc\n\t\t}\n\tcase 1485:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ProfileTypeSwaps\n\t\t}\n\tcase 1486:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ProfileTypeSource\n\t\t}\n\tcase 1487:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ProfileTypeAll\n\t\t}\n\tcase 1488:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1489:\n\t\t{\n\t\t\tv := yyS[yypt-0].item.(int64)\n\t\t\tparser.yyVAL.item = &v\n\t\t}\n\tcase 1490:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1491:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.([]*auth.RoleIdentity)\n\t\t}\n\tcase 1497:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowEngines}\n\t\t}\n\tcase 1498:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowDatabases}\n\t\t}\n\tcase 1499:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowCharset}\n\t\t}\n\tcase 1500:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:     ast.ShowTables,\n\t\t\t\tDBName: yyS[yypt-0].item.(string),\n\t\t\t\tFull:   yyS[yypt-2].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1501:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:     ast.ShowOpenTables,\n\t\t\t\tDBName: yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1502:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:     ast.ShowTableStatus,\n\t\t\t\tDBName: yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1503:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:    ast.ShowIndex,\n\t\t\t\tTable: yyS[yypt-0].item.(*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 1504:\n\t\t{\n\t\t\tshow := &ast.ShowStmt{\n\t\t\t\tTp:    ast.ShowIndex,\n\t\t\t\tTable: &ast.TableName{Name: model.NewCIStr(yyS[yypt-2].ident), Schema: model.NewCIStr(yyS[yypt-0].ident)},\n\t\t\t}\n\t\t\tparser.yyVAL.item = show\n\t\t}\n\tcase 1505:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:     ast.ShowColumns,\n\t\t\t\tTable:  yyS[yypt-1].item.(*ast.TableName),\n\t\t\t\tDBName: yyS[yypt-0].item.(string),\n\t\t\t\tFull:   yyS[yypt-3].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1506:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:       ast.ShowColumns,\n\t\t\t\tTable:    yyS[yypt-1].item.(*ast.TableName),\n\t\t\t\tDBName:   yyS[yypt-0].item.(string),\n\t\t\t\tFull:     yyS[yypt-3].item.(bool),\n\t\t\t\tExtended: true,\n\t\t\t}\n\t\t}\n\tcase 1507:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowWarnings}\n\t\t}\n\tcase 1508:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowErrors}\n\t\t}\n\tcase 1509:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:          ast.ShowVariables,\n\t\t\t\tGlobalScope: yyS[yypt-1].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1510:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:          ast.ShowStatus,\n\t\t\t\tGlobalScope: yyS[yypt-1].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1511:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:          ast.ShowBindings,\n\t\t\t\tGlobalScope: yyS[yypt-1].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1512:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowCollation,\n\t\t\t}\n\t\t}\n\tcase 1513:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:     ast.ShowTriggers,\n\t\t\t\tDBName: yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1514:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowProcedureStatus,\n\t\t\t}\n\t\t}\n\tcase 1515:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowPumpStatus,\n\t\t\t}\n\t\t}\n\tcase 1516:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowDrainerStatus,\n\t\t\t}\n\t\t}\n\tcase 1517:\n\t\t{\n\t\t\t// This statement is similar to SHOW PROCEDURE STATUS but for stored functions.\n\t\t\t// See http://dev.mysql.com/doc/refman/5.7/en/show-function-status.html\n\t\t\t// We do not support neither stored functions nor stored procedures.\n\t\t\t// So we reuse show procedure status process logic.\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowProcedureStatus,\n\t\t\t}\n\t\t}\n\tcase 1518:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp:     ast.ShowEvents,\n\t\t\t\tDBName: yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1519:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ShowStmt{\n\t\t\t\tTp: ast.ShowPlugins,\n\t\t\t}\n\t\t}\n\tcase 1520:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1521:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PatternLikeExpr{\n\t\t\t\tPattern: yyS[yypt-0].expr,\n\t\t\t\tEscape:  '\\\\',\n\t\t\t}\n\t\t}\n\tcase 1522:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].expr\n\t\t}\n\tcase 1523:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1524:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1525:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1526:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1527:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1528:\n\t\t{\n\t\t\tparser.yyVAL.item = \"\"\n\t\t}\n\tcase 1529:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(string)\n\t\t}\n\tcase 1530:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(*ast.TableName)\n\t\t}\n\tcase 1531:\n\t\t{\n\t\t\ttmp := yyS[yypt-0].item.(*ast.FlushStmt)\n\t\t\ttmp.NoWriteToBinLog = yyS[yypt-1].item.(bool)\n\t\t\tparser.yyVAL.statement = tmp\n\t\t}\n\tcase 1532:\n\t\t{\n\t\t\tparser.yyVAL.item = []string{yyS[yypt-0].ident}\n\t\t}\n\tcase 1533:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]string), yyS[yypt-0].ident)\n\t\t}\n\tcase 1534:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FlushStmt{\n\t\t\t\tTp: ast.FlushPrivileges,\n\t\t\t}\n\t\t}\n\tcase 1535:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FlushStmt{\n\t\t\t\tTp: ast.FlushStatus,\n\t\t\t}\n\t\t}\n\tcase 1536:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FlushStmt{\n\t\t\t\tTp:      ast.FlushTiDBPlugin,\n\t\t\t\tPlugins: yyS[yypt-0].item.([]string),\n\t\t\t}\n\t\t}\n\tcase 1537:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FlushStmt{\n\t\t\t\tTp: ast.FlushHosts,\n\t\t\t}\n\t\t}\n\tcase 1538:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FlushStmt{\n\t\t\t\tTp:      ast.FlushLogs,\n\t\t\t\tLogType: yyS[yypt-1].item.(ast.LogType),\n\t\t\t}\n\t\t}\n\tcase 1539:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FlushStmt{\n\t\t\t\tTp:       ast.FlushTables,\n\t\t\t\tTables:   yyS[yypt-1].item.([]*ast.TableName),\n\t\t\t\tReadLock: yyS[yypt-0].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1540:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.LogTypeDefault\n\t\t}\n\tcase 1541:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.LogTypeBinary\n\t\t}\n\tcase 1542:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.LogTypeEngine\n\t\t}\n\tcase 1543:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.LogTypeError\n\t\t}\n\tcase 1544:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.LogTypeGeneral\n\t\t}\n\tcase 1545:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.LogTypeSlow\n\t\t}\n\tcase 1546:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1547:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1548:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1549:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.TableName{}\n\t\t}\n\tcase 1550:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1551:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1552:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1608:\n\t\t{\n\t\t\t// `(select 1)`; is a valid select statement\n\t\t\t// TODO: This is used to fix issue #320. There may be a better solution.\n\t\t\tparser.yyVAL.statement = yyS[yypt-0].expr.(*ast.SubqueryExpr).Query.(ast.StmtNode)\n\t\t}\n\tcase 1633:\n\t\t{\n\t\t\tif yyS[yypt-0].statement != nil {\n\t\t\t\ts := yyS[yypt-0].statement\n\t\t\t\tif lexer, ok := yylex.(stmtTexter); ok {\n\t\t\t\t\ts.SetText(lexer.stmtText())\n\t\t\t\t}\n\t\t\t\tparser.result = append(parser.result, s)\n\t\t\t}\n\t\t}\n\tcase 1634:\n\t\t{\n\t\t\tif yyS[yypt-0].statement != nil {\n\t\t\t\ts := yyS[yypt-0].statement\n\t\t\t\tif lexer, ok := yylex.(stmtTexter); ok {\n\t\t\t\t\ts.SetText(lexer.stmtText())\n\t\t\t\t}\n\t\t\t\tparser.result = append(parser.result, s)\n\t\t\t}\n\t\t}\n\tcase 1635:\n\t\t{\n\t\t\tcst := yyS[yypt-0].item.(*ast.Constraint)\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tcst.Name = yyS[yypt-1].item.(string)\n\t\t\t}\n\t\t\tparser.yyVAL.item = cst\n\t\t}\n\tcase 1636:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(*ast.ColumnDef)\n\t\t}\n\tcase 1637:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.item = []interface{}{yyS[yypt-0].item.(interface{})}\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.item = []interface{}{}\n\t\t\t}\n\t\t}\n\tcase 1638:\n\t\t{\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]interface{}), yyS[yypt-0].item)\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.item = yyS[yypt-2].item\n\t\t\t}\n\t\t}\n\tcase 1639:\n\t\t{\n\t\t\tvar columnDefs []*ast.ColumnDef\n\t\t\tvar constraints []*ast.Constraint\n\t\t\tparser.yyVAL.item = &ast.CreateTableStmt{\n\t\t\t\tCols:        columnDefs,\n\t\t\t\tConstraints: constraints,\n\t\t\t}\n\t\t}\n\tcase 1640:\n\t\t{\n\t\t\ttes := yyS[yypt-1].item.([]interface{})\n\t\t\tvar columnDefs []*ast.ColumnDef\n\t\t\tvar constraints []*ast.Constraint\n\t\t\tfor _, te := range tes {\n\t\t\t\tswitch te := te.(type) {\n\t\t\t\tcase *ast.ColumnDef:\n\t\t\t\t\tcolumnDefs = append(columnDefs, te)\n\t\t\t\tcase *ast.Constraint:\n\t\t\t\t\tconstraints = append(constraints, te)\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.CreateTableStmt{\n\t\t\t\tCols:        columnDefs,\n\t\t\t\tConstraints: constraints,\n\t\t\t}\n\t\t}\n\tcase 1641:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1642:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionCharset, StrValue: yyS[yypt-0].item.(string),\n\t\t\t\tUintValue: ast.TableOptionCharsetWithoutConvertTo}\n\t\t}\n\tcase 1643:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionCollate, StrValue: yyS[yypt-0].item.(string),\n\t\t\t\tUintValue: ast.TableOptionCharsetWithoutConvertTo}\n\t\t}\n\tcase 1644:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionAutoIncrement, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 1645:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionAvgRowLength, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 1646:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionConnection, StrValue: yyS[yypt-0].ident}\n\t\t}\n\tcase 1647:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionCheckSum, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 1648:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionTableCheckSum, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 1649:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionPassword, StrValue: yyS[yypt-0].ident}\n\t\t}\n\tcase 1650:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionCompression, StrValue: yyS[yypt-0].ident}\n\t\t}\n\tcase 1651:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionKeyBlockSize, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 1652:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionDelayKeyWrite, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 1653:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionRowFormat, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 1654:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionStatsPersistent}\n\t\t}\n\tcase 1655:\n\t\t{\n\t\t\tn := yyS[yypt-0].item.(uint64)\n\t\t\tif n != 0 && n != 1 {\n\t\t\t\tyylex.AppendError(yylex.Errorf(\"The value of STATS_AUTO_RECALC must be one of [0|1|DEFAULT].\"))\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionStatsAutoRecalc, UintValue: n}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The STATS_AUTO_RECALC is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1656:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionStatsAutoRecalc, Default: true}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The STATS_AUTO_RECALC is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1657:\n\t\t{\n\t\t\t// Parse it but will ignore it.\n\t\t\t// In MySQL, STATS_SAMPLE_PAGES=N(Where 0<N<=65535) or STAS_SAMPLE_PAGES=DEFAULT.\n\t\t\t// Cause we don't support it, so we don't check range of the value.\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionStatsSamplePages, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The STATS_SAMPLE_PAGES is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1658:\n\t\t{\n\t\t\t// Parse it but will ignore it.\n\t\t\t// In MySQL, default value of STATS_SAMPLE_PAGES is 0.\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionStatsSamplePages, Default: true}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The STATS_SAMPLE_PAGES is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1659:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionShardRowID, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 1660:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionPreSplitRegion, UintValue: yyS[yypt-0].item.(uint64)}\n\t\t}\n\tcase 1661:\n\t\t{\n\t\t\t// Parse it but will ignore it.\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionPackKeys}\n\t\t}\n\tcase 1662:\n\t\t{\n\t\t\t// Parse it but will ignore it.\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionStorageMedia, StrValue: \"MEMORY\"}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The STORAGE clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1663:\n\t\t{\n\t\t\t// Parse it but will ignore it.\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionStorageMedia, StrValue: \"DISK\"}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The STORAGE clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1664:\n\t\t{\n\t\t\t// Parse it but will ignore it\n\t\t\t// See https://github.com/mysql/mysql-server/blob/8.0/sql/sql_yacc.yy#L5977-L5984\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionSecondaryEngineNull}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The SECONDARY_ENGINE clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1665:\n\t\t{\n\t\t\t// Parse it but will ignore it\n\t\t\t// See https://github.com/mysql/mysql-server/blob/8.0/sql/sql_yacc.yy#L5977-L5984\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionSecondaryEngine, StrValue: yyS[yypt-0].item.(string)}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The SECONDARY_ENGINE clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1666:\n\t\t{\n\t\t\t// Parse it but will ignore it\n\t\t\tparser.yyVAL.item = &ast.TableOption{\n\t\t\t\tTp:         ast.TableOptionUnion,\n\t\t\t\tTableNames: yyS[yypt-1].item.([]*ast.TableName),\n\t\t\t}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The UNION option is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1667:\n\t\t{\n\t\t\t// Parse it but will ignore it\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionEncryption, StrValue: yyS[yypt-0].ident}\n\t\t\tyylex.AppendError(yylex.Errorf(\"The ENCRYPTION clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1668:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionRefTable, TableNames: []*ast.TableName{yyS[yypt-0].item.(*ast.TableName)}}\n\t\t}\n\tcase 1669:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TableOption{Tp: ast.TableOptionDBType, StrValue: yyS[yypt-0].ident}\n\t\t}\n\tcase 1672:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.TableOption{}\n\t\t}\n\tcase 1674:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.TableOption{yyS[yypt-0].item.(*ast.TableOption)}\n\t\t}\n\tcase 1675:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-1].item.([]*ast.TableOption), yyS[yypt-0].item.(*ast.TableOption))\n\t\t}\n\tcase 1676:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.TableOption), yyS[yypt-0].item.(*ast.TableOption))\n\t\t}\n\tcase 1679:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.TruncateTableStmt{Table: yyS[yypt-0].item.(*ast.TableName)}\n\t\t}\n\tcase 1680:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.RowFormatDefault\n\t\t}\n\tcase 1681:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.RowFormatDynamic\n\t\t}\n\tcase 1682:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.RowFormatFixed\n\t\t}\n\tcase 1683:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.RowFormatCompressed\n\t\t}\n\tcase 1684:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.RowFormatRedundant\n\t\t}\n\tcase 1685:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.RowFormatCompact\n\t\t}\n\tcase 1686:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TokuDBRowFormatDefault\n\t\t}\n\tcase 1687:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TokuDBRowFormatFast\n\t\t}\n\tcase 1688:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TokuDBRowFormatSmall\n\t\t}\n\tcase 1689:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TokuDBRowFormatZlib\n\t\t}\n\tcase 1690:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TokuDBRowFormatQuickLZ\n\t\t}\n\tcase 1691:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TokuDBRowFormatLzma\n\t\t}\n\tcase 1692:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TokuDBRowFormatSnappy\n\t\t}\n\tcase 1693:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TokuDBRowFormatUncompressed\n\t\t}\n\tcase 1694:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1695:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1696:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1697:\n\t\t{\n\t\t\t// TODO: check flen 0\n\t\t\tx := types.NewFieldType(yyS[yypt-2].item.(byte))\n\t\t\tx.Flen = yyS[yypt-1].item.(int)\n\t\t\tfor _, o := range yyS[yypt-0].item.([]*ast.TypeOpt) {\n\t\t\t\tif o.IsUnsigned {\n\t\t\t\t\tx.Flag |= mysql.UnsignedFlag\n\t\t\t\t}\n\t\t\t\tif o.IsZerofill {\n\t\t\t\t\tx.Flag |= mysql.ZerofillFlag\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1698:\n\t\t{\n\t\t\t// TODO: check flen 0\n\t\t\tx := types.NewFieldType(yyS[yypt-1].item.(byte))\n\t\t\tx.Flen = 1\n\t\t\tfor _, o := range yyS[yypt-0].item.([]*ast.TypeOpt) {\n\t\t\t\tif o.IsUnsigned {\n\t\t\t\t\tx.Flag |= mysql.UnsignedFlag\n\t\t\t\t}\n\t\t\t\tif o.IsZerofill {\n\t\t\t\t\tx.Flag |= mysql.ZerofillFlag\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1699:\n\t\t{\n\t\t\tfopt := yyS[yypt-1].item.(*ast.FloatOpt)\n\t\t\tx := types.NewFieldType(yyS[yypt-2].item.(byte))\n\t\t\tx.Flen = fopt.Flen\n\t\t\tx.Decimal = fopt.Decimal\n\t\t\tfor _, o := range yyS[yypt-0].item.([]*ast.TypeOpt) {\n\t\t\t\tif o.IsUnsigned {\n\t\t\t\t\tx.Flag |= mysql.UnsignedFlag\n\t\t\t\t}\n\t\t\t\tif o.IsZerofill {\n\t\t\t\t\tx.Flag |= mysql.ZerofillFlag\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1700:\n\t\t{\n\t\t\tfopt := yyS[yypt-1].item.(*ast.FloatOpt)\n\t\t\tx := types.NewFieldType(yyS[yypt-2].item.(byte))\n\t\t\tx.Flen = fopt.Flen\n\t\t\tif x.Tp == mysql.TypeFloat && fopt.Decimal == types.UnspecifiedLength && x.Flen <= mysql.MaxDoublePrecisionLength {\n\t\t\t\tif x.Flen > mysql.MaxFloatPrecisionLength {\n\t\t\t\t\tx.Tp = mysql.TypeDouble\n\t\t\t\t}\n\t\t\t\tx.Flen = types.UnspecifiedLength\n\t\t\t}\n\t\t\tx.Decimal = fopt.Decimal\n\t\t\tfor _, o := range yyS[yypt-0].item.([]*ast.TypeOpt) {\n\t\t\t\tif o.IsUnsigned {\n\t\t\t\t\tx.Flag |= mysql.UnsignedFlag\n\t\t\t\t}\n\t\t\t\tif o.IsZerofill {\n\t\t\t\t\tx.Flag |= mysql.ZerofillFlag\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1701:\n\t\t{\n\t\t\tx := types.NewFieldType(yyS[yypt-1].item.(byte))\n\t\t\tx.Flen = yyS[yypt-0].item.(int)\n\t\t\tif x.Flen == types.UnspecifiedLength {\n\t\t\t\tx.Flen = 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1702:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeTiny\n\t\t}\n\tcase 1703:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeShort\n\t\t}\n\tcase 1704:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeInt24\n\t\t}\n\tcase 1705:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeLong\n\t\t}\n\tcase 1706:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeTiny\n\t\t}\n\tcase 1707:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeShort\n\t\t}\n\tcase 1708:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeInt24\n\t\t}\n\tcase 1709:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeLong\n\t\t}\n\tcase 1710:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeLonglong\n\t\t}\n\tcase 1711:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeLong\n\t\t}\n\tcase 1712:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeLonglong\n\t\t}\n\tcase 1713:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeTiny\n\t\t}\n\tcase 1714:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeTiny\n\t\t}\n\tcase 1718:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeNewDecimal\n\t\t}\n\tcase 1719:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeNewDecimal\n\t\t}\n\tcase 1720:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeNewDecimal\n\t\t}\n\tcase 1721:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeFloat\n\t\t}\n\tcase 1722:\n\t\t{\n\t\t\tif parser.lexer.GetSQLMode().HasRealAsFloatMode() {\n\t\t\t\tparser.yyVAL.item = mysql.TypeFloat\n\t\t\t} else {\n\t\t\t\tparser.yyVAL.item = mysql.TypeDouble\n\t\t\t}\n\t\t}\n\tcase 1723:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeDouble\n\t\t}\n\tcase 1724:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeDouble\n\t\t}\n\tcase 1725:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TypeBit\n\t\t}\n\tcase 1726:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeString)\n\t\t\tx.Flen = yyS[yypt-1].item.(int)\n\t\t\tx.Charset = yyS[yypt-0].item.(*ast.OptBinary).Charset\n\t\t\tif yyS[yypt-0].item.(*ast.OptBinary).IsBinary {\n\t\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1727:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeString)\n\t\t\tx.Charset = yyS[yypt-0].item.(*ast.OptBinary).Charset\n\t\t\tif yyS[yypt-0].item.(*ast.OptBinary).IsBinary {\n\t\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1728:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeString)\n\t\t\tx.Flen = yyS[yypt-1].item.(int)\n\t\t\tx.Charset = yyS[yypt-0].item.(*ast.OptBinary).Charset\n\t\t\tif yyS[yypt-0].item.(*ast.OptBinary).IsBinary {\n\t\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1729:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeString)\n\t\t\tx.Charset = yyS[yypt-0].item.(*ast.OptBinary).Charset\n\t\t\tif yyS[yypt-0].item.(*ast.OptBinary).IsBinary {\n\t\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1730:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeVarchar)\n\t\t\tx.Flen = yyS[yypt-1].item.(int)\n\t\t\tx.Charset = yyS[yypt-0].item.(*ast.OptBinary).Charset\n\t\t\tif yyS[yypt-0].item.(*ast.OptBinary).IsBinary {\n\t\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1731:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeVarchar)\n\t\t\tx.Flen = yyS[yypt-1].item.(int)\n\t\t\tx.Charset = yyS[yypt-0].item.(*ast.OptBinary).Charset\n\t\t\tif yyS[yypt-0].item.(*ast.OptBinary).IsBinary {\n\t\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1732:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeString)\n\t\t\tx.Flen = yyS[yypt-0].item.(int)\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CharsetBin\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1733:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeVarchar)\n\t\t\tx.Flen = yyS[yypt-0].item.(int)\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CharsetBin\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1734:\n\t\t{\n\t\t\tx := yyS[yypt-0].item.(*types.FieldType)\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CharsetBin\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(*types.FieldType)\n\t\t}\n\tcase 1735:\n\t\t{\n\t\t\tx := yyS[yypt-1].item.(*types.FieldType)\n\t\t\tx.Charset = yyS[yypt-0].item.(*ast.OptBinary).Charset\n\t\t\tif yyS[yypt-0].item.(*ast.OptBinary).IsBinary {\n\t\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1736:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeEnum)\n\t\t\tx.Elems = yyS[yypt-2].item.([]string)\n\t\t\tx.Charset = yyS[yypt-0].item.(string)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1737:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeSet)\n\t\t\tx.Elems = yyS[yypt-2].item.([]string)\n\t\t\tx.Charset = yyS[yypt-0].item.(string)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1738:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeJSON)\n\t\t\tx.Decimal = 0\n\t\t\tx.Charset = charset.CharsetBin\n\t\t\tx.Collate = charset.CollationBin\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1739:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeMediumBlob)\n\t\t\tx.Charset = yyS[yypt-0].item.(*ast.OptBinary).Charset\n\t\t\tif yyS[yypt-0].item.(*ast.OptBinary).IsBinary {\n\t\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1740:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeMediumBlob)\n\t\t\tx.Charset = yyS[yypt-0].item.(*ast.OptBinary).Charset\n\t\t\tif yyS[yypt-0].item.(*ast.OptBinary).IsBinary {\n\t\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1760:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeTinyBlob)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1761:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeBlob)\n\t\t\tx.Flen = yyS[yypt-0].item.(int)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1762:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeMediumBlob)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1763:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeLongBlob)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1764:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeMediumBlob)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1765:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeTinyBlob)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1766:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeBlob)\n\t\t\tx.Flen = yyS[yypt-0].item.(int)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1767:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeMediumBlob)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1768:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeLongBlob)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1769:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1770:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.OptBinary{\n\t\t\t\tIsBinary: false,\n\t\t\t\tCharset:  charset.CharsetLatin1,\n\t\t\t}\n\t\t}\n\tcase 1771:\n\t\t{\n\t\t\tname, _, err := charset.GetCharsetInfo(\"ucs2\")\n\t\t\tif err != nil {\n\t\t\t\tyylex.AppendError(ErrUnknownCharacterSet.GenWithStackByArgs(\"ucs2\"))\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.OptBinary{\n\t\t\t\tIsBinary: false,\n\t\t\t\tCharset:  name,\n\t\t\t}\n\t\t}\n\tcase 1772:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.OptBinary{\n\t\t\t\tIsBinary: false,\n\t\t\t\tCharset:  \"\",\n\t\t\t}\n\t\t}\n\tcase 1773:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeDate)\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1774:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeDatetime)\n\t\t\tx.Flen = mysql.MaxDatetimeWidthNoFsp\n\t\t\tx.Decimal = yyS[yypt-0].item.(int)\n\t\t\tif x.Decimal > 0 {\n\t\t\t\tx.Flen = x.Flen + 1 + x.Decimal\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1775:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeTimestamp)\n\t\t\tx.Flen = mysql.MaxDatetimeWidthNoFsp\n\t\t\tx.Decimal = yyS[yypt-0].item.(int)\n\t\t\tif x.Decimal > 0 {\n\t\t\t\tx.Flen = x.Flen + 1 + x.Decimal\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1776:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeDuration)\n\t\t\tx.Flen = mysql.MaxDurationWidthNoFsp\n\t\t\tx.Decimal = yyS[yypt-0].item.(int)\n\t\t\tif x.Decimal > 0 {\n\t\t\t\tx.Flen = x.Flen + 1 + x.Decimal\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1777:\n\t\t{\n\t\t\tx := types.NewFieldType(mysql.TypeYear)\n\t\t\tx.Flen = yyS[yypt-1].item.(int)\n\t\t\tif x.Flen != types.UnspecifiedLength && x.Flen != 4 {\n\t\t\t\tyylex.AppendError(ErrInvalidYearColumnLength.GenWithStackByArgs())\n\t\t\t\treturn -1\n\t\t\t}\n\t\t\tparser.yyVAL.item = x\n\t\t}\n\tcase 1778:\n\t\t{\n\t\t\tparser.yyVAL.item = int(yyS[yypt-1].item.(uint64))\n\t\t}\n\tcase 1779:\n\t\t{\n\t\t\tparser.yyVAL.item = types.UnspecifiedLength\n\t\t}\n\tcase 1780:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(int)\n\t\t}\n\tcase 1781:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TypeOpt{IsUnsigned: true}\n\t\t}\n\tcase 1782:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TypeOpt{IsUnsigned: false}\n\t\t}\n\tcase 1783:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TypeOpt{IsZerofill: true, IsUnsigned: true}\n\t\t}\n\tcase 1784:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.TypeOpt{}\n\t\t}\n\tcase 1785:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-1].item.([]*ast.TypeOpt), yyS[yypt-0].item.(*ast.TypeOpt))\n\t\t}\n\tcase 1786:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FloatOpt{Flen: types.UnspecifiedLength, Decimal: types.UnspecifiedLength}\n\t\t}\n\tcase 1787:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FloatOpt{Flen: yyS[yypt-0].item.(int), Decimal: types.UnspecifiedLength}\n\t\t}\n\tcase 1788:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(*ast.FloatOpt)\n\t\t}\n\tcase 1789:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FloatOpt{Flen: int(yyS[yypt-3].item.(uint64)), Decimal: int(yyS[yypt-1].item.(uint64))}\n\t\t}\n\tcase 1790:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1791:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1792:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.OptBinary{\n\t\t\t\tIsBinary: false,\n\t\t\t\tCharset:  \"\",\n\t\t\t}\n\t\t}\n\tcase 1793:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.OptBinary{\n\t\t\t\tIsBinary: true,\n\t\t\t\tCharset:  yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1794:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.OptBinary{\n\t\t\t\tIsBinary: yyS[yypt-0].item.(bool),\n\t\t\t\tCharset:  yyS[yypt-1].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1795:\n\t\t{\n\t\t\tparser.yyVAL.item = \"\"\n\t\t}\n\tcase 1796:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(string)\n\t\t}\n\tcase 1800:\n\t\t{\n\t\t\tparser.yyVAL.item = \"\"\n\t\t}\n\tcase 1801:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(string)\n\t\t}\n\tcase 1802:\n\t\t{\n\t\t\tparser.yyVAL.item = []string{yyS[yypt-0].ident}\n\t\t}\n\tcase 1803:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]string), yyS[yypt-0].ident)\n\t\t}\n\tcase 1804:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1805:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1806:\n\t\t{\n\t\t\tvar refs *ast.Join\n\t\t\tif x, ok := yyS[yypt-5].item.(*ast.Join); ok {\n\t\t\t\trefs = x\n\t\t\t} else {\n\t\t\t\trefs = &ast.Join{Left: yyS[yypt-5].item.(ast.ResultSetNode)}\n\t\t\t}\n\t\t\tst := &ast.UpdateStmt{\n\t\t\t\tPriority:  yyS[yypt-7].item.(mysql.PriorityEnum),\n\t\t\t\tTableRefs: &ast.TableRefsClause{TableRefs: refs},\n\t\t\t\tList:      yyS[yypt-3].item.([]*ast.Assignment),\n\t\t\t\tIgnoreErr: yyS[yypt-6].item.(bool),\n\t\t\t}\n\t\t\tif yyS[yypt-8].item != nil {\n\t\t\t\tst.TableHints = yyS[yypt-8].item.([]*ast.TableOptimizerHint)\n\t\t\t}\n\t\t\tif yyS[yypt-2].item != nil {\n\t\t\t\tst.Where = yyS[yypt-2].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tst.Order = yyS[yypt-1].item.(*ast.OrderByClause)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tst.Limit = yyS[yypt-0].item.(*ast.Limit)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = st\n\t\t}\n\tcase 1807:\n\t\t{\n\t\t\tst := &ast.UpdateStmt{\n\t\t\t\tPriority:  yyS[yypt-5].item.(mysql.PriorityEnum),\n\t\t\t\tTableRefs: &ast.TableRefsClause{TableRefs: yyS[yypt-3].item.(*ast.Join)},\n\t\t\t\tList:      yyS[yypt-1].item.([]*ast.Assignment),\n\t\t\t\tIgnoreErr: yyS[yypt-4].item.(bool),\n\t\t\t}\n\t\t\tif yyS[yypt-6].item != nil {\n\t\t\t\tst.TableHints = yyS[yypt-6].item.([]*ast.TableOptimizerHint)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tst.Where = yyS[yypt-0].item.(ast.ExprNode)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = st\n\t\t}\n\tcase 1808:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.UseStmt{DBName: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 1809:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].expr\n\t\t}\n\tcase 1810:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1811:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1814:\n\t\t{\n\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/create-user.html\n\t\t\tparser.yyVAL.statement = &ast.CreateUserStmt{\n\t\t\t\tIsCreateRole: false,\n\t\t\t\tIfNotExists:  yyS[yypt-3].item.(bool),\n\t\t\t\tSpecs:        yyS[yypt-2].item.([]*ast.UserSpec),\n\t\t\t\tTLSOptions:   yyS[yypt-1].item.([]*ast.TLSOption),\n\t\t\t\tEngineOpt:    yyS[yypt-0].item.(*ast.EngineOption),\n\t\t\t}\n\t\t}\n\tcase 1815:\n\t\t{\n\t\t\t// See https://dev.mysql.com/doc/refman/8.0/en/create-role.html\n\t\t\tparser.yyVAL.statement = &ast.CreateUserStmt{\n\t\t\t\tIsCreateRole: true,\n\t\t\t\tIfNotExists:  yyS[yypt-1].item.(bool),\n\t\t\t\tSpecs:        yyS[yypt-0].item.([]*ast.UserSpec),\n\t\t\t}\n\t\t}\n\tcase 1816:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.AlterUserStmt{\n\t\t\t\tIfExists:   yyS[yypt-3].item.(bool),\n\t\t\t\tSpecs:      yyS[yypt-2].item.([]*ast.UserSpec),\n\t\t\t\tTLSOptions: yyS[yypt-1].item.([]*ast.TLSOption),\n\t\t\t\tEngineOpt:  yyS[yypt-0].item.(*ast.EngineOption),\n\t\t\t}\n\t\t}\n\tcase 1817:\n\t\t{\n\t\t\tauth := &ast.AuthOption{\n\t\t\t\tAuthString:   yyS[yypt-0].item.(string),\n\t\t\t\tByAuthString: true,\n\t\t\t}\n\t\t\tparser.yyVAL.statement = &ast.AlterUserStmt{\n\t\t\t\tIfExists:    yyS[yypt-6].item.(bool),\n\t\t\t\tCurrentAuth: auth,\n\t\t\t}\n\t\t}\n\tcase 1818:\n\t\t{\n\t\t\tuserSpec := &ast.UserSpec{\n\t\t\t\tUser:      yyS[yypt-2].item.(*auth.UserIdentity),\n\t\t\t\tPartyCode: yyS[yypt-1].item.(string),\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tuserSpec.AuthOpt = yyS[yypt-0].item.(*ast.AuthOption)\n\t\t\t}\n\t\t\tparser.yyVAL.item = userSpec\n\t\t}\n\tcase 1819:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.UserSpec{yyS[yypt-0].item.(*ast.UserSpec)}\n\t\t}\n\tcase 1820:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.UserSpec), yyS[yypt-0].item.(*ast.UserSpec))\n\t\t}\n\tcase 1821:\n\t\t{\n\t\t\tparser.yyVAL.item = (*ast.EngineOption)(nil)\n\t\t}\n\tcase 1822:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.EngineOption{\n\t\t\t\tTokenAuth:  &ast.TokenAuthOption{Token: yyS[yypt-1].ident},\n\t\t\t\tPubKeyAuth: nil,\n\t\t\t\tEndpoints:  yyS[yypt-0].item.([]string),\n\t\t\t}\n\t\t}\n\tcase 1823:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.EngineOption{\n\t\t\t\tTokenAuth: nil,\n\t\t\t\tPubKeyAuth: &ast.PubKeyAuthOption{\n\t\t\t\t\tMessage:   yyS[yypt-3].ident,\n\t\t\t\t\tSignature: yyS[yypt-2].ident,\n\t\t\t\t\tPubKey:    yyS[yypt-1].ident,\n\t\t\t\t},\n\t\t\t\tEndpoints: yyS[yypt-0].item.([]string),\n\t\t\t}\n\t\t}\n\tcase 1824:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.EngineOption{\n\t\t\t\tTokenAuth:  nil,\n\t\t\t\tPubKeyAuth: nil,\n\t\t\t\tEndpoints:  yyS[yypt-0].item.([]string),\n\t\t\t}\n\t\t}\n\tcase 1825:\n\t\t{\n\t\t\tl := []string{}\n\t\t\tparser.yyVAL.item = l\n\t\t}\n\tcase 1826:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1827:\n\t\t{\n\t\t\tl := []*ast.ResourceOption{}\n\t\t\tparser.yyVAL.item = l\n\t\t}\n\tcase 1828:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t\tyylex.AppendError(yylex.Errorf(\"TiDB does not support WITH ConnectionOptions now, they would be parsed but ignored.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1829:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.ResourceOption{yyS[yypt-0].item.(*ast.ResourceOption)}\n\t\t}\n\tcase 1830:\n\t\t{\n\t\t\tl := yyS[yypt-1].item.([]*ast.ResourceOption)\n\t\t\tl = append(l, yyS[yypt-0].item.(*ast.ResourceOption))\n\t\t\tparser.yyVAL.item = l\n\t\t}\n\tcase 1831:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ResourceOption{\n\t\t\t\tType:  ast.MaxQueriesPerHour,\n\t\t\t\tCount: yyS[yypt-0].item.(int64),\n\t\t\t}\n\t\t}\n\tcase 1832:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ResourceOption{\n\t\t\t\tType:  ast.MaxUpdatesPerHour,\n\t\t\t\tCount: yyS[yypt-0].item.(int64),\n\t\t\t}\n\t\t}\n\tcase 1833:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ResourceOption{\n\t\t\t\tType:  ast.MaxConnectionsPerHour,\n\t\t\t\tCount: yyS[yypt-0].item.(int64),\n\t\t\t}\n\t\t}\n\tcase 1834:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.ResourceOption{\n\t\t\t\tType:  ast.MaxUserConnections,\n\t\t\t\tCount: yyS[yypt-0].item.(int64),\n\t\t\t}\n\t\t}\n\tcase 1835:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.TLSOption{}\n\t\t}\n\tcase 1836:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1837:\n\t\t{\n\t\t\tt := &ast.TLSOption{\n\t\t\t\tType: ast.TslNone,\n\t\t\t}\n\t\t\tparser.yyVAL.item = []*ast.TLSOption{t}\n\t\t}\n\tcase 1838:\n\t\t{\n\t\t\tt := &ast.TLSOption{\n\t\t\t\tType: ast.Ssl,\n\t\t\t}\n\t\t\tparser.yyVAL.item = []*ast.TLSOption{t}\n\t\t}\n\tcase 1839:\n\t\t{\n\t\t\tt := &ast.TLSOption{\n\t\t\t\tType: ast.X509,\n\t\t\t}\n\t\t\tparser.yyVAL.item = []*ast.TLSOption{t}\n\t\t}\n\tcase 1840:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1841:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.TLSOption{yyS[yypt-0].item.(*ast.TLSOption)}\n\t\t}\n\tcase 1842:\n\t\t{\n\t\t\tl := yyS[yypt-2].item.([]*ast.TLSOption)\n\t\t\tl = append(l, yyS[yypt-0].item.(*ast.TLSOption))\n\t\t\tparser.yyVAL.item = l\n\t\t}\n\tcase 1843:\n\t\t{\n\t\t\tl := yyS[yypt-1].item.([]*ast.TLSOption)\n\t\t\tl = append(l, yyS[yypt-0].item.(*ast.TLSOption))\n\t\t\tparser.yyVAL.item = l\n\t\t}\n\tcase 1844:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TLSOption{\n\t\t\t\tType:  ast.Issuer,\n\t\t\t\tValue: yyS[yypt-0].ident,\n\t\t\t}\n\t\t}\n\tcase 1845:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TLSOption{\n\t\t\t\tType:  ast.Subject,\n\t\t\t\tValue: yyS[yypt-0].ident,\n\t\t\t}\n\t\t}\n\tcase 1846:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.TLSOption{\n\t\t\t\tType:  ast.Cipher,\n\t\t\t\tValue: yyS[yypt-0].ident,\n\t\t\t}\n\t\t}\n\tcase 1847:\n\t\t{\n\t\t\tl := []*ast.PasswordOrLockOption{}\n\t\t\tparser.yyVAL.item = l\n\t\t}\n\tcase 1848:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t\tyylex.AppendError(yylex.Errorf(\"TiDB does not support PASSWORD EXPIRE and ACCOUNT LOCK now, they would be parsed but ignored.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\tcase 1849:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.PasswordOrLockOption{yyS[yypt-0].item.(*ast.PasswordOrLockOption)}\n\t\t}\n\tcase 1850:\n\t\t{\n\t\t\tl := yyS[yypt-1].item.([]*ast.PasswordOrLockOption)\n\t\t\tl = append(l, yyS[yypt-0].item.(*ast.PasswordOrLockOption))\n\t\t\tparser.yyVAL.item = l\n\t\t}\n\tcase 1851:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PasswordOrLockOption{\n\t\t\t\tType: ast.Unlock,\n\t\t\t}\n\t\t}\n\tcase 1852:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PasswordOrLockOption{\n\t\t\t\tType: ast.Lock,\n\t\t\t}\n\t\t}\n\tcase 1853:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PasswordOrLockOption{\n\t\t\t\tType: ast.PasswordExpire,\n\t\t\t}\n\t\t}\n\tcase 1854:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PasswordOrLockOption{\n\t\t\t\tType:  ast.PasswordExpireInterval,\n\t\t\t\tCount: yyS[yypt-1].item.(int64),\n\t\t\t}\n\t\t}\n\tcase 1855:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PasswordOrLockOption{\n\t\t\t\tType: ast.PasswordExpireNever,\n\t\t\t}\n\t\t}\n\tcase 1856:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PasswordOrLockOption{\n\t\t\t\tType: ast.PasswordExpireDefault,\n\t\t\t}\n\t\t}\n\tcase 1857:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1858:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1859:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1860:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AuthOption{\n\t\t\t\tAuthString:   yyS[yypt-0].item.(string),\n\t\t\t\tByAuthString: true,\n\t\t\t}\n\t\t}\n\tcase 1861:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1862:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AuthOption{\n\t\t\t\tAuthString:   yyS[yypt-0].item.(string),\n\t\t\t\tByAuthString: true,\n\t\t\t}\n\t\t}\n\tcase 1863:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AuthOption{\n\t\t\t\tHashString: yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1864:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.AuthOption{\n\t\t\t\tHashString: yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1865:\n\t\t{\n\t\t\tparser.yyVAL.item = \"\"\n\t\t}\n\tcase 1866:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(string)\n\t\t}\n\tcase 1867:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1868:\n\t\t{\n\t\t\trole := yyS[yypt-0].item.(*auth.RoleIdentity)\n\t\t\troleSpec := &ast.UserSpec{\n\t\t\t\tUser: &auth.UserIdentity{\n\t\t\t\t\tUsername: role.Username,\n\t\t\t\t\tHostname: role.Hostname,\n\t\t\t\t},\n\t\t\t\tIsRole: true,\n\t\t\t}\n\t\t\tparser.yyVAL.item = roleSpec\n\t\t}\n\tcase 1869:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.UserSpec{yyS[yypt-0].item.(*ast.UserSpec)}\n\t\t}\n\tcase 1870:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.UserSpec), yyS[yypt-0].item.(*ast.UserSpec))\n\t\t}\n\tcase 1871:\n\t\t{\n\t\t\tstartOffset := parser.startOffset(&yyS[yypt-2])\n\t\t\tendOffset := parser.startOffset(&yyS[yypt-1])\n\t\t\tselStmt := yyS[yypt-2].statement.(*ast.SelectStmt)\n\t\t\tselStmt.SetText(strings.TrimSpace(parser.src[startOffset:endOffset]))\n\n\t\t\tstartOffset = parser.startOffset(&yyS[yypt])\n\t\t\thintedSelStmt := yyS[yypt-0].statement.(*ast.SelectStmt)\n\t\t\thintedSelStmt.SetText(strings.TrimSpace(parser.src[startOffset:]))\n\n\t\t\tx := &ast.CreateBindingStmt{\n\t\t\t\tOriginSel:   selStmt,\n\t\t\t\tHintedSel:   hintedSelStmt,\n\t\t\t\tGlobalScope: yyS[yypt-5].item.(bool),\n\t\t\t}\n\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 1872:\n\t\t{\n\t\t\tstartOffset := parser.startOffset(&yyS[yypt])\n\t\t\tselStmt := yyS[yypt-0].statement.(*ast.SelectStmt)\n\t\t\tselStmt.SetText(strings.TrimSpace(parser.src[startOffset:]))\n\n\t\t\tx := &ast.DropBindingStmt{\n\t\t\t\tOriginSel:   selStmt,\n\t\t\t\tGlobalScope: yyS[yypt-3].item.(bool),\n\t\t\t}\n\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 1873:\n\t\t{\n\t\t\tstartOffset := parser.startOffset(&yyS[yypt-2])\n\t\t\tendOffset := parser.startOffset(&yyS[yypt-1])\n\t\t\tselStmt := yyS[yypt-2].statement.(*ast.SelectStmt)\n\t\t\tselStmt.SetText(strings.TrimSpace(parser.src[startOffset:endOffset]))\n\n\t\t\tstartOffset = parser.startOffset(&yyS[yypt])\n\t\t\thintedSelStmt := yyS[yypt-0].statement.(*ast.SelectStmt)\n\t\t\thintedSelStmt.SetText(strings.TrimSpace(parser.src[startOffset:]))\n\n\t\t\tx := &ast.DropBindingStmt{\n\t\t\t\tOriginSel:   selStmt,\n\t\t\t\tHintedSel:   hintedSelStmt,\n\t\t\t\tGlobalScope: yyS[yypt-5].item.(bool),\n\t\t\t}\n\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 1874:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.GrantStmt{\n\t\t\t\tPrivs:      yyS[yypt-7].item.([]*ast.PrivElem),\n\t\t\t\tObjectType: yyS[yypt-5].item.(ast.ObjectTypeType),\n\t\t\t\tLevel:      yyS[yypt-4].item.(*ast.GrantLevel),\n\t\t\t\tUsers:      yyS[yypt-2].item.([]*ast.UserSpec),\n\t\t\t\tTLSOptions: yyS[yypt-1].item.([]*ast.TLSOption),\n\t\t\t\tWithGrant:  yyS[yypt-0].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1875:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.GrantRoleStmt{\n\t\t\t\tRoles: yyS[yypt-2].item.([]*auth.RoleIdentity),\n\t\t\t\tUsers: yyS[yypt-0].item.([]*auth.UserIdentity),\n\t\t\t}\n\t\t}\n\tcase 1876:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1877:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1878:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1879:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1880:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1881:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1882:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PrivElem{\n\t\t\t\tPriv: yyS[yypt-0].item.(mysql.PrivilegeType),\n\t\t\t}\n\t\t}\n\tcase 1883:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.PrivElem{\n\t\t\t\tPriv: yyS[yypt-3].item.(mysql.PrivilegeType),\n\t\t\t\tCols: yyS[yypt-1].item.([]*ast.ColumnName),\n\t\t\t}\n\t\t}\n\tcase 1884:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.PrivElem{yyS[yypt-0].item.(*ast.PrivElem)}\n\t\t}\n\tcase 1885:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]*ast.PrivElem), yyS[yypt-0].item.(*ast.PrivElem))\n\t\t}\n\tcase 1886:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.AllPriv\n\t\t}\n\tcase 1887:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.AllPriv\n\t\t}\n\tcase 1888:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.AlterPriv\n\t\t}\n\tcase 1889:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.CreatePriv\n\t\t}\n\tcase 1890:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.CreateUserPriv\n\t\t}\n\tcase 1891:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.TriggerPriv\n\t\t}\n\tcase 1892:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.DeletePriv\n\t\t}\n\tcase 1893:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.DropPriv\n\t\t}\n\tcase 1894:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.ProcessPriv\n\t\t}\n\tcase 1895:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.ExecutePriv\n\t\t}\n\tcase 1896:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.IndexPriv\n\t\t}\n\tcase 1897:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.InsertPriv\n\t\t}\n\tcase 1898:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.SelectPriv\n\t\t}\n\tcase 1899:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.SuperPriv\n\t\t}\n\tcase 1900:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.ShowDBPriv\n\t\t}\n\tcase 1901:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.UpdatePriv\n\t\t}\n\tcase 1902:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.GrantPriv\n\t\t}\n\tcase 1903:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.ReferencesPriv\n\t\t}\n\tcase 1904:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.PrivilegeType(0)\n\t\t}\n\tcase 1905:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.PrivilegeType(0)\n\t\t}\n\tcase 1906:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.PrivilegeType(0)\n\t\t}\n\tcase 1907:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.ReloadPriv\n\t\t}\n\tcase 1908:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.FilePriv\n\t\t}\n\tcase 1909:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.CreateTMPTablePriv\n\t\t}\n\tcase 1910:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.LockTablesPriv\n\t\t}\n\tcase 1911:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.CreateViewPriv\n\t\t}\n\tcase 1912:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.ShowViewPriv\n\t\t}\n\tcase 1913:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.CreateRolePriv\n\t\t}\n\tcase 1914:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.DropRolePriv\n\t\t}\n\tcase 1915:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.CreateRoutinePriv\n\t\t}\n\tcase 1916:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.AlterRoutinePriv\n\t\t}\n\tcase 1917:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.EventPriv\n\t\t}\n\tcase 1918:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.ShutdownPriv\n\t\t}\n\tcase 1919:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.PlaintextPriv\n\t\t}\n\tcase 1920:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.PlaintextAfterJoinPriv\n\t\t}\n\tcase 1921:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.PlaintextAsJoinPayloadPriv\n\t\t}\n\tcase 1922:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.RevealRankPriv\n\t\t}\n\tcase 1923:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.PlaintextAfterGroupByPriv\n\t\t}\n\tcase 1924:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.PlaintextAfterComparePriv\n\t\t}\n\tcase 1925:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.PlaintextAfterAggregatePriv\n\t\t}\n\tcase 1926:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.EncryptedOnlyPriv\n\t\t}\n\tcase 1927:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.ShowPriv\n\t\t}\n\tcase 1928:\n\t\t{\n\t\t\tparser.yyVAL.item = mysql.DescribePriv\n\t\t}\n\tcase 1929:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ObjectTypeNone\n\t\t}\n\tcase 1930:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.ObjectTypeTable\n\t\t}\n\tcase 1931:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.GrantLevel{\n\t\t\t\tLevel: ast.GrantLevelDB,\n\t\t\t}\n\t\t}\n\tcase 1932:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.GrantLevel{\n\t\t\t\tLevel: ast.GrantLevelGlobal,\n\t\t\t}\n\t\t}\n\tcase 1933:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.GrantLevel{\n\t\t\t\tLevel:  ast.GrantLevelDB,\n\t\t\t\tDBName: yyS[yypt-2].ident,\n\t\t\t}\n\t\t}\n\tcase 1934:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.GrantLevel{\n\t\t\t\tLevel:     ast.GrantLevelTable,\n\t\t\t\tDBName:    yyS[yypt-2].ident,\n\t\t\t\tTableName: yyS[yypt-0].ident,\n\t\t\t}\n\t\t}\n\tcase 1935:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.GrantLevel{\n\t\t\t\tLevel:     ast.GrantLevelTable,\n\t\t\t\tTableName: yyS[yypt-0].ident,\n\t\t\t}\n\t\t}\n\tcase 1936:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.RevokeStmt{\n\t\t\t\tPrivs:      yyS[yypt-5].item.([]*ast.PrivElem),\n\t\t\t\tObjectType: yyS[yypt-3].item.(ast.ObjectTypeType),\n\t\t\t\tLevel:      yyS[yypt-2].item.(*ast.GrantLevel),\n\t\t\t\tUsers:      yyS[yypt-0].item.([]*ast.UserSpec),\n\t\t\t}\n\t\t}\n\tcase 1937:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.RevokeRoleStmt{\n\t\t\t\tRoles: yyS[yypt-2].item.([]*auth.RoleIdentity),\n\t\t\t\tUsers: yyS[yypt-0].item.([]*auth.UserIdentity),\n\t\t\t}\n\t\t}\n\tcase 1938:\n\t\t{\n\t\t\tx := &ast.LoadDataStmt{\n\t\t\t\tPath:               yyS[yypt-10].ident,\n\t\t\t\tOnDuplicate:        yyS[yypt-9].item.(ast.OnDuplicateKeyHandlingType),\n\t\t\t\tTable:              yyS[yypt-6].item.(*ast.TableName),\n\t\t\t\tColumnsAndUserVars: yyS[yypt-1].item.([]*ast.ColumnNameOrUserVar),\n\t\t\t\tIgnoreLines:        yyS[yypt-2].item.(uint64),\n\t\t\t}\n\t\t\tif yyS[yypt-12].item != nil {\n\t\t\t\tx.IsLocal = true\n\t\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/load-data.html#load-data-duplicate-key-handling\n\t\t\t\t// If you do not specify IGNORE or REPLACE modifier , then we set default behavior to IGNORE when LOCAL modifier is specified\n\t\t\t\tif x.OnDuplicate == ast.OnDuplicateKeyHandlingError {\n\t\t\t\t\tx.OnDuplicate = ast.OnDuplicateKeyHandlingIgnore\n\t\t\t\t}\n\t\t\t}\n\t\t\tif yyS[yypt-4].item != nil {\n\t\t\t\tx.FieldsInfo = yyS[yypt-4].item.(*ast.FieldsClause)\n\t\t\t}\n\t\t\tif yyS[yypt-3].item != nil {\n\t\t\t\tx.LinesInfo = yyS[yypt-3].item.(*ast.LinesClause)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tx.ColumnAssignments = yyS[yypt-0].item.([]*ast.Assignment)\n\t\t\t}\n\t\t\tcolumns := []*ast.ColumnName{}\n\t\t\tfor _, v := range x.ColumnsAndUserVars {\n\t\t\t\tif v.ColumnName != nil {\n\t\t\t\t\tcolumns = append(columns, v.ColumnName)\n\t\t\t\t}\n\t\t\t}\n\t\t\tx.Columns = columns\n\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 1939:\n\t\t{\n\t\t\tparser.yyVAL.item = uint64(0)\n\t\t}\n\tcase 1940:\n\t\t{\n\t\t\tparser.yyVAL.item = getUint64FromNUM(yyS[yypt-1].item)\n\t\t}\n\tcase 1943:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1944:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1945:\n\t\t{\n\t\t\tescape := \"\\\\\"\n\t\t\tparser.yyVAL.item = &ast.FieldsClause{\n\t\t\t\tTerminated: \"\\t\",\n\t\t\t\tEscaped:    escape[0],\n\t\t\t}\n\t\t}\n\tcase 1946:\n\t\t{\n\t\t\tfieldsClause := &ast.FieldsClause{\n\t\t\t\tTerminated: \"\\t\",\n\t\t\t\tEscaped:    []byte(\"\\\\\")[0],\n\t\t\t}\n\t\t\tfieldItems := yyS[yypt-0].item.([]*ast.FieldItem)\n\t\t\tfor _, item := range fieldItems {\n\t\t\t\tswitch item.Type {\n\t\t\t\tcase ast.Terminated:\n\t\t\t\t\tfieldsClause.Terminated = item.Value\n\t\t\t\tcase ast.Enclosed:\n\t\t\t\t\tvar enclosed byte\n\t\t\t\t\tif len(item.Value) > 0 {\n\t\t\t\t\t\tenclosed = item.Value[0]\n\t\t\t\t\t}\n\t\t\t\t\tfieldsClause.Enclosed = enclosed\n\t\t\t\t\tif item.OptEnclosed {\n\t\t\t\t\t\tfieldsClause.OptEnclosed = true\n\t\t\t\t\t}\n\t\t\t\tcase ast.Escaped:\n\t\t\t\t\tvar escaped byte\n\t\t\t\t\tif len(item.Value) > 0 {\n\t\t\t\t\t\tescaped = item.Value[0]\n\t\t\t\t\t}\n\t\t\t\t\tfieldsClause.Escaped = escaped\n\t\t\t\t}\n\t\t\t}\n\t\t\tparser.yyVAL.item = fieldsClause\n\t\t}\n\tcase 1949:\n\t\t{\n\t\t\tfieldItems := yyS[yypt-1].item.([]*ast.FieldItem)\n\t\t\tparser.yyVAL.item = append(fieldItems, yyS[yypt-0].item.(*ast.FieldItem))\n\t\t}\n\tcase 1950:\n\t\t{\n\t\t\tfieldItems := make([]*ast.FieldItem, 1, 1)\n\t\t\tfieldItems[0] = yyS[yypt-0].item.(*ast.FieldItem)\n\t\t\tparser.yyVAL.item = fieldItems\n\t\t}\n\tcase 1951:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.FieldItem{\n\t\t\t\tType:  ast.Terminated,\n\t\t\t\tValue: yyS[yypt-0].item.(string),\n\t\t\t}\n\t\t}\n\tcase 1952:\n\t\t{\n\t\t\tstr := yyS[yypt-0].item.(string)\n\t\t\tif str != \"\\\\\" && len(str) > 1 {\n\t\t\t\tyylex.AppendError(ErrWrongFieldTerminators.GenWithStackByArgs())\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.FieldItem{\n\t\t\t\tType:        ast.Enclosed,\n\t\t\t\tValue:       str,\n\t\t\t\tOptEnclosed: true,\n\t\t\t}\n\t\t}\n\tcase 1953:\n\t\t{\n\t\t\tstr := yyS[yypt-0].item.(string)\n\t\t\tif str != \"\\\\\" && len(str) > 1 {\n\t\t\t\tyylex.AppendError(ErrWrongFieldTerminators.GenWithStackByArgs())\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.FieldItem{\n\t\t\t\tType:  ast.Enclosed,\n\t\t\t\tValue: str,\n\t\t\t}\n\t\t}\n\tcase 1954:\n\t\t{\n\t\t\tstr := yyS[yypt-0].item.(string)\n\t\t\tif str != \"\\\\\" && len(str) > 1 {\n\t\t\t\tyylex.AppendError(ErrWrongFieldTerminators.GenWithStackByArgs())\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tparser.yyVAL.item = &ast.FieldItem{\n\t\t\t\tType:  ast.Escaped,\n\t\t\t\tValue: str,\n\t\t\t}\n\t\t}\n\tcase 1955:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1956:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(ast.BinaryLiteral).ToString()\n\t\t}\n\tcase 1957:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(ast.BinaryLiteral).ToString()\n\t\t}\n\tcase 1958:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.LinesClause{Terminated: \"\\n\"}\n\t\t}\n\tcase 1959:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.LinesClause{Starting: yyS[yypt-1].item.(string), Terminated: yyS[yypt-0].item.(string)}\n\t\t}\n\tcase 1960:\n\t\t{\n\t\t\tparser.yyVAL.item = \"\"\n\t\t}\n\tcase 1961:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1962:\n\t\t{\n\t\t\tparser.yyVAL.item = \"\\n\"\n\t\t}\n\tcase 1963:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].ident\n\t\t}\n\tcase 1964:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 1965:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item\n\t\t}\n\tcase 1966:\n\t\t{\n\t\t\tl := yyS[yypt-2].item.([]*ast.Assignment)\n\t\t\tparser.yyVAL.item = append(l, yyS[yypt-0].item.(*ast.Assignment))\n\t\t}\n\tcase 1967:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.Assignment{yyS[yypt-0].item.(*ast.Assignment)}\n\t\t}\n\tcase 1968:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.Assignment{\n\t\t\t\tColumn: yyS[yypt-2].expr.(*ast.ColumnNameExpr).Name,\n\t\t\t\tExpr:   yyS[yypt-0].expr,\n\t\t\t}\n\t\t}\n\tcase 1969:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.UnlockTablesStmt{}\n\t\t}\n\tcase 1970:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.LockTablesStmt{\n\t\t\t\tTableLocks: yyS[yypt-0].item.([]ast.TableLock),\n\t\t\t}\n\t\t}\n\tcase 1973:\n\t\t{\n\t\t\tparser.yyVAL.item = ast.TableLock{\n\t\t\t\tTable: yyS[yypt-1].item.(*ast.TableName),\n\t\t\t\tType:  yyS[yypt-0].item.(model.TableLockType),\n\t\t\t}\n\t\t}\n\tcase 1974:\n\t\t{\n\t\t\tparser.yyVAL.item = model.TableLockRead\n\t\t}\n\tcase 1975:\n\t\t{\n\t\t\tparser.yyVAL.item = model.TableLockReadLocal\n\t\t}\n\tcase 1976:\n\t\t{\n\t\t\tparser.yyVAL.item = model.TableLockWrite\n\t\t}\n\tcase 1977:\n\t\t{\n\t\t\tparser.yyVAL.item = model.TableLockWriteLocal\n\t\t}\n\tcase 1978:\n\t\t{\n\t\t\tparser.yyVAL.item = []ast.TableLock{yyS[yypt-0].item.(ast.TableLock)}\n\t\t}\n\tcase 1979:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-2].item.([]ast.TableLock), yyS[yypt-0].item.(ast.TableLock))\n\t\t}\n\tcase 1980:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.KillStmt{\n\t\t\t\tConnectionID:  getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t\tTiDBExtension: yyS[yypt-1].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1981:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.KillStmt{\n\t\t\t\tConnectionID:  getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t\tTiDBExtension: yyS[yypt-2].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1982:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.KillStmt{\n\t\t\t\tConnectionID:  getUint64FromNUM(yyS[yypt-0].item),\n\t\t\t\tQuery:         true,\n\t\t\t\tTiDBExtension: yyS[yypt-2].item.(bool),\n\t\t\t}\n\t\t}\n\tcase 1983:\n\t\t{\n\t\t\tparser.yyVAL.item = false\n\t\t}\n\tcase 1984:\n\t\t{\n\t\t\tparser.yyVAL.item = true\n\t\t}\n\tcase 1985:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.LoadStatsStmt{\n\t\t\t\tPath: yyS[yypt-0].ident,\n\t\t\t}\n\t\t}\n\tcase 1986:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.CreateSequenceStmt{\n\t\t\t\tIsTemporary: yyS[yypt-5].item.(bool),\n\t\t\t\tIfNotExists: yyS[yypt-3].item.(bool),\n\t\t\t\tName:        yyS[yypt-2].item.(*ast.TableName),\n\t\t\t\tSeqOptions:  yyS[yypt-1].item.([]*ast.SequenceOption),\n\t\t\t\tTblOptions:  yyS[yypt-0].item.([]*ast.TableOption),\n\t\t\t}\n\t\t}\n\tcase 1987:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.SequenceOption{}\n\t\t}\n\tcase 1989:\n\t\t{\n\t\t\tparser.yyVAL.item = []*ast.SequenceOption{yyS[yypt-0].item.(*ast.SequenceOption)}\n\t\t}\n\tcase 1990:\n\t\t{\n\t\t\tparser.yyVAL.item = append(yyS[yypt-1].item.([]*ast.SequenceOption), yyS[yypt-0].item.(*ast.SequenceOption))\n\t\t}\n\tcase 1991:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceOptionIncrementBy, IntValue: yyS[yypt-0].item.(int64)}\n\t\t}\n\tcase 1992:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceOptionIncrementBy, IntValue: yyS[yypt-0].item.(int64)}\n\t\t}\n\tcase 1993:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceStartWith, IntValue: yyS[yypt-0].item.(int64)}\n\t\t}\n\tcase 1994:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceStartWith, IntValue: yyS[yypt-0].item.(int64)}\n\t\t}\n\tcase 1995:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceMinValue, IntValue: yyS[yypt-0].item.(int64)}\n\t\t}\n\tcase 1996:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceNoMinValue}\n\t\t}\n\tcase 1997:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceNoMinValue}\n\t\t}\n\tcase 1998:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceMaxValue, IntValue: yyS[yypt-0].item.(int64)}\n\t\t}\n\tcase 1999:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceNoMaxValue}\n\t\t}\n\tcase 2000:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceNoMaxValue}\n\t\t}\n\tcase 2001:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceCache, IntValue: yyS[yypt-0].item.(int64)}\n\t\t}\n\tcase 2002:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceNoCache}\n\t\t}\n\tcase 2003:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceNoCache}\n\t\t}\n\tcase 2004:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceCycle}\n\t\t}\n\tcase 2005:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceNoCycle}\n\t\t}\n\tcase 2006:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceNoCycle}\n\t\t}\n\tcase 2007:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceOrder}\n\t\t}\n\tcase 2008:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceNoOrder}\n\t\t}\n\tcase 2009:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.SequenceOption{Tp: ast.SequenceNoOrder}\n\t\t}\n\tcase 2010:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(int64)\n\t\t}\n\tcase 2011:\n\t\t{\n\t\t\tparser.yyVAL.item = yyS[yypt-0].item.(int64)\n\t\t}\n\tcase 2012:\n\t\t{\n\t\t\tparser.yyVAL.item = -yyS[yypt-0].item.(int64)\n\t\t}\n\tcase 2013:\n\t\t{\n\t\t\tparser.yyVAL.statement = &ast.DropSequenceStmt{\n\t\t\t\tIsTemporary: yyS[yypt-3].item.(bool),\n\t\t\t\tIfExists:    yyS[yypt-1].item.(bool),\n\t\t\t\tSequences:   yyS[yypt-0].item.([]*ast.TableName),\n\t\t\t}\n\t\t}\n\tcase 2014:\n\t\t{\n\t\t\tx := &ast.IndexAdviseStmt{\n\t\t\t\tPath:       yyS[yypt-3].ident,\n\t\t\t\tMaxMinutes: yyS[yypt-2].item.(uint64),\n\t\t\t}\n\t\t\tif yyS[yypt-5].item != nil {\n\t\t\t\tx.IsLocal = true\n\t\t\t}\n\t\t\tif yyS[yypt-1].item != nil {\n\t\t\t\tx.MaxIndexNum = yyS[yypt-1].item.(*ast.MaxIndexNumClause)\n\t\t\t}\n\t\t\tif yyS[yypt-0].item != nil {\n\t\t\t\tx.LinesInfo = yyS[yypt-0].item.(*ast.LinesClause)\n\t\t\t}\n\t\t\tparser.yyVAL.statement = x\n\t\t}\n\tcase 2015:\n\t\t{\n\t\t\tparser.yyVAL.item = uint64(ast.UnspecifiedSize)\n\t\t}\n\tcase 2016:\n\t\t{\n\t\t\tparser.yyVAL.item = getUint64FromNUM(yyS[yypt-0].item)\n\t\t}\n\tcase 2017:\n\t\t{\n\t\t\tparser.yyVAL.item = nil\n\t\t}\n\tcase 2018:\n\t\t{\n\t\t\tparser.yyVAL.item = &ast.MaxIndexNumClause{\n\t\t\t\tPerTable: yyS[yypt-1].item.(uint64),\n\t\t\t\tPerDB:    yyS[yypt-0].item.(uint64),\n\t\t\t}\n\t\t}\n\tcase 2019:\n\t\t{\n\t\t\tparser.yyVAL.item = uint64(ast.UnspecifiedSize)\n\t\t}\n\tcase 2020:\n\t\t{\n\t\t\tparser.yyVAL.item = getUint64FromNUM(yyS[yypt-0].item)\n\t\t}\n\tcase 2021:\n\t\t{\n\t\t\tparser.yyVAL.item = uint64(ast.UnspecifiedSize)\n\t\t}\n\tcase 2022:\n\t\t{\n\t\t\tparser.yyVAL.item = getUint64FromNUM(yyS[yypt-0].item)\n\t\t}\n\n\t}\n\n\tif yyEx != nil && yyEx.Reduced(r, exState, parser.yyVAL) {\n\t\treturn -1\n\t}\n\tgoto yystack /* stack new state and value */\n}\n"
  },
  {
    "path": "pkg/parser/parser.y",
    "content": "%{\n// Copyright 2013 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Initial yacc source generated by ebnf2y[1]\n// at 2013-10-04 23:10:47.861401015 +0200 CEST\n//\n//  $ ebnf2y -o ql.y -oe ql.ebnf -start StatementList -pkg ql -p _\n//\n//   [1]: http://github.com/cznic/ebnf2y\n\n// Modified by Ant Group in 2023\n\npackage parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\t\"github.com/secretflow/scql/pkg/parser/auth\"\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/types\"\n)\n\n%}\n\n%union {\n\toffset int // offset\n\titem interface{}\n\tident string\n\texpr ast.ExprNode\n\tstatement ast.StmtNode\n}\n\n%token\t<ident>\n\n\t/*yy:token \"%c\"     */\n\tidentifier \"identifier\"\n\n\t/*yy:token \"_%c\"    */\n\tunderscoreCS \"UNDERSCORE_CHARSET\"\n\n\t/*yy:token \"\\\"%c\\\"\" */\n\tstringLit          \"string literal\"\n\tsingleAtIdentifier \"identifier with single leading at\"\n\tdoubleAtIdentifier \"identifier with double leading at\"\n\tinvalid            \"a special token never used by parser, used by lexer to indicate error\"\n\thintComment        \"an optimizer hint\"\n\tandand             \"&&\"\n\tpipes              \"||\"\n\n\t/* The following tokens belong to ODBCDateTimeType. */\n\todbcDateType      \"d\"\n\todbcTimeType      \"t\"\n\todbcTimestampType \"ts\"\n\n\t/* The following tokens belong to ReservedKeyword. Notice: make sure these tokens are contained in ReservedKeyword. */\n\tadd               \"ADD\"\n\tall               \"ALL\"\n\talter             \"ALTER\"\n\tanalyze           \"ANALYZE\"\n\tand               \"AND\"\n\tas                \"AS\"\n\tasc               \"ASC\"\n\tbetween           \"BETWEEN\"\n\tbigIntType        \"BIGINT\"\n\tbinaryType        \"BINARY\"\n\tblobType          \"BLOB\"\n\tboth              \"BOTH\"\n\tby                \"BY\"\n\tcascade           \"CASCADE\"\n\tcaseKwd           \"CASE\"\n\tchange            \"CHANGE\"\n\tcharacter         \"CHARACTER\"\n\tcharType          \"CHAR\"\n\tcheck             \"CHECK\"\n\tcollate           \"COLLATE\"\n\tcolumn            \"COLUMN\"\n\tconstraint        \"CONSTRAINT\"\n\tconvert           \"CONVERT\"\n\tcreate            \"CREATE\"\n\tcross             \"CROSS\"\n\tcumeDist          \"CUME_DIST\"\n\tcurrentDate       \"CURRENT_DATE\"\n\tcurrentTime       \"CURRENT_TIME\"\n\tcurrentTs         \"CURRENT_TIMESTAMP\"\n\tcurrentUser       \"CURRENT_USER\"\n\tcurrentRole       \"CURRENT_ROLE\"\n\tdatabase          \"DATABASE\"\n\tdatabases         \"DATABASES\"\n\tdayHour           \"DAY_HOUR\"\n\tdayMicrosecond    \"DAY_MICROSECOND\"\n\tdayMinute         \"DAY_MINUTE\"\n\tdaySecond         \"DAY_SECOND\"\n\tdecimalType       \"DECIMAL\"\n\tdefaultKwd        \"DEFAULT\"\n\tdelayed           \"DELAYED\"\n\tdeleteKwd         \"DELETE\"\n\tdenseRank         \"DENSE_RANK\"\n\tdesc              \"DESC\"\n\tdescribe          \"DESCRIBE\"\n\tdistinct          \"DISTINCT\"\n\tdistinctRow       \"DISTINCTROW\"\n\tdiv               \"DIV\"\n\tdoubleType        \"DOUBLE\"\n\tdrop              \"DROP\"\n\tdual              \"DUAL\"\n\telseKwd           \"ELSE\"\n\tenclosed          \"ENCLOSED\"\n\terrorKwd          \"ERROR\"\n\tescaped           \"ESCAPED\"\n\texists            \"EXISTS\"\n\texplain           \"EXPLAIN\"\n\texcept            \"EXCEPT\"\n\tfalseKwd          \"FALSE\"\n\tfirstValue        \"FIRST_VALUE\"\n\tfloatType         \"FLOAT\"\n\tforKwd            \"FOR\"\n\tforce             \"FORCE\"\n\tforeign           \"FOREIGN\"\n\tfrom              \"FROM\"\n\tfulltext          \"FULLTEXT\"\n\tgenerated         \"GENERATED\"\n\tgeneral           \"GENERAL\"\n\tgrant             \"GRANT\"\n\tgroup             \"GROUP\"\n\tgroups            \"GROUPS\"\n\thaving            \"HAVING\"\n\thighPriority      \"HIGH_PRIORITY\"\n\thourMicrosecond   \"HOUR_MICROSECOND\"\n\thourMinute        \"HOUR_MINUTE\"\n\thourSecond        \"HOUR_SECOND\"\n\tifKwd             \"IF\"\n\tignore            \"IGNORE\"\n\tin                \"IN\"\n\tindex             \"INDEX\"\n\tinfile            \"INFILE\"\n\tinner             \"INNER\"\n\tintegerType       \"INTEGER\"\n\tinterval          \"INTERVAL\"\n\tinto              \"INTO\"\n\toutfile           \"OUTFILE\"\n\tis                \"IS\"\n\tinsert            \"INSERT\"\n\tintType           \"INT\"\n\tint1Type          \"INT1\"\n\tint2Type          \"INT2\"\n\tint3Type          \"INT3\"\n\tint4Type          \"INT4\"\n\tint8Type          \"INT8\"\n\tjoin              \"JOIN\"\n\tkey               \"KEY\"\n\tkeys              \"KEYS\"\n\tkill              \"KILL\"\n\tlag               \"LAG\"\n\tlastValue         \"LAST_VALUE\"\n\tlead              \"LEAD\"\n\tleading           \"LEADING\"\n\tleft              \"LEFT\"\n\tlike              \"LIKE\"\n\tlimit             \"LIMIT\"\n\tlines             \"LINES\"\n\tlinear            \"LINEAR\"\n\tload              \"LOAD\"\n\tlocalTime         \"LOCALTIME\"\n\tlocalTs           \"LOCALTIMESTAMP\"\n\tlock              \"LOCK\"\n\tlongblobType      \"LONGBLOB\"\n\tlongtextType      \"LONGTEXT\"\n\tlowPriority       \"LOW_PRIORITY\"\n\tmatch             \"MATCH\"\n\tmaxValue          \"MAXVALUE\"\n\tmediumblobType    \"MEDIUMBLOB\"\n\tmediumIntType     \"MEDIUMINT\"\n\tmediumtextType    \"MEDIUMTEXT\"\n\tminuteMicrosecond \"MINUTE_MICROSECOND\"\n\tminuteSecond      \"MINUTE_SECOND\"\n\tmod               \"MOD\"\n\tnot               \"NOT\"\n\tnoWriteToBinLog   \"NO_WRITE_TO_BINLOG\"\n\tnthValue          \"NTH_VALUE\"\n\tntile             \"NTILE\"\n\tnull              \"NULL\"\n\tnumericType       \"NUMERIC\"\n\tnvarcharType      \"NVARCHAR\"\n\ton                \"ON\"\n\toptimize          \"OPTIMIZE\"\n\toption            \"OPTION\"\n\toptionally        \"OPTIONALLY\"\n\tor                \"OR\"\n\torder             \"ORDER\"\n\touter             \"OUTER\"\n\tover              \"OVER\"\n\tpackKeys          \"PACK_KEYS\"\n\tpartition         \"PARTITION\"\n\tparser            \"PARSER\"\n\tpercentRank       \"PERCENT_RANK\"\n\tprecisionType     \"PRECISION\"\n\tprimary           \"PRIMARY\"\n\tprocedure         \"PROCEDURE\"\n\tshardRowIDBits    \"SHARD_ROW_ID_BITS\"\n\tpreSplitRegions   \"PRE_SPLIT_REGIONS\"\n\trangeKwd          \"RANGE\"\n\trank              \"RANK\"\n\tread              \"READ\"\n\trealType          \"REAL\"\n\treferences        \"REFERENCES\"\n\tregexpKwd         \"REGEXP\"\n\trename            \"RENAME\"\n\trepeat            \"REPEAT\"\n\treplace           \"REPLACE\"\n\trequire           \"REQUIRE\"\n\trestrict          \"RESTRICT\"\n\trevoke            \"REVOKE\"\n\tright             \"RIGHT\"\n\trlike             \"RLIKE\"\n\trow               \"ROW\"\n\trows              \"ROWS\"\n\trowNumber         \"ROW_NUMBER\"\n\tsecondMicrosecond \"SECOND_MICROSECOND\"\n\tselectKwd         \"SELECT\"\n\tset               \"SET\"\n\tshow              \"SHOW\"\n\tsmallIntType      \"SMALLINT\"\n\tspatial           \"SPATIAL\"\n\tsql               \"SQL\"\n\tsqlBigResult      \"SQL_BIG_RESULT\"\n\tsqlCalcFoundRows  \"SQL_CALC_FOUND_ROWS\"\n\tsqlSmallResult    \"SQL_SMALL_RESULT\"\n\tssl               \"SSL\"\n\tstarting          \"STARTING\"\n\tstraightJoin      \"STRAIGHT_JOIN\"\n\ttableKwd          \"TABLE\"\n\tstored            \"STORED\"\n\tterminated        \"TERMINATED\"\n\tthen              \"THEN\"\n\ttinyblobType      \"TINYBLOB\"\n\ttinyIntType       \"TINYINT\"\n\ttinytextType      \"TINYTEXT\"\n\tto                \"TO\"\n\ttrailing          \"TRAILING\"\n\ttrigger           \"TRIGGER\"\n\ttrueKwd           \"TRUE\"\n\tunique            \"UNIQUE\"\n\tunion             \"UNION\"\n\tunlock            \"UNLOCK\"\n\tunsigned          \"UNSIGNED\"\n\tuntil             \"UNTIL\"\n\tupdate            \"UPDATE\"\n\tusage             \"USAGE\"\n\tuse               \"USE\"\n\tusing             \"USING\"\n\tutcDate           \"UTC_DATE\"\n\tutcTimestamp      \"UTC_TIMESTAMP\"\n\tutcTime           \"UTC_TIME\"\n\tvalues            \"VALUES\"\n\tlong              \"LONG\"\n\tvarcharType       \"VARCHAR\"\n\tvarcharacter      \"VARCHARACTER\"\n\tvarbinaryType     \"VARBINARY\"\n\tvarying           \"VARYING\"\n\tvirtual           \"VIRTUAL\"\n\twhen              \"WHEN\"\n\twhere             \"WHERE\"\n\twrite             \"WRITE\"\n\twindow            \"WINDOW\"\n\twith              \"WITH\"\n\txor               \"XOR\"\n\tyearMonth         \"YEAR_MONTH\"\n\tzerofill          \"ZEROFILL\"\n\tnatural           \"NATURAL\"\n\n\t/* The following tokens belong to UnReservedKeyword. Notice: make sure these tokens are contained in UnReservedKeyword. */\n\taccount                 \"ACCOUNT\"\n\taction                  \"ACTION\"\n\tadvise                  \"ADVISE\"\n\tafter                   \"AFTER\"\n\tagainst                 \"AGAINST\"\n\talways                  \"ALWAYS\"\n\talgorithm               \"ALGORITHM\"\n\tany                     \"ANY\"\n\tascii                   \"ASCII\"\n\tautoIncrement           \"AUTO_INCREMENT\"\n\tautoRandom              \"AUTO_RANDOM\"\n\tavgRowLength            \"AVG_ROW_LENGTH\"\n\tavg                     \"AVG\"\n\tbegin                   \"BEGIN\"\n\tbinlog                  \"BINLOG\"\n\tbitType                 \"BIT\"\n\tblock                   \"BLOCK\"\n\tbooleanType             \"BOOLEAN\"\n\tboolType                \"BOOL\"\n\tbtree                   \"BTREE\"\n\tbyteType                \"BYTE\"\n\tcache                   \"CACHE\"\n\tcascaded                \"CASCADED\"\n\tcapture                 \"CAPTURE\"\n\tcharsetKwd              \"CHARSET\"\n\tchecksum                \"CHECKSUM\"\n\tcipher                  \"CIPHER\"\n\tcleanup                 \"CLEANUP\"\n\tclient                  \"CLIENT\"\n\tcoalesce                \"COALESCE\"\n\tcollation               \"COLLATION\"\n\tcolumnFormat            \"COLUMN_FORMAT\"\n\tcolumns                 \"COLUMNS\"\n\tcomment                 \"COMMENT\"\n\tcommit                  \"COMMIT\"\n\tcommitted               \"COMMITTED\"\n\tcompact                 \"COMPACT\"\n\tcompressed              \"COMPRESSED\"\n\tcompression             \"COMPRESSION\"\n\tconnection              \"CONNECTION\"\n\tconsistent              \"CONSISTENT\"\n\tcontext                 \"CONTEXT\"\n\tcpu                     \"CPU\"\n\tcurrent                 \"CURRENT\"\n\tcycle                   \"CYCLE\"\n\tday                     \"DAY\"\n\tdata                    \"DATA\"\n\tdateType                \"DATE\"\n\tdatetimeType            \"DATETIME\"\n\tdeallocate              \"DEALLOCATE\"\n\tdefiner                 \"DEFINER\"\n\tdelayKeyWrite           \"DELAY_KEY_WRITE\"\n\tdirectory               \"DIRECTORY\"\n\tdisable                 \"DISABLE\"\n\tdiscard                 \"DISCARD\"\n\tdisk                    \"DISK\"\n\tdo                      \"DO\"\n\tduplicate               \"DUPLICATE\"\n\tdynamic                 \"DYNAMIC\"\n\tenable                  \"ENABLE\"\n\tencryption              \"ENCRYPTION\"\n\tend                     \"END\"\n\tengine                  \"ENGINE\"\n\tengines                 \"ENGINES\"\n\tenum                    \"ENUM\"\n\tevent                   \"EVENT\"\n\tevents                  \"EVENTS\"\n\tevolve                  \"EVOLVE\"\n\tescape                  \"ESCAPE\"\n\texchange                \"EXCHANGE\"\n\texclusive               \"EXCLUSIVE\"\n\texecute                 \"EXECUTE\"\n\texpansion               \"EXPANSION\"\n\texpire                  \"EXPIRE\"\n\textended                \"EXTENDED\"\n\tfaultsSym               \"FAULTS\"\n\tfields                  \"FIELDS\"\n\tfile                    \"FILE\"\n\tfirst                   \"FIRST\"\n\tfixed                   \"FIXED\"\n\tflush                   \"FLUSH\"\n\tfollowing               \"FOLLOWING\"\n\tformat                  \"FORMAT\"\n\tfull                    \"FULL\"\n\tfunction                \"FUNCTION\"\n\tgrants                  \"GRANTS\"\n\thash                    \"HASH\"\n\thistory                 \"HISTORY\"\n\thosts                   \"HOSTS\"\n\thour                    \"HOUR\"\n\tidentified              \"IDENTIFIED\"\n\timportKwd               \"IMPORT\"\n\tinsertMethod            \"INSERT_METHOD\"\n\tisolation               \"ISOLATION\"\n\tissuer                  \"ISSUER\"\n\tincrement               \"INCREMENT\"\n\tincremental             \"INCREMENTAL\"\n\tindexes                 \"INDEXES\"\n\tinvisible               \"INVISIBLE\"\n\tinvoker                 \"INVOKER\"\n\tio                      \"IO\"\n\tipc                     \"IPC\"\n\tjsonType                \"JSON\"\n\tkeyBlockSize            \"KEY_BLOCK_SIZE\"\n\tlabels                  \"LABELS\"\n\tlanguage                \"LANGUAGE\"\n\tlast                    \"LAST\"\n\tless                    \"LESS\"\n\tlevel                   \"LEVEL\"\n\tlist                    \"LIST\"\n\tlocal                   \"LOCAL\"\n\tlocation                \"LOCATION\"\n\tlogs                    \"LOGS\"\n\tmaster                  \"MASTER\"\n\tmicrosecond             \"MICROSECOND\"\n\tminute                  \"MINUTE\"\n\tmode                    \"MODE\"\n\tmodify                  \"MODIFY\"\n\tmonth                   \"MONTH\"\n\tmaxRows                 \"MAX_ROWS\"\n\tmaxConnectionsPerHour   \"MAX_CONNECTIONS_PER_HOUR\"\n\tmaxQueriesPerHour       \"MAX_QUERIES_PER_HOUR\"\n\tmaxUpdatesPerHour       \"MAX_UPDATES_PER_HOUR\"\n\tmaxUserConnections      \"MAX_USER_CONNECTIONS\"\n\tmemory                  \"MEMORY\"\n\tmerge                   \"MERGE\"\n\tminRows                 \"MIN_ROWS\"\n\tminValue                \"MINVALUE\"\n\tmax_minutes             \"MAX_MINUTES\"\n\tmax_idxnum              \"MAX_IDXNUM\"\n\tnames                   \"NAMES\"\n\tnational                \"NATIONAL\"\n\tncharType               \"NCHAR\"\n\tnever                   \"NEVER\"\n\tno                      \"NO\"\n\tnocache                 \"NOCACHE\"\n\tnocycle                 \"NOCYCLE\"\n\tnodegroup               \"NODEGROUP\"\n\tnomaxvalue              \"NOMAXVALUE\"\n\tnominvalue              \"NOMINVALUE\"\n\tnone                    \"NONE\"\n\tnoorder                 \"NOORDER\"\n\tnulls                   \"NULLS\"\n\toffset                  \"OFFSET\"\n\tonly                    \"ONLY\"\n\tpageSym                 \"PAGE\"\n\tpartyCode               \"PARTY_CODE\"\n\tpassword                \"PASSWORD\"\n\tpartial                 \"PARTIAL\"\n\tpartitioning            \"PARTITIONING\"\n\tpartitions              \"PARTITIONS\"\n\tpipesAsOr\n\tplugins                 \"PLUGINS\"\n\tpreceding               \"PRECEDING\"\n\tprepare                 \"PREPARE\"\n\tprivileges              \"PRIVILEGES\"\n\tprocess                 \"PROCESS\"\n\tprocesslist             \"PROCESSLIST\"\n\tprofile                 \"PROFILE\"\n\tprofiles                \"PROFILES\"\n\tper_table               \"PER_TABLE\"\n\tper_db                  \"PER_DB\"\n\tquarter                 \"QUARTER\"\n\tquery                   \"QUERY\"\n\tqueries                 \"QUERIES\"\n\tquick                   \"QUICK\"\n\trebuild                 \"REBUILD\"\n\trecover                 \"RECOVER\"\n\tredundant               \"REDUNDANT\"\n\treload                  \"RELOAD\"\n\tremove                  \"REMOVE\"\n\treorganize              \"REORGANIZE\"\n\trepair                  \"REPAIR\"\n\trepeatable              \"REPEATABLE\"\n\trespect                 \"RESPECT\"\n\treplica                 \"REPLICA\"\n\treplication             \"REPLICATION\"\n\treverse                 \"REVERSE\"\n\trole                    \"ROLE\"\n\trollback                \"ROLLBACK\"\n\troutine                 \"ROUTINE\"\n\trowCount                \"ROW_COUNT\"\n\trowFormat               \"ROW_FORMAT\"\n\trtree                   \"RTREE\"\n\tsecond                  \"SECOND\"\n\tsecondaryEngine         \"SECONDARY_ENGINE\"\n\tsecondaryLoad           \"SECONDARY_LOAD\"\n\tsecondaryUnload         \"SECONDARY_UNLOAD\"\n\tsecurity                \"SECURITY\"\n\tseparator               \"SEPARATOR\"\n\tsequence                \"SEQUENCE\"\n\tserial                  \"SERIAL\"\n\tserializable            \"SERIALIZABLE\"\n\tsession                 \"SESSION\"\n\tshare                   \"SHARE\"\n\tshared                  \"SHARED\"\n\tshutdown                \"SHUTDOWN\"\n\tsigned                  \"SIGNED\"\n\tsimple                  \"SIMPLE\"\n\tslave                   \"SLAVE\"\n\tslow                    \"SLOW\"\n\tsnapshot                \"SNAPSHOT\"\n\tsqlBufferResult         \"SQL_BUFFER_RESULT\"\n\tsqlCache                \"SQL_CACHE\"\n\tsqlNoCache              \"SQL_NO_CACHE\"\n\tsqlTsiDay               \"SQL_TSI_DAY\"\n\tsqlTsiHour              \"SQL_TSI_HOUR\"\n\tsqlTsiMinute            \"SQL_TSI_MINUTE\"\n\tsqlTsiMonth             \"SQL_TSI_MONTH\"\n\tsqlTsiQuarter           \"SQL_TSI_QUARTER\"\n\tsqlTsiSecond            \"SQL_TSI_SECOND\"\n\tsqlTsiWeek              \"SQL_TSI_WEEK\"\n\tsqlTsiYear              \"SQL_TSI_YEAR\"\n\tstart                   \"START\"\n\tstatsAutoRecalc         \"STATS_AUTO_RECALC\"\n\tstatsPersistent         \"STATS_PERSISTENT\"\n\tstatsSamplePages        \"STATS_SAMPLE_PAGES\"\n\tstatus                  \"STATUS\"\n\tstorage                 \"STORAGE\"\n\tswaps                   \"SWAPS\"\n\tswitchesSym             \"SWITCHES\"\n\tsystemTime              \"SYSTEM_TIME\"\n\topen                    \"OPEN\"\n\tsource                  \"SOURCE\"\n\tsubject                 \"SUBJECT\"\n\tsubpartition            \"SUBPARTITION\"\n\tsubpartitions           \"SUBPARTITIONS\"\n\tsuper                   \"SUPER\"\n\tsome                    \"SOME\"\n\tglobal                  \"GLOBAL\"\n\ttableChecksum           \"TABLE_CHECKSUM\"\n\ttables                  \"TABLES\"\n\ttablespace              \"TABLESPACE\"\n\ttemporary               \"TEMPORARY\"\n\ttemptable               \"TEMPTABLE\"\n\ttextType                \"TEXT\"\n\tthan                    \"THAN\"\n\ttimeType                \"TIME\"\n\ttimestampType           \"TIMESTAMP\"\n\ttrace                   \"TRACE\"\n\ttraditional             \"TRADITIONAL\"\n\ttransaction             \"TRANSACTION\"\n\ttriggers                \"TRIGGERS\"\n\ttruncate                \"TRUNCATE\"\n\ttp                      \"TYPE\"\n\tunbounded               \"UNBOUNDED\"\n\tuncommitted             \"UNCOMMITTED\"\n\tunicodeSym              \"UNICODE\"\n\tunknown                 \"UNKNOWN\"\n\tuser                    \"USER\"\n\tundefined               \"UNDEFINED\"\n\tvalidation              \"VALIDATION\"\n\tvalue                   \"VALUE\"\n\tvariables               \"VARIABLES\"\n\tview                    \"VIEW\"\n\tvisible                 \"VISIBLE\"\n\tbinding                 \"BINDING\"\n\tbindings                \"BINDINGS\"\n\twarnings                \"WARNINGS\"\n\twithout                 \"WITHOUT\"\n\tidentSQLErrors          \"ERRORS\"\n\tweek                    \"WEEK\"\n\tyearType                \"YEAR\"\n\tx509                    \"X509\"\n\tenforced                \"ENFORCED\"\n\tnowait                  \"NOWAIT\"\n\tplaintext               \"PLAINTEXT\"\n\tplaintextAfterJoin      \"PLAINTEXT_AFTER_JOIN\"\n\tplaintextAsJoinPayload  \"PLAINTEXT_AS_JOIN_PAYLOAD\"\n\trevealRank              \"REVEAL_RANK\"\n\tplaintextAfterGroupBy   \"PLAINTEXT_AFTER_GROUP_BY\"\n\tplaintextAfterCompare   \"PLAINTEXT_AFTER_COMPARE\"\n\tplaintextAfterAggregate \"PLAINTEXT_AFTER_AGGREGATE\"\n\tencryptedOnly           \"ENCRYPTED_ONLY\"\n\ttokenWord               \"TOKEN\"\n\tendpoint                \"ENDPOINT\"\n\trefTable                \"REF_TABLE\"\n\tdbType                  \"DB_TYPE\"\n\n\t/* The following tokens belong to NotKeywordToken. Notice: make sure these tokens are contained in NotKeywordToken. */\n\taddDate               \"ADDDATE\"\n\tbitAnd                \"BIT_AND\"\n\tbitOr                 \"BIT_OR\"\n\tbitXor                \"BIT_XOR\"\n\tbound                 \"BOUND\"\n\tcast                  \"CAST\"\n\tcopyKwd               \"COPY\"\n\tcount                 \"COUNT\"\n\tcurTime               \"CURTIME\"\n\tdateAdd               \"DATE_ADD\"\n\tdateSub               \"DATE_SUB\"\n\texact                 \"EXACT\"\n\textract               \"EXTRACT\"\n\tflashback             \"FLASHBACK\"\n\tgetFormat             \"GET_FORMAT\"\n\tgroupConcat           \"GROUP_CONCAT\"\n\tnext_row_id           \"NEXT_ROW_ID\"\n\tinplace               \"INPLACE\"\n\tinstant               \"INSTANT\"\n\tinternal              \"INTERNAL\"\n\tmin                   \"MIN\"\n\tmax                   \"MAX\"\n\tnow                   \"NOW\"\n\tpercentileDisc        \"PERCENTILE_DISC\"\n\tposition              \"POSITION\"\n\trecent                \"RECENT\"\n\tstaleness             \"STALENESS\"\n\tstd                   \"STD\"\n\tstddev                \"STDDEV\"\n\tstddevPop             \"STDDEV_POP\"\n\tstddevSamp            \"STDDEV_SAMP\"\n\tstrong                \"STRONG\"\n\tsubDate               \"SUBDATE\"\n\tsum                   \"SUM\"\n\tsubstring             \"SUBSTRING\"\n\ttimestampAdd          \"TIMESTAMPADD\"\n\ttimestampDiff         \"TIMESTAMPDIFF\"\n\ttokudbDefault         \"TOKUDB_DEFAULT\"\n\ttokudbFast            \"TOKUDB_FAST\"\n\ttokudbLzma            \"TOKUDB_LZMA\"\n\ttokudbQuickLZ         \"TOKUDB_QUICKLZ\"\n\ttokudbSnappy          \"TOKUDB_SNAPPY\"\n\ttokudbSmall           \"TOKUDB_SMALL\"\n\ttokudbUncompressed    \"TOKUDB_UNCOMPRESSED\"\n\ttokudbZlib            \"TOKUDB_ZLIB\"\n\ttop                   \"TOP\"\n\ttrim                  \"TRIM\"\n\tvariance              \"VARIANCE\"\n\tvarPop                \"VAR_POP\"\n\tvarSamp               \"VAR_SAMP\"\n\texprPushdownBlacklist \"EXPR_PUSHDOWN_BLACKLIST\"\n\toptRuleBlacklist      \"OPT_RULE_BLACKLIST\"\n\n\t/* The following tokens belong to TiDBKeyword. Notice: make sure these tokens are contained in TiDBKeyword. */\n\tadmin                 \"ADMIN\"\n\tbuckets               \"BUCKETS\"\n\tbuiltins              \"BUILTINS\"\n\tcancel                \"CANCEL\"\n\tcmSketch              \"CMSKETCH\"\n\tddl                   \"DDL\"\n\tdepth                 \"DEPTH\"\n\tdrainer               \"DRAINER\"\n\tjobs                  \"JOBS\"\n\tjob                   \"JOB\"\n\tnodeID                \"NODE_ID\"\n\tnodeState             \"NODE_STATE\"\n\toptimistic            \"OPTIMISTIC\"\n\tpessimistic           \"PESSIMISTIC\"\n\tpump                  \"PUMP\"\n\tsamples               \"SAMPLES\"\n\tstats                 \"STATS\"\n\tstatsMeta             \"STATS_META\"\n\tstatsHistograms       \"STATS_HISTOGRAMS\"\n\tstatsBuckets          \"STATS_BUCKETS\"\n\tstatsHealthy          \"STATS_HEALTHY\"\n\ttidb                  \"TIDB\"\n\ttiFlash               \"TIFLASH\"\n\ttopn                  \"TOPN\"\n\tsplit                 \"SPLIT\"\n\twidth                 \"WIDTH\"\n\tregions               \"REGIONS\"\n\tregion                \"REGION\"\n\tleftMarker            \"{{\"\n\trightMarker           \"}}\"\n\tbuiltinAddDate\n\tbuiltinBitAnd\n\tbuiltinBitOr\n\tbuiltinBitXor\n\tbuiltinCast\n\tbuiltinCount\n\tbuiltinCurDate\n\tbuiltinCurTime\n\tbuiltinDateAdd\n\tbuiltinDateSub\n\tbuiltinExtract\n\tbuiltinGroupConcat\n\tbuiltinMax\n\tbuiltinMin\n\tbuiltinNow\n\tbuiltinPercentileDisc\n\tbuiltinPosition\n\tbuiltinSubDate\n\tbuiltinSubstring\n\tbuiltinSum\n\tbuiltinSysDate\n\tbuiltinStddevPop\n\tbuiltinStddevSamp\n\tbuiltinTrim\n\tbuiltinUser\n\tbuiltinVarPop\n\tbuiltinVarSamp\n\tbuiltinMedian\n\n%token\t<item>\n\n\t/*yy:token \"1.%d\"   */\n\tfloatLit \"floating-point literal\"\n\n\t/*yy:token \"1.%d\"   */\n\tdecLit \"decimal literal\"\n\n\t/*yy:token \"%d\"     */\n\tintLit \"integer literal\"\n\n\t/*yy:token \"%x\"     */\n\thexLit \"hexadecimal literal\"\n\n\t/*yy:token \"%b\"     */\n\tbitLit       \"bit literal\"\n\tandnot       \"&^\"\n\tassignmentEq \":=\"\n\teq           \"=\"\n\tge           \">=\"\n\tle           \"<=\"\n\tjss          \"->\"\n\tjuss         \"->>\"\n\tlsh          \"<<\"\n\tneq          \"!=\"\n\tneqSynonym   \"<>\"\n\tnulleq       \"<=>\"\n\trsh          \">>\"\n\n%token not2\n%type\t<expr>\n\tExpression             \"expression\"\n\tMaxValueOrExpression   \"maxvalue or expression\"\n\tBoolPri                \"boolean primary expression\"\n\tExprOrDefault          \"expression or default\"\n\tPredicateExpr          \"Predicate expression factor\"\n\tSetExpr                \"Set variable statement value's expression\"\n\tBitExpr                \"bit expression\"\n\tSimpleExpr             \"simple expression\"\n\tParamMarker            \"param marker expression\"\n\tSimpleIdent            \"Simple Identifier expression\"\n\tSumExpr                \"aggregate functions\"\n\tFunctionCallGeneric    \"Function call with Identifier\"\n\tFunctionCallKeyword    \"Function call with keyword as function name\"\n\tFunctionCallNonKeyword \"Function call with nonkeyword as function name\"\n\tLiteral                \"literal value\"\n\tVariable               \"User or system variable\"\n\tSystemVariable         \"System defined variable name\"\n\tUserVariable           \"User defined variable name\"\n\tSubSelect              \"Sub Select\"\n\tStringLiteral          \"text literal\"\n\tExpressionOpt          \"Optional expression\"\n\tSignedLiteral          \"Literal or NumLiteral with sign\"\n\tDefaultValueExpr       \"DefaultValueExpr(Now or Signed Literal)\"\n\tNowSymOptionFraction   \"NowSym with optional fraction part\"\n\tCharsetNameOrDefault   \"Character set name or default\"\n\n%type\t<statement>\n\tAdminStmt            \"Check table statement or show ddl statement\"\n\tAlterDatabaseStmt    \"Alter database statement\"\n\tAlterTableStmt       \"Alter table statement\"\n\tAlterUserStmt        \"Alter user statement\"\n\tAnalyzeTableStmt     \"Analyze table statement\"\n\tBeginTransactionStmt \"BEGIN TRANSACTION statement\"\n\tBinlogStmt           \"Binlog base64 statement\"\n\tCommitStmt           \"COMMIT statement\"\n\tCreateTableStmt      \"CREATE TABLE statement\"\n\tCreateViewStmt       \"CREATE VIEW  stetement\"\n\tCreateUserStmt       \"CREATE User statement\"\n\tCreateRoleStmt       \"CREATE Role statement\"\n\tCreateDatabaseStmt   \"Create Database Statement\"\n\tCreateIndexStmt      \"CREATE INDEX statement\"\n\tCreateBindingStmt    \"CREATE BINDING  statement\"\n\tCreateSequenceStmt   \"CREATE SEQUENCE statement\"\n\tDoStmt               \"Do statement\"\n\tDropDatabaseStmt     \"DROP DATABASE statement\"\n\tDropIndexStmt        \"DROP INDEX statement\"\n\tDropStatsStmt        \"DROP STATS statement\"\n\tDropTableStmt        \"DROP TABLE statement\"\n\tDropSequenceStmt     \"DROP SEQUENCE statement\"\n\tDropUserStmt         \"DROP USER\"\n\tDropRoleStmt         \"DROP ROLE\"\n\tDropViewStmt         \"DROP VIEW statement\"\n\tDropBindingStmt      \"DROP BINDING  statement\"\n\tDeallocateStmt       \"Deallocate prepared statement\"\n\tDeleteFromStmt       \"DELETE FROM statement\"\n\tEmptyStmt            \"empty statement\"\n\tExecuteStmt          \"Execute statement\"\n\tExplainStmt          \"EXPLAIN statement\"\n\tExplainableStmt      \"explainable statement\"\n\tFlushStmt            \"Flush statement\"\n\tFlashbackTableStmt   \"Flashback table statement\"\n\tGrantStmt            \"Grant statement\"\n\tGrantRoleStmt        \"Grant role statement\"\n\tInsertIntoStmt       \"INSERT INTO statement\"\n\tIndexAdviseStmt      \"INDEX ADVISE stetement\"\n\tKillStmt             \"Kill statement\"\n\tLoadDataStmt         \"Load data statement\"\n\tLoadStatsStmt        \"Load statistic statement\"\n\tLockTablesStmt       \"Lock tables statement\"\n\tPreparedStmt         \"PreparedStmt\"\n\tSelectStmt           \"SELECT statement\"\n\tRenameTableStmt      \"rename table statement\"\n\tReplaceIntoStmt      \"REPLACE INTO statement\"\n\tRecoverTableStmt     \"recover table statement\"\n\tRevokeStmt           \"Revoke statement\"\n\tRevokeRoleStmt       \"Revoke role statement\"\n\tRollbackStmt         \"ROLLBACK statement\"\n\tSplitRegionStmt      \"Split index region statement\"\n\tSetStmt              \"Set variable statement\"\n\tChangeStmt           \"Change statement\"\n\tSetRoleStmt          \"Set active role statement\"\n\tSetDefaultRoleStmt   \"Set default statement for some user\"\n\tShowStmt             \"Show engines/databases/tables/user/columns/warnings/status statement\"\n\tStatement            \"statement\"\n\tTraceStmt            \"TRACE statement\"\n\tTraceableStmt        \"traceable statement\"\n\tTruncateTableStmt    \"TRUNCATE TABLE statement\"\n\tUnlockTablesStmt     \"Unlock tables statement\"\n\tUpdateStmt           \"UPDATE statement\"\n\tUnionStmt            \"Union select state ment\"\n\tUseStmt              \"USE statement\"\n\tShutdownStmt         \"SHUTDOWN statement\"\n\n%type\t<item>\n\tAdminShowSlow                          \"Admin Show Slow statement\"\n\tAllOrPartitionNameList                 \"All or partition name list\"\n\tAlgorithmClause                        \"Alter table algorithm\"\n\tAlterTablePartitionOpt                 \"Alter table partition option\"\n\tAlterTableSpec                         \"Alter table specification\"\n\tAlterTableSpecList                     \"Alter table specification list\"\n\tAlterTableSpecListOpt                  \"Alter table specification list optional\"\n\tAnalyzeOption                          \"Analyze option\"\n\tAnalyzeOptionList                      \"Analyze option list\"\n\tAnalyzeOptionListOpt                   \"Optional analyze option list\"\n\tAnyOrAll                               \"Any or All for subquery\"\n\tAssignment                             \"assignment\"\n\tAssignmentList                         \"assignment list\"\n\tAssignmentListOpt                      \"assignment list opt\"\n\tAuthOption                             \"User auth option\"\n\tAuthString                             \"Password string value\"\n\tOptionalBraces                         \"optional braces\"\n\tCastType                               \"Cast function target type\"\n\tCharsetName                            \"Character set name\"\n\tClearPasswordExpireOptions             \"Clear password expire options\"\n\tCollationName                          \"Collation name\"\n\tColumnDef                              \"table column definition\"\n\tColumnDefList                          \"table column definition list\"\n\tColumnFormat                           \"Column format\"\n\tColumnName                             \"column name\"\n\tColumnNameOrUserVariable               \"column name or user variable\"\n\tColumnNameList                         \"column name list\"\n\tColumnNameOrUserVariableList           \"column name or user variable list\"\n\tColumnList                             \"column list\"\n\tColumnNameListOpt                      \"column name list opt\"\n\tColumnNameOrUserVarListOpt             \"column name or user vairiabe list opt\"\n\tColumnNameOrUserVarListOptWithBrackets \"column name or user variable list opt with brackets\"\n\tColumnSetValue                         \"insert statement set value by column name\"\n\tColumnSetValueList                     \"insert statement set value by column name list\"\n\tCompareOp                              \"Compare opcode\"\n\tColumnOption                           \"column definition option\"\n\tColumnOptionList                       \"column definition option list\"\n\tVirtualOrStored                        \"indicate generated column is stored or not\"\n\tColumnOptionListOpt                    \"optional column definition option list\"\n\tConnectionOption                       \"single connection options\"\n\tConnectionOptionList                   \"connection options for CREATE USER statement\"\n\tConnectionOptions                      \"optional connection options for CREATE USER statement\"\n\tConstraint                             \"table constraint\"\n\tConstraintElem                         \"table constraint element\"\n\tConstraintKeywordOpt                   \"Constraint Keyword or empty\"\n\tCreateSequenceOptionListOpt            \"create sequence list opt\"\n\tCreateTableOptionListOpt               \"create table option list opt\"\n\tCreateTableSelectOpt                   \"Select/Union statement in CREATE TABLE ... SELECT\"\n\tCreateViewSelectOpt                    \"Select/Union statement in CREATE VIEW ... AS SELECT\"\n\tDatabaseOption                         \"CREATE Database specification\"\n\tDatabaseOptionList                     \"CREATE Database specification list\"\n\tDatabaseOptionListOpt                  \"CREATE Database specification list opt\"\n\tDBName                                 \"Database Name\"\n\tDistinctOpt                            \"Explicit distinct option\"\n\tDefaultFalseDistinctOpt                \"Distinct option which defaults to false\"\n\tDefaultTrueDistinctOpt                 \"Distinct option which defaults to true\"\n\tBuggyDefaultFalseDistinctOpt           \"Distinct option which accepts DISTINCT ALL and defaults to false\"\n\tRequireClause                          \"Encrypted connections options\"\n\tRequireClauseOpt                       \"optional Encrypted connections options\"\n\tEqOpt                                  \"= or empty\"\n\tEscapedTableRef                        \"escaped table reference\"\n\tExplainFormatType                      \"explain format type\"\n\tExpressionList                         \"expression list\"\n\tMaxValueOrExpressionList               \"maxvalue or expression list\"\n\tExpressionListOpt                      \"expression list opt\"\n\tFuncDatetimePrecListOpt                \"Function datetime precision list opt\"\n\tFuncDatetimePrecList                   \"Function datetime precision list\"\n\tField                                  \"field expression\"\n\tFields                                 \"Fields clause\"\n\tFieldAsName                            \"Field alias name\"\n\tFieldAsNameOpt                         \"Field alias name opt\"\n\tFieldList                              \"field expression list\"\n\tFieldTerminator                        \"Field terminator\"\n\tFlushOption                            \"Flush option\"\n\tFulltextSearchModifierOpt              \"Fulltext modifier\"\n\tPluginNameList                         \"Plugin Name List\"\n\tTableRefsClause                        \"Table references clause\"\n\tFieldItem                              \"Field item for load data clause\"\n\tFieldItemList                          \"Field items for load data clause\"\n\tFuncDatetimePrec                       \"Function datetime precision\"\n\tGetFormatSelector                      \"{DATE|DATETIME|TIME|TIMESTAMP}\"\n\tGlobalScope                            \"The scope of variable\"\n\tGroupByClause                          \"GROUP BY clause\"\n\tHashString                             \"Hashed string\"\n\tHavingClause                           \"HAVING clause\"\n\tHandleRange                            \"handle range\"\n\tHandleRangeList                        \"handle range list\"\n\tIfExists                               \"If Exists\"\n\tIfNotExists                            \"If Not Exists\"\n\tIgnoreOptional                         \"IGNORE or empty\"\n\tIndexHint                              \"index hint\"\n\tIndexHintList                          \"index hint list\"\n\tIndexHintListOpt                       \"index hint list opt\"\n\tIndexHintScope                         \"index hint scope\"\n\tIndexHintType                          \"index hint type\"\n\tIndexInvisible                         \"index visible/invisible\"\n\tIndexKeyTypeOpt                        \"index key type\"\n\tIndexLockAndAlgorithmOpt               \"index lock and algorithm\"\n\tIndexName                              \"index name\"\n\tIndexNameAndTypeOpt                    \"index name and index type\"\n\tIndexNameList                          \"index name list\"\n\tIndexOption                            \"Index Option\"\n\tIndexOptionList                        \"Index Option List or empty\"\n\tIndexType                              \"index type\"\n\tIndexTypeName                          \"index type name\"\n\tIndexTypeOpt                           \"optional index type\"\n\tIndexPartSpecification                 \"Index column name or expression\"\n\tIndexPartSpecificationList             \"List of index column name or expression\"\n\tIndexPartSpecificationListOpt          \"Optional list of index column name or expression\"\n\tInsertValues                           \"Rest part of INSERT/REPLACE INTO statement\"\n\tJoinTable                              \"join table\"\n\tJoinType                               \"join type\"\n\tKillOrKillTiDB                         \"Kill or Kill TiDB\"\n\tLocationLabelList                      \"location label name list\"\n\tLikeEscapeOpt                          \"like escape option\"\n\tLikeTableWithOrWithoutParen            \"LIKE table_name or ( LIKE table_name )\"\n\tLimitClause                            \"LIMIT clause\"\n\tLimitOption                            \"Limit option could be integer or parameter marker.\"\n\tLines                                  \"Lines clause\"\n\tLinesTerminated                        \"Lines terminated by\"\n\tLoadDataSetSpecOpt                     \"Optional load data specification\"\n\tLoadDataSetList                        \"Load data specifications\"\n\tLoadDataSetItem                        \"Single load data specification\"\n\tLocalOpt                               \"Local opt\"\n\tLockClause                             \"Alter table lock clause\"\n\tLogTypeOpt                             \"Optional log type used in FLUSH statements\"\n\tNumLiteral                             \"Num/Int/Float/Decimal Literal\"\n\tNoWriteToBinLogAliasOpt                \"NO_WRITE_TO_BINLOG alias LOCAL or empty\"\n\tObjectType                             \"Grant statement object type\"\n\tOnDuplicateKeyUpdate                   \"ON DUPLICATE KEY UPDATE value list\"\n\tDuplicateOpt                           \"[IGNORE|REPLACE] in CREATE TABLE ... SELECT statement or LOAD DATA statement\"\n\tOptFull                                \"Full or empty\"\n\tOptTemporary                           \"TEMPORARY or empty\"\n\tOrder                                  \"ORDER BY clause optional collation specification\"\n\tOrderBy                                \"ORDER BY clause\"\n\tOrReplace                              \"or replace\"\n\tByItem                                 \"BY item\"\n\tOrderByOptional                        \"Optional ORDER BY clause optional\"\n\tByList                                 \"BY list\"\n\tAlterOrderItem                         \"Alter Order item\"\n\tAlterOrderList                         \"Alter Order list\"\n\tQuickOptional                          \"QUICK or empty\"\n\tPartitionDefinition                    \"Partition definition\"\n\tPartitionDefinitionList                \"Partition definition list\"\n\tPartitionDefinitionListOpt             \"Partition definition list option\"\n\tPartitionKeyAlgorithmOpt               \"ALGORITHM = n option for KEY partition\"\n\tPartitionMethod                        \"Partition method\"\n\tPartitionOpt                           \"Partition option\"\n\tPartitionNameList                      \"Partition name list\"\n\tPartitionNameListOpt                   \"table partition names list optional\"\n\tPartitionNumOpt                        \"PARTITION NUM option\"\n\tPartDefValuesOpt                       \"VALUES {LESS THAN {(expr | value_list) | MAXVALUE} | IN {value_list}\"\n\tPartDefOptionList                      \"PartDefOption list\"\n\tPartDefOption                          \"COMMENT [=] xxx | TABLESPACE [=] tablespace_name | ENGINE [=] xxx\"\n\tPartyCodeString                        \"Party code string value\"\n\tPartyCodeOption                        \"Party code option\"\n\tPasswordExpire                         \"Single password option for create user statement\"\n\tPasswordOpt                            \"Password option\"\n\tPasswordOrLockOption                   \"Single password or lock option for create user statement\"\n\tPasswordOrLockOptionList               \"Password or lock options for create user statement\"\n\tPasswordOrLockOptions                  \"Optional password or lock options for create user statement\"\n\tColumnPosition                         \"Column position [First|After ColumnName]\"\n\tPrepareSQL                             \"Prepare statement sql string\"\n\tPriorityOpt                            \"Statement priority option\"\n\tPrivElem                               \"Privilege element\"\n\tPrivElemList                           \"Privilege element list\"\n\tPrivLevel                              \"Privilege scope\"\n\tPrivType                               \"Privilege type\"\n\tReferDef                               \"Reference definition\"\n\tOnDelete                               \"ON DELETE clause\"\n\tOnUpdate                               \"ON UPDATE clause\"\n\tOnDeleteUpdateOpt                      \"optional ON DELETE and UPDATE clause\"\n\tOptGConcatSeparator                    \"optional GROUP_CONCAT SEPARATOR\"\n\tReferOpt                               \"reference option\"\n\tReorganizePartitionRuleOpt             \"optional reorganize partition partition list and definitions\"\n\tRequireList                            \"require list\"\n\tRequireListElement                     \"require list element\"\n\tRolename                               \"Rolename\"\n\tRolenameList                           \"RolenameList\"\n\tRoleSpec                               \"Rolename and auth option\"\n\tRoleSpecList                           \"Rolename and auth option list\"\n\tRoleNameString                         \"role name string\"\n\tRowFormat                              \"Row format option\"\n\tRowValue                               \"Row value\"\n\tSelectLockOpt                          \"FOR UPDATE or LOCK IN SHARE MODE,\"\n\tSelectStmtCalcFoundRows                \"SELECT statement optional SQL_CALC_FOUND_ROWS\"\n\tSelectStmtSQLBigResult                 \"SELECT statement optional SQL_BIG_RESULT\"\n\tSelectStmtSQLBufferResult              \"SELECT statement optional SQL_BUFFER_RESULT\"\n\tSelectStmtSQLCache                     \"SELECT statement optional SQL_CAHCE/SQL_NO_CACHE\"\n\tSelectStmtSQLSmallResult               \"SELECT statement optional SQL_SMALL_RESULT\"\n\tSelectStmtStraightJoin                 \"SELECT statement optional STRAIGHT_JOIN\"\n\tSelectStmtFieldList                    \"SELECT statement field list\"\n\tSelectStmtLimit                        \"SELECT statement optional LIMIT clause\"\n\tSelectStmtOpts                         \"Select statement options\"\n\tSelectStmtBasic                        \"SELECT statement from constant value\"\n\tSelectStmtFromDualTable                \"SELECT statement from dual table\"\n\tSelectStmtFromTable                    \"SELECT statement from table\"\n\tSelectStmtGroup                        \"SELECT statement optional GROUP BY clause\"\n\tSelectStmtIntoOption                   \"SELECT statement into clause\"\n\tSequenceOption                         \"create sequence option\"\n\tSequenceOptionList                     \"create sequence option list\"\n\tSetRoleOpt                             \"Set role options\"\n\tSetDefaultRoleOpt                      \"Set default role options\"\n\tShowTargetFilterable                   \"Show target that can be filtered by WHERE or LIKE\"\n\tShowDatabaseNameOpt                    \"Show tables/columns statement database name option\"\n\tShowTableAliasOpt                      \"Show table alias option\"\n\tShowLikeOrWhereOpt                     \"Show like or where clause option\"\n\tShowProfileArgsOpt                     \"Show profile args option\"\n\tShowProfileTypesOpt                    \"Show profile types option\"\n\tShowProfileType                        \"Show profile type\"\n\tShowProfileTypes                       \"Show profile types\"\n\tSplitOption                            \"Split Option\"\n\tSplitSyntaxOption                      \"Split syntax Option\"\n\tStarting                               \"Starting by\"\n\tStatementList                          \"statement list\"\n\tStatsPersistentVal                     \"stats_persistent value\"\n\tStringName                             \"string literal or identifier\"\n\tStringList                             \"string list\"\n\tSubPartDefinition                      \"SubPartition definition\"\n\tSubPartDefinitionList                  \"SubPartition definition list\"\n\tSubPartDefinitionListOpt               \"SubPartition definition list optional\"\n\tSubPartitionMethod                     \"SubPartition method\"\n\tSubPartitionOpt                        \"SubPartition option\"\n\tSubPartitionNumOpt                     \"SubPartition NUM option\"\n\tSymbol                                 \"Constraint Symbol\"\n\tTableAliasRefList                      \"table alias reference list\"\n\tTableAsName                            \"table alias name\"\n\tTableAsNameOpt                         \"table alias name optional\"\n\tTableElement                           \"table definition element\"\n\tTableElementList                       \"table definition element list\"\n\tTableElementListOpt                    \"table definition element list optional\"\n\tTableFactor                            \"table factor\"\n\tTableLock                              \"Table name and lock type\"\n\tTableLockList                          \"Table lock list\"\n\tTableName                              \"Table name\"\n\tTableNameOptWild                       \"Table name with optional wildcard\"\n\tTableNameList                          \"Table name list\"\n\tTableNameListOpt                       \"Table name list opt\"\n\tTableOption                            \"create table option\"\n\tTableOptionList                        \"create table option list\"\n\tTableRef                               \"table reference\"\n\tTableRefs                              \"table references\"\n\tTableToTable                           \"rename table to table\"\n\tTableToTableList                       \"rename table to table by list\"\n\tTimeUnit                               \"Time unit for 'DATE_ADD', 'DATE_SUB', 'ADDDATE', 'SUBDATE', 'EXTRACT'\"\n\tTimestampUnit                          \"Time unit for 'TIMESTAMPADD' and 'TIMESTAMPDIFF'\"\n\tTimestampBound                         \"Timestamp bound for start transaction with timestamp mode\"\n\tLockType                               \"Table locks type\"\n\tFlashbackUntil                         \"Flashback until timestamp\"\n\tFlashbackToNewName                     \"Flashback to new name\"\n\tTransactionChar                        \"Transaction characteristic\"\n\tTransactionChars                       \"Transaction characteristic list\"\n\tTrimDirection                          \"Trim string direction\"\n\tUnionOpt                               \"Union Option(empty/ALL/DISTINCT)\"\n\tUnionClauseList                        \"Union select clause list\"\n\tUnionSelect                            \"Union (select) item\"\n\tUsername                               \"Username\"\n\tUsernameList                           \"UsernameList\"\n\tUserSpec                               \"Username and auth option\"\n\tUserSpecList                           \"Username and auth option list\"\n\tUserVariableList                       \"User defined variable name list\"\n\tUsingRoles                             \"UsingRoles is role option for SHOW GRANT\"\n\tValues                                 \"values\"\n\tValuesList                             \"values list\"\n\tValuesOpt                              \"values optional\"\n\tVariableAssignment                     \"set variable value\"\n\tVariableAssignmentList                 \"set variable value list\"\n\tViewAlgorithm                          \"view algorithm\"\n\tViewCheckOption                        \"view check option\"\n\tViewDefiner                            \"view definer\"\n\tViewName                               \"view name\"\n\tViewFieldList                          \"create view statement field list\"\n\tViewSQLSecurity                        \"view sql security\"\n\tWhereClause                            \"WHERE clause\"\n\tWhereClauseOptional                    \"Optional WHERE clause\"\n\tWhenClause                             \"When clause\"\n\tWhenClauseList                         \"When clause list\"\n\tWithReadLockOpt                        \"With Read Lock opt\"\n\tWithGrantOptionOpt                     \"With Grant Option opt\"\n\tWithValidation                         \"with validation\"\n\tWithValidationOpt                      \"optional with validation\"\n\tElseOpt                                \"Optional else clause\"\n\tType                                   \"Types\"\n\tOptExistingWindowName                  \"Optional existing WINDOW name\"\n\tOptFromFirstLast                       \"Optional FROM FIRST/LAST\"\n\tOptLLDefault                           \"Optional LEAD/LAG default\"\n\tOptLeadLagInfo                         \"Optional LEAD/LAG info\"\n\tOptNullTreatment                       \"Optional NULL treatment\"\n\tOptPartitionClause                     \"Optional PARTITION clause\"\n\tOptWild                                \"Optional Wildcard\"\n\tOptWindowOrderByClause                 \"Optional ORDER BY clause in WINDOW\"\n\tOptWindowFrameClause                   \"Optional FRAME clause in WINDOW\"\n\tOptWindowingClause                     \"Optional OVER clause\"\n\tWindowingClause                        \"OVER clause\"\n\tWindowClauseOptional                   \"Optional WINDOW clause\"\n\tWindowDefinitionList                   \"WINDOW definition list\"\n\tWindowDefinition                       \"WINDOW definition\"\n\tWindowFrameUnits                       \"WINDOW frame units\"\n\tWindowFrameBetween                     \"WINDOW frame between\"\n\tWindowFrameBound                       \"WINDOW frame bound\"\n\tWindowFrameExtent                      \"WINDOW frame extent\"\n\tWindowFrameStart                       \"WINDOW frame start\"\n\tWindowFuncCall                         \"WINDOW function call\"\n\tWindowName                             \"WINDOW name\"\n\tWindowNameOrSpec                       \"WINDOW name or spec\"\n\tWindowSpec                             \"WINDOW spec\"\n\tWindowSpecDetails                      \"WINDOW spec details\"\n\tBetweenOrNotOp                         \"Between predicate\"\n\tIsOrNotOp                              \"Is predicate\"\n\tInOrNotOp                              \"In predicate\"\n\tLikeOrNotOp                            \"Like predicate\"\n\tRegexpOrNotOp                          \"Regexp predicate\"\n\tNumericType                            \"Numeric types\"\n\tIntegerType                            \"Integer Types types\"\n\tBooleanType                            \"Boolean Types types\"\n\tFixedPointType                         \"Exact value types\"\n\tFloatingPointType                      \"Approximate value types\"\n\tBitValueType                           \"bit value types\"\n\tStringType                             \"String types\"\n\tBlobType                               \"Blob types\"\n\tTextType                               \"Text types\"\n\tDateAndTimeType                        \"Date and Time types\"\n\tOptFieldLen                            \"Field length or empty\"\n\tFieldLen                               \"Field length\"\n\tFieldOpts                              \"Field type definition option list\"\n\tFieldOpt                               \"Field type definition option\"\n\tFloatOpt                               \"Floating-point type option\"\n\tPrecision                              \"Floating-point precision option\"\n\tOptBinary                              \"Optional BINARY\"\n\tOptBinMod                              \"Optional BINARY mode\"\n\tOptCharsetWithOptBinary                \"Optional BINARY or ASCII or UNICODE or BYTE\"\n\tOptCharset                             \"Optional Character setting\"\n\tOptCollate                             \"Optional Collate setting\"\n\tIgnoreLines                            \"Ignore num(int) lines\"\n\tNUM                                    \"A number\"\n\tNumList                                \"Some numbers\"\n\tLengthNum                              \"Field length num(uint64)\"\n\tSignedNum                              \"Signed num(int64)\"\n\tTableOptimizerHints                    \"Table level optimizer hints\"\n\tEnforcedOrNot                          \"{ENFORCED|NOT ENFORCED}\"\n\tEnforcedOrNotOpt                       \"Optional {ENFORCED|NOT ENFORCED}\"\n\tEnforcedOrNotOrNotNullOpt              \"{[ENFORCED|NOT ENFORCED|NOT NULL]}\"\n\tMatch                                  \"[MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]\"\n\tMatchOpt                               \"optional MATCH clause\"\n\tMaxMinutesOpt                          \"MAX_MINUTES num(int)\"\n\tMaxIndexNumOpt                         \"MAX_IDXNUM clause\"\n\tPerTable                               \"Max index number PER_TABLE\"\n\tPerDB                                  \"Max index number PER_DB\"\n\tEngineOpt                              \"SCQLEngine credential and endpoint information\"\n\tEndpointOpt                            \"SCQLEngine endpoint information\"\n\tTypeName                               \"Column Type Name\"\n\tPartyFile                              \"Party file\"\n\tPartyFileList                          \"Party file list\"\n\tPartySelectFieldList                   \"Party file select field list\"\n\n%type\t<ident>\n\tAsOpt             \"AS or EmptyString\"\n\tKeyOrIndex        \"{KEY|INDEX}\"\n\tColumnKeywordOpt  \"Column keyword or empty\"\n\tPrimaryOpt        \"Optional primary keyword\"\n\tNowSym            \"CURRENT_TIMESTAMP/LOCALTIME/LOCALTIMESTAMP\"\n\tNowSymFunc        \"CURRENT_TIMESTAMP/LOCALTIME/LOCALTIMESTAMP/NOW\"\n\tDefaultKwdOpt     \"optional DEFAULT keyword\"\n\tDatabaseSym       \"DATABASE or SCHEMA\"\n\tExplainSym        \"EXPLAIN or DESCRIBE or DESC\"\n\tRegexpSym         \"REGEXP or RLIKE\"\n\tIntoOpt           \"INTO or EmptyString\"\n\tValueSym          \"Value or Values\"\n\tChar              \"{CHAR|CHARACTER}\"\n\tNChar             \"{NCHAR|NATIONAL CHARACTER|NATIONAL CHAR}\"\n\tVarchar           \"{VARCHAR|VARCHARACTER|CHARACTER VARYING|CHAR VARYING}\"\n\tNVarchar          \"{NATIONAL VARCHAR|NATIONAL VARCHARACTER|NVARCHAR|NCHAR VARCHAR|NATIONAL CHARACTER VARYING|NATIONAL CHAR VARYING|NCHAR VARYING}\"\n\tYear              \"{YEAR|SQL_TSI_YEAR}\"\n\tDeallocateSym     \"Deallocate or drop\"\n\tOuterOpt          \"optional OUTER clause\"\n\tCrossOpt          \"Cross join option\"\n\tTablesTerminalSym \"{TABLE|TABLES}\"\n\tIsolationLevel    \"Isolation level\"\n\tShowIndexKwd      \"Show index/indexs/key keyword\"\n\tDistinctKwd       \"DISTINCT/DISTINCTROW keyword\"\n\tFromOrIn          \"From or In\"\n\tOptTable          \"Optional table keyword\"\n\tOptInteger        \"Optional Integer keyword\"\n\tCharsetKw         \"charset or charater set\"\n\tCommaOpt          \"optional comma\"\n\tlogAnd            \"logical and operator\"\n\tlogOr             \"logical or operator\"\n\tLinearOpt         \"linear or empty\"\n\tFieldsOrColumns   \"Fields or columns\"\n\tStorageMedia      \"{DISK|MEMORY|DEFAULT}\"\n\n%type\t<ident>\n\tODBCDateTimeType                \"ODBC type keywords for date and time literals\"\n\tIdentifier                      \"identifier or unreserved keyword\"\n\tNotKeywordToken                 \"Tokens not mysql keyword but treated specially\"\n\tUnReservedKeyword               \"MySQL unreserved keywords\"\n\tTiDBKeyword                     \"TiDB added keywords\"\n\tFunctionNameConflict            \"Built-in function call names which are conflict with keywords\"\n\tFunctionNameOptionalBraces      \"Function with optional braces, all of them are reserved keywords.\"\n\tFunctionNameDatetimePrecision   \"Function with optional datetime precision, all of them are reserved keywords.\"\n\tFunctionNameDateArith           \"Date arith function call names (date_add or date_sub)\"\n\tFunctionNameDateArithMultiForms \"Date arith function call names (adddate or subdate)\"\n\tVariableName                    \"A simple Identifier like xx or the xx.xx form\"\n\n%precedence empty\n%precedence sqlBufferResult\n%precedence sqlBigResult\n%precedence sqlSmallResult\n%precedence sqlCache sqlNoCache\n%precedence lowerThanIntervalKeyword\n%precedence interval\n%precedence lowerThanStringLitToken\n%precedence stringLit\n%precedence lowerThanSetKeyword\n%precedence set\n%precedence lowerThanInsertValues\n%precedence insertValues\n%precedence lowerThanCreateTableSelect\n%precedence createTableSelect\n%precedence lowerThanCharsetKwd\n%precedence charsetKwd\n%precedence lowerThanKey\n%precedence key\n%precedence lowerThanLocal\n%precedence local\n%precedence lowerThanRemove\n%precedence remove\n%precedence lowerThenOrder\n%precedence order\n%left join straightJoin inner cross left right full natural\n\n/* A dummy token to force the priority of TableRef production in a join. */\n%left tableRefPriority\n%precedence lowerThanOn\n%precedence on using\n%right assignmentEq\n%left pipes or pipesAsOr\n%left xor\n%left andand and\n%left between\n%precedence lowerThanEq\n%left eq ge le neq neqSynonym '>' '<' is like in\n%left '|'\n%left '&'\n%left rsh lsh\n%left '-' '+'\n%left '*' '/' '%' div mod\n%left '^'\n%left '~' neg\n%precedence lowerThanNot\n%right not not2\n%right collate\n%right encryption\n%left labels\n%precedence '('\n%precedence quick\n%precedence escape\n%precedence lowerThanComma\n%precedence ','\n%precedence higherThanComma\n\n%start\tStart\n\n%%\n\nStart:\n\tStatementList\n\n/**************************************AlterTableStmt***************************************\n * See https://dev.mysql.com/doc/refman/5.7/en/alter-table.html\n *******************************************************************************************/\nAlterTableStmt:\n\t\"ALTER\" IgnoreOptional \"TABLE\" TableName AlterTableSpecListOpt AlterTablePartitionOpt\n\t{\n\t\tspecs := $5.([]*ast.AlterTableSpec)\n\t\tif $6 != nil {\n\t\t\tspecs = append(specs, $6.(*ast.AlterTableSpec))\n\t\t}\n\t\t$$ = &ast.AlterTableStmt{\n\t\t\tTable: $4.(*ast.TableName),\n\t\t\tSpecs: specs,\n\t\t}\n\t}\n|\t\"ALTER\" IgnoreOptional \"TABLE\" TableName \"ANALYZE\" \"PARTITION\" PartitionNameList AnalyzeOptionListOpt\n\t{\n\t\t$$ = &ast.AnalyzeTableStmt{TableNames: []*ast.TableName{$4.(*ast.TableName)}, PartitionNames: $7.([]model.CIStr), AnalyzeOpts: $8.([]ast.AnalyzeOpt)}\n\t}\n|\t\"ALTER\" IgnoreOptional \"TABLE\" TableName \"ANALYZE\" \"PARTITION\" PartitionNameList \"INDEX\" IndexNameList AnalyzeOptionListOpt\n\t{\n\t\t$$ = &ast.AnalyzeTableStmt{\n\t\t\tTableNames:     []*ast.TableName{$4.(*ast.TableName)},\n\t\t\tPartitionNames: $7.([]model.CIStr),\n\t\t\tIndexNames:     $9.([]model.CIStr),\n\t\t\tIndexFlag:      true,\n\t\t\tAnalyzeOpts:    $10.([]ast.AnalyzeOpt),\n\t\t}\n\t}\n\nAlterTablePartitionOpt:\n\tPartitionOpt\n\t{\n\t\tif $1 != nil {\n\t\t\t$$ = &ast.AlterTableSpec{\n\t\t\t\tTp:        ast.AlterTablePartition,\n\t\t\t\tPartition: $1.(*ast.PartitionOptions),\n\t\t\t}\n\t\t} else {\n\t\t\t$$ = nil\n\t\t}\n\t}\n|\t\"REMOVE\" \"PARTITIONING\"\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableRemovePartitioning,\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The REMOVE PARTITIONING clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n\nLocationLabelList:\n\t{\n\t\t$$ = []string{}\n\t}\n|\t\"LOCATION\" \"LABELS\" StringList\n\t{\n\t\t$$ = $3\n\t}\n\nAlterTableSpec:\n\tTableOptionList %prec higherThanComma\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:      ast.AlterTableOption,\n\t\t\tOptions: $1.([]*ast.TableOption),\n\t\t}\n\t}\n|\t\"SET\" \"TIFLASH\" \"REPLICA\" LengthNum LocationLabelList\n\t{\n\t\ttiflashReplicaSpec := &ast.TiFlashReplicaSpec{\n\t\t\tCount:  $4.(uint64),\n\t\t\tLabels: $5.([]string),\n\t\t}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:             ast.AlterTableSetTiFlashReplica,\n\t\t\tTiFlashReplica: tiflashReplicaSpec,\n\t\t}\n\t}\n|\t\"CONVERT\" \"TO\" CharsetKw CharsetName OptCollate\n\t{\n\t\top := &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableOption,\n\t\t\tOptions: []*ast.TableOption{{Tp: ast.TableOptionCharset, StrValue: $4.(string),\n\t\t\t\tUintValue: ast.TableOptionCharsetWithConvertTo}},\n\t\t}\n\t\tif $5 != \"\" {\n\t\t\top.Options = append(op.Options, &ast.TableOption{Tp: ast.TableOptionCollate, StrValue: $5.(string)})\n\t\t}\n\t\t$$ = op\n\t}\n|\t\"CONVERT\" \"TO\" CharsetKw \"DEFAULT\" OptCollate\n\t{\n\t\top := &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableOption,\n\t\t\tOptions: []*ast.TableOption{{Tp: ast.TableOptionCharset, Default: true,\n\t\t\t\tUintValue: ast.TableOptionCharsetWithConvertTo}},\n\t\t}\n\t\tif $5 != \"\" {\n\t\t\top.Options = append(op.Options, &ast.TableOption{Tp: ast.TableOptionCollate, StrValue: $5.(string)})\n\t\t}\n\t\t$$ = op\n\t}\n|\t\"ADD\" ColumnKeywordOpt IfNotExists ColumnDef ColumnPosition\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tIfNotExists: $3.(bool),\n\t\t\tTp:          ast.AlterTableAddColumns,\n\t\t\tNewColumns:  []*ast.ColumnDef{$4.(*ast.ColumnDef)},\n\t\t\tPosition:    $5.(*ast.ColumnPosition),\n\t\t}\n\t}\n|\t\"ADD\" ColumnKeywordOpt IfNotExists '(' TableElementList ')'\n\t{\n\t\ttes := $5.([]interface{})\n\t\tvar columnDefs []*ast.ColumnDef\n\t\tvar constraints []*ast.Constraint\n\t\tfor _, te := range tes {\n\t\t\tswitch te := te.(type) {\n\t\t\tcase *ast.ColumnDef:\n\t\t\t\tcolumnDefs = append(columnDefs, te)\n\t\t\tcase *ast.Constraint:\n\t\t\t\tconstraints = append(constraints, te)\n\t\t\t}\n\t\t}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tIfNotExists:    $3.(bool),\n\t\t\tTp:             ast.AlterTableAddColumns,\n\t\t\tNewColumns:     columnDefs,\n\t\t\tNewConstraints: constraints,\n\t\t}\n\t}\n|\t\"ADD\" Constraint\n\t{\n\t\tconstraint := $2.(*ast.Constraint)\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:         ast.AlterTableAddConstraint,\n\t\t\tConstraint: constraint,\n\t\t}\n\t}\n|\t\"ADD\" \"PARTITION\" IfNotExists NoWriteToBinLogAliasOpt PartitionDefinitionListOpt\n\t{\n\t\tvar defs []*ast.PartitionDefinition\n\t\tif $5 != nil {\n\t\t\tdefs = $5.([]*ast.PartitionDefinition)\n\t\t}\n\t\tnoWriteToBinlog := $4.(bool)\n\t\tif noWriteToBinlog {\n\t\t\tyylex.AppendError(yylex.Errorf(\"The NO_WRITE_TO_BINLOG option is parsed but ignored for now.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tIfNotExists:     $3.(bool),\n\t\t\tNoWriteToBinlog: noWriteToBinlog,\n\t\t\tTp:              ast.AlterTableAddPartitions,\n\t\t\tPartDefinitions: defs,\n\t\t}\n\t}\n|\t\"ADD\" \"PARTITION\" IfNotExists NoWriteToBinLogAliasOpt \"PARTITIONS\" NUM\n\t{\n\t\tnoWriteToBinlog := $4.(bool)\n\t\tif noWriteToBinlog {\n\t\t\tyylex.AppendError(yylex.Errorf(\"The NO_WRITE_TO_BINLOG option is parsed but ignored for now.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tIfNotExists:     $3.(bool),\n\t\t\tNoWriteToBinlog: noWriteToBinlog,\n\t\t\tTp:              ast.AlterTableAddPartitions,\n\t\t\tNum:             getUint64FromNUM($6),\n\t\t}\n\t}\n|\t\"CHECK\" \"PARTITION\" AllOrPartitionNameList\n\t{\n\t\tyylex.AppendError(yylex.Errorf(\"The CHECK PARTITIONING clause is parsed but not implement yet.\"))\n\t\tparser.lastErrorAsWarn()\n\t\tret := &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableCheckPartitions,\n\t\t}\n\t\tif $3 == nil {\n\t\t\tret.OnAllPartitions = true\n\t\t} else {\n\t\t\tret.PartitionNames = $3.([]model.CIStr)\n\t\t}\n\t\t$$ = ret\n\t}\n|\t\"COALESCE\" \"PARTITION\" NoWriteToBinLogAliasOpt NUM\n\t{\n\t\tnoWriteToBinlog := $3.(bool)\n\t\tif noWriteToBinlog {\n\t\t\tyylex.AppendError(yylex.Errorf(\"The NO_WRITE_TO_BINLOG option is parsed but ignored for now.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:              ast.AlterTableCoalescePartitions,\n\t\t\tNoWriteToBinlog: noWriteToBinlog,\n\t\t\tNum:             getUint64FromNUM($4),\n\t\t}\n\t}\n|\t\"DROP\" ColumnKeywordOpt IfExists ColumnName RestrictOrCascadeOpt\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tIfExists:      $3.(bool),\n\t\t\tTp:            ast.AlterTableDropColumn,\n\t\t\tOldColumnName: $4.(*ast.ColumnName),\n\t\t}\n\t}\n|\t\"DROP\" \"PRIMARY\" \"KEY\"\n\t{\n\t\t$$ = &ast.AlterTableSpec{Tp: ast.AlterTableDropPrimaryKey}\n\t}\n|\t\"DROP\" \"PARTITION\" IfExists PartitionNameList %prec lowerThanComma\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tIfExists:       $3.(bool),\n\t\t\tTp:             ast.AlterTableDropPartition,\n\t\t\tPartitionNames: $4.([]model.CIStr),\n\t\t}\n\t}\n|\t\"EXCHANGE\" \"PARTITION\" Identifier \"WITH\" \"TABLE\" TableName WithValidationOpt\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:             ast.AlterTableExchangePartition,\n\t\t\tPartitionNames: []model.CIStr{model.NewCIStr($3)},\n\t\t\tNewTable:       $6.(*ast.TableName),\n\t\t\tWithValidation: $7.(bool),\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"TiDB does not support EXCHANGE PARTITION now, it would be parsed but ignored.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"TRUNCATE\" \"PARTITION\" AllOrPartitionNameList\n\t{\n\t\tret := &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableTruncatePartition,\n\t\t}\n\t\tif $3 == nil {\n\t\t\tret.OnAllPartitions = true\n\t\t\tyylex.AppendError(yylex.Errorf(\"The TRUNCATE PARTITION ALL clause is parsed but ignored by all storage engines.\"))\n\t\t\tparser.lastErrorAsWarn()\n\t\t} else {\n\t\t\tret.PartitionNames = $3.([]model.CIStr)\n\t\t}\n\t\t$$ = ret\n\t}\n|\t\"OPTIMIZE\" \"PARTITION\" NoWriteToBinLogAliasOpt AllOrPartitionNameList\n\t{\n\t\tret := &ast.AlterTableSpec{\n\t\t\tNoWriteToBinlog: $3.(bool),\n\t\t\tTp:              ast.AlterTableOptimizePartition,\n\t\t}\n\t\tif $4 == nil {\n\t\t\tret.OnAllPartitions = true\n\t\t} else {\n\t\t\tret.PartitionNames = $4.([]model.CIStr)\n\t\t}\n\t\t$$ = ret\n\t\tyylex.AppendError(yylex.Errorf(\"The OPTIMIZE PARTITION clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"REPAIR\" \"PARTITION\" NoWriteToBinLogAliasOpt AllOrPartitionNameList\n\t{\n\t\tret := &ast.AlterTableSpec{\n\t\t\tNoWriteToBinlog: $3.(bool),\n\t\t\tTp:              ast.AlterTableRepairPartition,\n\t\t}\n\t\tif $4 == nil {\n\t\t\tret.OnAllPartitions = true\n\t\t} else {\n\t\t\tret.PartitionNames = $4.([]model.CIStr)\n\t\t}\n\t\t$$ = ret\n\t\tyylex.AppendError(yylex.Errorf(\"The REPAIR PARTITION clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"IMPORT\" \"PARTITION\" AllOrPartitionNameList \"TABLESPACE\"\n\t{\n\t\tret := &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableImportPartitionTablespace,\n\t\t}\n\t\tif $3 == nil {\n\t\t\tret.OnAllPartitions = true\n\t\t} else {\n\t\t\tret.PartitionNames = $3.([]model.CIStr)\n\t\t}\n\t\t$$ = ret\n\t\tyylex.AppendError(yylex.Errorf(\"The IMPORT PARTITION TABLESPACE clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"DISCARD\" \"PARTITION\" AllOrPartitionNameList \"TABLESPACE\"\n\t{\n\t\tret := &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableDiscardPartitionTablespace,\n\t\t}\n\t\tif $3 == nil {\n\t\t\tret.OnAllPartitions = true\n\t\t} else {\n\t\t\tret.PartitionNames = $3.([]model.CIStr)\n\t\t}\n\t\t$$ = ret\n\t\tyylex.AppendError(yylex.Errorf(\"The DISCARD PARTITION TABLESPACE clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"IMPORT\" \"TABLESPACE\"\n\t{\n\t\tret := &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableImportTablespace,\n\t\t}\n\t\t$$ = ret\n\t\tyylex.AppendError(yylex.Errorf(\"The IMPORT TABLESPACE clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"DISCARD\" \"TABLESPACE\"\n\t{\n\t\tret := &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableDiscardTablespace,\n\t\t}\n\t\t$$ = ret\n\t\tyylex.AppendError(yylex.Errorf(\"The DISCARD TABLESPACE clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"REBUILD\" \"PARTITION\" NoWriteToBinLogAliasOpt AllOrPartitionNameList\n\t{\n\t\tret := &ast.AlterTableSpec{\n\t\t\tTp:              ast.AlterTableRebuildPartition,\n\t\t\tNoWriteToBinlog: $3.(bool),\n\t\t}\n\t\tif $4 == nil {\n\t\t\tret.OnAllPartitions = true\n\t\t} else {\n\t\t\tret.PartitionNames = $4.([]model.CIStr)\n\t\t}\n\t\t$$ = ret\n\t\tyylex.AppendError(yylex.Errorf(\"REBUILD PARTITION syntax is parsed but not implement for now.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"REORGANIZE\" \"PARTITION\" NoWriteToBinLogAliasOpt ReorganizePartitionRuleOpt\n\t{\n\t\tret := $4.(*ast.AlterTableSpec)\n\t\tret.NoWriteToBinlog = $3.(bool)\n\t\t$$ = ret\n\t\tyylex.AppendError(yylex.Errorf(\"REORGANIZE PARTITION syntax is parsed but not implement for now.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"DROP\" KeyOrIndex IfExists Identifier\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tIfExists: $3.(bool),\n\t\t\tTp:       ast.AlterTableDropIndex,\n\t\t\tName:     $4,\n\t\t}\n\t}\n|\t\"DROP\" \"FOREIGN\" \"KEY\" IfExists Symbol\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tIfExists: $4.(bool),\n\t\t\tTp:       ast.AlterTableDropForeignKey,\n\t\t\tName:     $5.(string),\n\t\t}\n\t}\n|\t\"ORDER\" \"BY\" AlterOrderList %prec lowerThenOrder\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:          ast.AlterTableOrderByColumns,\n\t\t\tOrderByList: $3.([]*ast.AlterOrderItem),\n\t\t}\n\t}\n|\t\"DISABLE\" \"KEYS\"\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableDisableKeys,\n\t\t}\n\t}\n|\t\"ENABLE\" \"KEYS\"\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableEnableKeys,\n\t\t}\n\t}\n|\t\"MODIFY\" ColumnKeywordOpt IfExists ColumnDef ColumnPosition\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tIfExists:   $3.(bool),\n\t\t\tTp:         ast.AlterTableModifyColumn,\n\t\t\tNewColumns: []*ast.ColumnDef{$4.(*ast.ColumnDef)},\n\t\t\tPosition:   $5.(*ast.ColumnPosition),\n\t\t}\n\t}\n|\t\"CHANGE\" ColumnKeywordOpt IfExists ColumnName ColumnDef ColumnPosition\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tIfExists:      $3.(bool),\n\t\t\tTp:            ast.AlterTableChangeColumn,\n\t\t\tOldColumnName: $4.(*ast.ColumnName),\n\t\t\tNewColumns:    []*ast.ColumnDef{$5.(*ast.ColumnDef)},\n\t\t\tPosition:      $6.(*ast.ColumnPosition),\n\t\t}\n\t}\n|\t\"ALTER\" ColumnKeywordOpt ColumnName \"SET\" \"DEFAULT\" SignedLiteral\n\t{\n\t\toption := &ast.ColumnOption{Expr: $6}\n\t\tcolDef := &ast.ColumnDef{\n\t\t\tName:    $3.(*ast.ColumnName),\n\t\t\tOptions: []*ast.ColumnOption{option},\n\t\t}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:         ast.AlterTableAlterColumn,\n\t\t\tNewColumns: []*ast.ColumnDef{colDef},\n\t\t}\n\t}\n|\t\"ALTER\" ColumnKeywordOpt ColumnName \"SET\" \"DEFAULT\" '(' Expression ')'\n\t{\n\t\toption := &ast.ColumnOption{Expr: $7}\n\t\tcolDef := &ast.ColumnDef{\n\t\t\tName:    $3.(*ast.ColumnName),\n\t\t\tOptions: []*ast.ColumnOption{option},\n\t\t}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:         ast.AlterTableAlterColumn,\n\t\t\tNewColumns: []*ast.ColumnDef{colDef},\n\t\t}\n\t}\n|\t\"ALTER\" ColumnKeywordOpt ColumnName \"DROP\" \"DEFAULT\"\n\t{\n\t\tcolDef := &ast.ColumnDef{\n\t\t\tName: $3.(*ast.ColumnName),\n\t\t}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:         ast.AlterTableAlterColumn,\n\t\t\tNewColumns: []*ast.ColumnDef{colDef},\n\t\t}\n\t}\n|\t\"RENAME\" \"COLUMN\" Identifier \"TO\" Identifier\n\t{\n\t\toldColName := &ast.ColumnName{Name: model.NewCIStr($3)}\n\t\tnewColName := &ast.ColumnName{Name: model.NewCIStr($5)}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:            ast.AlterTableRenameColumn,\n\t\t\tOldColumnName: oldColName,\n\t\t\tNewColumnName: newColName,\n\t\t}\n\t}\n|\t\"RENAME\" \"TO\" TableName\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:       ast.AlterTableRenameTable,\n\t\t\tNewTable: $3.(*ast.TableName),\n\t\t}\n\t}\n|\t\"RENAME\" EqOpt TableName\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:       ast.AlterTableRenameTable,\n\t\t\tNewTable: $3.(*ast.TableName),\n\t\t}\n\t}\n|\t\"RENAME\" \"AS\" TableName\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:       ast.AlterTableRenameTable,\n\t\t\tNewTable: $3.(*ast.TableName),\n\t\t}\n\t}\n|\t\"RENAME\" KeyOrIndex Identifier \"TO\" Identifier\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:      ast.AlterTableRenameIndex,\n\t\t\tFromKey: model.NewCIStr($3),\n\t\t\tToKey:   model.NewCIStr($5),\n\t\t}\n\t}\n|\tLockClause\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:       ast.AlterTableLock,\n\t\t\tLockType: $1.(ast.LockType),\n\t\t}\n\t}\n|\tAlgorithmClause\n\t{\n\t\t// Parse it and ignore it. Just for compatibility.\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:        ast.AlterTableAlgorithm,\n\t\t\tAlgorithm: $1.(ast.AlgorithmType),\n\t\t}\n\t}\n|\t\"FORCE\"\n\t{\n\t\t// Parse it and ignore it. Just for compatibility.\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableForce,\n\t\t}\n\t}\n|\t\"WITH\" \"VALIDATION\"\n\t{\n\t\t// Parse it and ignore it. Just for compatibility.\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableWithValidation,\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The WITH/WITHOUT VALIDATION clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"WITHOUT\" \"VALIDATION\"\n\t{\n\t\t// Parse it and ignore it. Just for compatibility.\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableWithoutValidation,\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The WITH/WITHOUT VALIDATION clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n// Added in MySQL 8.0.13, see: https://dev.mysql.com/doc/refman/8.0/en/keywords.html for details\n|\t\"SECONDARY_LOAD\"\n\t{\n\t\t// Parse it and ignore it. Just for compatibility.\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableSecondaryLoad,\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The SECONDARY_LOAD clause is parsed but not implement yet.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n// Added in MySQL 8.0.13, see: https://dev.mysql.com/doc/refman/8.0/en/keywords.html for details\n|\t\"SECONDARY_UNLOAD\"\n\t{\n\t\t// Parse it and ignore it. Just for compatibility.\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp: ast.AlterTableSecondaryUnload,\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The SECONDARY_UNLOAD VALIDATION clause is parsed but not implement yet.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"ALTER\" \"CHECK\" Identifier EnforcedOrNot\n\t{\n\t\t// Parse it and ignore it. Just for compatibility.\n\t\tc := &ast.Constraint{\n\t\t\tName:     $3,\n\t\t\tEnforced: $4.(bool),\n\t\t}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:         ast.AlterTableAlterCheck,\n\t\t\tConstraint: c,\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The ALTER CHECK clause is parsed but not implemented yet.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"DROP\" \"CHECK\" Identifier\n\t{\n\t\t// Parse it and ignore it. Just for compatibility.\n\t\tc := &ast.Constraint{\n\t\t\tName: $3,\n\t\t}\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:         ast.AlterTableDropCheck,\n\t\t\tConstraint: c,\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The DROP CHECK clause is parsed but not implemented yet.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"ALTER\" \"INDEX\" Identifier IndexInvisible\n\t{\n\t\t$$ = &ast.AlterTableSpec{\n\t\t\tTp:         ast.AlterTableIndexInvisible,\n\t\t\tName:       $3,\n\t\t\tVisibility: $4.(ast.IndexVisibility),\n\t\t}\n\t}\n\nReorganizePartitionRuleOpt:\n\t/* empty */ %prec lowerThanRemove\n\t{\n\t\tret := &ast.AlterTableSpec{\n\t\t\tTp:              ast.AlterTableReorganizePartition,\n\t\t\tOnAllPartitions: true,\n\t\t}\n\t\t$$ = ret\n\t}\n|\tPartitionNameList \"INTO\" '(' PartitionDefinitionList ')'\n\t{\n\t\tret := &ast.AlterTableSpec{\n\t\t\tTp:              ast.AlterTableReorganizePartition,\n\t\t\tPartitionNames:  $1.([]model.CIStr),\n\t\t\tPartDefinitions: $4.([]*ast.PartitionDefinition),\n\t\t}\n\t\t$$ = ret\n\t}\n\nAllOrPartitionNameList:\n\t\"ALL\"\n\t{\n\t\t$$ = nil\n\t}\n|\tPartitionNameList %prec lowerThanComma\n\t{\n\t\t$$ = $1\n\t}\n\nWithValidationOpt:\n\t{\n\t\t$$ = true\n\t}\n|\tWithValidation\n\t{\n\t\t$$ = $1\n\t}\n\nWithValidation:\n\t\"WITH\" \"VALIDATION\"\n\t{\n\t\t$$ = true\n\t}\n|\t\"WITHOUT\" \"VALIDATION\"\n\t{\n\t\t$$ = false\n\t}\n\nAlgorithmClause:\n\t\"ALGORITHM\" EqOpt \"DEFAULT\"\n\t{\n\t\t$$ = ast.AlgorithmTypeDefault\n\t}\n|\t\"ALGORITHM\" EqOpt \"COPY\"\n\t{\n\t\t$$ = ast.AlgorithmTypeCopy\n\t}\n|\t\"ALGORITHM\" EqOpt \"INPLACE\"\n\t{\n\t\t$$ = ast.AlgorithmTypeInplace\n\t}\n|\t\"ALGORITHM\" EqOpt \"INSTANT\"\n\t{\n\t\t$$ = ast.AlgorithmTypeInstant\n\t}\n|\t\"ALGORITHM\" EqOpt identifier\n\t{\n\t\tyylex.AppendError(ErrUnknownAlterAlgorithm.GenWithStackByArgs($1))\n\t\treturn 1\n\t}\n\nLockClause:\n\t\"LOCK\" EqOpt \"DEFAULT\"\n\t{\n\t\t$$ = ast.LockTypeDefault\n\t}\n|\t\"LOCK\" EqOpt Identifier\n\t{\n\t\tid := strings.ToUpper($3)\n\n\t\tif id == \"NONE\" {\n\t\t\t$$ = ast.LockTypeNone\n\t\t} else if id == \"SHARED\" {\n\t\t\t$$ = ast.LockTypeShared\n\t\t} else if id == \"EXCLUSIVE\" {\n\t\t\t$$ = ast.LockTypeExclusive\n\t\t} else {\n\t\t\tyylex.AppendError(ErrUnknownAlterLock.GenWithStackByArgs($3))\n\t\t\treturn 1\n\t\t}\n\t}\n\nKeyOrIndex:\n\t\"KEY\"\n|\t\"INDEX\"\n\nKeyOrIndexOpt:\n\t{}\n|\tKeyOrIndex\n\nColumnKeywordOpt:\n\t{}\n|\t\"COLUMN\"\n\nColumnPosition:\n\t{\n\t\t$$ = &ast.ColumnPosition{Tp: ast.ColumnPositionNone}\n\t}\n|\t\"FIRST\"\n\t{\n\t\t$$ = &ast.ColumnPosition{Tp: ast.ColumnPositionFirst}\n\t}\n|\t\"AFTER\" ColumnName\n\t{\n\t\t$$ = &ast.ColumnPosition{\n\t\t\tTp:             ast.ColumnPositionAfter,\n\t\t\tRelativeColumn: $2.(*ast.ColumnName),\n\t\t}\n\t}\n\nAlterTableSpecListOpt:\n\t/* empty */\n\t{\n\t\t$$ = make([]*ast.AlterTableSpec, 0, 1)\n\t}\n|\tAlterTableSpecList\n\t{\n\t\t$$ = $1\n\t}\n\nAlterTableSpecList:\n\tAlterTableSpec\n\t{\n\t\t$$ = []*ast.AlterTableSpec{$1.(*ast.AlterTableSpec)}\n\t}\n|\tAlterTableSpecList ',' AlterTableSpec\n\t{\n\t\t$$ = append($1.([]*ast.AlterTableSpec), $3.(*ast.AlterTableSpec))\n\t}\n\nPartitionNameList:\n\tIdentifier\n\t{\n\t\t$$ = []model.CIStr{model.NewCIStr($1)}\n\t}\n|\tPartitionNameList ',' Identifier\n\t{\n\t\t$$ = append($1.([]model.CIStr), model.NewCIStr($3))\n\t}\n\nConstraintKeywordOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"CONSTRAINT\"\n\t{\n\t\t$$ = nil\n\t}\n|\t\"CONSTRAINT\" Symbol\n\t{\n\t\t$$ = $2.(string)\n\t}\n\nSymbol:\n\tIdentifier\n\t{\n\t\t$$ = $1\n\t}\n\n/**************************************RenameTableStmt***************************************\n * See http://dev.mysql.com/doc/refman/5.7/en/rename-table.html\n *\n * TODO: refactor this when you are going to add full support for multiple schema changes.\n * Currently it is only useful for syncer which depends heavily on tidb parser to do some dirty work.\n *******************************************************************************************/\nRenameTableStmt:\n\t\"RENAME\" \"TABLE\" TableToTableList\n\t{\n\t\t$$ = &ast.RenameTableStmt{\n\t\t\tOldTable:      $3.([]*ast.TableToTable)[0].OldTable,\n\t\t\tNewTable:      $3.([]*ast.TableToTable)[0].NewTable,\n\t\t\tTableToTables: $3.([]*ast.TableToTable),\n\t\t}\n\t}\n\nTableToTableList:\n\tTableToTable\n\t{\n\t\t$$ = []*ast.TableToTable{$1.(*ast.TableToTable)}\n\t}\n|\tTableToTableList ',' TableToTable\n\t{\n\t\t$$ = append($1.([]*ast.TableToTable), $3.(*ast.TableToTable))\n\t}\n\nTableToTable:\n\tTableName \"TO\" TableName\n\t{\n\t\t$$ = &ast.TableToTable{\n\t\t\tOldTable: $1.(*ast.TableName),\n\t\t\tNewTable: $3.(*ast.TableName),\n\t\t}\n\t}\n\n/*******************************************************************\n *\n *  Recover Table Statement\n *\n *  Example:\n *      RECOVER TABLE t1;\n *      RECOVER TABLE BY JOB 100;\n *\n *******************************************************************/\nRecoverTableStmt:\n\t\"RECOVER\" \"TABLE\" \"BY\" \"JOB\" NUM\n\t{\n\t\t$$ = &ast.RecoverTableStmt{\n\t\t\tJobID: $5.(int64),\n\t\t}\n\t}\n|\t\"RECOVER\" \"TABLE\" TableName\n\t{\n\t\t$$ = &ast.RecoverTableStmt{\n\t\t\tTable: $3.(*ast.TableName),\n\t\t}\n\t}\n|\t\"RECOVER\" \"TABLE\" TableName NUM\n\t{\n\t\t$$ = &ast.RecoverTableStmt{\n\t\t\tTable:  $3.(*ast.TableName),\n\t\t\tJobNum: $4.(int64),\n\t\t}\n\t}\n\n/*******************************************************************\n *\n *  Flush Back Table Statement\n *\n *  Example:\n *\n *******************************************************************/\nFlashbackTableStmt:\n\t\"FLASHBACK\" \"TABLE\" TableName FlashbackUntil FlashbackToNewName\n\t{\n\t\t$$ = &ast.FlashBackTableStmt{\n\t\t\tTable:     $3.(*ast.TableName),\n\t\t\tTimestamp: $4.(ast.ValueExpr),\n\t\t\tNewName:   $5.(string),\n\t\t}\n\t}\n\nFlashbackUntil:\n\t\"UNTIL\" \"TIMESTAMP\" StringLiteral\n\t{\n\t\t$$ = $3\n\t}\n\nFlashbackToNewName:\n\t{\n\t\t$$ = \"\"\n\t}\n|\t\"TO\" Identifier\n\t{\n\t\t$$ = $2\n\t}\n\n/*******************************************************************\n *\n *  Split index region statement\n *\n *  Example:\n *      SPLIT TABLE table_name INDEX index_name BY (val1...),(val2...)...\n *\n *******************************************************************/\nSplitRegionStmt:\n\t\"SPLIT\" SplitSyntaxOption \"TABLE\" TableName PartitionNameListOpt SplitOption\n\t{\n\t\t$$ = &ast.SplitRegionStmt{\n\t\t\tSplitSyntaxOpt: $2.(*ast.SplitSyntaxOption),\n\t\t\tTable:          $4.(*ast.TableName),\n\t\t\tPartitionNames: $5.([]model.CIStr),\n\t\t\tSplitOpt:       $6.(*ast.SplitOption),\n\t\t}\n\t}\n|\t\"SPLIT\" SplitSyntaxOption \"TABLE\" TableName PartitionNameListOpt \"INDEX\" Identifier SplitOption\n\t{\n\t\t$$ = &ast.SplitRegionStmt{\n\t\t\tSplitSyntaxOpt: $2.(*ast.SplitSyntaxOption),\n\t\t\tTable:          $4.(*ast.TableName),\n\t\t\tPartitionNames: $5.([]model.CIStr),\n\t\t\tIndexName:      model.NewCIStr($7),\n\t\t\tSplitOpt:       $8.(*ast.SplitOption),\n\t\t}\n\t}\n\nSplitOption:\n\t\"BETWEEN\" RowValue \"AND\" RowValue \"REGIONS\" NUM\n\t{\n\t\t$$ = &ast.SplitOption{\n\t\t\tLower: $2.([]ast.ExprNode),\n\t\t\tUpper: $4.([]ast.ExprNode),\n\t\t\tNum:   $6.(int64),\n\t\t}\n\t}\n|\t\"BY\" ValuesList\n\t{\n\t\t$$ = &ast.SplitOption{\n\t\t\tValueLists: $2.([][]ast.ExprNode),\n\t\t}\n\t}\n\nSplitSyntaxOption:\n\t/* empty */\n\t{\n\t\t$$ = &ast.SplitSyntaxOption{}\n\t}\n|\t\"REGION\" \"FOR\"\n\t{\n\t\t$$ = &ast.SplitSyntaxOption{\n\t\t\tHasRegionFor: true,\n\t\t}\n\t}\n|\t\"PARTITION\"\n\t{\n\t\t$$ = &ast.SplitSyntaxOption{\n\t\t\tHasPartition: true,\n\t\t}\n\t}\n|\t\"REGION\" \"FOR\" \"PARTITION\"\n\t{\n\t\t$$ = &ast.SplitSyntaxOption{\n\t\t\tHasRegionFor: true,\n\t\t\tHasPartition: true,\n\t\t}\n\t}\n\nAnalyzeTableStmt:\n\t\"ANALYZE\" \"TABLE\" TableNameList AnalyzeOptionListOpt\n\t{\n\t\t$$ = &ast.AnalyzeTableStmt{TableNames: $3.([]*ast.TableName), AnalyzeOpts: $4.([]ast.AnalyzeOpt)}\n\t}\n|\t\"ANALYZE\" \"TABLE\" TableName \"INDEX\" IndexNameList AnalyzeOptionListOpt\n\t{\n\t\t$$ = &ast.AnalyzeTableStmt{TableNames: []*ast.TableName{$3.(*ast.TableName)}, IndexNames: $5.([]model.CIStr), IndexFlag: true, AnalyzeOpts: $6.([]ast.AnalyzeOpt)}\n\t}\n|\t\"ANALYZE\" \"INCREMENTAL\" \"TABLE\" TableName \"INDEX\" IndexNameList AnalyzeOptionListOpt\n\t{\n\t\t$$ = &ast.AnalyzeTableStmt{TableNames: []*ast.TableName{$4.(*ast.TableName)}, IndexNames: $6.([]model.CIStr), IndexFlag: true, Incremental: true, AnalyzeOpts: $7.([]ast.AnalyzeOpt)}\n\t}\n|\t\"ANALYZE\" \"TABLE\" TableName \"PARTITION\" PartitionNameList AnalyzeOptionListOpt\n\t{\n\t\t$$ = &ast.AnalyzeTableStmt{TableNames: []*ast.TableName{$3.(*ast.TableName)}, PartitionNames: $5.([]model.CIStr), AnalyzeOpts: $6.([]ast.AnalyzeOpt)}\n\t}\n|\t\"ANALYZE\" \"TABLE\" TableName \"PARTITION\" PartitionNameList \"INDEX\" IndexNameList AnalyzeOptionListOpt\n\t{\n\t\t$$ = &ast.AnalyzeTableStmt{\n\t\t\tTableNames:     []*ast.TableName{$3.(*ast.TableName)},\n\t\t\tPartitionNames: $5.([]model.CIStr),\n\t\t\tIndexNames:     $7.([]model.CIStr),\n\t\t\tIndexFlag:      true,\n\t\t\tAnalyzeOpts:    $8.([]ast.AnalyzeOpt),\n\t\t}\n\t}\n|\t\"ANALYZE\" \"INCREMENTAL\" \"TABLE\" TableName \"PARTITION\" PartitionNameList \"INDEX\" IndexNameList AnalyzeOptionListOpt\n\t{\n\t\t$$ = &ast.AnalyzeTableStmt{\n\t\t\tTableNames:     []*ast.TableName{$4.(*ast.TableName)},\n\t\t\tPartitionNames: $6.([]model.CIStr),\n\t\t\tIndexNames:     $8.([]model.CIStr),\n\t\t\tIndexFlag:      true,\n\t\t\tIncremental:    true,\n\t\t\tAnalyzeOpts:    $9.([]ast.AnalyzeOpt),\n\t\t}\n\t}\n\nAnalyzeOptionListOpt:\n\t{\n\t\t$$ = []ast.AnalyzeOpt{}\n\t}\n|\t\"WITH\" AnalyzeOptionList\n\t{\n\t\t$$ = $2.([]ast.AnalyzeOpt)\n\t}\n\nAnalyzeOptionList:\n\tAnalyzeOption\n\t{\n\t\t$$ = []ast.AnalyzeOpt{$1.(ast.AnalyzeOpt)}\n\t}\n|\tAnalyzeOptionList ',' AnalyzeOption\n\t{\n\t\t$$ = append($1.([]ast.AnalyzeOpt), $3.(ast.AnalyzeOpt))\n\t}\n\nAnalyzeOption:\n\tNUM \"BUCKETS\"\n\t{\n\t\t$$ = ast.AnalyzeOpt{Type: ast.AnalyzeOptNumBuckets, Value: getUint64FromNUM($1)}\n\t}\n|\tNUM \"TOPN\"\n\t{\n\t\t$$ = ast.AnalyzeOpt{Type: ast.AnalyzeOptNumTopN, Value: getUint64FromNUM($1)}\n\t}\n|\tNUM \"CMSKETCH\" \"DEPTH\"\n\t{\n\t\t$$ = ast.AnalyzeOpt{Type: ast.AnalyzeOptCMSketchDepth, Value: getUint64FromNUM($1)}\n\t}\n|\tNUM \"CMSKETCH\" \"WIDTH\"\n\t{\n\t\t$$ = ast.AnalyzeOpt{Type: ast.AnalyzeOptCMSketchWidth, Value: getUint64FromNUM($1)}\n\t}\n|\tNUM \"SAMPLES\"\n\t{\n\t\t$$ = ast.AnalyzeOpt{Type: ast.AnalyzeOptNumSamples, Value: getUint64FromNUM($1)}\n\t}\n\n/*******************************************************************************************/\nAssignment:\n\tColumnName eq ExprOrDefault\n\t{\n\t\t$$ = &ast.Assignment{Column: $1.(*ast.ColumnName), Expr: $3}\n\t}\n\nAssignmentList:\n\tAssignment\n\t{\n\t\t$$ = []*ast.Assignment{$1.(*ast.Assignment)}\n\t}\n|\tAssignmentList ',' Assignment\n\t{\n\t\t$$ = append($1.([]*ast.Assignment), $3.(*ast.Assignment))\n\t}\n\nAssignmentListOpt:\n\t/* EMPTY */\n\t{\n\t\t$$ = []*ast.Assignment{}\n\t}\n|\tAssignmentList\n\nBeginTransactionStmt:\n\t\"BEGIN\"\n\t{\n\t\t$$ = &ast.BeginStmt{}\n\t}\n|\t\"BEGIN\" \"PESSIMISTIC\"\n\t{\n\t\t$$ = &ast.BeginStmt{\n\t\t\tMode: ast.Pessimistic,\n\t\t}\n\t}\n|\t\"BEGIN\" \"OPTIMISTIC\"\n\t{\n\t\t$$ = &ast.BeginStmt{\n\t\t\tMode: ast.Optimistic,\n\t\t}\n\t}\n|\t\"START\" \"TRANSACTION\"\n\t{\n\t\t$$ = &ast.BeginStmt{}\n\t}\n|\t\"START\" \"TRANSACTION\" \"READ\" \"WRITE\"\n\t{\n\t\t$$ = &ast.BeginStmt{}\n\t}\n|\t\"START\" \"TRANSACTION\" \"WITH\" \"CONSISTENT\" \"SNAPSHOT\"\n\t{\n\t\t$$ = &ast.BeginStmt{}\n\t}\n|\t\"START\" \"TRANSACTION\" \"READ\" \"ONLY\"\n\t{\n\t\t$$ = &ast.BeginStmt{\n\t\t\tReadOnly: true,\n\t\t}\n\t}\n|\t\"START\" \"TRANSACTION\" \"READ\" \"ONLY\" \"WITH\" \"TIMESTAMP\" \"BOUND\" TimestampBound\n\t{\n\t\t$$ = &ast.BeginStmt{\n\t\t\tReadOnly: true,\n\t\t\tBound:    $8.(*ast.TimestampBound),\n\t\t}\n\t}\n\nTimestampBound:\n\t\"STRONG\"\n\t{\n\t\t$$ = &ast.TimestampBound{\n\t\t\tMode: ast.TimestampBoundStrong,\n\t\t}\n\t}\n|\t\"READ\" \"TIMESTAMP\" Expression\n\t{\n\t\t$$ = &ast.TimestampBound{\n\t\t\tMode:      ast.TimestampBoundReadTimestamp,\n\t\t\tTimestamp: $3.(ast.ExprNode),\n\t\t}\n\t}\n|\t\"MIN\" \"READ\" \"TIMESTAMP\" Expression\n\t{\n\t\t$$ = &ast.TimestampBound{\n\t\t\tMode:      ast.TimestampBoundMinReadTimestamp,\n\t\t\tTimestamp: $4.(ast.ExprNode),\n\t\t}\n\t}\n|\t\"MAX\" \"STALENESS\" Expression\n\t{\n\t\t$$ = &ast.TimestampBound{\n\t\t\tMode:      ast.TimestampBoundMaxStaleness,\n\t\t\tTimestamp: $3.(ast.ExprNode),\n\t\t}\n\t}\n|\t\"EXACT\" \"STALENESS\" Expression\n\t{\n\t\t$$ = &ast.TimestampBound{\n\t\t\tMode:      ast.TimestampBoundExactStaleness,\n\t\t\tTimestamp: $3.(ast.ExprNode),\n\t\t}\n\t}\n\nBinlogStmt:\n\t\"BINLOG\" stringLit\n\t{\n\t\t$$ = &ast.BinlogStmt{Str: $2}\n\t}\n\nColumnDefList:\n\tColumnDef\n\t{\n\t\t$$ = []*ast.ColumnDef{$1.(*ast.ColumnDef)}\n\t}\n|\tColumnDefList ',' ColumnDef\n\t{\n\t\t$$ = append($1.([]*ast.ColumnDef), $3.(*ast.ColumnDef))\n\t}\n\nColumnDef:\n\tColumnName TypeName ColumnOptionListOpt\n\t{\n\t\tcolDef := &ast.ColumnDef{Name: $1.(*ast.ColumnName), Type: $2.(string), Options: $3.([]*ast.ColumnOption)}\n\t\tif !colDef.Validate() {\n\t\t\tyylex.AppendError(yylex.Errorf(\"Invalid column definition\"))\n\t\t\treturn 1\n\t\t}\n\t\t$$ = colDef\n\t}\n\nColumnName:\n\tIdentifier\n\t{\n\t\t$$ = &ast.ColumnName{Name: model.NewCIStr($1)}\n\t}\n|\tIdentifier '.' Identifier\n\t{\n\t\t$$ = &ast.ColumnName{Table: model.NewCIStr($1), Name: model.NewCIStr($3)}\n\t}\n|\tIdentifier '.' Identifier '.' Identifier\n\t{\n\t\t$$ = &ast.ColumnName{Schema: model.NewCIStr($1), Table: model.NewCIStr($3), Name: model.NewCIStr($5)}\n\t}\n\nTypeName:\n\tIdentifier\n\t{\n\t\t$$ = $1\n\t}\n|\tstringLit\n\t{\n\t\t$$ = $1\n\t}\n|\t\"LONG\"\n\t{\n\t\t$$ = \"LONG\"\n\t}\n|\t\"INT\"\n\t{\n\t\t$$ = \"INT\"\n\t}\n|\t\"FLOAT\"\n\t{\n\t\t$$ = \"FLOAT\"\n\t}\n|\t\"DOUBLE\"\n\t{\n\t\t$$ = \"DOUBLE\"\n\t}\n\nColumnNameList:\n\tColumnName\n\t{\n\t\t$$ = []*ast.ColumnName{$1.(*ast.ColumnName)}\n\t}\n|\tColumnNameList ',' ColumnName\n\t{\n\t\t$$ = append($1.([]*ast.ColumnName), $3.(*ast.ColumnName))\n\t}\n\nColumnNameListOpt:\n\t/* EMPTY */\n\t{\n\t\t$$ = []*ast.ColumnName{}\n\t}\n|\tColumnNameList\n\t{\n\t\t$$ = $1.([]*ast.ColumnName)\n\t}\n\nColumnNameOrUserVarListOpt:\n\t/* EMPTY */\n\t{\n\t\t$$ = []*ast.ColumnNameOrUserVar{}\n\t}\n|\tColumnNameOrUserVariableList\n\t{\n\t\t$$ = $1.([]*ast.ColumnNameOrUserVar)\n\t}\n\nColumnNameOrUserVariableList:\n\tColumnNameOrUserVariable\n\t{\n\t\t$$ = []*ast.ColumnNameOrUserVar{$1.(*ast.ColumnNameOrUserVar)}\n\t}\n|\tColumnNameOrUserVariableList ',' ColumnNameOrUserVariable\n\t{\n\t\t$$ = append($1.([]*ast.ColumnNameOrUserVar), $3.(*ast.ColumnNameOrUserVar))\n\t}\n\nColumnNameOrUserVariable:\n\tColumnName\n\t{\n\t\t$$ = &ast.ColumnNameOrUserVar{ColumnName: $1.(*ast.ColumnName)}\n\t}\n|\tUserVariable\n\t{\n\t\t$$ = &ast.ColumnNameOrUserVar{UserVar: $1.(*ast.VariableExpr)}\n\t}\n\nColumnNameOrUserVarListOptWithBrackets:\n\t/* EMPTY */\n\t{\n\t\t$$ = []*ast.ColumnNameOrUserVar{}\n\t}\n|\t'(' ColumnNameOrUserVarListOpt ')'\n\t{\n\t\t$$ = $2.([]*ast.ColumnNameOrUserVar)\n\t}\n\nCommitStmt:\n\t\"COMMIT\"\n\t{\n\t\t$$ = &ast.CommitStmt{}\n\t}\n\nPrimaryOpt:\n\t{}\n|\t\"PRIMARY\"\n\nEnforcedOrNot:\n\t\"ENFORCED\"\n\t{\n\t\t$$ = true\n\t}\n|\t\"NOT\" \"ENFORCED\"\n\t{\n\t\t$$ = false\n\t}\n\nEnforcedOrNotOpt:\n\t%prec lowerThanNot\n\t{\n\t\t$$ = true\n\t}\n|\tEnforcedOrNot\n\t{\n\t\t$$ = $1\n\t}\n\nEnforcedOrNotOrNotNullOpt:\n\t//\t This branch is needed to workaround the need of a lookahead of 2 for the grammar:\n\t//\n\t//\t  { [NOT] NULL | CHECK(...) [NOT] ENFORCED } ...\n\t\"NOT\" \"NULL\"\n\t{\n\t\t$$ = 0\n\t}\n|\tEnforcedOrNotOpt\n\t{\n\t\tif $1.(bool) {\n\t\t\t$$ = 1\n\t\t} else {\n\t\t\t$$ = 2\n\t\t}\n\t}\n\nColumnOption:\n\t\"NOT\" \"NULL\"\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionNotNull}\n\t}\n|\t\"NULL\"\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionNull}\n\t}\n|\t\"AUTO_INCREMENT\"\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionAutoIncrement}\n\t}\n|\tPrimaryOpt \"KEY\"\n\t{\n\t\t// KEY is normally a synonym for INDEX. The key attribute PRIMARY KEY\n\t\t// can also be specified as just KEY when given in a column definition.\n\t\t// See http://dev.mysql.com/doc/refman/5.7/en/create-table.html\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionPrimaryKey}\n\t}\n|\t\"UNIQUE\" %prec lowerThanKey\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionUniqKey}\n\t}\n|\t\"UNIQUE\" \"KEY\"\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionUniqKey}\n\t}\n|\t\"DEFAULT\" DefaultValueExpr\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionDefaultValue, Expr: $2}\n\t}\n|\t\"SERIAL\" \"DEFAULT\" \"VALUE\"\n\t{\n\t\t$$ = []*ast.ColumnOption{{Tp: ast.ColumnOptionNotNull}, {Tp: ast.ColumnOptionAutoIncrement}, {Tp: ast.ColumnOptionUniqKey}}\n\t}\n|\t\"ON\" \"UPDATE\" NowSymOptionFraction\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionOnUpdate, Expr: $3}\n\t}\n|\t\"COMMENT\" stringLit\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionComment, Expr: ast.NewValueExpr($2)}\n\t}\n|\tConstraintKeywordOpt \"CHECK\" '(' Expression ')' EnforcedOrNotOrNotNullOpt\n\t{\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/create-table.html\n\t\t// The CHECK clause is parsed but ignored by all storage engines.\n\t\t// See the branch named `EnforcedOrNotOrNotNullOpt`.\n\n\t\toptionCheck := &ast.ColumnOption{\n\t\t\tTp:       ast.ColumnOptionCheck,\n\t\t\tExpr:     $4,\n\t\t\tEnforced: true,\n\t\t}\n\t\tswitch $6.(int) {\n\t\tcase 0:\n\t\t\t$$ = []*ast.ColumnOption{optionCheck, {Tp: ast.ColumnOptionNotNull}}\n\t\tcase 1:\n\t\t\toptionCheck.Enforced = true\n\t\t\t$$ = optionCheck\n\t\tcase 2:\n\t\t\toptionCheck.Enforced = false\n\t\t\t$$ = optionCheck\n\t\tdefault:\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The CHECK clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\tGeneratedAlways \"AS\" '(' Expression ')' VirtualOrStored\n\t{\n\t\tstartOffset := parser.startOffset(&yyS[yypt-2])\n\t\tendOffset := parser.endOffset(&yyS[yypt-1])\n\t\texpr := $4\n\t\texpr.SetText(parser.src[startOffset:endOffset])\n\n\t\t$$ = &ast.ColumnOption{\n\t\t\tTp:     ast.ColumnOptionGenerated,\n\t\t\tExpr:   expr,\n\t\t\tStored: $6.(bool),\n\t\t}\n\t}\n|\tReferDef\n\t{\n\t\t$$ = &ast.ColumnOption{\n\t\t\tTp:    ast.ColumnOptionReference,\n\t\t\tRefer: $1.(*ast.ReferenceDef),\n\t\t}\n\t}\n|\t\"COLLATE\" CollationName\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionCollate, StrValue: $2.(string)}\n\t}\n|\t\"COLUMN_FORMAT\" ColumnFormat\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionColumnFormat, StrValue: $2.(string)}\n\t}\n|\t\"STORAGE\" StorageMedia\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionStorage, StrValue: $2}\n\t\tyylex.AppendError(yylex.Errorf(\"The STORAGE clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"AUTO_RANDOM\" OptFieldLen\n\t{\n\t\t$$ = &ast.ColumnOption{Tp: ast.ColumnOptionAutoRandom, AutoRandomBitLength: $2.(int)}\n\t}\n\nStorageMedia:\n\t\"DEFAULT\"\n|\t\"DISK\"\n|\t\"MEMORY\"\n\nColumnFormat:\n\t\"DEFAULT\"\n\t{\n\t\t$$ = \"DEFAULT\"\n\t}\n|\t\"FIXED\"\n\t{\n\t\t$$ = \"FIXED\"\n\t}\n|\t\"DYNAMIC\"\n\t{\n\t\t$$ = \"DYNAMIC\"\n\t}\n\nGeneratedAlways:\n\n|\t\"GENERATED\" \"ALWAYS\"\n\nVirtualOrStored:\n\t{\n\t\t$$ = false\n\t}\n|\t\"VIRTUAL\"\n\t{\n\t\t$$ = false\n\t}\n|\t\"STORED\"\n\t{\n\t\t$$ = true\n\t}\n\nColumnOptionList:\n\tColumnOption\n\t{\n\t\tif columnOption, ok := $1.(*ast.ColumnOption); ok {\n\t\t\t$$ = []*ast.ColumnOption{columnOption}\n\t\t} else {\n\t\t\t$$ = $1\n\t\t}\n\t}\n|\tColumnOptionList ColumnOption\n\t{\n\t\tif columnOption, ok := $2.(*ast.ColumnOption); ok {\n\t\t\t$$ = append($1.([]*ast.ColumnOption), columnOption)\n\t\t} else {\n\t\t\t$$ = append($1.([]*ast.ColumnOption), $2.([]*ast.ColumnOption)...)\n\t\t}\n\t}\n\nColumnOptionListOpt:\n\t{\n\t\t$$ = []*ast.ColumnOption{}\n\t}\n|\tColumnOptionList\n\t{\n\t\t$$ = $1.([]*ast.ColumnOption)\n\t}\n\nConstraintElem:\n\t\"PRIMARY\" \"KEY\" IndexNameAndTypeOpt '(' IndexPartSpecificationList ')' IndexOptionList\n\t{\n\t\tc := &ast.Constraint{\n\t\t\tTp:   ast.ConstraintPrimaryKey,\n\t\t\tKeys: $5.([]*ast.IndexPartSpecification),\n\t\t\tName: $3.([]interface{})[0].(string),\n\t\t}\n\t\tif $7 != nil {\n\t\t\tc.Option = $7.(*ast.IndexOption)\n\t\t}\n\t\tif indexType := $3.([]interface{})[1]; indexType != nil {\n\t\t\tif c.Option == nil {\n\t\t\t\tc.Option = &ast.IndexOption{}\n\t\t\t}\n\t\t\tc.Option.Tp = indexType.(model.IndexType)\n\t\t}\n\t\t$$ = c\n\t}\n|\t\"FULLTEXT\" KeyOrIndexOpt IndexName '(' IndexPartSpecificationList ')' IndexOptionList\n\t{\n\t\tc := &ast.Constraint{\n\t\t\tTp:   ast.ConstraintFulltext,\n\t\t\tKeys: $5.([]*ast.IndexPartSpecification),\n\t\t\tName: $3.(string),\n\t\t}\n\t\tif $7 != nil {\n\t\t\tc.Option = $7.(*ast.IndexOption)\n\t\t}\n\t\t$$ = c\n\t}\n|\tKeyOrIndex IfNotExists IndexNameAndTypeOpt '(' IndexPartSpecificationList ')' IndexOptionList\n\t{\n\t\tc := &ast.Constraint{\n\t\t\tIfNotExists: $2.(bool),\n\t\t\tTp:          ast.ConstraintIndex,\n\t\t\tKeys:        $5.([]*ast.IndexPartSpecification),\n\t\t}\n\t\tif $7 != nil {\n\t\t\tc.Option = $7.(*ast.IndexOption)\n\t\t}\n\t\tc.Name = $3.([]interface{})[0].(string)\n\t\tif indexType := $3.([]interface{})[1]; indexType != nil {\n\t\t\tif c.Option == nil {\n\t\t\t\tc.Option = &ast.IndexOption{}\n\t\t\t}\n\t\t\tc.Option.Tp = indexType.(model.IndexType)\n\t\t}\n\t\t$$ = c\n\t}\n|\t\"UNIQUE\" KeyOrIndexOpt IndexNameAndTypeOpt '(' IndexPartSpecificationList ')' IndexOptionList\n\t{\n\t\tc := &ast.Constraint{\n\t\t\tTp:   ast.ConstraintUniq,\n\t\t\tKeys: $5.([]*ast.IndexPartSpecification),\n\t\t}\n\t\tif $7 != nil {\n\t\t\tc.Option = $7.(*ast.IndexOption)\n\t\t}\n\t\tc.Name = $3.([]interface{})[0].(string)\n\t\tif indexType := $3.([]interface{})[1]; indexType != nil {\n\t\t\tif c.Option == nil {\n\t\t\t\tc.Option = &ast.IndexOption{}\n\t\t\t}\n\t\t\tc.Option.Tp = indexType.(model.IndexType)\n\t\t}\n\t\t$$ = c\n\t}\n|\t\"FOREIGN\" \"KEY\" IfNotExists IndexName '(' IndexPartSpecificationList ')' ReferDef\n\t{\n\t\t$$ = &ast.Constraint{\n\t\t\tIfNotExists: $3.(bool),\n\t\t\tTp:          ast.ConstraintForeignKey,\n\t\t\tKeys:        $6.([]*ast.IndexPartSpecification),\n\t\t\tName:        $4.(string),\n\t\t\tRefer:       $8.(*ast.ReferenceDef),\n\t\t}\n\t}\n|\t\"CHECK\" '(' Expression ')' EnforcedOrNotOpt\n\t{\n\t\t$$ = &ast.Constraint{\n\t\t\tTp:       ast.ConstraintCheck,\n\t\t\tExpr:     $3.(ast.ExprNode),\n\t\t\tEnforced: $5.(bool),\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The CHECK clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n\nMatch:\n\t\"MATCH\" \"FULL\"\n\t{\n\t\t$$ = ast.MatchFull\n\t}\n|\t\"MATCH\" \"PARTIAL\"\n\t{\n\t\t$$ = ast.MatchPartial\n\t}\n|\t\"MATCH\" \"SIMPLE\"\n\t{\n\t\t$$ = ast.MatchSimple\n\t}\n\nMatchOpt:\n\t{\n\t\t$$ = ast.MatchNone\n\t}\n|\tMatch\n\t{\n\t\t$$ = $1\n\t\tyylex.AppendError(yylex.Errorf(\"The MATCH clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n\nReferDef:\n\t\"REFERENCES\" TableName IndexPartSpecificationListOpt MatchOpt OnDeleteUpdateOpt\n\t{\n\t\tonDeleteUpdate := $5.([2]interface{})\n\t\t$$ = &ast.ReferenceDef{\n\t\t\tTable:                   $2.(*ast.TableName),\n\t\t\tIndexPartSpecifications: $3.([]*ast.IndexPartSpecification),\n\t\t\tOnDelete:                onDeleteUpdate[0].(*ast.OnDeleteOpt),\n\t\t\tOnUpdate:                onDeleteUpdate[1].(*ast.OnUpdateOpt),\n\t\t\tMatch:                   $4.(ast.MatchType),\n\t\t}\n\t}\n\nOnDelete:\n\t\"ON\" \"DELETE\" ReferOpt\n\t{\n\t\t$$ = &ast.OnDeleteOpt{ReferOpt: $3.(ast.ReferOptionType)}\n\t}\n\nOnUpdate:\n\t\"ON\" \"UPDATE\" ReferOpt\n\t{\n\t\t$$ = &ast.OnUpdateOpt{ReferOpt: $3.(ast.ReferOptionType)}\n\t}\n\nOnDeleteUpdateOpt:\n\t%prec lowerThanOn\n\t{\n\t\t$$ = [2]interface{}{&ast.OnDeleteOpt{}, &ast.OnUpdateOpt{}}\n\t}\n|\tOnDelete %prec lowerThanOn\n\t{\n\t\t$$ = [2]interface{}{$1, &ast.OnUpdateOpt{}}\n\t}\n|\tOnUpdate %prec lowerThanOn\n\t{\n\t\t$$ = [2]interface{}{&ast.OnDeleteOpt{}, $1}\n\t}\n|\tOnDelete OnUpdate\n\t{\n\t\t$$ = [2]interface{}{$1, $2}\n\t}\n|\tOnUpdate OnDelete\n\t{\n\t\t$$ = [2]interface{}{$2, $1}\n\t}\n\nReferOpt:\n\t\"RESTRICT\"\n\t{\n\t\t$$ = ast.ReferOptionRestrict\n\t}\n|\t\"CASCADE\"\n\t{\n\t\t$$ = ast.ReferOptionCascade\n\t}\n|\t\"SET\" \"NULL\"\n\t{\n\t\t$$ = ast.ReferOptionSetNull\n\t}\n|\t\"NO\" \"ACTION\"\n\t{\n\t\t$$ = ast.ReferOptionNoAction\n\t}\n|\t\"SET\" \"DEFAULT\"\n\t{\n\t\t$$ = ast.ReferOptionSetDefault\n\t\tyylex.AppendError(yylex.Errorf(\"The SET DEFAULT clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n\n/*\n * The DEFAULT clause specifies a default value for a column.\n * With one exception, the default value must be a constant;\n * it cannot be a function or an expression. This means, for example,\n * that you cannot set the default for a date column to be the value of\n * a function such as NOW() or CURRENT_DATE. The exception is that you\n * can specify CURRENT_TIMESTAMP as the default for a TIMESTAMP or DATETIME column.\n *\n * See http://dev.mysql.com/doc/refman/5.7/en/create-table.html\n *      https://github.com/mysql/mysql-server/blob/5.7/sql/sql_yacc.yy#L6832\n */\nDefaultValueExpr:\n\tNowSymOptionFraction\n|\tSignedLiteral\n\nNowSymOptionFraction:\n\tNowSym\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(\"CURRENT_TIMESTAMP\")}\n\t}\n|\tNowSymFunc '(' ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(\"CURRENT_TIMESTAMP\")}\n\t}\n|\tNowSymFunc '(' NUM ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(\"CURRENT_TIMESTAMP\"), Args: []ast.ExprNode{ast.NewValueExpr($3)}}\n\t}\n\n/*\n* See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_localtime\n* TODO: Process other three keywords\n*/\nNowSymFunc:\n\t\"CURRENT_TIMESTAMP\"\n|\t\"LOCALTIME\"\n|\t\"LOCALTIMESTAMP\"\n|\tbuiltinNow\n\nNowSym:\n\t\"CURRENT_TIMESTAMP\"\n|\t\"LOCALTIME\"\n|\t\"LOCALTIMESTAMP\"\n\nSignedLiteral:\n\tLiteral\n\t{\n\t\t$$ = ast.NewValueExpr($1)\n\t}\n|\t'+' NumLiteral\n\t{\n\t\t$$ = &ast.UnaryOperationExpr{Op: opcode.Plus, V: ast.NewValueExpr($2)}\n\t}\n|\t'-' NumLiteral\n\t{\n\t\t$$ = &ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr($2)}\n\t}\n\nNumLiteral:\n\tintLit\n|\tfloatLit\n|\tdecLit\n\n/**************************************CreateIndexStmt***************************************\n * See https://dev.mysql.com/doc/refman/8.0/en/create-index.html\n *\n * TYPE type_name is recognized as a synonym for USING type_name. However, USING is the preferred form.\n *\n * CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name\n *     [index_type]\n *     ON tbl_name (key_part,...)\n *     [index_option]\n *     [algorithm_option | lock_option] ...\n *\n * key_part: {col_name [(length)] | (expr)} [ASC | DESC]\n *\n * index_option:\n *     KEY_BLOCK_SIZE [=] value\n *   | index_type\n *   | WITH PARSER parser_name\n *   | COMMENT 'string'\n *   | {VISIBLE | INVISIBLE}\n *\n * index_type:\n *     USING {BTREE | HASH}\n *\n * algorithm_option:\n *     ALGORITHM [=] {DEFAULT | INPLACE | COPY}\n *\n * lock_option:\n *     LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}\n *******************************************************************************************/\nCreateIndexStmt:\n\t\"CREATE\" IndexKeyTypeOpt \"INDEX\" IfNotExists Identifier IndexTypeOpt \"ON\" TableName '(' IndexPartSpecificationList ')' IndexOptionList IndexLockAndAlgorithmOpt\n\t{\n\t\tvar indexOption *ast.IndexOption\n\t\tif $12 != nil {\n\t\t\tindexOption = $12.(*ast.IndexOption)\n\t\t\tif indexOption.Tp == model.IndexTypeInvalid {\n\t\t\t\tif $6 != nil {\n\t\t\t\t\tindexOption.Tp = $6.(model.IndexType)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tindexOption = &ast.IndexOption{}\n\t\t\tif $6 != nil {\n\t\t\t\tindexOption.Tp = $6.(model.IndexType)\n\t\t\t}\n\t\t}\n\t\tvar indexLockAndAlgorithm *ast.IndexLockAndAlgorithm\n\t\tif $13 != nil {\n\t\t\tindexLockAndAlgorithm = $13.(*ast.IndexLockAndAlgorithm)\n\t\t\tif indexLockAndAlgorithm.LockTp == ast.LockTypeDefault && indexLockAndAlgorithm.AlgorithmTp == ast.AlgorithmTypeDefault {\n\t\t\t\tindexLockAndAlgorithm = nil\n\t\t\t}\n\t\t}\n\t\t$$ = &ast.CreateIndexStmt{\n\t\t\tIfNotExists:             $4.(bool),\n\t\t\tIndexName:               $5,\n\t\t\tTable:                   $8.(*ast.TableName),\n\t\t\tIndexPartSpecifications: $10.([]*ast.IndexPartSpecification),\n\t\t\tIndexOption:             indexOption,\n\t\t\tKeyType:                 $2.(ast.IndexKeyType),\n\t\t\tLockAlg:                 indexLockAndAlgorithm,\n\t\t}\n\t}\n\nIndexPartSpecificationListOpt:\n\t{\n\t\t$$ = ([]*ast.IndexPartSpecification)(nil)\n\t}\n|\t'(' IndexPartSpecificationList ')'\n\t{\n\t\t$$ = $2\n\t}\n\nIndexPartSpecificationList:\n\tIndexPartSpecification\n\t{\n\t\t$$ = []*ast.IndexPartSpecification{$1.(*ast.IndexPartSpecification)}\n\t}\n|\tIndexPartSpecificationList ',' IndexPartSpecification\n\t{\n\t\t$$ = append($1.([]*ast.IndexPartSpecification), $3.(*ast.IndexPartSpecification))\n\t}\n\nIndexPartSpecification:\n\tColumnName OptFieldLen Order\n\t{\n\t\t// Order is parsed but just ignored as MySQL did.\n\t\t$$ = &ast.IndexPartSpecification{Column: $1.(*ast.ColumnName), Length: $2.(int)}\n\t}\n|\t'(' Expression ')' Order\n\t{\n\t\t$$ = &ast.IndexPartSpecification{Expr: $2}\n\t}\n\nIndexLockAndAlgorithmOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\tLockClause\n\t{\n\t\t$$ = &ast.IndexLockAndAlgorithm{\n\t\t\tLockTp:      $1.(ast.LockType),\n\t\t\tAlgorithmTp: ast.AlgorithmTypeDefault,\n\t\t}\n\t}\n|\tAlgorithmClause\n\t{\n\t\t$$ = &ast.IndexLockAndAlgorithm{\n\t\t\tLockTp:      ast.LockTypeDefault,\n\t\t\tAlgorithmTp: $1.(ast.AlgorithmType),\n\t\t}\n\t}\n|\tLockClause AlgorithmClause\n\t{\n\t\t$$ = &ast.IndexLockAndAlgorithm{\n\t\t\tLockTp:      $1.(ast.LockType),\n\t\t\tAlgorithmTp: $2.(ast.AlgorithmType),\n\t\t}\n\t}\n|\tAlgorithmClause LockClause\n\t{\n\t\t$$ = &ast.IndexLockAndAlgorithm{\n\t\t\tLockTp:      $2.(ast.LockType),\n\t\t\tAlgorithmTp: $1.(ast.AlgorithmType),\n\t\t}\n\t}\n\nIndexKeyTypeOpt:\n\t{\n\t\t$$ = ast.IndexKeyTypeNone\n\t}\n|\t\"UNIQUE\"\n\t{\n\t\t$$ = ast.IndexKeyTypeUnique\n\t}\n|\t\"SPATIAL\"\n\t{\n\t\t$$ = ast.IndexKeyTypeSpatial\n\t}\n|\t\"FULLTEXT\"\n\t{\n\t\t$$ = ast.IndexKeyTypeFullText\n\t}\n\n/**************************************AlterDatabaseStmt***************************************\n * See https://dev.mysql.com/doc/refman/5.7/en/alter-database.html\n * 'ALTER DATABASE ... UPGRADE DATA DIRECTORY NAME' is not supported yet.\n *\n *  ALTER {DATABASE | SCHEMA} [db_name]\n *   alter_specification ...\n *\n *  alter_specification:\n *   [DEFAULT] CHARACTER SET [=] charset_name\n * | [DEFAULT] COLLATE [=] collation_name\n * | [DEFAULT] ENCRYPTION [=] {'Y' | 'N'}\n *******************************************************************************************/\nAlterDatabaseStmt:\n\t\"ALTER\" DatabaseSym DBName DatabaseOptionList\n\t{\n\t\t$$ = &ast.AlterDatabaseStmt{\n\t\t\tName:                 $3.(string),\n\t\t\tAlterDefaultDatabase: false,\n\t\t\tOptions:              $4.([]*ast.DatabaseOption),\n\t\t}\n\t}\n|\t\"ALTER\" DatabaseSym DatabaseOptionList\n\t{\n\t\t$$ = &ast.AlterDatabaseStmt{\n\t\t\tName:                 \"\",\n\t\t\tAlterDefaultDatabase: true,\n\t\t\tOptions:              $3.([]*ast.DatabaseOption),\n\t\t}\n\t}\n\n/*******************************************************************\n *\n *  Create Database Statement\n *  CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name\n *      [create_specification] ...\n *\n *  create_specification:\n *      [DEFAULT] CHARACTER SET [=] charset_name\n *    | [DEFAULT] COLLATE [=] collation_name\n *    | [DEFAULT] ENCRYPTION [=] {'Y' | 'N'}\n *******************************************************************/\nCreateDatabaseStmt:\n\t\"CREATE\" DatabaseSym IfNotExists DBName DatabaseOptionListOpt\n\t{\n\t\t$$ = &ast.CreateDatabaseStmt{\n\t\t\tIfNotExists: $3.(bool),\n\t\t\tName:        $4.(string),\n\t\t\tOptions:     $5.([]*ast.DatabaseOption),\n\t\t}\n\t}\n\nDBName:\n\tIdentifier\n\t{\n\t\t$$ = $1\n\t}\n\nDatabaseOption:\n\tDefaultKwdOpt CharsetKw EqOpt CharsetName\n\t{\n\t\t$$ = &ast.DatabaseOption{Tp: ast.DatabaseOptionCharset, Value: $4.(string)}\n\t}\n|\tDefaultKwdOpt \"COLLATE\" EqOpt CollationName\n\t{\n\t\t$$ = &ast.DatabaseOption{Tp: ast.DatabaseOptionCollate, Value: $4.(string)}\n\t}\n|\tDefaultKwdOpt \"ENCRYPTION\" EqOpt stringLit\n\t{\n\t\t$$ = &ast.DatabaseOption{Tp: ast.DatabaseOptionEncryption, Value: $4}\n\t}\n\nDatabaseOptionListOpt:\n\t{\n\t\t$$ = []*ast.DatabaseOption{}\n\t}\n|\tDatabaseOptionList\n\nDatabaseOptionList:\n\tDatabaseOption\n\t{\n\t\t$$ = []*ast.DatabaseOption{$1.(*ast.DatabaseOption)}\n\t}\n|\tDatabaseOptionList DatabaseOption\n\t{\n\t\t$$ = append($1.([]*ast.DatabaseOption), $2.(*ast.DatabaseOption))\n\t}\n\n/*******************************************************************\n *\n *  Create Table Statement\n *\n *  Example:\n *      CREATE TABLE Persons\n *      (\n *          P_Id int NOT NULL,\n *          LastName varchar(255) NOT NULL,\n *          FirstName varchar(255),\n *          Address varchar(255),\n *          City varchar(255),\n *          PRIMARY KEY (P_Id)\n *      )\n *******************************************************************/\nCreateTableStmt:\n\t\"CREATE\" OptTemporary \"TABLE\" IfNotExists TableName TableElementListOpt CreateTableOptionListOpt PartitionOpt DuplicateOpt AsOpt CreateTableSelectOpt\n\t{\n\t\tstmt := $6.(*ast.CreateTableStmt)\n\t\tstmt.Table = $5.(*ast.TableName)\n\t\tstmt.IfNotExists = $4.(bool)\n\t\tstmt.IsTemporary = $2.(bool)\n\t\tstmt.Options = $7.([]*ast.TableOption)\n\t\tif $8 != nil {\n\t\t\tstmt.Partition = $8.(*ast.PartitionOptions)\n\t\t}\n\t\tstmt.OnDuplicate = $9.(ast.OnDuplicateKeyHandlingType)\n\t\tstmt.Select = $11.(*ast.CreateTableStmt).Select\n\t\t$$ = stmt\n\t}\n|\t\"CREATE\" OptTemporary \"TABLE\" IfNotExists TableName LikeTableWithOrWithoutParen\n\t{\n\t\t$$ = &ast.CreateTableStmt{\n\t\t\tTable:       $5.(*ast.TableName),\n\t\t\tReferTable:  $6.(*ast.TableName),\n\t\t\tIfNotExists: $4.(bool),\n\t\t\tIsTemporary: $2.(bool),\n\t\t}\n\t}\n\nDefaultKwdOpt:\n\t%prec lowerThanCharsetKwd\n\t{}\n|\t\"DEFAULT\"\n\nPartitionOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"PARTITION\" \"BY\" PartitionMethod PartitionNumOpt SubPartitionOpt PartitionDefinitionListOpt\n\t{\n\t\tmethod := $3.(*ast.PartitionMethod)\n\t\tmethod.Num = $4.(uint64)\n\t\tsub, _ := $5.(*ast.PartitionMethod)\n\t\tdefs, _ := $6.([]*ast.PartitionDefinition)\n\t\topt := &ast.PartitionOptions{\n\t\t\tPartitionMethod: *method,\n\t\t\tSub:             sub,\n\t\t\tDefinitions:     defs,\n\t\t}\n\t\tif err := opt.Validate(); err != nil {\n\t\t\tyylex.AppendError(err)\n\t\t\treturn 1\n\t\t}\n\t\t$$ = opt\n\t}\n\nSubPartitionMethod:\n\tLinearOpt \"KEY\" PartitionKeyAlgorithmOpt '(' ColumnNameListOpt ')'\n\t{\n\t\t$$ = &ast.PartitionMethod{\n\t\t\tTp:          model.PartitionTypeKey,\n\t\t\tLinear:      len($1) != 0,\n\t\t\tColumnNames: $5.([]*ast.ColumnName),\n\t\t}\n\t}\n|\tLinearOpt \"HASH\" '(' Expression ')'\n\t{\n\t\t$$ = &ast.PartitionMethod{\n\t\t\tTp:     model.PartitionTypeHash,\n\t\t\tLinear: len($1) != 0,\n\t\t\tExpr:   $4.(ast.ExprNode),\n\t\t}\n\t}\n\nPartitionKeyAlgorithmOpt:\n\t/* empty */\n\t{}\n|\t\"ALGORITHM\" '=' NUM\n\t{}\n\nPartitionMethod:\n\tSubPartitionMethod\n\t{\n\t\t$$ = $1\n\t}\n|\t\"RANGE\" '(' Expression ')'\n\t{\n\t\t$$ = &ast.PartitionMethod{\n\t\t\tTp:   model.PartitionTypeRange,\n\t\t\tExpr: $3.(ast.ExprNode),\n\t\t}\n\t}\n|\t\"RANGE\" FieldsOrColumns '(' ColumnNameList ')'\n\t{\n\t\t$$ = &ast.PartitionMethod{\n\t\t\tTp:          model.PartitionTypeRange,\n\t\t\tColumnNames: $4.([]*ast.ColumnName),\n\t\t}\n\t}\n|\t\"LIST\" '(' Expression ')'\n\t{\n\t\t$$ = &ast.PartitionMethod{\n\t\t\tTp:   model.PartitionTypeList,\n\t\t\tExpr: $3.(ast.ExprNode),\n\t\t}\n\t}\n|\t\"LIST\" FieldsOrColumns '(' ColumnNameList ')'\n\t{\n\t\t$$ = &ast.PartitionMethod{\n\t\t\tTp:          model.PartitionTypeList,\n\t\t\tColumnNames: $4.([]*ast.ColumnName),\n\t\t}\n\t}\n|\t\"SYSTEM_TIME\" \"INTERVAL\" Expression TimeUnit\n\t{\n\t\t$$ = &ast.PartitionMethod{\n\t\t\tTp:   model.PartitionTypeSystemTime,\n\t\t\tExpr: $3.(ast.ExprNode),\n\t\t\tUnit: $4.(ast.TimeUnitType),\n\t\t}\n\t}\n|\t\"SYSTEM_TIME\" \"LIMIT\" LengthNum\n\t{\n\t\t$$ = &ast.PartitionMethod{\n\t\t\tTp:    model.PartitionTypeSystemTime,\n\t\t\tLimit: $3.(uint64),\n\t\t}\n\t}\n|\t\"SYSTEM_TIME\"\n\t{\n\t\t$$ = &ast.PartitionMethod{\n\t\t\tTp: model.PartitionTypeSystemTime,\n\t\t}\n\t}\n\nLinearOpt:\n\t{\n\t\t$$ = \"\"\n\t}\n|\t\"LINEAR\"\n\t{\n\t\t$$ = $1\n\t}\n\nSubPartitionOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"SUBPARTITION\" \"BY\" SubPartitionMethod SubPartitionNumOpt\n\t{\n\t\tmethod := $3.(*ast.PartitionMethod)\n\t\tmethod.Num = $4.(uint64)\n\t\t$$ = method\n\t}\n\nSubPartitionNumOpt:\n\t{\n\t\t$$ = uint64(0)\n\t}\n|\t\"SUBPARTITIONS\" LengthNum\n\t{\n\t\tres := $2.(uint64)\n\t\tif res == 0 {\n\t\t\tyylex.AppendError(ast.ErrNoParts.GenWithStackByArgs(\"subpartitions\"))\n\t\t\treturn 1\n\t\t}\n\t\t$$ = res\n\t}\n\nPartitionNumOpt:\n\t{\n\t\t$$ = uint64(0)\n\t}\n|\t\"PARTITIONS\" LengthNum\n\t{\n\t\tres := $2.(uint64)\n\t\tif res == 0 {\n\t\t\tyylex.AppendError(ast.ErrNoParts.GenWithStackByArgs(\"partitions\"))\n\t\t\treturn 1\n\t\t}\n\t\t$$ = res\n\t}\n\nPartitionDefinitionListOpt:\n\t/* empty */ %prec lowerThanCreateTableSelect\n\t{\n\t\t$$ = nil\n\t}\n|\t'(' PartitionDefinitionList ')'\n\t{\n\t\t$$ = $2.([]*ast.PartitionDefinition)\n\t}\n\nPartitionDefinitionList:\n\tPartitionDefinition\n\t{\n\t\t$$ = []*ast.PartitionDefinition{$1.(*ast.PartitionDefinition)}\n\t}\n|\tPartitionDefinitionList ',' PartitionDefinition\n\t{\n\t\t$$ = append($1.([]*ast.PartitionDefinition), $3.(*ast.PartitionDefinition))\n\t}\n\nPartitionDefinition:\n\t\"PARTITION\" Identifier PartDefValuesOpt PartDefOptionList SubPartDefinitionListOpt\n\t{\n\t\t$$ = &ast.PartitionDefinition{\n\t\t\tName:    model.NewCIStr($2),\n\t\t\tClause:  $3.(ast.PartitionDefinitionClause),\n\t\t\tOptions: $4.([]*ast.TableOption),\n\t\t\tSub:     $5.([]*ast.SubPartitionDefinition),\n\t\t}\n\t}\n\nSubPartDefinitionListOpt:\n\t/*empty*/\n\t{\n\t\t$$ = make([]*ast.SubPartitionDefinition, 0)\n\t}\n|\t'(' SubPartDefinitionList ')'\n\t{\n\t\t$$ = $2\n\t}\n\nSubPartDefinitionList:\n\tSubPartDefinition\n\t{\n\t\t$$ = []*ast.SubPartitionDefinition{$1.(*ast.SubPartitionDefinition)}\n\t}\n|\tSubPartDefinitionList ',' SubPartDefinition\n\t{\n\t\tlist := $1.([]*ast.SubPartitionDefinition)\n\t\t$$ = append(list, $3.(*ast.SubPartitionDefinition))\n\t}\n\nSubPartDefinition:\n\t\"SUBPARTITION\" Identifier PartDefOptionList\n\t{\n\t\t$$ = &ast.SubPartitionDefinition{\n\t\t\tName:    model.NewCIStr($2),\n\t\t\tOptions: $3.([]*ast.TableOption),\n\t\t}\n\t}\n\nPartDefOptionList:\n\t/*empty*/\n\t{\n\t\t$$ = make([]*ast.TableOption, 0)\n\t}\n|\tPartDefOptionList PartDefOption\n\t{\n\t\tlist := $1.([]*ast.TableOption)\n\t\t$$ = append(list, $2.(*ast.TableOption))\n\t}\n\nPartDefOption:\n\t\"COMMENT\" EqOpt stringLit\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionComment, StrValue: $3}\n\t}\n|\t\"ENGINE\" EqOpt StringName\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionEngine, StrValue: $3.(string)}\n\t}\n|\t\"STORAGE\" \"ENGINE\" EqOpt StringName\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionEngine, StrValue: $4.(string)}\n\t}\n|\t\"INSERT_METHOD\" EqOpt StringName\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionInsertMethod, StrValue: $3.(string)}\n\t}\n|\t\"DATA\" \"DIRECTORY\" EqOpt stringLit\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionDataDirectory, StrValue: $4}\n\t}\n|\t\"INDEX\" \"DIRECTORY\" EqOpt stringLit\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionIndexDirectory, StrValue: $4}\n\t}\n|\t\"MAX_ROWS\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionMaxRows, UintValue: $3.(uint64)}\n\t}\n|\t\"MIN_ROWS\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionMinRows, UintValue: $3.(uint64)}\n\t}\n|\t\"TABLESPACE\" EqOpt Identifier\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionTablespace, StrValue: $3}\n\t}\n|\t\"NODEGROUP\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionNodegroup, UintValue: $3.(uint64)}\n\t}\n\nPartDefValuesOpt:\n\t{\n\t\t$$ = &ast.PartitionDefinitionClauseNone{}\n\t}\n|\t\"VALUES\" \"LESS\" \"THAN\" \"MAXVALUE\"\n\t{\n\t\t$$ = &ast.PartitionDefinitionClauseLessThan{\n\t\t\tExprs: []ast.ExprNode{&ast.MaxValueExpr{}},\n\t\t}\n\t}\n|\t\"VALUES\" \"LESS\" \"THAN\" '(' MaxValueOrExpressionList ')'\n\t{\n\t\t$$ = &ast.PartitionDefinitionClauseLessThan{\n\t\t\tExprs: $5.([]ast.ExprNode),\n\t\t}\n\t}\n|\t\"DEFAULT\"\n\t{\n\t\t$$ = &ast.PartitionDefinitionClauseIn{}\n\t}\n|\t\"VALUES\" \"IN\" '(' MaxValueOrExpressionList ')'\n\t{\n\t\texprs := $4.([]ast.ExprNode)\n\t\tvalues := make([][]ast.ExprNode, 0, len(exprs))\n\t\tfor _, expr := range exprs {\n\t\t\tif row, ok := expr.(*ast.RowExpr); ok {\n\t\t\t\tvalues = append(values, row.Values)\n\t\t\t} else {\n\t\t\t\tvalues = append(values, []ast.ExprNode{expr})\n\t\t\t}\n\t\t}\n\t\t$$ = &ast.PartitionDefinitionClauseIn{Values: values}\n\t}\n|\t\"HISTORY\"\n\t{\n\t\t$$ = &ast.PartitionDefinitionClauseHistory{Current: false}\n\t}\n|\t\"CURRENT\"\n\t{\n\t\t$$ = &ast.PartitionDefinitionClauseHistory{Current: true}\n\t}\n\nDuplicateOpt:\n\t{\n\t\t$$ = ast.OnDuplicateKeyHandlingError\n\t}\n|\t\"IGNORE\"\n\t{\n\t\t$$ = ast.OnDuplicateKeyHandlingIgnore\n\t}\n|\t\"REPLACE\"\n\t{\n\t\t$$ = ast.OnDuplicateKeyHandlingReplace\n\t}\n\nAsOpt:\n\t{}\n|\t\"AS\"\n\t{}\n\nCreateTableSelectOpt:\n\t/* empty */\n\t{\n\t\t$$ = &ast.CreateTableStmt{}\n\t}\n|\tSelectStmt\n\t{\n\t\t$$ = &ast.CreateTableStmt{Select: $1}\n\t}\n|\tUnionStmt\n\t{\n\t\t$$ = &ast.CreateTableStmt{Select: $1}\n\t}\n|\tSubSelect %prec createTableSelect\n\t// TODO: We may need better solution as issue #320.\n\t{\n\t\t$$ = &ast.CreateTableStmt{Select: $1}\n\t}\n\nCreateViewSelectOpt:\n\tSelectStmt\n\t{\n\t\t$$ = $1.(*ast.SelectStmt)\n\t}\n|\tUnionStmt\n\t{\n\t\t$$ = $1.(*ast.UnionStmt)\n\t}\n|\t'(' SelectStmt ')'\n\t{\n\t\t$$ = $2.(*ast.SelectStmt)\n\t}\n|\t'(' UnionStmt ')'\n\t{\n\t\t$$ = $2.(*ast.UnionStmt)\n\t}\n\nLikeTableWithOrWithoutParen:\n\t\"LIKE\" TableName\n\t{\n\t\t$$ = $2\n\t}\n|\t'(' \"LIKE\" TableName ')'\n\t{\n\t\t$$ = $3\n\t}\n\n/*******************************************************************\n *\n *  Create View Statement\n *\n *  Example:\n *      CREATE VIEW OR REPLACE ALGORITHM = MERGE DEFINER=\"root@localhost\" SQL SECURITY = definer view_name (col1,col2)\n *          as select Col1,Col2 from table WITH LOCAL CHECK OPTION\n *******************************************************************/\nCreateViewStmt:\n\t\"CREATE\" OrReplace ViewAlgorithm ViewDefiner ViewSQLSecurity \"VIEW\" ViewName ViewFieldList \"AS\" CreateViewSelectOpt ViewCheckOption\n\t{\n\t\tstartOffset := parser.startOffset(&yyS[yypt-1])\n\t\tselStmt := $10.(ast.StmtNode)\n\t\tselStmt.SetText(strings.TrimSpace(parser.src[startOffset:]))\n\t\tx := &ast.CreateViewStmt{\n\t\t\tOrReplace: $2.(bool),\n\t\t\tViewName:  $7.(*ast.TableName),\n\t\t\tSelect:    selStmt,\n\t\t\tAlgorithm: $3.(model.ViewAlgorithm),\n\t\t\tDefiner:   $4.(*auth.UserIdentity),\n\t\t\tSecurity:  $5.(model.ViewSecurity),\n\t\t}\n\t\tif $8 != nil {\n\t\t\tx.Cols = $8.([]model.CIStr)\n\t\t}\n\t\tif $11 != nil {\n\t\t\tx.CheckOption = $11.(model.ViewCheckOption)\n\t\t\tendOffset := parser.startOffset(&yyS[yypt])\n\t\t\tselStmt.SetText(strings.TrimSpace(parser.src[startOffset:endOffset]))\n\t\t} else {\n\t\t\tx.CheckOption = model.CheckOptionCascaded\n\t\t}\n\t\t$$ = x\n\t}\n\nOrReplace:\n\t/* EMPTY */\n\t{\n\t\t$$ = false\n\t}\n|\t\"OR\" \"REPLACE\"\n\t{\n\t\t$$ = true\n\t}\n\nViewAlgorithm:\n\t/* EMPTY */\n\t{\n\t\t$$ = model.AlgorithmUndefined\n\t}\n|\t\"ALGORITHM\" \"=\" \"UNDEFINED\"\n\t{\n\t\t$$ = model.AlgorithmUndefined\n\t}\n|\t\"ALGORITHM\" \"=\" \"MERGE\"\n\t{\n\t\t$$ = model.AlgorithmMerge\n\t}\n|\t\"ALGORITHM\" \"=\" \"TEMPTABLE\"\n\t{\n\t\t$$ = model.AlgorithmTemptable\n\t}\n\nViewDefiner:\n\t/* EMPTY */\n\t{\n\t\t$$ = &auth.UserIdentity{CurrentUser: true}\n\t}\n|\t\"DEFINER\" \"=\" Username\n\t{\n\t\t$$ = $3\n\t}\n\nViewSQLSecurity:\n\t/* EMPTY */\n\t{\n\t\t$$ = model.SecurityDefiner\n\t}\n|\t\"SQL\" \"SECURITY\" \"DEFINER\"\n\t{\n\t\t$$ = model.SecurityDefiner\n\t}\n|\t\"SQL\" \"SECURITY\" \"INVOKER\"\n\t{\n\t\t$$ = model.SecurityInvoker\n\t}\n\nViewName:\n\tTableName\n\t{\n\t\t$$ = $1.(*ast.TableName)\n\t}\n\nViewFieldList:\n\t/* Empty */\n\t{\n\t\t$$ = nil\n\t}\n|\t'(' ColumnList ')'\n\t{\n\t\t$$ = $2.([]model.CIStr)\n\t}\n\nColumnList:\n\tIdentifier\n\t{\n\t\t$$ = []model.CIStr{model.NewCIStr($1)}\n\t}\n|\tColumnList ',' Identifier\n\t{\n\t\t$$ = append($1.([]model.CIStr), model.NewCIStr($3))\n\t}\n\nViewCheckOption:\n\t/* EMPTY */\n\t{\n\t\t$$ = nil\n\t}\n|\t\"WITH\" \"CASCADED\" \"CHECK\" \"OPTION\"\n\t{\n\t\t$$ = model.CheckOptionCascaded\n\t}\n|\t\"WITH\" \"LOCAL\" \"CHECK\" \"OPTION\"\n\t{\n\t\t$$ = model.CheckOptionLocal\n\t}\n\n/******************************************************************\n * Do statement\n * See https://dev.mysql.com/doc/refman/5.7/en/do.html\n ******************************************************************/\nDoStmt:\n\t\"DO\" ExpressionList\n\t{\n\t\t$$ = &ast.DoStmt{\n\t\t\tExprs: $2.([]ast.ExprNode),\n\t\t}\n\t}\n\n/*******************************************************************\n *\n *  Delete Statement\n *\n *******************************************************************/\nDeleteFromStmt:\n\t\"DELETE\" TableOptimizerHints PriorityOpt QuickOptional IgnoreOptional \"FROM\" TableName TableAsNameOpt IndexHintListOpt WhereClauseOptional OrderByOptional LimitClause\n\t{\n\t\t// Single Table\n\t\ttn := $7.(*ast.TableName)\n\t\ttn.IndexHints = $9.([]*ast.IndexHint)\n\t\tjoin := &ast.Join{Left: &ast.TableSource{Source: tn, AsName: $8.(model.CIStr)}, Right: nil}\n\t\tx := &ast.DeleteStmt{\n\t\t\tTableRefs: &ast.TableRefsClause{TableRefs: join},\n\t\t\tPriority:  $3.(mysql.PriorityEnum),\n\t\t\tQuick:     $4.(bool),\n\t\t\tIgnoreErr: $5.(bool),\n\t\t}\n\t\tif $10 != nil {\n\t\t\tx.Where = $10.(ast.ExprNode)\n\t\t}\n\t\tif $11 != nil {\n\t\t\tx.Order = $11.(*ast.OrderByClause)\n\t\t}\n\t\tif $12 != nil {\n\t\t\tx.Limit = $12.(*ast.Limit)\n\t\t}\n\n\t\t$$ = x\n\t}\n|\t\"DELETE\" TableOptimizerHints PriorityOpt QuickOptional IgnoreOptional TableAliasRefList \"FROM\" TableRefs WhereClauseOptional\n\t{\n\t\t// Multiple Table\n\t\tx := &ast.DeleteStmt{\n\t\t\tPriority:     $3.(mysql.PriorityEnum),\n\t\t\tQuick:        $4.(bool),\n\t\t\tIgnoreErr:    $5.(bool),\n\t\t\tIsMultiTable: true,\n\t\t\tBeforeFrom:   true,\n\t\t\tTables:       &ast.DeleteTableList{Tables: $6.([]*ast.TableName)},\n\t\t\tTableRefs:    &ast.TableRefsClause{TableRefs: $8.(*ast.Join)},\n\t\t}\n\t\tif $2 != nil {\n\t\t\tx.TableHints = $2.([]*ast.TableOptimizerHint)\n\t\t}\n\t\tif $9 != nil {\n\t\t\tx.Where = $9.(ast.ExprNode)\n\t\t}\n\t\t$$ = x\n\t}\n|\t\"DELETE\" TableOptimizerHints PriorityOpt QuickOptional IgnoreOptional \"FROM\" TableAliasRefList \"USING\" TableRefs WhereClauseOptional\n\t{\n\t\t// Multiple Table\n\t\tx := &ast.DeleteStmt{\n\t\t\tPriority:     $3.(mysql.PriorityEnum),\n\t\t\tQuick:        $4.(bool),\n\t\t\tIgnoreErr:    $5.(bool),\n\t\t\tIsMultiTable: true,\n\t\t\tTables:       &ast.DeleteTableList{Tables: $7.([]*ast.TableName)},\n\t\t\tTableRefs:    &ast.TableRefsClause{TableRefs: $9.(*ast.Join)},\n\t\t}\n\t\tif $2 != nil {\n\t\t\tx.TableHints = $2.([]*ast.TableOptimizerHint)\n\t\t}\n\t\tif $10 != nil {\n\t\t\tx.Where = $10.(ast.ExprNode)\n\t\t}\n\t\t$$ = x\n\t}\n\nDatabaseSym:\n\t\"DATABASE\"\n\nDropDatabaseStmt:\n\t\"DROP\" DatabaseSym IfExists DBName\n\t{\n\t\t$$ = &ast.DropDatabaseStmt{IfExists: $3.(bool), Name: $4.(string)}\n\t}\n\n/******************************************************************\n * Drop Index Statement\n * See https://dev.mysql.com/doc/refman/8.0/en/drop-index.html\n *\n *  DROP INDEX index_name ON tbl_name\n *      [algorithm_option | lock_option] ...\n *\n *  algorithm_option:\n *      ALGORITHM [=] {DEFAULT|INPLACE|COPY}\n *\n *  lock_option:\n *      LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}\n ******************************************************************/\nDropIndexStmt:\n\t\"DROP\" \"INDEX\" IfExists Identifier \"ON\" TableName IndexLockAndAlgorithmOpt\n\t{\n\t\tvar indexLockAndAlgorithm *ast.IndexLockAndAlgorithm\n\t\tif $7 != nil {\n\t\t\tindexLockAndAlgorithm = $7.(*ast.IndexLockAndAlgorithm)\n\t\t\tif indexLockAndAlgorithm.LockTp == ast.LockTypeDefault && indexLockAndAlgorithm.AlgorithmTp == ast.AlgorithmTypeDefault {\n\t\t\t\tindexLockAndAlgorithm = nil\n\t\t\t}\n\t\t}\n\t\t$$ = &ast.DropIndexStmt{IfExists: $3.(bool), IndexName: $4, Table: $6.(*ast.TableName), LockAlg: indexLockAndAlgorithm}\n\t}\n\nDropTableStmt:\n\t\"DROP\" OptTemporary TableOrTables IfExists TableNameList RestrictOrCascadeOpt\n\t{\n\t\t$$ = &ast.DropTableStmt{IfExists: $4.(bool), Tables: $5.([]*ast.TableName), IsView: false, IsTemporary: $2.(bool)}\n\t}\n\nOptTemporary:\n\t/* empty */\n\t{\n\t\t$$ = false\n\t}\n|\t\"TEMPORARY\"\n\t{\n\t\t$$ = true\n\t\tyylex.AppendError(yylex.Errorf(\"TiDB doesn't support TEMPORARY TABLE, TEMPORARY will be parsed but ignored.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n\nDropViewStmt:\n\t\"DROP\" \"VIEW\" TableNameList RestrictOrCascadeOpt\n\t{\n\t\t$$ = &ast.DropTableStmt{Tables: $3.([]*ast.TableName), IsView: true}\n\t}\n|\t\"DROP\" \"VIEW\" \"IF\" \"EXISTS\" TableNameList RestrictOrCascadeOpt\n\t{\n\t\t$$ = &ast.DropTableStmt{IfExists: true, Tables: $5.([]*ast.TableName), IsView: true}\n\t}\n\nDropUserStmt:\n\t\"DROP\" \"USER\" UsernameList\n\t{\n\t\t$$ = &ast.DropUserStmt{IsDropRole: false, IfExists: false, UserList: $3.([]*auth.UserIdentity)}\n\t}\n|\t\"DROP\" \"USER\" \"IF\" \"EXISTS\" UsernameList\n\t{\n\t\t$$ = &ast.DropUserStmt{IsDropRole: false, IfExists: true, UserList: $5.([]*auth.UserIdentity)}\n\t}\n\nDropRoleStmt:\n\t\"DROP\" \"ROLE\" RolenameList\n\t{\n\t\ttmp := make([]*auth.UserIdentity, 0, 10)\n\t\troleList := $3.([]*auth.RoleIdentity)\n\t\tfor _, r := range roleList {\n\t\t\ttmp = append(tmp, &auth.UserIdentity{Username: r.Username, Hostname: r.Hostname})\n\t\t}\n\t\t$$ = &ast.DropUserStmt{IsDropRole: true, IfExists: false, UserList: tmp}\n\t}\n|\t\"DROP\" \"ROLE\" \"IF\" \"EXISTS\" RolenameList\n\t{\n\t\ttmp := make([]*auth.UserIdentity, 0, 10)\n\t\troleList := $5.([]*auth.RoleIdentity)\n\t\tfor _, r := range roleList {\n\t\t\ttmp = append(tmp, &auth.UserIdentity{Username: r.Username, Hostname: r.Hostname})\n\t\t}\n\t\t$$ = &ast.DropUserStmt{IsDropRole: true, IfExists: true, UserList: tmp}\n\t}\n\nDropStatsStmt:\n\t\"DROP\" \"STATS\" TableName\n\t{\n\t\t$$ = &ast.DropStatsStmt{Table: $3.(*ast.TableName)}\n\t}\n\nRestrictOrCascadeOpt:\n\t{}\n|\t\"RESTRICT\"\n|\t\"CASCADE\"\n\nTableOrTables:\n\t\"TABLE\"\n|\t\"TABLES\"\n\nEqOpt:\n\t{}\n|\teq\n\nEmptyStmt:\n\t/* EMPTY */\n\t{\n\t\t$$ = nil\n\t}\n\nTraceStmt:\n\t\"TRACE\" TraceableStmt\n\t{\n\t\t$$ = &ast.TraceStmt{\n\t\t\tStmt:   $2,\n\t\t\tFormat: \"json\",\n\t\t}\n\t\tstartOffset := parser.startOffset(&yyS[yypt])\n\t\t$2.SetText(string(parser.src[startOffset:]))\n\t}\n|\t\"TRACE\" \"FORMAT\" \"=\" stringLit TraceableStmt\n\t{\n\t\t$$ = &ast.TraceStmt{\n\t\t\tStmt:   $5,\n\t\t\tFormat: $4,\n\t\t}\n\t\tstartOffset := parser.startOffset(&yyS[yypt])\n\t\t$5.SetText(string(parser.src[startOffset:]))\n\t}\n\nExplainSym:\n\t\"EXPLAIN\"\n|\t\"DESCRIBE\"\n|\t\"DESC\"\n\nExplainStmt:\n\tExplainSym TableName\n\t{\n\t\t$$ = &ast.ExplainStmt{\n\t\t\tStmt: &ast.ShowStmt{\n\t\t\t\tTp:    ast.ShowColumns,\n\t\t\t\tTable: $2.(*ast.TableName),\n\t\t\t},\n\t\t}\n\t}\n|\tExplainSym TableName ColumnName\n\t{\n\t\t$$ = &ast.ExplainStmt{\n\t\t\tStmt: &ast.ShowStmt{\n\t\t\t\tTp:     ast.ShowColumns,\n\t\t\t\tTable:  $2.(*ast.TableName),\n\t\t\t\tColumn: $3.(*ast.ColumnName),\n\t\t\t},\n\t\t}\n\t}\n|\tExplainSym ExplainableStmt\n\t{\n\t\t$$ = &ast.ExplainStmt{\n\t\t\tStmt:   $2,\n\t\t\tFormat: \"row\",\n\t\t}\n\t}\n|\tExplainSym \"FOR\" \"CONNECTION\" NUM\n\t{\n\t\t$$ = &ast.ExplainForStmt{\n\t\t\tFormat:       \"row\",\n\t\t\tConnectionID: getUint64FromNUM($4),\n\t\t}\n\t}\n|\tExplainSym \"FORMAT\" \"=\" stringLit \"FOR\" \"CONNECTION\" NUM\n\t{\n\t\t$$ = &ast.ExplainForStmt{\n\t\t\tFormat:       $4,\n\t\t\tConnectionID: getUint64FromNUM($7),\n\t\t}\n\t}\n|\tExplainSym \"FORMAT\" \"=\" stringLit ExplainableStmt\n\t{\n\t\t$$ = &ast.ExplainStmt{\n\t\t\tStmt:   $5,\n\t\t\tFormat: $4,\n\t\t}\n\t}\n|\tExplainSym \"FORMAT\" \"=\" ExplainFormatType \"FOR\" \"CONNECTION\" NUM\n\t{\n\t\t$$ = &ast.ExplainForStmt{\n\t\t\tFormat:       $4.(string),\n\t\t\tConnectionID: getUint64FromNUM($7),\n\t\t}\n\t}\n|\tExplainSym \"FORMAT\" \"=\" ExplainFormatType ExplainableStmt\n\t{\n\t\t$$ = &ast.ExplainStmt{\n\t\t\tStmt:   $5,\n\t\t\tFormat: $4.(string),\n\t\t}\n\t}\n|\tExplainSym \"ANALYZE\" ExplainableStmt\n\t{\n\t\t$$ = &ast.ExplainStmt{\n\t\t\tStmt:    $3,\n\t\t\tFormat:  \"row\",\n\t\t\tAnalyze: true,\n\t\t}\n\t}\n\nExplainFormatType:\n\t\"TRADITIONAL\"\n\t{\n\t\t$$ = \"row\"\n\t}\n|\t\"JSON\"\n\t{\n\t\t$$ = \"json\"\n\t}\n\nLengthNum:\n\tNUM\n\t{\n\t\t$$ = getUint64FromNUM($1)\n\t}\n\nNUM:\n\tintLit\n\nExpression:\n\tsingleAtIdentifier assignmentEq Expression %prec assignmentEq\n\t{\n\t\tv := $1\n\t\tv = strings.TrimPrefix(v, \"@\")\n\t\t$$ = &ast.VariableExpr{\n\t\t\tName:     v,\n\t\t\tIsGlobal: false,\n\t\t\tIsSystem: false,\n\t\t\tValue:    $3,\n\t\t}\n\t}\n|\tExpression logOr Expression %prec pipes\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.LogicOr, L: $1, R: $3}\n\t}\n|\tExpression \"XOR\" Expression %prec xor\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.LogicXor, L: $1, R: $3}\n\t}\n|\tExpression logAnd Expression %prec andand\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.LogicAnd, L: $1, R: $3}\n\t}\n|\t\"NOT\" Expression %prec not\n\t{\n\t\texpr, ok := $2.(*ast.ExistsSubqueryExpr)\n\t\tif ok {\n\t\t\texpr.Not = true\n\t\t\t$$ = $2\n\t\t} else {\n\t\t\t$$ = &ast.UnaryOperationExpr{Op: opcode.Not, V: $2}\n\t\t}\n\t}\n|\t\"MATCH\" '(' ColumnNameList ')' \"AGAINST\" '(' BitExpr FulltextSearchModifierOpt ')'\n\t{\n\t\t$$ = &ast.MatchAgainst{\n\t\t\tColumnNames: $3.([]*ast.ColumnName),\n\t\t\tAgainst:     $7,\n\t\t\tModifier:    ast.FulltextSearchModifier($8.(int)),\n\t\t}\n\t}\n|\tBoolPri IsOrNotOp trueKwd %prec is\n\t{\n\t\t$$ = &ast.IsTruthExpr{Expr: $1, Not: !$2.(bool), True: int64(1)}\n\t}\n|\tBoolPri IsOrNotOp falseKwd %prec is\n\t{\n\t\t$$ = &ast.IsTruthExpr{Expr: $1, Not: !$2.(bool), True: int64(0)}\n\t}\n|\tBoolPri IsOrNotOp \"UNKNOWN\" %prec is\n\t{\n\t\t/* https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_is */\n\t\t$$ = &ast.IsNullExpr{Expr: $1, Not: !$2.(bool)}\n\t}\n|\tBoolPri\n\nMaxValueOrExpression:\n\t\"MAXVALUE\"\n\t{\n\t\t$$ = &ast.MaxValueExpr{}\n\t}\n|\tExpression\n\t{\n\t\t$$ = $1\n\t}\n\nFulltextSearchModifierOpt:\n\t/* empty */\n\t{\n\t\t$$ = ast.FulltextSearchModifierNaturalLanguageMode\n\t}\n|\t\"IN\" \"NATURAL\" \"LANGUAGE\" \"MODE\"\n\t{\n\t\t$$ = ast.FulltextSearchModifierNaturalLanguageMode\n\t}\n|\t\"IN\" \"NATURAL\" \"LANGUAGE\" \"MODE\" \"WITH\" \"QUERY\" \"EXPANSION\"\n\t{\n\t\t$$ = ast.FulltextSearchModifierNaturalLanguageMode | ast.FulltextSearchModifierWithQueryExpansion\n\t}\n|\t\"IN\" \"BOOLEAN\" \"MODE\"\n\t{\n\t\t$$ = ast.FulltextSearchModifierBooleanMode\n\t}\n|\t\"WITH\" \"QUERY\" \"EXPANSION\"\n\t{\n\t\t$$ = ast.FulltextSearchModifierWithQueryExpansion\n\t}\n\nlogOr:\n\tpipesAsOr\n|\t\"OR\"\n\nlogAnd:\n\t\"&&\"\n|\t\"AND\"\n\nExpressionList:\n\tExpression\n\t{\n\t\t$$ = []ast.ExprNode{$1}\n\t}\n|\tExpressionList ',' Expression\n\t{\n\t\t$$ = append($1.([]ast.ExprNode), $3)\n\t}\n\nMaxValueOrExpressionList:\n\tMaxValueOrExpression\n\t{\n\t\t$$ = []ast.ExprNode{$1}\n\t}\n|\tMaxValueOrExpressionList ',' MaxValueOrExpression\n\t{\n\t\t$$ = append($1.([]ast.ExprNode), $3)\n\t}\n\nExpressionListOpt:\n\t{\n\t\t$$ = []ast.ExprNode{}\n\t}\n|\tExpressionList\n\nFuncDatetimePrecListOpt:\n\t{\n\t\t$$ = []ast.ExprNode{}\n\t}\n|\tFuncDatetimePrecList\n\t{\n\t\t$$ = $1\n\t}\n\nFuncDatetimePrecList:\n\tintLit\n\t{\n\t\texpr := ast.NewValueExpr($1)\n\t\t$$ = []ast.ExprNode{expr}\n\t}\n\nBoolPri:\n\tBoolPri IsOrNotOp \"NULL\" %prec is\n\t{\n\t\t$$ = &ast.IsNullExpr{Expr: $1, Not: !$2.(bool)}\n\t}\n|\tBoolPri CompareOp PredicateExpr %prec eq\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: $2.(opcode.Op), L: $1, R: $3}\n\t}\n|\tBoolPri CompareOp AnyOrAll SubSelect %prec eq\n\t{\n\t\tsq := $4.(*ast.SubqueryExpr)\n\t\tsq.MultiRows = true\n\t\t$$ = &ast.CompareSubqueryExpr{Op: $2.(opcode.Op), L: $1, R: sq, All: $3.(bool)}\n\t}\n|\tBoolPri CompareOp singleAtIdentifier assignmentEq PredicateExpr %prec assignmentEq\n\t{\n\t\tv := $3\n\t\tv = strings.TrimPrefix(v, \"@\")\n\t\tvariable := &ast.VariableExpr{\n\t\t\tName:     v,\n\t\t\tIsGlobal: false,\n\t\t\tIsSystem: false,\n\t\t\tValue:    $5,\n\t\t}\n\t\t$$ = &ast.BinaryOperationExpr{Op: $2.(opcode.Op), L: $1, R: variable}\n\t}\n|\tPredicateExpr\n\nCompareOp:\n\t\">=\"\n\t{\n\t\t$$ = opcode.GE\n\t}\n|\t'>'\n\t{\n\t\t$$ = opcode.GT\n\t}\n|\t\"<=\"\n\t{\n\t\t$$ = opcode.LE\n\t}\n|\t'<'\n\t{\n\t\t$$ = opcode.LT\n\t}\n|\t\"!=\"\n\t{\n\t\t$$ = opcode.NE\n\t}\n|\t\"<>\"\n\t{\n\t\t$$ = opcode.NE\n\t}\n|\t\"=\"\n\t{\n\t\t$$ = opcode.EQ\n\t}\n|\t\"<=>\"\n\t{\n\t\t$$ = opcode.NullEQ\n\t}\n\nBetweenOrNotOp:\n\t\"BETWEEN\"\n\t{\n\t\t$$ = true\n\t}\n|\t\"NOT\" \"BETWEEN\"\n\t{\n\t\t$$ = false\n\t}\n\nIsOrNotOp:\n\t\"IS\"\n\t{\n\t\t$$ = true\n\t}\n|\t\"IS\" \"NOT\"\n\t{\n\t\t$$ = false\n\t}\n\nInOrNotOp:\n\t\"IN\"\n\t{\n\t\t$$ = true\n\t}\n|\t\"NOT\" \"IN\"\n\t{\n\t\t$$ = false\n\t}\n\nLikeOrNotOp:\n\t\"LIKE\"\n\t{\n\t\t$$ = true\n\t}\n|\t\"NOT\" \"LIKE\"\n\t{\n\t\t$$ = false\n\t}\n\nRegexpOrNotOp:\n\tRegexpSym\n\t{\n\t\t$$ = true\n\t}\n|\t\"NOT\" RegexpSym\n\t{\n\t\t$$ = false\n\t}\n\nAnyOrAll:\n\t\"ANY\"\n\t{\n\t\t$$ = false\n\t}\n|\t\"SOME\"\n\t{\n\t\t$$ = false\n\t}\n|\t\"ALL\"\n\t{\n\t\t$$ = true\n\t}\n\nPredicateExpr:\n\tBitExpr InOrNotOp '(' ExpressionList ')'\n\t{\n\t\t$$ = &ast.PatternInExpr{Expr: $1, Not: !$2.(bool), List: $4.([]ast.ExprNode)}\n\t}\n|\tBitExpr InOrNotOp SubSelect\n\t{\n\t\tsq := $3.(*ast.SubqueryExpr)\n\t\tsq.MultiRows = true\n\t\t$$ = &ast.PatternInExpr{Expr: $1, Not: !$2.(bool), Sel: sq}\n\t}\n|\tBitExpr BetweenOrNotOp BitExpr \"AND\" PredicateExpr\n\t{\n\t\t$$ = &ast.BetweenExpr{\n\t\t\tExpr:  $1,\n\t\t\tLeft:  $3,\n\t\t\tRight: $5,\n\t\t\tNot:   !$2.(bool),\n\t\t}\n\t}\n|\tBitExpr LikeOrNotOp SimpleExpr LikeEscapeOpt\n\t{\n\t\tescape := $4.(string)\n\t\tif len(escape) > 1 {\n\t\t\tyylex.AppendError(ErrWrongArguments.GenWithStackByArgs(\"ESCAPE\"))\n\t\t\treturn 1\n\t\t} else if len(escape) == 0 {\n\t\t\tescape = \"\\\\\"\n\t\t}\n\t\t$$ = &ast.PatternLikeExpr{\n\t\t\tExpr:    $1,\n\t\t\tPattern: $3,\n\t\t\tNot:     !$2.(bool),\n\t\t\tEscape:  escape[0],\n\t\t}\n\t}\n|\tBitExpr RegexpOrNotOp SimpleExpr\n\t{\n\t\t$$ = &ast.PatternRegexpExpr{Expr: $1, Pattern: $3, Not: !$2.(bool)}\n\t}\n|\tBitExpr\n\nRegexpSym:\n\t\"REGEXP\"\n|\t\"RLIKE\"\n\nLikeEscapeOpt:\n\t%prec empty\n\t{\n\t\t$$ = \"\\\\\"\n\t}\n|\t\"ESCAPE\" stringLit\n\t{\n\t\t$$ = $2\n\t}\n\nField:\n\t'*'\n\t{\n\t\t$$ = &ast.SelectField{WildCard: &ast.WildCardField{}}\n\t}\n|\tIdentifier '.' '*'\n\t{\n\t\twildCard := &ast.WildCardField{Table: model.NewCIStr($1)}\n\t\t$$ = &ast.SelectField{WildCard: wildCard}\n\t}\n|\tIdentifier '.' Identifier '.' '*'\n\t{\n\t\twildCard := &ast.WildCardField{Schema: model.NewCIStr($1), Table: model.NewCIStr($3)}\n\t\t$$ = &ast.SelectField{WildCard: wildCard}\n\t}\n|\tExpression FieldAsNameOpt\n\t{\n\t\texpr := $1\n\t\tasName := $2.(string)\n\t\t$$ = &ast.SelectField{Expr: expr, AsName: model.NewCIStr(asName)}\n\t}\n|\t'{' Identifier Expression '}' FieldAsNameOpt\n\t{\n\t\t/*\n\t\t * ODBC escape syntax.\n\t\t * See https://dev.mysql.com/doc/refman/5.7/en/expressions.html\n\t\t */\n\t\texpr := $3\n\t\tasName := $5.(string)\n\t\t$$ = &ast.SelectField{Expr: expr, AsName: model.NewCIStr(asName)}\n\t}\n\nFieldAsNameOpt:\n\t/* EMPTY */\n\t{\n\t\t$$ = \"\"\n\t}\n|\tFieldAsName\n\t{\n\t\t$$ = $1\n\t}\n\nFieldAsName:\n\tIdentifier\n\t{\n\t\t$$ = $1\n\t}\n|\t\"AS\" Identifier\n\t{\n\t\t$$ = $2\n\t}\n|\tstringLit\n\t{\n\t\t$$ = $1\n\t}\n|\t\"AS\" stringLit\n\t{\n\t\t$$ = $2\n\t}\n\nFieldList:\n\tField\n\t{\n\t\tfield := $1.(*ast.SelectField)\n\t\tfield.Offset = parser.startOffset(&yyS[yypt])\n\t\t$$ = []*ast.SelectField{field}\n\t}\n|\tFieldList ',' Field\n\t{\n\t\tfl := $1.([]*ast.SelectField)\n\t\tlast := fl[len(fl)-1]\n\t\tif last.Expr != nil && last.AsName.O == \"\" {\n\t\t\tlastEnd := parser.endOffset(&yyS[yypt-1])\n\t\t\tlast.SetText(parser.src[last.Offset:lastEnd])\n\t\t}\n\t\tnewField := $3.(*ast.SelectField)\n\t\tnewField.Offset = parser.startOffset(&yyS[yypt])\n\t\t$$ = append(fl, newField)\n\t}\n\nGroupByClause:\n\t\"GROUP\" \"BY\" ByList\n\t{\n\t\t$$ = &ast.GroupByClause{Items: $3.([]*ast.ByItem)}\n\t}\n\nHavingClause:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"HAVING\" Expression\n\t{\n\t\t$$ = &ast.HavingClause{Expr: $2}\n\t}\n\nIfExists:\n\t{\n\t\t$$ = false\n\t}\n|\t\"IF\" \"EXISTS\"\n\t{\n\t\t$$ = true\n\t}\n\nIfNotExists:\n\t{\n\t\t$$ = false\n\t}\n|\t\"IF\" \"NOT\" \"EXISTS\"\n\t{\n\t\t$$ = true\n\t}\n\nIgnoreOptional:\n\t{\n\t\t$$ = false\n\t}\n|\t\"IGNORE\"\n\t{\n\t\t$$ = true\n\t}\n\nIndexName:\n\t{\n\t\t$$ = \"\"\n\t}\n|\tIdentifier\n\t{\n\t\t// \"index name\"\n\t\t$$ = $1\n\t}\n\nIndexOptionList:\n\t{\n\t\t$$ = nil\n\t}\n|\tIndexOptionList IndexOption\n\t{\n\t\t// Merge the options\n\t\tif $1 == nil {\n\t\t\t$$ = $2\n\t\t} else {\n\t\t\topt1 := $1.(*ast.IndexOption)\n\t\t\topt2 := $2.(*ast.IndexOption)\n\t\t\tif len(opt2.Comment) > 0 {\n\t\t\t\topt1.Comment = opt2.Comment\n\t\t\t} else if opt2.Tp != 0 {\n\t\t\t\topt1.Tp = opt2.Tp\n\t\t\t} else if opt2.KeyBlockSize > 0 {\n\t\t\t\topt1.KeyBlockSize = opt2.KeyBlockSize\n\t\t\t} else if len(opt2.ParserName.O) > 0 {\n\t\t\t\topt1.ParserName = opt2.ParserName\n\t\t\t} else if opt2.Visibility != ast.IndexVisibilityDefault {\n\t\t\t\topt1.Visibility = opt2.Visibility\n\t\t\t}\n\t\t\t$$ = opt1\n\t\t}\n\t}\n\nIndexOption:\n\t\"KEY_BLOCK_SIZE\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.IndexOption{\n\t\t\tKeyBlockSize: $3.(uint64),\n\t\t}\n\t}\n|\tIndexType\n\t{\n\t\t$$ = &ast.IndexOption{\n\t\t\tTp: $1.(model.IndexType),\n\t\t}\n\t}\n|\t\"WITH\" \"PARSER\" Identifier\n\t{\n\t\t$$ = &ast.IndexOption{\n\t\t\tParserName: model.NewCIStr($3),\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The WITH PARASER clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"COMMENT\" stringLit\n\t{\n\t\t$$ = &ast.IndexOption{\n\t\t\tComment: $2,\n\t\t}\n\t}\n|\tIndexInvisible\n\t{\n\t\t$$ = &ast.IndexOption{\n\t\t\tVisibility: $1.(ast.IndexVisibility),\n\t\t}\n\t}\n\n/*\n  See: https://github.com/mysql/mysql-server/blob/8.0/sql/sql_yacc.yy#L7179\n\n  The syntax for defining an index is:\n\n    ... INDEX [index_name] [USING|TYPE] <index_type> ...\n\n  The problem is that whereas USING is a reserved word, TYPE is not. We can\n  still handle it if an index name is supplied, i.e.:\n\n    ... INDEX type TYPE <index_type> ...\n\n  here the index's name is unmbiguously 'type', but for this:\n\n    ... INDEX TYPE <index_type> ...\n\n  it's impossible to know what this actually mean - is 'type' the name or the\n  type? For this reason we accept the TYPE syntax only if a name is supplied.\n*/\nIndexNameAndTypeOpt:\n\tIndexName\n\t{\n\t\t$$ = []interface{}{$1, nil}\n\t}\n|\tIndexName \"USING\" IndexTypeName\n\t{\n\t\t$$ = []interface{}{$1, $3}\n\t}\n|\tIdentifier \"TYPE\" IndexTypeName\n\t{\n\t\t$$ = []interface{}{$1, $3}\n\t}\n\nIndexTypeOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\tIndexType\n\t{\n\t\t$$ = $1\n\t}\n\nIndexType:\n\t\"USING\" IndexTypeName\n\t{\n\t\t$$ = $2\n\t}\n|\t\"TYPE\" IndexTypeName\n\t{\n\t\t$$ = $2\n\t}\n\nIndexTypeName:\n\t\"BTREE\"\n\t{\n\t\t$$ = model.IndexTypeBtree\n\t}\n|\t\"HASH\"\n\t{\n\t\t$$ = model.IndexTypeHash\n\t}\n|\t\"RTREE\"\n\t{\n\t\t$$ = model.IndexTypeRtree\n\t}\n\nIndexInvisible:\n\t\"VISIBLE\"\n\t{\n\t\t$$ = ast.IndexVisibilityVisible\n\t}\n|\t\"INVISIBLE\"\n\t{\n\t\t$$ = ast.IndexVisibilityInvisible\n\t}\n\n/**********************************Identifier********************************************/\nIdentifier:\n\tidentifier\n|\tUnReservedKeyword\n|\tNotKeywordToken\n|\tTiDBKeyword\n\nUnReservedKeyword:\n\t\"ACTION\"\n|\t\"ADVISE\"\n|\t\"ASCII\"\n|\t\"AUTO_INCREMENT\"\n|\t\"AFTER\"\n|\t\"ALWAYS\"\n|\t\"AVG\"\n|\t\"BEGIN\"\n|\t\"BIT\"\n|\t\"BOOL\"\n|\t\"BOOLEAN\"\n|\t\"BTREE\"\n|\t\"BYTE\"\n|\t\"CAPTURE\"\n|\t\"CLEANUP\"\n|\t\"CHARSET\"\n|\t\"COLUMNS\"\n|\t\"COMMIT\"\n|\t\"COMPACT\"\n|\t\"COMPRESSED\"\n|\t\"CONSISTENT\"\n|\t\"CURRENT\"\n|\t\"DATA\"\n|\t\"DATE\" %prec lowerThanStringLitToken\n|\t\"DATETIME\"\n|\t\"DAY\"\n|\t\"DEALLOCATE\"\n|\t\"DO\"\n|\t\"DUPLICATE\"\n|\t\"DYNAMIC\"\n|\t\"ENCRYPTION\"\n|\t\"END\"\n|\t\"ENFORCED\"\n|\t\"ENGINE\"\n|\t\"ENGINES\"\n|\t\"ENUM\"\n|\t\"ERRORS\"\n|\t\"ESCAPE\"\n|\t\"EVOLVE\"\n|\t\"EXECUTE\"\n|\t\"EXTENDED\"\n|\t\"FIELDS\"\n|\t\"FILE\"\n|\t\"FIRST\"\n|\t\"FIXED\"\n|\t\"FLUSH\"\n|\t\"FOLLOWING\"\n|\t\"FORMAT\"\n|\t\"FULL\"\n|\t\"GLOBAL\"\n|\t\"HASH\"\n|\t\"HOUR\"\n|\t\"INSERT_METHOD\"\n|\t\"LESS\"\n|\t\"LOCAL\"\n|\t\"LAST\"\n|\t\"NAMES\"\n|\t\"OFFSET\"\n|\t\"PASSWORD\" %prec lowerThanEq\n|\t\"PREPARE\"\n|\t\"QUICK\"\n|\t\"REBUILD\"\n|\t\"REDUNDANT\"\n|\t\"REORGANIZE\"\n|\t\"ROLE\"\n|\t\"ROLLBACK\"\n|\t\"SESSION\"\n|\t\"SIGNED\"\n|\t\"SHUTDOWN\"\n|\t\"SNAPSHOT\"\n|\t\"START\"\n|\t\"STATUS\"\n|\t\"OPEN\"\n|\t\"SUBPARTITIONS\"\n|\t\"SUBPARTITION\"\n|\t\"TABLES\"\n|\t\"TABLESPACE\"\n|\t\"TEXT\"\n|\t\"THAN\"\n|\t\"TIME\" %prec lowerThanStringLitToken\n|\t\"TIMESTAMP\" %prec lowerThanStringLitToken\n|\t\"TRACE\"\n|\t\"TRANSACTION\"\n|\t\"TRUNCATE\"\n|\t\"UNBOUNDED\"\n|\t\"UNKNOWN\"\n|\t\"VALUE\"\n|\t\"WARNINGS\"\n|\t\"YEAR\"\n|\t\"MODE\"\n|\t\"WEEK\"\n|\t\"ANY\"\n|\t\"SOME\"\n|\t\"USER\"\n|\t\"IDENTIFIED\"\n|\t\"COLLATION\"\n|\t\"COMMENT\"\n|\t\"AVG_ROW_LENGTH\"\n|\t\"CONNECTION\"\n|\t\"CHECKSUM\"\n|\t\"COMPRESSION\"\n|\t\"KEY_BLOCK_SIZE\"\n|\t\"MASTER\"\n|\t\"MAX_ROWS\"\n|\t\"MIN_ROWS\"\n|\t\"NATIONAL\"\n|\t\"NCHAR\"\n|\t\"ROW_FORMAT\"\n|\t\"QUARTER\"\n|\t\"GRANTS\"\n|\t\"TRIGGERS\"\n|\t\"DELAY_KEY_WRITE\"\n|\t\"ISOLATION\"\n|\t\"JSON\"\n|\t\"REPEATABLE\"\n|\t\"RESPECT\"\n|\t\"COMMITTED\"\n|\t\"UNCOMMITTED\"\n|\t\"ONLY\"\n|\t\"SERIAL\"\n|\t\"SERIALIZABLE\"\n|\t\"LEVEL\"\n|\t\"VARIABLES\"\n|\t\"SQL_CACHE\"\n|\t\"INDEXES\"\n|\t\"PROCESSLIST\"\n|\t\"SQL_NO_CACHE\"\n|\t\"DISABLE\"\n|\t\"ENABLE\"\n|\t\"REVERSE\"\n|\t\"PRIVILEGES\"\n|\t\"NO\"\n|\t\"BINLOG\"\n|\t\"FUNCTION\"\n|\t\"VIEW\"\n|\t\"BINDING\"\n|\t\"BINDINGS\"\n|\t\"MODIFY\"\n|\t\"EVENTS\"\n|\t\"PARTITIONS\"\n|\t\"NONE\"\n|\t\"NULLS\"\n|\t\"SUPER\"\n|\t\"EXCLUSIVE\"\n|\t\"STATS_PERSISTENT\"\n|\t\"STATS_AUTO_RECALC\"\n|\t\"ROW_COUNT\"\n|\t\"COALESCE\"\n|\t\"MONTH\"\n|\t\"PROCESS\"\n|\t\"PROFILE\"\n|\t\"PROFILES\"\n|\t\"MICROSECOND\"\n|\t\"MINUTE\"\n|\t\"PLUGINS\"\n|\t\"PRECEDING\"\n|\t\"QUERY\"\n|\t\"QUERIES\"\n|\t\"SECOND\"\n|\t\"SEPARATOR\"\n|\t\"SHARE\"\n|\t\"SHARED\"\n|\t\"SLOW\"\n|\t\"MAX_CONNECTIONS_PER_HOUR\"\n|\t\"MAX_QUERIES_PER_HOUR\"\n|\t\"MAX_UPDATES_PER_HOUR\"\n|\t\"MAX_USER_CONNECTIONS\"\n|\t\"REPLICATION\"\n|\t\"CLIENT\"\n|\t\"SLAVE\"\n|\t\"RELOAD\"\n|\t\"TEMPORARY\"\n|\t\"ROUTINE\"\n|\t\"EVENT\"\n|\t\"ALGORITHM\"\n|\t\"DEFINER\"\n|\t\"INVOKER\"\n|\t\"MERGE\"\n|\t\"TEMPTABLE\"\n|\t\"UNDEFINED\"\n|\t\"SECURITY\"\n|\t\"CASCADED\"\n|\t\"RECOVER\"\n|\t\"CIPHER\"\n|\t\"SUBJECT\"\n|\t\"ISSUER\"\n|\t\"X509\"\n|\t\"NEVER\"\n|\t\"EXPIRE\"\n|\t\"ACCOUNT\"\n|\t\"INCREMENTAL\"\n|\t\"CPU\"\n|\t\"MEMORY\"\n|\t\"BLOCK\"\n|\t\"IO\"\n|\t\"CONTEXT\"\n|\t\"SWITCHES\"\n|\t\"PAGE\"\n|\t\"FAULTS\"\n|\t\"IPC\"\n|\t\"SWAPS\"\n|\t\"SOURCE\"\n|\t\"TRADITIONAL\"\n|\t\"SQL_BUFFER_RESULT\"\n|\t\"DIRECTORY\"\n|\t\"HISTORY\"\n|\t\"LIST\"\n|\t\"NODEGROUP\"\n|\t\"SYSTEM_TIME\"\n|\t\"PARTIAL\"\n|\t\"SIMPLE\"\n|\t\"REMOVE\"\n|\t\"PARTITIONING\"\n|\t\"STORAGE\"\n|\t\"DISK\"\n|\t\"STATS_SAMPLE_PAGES\"\n|\t\"SECONDARY_ENGINE\"\n|\t\"SECONDARY_LOAD\"\n|\t\"SECONDARY_UNLOAD\"\n|\t\"VALIDATION\"\n|\t\"WITHOUT\"\n|\t\"RTREE\"\n|\t\"EXCHANGE\"\n|\t\"COLUMN_FORMAT\"\n|\t\"REPAIR\"\n|\t\"IMPORT\"\n|\t\"DISCARD\"\n|\t\"TABLE_CHECKSUM\"\n|\t\"UNICODE\"\n|\t\"AUTO_RANDOM\"\n|\t\"SQL_TSI_DAY\"\n|\t\"SQL_TSI_HOUR\"\n|\t\"SQL_TSI_MINUTE\"\n|\t\"SQL_TSI_MONTH\"\n|\t\"SQL_TSI_QUARTER\"\n|\t\"SQL_TSI_SECOND\"\n|\t\"LANGUAGE\"\n|\t\"SQL_TSI_WEEK\"\n|\t\"SQL_TSI_YEAR\"\n|\t\"INVISIBLE\"\n|\t\"VISIBLE\"\n|\t\"TYPE\"\n|\t\"NOWAIT\"\n|\t\"REPLICA\"\n|\t\"LOCATION\"\n|\t\"LABELS\"\n|\t\"LOGS\"\n|\t\"HOSTS\"\n|\t\"AGAINST\"\n|\t\"EXPANSION\"\n|\t\"INCREMENT\"\n|\t\"MINVALUE\"\n|\t\"NOMAXVALUE\"\n|\t\"NOMINVALUE\"\n|\t\"NOCACHE\"\n|\t\"CACHE\"\n|\t\"CYCLE\"\n|\t\"NOCYCLE\"\n|\t\"NOORDER\"\n|\t\"SEQUENCE\"\n|\t\"MAX_MINUTES\"\n|\t\"MAX_IDXNUM\"\n|\t\"PER_TABLE\"\n|\t\"PER_DB\"\n|\t\"PLAINTEXT\"\n|\t\"PLAINTEXT_AFTER_JOIN\"\n|\t\"PLAINTEXT_AS_JOIN_PAYLOAD\"\n|\t\"REVEAL_RANK\"\n|\t\"PLAINTEXT_AFTER_GROUP_BY\"\n|\t\"PLAINTEXT_AFTER_COMPARE\"\n|\t\"PLAINTEXT_AFTER_AGGREGATE\"\n|\t\"ENCRYPTED_ONLY\"\n|\t\"PARTY_CODE\"\n|\t\"TOKEN\"\n|\t\"ENDPOINT\"\n|\t\"REF_TABLE\"\n|\t\"DB_TYPE\"\n\nTiDBKeyword:\n\t\"ADMIN\"\n|\t\"BUCKETS\"\n|\t\"BUILTINS\"\n|\t\"CANCEL\"\n|\t\"CMSKETCH\"\n|\t\"DDL\"\n|\t\"DEPTH\"\n|\t\"DRAINER\"\n|\t\"JOBS\"\n|\t\"JOB\"\n|\t\"NODE_ID\"\n|\t\"NODE_STATE\"\n|\t\"PUMP\"\n|\t\"SAMPLES\"\n|\t\"STATS\"\n|\t\"STATS_META\"\n|\t\"STATS_HISTOGRAMS\"\n|\t\"STATS_BUCKETS\"\n|\t\"STATS_HEALTHY\"\n|\t\"TIDB\"\n|\t\"TIFLASH\"\n|\t\"TOPN\"\n|\t\"SPLIT\"\n|\t\"OPTIMISTIC\"\n|\t\"PESSIMISTIC\"\n|\t\"WIDTH\"\n|\t\"REGIONS\"\n|\t\"REGION\"\n|\t\"{{\"\n|\t\"}}\"\n\nNotKeywordToken:\n\t\"ADDDATE\"\n|\t\"BIT_AND\"\n|\t\"BIT_OR\"\n|\t\"BIT_XOR\"\n|\t\"CAST\"\n|\t\"COPY\"\n|\t\"COUNT\"\n|\t\"CURTIME\"\n|\t\"DATE_ADD\"\n|\t\"DATE_SUB\"\n|\t\"EXTRACT\"\n|\t\"GET_FORMAT\"\n|\t\"GROUP_CONCAT\"\n|\t\"INPLACE\"\n|\t\"INSTANT\"\n|\t\"INTERNAL\"\n|\t\"MIN\"\n|\t\"MAX\"\n|\t\"NOW\"\n|\t\"RECENT\"\n|\t\"PERCENTILE_DISC\"\n|\t\"POSITION\"\n|\t\"SUBDATE\"\n|\t\"SUBSTRING\"\n|\t\"SUM\"\n|\t\"STD\"\n|\t\"STDDEV\"\n|\t\"STDDEV_POP\"\n|\t\"STDDEV_SAMP\"\n|\t\"VARIANCE\"\n|\t\"VAR_POP\"\n|\t\"VAR_SAMP\"\n|\t\"TIMESTAMPADD\"\n|\t\"TIMESTAMPDIFF\"\n|\t\"TOKUDB_DEFAULT\"\n|\t\"TOKUDB_FAST\"\n|\t\"TOKUDB_LZMA\"\n|\t\"TOKUDB_QUICKLZ\"\n|\t\"TOKUDB_SNAPPY\"\n|\t\"TOKUDB_SMALL\"\n|\t\"TOKUDB_UNCOMPRESSED\"\n|\t\"TOKUDB_ZLIB\"\n|\t\"TOP\"\n|\t\"TRIM\"\n|\t\"NEXT_ROW_ID\"\n|\t\"EXPR_PUSHDOWN_BLACKLIST\"\n|\t\"OPT_RULE_BLACKLIST\"\n|\t\"BOUND\"\n|\t\"EXACT\"\n|\t\"STALENESS\"\n|\t\"STRONG\"\n|\t\"FLASHBACK\"\n\n/************************************************************************************\n *\n *  Insert Statements\n *\n *  TODO: support PARTITION\n **********************************************************************************/\nInsertIntoStmt:\n\t\"INSERT\" PriorityOpt IgnoreOptional IntoOpt TableName InsertValues OnDuplicateKeyUpdate\n\t{\n\t\tx := $6.(*ast.InsertStmt)\n\t\tx.Priority = $2.(mysql.PriorityEnum)\n\t\tx.IgnoreErr = $3.(bool)\n\t\t// Wraps many layers here so that it can be processed the same way as select statement.\n\t\tts := &ast.TableSource{Source: $5.(*ast.TableName)}\n\t\tx.Table = &ast.TableRefsClause{TableRefs: &ast.Join{Left: ts}}\n\t\tif $7 != nil {\n\t\t\tx.OnDuplicate = $7.([]*ast.Assignment)\n\t\t}\n\t\t$$ = x\n\t}\n\nIntoOpt:\n\t{}\n|\t\"INTO\"\n\nInsertValues:\n\t'(' ColumnNameListOpt ')' ValueSym ValuesList\n\t{\n\t\t$$ = &ast.InsertStmt{\n\t\t\tColumns: $2.([]*ast.ColumnName),\n\t\t\tLists:   $5.([][]ast.ExprNode),\n\t\t}\n\t}\n|\t'(' ColumnNameListOpt ')' SelectStmt\n\t{\n\t\t$$ = &ast.InsertStmt{Columns: $2.([]*ast.ColumnName), Select: $4.(*ast.SelectStmt)}\n\t}\n|\t'(' ColumnNameListOpt ')' '(' SelectStmt ')'\n\t{\n\t\t$$ = &ast.InsertStmt{Columns: $2.([]*ast.ColumnName), Select: $5.(*ast.SelectStmt)}\n\t}\n|\t'(' ColumnNameListOpt ')' UnionStmt\n\t{\n\t\t$$ = &ast.InsertStmt{Columns: $2.([]*ast.ColumnName), Select: $4.(*ast.UnionStmt)}\n\t}\n|\tValueSym ValuesList %prec insertValues\n\t{\n\t\t$$ = &ast.InsertStmt{Lists: $2.([][]ast.ExprNode)}\n\t}\n|\t'(' SelectStmt ')'\n\t{\n\t\t$$ = &ast.InsertStmt{Select: $2.(*ast.SelectStmt)}\n\t}\n|\tSelectStmt\n\t{\n\t\t$$ = &ast.InsertStmt{Select: $1.(*ast.SelectStmt)}\n\t}\n|\tUnionStmt\n\t{\n\t\t$$ = &ast.InsertStmt{Select: $1.(*ast.UnionStmt)}\n\t}\n|\t\"SET\" ColumnSetValueList\n\t{\n\t\t$$ = &ast.InsertStmt{Setlist: $2.([]*ast.Assignment)}\n\t}\n\nValueSym:\n\t\"VALUE\"\n|\t\"VALUES\"\n\nValuesList:\n\tRowValue\n\t{\n\t\t$$ = [][]ast.ExprNode{$1.([]ast.ExprNode)}\n\t}\n|\tValuesList ',' RowValue\n\t{\n\t\t$$ = append($1.([][]ast.ExprNode), $3.([]ast.ExprNode))\n\t}\n\nRowValue:\n\t'(' ValuesOpt ')'\n\t{\n\t\t$$ = $2\n\t}\n\nValuesOpt:\n\t{\n\t\t$$ = []ast.ExprNode{}\n\t}\n|\tValues\n\nValues:\n\tValues ',' ExprOrDefault\n\t{\n\t\t$$ = append($1.([]ast.ExprNode), $3)\n\t}\n|\tExprOrDefault\n\t{\n\t\t$$ = []ast.ExprNode{$1}\n\t}\n\nExprOrDefault:\n\tExpression\n|\t\"DEFAULT\"\n\t{\n\t\t$$ = &ast.DefaultExpr{}\n\t}\n\nColumnSetValue:\n\tColumnName eq ExprOrDefault\n\t{\n\t\t$$ = &ast.Assignment{\n\t\t\tColumn: $1.(*ast.ColumnName),\n\t\t\tExpr:   $3,\n\t\t}\n\t}\n\nColumnSetValueList:\n\t{\n\t\t$$ = []*ast.Assignment{}\n\t}\n|\tColumnSetValue\n\t{\n\t\t$$ = []*ast.Assignment{$1.(*ast.Assignment)}\n\t}\n|\tColumnSetValueList ',' ColumnSetValue\n\t{\n\t\t$$ = append($1.([]*ast.Assignment), $3.(*ast.Assignment))\n\t}\n\n/*\n * ON DUPLICATE KEY UPDATE col_name=expr [, col_name=expr] ...\n * See https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html\n */\nOnDuplicateKeyUpdate:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"ON\" \"DUPLICATE\" \"KEY\" \"UPDATE\" AssignmentList\n\t{\n\t\t$$ = $5\n\t}\n\n/************************************************************************************\n *  Replace Statements\n *  See https://dev.mysql.com/doc/refman/5.7/en/replace.html\n *\n *  TODO: support PARTITION\n **********************************************************************************/\nReplaceIntoStmt:\n\t\"REPLACE\" PriorityOpt IntoOpt TableName InsertValues\n\t{\n\t\tx := $5.(*ast.InsertStmt)\n\t\tx.IsReplace = true\n\t\tx.Priority = $2.(mysql.PriorityEnum)\n\t\tts := &ast.TableSource{Source: $4.(*ast.TableName)}\n\t\tx.Table = &ast.TableRefsClause{TableRefs: &ast.Join{Left: ts}}\n\t\t$$ = x\n\t}\n\nODBCDateTimeType:\n\t\"d\"\n\t{\n\t\t$$ = ast.DateLiteral\n\t}\n|\t\"t\"\n\t{\n\t\t$$ = ast.TimeLiteral\n\t}\n|\t\"ts\"\n\t{\n\t\t$$ = ast.TimestampLiteral\n\t}\n\nLiteral:\n\t\"FALSE\"\n\t{\n\t\t$$ = ast.NewValueExpr(false)\n\t}\n|\t\"NULL\"\n\t{\n\t\t$$ = ast.NewValueExpr(nil)\n\t}\n|\t\"TRUE\"\n\t{\n\t\t$$ = ast.NewValueExpr(true)\n\t}\n|\tfloatLit\n\t{\n\t\t$$ = ast.NewValueExpr($1)\n\t}\n|\tdecLit\n\t{\n\t\t$$ = ast.NewValueExpr($1)\n\t}\n|\tintLit\n\t{\n\t\t$$ = ast.NewValueExpr($1)\n\t}\n|\tStringLiteral %prec lowerThanStringLitToken\n\t{\n\t\t$$ = $1\n\t}\n|\t\"UNDERSCORE_CHARSET\" stringLit\n\t{\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/charset-literal.html\n\t\tco, err := charset.GetDefaultCollation($1)\n\t\tif err != nil {\n\t\t\tyylex.AppendError(yylex.Errorf(\"Get collation error for charset: %s\", $1))\n\t\t\treturn 1\n\t\t}\n\t\texpr := ast.NewValueExpr($2)\n\t\ttp := expr.GetType()\n\t\ttp.Charset = $1\n\t\ttp.Collate = co\n\t\tif tp.Collate == charset.CollationBin {\n\t\t\ttp.Flag |= mysql.BinaryFlag\n\t\t}\n\t\t$$ = expr\n\t}\n|\thexLit\n\t{\n\t\t$$ = ast.NewValueExpr($1)\n\t}\n|\tbitLit\n\t{\n\t\t$$ = ast.NewValueExpr($1)\n\t}\n\nStringLiteral:\n\tstringLit\n\t{\n\t\texpr := ast.NewValueExpr($1)\n\t\t$$ = expr\n\t}\n|\tStringLiteral stringLit\n\t{\n\t\tvalExpr := $1.(ast.ValueExpr)\n\t\tstrLit := valExpr.GetString()\n\t\texpr := ast.NewValueExpr(strLit + $2)\n\t\t// Fix #4239, use first string literal as projection name.\n\t\tif valExpr.GetProjectionOffset() >= 0 {\n\t\t\texpr.SetProjectionOffset(valExpr.GetProjectionOffset())\n\t\t} else {\n\t\t\texpr.SetProjectionOffset(len(strLit))\n\t\t}\n\t\t$$ = expr\n\t}\n\nAlterOrderList:\n\tAlterOrderItem\n\t{\n\t\t$$ = []*ast.AlterOrderItem{$1.(*ast.AlterOrderItem)}\n\t}\n|\tAlterOrderList ',' AlterOrderItem\n\t{\n\t\t$$ = append($1.([]*ast.AlterOrderItem), $3.(*ast.AlterOrderItem))\n\t}\n\nAlterOrderItem:\n\tColumnName Order\n\t{\n\t\t$$ = &ast.AlterOrderItem{Column: $1.(*ast.ColumnName), Desc: $2.(bool)}\n\t}\n\nOrderBy:\n\t\"ORDER\" \"BY\" ByList\n\t{\n\t\t$$ = &ast.OrderByClause{Items: $3.([]*ast.ByItem)}\n\t}\n\nByList:\n\tByItem\n\t{\n\t\t$$ = []*ast.ByItem{$1.(*ast.ByItem)}\n\t}\n|\tByList ',' ByItem\n\t{\n\t\t$$ = append($1.([]*ast.ByItem), $3.(*ast.ByItem))\n\t}\n\nByItem:\n\tExpression Order\n\t{\n\t\texpr := $1\n\t\tvalueExpr, ok := expr.(ast.ValueExpr)\n\t\tif ok {\n\t\t\tposition, isPosition := valueExpr.GetValue().(int64)\n\t\t\tif isPosition {\n\t\t\t\texpr = &ast.PositionExpr{N: int(position)}\n\t\t\t}\n\t\t}\n\t\t$$ = &ast.ByItem{Expr: expr, Desc: $2.(bool)}\n\t}\n\nOrder:\n\t/* EMPTY */\n\t{\n\t\t$$ = false // ASC by default\n\t}\n|\t\"ASC\"\n\t{\n\t\t$$ = false\n\t}\n|\t\"DESC\"\n\t{\n\t\t$$ = true\n\t}\n\nOrderByOptional:\n\t{\n\t\t$$ = nil\n\t}\n|\tOrderBy\n\t{\n\t\t$$ = $1\n\t}\n\nBitExpr:\n\tBitExpr '|' BitExpr %prec '|'\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.Or, L: $1, R: $3}\n\t}\n|\tBitExpr '&' BitExpr %prec '&'\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.And, L: $1, R: $3}\n\t}\n|\tBitExpr \"<<\" BitExpr %prec lsh\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.LeftShift, L: $1, R: $3}\n\t}\n|\tBitExpr \">>\" BitExpr %prec rsh\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.RightShift, L: $1, R: $3}\n\t}\n|\tBitExpr '+' BitExpr %prec '+'\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.Plus, L: $1, R: $3}\n\t}\n|\tBitExpr '-' BitExpr %prec '-'\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.Minus, L: $1, R: $3}\n\t}\n|\tBitExpr '+' \"INTERVAL\" Expression TimeUnit %prec '+'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr(\"DATE_ADD\"),\n\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t$1,\n\t\t\t\t$4,\n\t\t\t\t&ast.TimeUnitExpr{Unit: $5.(ast.TimeUnitType)},\n\t\t\t},\n\t\t}\n\t}\n|\tBitExpr '-' \"INTERVAL\" Expression TimeUnit %prec '+'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr(\"DATE_SUB\"),\n\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t$1,\n\t\t\t\t$4,\n\t\t\t\t&ast.TimeUnitExpr{Unit: $5.(ast.TimeUnitType)},\n\t\t\t},\n\t\t}\n\t}\n|\tBitExpr '*' BitExpr %prec '*'\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.Mul, L: $1, R: $3}\n\t}\n|\tBitExpr '/' BitExpr %prec '/'\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.Div, L: $1, R: $3}\n\t}\n|\tBitExpr '%' BitExpr %prec '%'\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.Mod, L: $1, R: $3}\n\t}\n|\tBitExpr \"DIV\" BitExpr %prec div\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.IntDiv, L: $1, R: $3}\n\t}\n|\tBitExpr \"MOD\" BitExpr %prec mod\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.Mod, L: $1, R: $3}\n\t}\n|\tBitExpr '^' BitExpr\n\t{\n\t\t$$ = &ast.BinaryOperationExpr{Op: opcode.Xor, L: $1, R: $3}\n\t}\n|\tSimpleExpr\n\nSimpleIdent:\n\tIdentifier\n\t{\n\t\t$$ = &ast.ColumnNameExpr{Name: &ast.ColumnName{\n\t\t\tName: model.NewCIStr($1),\n\t\t}}\n\t}\n|\tIdentifier '.' Identifier\n\t{\n\t\t$$ = &ast.ColumnNameExpr{Name: &ast.ColumnName{\n\t\t\tTable: model.NewCIStr($1),\n\t\t\tName:  model.NewCIStr($3),\n\t\t}}\n\t}\n|\t'.' Identifier '.' Identifier\n\t{\n\t\t$$ = &ast.ColumnNameExpr{Name: &ast.ColumnName{\n\t\t\tTable: model.NewCIStr($2),\n\t\t\tName:  model.NewCIStr($4),\n\t\t}}\n\t}\n|\tIdentifier '.' Identifier '.' Identifier\n\t{\n\t\t$$ = &ast.ColumnNameExpr{Name: &ast.ColumnName{\n\t\t\tSchema: model.NewCIStr($1),\n\t\t\tTable:  model.NewCIStr($3),\n\t\t\tName:   model.NewCIStr($5),\n\t\t}}\n\t}\n\nParamMarker:\n\t\"{{\" StringName \"}}\"\n\t{\n\t\t$$ = ast.NewParamMarkerExpr(yyS[yypt].offset, $2.(string))\n\t}\n\nSimpleExpr:\n\tSimpleIdent\n|\tFunctionCallKeyword\n|\tFunctionCallNonKeyword\n|\tFunctionCallGeneric\n|\tSimpleExpr \"COLLATE\" StringName %prec neg\n\t{\n\t\t// TODO: Create a builtin function hold expr and collation. When do evaluation, convert expr result using the collation.\n\t\t$$ = $1\n\t}\n|\tWindowFuncCall\n\t{\n\t\t$$ = $1.(*ast.WindowFuncExpr)\n\t}\n|\tLiteral\n|\tParamMarker\n\t{\n\t\t$$ = $1\n\t}\n|\tVariable\n|\tSumExpr\n|\t'!' SimpleExpr %prec neg\n\t{\n\t\t$$ = &ast.UnaryOperationExpr{Op: opcode.Not, V: $2}\n\t}\n|\t'~' SimpleExpr %prec neg\n\t{\n\t\t$$ = &ast.UnaryOperationExpr{Op: opcode.BitNeg, V: $2}\n\t}\n|\t'-' SimpleExpr %prec neg\n\t{\n\t\t$$ = &ast.UnaryOperationExpr{Op: opcode.Minus, V: $2}\n\t}\n|\t'+' SimpleExpr %prec neg\n\t{\n\t\t$$ = &ast.UnaryOperationExpr{Op: opcode.Plus, V: $2}\n\t}\n|\tSimpleExpr pipes SimpleExpr\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Concat), Args: []ast.ExprNode{$1, $3}}\n\t}\n|\tnot2 SimpleExpr %prec neg\n\t{\n\t\t$$ = &ast.UnaryOperationExpr{Op: opcode.Not, V: $2}\n\t}\n|\tSubSelect\n|\t'(' Expression ')'\n\t{\n\t\tstartOffset := parser.startOffset(&yyS[yypt-1])\n\t\tendOffset := parser.endOffset(&yyS[yypt])\n\t\texpr := $2\n\t\texpr.SetText(parser.src[startOffset:endOffset])\n\t\t$$ = &ast.ParenthesesExpr{Expr: expr}\n\t}\n|\t'(' ExpressionList ',' Expression ')'\n\t{\n\t\tvalues := append($2.([]ast.ExprNode), $4)\n\t\t$$ = &ast.RowExpr{Values: values}\n\t}\n|\t\"ROW\" '(' ExpressionList ',' Expression ')'\n\t{\n\t\tvalues := append($3.([]ast.ExprNode), $5)\n\t\t$$ = &ast.RowExpr{Values: values}\n\t}\n|\t\"EXISTS\" SubSelect\n\t{\n\t\tsq := $2.(*ast.SubqueryExpr)\n\t\tsq.Exists = true\n\t\t$$ = &ast.ExistsSubqueryExpr{Sel: sq}\n\t}\n|\t\"BINARY\" SimpleExpr %prec neg\n\t{\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#operator_binary\n\t\tx := types.NewFieldType(mysql.TypeString)\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CharsetBin\n\t\t$$ = &ast.FuncCastExpr{\n\t\t\tExpr:         $2,\n\t\t\tTp:           x,\n\t\t\tFunctionType: ast.CastBinaryOperator,\n\t\t}\n\t}\n|\tbuiltinCast '(' Expression \"AS\" CastType ')'\n\t{\n\t\t/* See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_cast */\n\t\ttp := $5.(*types.FieldType)\n\t\tdefaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimalForCast(tp.Tp)\n\t\tif tp.Flen == types.UnspecifiedLength {\n\t\t\ttp.Flen = defaultFlen\n\t\t}\n\t\tif tp.Decimal == types.UnspecifiedLength {\n\t\t\ttp.Decimal = defaultDecimal\n\t\t}\n\t\t$$ = &ast.FuncCastExpr{\n\t\t\tExpr:         $3,\n\t\t\tTp:           tp,\n\t\t\tFunctionType: ast.CastFunction,\n\t\t}\n\t}\n|\t\"CASE\" ExpressionOpt WhenClauseList ElseOpt \"END\"\n\t{\n\t\tx := &ast.CaseExpr{WhenClauses: $3.([]*ast.WhenClause)}\n\t\tif $2 != nil {\n\t\t\tx.Value = $2\n\t\t}\n\t\tif $4 != nil {\n\t\t\tx.ElseClause = $4.(ast.ExprNode)\n\t\t}\n\t\t$$ = x\n\t}\n|\t\"CONVERT\" '(' Expression ',' CastType ')'\n\t{\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert\n\t\ttp := $5.(*types.FieldType)\n\t\tdefaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimalForCast(tp.Tp)\n\t\tif tp.Flen == types.UnspecifiedLength {\n\t\t\ttp.Flen = defaultFlen\n\t\t}\n\t\tif tp.Decimal == types.UnspecifiedLength {\n\t\t\ttp.Decimal = defaultDecimal\n\t\t}\n\t\t$$ = &ast.FuncCastExpr{\n\t\t\tExpr:         $3,\n\t\t\tTp:           tp,\n\t\t\tFunctionType: ast.CastConvertFunction,\n\t\t}\n\t}\n|\t\"CONVERT\" '(' Expression \"USING\" CharsetName ')'\n\t{\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert\n\t\tcharset1 := ast.NewValueExpr($5)\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{$3, charset1},\n\t\t}\n\t}\n|\t\"DEFAULT\" '(' SimpleIdent ')'\n\t{\n\t\t$$ = &ast.DefaultExpr{Name: $3.(*ast.ColumnNameExpr).Name}\n\t}\n|\t\"VALUES\" '(' SimpleIdent ')' %prec lowerThanInsertValues\n\t{\n\t\t$$ = &ast.ValuesExpr{Column: $3.(*ast.ColumnNameExpr)}\n\t}\n|\tSimpleIdent jss stringLit\n\t{\n\t\texpr := ast.NewValueExpr($3)\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONExtract), Args: []ast.ExprNode{$1, expr}}\n\t}\n|\tSimpleIdent juss stringLit\n\t{\n\t\texpr := ast.NewValueExpr($3)\n\t\textract := &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONExtract), Args: []ast.ExprNode{$1, expr}}\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONUnquote), Args: []ast.ExprNode{extract}}\n\t}\n\nDistinctKwd:\n\t\"DISTINCT\"\n|\t\"DISTINCTROW\"\n\nDistinctOpt:\n\t\"ALL\"\n\t{\n\t\t$$ = false\n\t}\n|\tDistinctKwd\n\t{\n\t\t$$ = true\n\t}\n\nDefaultFalseDistinctOpt:\n\t{\n\t\t$$ = false\n\t}\n|\tDistinctOpt\n\nDefaultTrueDistinctOpt:\n\t{\n\t\t$$ = true\n\t}\n|\tDistinctOpt\n\nBuggyDefaultFalseDistinctOpt:\n\tDefaultFalseDistinctOpt\n|\tDistinctKwd \"ALL\"\n\t{\n\t\t$$ = true\n\t}\n\nFunctionNameConflict:\n\t\"ASCII\"\n|\t\"CHARSET\"\n|\t\"COALESCE\"\n|\t\"COLLATION\"\n|\t\"DATE\"\n|\t\"DATABASE\"\n|\t\"DAY\"\n|\t\"HOUR\"\n|\t\"IF\"\n|\t\"INTERVAL\" %prec lowerThanIntervalKeyword\n|\t\"FORMAT\"\n|\t\"LEFT\"\n|\t\"MICROSECOND\"\n|\t\"MINUTE\"\n|\t\"MONTH\"\n|\tbuiltinNow\n|\t\"QUARTER\"\n|\t\"REPEAT\"\n|\t\"REPLACE\"\n|\t\"REVERSE\"\n|\t\"RIGHT\"\n|\t\"ROW_COUNT\"\n|\t\"SECOND\"\n|\t\"TIME\"\n|\t\"TIMESTAMP\"\n|\t\"TRUNCATE\"\n|\t\"USER\"\n|\t\"WEEK\"\n|\t\"YEAR\"\n\nOptionalBraces:\n\t{}\n|\t'(' ')'\n\t{}\n\nFunctionNameOptionalBraces:\n\t\"CURRENT_USER\"\n|\t\"CURRENT_DATE\"\n|\t\"CURRENT_ROLE\"\n|\t\"UTC_DATE\"\n\nFunctionNameDatetimePrecision:\n\t\"CURRENT_TIME\"\n|\t\"CURRENT_TIMESTAMP\"\n|\t\"LOCALTIME\"\n|\t\"LOCALTIMESTAMP\"\n|\t\"UTC_TIME\"\n|\t\"UTC_TIMESTAMP\"\n\nFunctionCallKeyword:\n\tFunctionNameConflict '(' ExpressionListOpt ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}\n\t}\n|\tbuiltinUser '(' ExpressionListOpt ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}\n\t}\n|\tFunctionNameOptionalBraces OptionalBraces\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1)}\n\t}\n|\tbuiltinCurDate '(' ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1)}\n\t}\n|\tFunctionNameDatetimePrecision FuncDatetimePrec\n\t{\n\t\targs := []ast.ExprNode{}\n\t\tif $2 != nil {\n\t\t\targs = append(args, $2.(ast.ExprNode))\n\t\t}\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: args}\n\t}\n|\t\"CHAR\" '(' ExpressionList ')'\n\t{\n\t\tnilVal := ast.NewValueExpr(nil)\n\t\targs := $3.([]ast.ExprNode)\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr(ast.CharFunc),\n\t\t\tArgs:   append(args, nilVal),\n\t\t}\n\t}\n|\t\"CHAR\" '(' ExpressionList \"USING\" CharsetName ')'\n\t{\n\t\tcharset1 := ast.NewValueExpr($5)\n\t\targs := $3.([]ast.ExprNode)\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr(ast.CharFunc),\n\t\t\tArgs:   append(args, charset1),\n\t\t}\n\t}\n|\t\"DATE\" stringLit\n\t{\n\t\texpr := ast.NewValueExpr($2)\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.DateLiteral), Args: []ast.ExprNode{expr}}\n\t}\n|\t\"TIME\" stringLit\n\t{\n\t\texpr := ast.NewValueExpr($2)\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.TimeLiteral), Args: []ast.ExprNode{expr}}\n\t}\n|\t\"TIMESTAMP\" stringLit\n\t{\n\t\texpr := ast.NewValueExpr($2)\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.TimestampLiteral), Args: []ast.ExprNode{expr}}\n\t}\n|\t\"INSERT\" '(' ExpressionListOpt ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.InsertFunc), Args: $3.([]ast.ExprNode)}\n\t}\n|\t\"MOD\" '(' BitExpr ',' BitExpr ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Mod), Args: []ast.ExprNode{$3, $5}}\n\t}\n|\t\"PASSWORD\" '(' ExpressionListOpt ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.PasswordFunc), Args: $3.([]ast.ExprNode)}\n\t}\n|\t'{' ODBCDateTimeType stringLit '}'\n\t{\n\t\t// This is ODBC syntax for date and time literals.\n\t\t// See: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html\n\t\texpr := ast.NewValueExpr($3)\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($2), Args: []ast.ExprNode{expr}}\n\t}\n\nFunctionCallNonKeyword:\n\tbuiltinCurTime '(' FuncDatetimePrecListOpt ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}\n\t}\n|\tbuiltinSysDate '(' FuncDatetimePrecListOpt ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}\n\t}\n|\tFunctionNameDateArithMultiForms '(' Expression ',' Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t$3,\n\t\t\t\t$5,\n\t\t\t\t&ast.TimeUnitExpr{Unit: ast.TimeUnitDay},\n\t\t\t},\n\t\t}\n\t}\n|\tFunctionNameDateArithMultiForms '(' Expression ',' \"INTERVAL\" Expression TimeUnit ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t$3,\n\t\t\t\t$6,\n\t\t\t\t&ast.TimeUnitExpr{Unit: $7.(ast.TimeUnitType)},\n\t\t\t},\n\t\t}\n\t}\n|\tFunctionNameDateArith '(' Expression ',' \"INTERVAL\" Expression TimeUnit ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t$3,\n\t\t\t\t$6,\n\t\t\t\t&ast.TimeUnitExpr{Unit: $7.(ast.TimeUnitType)},\n\t\t\t},\n\t\t}\n\t}\n|\tbuiltinExtract '(' TimeUnit \"FROM\" Expression ')'\n\t{\n\t\ttimeUnit := &ast.TimeUnitExpr{Unit: $3.(ast.TimeUnitType)}\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{timeUnit, $5},\n\t\t}\n\t}\n|\t\"GET_FORMAT\" '(' GetFormatSelector ',' Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs: []ast.ExprNode{\n\t\t\t\t&ast.GetFormatSelectorExpr{Selector: $3.(ast.GetFormatSelectorType)},\n\t\t\t\t$5,\n\t\t\t},\n\t\t}\n\t}\n|\tbuiltinPosition '(' BitExpr \"IN\" Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: []ast.ExprNode{$3, $5}}\n\t}\n|\tbuiltinSubstring '(' Expression ',' Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{$3, $5},\n\t\t}\n\t}\n|\tbuiltinSubstring '(' Expression \"FROM\" Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{$3, $5},\n\t\t}\n\t}\n|\tbuiltinSubstring '(' Expression ',' Expression ',' Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{$3, $5, $7},\n\t\t}\n\t}\n|\tbuiltinSubstring '(' Expression \"FROM\" Expression \"FOR\" Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{$3, $5, $7},\n\t\t}\n\t}\n|\t\"TIMESTAMPADD\" '(' TimestampUnit ',' Expression ',' Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{&ast.TimeUnitExpr{Unit: $3.(ast.TimeUnitType)}, $5, $7},\n\t\t}\n\t}\n|\t\"TIMESTAMPDIFF\" '(' TimestampUnit ',' Expression ',' Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{&ast.TimeUnitExpr{Unit: $3.(ast.TimeUnitType)}, $5, $7},\n\t\t}\n\t}\n|\tbuiltinTrim '(' Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{$3},\n\t\t}\n\t}\n|\tbuiltinTrim '(' Expression \"FROM\" Expression ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{$5, $3},\n\t\t}\n\t}\n|\tbuiltinTrim '(' TrimDirection \"FROM\" Expression ')'\n\t{\n\t\tnilVal := ast.NewValueExpr(nil)\n\t\tdirection := &ast.TrimDirectionExpr{Direction: $3.(ast.TrimDirectionType)}\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{$5, nilVal, direction},\n\t\t}\n\t}\n|\tbuiltinTrim '(' TrimDirection Expression \"FROM\" Expression ')'\n\t{\n\t\tdirection := &ast.TrimDirectionExpr{Direction: $3.(ast.TrimDirectionType)}\n\t\t$$ = &ast.FuncCallExpr{\n\t\t\tFnName: model.NewCIStr($1),\n\t\t\tArgs:   []ast.ExprNode{$6, $4, direction},\n\t\t}\n\t}\n\nGetFormatSelector:\n\t\"DATE\"\n\t{\n\t\t$$ = ast.GetFormatSelectorDate\n\t}\n|\t\"DATETIME\"\n\t{\n\t\t$$ = ast.GetFormatSelectorDatetime\n\t}\n|\t\"TIME\"\n\t{\n\t\t$$ = ast.GetFormatSelectorTime\n\t}\n|\t\"TIMESTAMP\"\n\t{\n\t\t$$ = ast.GetFormatSelectorDatetime\n\t}\n\nFunctionNameDateArith:\n\tbuiltinDateAdd\n|\tbuiltinDateSub\n\nFunctionNameDateArithMultiForms:\n\tbuiltinAddDate\n|\tbuiltinSubDate\n\nTrimDirection:\n\t\"BOTH\"\n\t{\n\t\t$$ = ast.TrimBoth\n\t}\n|\t\"LEADING\"\n\t{\n\t\t$$ = ast.TrimLeading\n\t}\n|\t\"TRAILING\"\n\t{\n\t\t$$ = ast.TrimTrailing\n\t}\n\nSumExpr:\n\t\"AVG\" '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)}\n\t\t}\n\t}\n|\tbuiltinBitAnd '(' Expression ')' OptWindowingClause\n\t{\n\t\tif $5 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, Spec: *($5.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3}}\n\t\t}\n\t}\n|\tbuiltinBitAnd '(' \"ALL\" Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}}\n\t\t}\n\t}\n|\tbuiltinBitOr '(' Expression ')' OptWindowingClause\n\t{\n\t\tif $5 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, Spec: *($5.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3}}\n\t\t}\n\t}\n|\tbuiltinBitOr '(' \"ALL\" Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}}\n\t\t}\n\t}\n|\tbuiltinBitXor '(' Expression ')' OptWindowingClause\n\t{\n\t\tif $5 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, Spec: *($5.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3}}\n\t\t}\n\t}\n|\tbuiltinBitXor '(' \"ALL\" Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}}\n\t\t}\n\t}\n|\tbuiltinCount '(' DistinctKwd ExpressionList ')'\n\t{\n\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: $4.([]ast.ExprNode), Distinct: true}\n\t}\n|\tbuiltinCount '(' \"ALL\" Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}}\n\t\t}\n\t}\n|\tbuiltinCount '(' Expression ')' OptWindowingClause\n\t{\n\t\tif $5 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, Spec: *($5.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3}}\n\t\t}\n\t}\n|\tbuiltinCount '(' '*' ')' OptWindowingClause\n\t{\n\t\targs := []ast.ExprNode{ast.NewValueExpr(1)}\n\t\tif $5 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: args, Spec: *($5.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: args}\n\t\t}\n\t}\n|\tbuiltinGroupConcat '(' BuggyDefaultFalseDistinctOpt ExpressionList OrderByOptional OptGConcatSeparator ')'\n\t{\n\t\targs := $4.([]ast.ExprNode)\n\t\targs = append(args, $6.(ast.ExprNode))\n\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: args, Distinct: $3.(bool)}\n\t}\n|\tbuiltinMax '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)}\n\t\t}\n\t}\n|\tbuiltinMin '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)}\n\t\t}\n\t}\n|\tbuiltinPercentileDisc '(' ExpressionList ')'\n\t{\n\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: $3.([]ast.ExprNode)}\n\t}\n|\tbuiltinSum '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)}\n\t\t}\n\t}\n|\tbuiltinStddevPop '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: ast.AggFuncStddevPop, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: ast.AggFuncStddevPop, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)}\n\t\t}\n\t}\n|\tbuiltinStddevSamp '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)}\n\t\t}\n\t}\n|\tbuiltinVarPop '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause\n\t{\n\t\tif $6 != nil {\n\t\t\t$$ = &ast.WindowFuncExpr{F: ast.AggFuncVarPop, Args: []ast.ExprNode{$4}, Distinct: $3.(bool), Spec: *($6.(*ast.WindowSpec))}\n\t\t} else {\n\t\t\t$$ = &ast.AggregateFuncExpr{F: ast.AggFuncVarPop, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)}\n\t\t}\n\t}\n|\tbuiltinVarSamp '(' BuggyDefaultFalseDistinctOpt Expression ')' OptWindowingClause\n\t{\n\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)}\n\t}\n|\tbuiltinMedian '(' BuggyDefaultFalseDistinctOpt Expression ')'\n\t{\n\t\t$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4}, Distinct: $3.(bool)}\n\t}\n\nOptGConcatSeparator:\n\t{\n\t\t$$ = ast.NewValueExpr(\",\")\n\t}\n|\t\"SEPARATOR\" stringLit\n\t{\n\t\t$$ = ast.NewValueExpr($2)\n\t}\n\nFunctionCallGeneric:\n\tidentifier '(' ExpressionListOpt ')'\n\t{\n\t\t$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}\n\t}\n\nFuncDatetimePrec:\n\t{\n\t\t$$ = nil\n\t}\n|\t'(' ')'\n\t{\n\t\t$$ = nil\n\t}\n|\t'(' intLit ')'\n\t{\n\t\texpr := ast.NewValueExpr($2)\n\t\t$$ = expr\n\t}\n\nTimeUnit:\n\tTimestampUnit\n\t{\n\t\t$$ = $1\n\t}\n|\t\"SECOND_MICROSECOND\"\n\t{\n\t\t$$ = ast.TimeUnitSecondMicrosecond\n\t}\n|\t\"MINUTE_MICROSECOND\"\n\t{\n\t\t$$ = ast.TimeUnitMinuteMicrosecond\n\t}\n|\t\"MINUTE_SECOND\"\n\t{\n\t\t$$ = ast.TimeUnitMinuteSecond\n\t}\n|\t\"HOUR_MICROSECOND\"\n\t{\n\t\t$$ = ast.TimeUnitHourMicrosecond\n\t}\n|\t\"HOUR_SECOND\"\n\t{\n\t\t$$ = ast.TimeUnitHourSecond\n\t}\n|\t\"HOUR_MINUTE\"\n\t{\n\t\t$$ = ast.TimeUnitHourMinute\n\t}\n|\t\"DAY_MICROSECOND\"\n\t{\n\t\t$$ = ast.TimeUnitDayMicrosecond\n\t}\n|\t\"DAY_SECOND\"\n\t{\n\t\t$$ = ast.TimeUnitDaySecond\n\t}\n|\t\"DAY_MINUTE\"\n\t{\n\t\t$$ = ast.TimeUnitDayMinute\n\t}\n|\t\"DAY_HOUR\"\n\t{\n\t\t$$ = ast.TimeUnitDayHour\n\t}\n|\t\"YEAR_MONTH\"\n\t{\n\t\t$$ = ast.TimeUnitYearMonth\n\t}\n\nTimestampUnit:\n\t\"MICROSECOND\"\n\t{\n\t\t$$ = ast.TimeUnitMicrosecond\n\t}\n|\t\"SECOND\"\n\t{\n\t\t$$ = ast.TimeUnitSecond\n\t}\n|\t\"MINUTE\"\n\t{\n\t\t$$ = ast.TimeUnitMinute\n\t}\n|\t\"HOUR\"\n\t{\n\t\t$$ = ast.TimeUnitHour\n\t}\n|\t\"DAY\"\n\t{\n\t\t$$ = ast.TimeUnitDay\n\t}\n|\t\"WEEK\"\n\t{\n\t\t$$ = ast.TimeUnitWeek\n\t}\n|\t\"MONTH\"\n\t{\n\t\t$$ = ast.TimeUnitMonth\n\t}\n|\t\"QUARTER\"\n\t{\n\t\t$$ = ast.TimeUnitQuarter\n\t}\n|\t\"YEAR\"\n\t{\n\t\t$$ = ast.TimeUnitYear\n\t}\n|\t\"SQL_TSI_SECOND\"\n\t{\n\t\t$$ = ast.TimeUnitSecond\n\t}\n|\t\"SQL_TSI_MINUTE\"\n\t{\n\t\t$$ = ast.TimeUnitMinute\n\t}\n|\t\"SQL_TSI_HOUR\"\n\t{\n\t\t$$ = ast.TimeUnitHour\n\t}\n|\t\"SQL_TSI_DAY\"\n\t{\n\t\t$$ = ast.TimeUnitDay\n\t}\n|\t\"SQL_TSI_WEEK\"\n\t{\n\t\t$$ = ast.TimeUnitWeek\n\t}\n|\t\"SQL_TSI_MONTH\"\n\t{\n\t\t$$ = ast.TimeUnitMonth\n\t}\n|\t\"SQL_TSI_QUARTER\"\n\t{\n\t\t$$ = ast.TimeUnitQuarter\n\t}\n|\t\"SQL_TSI_YEAR\"\n\t{\n\t\t$$ = ast.TimeUnitYear\n\t}\n\nExpressionOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\tExpression\n\t{\n\t\t$$ = $1\n\t}\n\nWhenClauseList:\n\tWhenClause\n\t{\n\t\t$$ = []*ast.WhenClause{$1.(*ast.WhenClause)}\n\t}\n|\tWhenClauseList WhenClause\n\t{\n\t\t$$ = append($1.([]*ast.WhenClause), $2.(*ast.WhenClause))\n\t}\n\nWhenClause:\n\t\"WHEN\" Expression \"THEN\" Expression\n\t{\n\t\t$$ = &ast.WhenClause{\n\t\t\tExpr:   $2,\n\t\t\tResult: $4,\n\t\t}\n\t}\n\nElseOpt:\n\t/* empty */\n\t{\n\t\t$$ = nil\n\t}\n|\t\"ELSE\" Expression\n\t{\n\t\t$$ = $2\n\t}\n\nCastType:\n\t\"BINARY\" OptFieldLen\n\t{\n\t\tx := types.NewFieldType(mysql.TypeVarString)\n\t\tx.Flen = $2.(int) // TODO: Flen should be the flen of expression\n\t\tif x.Flen != types.UnspecifiedLength {\n\t\t\tx.Tp = mysql.TypeString\n\t\t}\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\tx.Flag |= mysql.BinaryFlag\n\t\t$$ = x\n\t}\n|\t\"CHAR\" OptFieldLen OptBinary\n\t{\n\t\tx := types.NewFieldType(mysql.TypeVarString)\n\t\tx.Flen = $2.(int) // TODO: Flen should be the flen of expression\n\t\tx.Charset = $3.(*ast.OptBinary).Charset\n\t\tif $3.(*ast.OptBinary).IsBinary {\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t}\n\t\tif x.Charset == \"\" {\n\t\t\tx.Charset = mysql.DefaultCharset\n\t\t\tx.Collate = mysql.DefaultCollationName\n\t\t}\n\t\t$$ = x\n\t}\n|\t\"DATE\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeDate)\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\tx.Flag |= mysql.BinaryFlag\n\t\t$$ = x\n\t}\n|\t\"DATETIME\" OptFieldLen\n\t{\n\t\tx := types.NewFieldType(mysql.TypeDatetime)\n\t\tx.Flen, _ = mysql.GetDefaultFieldLengthAndDecimalForCast(mysql.TypeDatetime)\n\t\tx.Decimal = $2.(int)\n\t\tif x.Decimal > 0 {\n\t\t\tx.Flen = x.Flen + 1 + x.Decimal\n\t\t}\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\tx.Flag |= mysql.BinaryFlag\n\t\t$$ = x\n\t}\n|\t\"DECIMAL\" FloatOpt\n\t{\n\t\tfopt := $2.(*ast.FloatOpt)\n\t\tx := types.NewFieldType(mysql.TypeNewDecimal)\n\t\tx.Flen = fopt.Flen\n\t\tx.Decimal = fopt.Decimal\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\tx.Flag |= mysql.BinaryFlag\n\t\t$$ = x\n\t}\n|\t\"TIME\" OptFieldLen\n\t{\n\t\tx := types.NewFieldType(mysql.TypeDuration)\n\t\tx.Flen, _ = mysql.GetDefaultFieldLengthAndDecimalForCast(mysql.TypeDuration)\n\t\tx.Decimal = $2.(int)\n\t\tif x.Decimal > 0 {\n\t\t\tx.Flen = x.Flen + 1 + x.Decimal\n\t\t}\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\tx.Flag |= mysql.BinaryFlag\n\t\t$$ = x\n\t}\n|\t\"SIGNED\" OptInteger\n\t{\n\t\tx := types.NewFieldType(mysql.TypeLonglong)\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\tx.Flag |= mysql.BinaryFlag\n\t\t$$ = x\n\t}\n|\t\"UNSIGNED\" OptInteger\n\t{\n\t\tx := types.NewFieldType(mysql.TypeLonglong)\n\t\tx.Flag |= mysql.UnsignedFlag | mysql.BinaryFlag\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\t$$ = x\n\t}\n|\t\"JSON\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeJSON)\n\t\tx.Flag |= mysql.BinaryFlag | (mysql.ParseToJSONFlag)\n\t\tx.Charset = mysql.DefaultCharset\n\t\tx.Collate = mysql.DefaultCollationName\n\t\t$$ = x\n\t}\n|\t\"DOUBLE\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeDouble)\n\t\tx.Flen, x.Decimal = mysql.GetDefaultFieldLengthAndDecimalForCast(mysql.TypeDouble)\n\t\tx.Flag |= mysql.BinaryFlag\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\t$$ = x\n\t}\n|\t\"FLOAT\" FloatOpt\n\t{\n\t\tx := types.NewFieldType(mysql.TypeFloat)\n\t\tfopt := $2.(*ast.FloatOpt)\n\t\tif fopt.Flen >= 54 {\n\t\t\tyylex.AppendError(ErrTooBigPrecision.GenWithStackByArgs(fopt.Flen, \"CAST\", 53))\n\t\t} else if fopt.Flen >= 25 {\n\t\t\tx = types.NewFieldType(mysql.TypeDouble)\n\t\t}\n\t\tx.Flen, x.Decimal = mysql.GetDefaultFieldLengthAndDecimalForCast(x.Tp)\n\t\tx.Flag |= mysql.BinaryFlag\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\t$$ = x\n\t}\n|\t\"REAL\"\n\t{\n\t\tvar x *types.FieldType\n\t\tif parser.lexer.GetSQLMode().HasRealAsFloatMode() {\n\t\t\tx = types.NewFieldType(mysql.TypeFloat)\n\t\t} else {\n\t\t\tx = types.NewFieldType(mysql.TypeDouble)\n\t\t}\n\t\tx.Flen, x.Decimal = mysql.GetDefaultFieldLengthAndDecimalForCast(x.Tp)\n\t\tx.Flag |= mysql.BinaryFlag\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\t$$ = x\n\t}\n\nPriorityOpt:\n\t{\n\t\t$$ = mysql.NoPriority\n\t}\n|\t\"LOW_PRIORITY\"\n\t{\n\t\t$$ = mysql.LowPriority\n\t}\n|\t\"HIGH_PRIORITY\"\n\t{\n\t\t$$ = mysql.HighPriority\n\t}\n|\t\"DELAYED\"\n\t{\n\t\t$$ = mysql.DelayedPriority\n\t}\n\nTableName:\n\tIdentifier\n\t{\n\t\t$$ = &ast.TableName{Name: model.NewCIStr($1)}\n\t}\n|\tIdentifier '.' Identifier\n\t{\n\t\t$$ = &ast.TableName{Schema: model.NewCIStr($1), Name: model.NewCIStr($3)}\n\t}\n\nTableNameList:\n\tTableName\n\t{\n\t\ttbl := []*ast.TableName{$1.(*ast.TableName)}\n\t\t$$ = tbl\n\t}\n|\tTableNameList ',' TableName\n\t{\n\t\t$$ = append($1.([]*ast.TableName), $3.(*ast.TableName))\n\t}\n\nTableNameOptWild:\n\tIdentifier OptWild\n\t{\n\t\t$$ = &ast.TableName{Name: model.NewCIStr($1)}\n\t}\n|\tIdentifier '.' Identifier OptWild\n\t{\n\t\t$$ = &ast.TableName{Schema: model.NewCIStr($1), Name: model.NewCIStr($3)}\n\t}\n\nTableAliasRefList:\n\tTableNameOptWild\n\t{\n\t\ttbl := []*ast.TableName{$1.(*ast.TableName)}\n\t\t$$ = tbl\n\t}\n|\tTableAliasRefList ',' TableNameOptWild\n\t{\n\t\t$$ = append($1.([]*ast.TableName), $3.(*ast.TableName))\n\t}\n\nOptWild:\n\t%prec empty\n\t{}\n|\t'.' '*'\n\t{}\n\nQuickOptional:\n\t%prec empty\n\t{\n\t\t$$ = false\n\t}\n|\t\"QUICK\"\n\t{\n\t\t$$ = true\n\t}\n\n/***************************Prepared Statement Start******************************\n * See https://dev.mysql.com/doc/refman/5.7/en/prepare.html\n * Example:\n * PREPARE stmt_name FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';\n * OR\n * SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';\n * PREPARE stmt_name FROM @s;\n */\nPreparedStmt:\n\t\"PREPARE\" Identifier \"FROM\" PrepareSQL\n\t{\n\t\tvar sqlText string\n\t\tvar sqlVar *ast.VariableExpr\n\t\tswitch $4.(type) {\n\t\tcase string:\n\t\t\tsqlText = $4.(string)\n\t\tcase *ast.VariableExpr:\n\t\t\tsqlVar = $4.(*ast.VariableExpr)\n\t\t}\n\t\t$$ = &ast.PrepareStmt{\n\t\t\tName:    $2,\n\t\t\tSQLText: sqlText,\n\t\t\tSQLVar:  sqlVar,\n\t\t}\n\t}\n\nPrepareSQL:\n\tstringLit\n\t{\n\t\t$$ = $1\n\t}\n|\tUserVariable\n\t{\n\t\t$$ = $1.(interface{})\n\t}\n\n/*\n * See https://dev.mysql.com/doc/refman/5.7/en/execute.html\n * Example:\n * EXECUTE stmt1 USING @a, @b;\n * OR\n * EXECUTE stmt1;\n */\nExecuteStmt:\n\t\"EXECUTE\" Identifier\n\t{\n\t\t$$ = &ast.ExecuteStmt{Name: $2}\n\t}\n|\t\"EXECUTE\" Identifier \"USING\" UserVariableList\n\t{\n\t\t$$ = &ast.ExecuteStmt{\n\t\t\tName:      $2,\n\t\t\tUsingVars: $4.([]ast.ExprNode),\n\t\t}\n\t}\n\nUserVariableList:\n\tUserVariable\n\t{\n\t\t$$ = []ast.ExprNode{$1}\n\t}\n|\tUserVariableList ',' UserVariable\n\t{\n\t\t$$ = append($1.([]ast.ExprNode), $3)\n\t}\n\nDeallocateStmt:\n\tDeallocateSym \"PREPARE\" Identifier\n\t{\n\t\t$$ = &ast.DeallocateStmt{Name: $3}\n\t}\n\nDeallocateSym:\n\t\"DEALLOCATE\"\n|\t\"DROP\"\n\nRollbackStmt:\n\t\"ROLLBACK\"\n\t{\n\t\t$$ = &ast.RollbackStmt{}\n\t}\n\nShutdownStmt:\n\t\"SHUTDOWN\"\n\t{\n\t\t$$ = &ast.ShutdownStmt{}\n\t}\n\nSelectStmtBasic:\n\t\"SELECT\" SelectStmtOpts SelectStmtFieldList\n\t{\n\t\tst := &ast.SelectStmt{\n\t\t\tSelectStmtOpts: $2.(*ast.SelectStmtOpts),\n\t\t\tDistinct:       $2.(*ast.SelectStmtOpts).Distinct,\n\t\t\tFields:         $3.(*ast.FieldList),\n\t\t}\n\t\tif st.SelectStmtOpts.TableHints != nil {\n\t\t\tst.TableHints = st.SelectStmtOpts.TableHints\n\t\t}\n\t\t$$ = st\n\t}\n\nSelectStmtFromDualTable:\n\tSelectStmtBasic FromDual WhereClauseOptional\n\t{\n\t\tst := $1.(*ast.SelectStmt)\n\t\tlastField := st.Fields.Fields[len(st.Fields.Fields)-1]\n\t\tif lastField.Expr != nil && lastField.AsName.O == \"\" {\n\t\t\tlastEnd := yyS[yypt-1].offset - 1\n\t\t\tlastField.SetText(parser.src[lastField.Offset:lastEnd])\n\t\t}\n\t\tif $3 != nil {\n\t\t\tst.Where = $3.(ast.ExprNode)\n\t\t}\n\t}\n\nSelectStmtFromTable:\n\tSelectStmtBasic \"FROM\" TableRefsClause WhereClauseOptional SelectStmtGroup HavingClause WindowClauseOptional\n\t{\n\t\tst := $1.(*ast.SelectStmt)\n\t\tst.From = $3.(*ast.TableRefsClause)\n\t\tlastField := st.Fields.Fields[len(st.Fields.Fields)-1]\n\t\tif lastField.Expr != nil && lastField.AsName.O == \"\" {\n\t\t\tlastEnd := parser.endOffset(&yyS[yypt-5])\n\t\t\tlastField.SetText(parser.src[lastField.Offset:lastEnd])\n\t\t}\n\t\tif $4 != nil {\n\t\t\tst.Where = $4.(ast.ExprNode)\n\t\t}\n\t\tif $5 != nil {\n\t\t\tst.GroupBy = $5.(*ast.GroupByClause)\n\t\t}\n\t\tif $6 != nil {\n\t\t\tst.Having = $6.(*ast.HavingClause)\n\t\t}\n\t\tif $7 != nil {\n\t\t\tst.WindowSpecs = ($7.([]ast.WindowSpec))\n\t\t}\n\t\t$$ = st\n\t}\n\nSelectStmt:\n\tSelectStmtBasic OrderByOptional SelectStmtLimit SelectLockOpt SelectStmtIntoOption\n\t{\n\t\tst := $1.(*ast.SelectStmt)\n\t\tst.LockTp = $4.(ast.SelectLockType)\n\t\tlastField := st.Fields.Fields[len(st.Fields.Fields)-1]\n\t\tif lastField.Expr != nil && lastField.AsName.O == \"\" {\n\t\t\tsrc := parser.src\n\t\t\tvar lastEnd int\n\t\t\tif $2 != nil {\n\t\t\t\tlastEnd = yyS[yypt-3].offset - 1\n\t\t\t} else if $3 != nil {\n\t\t\t\tlastEnd = yyS[yypt-2].offset - 1\n\t\t\t} else if $4 != ast.SelectLockNone {\n\t\t\t\tlastEnd = yyS[yypt-1].offset - 1\n\t\t\t} else if $5 != nil {\n\t\t\t\tlastEnd = yyS[yypt].offset - 1\n\t\t\t} else {\n\t\t\t\tlastEnd = len(src)\n\t\t\t\tif src[lastEnd-1] == ';' {\n\t\t\t\t\tlastEnd--\n\t\t\t\t}\n\t\t\t}\n\t\t\tlastField.SetText(src[lastField.Offset:lastEnd])\n\t\t}\n\t\tif $2 != nil {\n\t\t\tst.OrderBy = $2.(*ast.OrderByClause)\n\t\t}\n\t\tif $3 != nil {\n\t\t\tst.Limit = $3.(*ast.Limit)\n\t\t}\n\t\tif $5 != nil {\n\t\t\tst.SelectIntoOpt = $5.(*ast.SelectIntoOption)\n\t\t}\n\t\t$$ = st\n\t}\n|\tSelectStmtFromDualTable OrderByOptional SelectStmtLimit SelectLockOpt SelectStmtIntoOption\n\t{\n\t\tst := $1.(*ast.SelectStmt)\n\t\tif $2 != nil {\n\t\t\tst.OrderBy = $2.(*ast.OrderByClause)\n\t\t}\n\t\tif $3 != nil {\n\t\t\tst.Limit = $3.(*ast.Limit)\n\t\t}\n\t\tst.LockTp = $4.(ast.SelectLockType)\n\t\tif $5 != nil {\n\t\t\tst.SelectIntoOpt = $5.(*ast.SelectIntoOption)\n\t\t}\n\t\t$$ = st\n\t}\n|\tSelectStmtFromTable OrderByOptional SelectStmtLimit SelectLockOpt SelectStmtIntoOption\n\t{\n\t\tst := $1.(*ast.SelectStmt)\n\t\tst.LockTp = $4.(ast.SelectLockType)\n\t\tif $2 != nil {\n\t\t\tst.OrderBy = $2.(*ast.OrderByClause)\n\t\t}\n\t\tif $3 != nil {\n\t\t\tst.Limit = $3.(*ast.Limit)\n\t\t}\n\t\tif $5 != nil {\n\t\t\tst.SelectIntoOpt = $5.(*ast.SelectIntoOption)\n\t\t}\n\t\t$$ = st\n\t}\n\nFromDual:\n\t\"FROM\" \"DUAL\"\n\nWindowClauseOptional:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"WINDOW\" WindowDefinitionList\n\t{\n\t\t$$ = $2.([]ast.WindowSpec)\n\t}\n\nWindowDefinitionList:\n\tWindowDefinition\n\t{\n\t\t$$ = []ast.WindowSpec{$1.(ast.WindowSpec)}\n\t}\n|\tWindowDefinitionList ',' WindowDefinition\n\t{\n\t\t$$ = append($1.([]ast.WindowSpec), $3.(ast.WindowSpec))\n\t}\n\nWindowDefinition:\n\tWindowName \"AS\" WindowSpec\n\t{\n\t\tvar spec = $3.(ast.WindowSpec)\n\t\tspec.Name = $1.(model.CIStr)\n\t\t$$ = spec\n\t}\n\nWindowName:\n\tIdentifier\n\t{\n\t\t$$ = model.NewCIStr($1)\n\t}\n\nWindowSpec:\n\t'(' WindowSpecDetails ')'\n\t{\n\t\t$$ = $2.(ast.WindowSpec)\n\t}\n\nWindowSpecDetails:\n\tOptExistingWindowName OptPartitionClause OptWindowOrderByClause OptWindowFrameClause\n\t{\n\t\tspec := ast.WindowSpec{Ref: $1.(model.CIStr)}\n\t\tif $2 != nil {\n\t\t\tspec.PartitionBy = $2.(*ast.PartitionByClause)\n\t\t}\n\t\tif $3 != nil {\n\t\t\tspec.OrderBy = $3.(*ast.OrderByClause)\n\t\t}\n\t\tif $4 != nil {\n\t\t\tspec.Frame = $4.(*ast.FrameClause)\n\t\t}\n\t\t$$ = spec\n\t}\n\nOptExistingWindowName:\n\t{\n\t\t$$ = model.CIStr{}\n\t}\n|\tWindowName\n\t{\n\t\t$$ = $1.(model.CIStr)\n\t}\n\nOptPartitionClause:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"PARTITION\" \"BY\" ByList\n\t{\n\t\t$$ = &ast.PartitionByClause{Items: $3.([]*ast.ByItem)}\n\t}\n\nOptWindowOrderByClause:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"ORDER\" \"BY\" ByList\n\t{\n\t\t$$ = &ast.OrderByClause{Items: $3.([]*ast.ByItem)}\n\t}\n\nOptWindowFrameClause:\n\t{\n\t\t$$ = nil\n\t}\n|\tWindowFrameUnits WindowFrameExtent\n\t{\n\t\t$$ = &ast.FrameClause{\n\t\t\tType:   $1.(ast.FrameType),\n\t\t\tExtent: $2.(ast.FrameExtent),\n\t\t}\n\t}\n\nWindowFrameUnits:\n\t\"ROWS\"\n\t{\n\t\t$$ = ast.FrameType(ast.Rows)\n\t}\n|\t\"RANGE\"\n\t{\n\t\t$$ = ast.FrameType(ast.Ranges)\n\t}\n|\t\"GROUPS\"\n\t{\n\t\t$$ = ast.FrameType(ast.Groups)\n\t}\n\nWindowFrameExtent:\n\tWindowFrameStart\n\t{\n\t\t$$ = ast.FrameExtent{\n\t\t\tStart: $1.(ast.FrameBound),\n\t\t\tEnd:   ast.FrameBound{Type: ast.CurrentRow},\n\t\t}\n\t}\n|\tWindowFrameBetween\n\t{\n\t\t$$ = $1.(ast.FrameExtent)\n\t}\n\nWindowFrameStart:\n\t\"UNBOUNDED\" \"PRECEDING\"\n\t{\n\t\t$$ = ast.FrameBound{Type: ast.Preceding, UnBounded: true}\n\t}\n|\tNumLiteral \"PRECEDING\"\n\t{\n\t\t$$ = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr($1)}\n\t}\n|\tParamMarker \"PRECEDING\"\n\t{\n\t\t$$ = ast.FrameBound{Type: ast.Preceding, Expr: $1}\n\t}\n|\t\"INTERVAL\" Expression TimeUnit \"PRECEDING\"\n\t{\n\t\t$$ = ast.FrameBound{Type: ast.Preceding, Expr: $2, Unit: $3.(ast.TimeUnitType)}\n\t}\n|\t\"CURRENT\" \"ROW\"\n\t{\n\t\t$$ = ast.FrameBound{Type: ast.CurrentRow}\n\t}\n\nWindowFrameBetween:\n\t\"BETWEEN\" WindowFrameBound \"AND\" WindowFrameBound\n\t{\n\t\t$$ = ast.FrameExtent{Start: $2.(ast.FrameBound), End: $4.(ast.FrameBound)}\n\t}\n\nWindowFrameBound:\n\tWindowFrameStart\n\t{\n\t\t$$ = $1.(ast.FrameBound)\n\t}\n|\t\"UNBOUNDED\" \"FOLLOWING\"\n\t{\n\t\t$$ = ast.FrameBound{Type: ast.Following, UnBounded: true}\n\t}\n|\tNumLiteral \"FOLLOWING\"\n\t{\n\t\t$$ = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr($1)}\n\t}\n|\tParamMarker \"FOLLOWING\"\n\t{\n\t\t$$ = ast.FrameBound{Type: ast.Following, Expr: $1}\n\t}\n|\t\"INTERVAL\" Expression TimeUnit \"FOLLOWING\"\n\t{\n\t\t$$ = ast.FrameBound{Type: ast.Following, Expr: $2, Unit: $3.(ast.TimeUnitType)}\n\t}\n\nOptWindowingClause:\n\t{\n\t\t$$ = nil\n\t}\n|\tWindowingClause\n\t{\n\t\tspec := $1.(ast.WindowSpec)\n\t\t$$ = &spec\n\t}\n\nWindowingClause:\n\t\"OVER\" WindowNameOrSpec\n\t{\n\t\t$$ = $2.(ast.WindowSpec)\n\t}\n\nWindowNameOrSpec:\n\tWindowName\n\t{\n\t\t$$ = ast.WindowSpec{Name: $1.(model.CIStr), OnlyAlias: true}\n\t}\n|\tWindowSpec\n\t{\n\t\t$$ = $1.(ast.WindowSpec)\n\t}\n\nWindowFuncCall:\n\t\"ROW_NUMBER\" '(' ')' WindowingClause\n\t{\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Spec: $4.(ast.WindowSpec)}\n\t}\n|\t\"RANK\" '(' ')' WindowingClause\n\t{\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Spec: $4.(ast.WindowSpec)}\n\t}\n|\t\"DENSE_RANK\" '(' ')' WindowingClause\n\t{\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Spec: $4.(ast.WindowSpec)}\n\t}\n|\t\"CUME_DIST\" '(' ')' WindowingClause\n\t{\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Spec: $4.(ast.WindowSpec)}\n\t}\n|\t\"PERCENT_RANK\" '(' ')' WindowingClause\n\t{\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Spec: $4.(ast.WindowSpec)}\n\t}\n|\t\"NTILE\" '(' SimpleExpr ')' WindowingClause\n\t{\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, Spec: $5.(ast.WindowSpec)}\n\t}\n|\t\"LEAD\" '(' Expression OptLeadLagInfo ')' OptNullTreatment WindowingClause\n\t{\n\t\targs := []ast.ExprNode{$3}\n\t\tif $4 != nil {\n\t\t\targs = append(args, $4.([]ast.ExprNode)...)\n\t\t}\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: args, IgnoreNull: $6.(bool), Spec: $7.(ast.WindowSpec)}\n\t}\n|\t\"LAG\" '(' Expression OptLeadLagInfo ')' OptNullTreatment WindowingClause\n\t{\n\t\targs := []ast.ExprNode{$3}\n\t\tif $4 != nil {\n\t\t\targs = append(args, $4.([]ast.ExprNode)...)\n\t\t}\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: args, IgnoreNull: $6.(bool), Spec: $7.(ast.WindowSpec)}\n\t}\n|\t\"FIRST_VALUE\" '(' Expression ')' OptNullTreatment WindowingClause\n\t{\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, IgnoreNull: $5.(bool), Spec: $6.(ast.WindowSpec)}\n\t}\n|\t\"LAST_VALUE\" '(' Expression ')' OptNullTreatment WindowingClause\n\t{\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3}, IgnoreNull: $5.(bool), Spec: $6.(ast.WindowSpec)}\n\t}\n|\t\"NTH_VALUE\" '(' Expression ',' SimpleExpr ')' OptFromFirstLast OptNullTreatment WindowingClause\n\t{\n\t\t$$ = &ast.WindowFuncExpr{F: $1, Args: []ast.ExprNode{$3, $5}, FromLast: $7.(bool), IgnoreNull: $8.(bool), Spec: $9.(ast.WindowSpec)}\n\t}\n\nOptLeadLagInfo:\n\t{\n\t\t$$ = nil\n\t}\n|\t',' NumLiteral OptLLDefault\n\t{\n\t\targs := []ast.ExprNode{ast.NewValueExpr($2)}\n\t\tif $3 != nil {\n\t\t\targs = append(args, $3.(ast.ExprNode))\n\t\t}\n\t\t$$ = args\n\t}\n|\t',' ParamMarker OptLLDefault\n\t{\n\t\targs := []ast.ExprNode{ast.NewValueExpr($2)}\n\t\tif $3 != nil {\n\t\t\targs = append(args, $3.(ast.ExprNode))\n\t\t}\n\t\t$$ = args\n\t}\n\nOptLLDefault:\n\t{\n\t\t$$ = nil\n\t}\n|\t',' Expression\n\t{\n\t\t$$ = $2\n\t}\n\nOptNullTreatment:\n\t{\n\t\t$$ = false\n\t}\n|\t\"RESPECT\" \"NULLS\"\n\t{\n\t\t$$ = false\n\t}\n|\t\"IGNORE\" \"NULLS\"\n\t{\n\t\t$$ = true\n\t}\n\nOptFromFirstLast:\n\t{\n\t\t$$ = false\n\t}\n|\t\"FROM\" \"FIRST\"\n\t{\n\t\t$$ = false\n\t}\n|\t\"FROM\" \"LAST\"\n\t{\n\t\t$$ = true\n\t}\n\nTableRefsClause:\n\tTableRefs\n\t{\n\t\t$$ = &ast.TableRefsClause{TableRefs: $1.(*ast.Join)}\n\t}\n\nTableRefs:\n\tEscapedTableRef\n\t{\n\t\tif j, ok := $1.(*ast.Join); ok {\n\t\t\t// if $1 is Join, use it directly\n\t\t\t$$ = j\n\t\t} else {\n\t\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: nil}\n\t\t}\n\t}\n|\tTableRefs ',' EscapedTableRef\n\t{\n\t\t/* from a, b is default cross join */\n\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin}\n\t}\n\nEscapedTableRef:\n\tTableRef %prec lowerThanSetKeyword\n\t{\n\t\t$$ = $1\n\t}\n|\t'{' Identifier TableRef '}'\n\t{\n\t\t/*\n\t\t * ODBC escape syntax for outer join is { OJ join_table }\n\t\t * Use an Identifier for OJ\n\t\t */\n\t\t$$ = $3\n\t}\n\nTableRef:\n\tTableFactor\n\t{\n\t\t$$ = $1\n\t}\n|\tJoinTable\n\t{\n\t\t$$ = $1\n\t}\n\nTableFactor:\n\tTableName PartitionNameListOpt TableAsNameOpt IndexHintListOpt\n\t{\n\t\ttn := $1.(*ast.TableName)\n\t\ttn.PartitionNames = $2.([]model.CIStr)\n\t\ttn.IndexHints = $4.([]*ast.IndexHint)\n\t\t$$ = &ast.TableSource{Source: tn, AsName: $3.(model.CIStr)}\n\t}\n|\t'(' SelectStmt ')' TableAsName\n\t{\n\t\tst := $2.(*ast.SelectStmt)\n\t\tendOffset := parser.endOffset(&yyS[yypt-1])\n\t\tparser.setLastSelectFieldText(st, endOffset)\n\t\t$$ = &ast.TableSource{Source: $2.(*ast.SelectStmt), AsName: $4.(model.CIStr)}\n\t}\n|\t'(' UnionStmt ')' TableAsName\n\t{\n\t\t$$ = &ast.TableSource{Source: $2.(*ast.UnionStmt), AsName: $4.(model.CIStr)}\n\t}\n|\t'(' TableRefs ')'\n\t{\n\t\t$$ = $2\n\t}\n\nPartitionNameListOpt:\n\t/* empty */\n\t{\n\t\t$$ = []model.CIStr{}\n\t}\n|\t\"PARTITION\" '(' PartitionNameList ')'\n\t{\n\t\t$$ = $3\n\t}\n\nTableAsNameOpt:\n\t{\n\t\t$$ = model.CIStr{}\n\t}\n|\tTableAsName\n\t{\n\t\t$$ = $1\n\t}\n\nTableAsName:\n\tIdentifier\n\t{\n\t\t$$ = model.NewCIStr($1)\n\t}\n|\t\"AS\" Identifier\n\t{\n\t\t$$ = model.NewCIStr($2)\n\t}\n\nIndexHintType:\n\t\"USE\" KeyOrIndex\n\t{\n\t\t$$ = ast.HintUse\n\t}\n|\t\"IGNORE\" KeyOrIndex\n\t{\n\t\t$$ = ast.HintIgnore\n\t}\n|\t\"FORCE\" KeyOrIndex\n\t{\n\t\t$$ = ast.HintForce\n\t}\n\nIndexHintScope:\n\t{\n\t\t$$ = ast.HintForScan\n\t}\n|\t\"FOR\" \"JOIN\"\n\t{\n\t\t$$ = ast.HintForJoin\n\t}\n|\t\"FOR\" \"ORDER\" \"BY\"\n\t{\n\t\t$$ = ast.HintForOrderBy\n\t}\n|\t\"FOR\" \"GROUP\" \"BY\"\n\t{\n\t\t$$ = ast.HintForGroupBy\n\t}\n\nIndexHint:\n\tIndexHintType IndexHintScope '(' IndexNameList ')'\n\t{\n\t\t$$ = &ast.IndexHint{\n\t\t\tIndexNames: $4.([]model.CIStr),\n\t\t\tHintType:   $1.(ast.IndexHintType),\n\t\t\tHintScope:  $2.(ast.IndexHintScope),\n\t\t}\n\t}\n\nIndexNameList:\n\t{\n\t\tvar nameList []model.CIStr\n\t\t$$ = nameList\n\t}\n|\tIdentifier\n\t{\n\t\t$$ = []model.CIStr{model.NewCIStr($1)}\n\t}\n|\tIndexNameList ',' Identifier\n\t{\n\t\t$$ = append($1.([]model.CIStr), model.NewCIStr($3))\n\t}\n|\t\"PRIMARY\"\n\t{\n\t\t$$ = []model.CIStr{model.NewCIStr($1)}\n\t}\n|\tIndexNameList ',' \"PRIMARY\"\n\t{\n\t\t$$ = append($1.([]model.CIStr), model.NewCIStr($3))\n\t}\n\nIndexHintList:\n\tIndexHint\n\t{\n\t\t$$ = []*ast.IndexHint{$1.(*ast.IndexHint)}\n\t}\n|\tIndexHintList IndexHint\n\t{\n\t\t$$ = append($1.([]*ast.IndexHint), $2.(*ast.IndexHint))\n\t}\n\nIndexHintListOpt:\n\t{\n\t\tvar hintList []*ast.IndexHint\n\t\t$$ = hintList\n\t}\n|\tIndexHintList\n\t{\n\t\t$$ = $1\n\t}\n\nJoinTable:\n\t/* Use %prec to evaluate production TableRef before cross join */\n\tTableRef CrossOpt TableRef %prec tableRefPriority\n\t{\n\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin}\n\t}\n|\tTableRef CrossOpt TableRef \"ON\" Expression\n\t{\n\t\ton := &ast.OnCondition{Expr: $5}\n\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin, On: on}\n\t}\n|\tTableRef CrossOpt TableRef \"USING\" '(' ColumnNameList ')'\n\t{\n\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin, Using: $6.([]*ast.ColumnName)}\n\t}\n|\tTableRef JoinType OuterOpt \"JOIN\" TableRef \"ON\" Expression\n\t{\n\t\ton := &ast.OnCondition{Expr: $7}\n\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $5.(ast.ResultSetNode), Tp: $2.(ast.JoinType), On: on}\n\t}\n|\tTableRef JoinType OuterOpt \"JOIN\" TableRef \"USING\" '(' ColumnNameList ')'\n\t{\n\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $5.(ast.ResultSetNode), Tp: $2.(ast.JoinType), Using: $8.([]*ast.ColumnName)}\n\t}\n|\tTableRef \"NATURAL\" \"JOIN\" TableRef\n\t{\n\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $4.(ast.ResultSetNode), NaturalJoin: true}\n\t}\n|\tTableRef \"NATURAL\" JoinType OuterOpt \"JOIN\" TableRef\n\t{\n\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $6.(ast.ResultSetNode), Tp: $3.(ast.JoinType), NaturalJoin: true}\n\t}\n|\tTableRef \"STRAIGHT_JOIN\" TableRef\n\t{\n\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), StraightJoin: true}\n\t}\n|\tTableRef \"STRAIGHT_JOIN\" TableRef \"ON\" Expression\n\t{\n\t\ton := &ast.OnCondition{Expr: $5}\n\t\t$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), StraightJoin: true, On: on}\n\t}\n\nJoinType:\n\t\"LEFT\"\n\t{\n\t\t$$ = ast.LeftJoin\n\t}\n|\t\"RIGHT\"\n\t{\n\t\t$$ = ast.RightJoin\n\t}\n\nOuterOpt:\n\t{}\n|\t\"OUTER\"\n\nCrossOpt:\n\t\"JOIN\"\n|\t\"CROSS\" \"JOIN\"\n|\t\"INNER\" \"JOIN\"\n\nLimitClause:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"LIMIT\" LimitOption\n\t{\n\t\t$$ = &ast.Limit{Count: $2.(ast.ValueExpr)}\n\t}\n\nLimitOption:\n\tLengthNum\n\t{\n\t\t$$ = ast.NewValueExpr($1)\n\t}\n|\tParamMarker\n\t{\n\t\t$$ = $1\n\t}\n\nSelectStmtLimit:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"LIMIT\" LimitOption\n\t{\n\t\t$$ = &ast.Limit{Count: $2.(ast.ExprNode)}\n\t}\n|\t\"LIMIT\" LimitOption ',' LimitOption\n\t{\n\t\t$$ = &ast.Limit{Offset: $2.(ast.ExprNode), Count: $4.(ast.ExprNode)}\n\t}\n|\t\"LIMIT\" LimitOption \"OFFSET\" LimitOption\n\t{\n\t\t$$ = &ast.Limit{Offset: $4.(ast.ExprNode), Count: $2.(ast.ExprNode)}\n\t}\n\nSelectStmtOpts:\n\tTableOptimizerHints DefaultFalseDistinctOpt PriorityOpt SelectStmtSQLSmallResult SelectStmtSQLBigResult SelectStmtSQLBufferResult SelectStmtSQLCache SelectStmtCalcFoundRows SelectStmtStraightJoin\n\t{\n\t\topt := &ast.SelectStmtOpts{}\n\t\tif $1 != nil {\n\t\t\topt.TableHints = $1.([]*ast.TableOptimizerHint)\n\t\t}\n\t\tif $2 != nil {\n\t\t\topt.Distinct = $2.(bool)\n\t\t}\n\t\tif $3 != nil {\n\t\t\topt.Priority = $3.(mysql.PriorityEnum)\n\t\t}\n\t\tif $4 != nil {\n\t\t\topt.SQLSmallResult = $4.(bool)\n\t\t}\n\t\tif $5 != nil {\n\t\t\topt.SQLBigResult = $5.(bool)\n\t\t}\n\t\tif $6 != nil {\n\t\t\topt.SQLBufferResult = $6.(bool)\n\t\t}\n\t\tif $7 != nil {\n\t\t\topt.SQLCache = $7.(bool)\n\t\t}\n\t\tif $8 != nil {\n\t\t\topt.CalcFoundRows = $8.(bool)\n\t\t}\n\t\tif $9 != nil {\n\t\t\topt.StraightJoin = $9.(bool)\n\t\t}\n\n\t\t$$ = opt\n\t}\n\nTableOptimizerHints:\n\t/* empty */\n\t{\n\t\t$$ = nil\n\t}\n|\thintComment\n\t{\n\t\thints, warns := parser.parseHint($1)\n\t\tfor _, w := range warns {\n\t\t\tyylex.AppendError(w)\n\t\t\tparser.lastErrorAsWarn()\n\t\t}\n\t\t$$ = hints\n\t}\n\nSelectStmtCalcFoundRows:\n\t{\n\t\t$$ = false\n\t}\n|\t\"SQL_CALC_FOUND_ROWS\"\n\t{\n\t\t$$ = true\n\t}\n\nSelectStmtSQLBigResult:\n\t%prec empty\n\t{\n\t\t$$ = false\n\t}\n|\t\"SQL_BIG_RESULT\"\n\t{\n\t\t$$ = true\n\t}\n\nSelectStmtSQLBufferResult:\n\t%prec empty\n\t{\n\t\t$$ = false\n\t}\n|\t\"SQL_BUFFER_RESULT\"\n\t{\n\t\t$$ = true\n\t}\n\nSelectStmtSQLCache:\n\t%prec empty\n\t{\n\t\t$$ = true\n\t}\n|\t\"SQL_CACHE\"\n\t{\n\t\t$$ = true\n\t}\n|\t\"SQL_NO_CACHE\"\n\t{\n\t\t$$ = false\n\t}\n\nSelectStmtSQLSmallResult:\n\t%prec empty\n\t{\n\t\t$$ = false\n\t}\n|\t\"SQL_SMALL_RESULT\"\n\t{\n\t\t$$ = true\n\t}\n\nSelectStmtStraightJoin:\n\t%prec empty\n\t{\n\t\t$$ = false\n\t}\n|\t\"STRAIGHT_JOIN\"\n\t{\n\t\t$$ = true\n\t}\n\nSelectStmtFieldList:\n\tFieldList\n\t{\n\t\t$$ = &ast.FieldList{Fields: $1.([]*ast.SelectField)}\n\t}\n\nSelectStmtGroup:\n\t/* EMPTY */\n\t{\n\t\t$$ = nil\n\t}\n|\tGroupByClause\n\nSelectStmtIntoOption:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"INTO\" \"OUTFILE\" stringLit Fields Lines\n\t{\n\t\tpartyFiles := []*ast.PartyFile{}\n\t\tpartyFile := &ast.PartyFile{\n\t\t\tFileName: $3,\n\t\t}\n\t\tx := &ast.SelectIntoOption{\n\t\t\tTp:         ast.SelectIntoOutfile,\n\t\t\tPartyFiles: append(partyFiles, partyFile),\n\t\t}\n\t\tif $4 != nil {\n\t\t\tx.FieldsInfo = $4.(*ast.FieldsClause)\n\t\t}\n\t\tif $5 != nil {\n\t\t\tx.LinesInfo = $5.(*ast.LinesClause)\n\t\t}\n\n\t\t$$ = x\n\t}\n|\t\"INTO\" \"OUTFILE\" PartyFileList Fields Lines\n\t{\n\t\tx := &ast.SelectIntoOption{\n\t\t\tTp:         ast.SelectIntoOutfile,\n\t\t\tPartyFiles: $3.([]*ast.PartyFile),\n\t\t}\n\t\tif $4 != nil {\n\t\t\tx.FieldsInfo = $4.(*ast.FieldsClause)\n\t\t}\n\t\tif $5 != nil {\n\t\t\tx.LinesInfo = $5.(*ast.LinesClause)\n\t\t}\n\n\t\t$$ = x\n\t}\n\nPartySelectFieldList:\n\t/* Empty */\n\t{\n\t\t$$ = []*ast.SelectField{}\n\t}\n|\t'(' FieldList ')'\n\t{\n\t\t$$ = $2.([]*ast.SelectField)\n\t}\n\nPartyFile:\n\t\"PARTY_CODE\" stringLit stringLit PartySelectFieldList\n\t{\n\t\t$$ = &ast.PartyFile{\n\t\t\tPartyCode: $2,\n\t\t\tFileName:  $3,\n\t\t\tFieldList: $4.([]*ast.SelectField),\n\t\t}\n\t}\n\nPartyFileList:\n\tPartyFile\n\t{\n\t\t$$ = []*ast.PartyFile{$1.(*ast.PartyFile)}\n\t}\n|\tPartyFileList PartyFile\n\t{\n\t\t$$ = append($1.([]*ast.PartyFile), $2.(*ast.PartyFile))\n\t}\n\n// See https://dev.mysql.com/doc/refman/5.7/en/subqueries.html\nSubSelect:\n\t'(' SelectStmt ')'\n\t{\n\t\ts := $2.(*ast.SelectStmt)\n\t\tendOffset := parser.endOffset(&yyS[yypt])\n\t\tparser.setLastSelectFieldText(s, endOffset)\n\t\tsrc := parser.src\n\t\t// See the implementation of yyParse function\n\t\ts.SetText(src[yyS[yypt-1].offset:yyS[yypt].offset])\n\t\t$$ = &ast.SubqueryExpr{Query: s}\n\t}\n|\t'(' UnionStmt ')'\n\t{\n\t\ts := $2.(*ast.UnionStmt)\n\t\tsrc := parser.src\n\t\t// See the implementation of yyParse function\n\t\ts.SetText(src[yyS[yypt-1].offset:yyS[yypt].offset])\n\t\t$$ = &ast.SubqueryExpr{Query: s}\n\t}\n\n// See https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html\nSelectLockOpt:\n\t/* empty */\n\t{\n\t\t$$ = ast.SelectLockNone\n\t}\n|\t\"FOR\" \"UPDATE\"\n\t{\n\t\t$$ = ast.SelectLockForUpdate\n\t}\n|\t\"FOR\" \"UPDATE\" \"NOWAIT\"\n\t{\n\t\t$$ = ast.SelectLockForUpdateNoWait\n\t}\n|\t\"LOCK\" \"IN\" \"SHARE\" \"MODE\"\n\t{\n\t\t$$ = ast.SelectLockInShareMode\n\t}\n\n// See https://dev.mysql.com/doc/refman/5.7/en/union.html\nUnionStmt:\n\tUnionClauseList \"UNION\" UnionOpt SelectStmtBasic OrderByOptional SelectStmtLimit SelectLockOpt\n\t{\n\t\tst := $4.(*ast.SelectStmt)\n\t\tunion := $1.(*ast.UnionStmt)\n\t\tst.IsAfterUnionDistinct = $3.(bool)\n\t\tlastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]\n\t\tendOffset := parser.endOffset(&yyS[yypt-5])\n\t\tparser.setLastSelectFieldText(lastSelect, endOffset)\n\t\tunion.SelectList.Selects = append(union.SelectList.Selects, st)\n\t\tif $5 != nil {\n\t\t\tunion.OrderBy = $5.(*ast.OrderByClause)\n\t\t}\n\t\tif $6 != nil {\n\t\t\tunion.Limit = $6.(*ast.Limit)\n\t\t}\n\t\tif $5 == nil && $6 == nil {\n\t\t\tst.LockTp = $7.(ast.SelectLockType)\n\t\t}\n\t\t$$ = union\n\t}\n|\tUnionClauseList \"UNION\" UnionOpt SelectStmtFromDualTable OrderByOptional SelectStmtLimit SelectLockOpt\n\t{\n\t\tst := $4.(*ast.SelectStmt)\n\t\tunion := $1.(*ast.UnionStmt)\n\t\tst.IsAfterUnionDistinct = $3.(bool)\n\t\tlastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]\n\t\tendOffset := parser.endOffset(&yyS[yypt-5])\n\t\tparser.setLastSelectFieldText(lastSelect, endOffset)\n\t\tunion.SelectList.Selects = append(union.SelectList.Selects, st)\n\t\tif $5 != nil {\n\t\t\tunion.OrderBy = $5.(*ast.OrderByClause)\n\t\t}\n\t\tif $6 != nil {\n\t\t\tunion.Limit = $6.(*ast.Limit)\n\t\t}\n\t\tif $5 == nil && $6 == nil {\n\t\t\tst.LockTp = $7.(ast.SelectLockType)\n\t\t}\n\t\t$$ = union\n\t}\n|\tUnionClauseList \"UNION\" UnionOpt SelectStmtFromTable OrderByOptional SelectStmtLimit SelectLockOpt\n\t{\n\t\tst := $4.(*ast.SelectStmt)\n\t\tunion := $1.(*ast.UnionStmt)\n\t\tst.IsAfterUnionDistinct = $3.(bool)\n\t\tlastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]\n\t\tendOffset := parser.endOffset(&yyS[yypt-5])\n\t\tparser.setLastSelectFieldText(lastSelect, endOffset)\n\t\tunion.SelectList.Selects = append(union.SelectList.Selects, st)\n\t\tif $5 != nil {\n\t\t\tunion.OrderBy = $5.(*ast.OrderByClause)\n\t\t}\n\t\tif $6 != nil {\n\t\t\tunion.Limit = $6.(*ast.Limit)\n\t\t}\n\t\tif $5 == nil && $6 == nil {\n\t\t\tst.LockTp = $7.(ast.SelectLockType)\n\t\t}\n\t\t$$ = union\n\t}\n|\tUnionClauseList \"UNION\" UnionOpt '(' SelectStmt ')' OrderByOptional SelectStmtLimit\n\t{\n\t\tunion := $1.(*ast.UnionStmt)\n\t\tlastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]\n\t\tendOffset := parser.endOffset(&yyS[yypt-6])\n\t\tparser.setLastSelectFieldText(lastSelect, endOffset)\n\t\tst := $5.(*ast.SelectStmt)\n\t\tst.IsInBraces = true\n\t\tst.IsAfterUnionDistinct = $3.(bool)\n\t\tendOffset = parser.endOffset(&yyS[yypt-2])\n\t\tparser.setLastSelectFieldText(st, endOffset)\n\t\tunion.SelectList.Selects = append(union.SelectList.Selects, st)\n\t\tif $7 != nil {\n\t\t\tunion.OrderBy = $7.(*ast.OrderByClause)\n\t\t}\n\t\tif $8 != nil {\n\t\t\tunion.Limit = $8.(*ast.Limit)\n\t\t}\n\t\t$$ = union\n\t}\n\nUnionClauseList:\n\tUnionSelect\n\t{\n\t\tselectList := &ast.UnionSelectList{Selects: []*ast.SelectStmt{$1.(*ast.SelectStmt)}}\n\t\t$$ = &ast.UnionStmt{\n\t\t\tSelectList: selectList,\n\t\t}\n\t}\n|\tUnionClauseList \"UNION\" UnionOpt UnionSelect\n\t{\n\t\tunion := $1.(*ast.UnionStmt)\n\t\tst := $4.(*ast.SelectStmt)\n\t\tst.IsAfterUnionDistinct = $3.(bool)\n\t\tlastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]\n\t\tendOffset := parser.endOffset(&yyS[yypt-2])\n\t\tparser.setLastSelectFieldText(lastSelect, endOffset)\n\t\tunion.SelectList.Selects = append(union.SelectList.Selects, st)\n\t\t$$ = union\n\t}\n\nUnionSelect:\n\tSelectStmt\n\t{\n\t\t$$ = $1.(interface{})\n\t}\n|\t'(' SelectStmt ')'\n\t{\n\t\tst := $2.(*ast.SelectStmt)\n\t\tst.IsInBraces = true\n\t\tendOffset := parser.endOffset(&yyS[yypt])\n\t\tparser.setLastSelectFieldText(st, endOffset)\n\t\t$$ = $2\n\t}\n\nUnionOpt:\n\tDefaultTrueDistinctOpt\n\n/********************Change Statement*******************************/\nChangeStmt:\n\t\"CHANGE\" \"PUMP\" \"TO\" \"NODE_STATE\" eq stringLit forKwd \"NODE_ID\" stringLit\n\t{\n\t\t$$ = &ast.ChangeStmt{\n\t\t\tNodeType: ast.PumpType,\n\t\t\tState:    $6,\n\t\t\tNodeID:   $9,\n\t\t}\n\t}\n|\t\"CHANGE\" \"DRAINER\" \"TO\" \"NODE_STATE\" eq stringLit forKwd \"NODE_ID\" stringLit\n\t{\n\t\t$$ = &ast.ChangeStmt{\n\t\t\tNodeType: ast.DrainerType,\n\t\t\tState:    $6,\n\t\t\tNodeID:   $9,\n\t\t}\n\t}\n\n/********************Set Statement*******************************/\nSetStmt:\n\t\"SET\" VariableAssignmentList\n\t{\n\t\t$$ = &ast.SetStmt{Variables: $2.([]*ast.VariableAssignment)}\n\t}\n|\t\"SET\" \"PASSWORD\" eq PasswordOpt\n\t{\n\t\t$$ = &ast.SetPwdStmt{Password: $4.(string)}\n\t}\n|\t\"SET\" \"PASSWORD\" \"FOR\" Username eq PasswordOpt\n\t{\n\t\t$$ = &ast.SetPwdStmt{User: $4.(*auth.UserIdentity), Password: $6.(string)}\n\t}\n|\t\"SET\" \"GLOBAL\" \"TRANSACTION\" TransactionChars\n\t{\n\t\tvars := $4.([]*ast.VariableAssignment)\n\t\tfor _, v := range vars {\n\t\t\tv.IsGlobal = true\n\t\t}\n\t\t$$ = &ast.SetStmt{Variables: vars}\n\t}\n|\t\"SET\" \"SESSION\" \"TRANSACTION\" TransactionChars\n\t{\n\t\t$$ = &ast.SetStmt{Variables: $4.([]*ast.VariableAssignment)}\n\t}\n|\t\"SET\" \"TRANSACTION\" TransactionChars\n\t{\n\t\tassigns := $3.([]*ast.VariableAssignment)\n\t\tfor i := 0; i < len(assigns); i++ {\n\t\t\tif assigns[i].Name == \"tx_isolation\" {\n\t\t\t\t// A special session variable that make setting tx_isolation take effect one time.\n\t\t\t\tassigns[i].Name = \"tx_isolation_one_shot\"\n\t\t\t}\n\t\t}\n\t\t$$ = &ast.SetStmt{Variables: assigns}\n\t}\n\nSetRoleStmt:\n\t\"SET\" \"ROLE\" SetRoleOpt\n\t{\n\t\t$$ = $3.(*ast.SetRoleStmt)\n\t}\n\nSetDefaultRoleStmt:\n\t\"SET\" \"DEFAULT\" \"ROLE\" SetDefaultRoleOpt \"TO\" UsernameList\n\t{\n\t\ttmp := $4.(*ast.SetRoleStmt)\n\t\t$$ = &ast.SetDefaultRoleStmt{\n\t\t\tSetRoleOpt: tmp.SetRoleOpt,\n\t\t\tRoleList:   tmp.RoleList,\n\t\t\tUserList:   $6.([]*auth.UserIdentity),\n\t\t}\n\t}\n\nSetDefaultRoleOpt:\n\t\"NONE\"\n\t{\n\t\t$$ = &ast.SetRoleStmt{SetRoleOpt: ast.SetRoleNone, RoleList: nil}\n\t}\n|\t\"ALL\"\n\t{\n\t\t$$ = &ast.SetRoleStmt{SetRoleOpt: ast.SetRoleAll, RoleList: nil}\n\t}\n|\tRolenameList\n\t{\n\t\t$$ = &ast.SetRoleStmt{SetRoleOpt: ast.SetRoleRegular, RoleList: $1.([]*auth.RoleIdentity)}\n\t}\n\nSetRoleOpt:\n\t\"ALL\" \"EXCEPT\" RolenameList\n\t{\n\t\t$$ = &ast.SetRoleStmt{SetRoleOpt: ast.SetRoleAllExcept, RoleList: $3.([]*auth.RoleIdentity)}\n\t}\n|\tSetDefaultRoleOpt\n\t{\n\t\t$$ = $1\n\t}\n|\t\"DEFAULT\"\n\t{\n\t\t$$ = &ast.SetRoleStmt{SetRoleOpt: ast.SetRoleDefault, RoleList: nil}\n\t}\n\nTransactionChars:\n\tTransactionChar\n\t{\n\t\tif $1 != nil {\n\t\t\t$$ = $1\n\t\t} else {\n\t\t\t$$ = []*ast.VariableAssignment{}\n\t\t}\n\t}\n|\tTransactionChars ',' TransactionChar\n\t{\n\t\tif $3 != nil {\n\t\t\tvarAssigns := $3.([]*ast.VariableAssignment)\n\t\t\t$$ = append($1.([]*ast.VariableAssignment), varAssigns...)\n\t\t} else {\n\t\t\t$$ = $1\n\t\t}\n\t}\n\nTransactionChar:\n\t\"ISOLATION\" \"LEVEL\" IsolationLevel\n\t{\n\t\tvarAssigns := []*ast.VariableAssignment{}\n\t\texpr := ast.NewValueExpr($3)\n\t\tvarAssigns = append(varAssigns, &ast.VariableAssignment{Name: \"tx_isolation\", Value: expr, IsSystem: true})\n\t\t$$ = varAssigns\n\t}\n|\t\"READ\" \"WRITE\"\n\t{\n\t\tvarAssigns := []*ast.VariableAssignment{}\n\t\texpr := ast.NewValueExpr(\"0\")\n\t\tvarAssigns = append(varAssigns, &ast.VariableAssignment{Name: \"tx_read_only\", Value: expr, IsSystem: true})\n\t\t$$ = varAssigns\n\t}\n|\t\"READ\" \"ONLY\"\n\t{\n\t\tvarAssigns := []*ast.VariableAssignment{}\n\t\texpr := ast.NewValueExpr(\"1\")\n\t\tvarAssigns = append(varAssigns, &ast.VariableAssignment{Name: \"tx_read_only\", Value: expr, IsSystem: true})\n\t\t$$ = varAssigns\n\t}\n\nIsolationLevel:\n\t\"REPEATABLE\" \"READ\"\n\t{\n\t\t$$ = ast.RepeatableRead\n\t}\n|\t\"READ\" \"COMMITTED\"\n\t{\n\t\t$$ = ast.ReadCommitted\n\t}\n|\t\"READ\" \"UNCOMMITTED\"\n\t{\n\t\t$$ = ast.ReadUncommitted\n\t}\n|\t\"SERIALIZABLE\"\n\t{\n\t\t$$ = ast.Serializable\n\t}\n\nSetExpr:\n\t\"ON\"\n\t{\n\t\t$$ = ast.NewValueExpr(\"ON\")\n\t}\n|\tExprOrDefault\n\nEqOrAssignmentEq:\n\teq\n|\tassignmentEq\n\nVariableName:\n\tIdentifier\n|\tIdentifier '.' Identifier\n\t{\n\t\t$$ = $1 + \".\" + $3\n\t}\n\nVariableAssignment:\n\tVariableName EqOrAssignmentEq SetExpr\n\t{\n\t\t$$ = &ast.VariableAssignment{Name: $1, Value: $3, IsSystem: true}\n\t}\n|\t\"GLOBAL\" VariableName EqOrAssignmentEq SetExpr\n\t{\n\t\t$$ = &ast.VariableAssignment{Name: $2, Value: $4, IsGlobal: true, IsSystem: true}\n\t}\n|\t\"SESSION\" VariableName EqOrAssignmentEq SetExpr\n\t{\n\t\t$$ = &ast.VariableAssignment{Name: $2, Value: $4, IsSystem: true}\n\t}\n|\t\"LOCAL\" VariableName EqOrAssignmentEq Expression\n\t{\n\t\t$$ = &ast.VariableAssignment{Name: $2, Value: $4, IsSystem: true}\n\t}\n|\tdoubleAtIdentifier EqOrAssignmentEq SetExpr\n\t{\n\t\tv := strings.ToLower($1)\n\t\tvar isGlobal bool\n\t\tif strings.HasPrefix(v, \"@@global.\") {\n\t\t\tisGlobal = true\n\t\t\tv = strings.TrimPrefix(v, \"@@global.\")\n\t\t} else if strings.HasPrefix(v, \"@@session.\") {\n\t\t\tv = strings.TrimPrefix(v, \"@@session.\")\n\t\t} else if strings.HasPrefix(v, \"@@local.\") {\n\t\t\tv = strings.TrimPrefix(v, \"@@local.\")\n\t\t} else if strings.HasPrefix(v, \"@@\") {\n\t\t\tv = strings.TrimPrefix(v, \"@@\")\n\t\t}\n\t\t$$ = &ast.VariableAssignment{Name: v, Value: $3, IsGlobal: isGlobal, IsSystem: true}\n\t}\n|\tsingleAtIdentifier EqOrAssignmentEq Expression\n\t{\n\t\tv := $1\n\t\tv = strings.TrimPrefix(v, \"@\")\n\t\t$$ = &ast.VariableAssignment{Name: v, Value: $3}\n\t}\n|\t\"NAMES\" CharsetName\n\t{\n\t\t$$ = &ast.VariableAssignment{\n\t\t\tName:  ast.SetNames,\n\t\t\tValue: ast.NewValueExpr($2.(string)),\n\t\t}\n\t}\n|\t\"NAMES\" CharsetName \"COLLATE\" \"DEFAULT\"\n\t{\n\t\t$$ = &ast.VariableAssignment{\n\t\t\tName:  ast.SetNames,\n\t\t\tValue: ast.NewValueExpr($2.(string)),\n\t\t}\n\t}\n|\t\"NAMES\" CharsetName \"COLLATE\" StringName\n\t{\n\t\t$$ = &ast.VariableAssignment{\n\t\t\tName:        ast.SetNames,\n\t\t\tValue:       ast.NewValueExpr($2.(string)),\n\t\t\tExtendValue: ast.NewValueExpr($4.(string)),\n\t\t}\n\t}\n|\t\"NAMES\" \"DEFAULT\"\n\t{\n\t\tv := &ast.DefaultExpr{}\n\t\t$$ = &ast.VariableAssignment{Name: ast.SetNames, Value: v}\n\t}\n|\tCharsetKw CharsetNameOrDefault\n\t{\n\t\t$$ = &ast.VariableAssignment{Name: ast.SetNames, Value: $2}\n\t}\n\nCharsetNameOrDefault:\n\tCharsetName\n\t{\n\t\t$$ = ast.NewValueExpr($1.(string))\n\t}\n|\t\"DEFAULT\"\n\t{\n\t\t$$ = &ast.DefaultExpr{}\n\t}\n\nCharsetName:\n\tStringName\n\t{\n\t\t// Validate input charset name to keep the same behavior as parser of MySQL.\n\t\tname, _, err := charset.GetCharsetInfo($1.(string))\n\t\tif err != nil {\n\t\t\tyylex.AppendError(ErrUnknownCharacterSet.GenWithStackByArgs($1))\n\t\t\treturn 1\n\t\t}\n\t\t// Use charset name returned from charset.GetCharsetInfo(),\n\t\t// to keep lower case of input for generated column restore.\n\t\t$$ = name\n\t}\n|\tbinaryType\n\t{\n\t\t$$ = charset.CharsetBin\n\t}\n\nCollationName:\n\tStringName\n\t{\n\t\tinfo, err := charset.GetCollationByName($1.(string))\n\t\tif err != nil {\n\t\t\tyylex.AppendError(err)\n\t\t\treturn 1\n\t\t}\n\t\t$$ = info.Name\n\t}\n\nVariableAssignmentList:\n\t{\n\t\t$$ = []*ast.VariableAssignment{}\n\t}\n|\tVariableAssignment\n\t{\n\t\t$$ = []*ast.VariableAssignment{$1.(*ast.VariableAssignment)}\n\t}\n|\tVariableAssignmentList ',' VariableAssignment\n\t{\n\t\t$$ = append($1.([]*ast.VariableAssignment), $3.(*ast.VariableAssignment))\n\t}\n\nVariable:\n\tSystemVariable\n|\tUserVariable\n\nSystemVariable:\n\tdoubleAtIdentifier\n\t{\n\t\tv := strings.ToLower($1)\n\t\tvar isGlobal bool\n\t\texplicitScope := true\n\t\tif strings.HasPrefix(v, \"@@global.\") {\n\t\t\tisGlobal = true\n\t\t\tv = strings.TrimPrefix(v, \"@@global.\")\n\t\t} else if strings.HasPrefix(v, \"@@session.\") {\n\t\t\tv = strings.TrimPrefix(v, \"@@session.\")\n\t\t} else if strings.HasPrefix(v, \"@@local.\") {\n\t\t\tv = strings.TrimPrefix(v, \"@@local.\")\n\t\t} else if strings.HasPrefix(v, \"@@\") {\n\t\t\tv, explicitScope = strings.TrimPrefix(v, \"@@\"), false\n\t\t}\n\t\t$$ = &ast.VariableExpr{Name: v, IsGlobal: isGlobal, IsSystem: true, ExplicitScope: explicitScope}\n\t}\n\nUserVariable:\n\tsingleAtIdentifier\n\t{\n\t\tv := $1\n\t\tv = strings.TrimPrefix(v, \"@\")\n\t\t$$ = &ast.VariableExpr{Name: v, IsGlobal: false, IsSystem: false}\n\t}\n\nUsername:\n\tStringName\n\t{\n\t\t$$ = &auth.UserIdentity{Username: $1.(string), Hostname: \"%\"}\n\t}\n|\tStringName '@' StringName\n\t{\n\t\t$$ = &auth.UserIdentity{Username: $1.(string), Hostname: $3.(string)}\n\t}\n|\tStringName singleAtIdentifier\n\t{\n\t\t$$ = &auth.UserIdentity{Username: $1.(string), Hostname: strings.TrimPrefix($2, \"@\")}\n\t}\n|\t\"CURRENT_USER\" OptionalBraces\n\t{\n\t\t$$ = &auth.UserIdentity{CurrentUser: true}\n\t}\n\nUsernameList:\n\tUsername\n\t{\n\t\t$$ = []*auth.UserIdentity{$1.(*auth.UserIdentity)}\n\t}\n|\tUsernameList ',' Username\n\t{\n\t\t$$ = append($1.([]*auth.UserIdentity), $3.(*auth.UserIdentity))\n\t}\n\nPasswordOpt:\n\tstringLit\n\t{\n\t\t$$ = $1\n\t}\n|\t\"PASSWORD\" '(' AuthString ')'\n\t{\n\t\t$$ = $3.(string)\n\t}\n\nAuthString:\n\tstringLit\n\t{\n\t\t$$ = $1\n\t}\n\nPartyCodeString:\n\tstringLit\n\t{\n\t\t$$ = $1\n\t}\n\nRoleNameString:\n\tstringLit\n\t{\n\t\t$$ = $1\n\t}\n|\tidentifier\n\t{\n\t\t$$ = $1\n\t}\n\nRolename:\n\tRoleNameString\n\t{\n\t\t$$ = &auth.RoleIdentity{Username: $1.(string), Hostname: \"%\"}\n\t}\n|\tStringName '@' StringName\n\t{\n\t\t$$ = &auth.RoleIdentity{Username: $1.(string), Hostname: $3.(string)}\n\t}\n|\tStringName singleAtIdentifier\n\t{\n\t\t$$ = &auth.RoleIdentity{Username: $1.(string), Hostname: strings.TrimPrefix($2, \"@\")}\n\t}\n\nRolenameList:\n\tRolename\n\t{\n\t\t$$ = []*auth.RoleIdentity{$1.(*auth.RoleIdentity)}\n\t}\n|\tRolenameList ',' Rolename\n\t{\n\t\t$$ = append($1.([]*auth.RoleIdentity), $3.(*auth.RoleIdentity))\n\t}\n\n/****************************Admin Statement*******************************/\nAdminStmt:\n\t\"ADMIN\" \"SHOW\" \"DDL\"\n\t{\n\t\t$$ = &ast.AdminStmt{Tp: ast.AdminShowDDL}\n\t}\n|\t\"ADMIN\" \"SHOW\" \"DDL\" \"JOBS\" WhereClauseOptional\n\t{\n\t\tstmt := &ast.AdminStmt{Tp: ast.AdminShowDDLJobs}\n\t\tif $5 != nil {\n\t\t\tstmt.Where = $5.(ast.ExprNode)\n\t\t}\n\t\t$$ = stmt\n\t}\n|\t\"ADMIN\" \"SHOW\" \"DDL\" \"JOBS\" NUM WhereClauseOptional\n\t{\n\t\tstmt := &ast.AdminStmt{\n\t\t\tTp:        ast.AdminShowDDLJobs,\n\t\t\tJobNumber: $5.(int64),\n\t\t}\n\t\tif $6 != nil {\n\t\t\tstmt.Where = $6.(ast.ExprNode)\n\t\t}\n\t\t$$ = stmt\n\t}\n|\t\"ADMIN\" \"SHOW\" TableName \"NEXT_ROW_ID\"\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:     ast.AdminShowNextRowID,\n\t\t\tTables: []*ast.TableName{$3.(*ast.TableName)},\n\t\t}\n\t}\n|\t\"ADMIN\" \"CHECK\" \"TABLE\" TableNameList\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:     ast.AdminCheckTable,\n\t\t\tTables: $4.([]*ast.TableName),\n\t\t}\n\t}\n|\t\"ADMIN\" \"CHECK\" \"INDEX\" TableName Identifier\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:     ast.AdminCheckIndex,\n\t\t\tTables: []*ast.TableName{$4.(*ast.TableName)},\n\t\t\tIndex:  string($5),\n\t\t}\n\t}\n|\t\"ADMIN\" \"RECOVER\" \"INDEX\" TableName Identifier\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:     ast.AdminRecoverIndex,\n\t\t\tTables: []*ast.TableName{$4.(*ast.TableName)},\n\t\t\tIndex:  string($5),\n\t\t}\n\t}\n|\t\"ADMIN\" \"CLEANUP\" \"INDEX\" TableName Identifier\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:     ast.AdminCleanupIndex,\n\t\t\tTables: []*ast.TableName{$4.(*ast.TableName)},\n\t\t\tIndex:  string($5),\n\t\t}\n\t}\n|\t\"ADMIN\" \"CHECK\" \"INDEX\" TableName Identifier HandleRangeList\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:           ast.AdminCheckIndexRange,\n\t\t\tTables:       []*ast.TableName{$4.(*ast.TableName)},\n\t\t\tIndex:        string($5),\n\t\t\tHandleRanges: $6.([]ast.HandleRange),\n\t\t}\n\t}\n|\t\"ADMIN\" \"CHECKSUM\" \"TABLE\" TableNameList\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:     ast.AdminChecksumTable,\n\t\t\tTables: $4.([]*ast.TableName),\n\t\t}\n\t}\n|\t\"ADMIN\" \"CANCEL\" \"DDL\" \"JOBS\" NumList\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:     ast.AdminCancelDDLJobs,\n\t\t\tJobIDs: $5.([]int64),\n\t\t}\n\t}\n|\t\"ADMIN\" \"SHOW\" \"DDL\" \"JOB\" \"QUERIES\" NumList\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:     ast.AdminShowDDLJobQueries,\n\t\t\tJobIDs: $6.([]int64),\n\t\t}\n\t}\n|\t\"ADMIN\" \"SHOW\" \"SLOW\" AdminShowSlow\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:       ast.AdminShowSlow,\n\t\t\tShowSlow: $4.(*ast.ShowSlow),\n\t\t}\n\t}\n|\t\"ADMIN\" \"RELOAD\" \"EXPR_PUSHDOWN_BLACKLIST\"\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp: ast.AdminReloadExprPushdownBlacklist,\n\t\t}\n\t}\n|\t\"ADMIN\" \"RELOAD\" \"OPT_RULE_BLACKLIST\"\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp: ast.AdminReloadOptRuleBlacklist,\n\t\t}\n\t}\n|\t\"ADMIN\" \"PLUGINS\" \"ENABLE\" PluginNameList\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:      ast.AdminPluginEnable,\n\t\t\tPlugins: $4.([]string),\n\t\t}\n\t}\n|\t\"ADMIN\" \"PLUGINS\" \"DISABLE\" PluginNameList\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp:      ast.AdminPluginDisable,\n\t\t\tPlugins: $4.([]string),\n\t\t}\n\t}\n|\t\"ADMIN\" \"CLEANUP\" \"TABLE\" \"LOCK\" TableNameList\n\t{\n\t\t$$ = &ast.CleanupTableLockStmt{\n\t\t\tTables: $5.([]*ast.TableName),\n\t\t}\n\t}\n|\t\"ADMIN\" \"REPAIR\" \"TABLE\" TableName CreateTableStmt\n\t{\n\t\t$$ = &ast.RepairTableStmt{\n\t\t\tTable:      $4.(*ast.TableName),\n\t\t\tCreateStmt: $5.(*ast.CreateTableStmt),\n\t\t}\n\t}\n|\t\"ADMIN\" \"FLUSH\" \"BINDINGS\"\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp: ast.AdminFlushBindings,\n\t\t}\n\t}\n|\t\"ADMIN\" \"CAPTURE\" \"BINDINGS\"\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp: ast.AdminCaptureBindings,\n\t\t}\n\t}\n|\t\"ADMIN\" \"EVOLVE\" \"BINDINGS\"\n\t{\n\t\t$$ = &ast.AdminStmt{\n\t\t\tTp: ast.AdminEvolveBindings,\n\t\t}\n\t}\n\nAdminShowSlow:\n\t\"RECENT\" NUM\n\t{\n\t\t$$ = &ast.ShowSlow{\n\t\t\tTp:    ast.ShowSlowRecent,\n\t\t\tCount: getUint64FromNUM($2),\n\t\t}\n\t}\n|\t\"TOP\" NUM\n\t{\n\t\t$$ = &ast.ShowSlow{\n\t\t\tTp:    ast.ShowSlowTop,\n\t\t\tKind:  ast.ShowSlowKindDefault,\n\t\t\tCount: getUint64FromNUM($2),\n\t\t}\n\t}\n|\t\"TOP\" \"INTERNAL\" NUM\n\t{\n\t\t$$ = &ast.ShowSlow{\n\t\t\tTp:    ast.ShowSlowTop,\n\t\t\tKind:  ast.ShowSlowKindInternal,\n\t\t\tCount: getUint64FromNUM($3),\n\t\t}\n\t}\n|\t\"TOP\" \"ALL\" NUM\n\t{\n\t\t$$ = &ast.ShowSlow{\n\t\t\tTp:    ast.ShowSlowTop,\n\t\t\tKind:  ast.ShowSlowKindAll,\n\t\t\tCount: getUint64FromNUM($3),\n\t\t}\n\t}\n\nHandleRangeList:\n\tHandleRange\n\t{\n\t\t$$ = []ast.HandleRange{$1.(ast.HandleRange)}\n\t}\n|\tHandleRangeList ',' HandleRange\n\t{\n\t\t$$ = append($1.([]ast.HandleRange), $3.(ast.HandleRange))\n\t}\n\nHandleRange:\n\t'(' NUM ',' NUM ')'\n\t{\n\t\t$$ = ast.HandleRange{Begin: $2.(int64), End: $4.(int64)}\n\t}\n\nNumList:\n\tNUM\n\t{\n\t\t$$ = []int64{$1.(int64)}\n\t}\n|\tNumList ',' NUM\n\t{\n\t\t$$ = append($1.([]int64), $3.(int64))\n\t}\n\n/****************************Show Statement*******************************/\nShowStmt:\n\t\"SHOW\" ShowTargetFilterable ShowLikeOrWhereOpt\n\t{\n\t\tstmt := $2.(*ast.ShowStmt)\n\t\tif $3 != nil {\n\t\t\tif x, ok := $3.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\tstmt.Pattern = x\n\t\t\t} else {\n\t\t\t\tstmt.Where = $3.(ast.ExprNode)\n\t\t\t}\n\t\t}\n\t\t$$ = stmt\n\t}\n|\t\"SHOW\" \"CREATE\" \"TABLE\" TableName\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:    ast.ShowCreateTable,\n\t\t\tTable: $4.(*ast.TableName),\n\t\t}\n\t}\n|\t\"SHOW\" \"CREATE\" \"VIEW\" TableName\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:    ast.ShowCreateView,\n\t\t\tTable: $4.(*ast.TableName),\n\t\t}\n\t}\n|\t\"SHOW\" \"CREATE\" \"DATABASE\" IfNotExists DBName\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:          ast.ShowCreateDatabase,\n\t\t\tIfNotExists: $4.(bool),\n\t\t\tDBName:      $5.(string),\n\t\t}\n\t}\n|\t\"SHOW\" \"CREATE\" \"SEQUENCE\" TableName\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:    ast.ShowCreateSequence,\n\t\t\tTable: $4.(*ast.TableName),\n\t\t}\n\t}\n|\t\"SHOW\" \"CREATE\" \"USER\" Username\n\t{\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/show-create-user.html\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:   ast.ShowCreateUser,\n\t\t\tUser: $4.(*auth.UserIdentity),\n\t\t}\n\t}\n|\t\"SHOW\" \"TABLE\" TableName \"REGIONS\" WhereClauseOptional\n\t{\n\t\tstmt := &ast.ShowStmt{\n\t\t\tTp:    ast.ShowRegions,\n\t\t\tTable: $3.(*ast.TableName),\n\t\t}\n\t\tif $5 != nil {\n\t\t\tstmt.Where = $5.(ast.ExprNode)\n\t\t}\n\t\t$$ = stmt\n\t}\n|\t\"SHOW\" \"TABLE\" TableName \"INDEX\" Identifier \"REGIONS\" WhereClauseOptional\n\t{\n\t\tstmt := &ast.ShowStmt{\n\t\t\tTp:        ast.ShowRegions,\n\t\t\tTable:     $3.(*ast.TableName),\n\t\t\tIndexName: model.NewCIStr($5),\n\t\t}\n\t\tif $7 != nil {\n\t\t\tstmt.Where = $7.(ast.ExprNode)\n\t\t}\n\t\t$$ = stmt\n\t}\n|\t\"SHOW\" \"GRANTS\" \"ON\" DBName\n\t{\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/show-grants.html\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:     ast.ShowGrants,\n\t\t\tDBName: $4.(string),\n\t\t}\n\t}\n|\t\"SHOW\" \"GRANTS\" \"ON\" DBName \"FOR\" Username UsingRoles\n\t{\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/show-grants.html\n\t\tif $7 != nil {\n\t\t\t$$ = &ast.ShowStmt{\n\t\t\t\tTp:     ast.ShowGrants,\n\t\t\t\tDBName: $4.(string),\n\t\t\t\tUser:   $6.(*auth.UserIdentity),\n\t\t\t\tRoles:  $7.([]*auth.RoleIdentity),\n\t\t\t}\n\t\t} else {\n\t\t\t$$ = &ast.ShowStmt{\n\t\t\t\tTp:     ast.ShowGrants,\n\t\t\t\tDBName: $4.(string),\n\t\t\t\tUser:   $6.(*auth.UserIdentity),\n\t\t\t\tRoles:  nil,\n\t\t\t}\n\t\t}\n\t}\n|\t\"SHOW\" \"MASTER\" \"STATUS\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp: ast.ShowMasterStatus,\n\t\t}\n\t}\n|\t\"SHOW\" OptFull \"PROCESSLIST\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:   ast.ShowProcessList,\n\t\t\tFull: $2.(bool),\n\t\t}\n\t}\n|\t\"SHOW\" \"STATS_META\" ShowLikeOrWhereOpt\n\t{\n\t\tstmt := &ast.ShowStmt{\n\t\t\tTp: ast.ShowStatsMeta,\n\t\t}\n\t\tif $3 != nil {\n\t\t\tif x, ok := $3.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\tstmt.Pattern = x\n\t\t\t} else {\n\t\t\t\tstmt.Where = $3.(ast.ExprNode)\n\t\t\t}\n\t\t}\n\t\t$$ = stmt\n\t}\n|\t\"SHOW\" \"STATS_HISTOGRAMS\" ShowLikeOrWhereOpt\n\t{\n\t\tstmt := &ast.ShowStmt{\n\t\t\tTp: ast.ShowStatsHistograms,\n\t\t}\n\t\tif $3 != nil {\n\t\t\tif x, ok := $3.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\tstmt.Pattern = x\n\t\t\t} else {\n\t\t\t\tstmt.Where = $3.(ast.ExprNode)\n\t\t\t}\n\t\t}\n\t\t$$ = stmt\n\t}\n|\t\"SHOW\" \"STATS_BUCKETS\" ShowLikeOrWhereOpt\n\t{\n\t\tstmt := &ast.ShowStmt{\n\t\t\tTp: ast.ShowStatsBuckets,\n\t\t}\n\t\tif $3 != nil {\n\t\t\tif x, ok := $3.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\tstmt.Pattern = x\n\t\t\t} else {\n\t\t\t\tstmt.Where = $3.(ast.ExprNode)\n\t\t\t}\n\t\t}\n\t\t$$ = stmt\n\t}\n|\t\"SHOW\" \"STATS_HEALTHY\" ShowLikeOrWhereOpt\n\t{\n\t\tstmt := &ast.ShowStmt{\n\t\t\tTp: ast.ShowStatsHealthy,\n\t\t}\n\t\tif $3 != nil {\n\t\t\tif x, ok := $3.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\tstmt.Pattern = x\n\t\t\t} else {\n\t\t\t\tstmt.Where = $3.(ast.ExprNode)\n\t\t\t}\n\t\t}\n\t\t$$ = stmt\n\t}\n|\t\"SHOW\" \"PROFILES\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp: ast.ShowProfiles,\n\t\t}\n\t}\n|\t\"SHOW\" \"PROFILE\" ShowProfileTypesOpt ShowProfileArgsOpt SelectStmtLimit\n\t{\n\t\tv := &ast.ShowStmt{\n\t\t\tTp: ast.ShowProfile,\n\t\t}\n\t\tif $3 != nil {\n\t\t\tv.ShowProfileTypes = $3.([]int)\n\t\t}\n\t\tif $4 != nil {\n\t\t\tv.ShowProfileArgs = $4.(*int64)\n\t\t}\n\t\tif $5 != nil {\n\t\t\tv.ShowProfileLimit = $5.(*ast.Limit)\n\t\t}\n\t\t$$ = v\n\t}\n|\t\"SHOW\" \"PRIVILEGES\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp: ast.ShowPrivileges,\n\t\t}\n\t}\n|\t\"SHOW\" \"ANALYZE\" \"STATUS\" ShowLikeOrWhereOpt\n\t{\n\t\tstmt := &ast.ShowStmt{\n\t\t\tTp: ast.ShowAnalyzeStatus,\n\t\t}\n\t\tif $4 != nil {\n\t\t\tif x, ok := $4.(*ast.PatternLikeExpr); ok && x.Expr == nil {\n\t\t\t\tstmt.Pattern = x\n\t\t\t} else {\n\t\t\t\tstmt.Where = $4.(ast.ExprNode)\n\t\t\t}\n\t\t}\n\t\t$$ = stmt\n\t}\n|\t\"SHOW\" \"BUILTINS\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp: ast.ShowBuiltins,\n\t\t}\n\t}\n\nShowProfileTypesOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\tShowProfileTypes\n\t{\n\t\t$$ = $1\n\t}\n\nShowProfileTypes:\n\tShowProfileType\n\t{\n\t\t$$ = []int{$1.(int)}\n\t}\n|\tShowProfileTypes ',' ShowProfileType\n\t{\n\t\tl := $1.([]int)\n\t\tl = append(l, $3.(int))\n\t\t$$ = l\n\t}\n\nShowProfileType:\n\t\"CPU\"\n\t{\n\t\t$$ = ast.ProfileTypeCPU\n\t}\n|\t\"MEMORY\"\n\t{\n\t\t$$ = ast.ProfileTypeMemory\n\t}\n|\t\"BLOCK\" \"IO\"\n\t{\n\t\t$$ = ast.ProfileTypeBlockIo\n\t}\n|\t\"CONTEXT\" \"SWITCHES\"\n\t{\n\t\t$$ = ast.ProfileTypeContextSwitch\n\t}\n|\t\"PAGE\" \"FAULTS\"\n\t{\n\t\t$$ = ast.ProfileTypePageFaults\n\t}\n|\t\"IPC\"\n\t{\n\t\t$$ = ast.ProfileTypeIpc\n\t}\n|\t\"SWAPS\"\n\t{\n\t\t$$ = ast.ProfileTypeSwaps\n\t}\n|\t\"SOURCE\"\n\t{\n\t\t$$ = ast.ProfileTypeSource\n\t}\n|\t\"ALL\"\n\t{\n\t\t$$ = ast.ProfileTypeAll\n\t}\n\nShowProfileArgsOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"FOR\" \"QUERY\" NUM\n\t{\n\t\tv := $3.(int64)\n\t\t$$ = &v\n\t}\n\nUsingRoles:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"USING\" RolenameList\n\t{\n\t\t$$ = $2.([]*auth.RoleIdentity)\n\t}\n\nShowIndexKwd:\n\t\"INDEX\"\n|\t\"INDEXES\"\n|\t\"KEYS\"\n\nFromOrIn:\n\t\"FROM\"\n|\t\"IN\"\n\nShowTargetFilterable:\n\t\"ENGINES\"\n\t{\n\t\t$$ = &ast.ShowStmt{Tp: ast.ShowEngines}\n\t}\n|\t\"DATABASES\"\n\t{\n\t\t$$ = &ast.ShowStmt{Tp: ast.ShowDatabases}\n\t}\n|\tCharsetKw\n\t{\n\t\t$$ = &ast.ShowStmt{Tp: ast.ShowCharset}\n\t}\n|\tOptFull \"TABLES\" ShowDatabaseNameOpt\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:     ast.ShowTables,\n\t\t\tDBName: $3.(string),\n\t\t\tFull:   $1.(bool),\n\t\t}\n\t}\n|\t\"OPEN\" \"TABLES\" ShowDatabaseNameOpt\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:     ast.ShowOpenTables,\n\t\t\tDBName: $3.(string),\n\t\t}\n\t}\n|\t\"TABLE\" \"STATUS\" ShowDatabaseNameOpt\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:     ast.ShowTableStatus,\n\t\t\tDBName: $3.(string),\n\t\t}\n\t}\n|\tShowIndexKwd FromOrIn TableName\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:    ast.ShowIndex,\n\t\t\tTable: $3.(*ast.TableName),\n\t\t}\n\t}\n|\tShowIndexKwd FromOrIn Identifier FromOrIn Identifier\n\t{\n\t\tshow := &ast.ShowStmt{\n\t\t\tTp:    ast.ShowIndex,\n\t\t\tTable: &ast.TableName{Name: model.NewCIStr($3), Schema: model.NewCIStr($5)},\n\t\t}\n\t\t$$ = show\n\t}\n|\tOptFull FieldsOrColumns ShowTableAliasOpt ShowDatabaseNameOpt\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:     ast.ShowColumns,\n\t\t\tTable:  $3.(*ast.TableName),\n\t\t\tDBName: $4.(string),\n\t\t\tFull:   $1.(bool),\n\t\t}\n\t}\n|\t\"EXTENDED\" OptFull FieldsOrColumns ShowTableAliasOpt ShowDatabaseNameOpt\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:       ast.ShowColumns,\n\t\t\tTable:    $4.(*ast.TableName),\n\t\t\tDBName:   $5.(string),\n\t\t\tFull:     $2.(bool),\n\t\t\tExtended: true,\n\t\t}\n\t}\n|\t\"WARNINGS\"\n\t{\n\t\t$$ = &ast.ShowStmt{Tp: ast.ShowWarnings}\n\t}\n|\t\"ERRORS\"\n\t{\n\t\t$$ = &ast.ShowStmt{Tp: ast.ShowErrors}\n\t}\n|\tGlobalScope \"VARIABLES\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:          ast.ShowVariables,\n\t\t\tGlobalScope: $1.(bool),\n\t\t}\n\t}\n|\tGlobalScope \"STATUS\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:          ast.ShowStatus,\n\t\t\tGlobalScope: $1.(bool),\n\t\t}\n\t}\n|\tGlobalScope \"BINDINGS\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:          ast.ShowBindings,\n\t\t\tGlobalScope: $1.(bool),\n\t\t}\n\t}\n|\t\"COLLATION\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp: ast.ShowCollation,\n\t\t}\n\t}\n|\t\"TRIGGERS\" ShowDatabaseNameOpt\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:     ast.ShowTriggers,\n\t\t\tDBName: $2.(string),\n\t\t}\n\t}\n|\t\"PROCEDURE\" \"STATUS\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp: ast.ShowProcedureStatus,\n\t\t}\n\t}\n|\t\"PUMP\" \"STATUS\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp: ast.ShowPumpStatus,\n\t\t}\n\t}\n|\t\"DRAINER\" \"STATUS\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp: ast.ShowDrainerStatus,\n\t\t}\n\t}\n|\t\"FUNCTION\" \"STATUS\"\n\t{\n\t\t// This statement is similar to SHOW PROCEDURE STATUS but for stored functions.\n\t\t// See http://dev.mysql.com/doc/refman/5.7/en/show-function-status.html\n\t\t// We do not support neither stored functions nor stored procedures.\n\t\t// So we reuse show procedure status process logic.\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp: ast.ShowProcedureStatus,\n\t\t}\n\t}\n|\t\"EVENTS\" ShowDatabaseNameOpt\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp:     ast.ShowEvents,\n\t\t\tDBName: $2.(string),\n\t\t}\n\t}\n|\t\"PLUGINS\"\n\t{\n\t\t$$ = &ast.ShowStmt{\n\t\t\tTp: ast.ShowPlugins,\n\t\t}\n\t}\n\nShowLikeOrWhereOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"LIKE\" SimpleExpr\n\t{\n\t\t$$ = &ast.PatternLikeExpr{\n\t\t\tPattern: $2,\n\t\t\tEscape:  '\\\\',\n\t\t}\n\t}\n|\t\"WHERE\" Expression\n\t{\n\t\t$$ = $2\n\t}\n\nGlobalScope:\n\t{\n\t\t$$ = false\n\t}\n|\t\"GLOBAL\"\n\t{\n\t\t$$ = true\n\t}\n|\t\"SESSION\"\n\t{\n\t\t$$ = false\n\t}\n\nOptFull:\n\t{\n\t\t$$ = false\n\t}\n|\t\"FULL\"\n\t{\n\t\t$$ = true\n\t}\n\nShowDatabaseNameOpt:\n\t{\n\t\t$$ = \"\"\n\t}\n|\tFromOrIn DBName\n\t{\n\t\t$$ = $2.(string)\n\t}\n\nShowTableAliasOpt:\n\tFromOrIn TableName\n\t{\n\t\t$$ = $2.(*ast.TableName)\n\t}\n\nFlushStmt:\n\t\"FLUSH\" NoWriteToBinLogAliasOpt FlushOption\n\t{\n\t\ttmp := $3.(*ast.FlushStmt)\n\t\ttmp.NoWriteToBinLog = $2.(bool)\n\t\t$$ = tmp\n\t}\n\nPluginNameList:\n\tIdentifier\n\t{\n\t\t$$ = []string{$1}\n\t}\n|\tPluginNameList ',' Identifier\n\t{\n\t\t$$ = append($1.([]string), $3)\n\t}\n\nFlushOption:\n\t\"PRIVILEGES\"\n\t{\n\t\t$$ = &ast.FlushStmt{\n\t\t\tTp: ast.FlushPrivileges,\n\t\t}\n\t}\n|\t\"STATUS\"\n\t{\n\t\t$$ = &ast.FlushStmt{\n\t\t\tTp: ast.FlushStatus,\n\t\t}\n\t}\n|\t\"TIDB\" \"PLUGINS\" PluginNameList\n\t{\n\t\t$$ = &ast.FlushStmt{\n\t\t\tTp:      ast.FlushTiDBPlugin,\n\t\t\tPlugins: $3.([]string),\n\t\t}\n\t}\n|\t\"HOSTS\"\n\t{\n\t\t$$ = &ast.FlushStmt{\n\t\t\tTp: ast.FlushHosts,\n\t\t}\n\t}\n|\tLogTypeOpt \"LOGS\"\n\t{\n\t\t$$ = &ast.FlushStmt{\n\t\t\tTp:      ast.FlushLogs,\n\t\t\tLogType: $1.(ast.LogType),\n\t\t}\n\t}\n|\tTableOrTables TableNameListOpt WithReadLockOpt\n\t{\n\t\t$$ = &ast.FlushStmt{\n\t\t\tTp:       ast.FlushTables,\n\t\t\tTables:   $2.([]*ast.TableName),\n\t\t\tReadLock: $3.(bool),\n\t\t}\n\t}\n\nLogTypeOpt:\n\t/* empty */\n\t{\n\t\t$$ = ast.LogTypeDefault\n\t}\n|\t\"BINARY\"\n\t{\n\t\t$$ = ast.LogTypeBinary\n\t}\n|\t\"ENGINE\"\n\t{\n\t\t$$ = ast.LogTypeEngine\n\t}\n|\t\"ERROR\"\n\t{\n\t\t$$ = ast.LogTypeError\n\t}\n|\t\"GENERAL\"\n\t{\n\t\t$$ = ast.LogTypeGeneral\n\t}\n|\t\"SLOW\"\n\t{\n\t\t$$ = ast.LogTypeSlow\n\t}\n\nNoWriteToBinLogAliasOpt:\n\t%prec lowerThanLocal\n\t{\n\t\t$$ = false\n\t}\n|\t\"NO_WRITE_TO_BINLOG\"\n\t{\n\t\t$$ = true\n\t}\n|\t\"LOCAL\"\n\t{\n\t\t$$ = true\n\t}\n\nTableNameListOpt:\n\t%prec empty\n\t{\n\t\t$$ = []*ast.TableName{}\n\t}\n|\tTableNameList\n\t{\n\t\t$$ = $1\n\t}\n\nWithReadLockOpt:\n\t{\n\t\t$$ = false\n\t}\n|\t\"WITH\" \"READ\" \"LOCK\"\n\t{\n\t\t$$ = true\n\t}\n\nStatement:\n\tEmptyStmt\n|\tAdminStmt\n|\tAlterDatabaseStmt\n|\tAlterTableStmt\n|\tAlterUserStmt\n|\tAnalyzeTableStmt\n|\tBeginTransactionStmt\n|\tBinlogStmt\n|\tCommitStmt\n|\tDeallocateStmt\n|\tDeleteFromStmt\n|\tExecuteStmt\n|\tExplainStmt\n|\tChangeStmt\n|\tCreateDatabaseStmt\n|\tCreateIndexStmt\n|\tCreateTableStmt\n|\tCreateViewStmt\n|\tCreateUserStmt\n|\tCreateRoleStmt\n|\tCreateBindingStmt\n|\tCreateSequenceStmt\n|\tDoStmt\n|\tDropDatabaseStmt\n|\tDropIndexStmt\n|\tDropTableStmt\n|\tDropSequenceStmt\n|\tDropViewStmt\n|\tDropUserStmt\n|\tDropRoleStmt\n|\tDropStatsStmt\n|\tDropBindingStmt\n|\tFlushStmt\n|\tFlashbackTableStmt\n|\tGrantStmt\n|\tGrantRoleStmt\n|\tInsertIntoStmt\n|\tIndexAdviseStmt\n|\tKillStmt\n|\tLoadDataStmt\n|\tLoadStatsStmt\n|\tPreparedStmt\n|\tRollbackStmt\n|\tRenameTableStmt\n|\tReplaceIntoStmt\n|\tRecoverTableStmt\n|\tRevokeStmt\n|\tRevokeRoleStmt\n|\tSelectStmt\n|\tUnionStmt\n|\tSetStmt\n|\tSetRoleStmt\n|\tSetDefaultRoleStmt\n|\tSplitRegionStmt\n|\tShowStmt\n|\tSubSelect\n\t{\n\t\t// `(select 1)`; is a valid select statement\n\t\t// TODO: This is used to fix issue #320. There may be a better solution.\n\t\t$$ = $1.(*ast.SubqueryExpr).Query.(ast.StmtNode)\n\t}\n|\tTraceStmt\n|\tTruncateTableStmt\n|\tUpdateStmt\n|\tUseStmt\n|\tUnlockTablesStmt\n|\tLockTablesStmt\n|\tShutdownStmt\n\nTraceableStmt:\n\tSelectStmt\n|\tDeleteFromStmt\n|\tUpdateStmt\n|\tInsertIntoStmt\n|\tReplaceIntoStmt\n|\tUnionStmt\n|\tLoadDataStmt\n|\tBeginTransactionStmt\n|\tCommitStmt\n|\tRollbackStmt\n|\tSetStmt\n\nExplainableStmt:\n\tSelectStmt\n|\tDeleteFromStmt\n|\tUpdateStmt\n|\tInsertIntoStmt\n|\tReplaceIntoStmt\n|\tUnionStmt\n\nStatementList:\n\tStatement\n\t{\n\t\tif $1 != nil {\n\t\t\ts := $1\n\t\t\tif lexer, ok := yylex.(stmtTexter); ok {\n\t\t\t\ts.SetText(lexer.stmtText())\n\t\t\t}\n\t\t\tparser.result = append(parser.result, s)\n\t\t}\n\t}\n|\tStatementList ';' Statement\n\t{\n\t\tif $3 != nil {\n\t\t\ts := $3\n\t\t\tif lexer, ok := yylex.(stmtTexter); ok {\n\t\t\t\ts.SetText(lexer.stmtText())\n\t\t\t}\n\t\t\tparser.result = append(parser.result, s)\n\t\t}\n\t}\n\nConstraint:\n\tConstraintKeywordOpt ConstraintElem\n\t{\n\t\tcst := $2.(*ast.Constraint)\n\t\tif $1 != nil {\n\t\t\tcst.Name = $1.(string)\n\t\t}\n\t\t$$ = cst\n\t}\n\nTableElement:\n\tColumnDef\n\t{\n\t\t$$ = $1.(*ast.ColumnDef)\n\t}\n\nTableElementList:\n\tTableElement\n\t{\n\t\tif $1 != nil {\n\t\t\t$$ = []interface{}{$1.(interface{})}\n\t\t} else {\n\t\t\t$$ = []interface{}{}\n\t\t}\n\t}\n|\tTableElementList ',' TableElement\n\t{\n\t\tif $3 != nil {\n\t\t\t$$ = append($1.([]interface{}), $3)\n\t\t} else {\n\t\t\t$$ = $1\n\t\t}\n\t}\n\nTableElementListOpt:\n\t/* empty */ %prec lowerThanCreateTableSelect\n\t{\n\t\tvar columnDefs []*ast.ColumnDef\n\t\tvar constraints []*ast.Constraint\n\t\t$$ = &ast.CreateTableStmt{\n\t\t\tCols:        columnDefs,\n\t\t\tConstraints: constraints,\n\t\t}\n\t}\n|\t'(' TableElementList ')'\n\t{\n\t\ttes := $2.([]interface{})\n\t\tvar columnDefs []*ast.ColumnDef\n\t\tvar constraints []*ast.Constraint\n\t\tfor _, te := range tes {\n\t\t\tswitch te := te.(type) {\n\t\t\tcase *ast.ColumnDef:\n\t\t\t\tcolumnDefs = append(columnDefs, te)\n\t\t\tcase *ast.Constraint:\n\t\t\t\tconstraints = append(constraints, te)\n\t\t\t}\n\t\t}\n\t\t$$ = &ast.CreateTableStmt{\n\t\t\tCols:        columnDefs,\n\t\t\tConstraints: constraints,\n\t\t}\n\t}\n\nTableOption:\n\tPartDefOption\n\t{\n\t\t$$ = $1\n\t}\n|\tDefaultKwdOpt CharsetKw EqOpt CharsetName\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionCharset, StrValue: $4.(string),\n\t\t\tUintValue: ast.TableOptionCharsetWithoutConvertTo}\n\t}\n|\tDefaultKwdOpt \"COLLATE\" EqOpt CollationName\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionCollate, StrValue: $4.(string),\n\t\t\tUintValue: ast.TableOptionCharsetWithoutConvertTo}\n\t}\n|\t\"AUTO_INCREMENT\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionAutoIncrement, UintValue: $3.(uint64)}\n\t}\n|\t\"AVG_ROW_LENGTH\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionAvgRowLength, UintValue: $3.(uint64)}\n\t}\n|\t\"CONNECTION\" EqOpt stringLit\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionConnection, StrValue: $3}\n\t}\n|\t\"CHECKSUM\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionCheckSum, UintValue: $3.(uint64)}\n\t}\n|\t\"TABLE_CHECKSUM\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionTableCheckSum, UintValue: $3.(uint64)}\n\t}\n|\t\"PASSWORD\" EqOpt stringLit\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionPassword, StrValue: $3}\n\t}\n|\t\"COMPRESSION\" EqOpt stringLit\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionCompression, StrValue: $3}\n\t}\n|\t\"KEY_BLOCK_SIZE\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionKeyBlockSize, UintValue: $3.(uint64)}\n\t}\n|\t\"DELAY_KEY_WRITE\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionDelayKeyWrite, UintValue: $3.(uint64)}\n\t}\n|\tRowFormat\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionRowFormat, UintValue: $1.(uint64)}\n\t}\n|\t\"STATS_PERSISTENT\" EqOpt StatsPersistentVal\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionStatsPersistent}\n\t}\n|\t\"STATS_AUTO_RECALC\" EqOpt LengthNum\n\t{\n\t\tn := $3.(uint64)\n\t\tif n != 0 && n != 1 {\n\t\t\tyylex.AppendError(yylex.Errorf(\"The value of STATS_AUTO_RECALC must be one of [0|1|DEFAULT].\"))\n\t\t\treturn 1\n\t\t}\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionStatsAutoRecalc, UintValue: n}\n\t\tyylex.AppendError(yylex.Errorf(\"The STATS_AUTO_RECALC is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"STATS_AUTO_RECALC\" EqOpt \"DEFAULT\"\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionStatsAutoRecalc, Default: true}\n\t\tyylex.AppendError(yylex.Errorf(\"The STATS_AUTO_RECALC is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"STATS_SAMPLE_PAGES\" EqOpt LengthNum\n\t{\n\t\t// Parse it but will ignore it.\n\t\t// In MySQL, STATS_SAMPLE_PAGES=N(Where 0<N<=65535) or STAS_SAMPLE_PAGES=DEFAULT.\n\t\t// Cause we don't support it, so we don't check range of the value.\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionStatsSamplePages, UintValue: $3.(uint64)}\n\t\tyylex.AppendError(yylex.Errorf(\"The STATS_SAMPLE_PAGES is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"STATS_SAMPLE_PAGES\" EqOpt \"DEFAULT\"\n\t{\n\t\t// Parse it but will ignore it.\n\t\t// In MySQL, default value of STATS_SAMPLE_PAGES is 0.\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionStatsSamplePages, Default: true}\n\t\tyylex.AppendError(yylex.Errorf(\"The STATS_SAMPLE_PAGES is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"SHARD_ROW_ID_BITS\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionShardRowID, UintValue: $3.(uint64)}\n\t}\n|\t\"PRE_SPLIT_REGIONS\" EqOpt LengthNum\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionPreSplitRegion, UintValue: $3.(uint64)}\n\t}\n|\t\"PACK_KEYS\" EqOpt StatsPersistentVal\n\t{\n\t\t// Parse it but will ignore it.\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionPackKeys}\n\t}\n|\t\"STORAGE\" \"MEMORY\"\n\t{\n\t\t// Parse it but will ignore it.\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionStorageMedia, StrValue: \"MEMORY\"}\n\t\tyylex.AppendError(yylex.Errorf(\"The STORAGE clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"STORAGE\" \"DISK\"\n\t{\n\t\t// Parse it but will ignore it.\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionStorageMedia, StrValue: \"DISK\"}\n\t\tyylex.AppendError(yylex.Errorf(\"The STORAGE clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"SECONDARY_ENGINE\" EqOpt \"NULL\"\n\t{\n\t\t// Parse it but will ignore it\n\t\t// See https://github.com/mysql/mysql-server/blob/8.0/sql/sql_yacc.yy#L5977-L5984\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionSecondaryEngineNull}\n\t\tyylex.AppendError(yylex.Errorf(\"The SECONDARY_ENGINE clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"SECONDARY_ENGINE\" EqOpt StringName\n\t{\n\t\t// Parse it but will ignore it\n\t\t// See https://github.com/mysql/mysql-server/blob/8.0/sql/sql_yacc.yy#L5977-L5984\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionSecondaryEngine, StrValue: $3.(string)}\n\t\tyylex.AppendError(yylex.Errorf(\"The SECONDARY_ENGINE clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"UNION\" EqOpt '(' TableNameListOpt ')'\n\t{\n\t\t// Parse it but will ignore it\n\t\t$$ = &ast.TableOption{\n\t\t\tTp:         ast.TableOptionUnion,\n\t\t\tTableNames: $4.([]*ast.TableName),\n\t\t}\n\t\tyylex.AppendError(yylex.Errorf(\"The UNION option is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"ENCRYPTION\" EqOpt stringLit\n\t{\n\t\t// Parse it but will ignore it\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionEncryption, StrValue: $3}\n\t\tyylex.AppendError(yylex.Errorf(\"The ENCRYPTION clause is parsed but ignored by all storage engines.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n|\t\"REF_TABLE\" EqOpt TableName\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionRefTable, TableNames: []*ast.TableName{$3.(*ast.TableName)}}\n\t}\n|\t\"DB_TYPE\" EqOpt stringLit\n\t{\n\t\t$$ = &ast.TableOption{Tp: ast.TableOptionDBType, StrValue: $3}\n\t}\n\nStatsPersistentVal:\n\t\"DEFAULT\"\n\t{}\n|\tLengthNum\n\t{}\n\nCreateTableOptionListOpt:\n\t/* empty */ %prec lowerThanCreateTableSelect\n\t{\n\t\t$$ = []*ast.TableOption{}\n\t}\n|\tTableOptionList %prec lowerThanComma\n\nTableOptionList:\n\tTableOption\n\t{\n\t\t$$ = []*ast.TableOption{$1.(*ast.TableOption)}\n\t}\n|\tTableOptionList TableOption\n\t{\n\t\t$$ = append($1.([]*ast.TableOption), $2.(*ast.TableOption))\n\t}\n|\tTableOptionList ',' TableOption\n\t{\n\t\t$$ = append($1.([]*ast.TableOption), $3.(*ast.TableOption))\n\t}\n\nOptTable:\n\t{}\n|\t\"TABLE\"\n\nTruncateTableStmt:\n\t\"TRUNCATE\" OptTable TableName\n\t{\n\t\t$$ = &ast.TruncateTableStmt{Table: $3.(*ast.TableName)}\n\t}\n\nRowFormat:\n\t\"ROW_FORMAT\" EqOpt \"DEFAULT\"\n\t{\n\t\t$$ = ast.RowFormatDefault\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"DYNAMIC\"\n\t{\n\t\t$$ = ast.RowFormatDynamic\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"FIXED\"\n\t{\n\t\t$$ = ast.RowFormatFixed\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"COMPRESSED\"\n\t{\n\t\t$$ = ast.RowFormatCompressed\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"REDUNDANT\"\n\t{\n\t\t$$ = ast.RowFormatRedundant\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"COMPACT\"\n\t{\n\t\t$$ = ast.RowFormatCompact\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"TOKUDB_DEFAULT\"\n\t{\n\t\t$$ = ast.TokuDBRowFormatDefault\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"TOKUDB_FAST\"\n\t{\n\t\t$$ = ast.TokuDBRowFormatFast\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"TOKUDB_SMALL\"\n\t{\n\t\t$$ = ast.TokuDBRowFormatSmall\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"TOKUDB_ZLIB\"\n\t{\n\t\t$$ = ast.TokuDBRowFormatZlib\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"TOKUDB_QUICKLZ\"\n\t{\n\t\t$$ = ast.TokuDBRowFormatQuickLZ\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"TOKUDB_LZMA\"\n\t{\n\t\t$$ = ast.TokuDBRowFormatLzma\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"TOKUDB_SNAPPY\"\n\t{\n\t\t$$ = ast.TokuDBRowFormatSnappy\n\t}\n|\t\"ROW_FORMAT\" EqOpt \"TOKUDB_UNCOMPRESSED\"\n\t{\n\t\t$$ = ast.TokuDBRowFormatUncompressed\n\t}\n\n/*************************************Type Begin***************************************/\nType:\n\tNumericType\n\t{\n\t\t$$ = $1\n\t}\n|\tStringType\n\t{\n\t\t$$ = $1\n\t}\n|\tDateAndTimeType\n\t{\n\t\t$$ = $1\n\t}\n\nNumericType:\n\tIntegerType OptFieldLen FieldOpts\n\t{\n\t\t// TODO: check flen 0\n\t\tx := types.NewFieldType($1.(byte))\n\t\tx.Flen = $2.(int)\n\t\tfor _, o := range $3.([]*ast.TypeOpt) {\n\t\t\tif o.IsUnsigned {\n\t\t\t\tx.Flag |= mysql.UnsignedFlag\n\t\t\t}\n\t\t\tif o.IsZerofill {\n\t\t\t\tx.Flag |= mysql.ZerofillFlag\n\t\t\t}\n\t\t}\n\t\t$$ = x\n\t}\n|\tBooleanType FieldOpts\n\t{\n\t\t// TODO: check flen 0\n\t\tx := types.NewFieldType($1.(byte))\n\t\tx.Flen = 1\n\t\tfor _, o := range $2.([]*ast.TypeOpt) {\n\t\t\tif o.IsUnsigned {\n\t\t\t\tx.Flag |= mysql.UnsignedFlag\n\t\t\t}\n\t\t\tif o.IsZerofill {\n\t\t\t\tx.Flag |= mysql.ZerofillFlag\n\t\t\t}\n\t\t}\n\t\t$$ = x\n\t}\n|\tFixedPointType FloatOpt FieldOpts\n\t{\n\t\tfopt := $2.(*ast.FloatOpt)\n\t\tx := types.NewFieldType($1.(byte))\n\t\tx.Flen = fopt.Flen\n\t\tx.Decimal = fopt.Decimal\n\t\tfor _, o := range $3.([]*ast.TypeOpt) {\n\t\t\tif o.IsUnsigned {\n\t\t\t\tx.Flag |= mysql.UnsignedFlag\n\t\t\t}\n\t\t\tif o.IsZerofill {\n\t\t\t\tx.Flag |= mysql.ZerofillFlag\n\t\t\t}\n\t\t}\n\t\t$$ = x\n\t}\n|\tFloatingPointType FloatOpt FieldOpts\n\t{\n\t\tfopt := $2.(*ast.FloatOpt)\n\t\tx := types.NewFieldType($1.(byte))\n\t\tx.Flen = fopt.Flen\n\t\tif x.Tp == mysql.TypeFloat && fopt.Decimal == types.UnspecifiedLength && x.Flen <= mysql.MaxDoublePrecisionLength {\n\t\t\tif x.Flen > mysql.MaxFloatPrecisionLength {\n\t\t\t\tx.Tp = mysql.TypeDouble\n\t\t\t}\n\t\t\tx.Flen = types.UnspecifiedLength\n\t\t}\n\t\tx.Decimal = fopt.Decimal\n\t\tfor _, o := range $3.([]*ast.TypeOpt) {\n\t\t\tif o.IsUnsigned {\n\t\t\t\tx.Flag |= mysql.UnsignedFlag\n\t\t\t}\n\t\t\tif o.IsZerofill {\n\t\t\t\tx.Flag |= mysql.ZerofillFlag\n\t\t\t}\n\t\t}\n\t\t$$ = x\n\t}\n|\tBitValueType OptFieldLen\n\t{\n\t\tx := types.NewFieldType($1.(byte))\n\t\tx.Flen = $2.(int)\n\t\tif x.Flen == types.UnspecifiedLength {\n\t\t\tx.Flen = 1\n\t\t}\n\t\t$$ = x\n\t}\n\nIntegerType:\n\t\"TINYINT\"\n\t{\n\t\t$$ = mysql.TypeTiny\n\t}\n|\t\"SMALLINT\"\n\t{\n\t\t$$ = mysql.TypeShort\n\t}\n|\t\"MEDIUMINT\"\n\t{\n\t\t$$ = mysql.TypeInt24\n\t}\n|\t\"INT\"\n\t{\n\t\t$$ = mysql.TypeLong\n\t}\n|\t\"INT1\"\n\t{\n\t\t$$ = mysql.TypeTiny\n\t}\n|\t\"INT2\"\n\t{\n\t\t$$ = mysql.TypeShort\n\t}\n|\t\"INT3\"\n\t{\n\t\t$$ = mysql.TypeInt24\n\t}\n|\t\"INT4\"\n\t{\n\t\t$$ = mysql.TypeLong\n\t}\n|\t\"INT8\"\n\t{\n\t\t$$ = mysql.TypeLonglong\n\t}\n|\t\"INTEGER\"\n\t{\n\t\t$$ = mysql.TypeLong\n\t}\n|\t\"BIGINT\"\n\t{\n\t\t$$ = mysql.TypeLonglong\n\t}\n\nBooleanType:\n\t\"BOOL\"\n\t{\n\t\t$$ = mysql.TypeTiny\n\t}\n|\t\"BOOLEAN\"\n\t{\n\t\t$$ = mysql.TypeTiny\n\t}\n\nOptInteger:\n\t{}\n|\t\"INTEGER\"\n|\t\"INT\"\n\nFixedPointType:\n\t\"DECIMAL\"\n\t{\n\t\t$$ = mysql.TypeNewDecimal\n\t}\n|\t\"NUMERIC\"\n\t{\n\t\t$$ = mysql.TypeNewDecimal\n\t}\n|\t\"FIXED\"\n\t{\n\t\t$$ = mysql.TypeNewDecimal\n\t}\n\nFloatingPointType:\n\t\"FLOAT\"\n\t{\n\t\t$$ = mysql.TypeFloat\n\t}\n|\t\"REAL\"\n\t{\n\t\tif parser.lexer.GetSQLMode().HasRealAsFloatMode() {\n\t\t\t$$ = mysql.TypeFloat\n\t\t} else {\n\t\t\t$$ = mysql.TypeDouble\n\t\t}\n\t}\n|\t\"DOUBLE\"\n\t{\n\t\t$$ = mysql.TypeDouble\n\t}\n|\t\"DOUBLE\" \"PRECISION\"\n\t{\n\t\t$$ = mysql.TypeDouble\n\t}\n\nBitValueType:\n\t\"BIT\"\n\t{\n\t\t$$ = mysql.TypeBit\n\t}\n\nStringType:\n\tChar FieldLen OptBinary\n\t{\n\t\tx := types.NewFieldType(mysql.TypeString)\n\t\tx.Flen = $2.(int)\n\t\tx.Charset = $3.(*ast.OptBinary).Charset\n\t\tif $3.(*ast.OptBinary).IsBinary {\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t}\n\t\t$$ = x\n\t}\n|\tChar OptBinary\n\t{\n\t\tx := types.NewFieldType(mysql.TypeString)\n\t\tx.Charset = $2.(*ast.OptBinary).Charset\n\t\tif $2.(*ast.OptBinary).IsBinary {\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t}\n\t\t$$ = x\n\t}\n|\tNChar FieldLen OptBinary\n\t{\n\t\tx := types.NewFieldType(mysql.TypeString)\n\t\tx.Flen = $2.(int)\n\t\tx.Charset = $3.(*ast.OptBinary).Charset\n\t\tif $3.(*ast.OptBinary).IsBinary {\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t}\n\t\t$$ = x\n\t}\n|\tNChar OptBinary\n\t{\n\t\tx := types.NewFieldType(mysql.TypeString)\n\t\tx.Charset = $2.(*ast.OptBinary).Charset\n\t\tif $2.(*ast.OptBinary).IsBinary {\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t}\n\t\t$$ = x\n\t}\n|\tVarchar FieldLen OptBinary\n\t{\n\t\tx := types.NewFieldType(mysql.TypeVarchar)\n\t\tx.Flen = $2.(int)\n\t\tx.Charset = $3.(*ast.OptBinary).Charset\n\t\tif $3.(*ast.OptBinary).IsBinary {\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t}\n\t\t$$ = x\n\t}\n|\tNVarchar FieldLen OptBinary\n\t{\n\t\tx := types.NewFieldType(mysql.TypeVarchar)\n\t\tx.Flen = $2.(int)\n\t\tx.Charset = $3.(*ast.OptBinary).Charset\n\t\tif $3.(*ast.OptBinary).IsBinary {\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t}\n\t\t$$ = x\n\t}\n|\t\"BINARY\" OptFieldLen\n\t{\n\t\tx := types.NewFieldType(mysql.TypeString)\n\t\tx.Flen = $2.(int)\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CharsetBin\n\t\tx.Flag |= mysql.BinaryFlag\n\t\t$$ = x\n\t}\n|\t\"VARBINARY\" FieldLen\n\t{\n\t\tx := types.NewFieldType(mysql.TypeVarchar)\n\t\tx.Flen = $2.(int)\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CharsetBin\n\t\tx.Flag |= mysql.BinaryFlag\n\t\t$$ = x\n\t}\n|\tBlobType\n\t{\n\t\tx := $1.(*types.FieldType)\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CharsetBin\n\t\tx.Flag |= mysql.BinaryFlag\n\t\t$$ = $1.(*types.FieldType)\n\t}\n|\tTextType OptCharsetWithOptBinary\n\t{\n\t\tx := $1.(*types.FieldType)\n\t\tx.Charset = $2.(*ast.OptBinary).Charset\n\t\tif $2.(*ast.OptBinary).IsBinary {\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t}\n\t\t$$ = x\n\t}\n|\t\"ENUM\" '(' StringList ')' OptCharset\n\t{\n\t\tx := types.NewFieldType(mysql.TypeEnum)\n\t\tx.Elems = $3.([]string)\n\t\tx.Charset = $5.(string)\n\t\t$$ = x\n\t}\n|\t\"SET\" '(' StringList ')' OptCharset\n\t{\n\t\tx := types.NewFieldType(mysql.TypeSet)\n\t\tx.Elems = $3.([]string)\n\t\tx.Charset = $5.(string)\n\t\t$$ = x\n\t}\n|\t\"JSON\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeJSON)\n\t\tx.Decimal = 0\n\t\tx.Charset = charset.CharsetBin\n\t\tx.Collate = charset.CollationBin\n\t\t$$ = x\n\t}\n|\t\"LONG\" Varchar OptCharsetWithOptBinary\n\t{\n\t\tx := types.NewFieldType(mysql.TypeMediumBlob)\n\t\tx.Charset = $3.(*ast.OptBinary).Charset\n\t\tif $3.(*ast.OptBinary).IsBinary {\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t}\n\t\t$$ = x\n\t}\n|\t\"LONG\" OptCharsetWithOptBinary\n\t{\n\t\tx := types.NewFieldType(mysql.TypeMediumBlob)\n\t\tx.Charset = $2.(*ast.OptBinary).Charset\n\t\tif $2.(*ast.OptBinary).IsBinary {\n\t\t\tx.Flag |= mysql.BinaryFlag\n\t\t}\n\t\t$$ = x\n\t}\n\nChar:\n\t\"CHARACTER\"\n|\t\"CHAR\"\n\nNChar:\n\t\"NCHAR\"\n|\t\"NATIONAL\" \"CHARACTER\"\n|\t\"NATIONAL\" \"CHAR\"\n\nVarchar:\n\t\"CHARACTER\" \"VARYING\"\n|\t\"CHAR\" \"VARYING\"\n|\t\"VARCHAR\"\n|\t\"VARCHARACTER\"\n\nNVarchar:\n\t\"NATIONAL\" \"VARCHAR\"\n|\t\"NATIONAL\" \"VARCHARACTER\"\n|\t\"NVARCHAR\"\n|\t\"NCHAR\" \"VARCHAR\"\n|\t\"NCHAR\" \"VARCHARACTER\"\n|\t\"NATIONAL\" \"CHARACTER\" \"VARYING\"\n|\t\"NATIONAL\" \"CHAR\" \"VARYING\"\n|\t\"NCHAR\" \"VARYING\"\n\nYear:\n\t\"YEAR\"\n|\t\"SQL_TSI_YEAR\"\n\nBlobType:\n\t\"TINYBLOB\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeTinyBlob)\n\t\t$$ = x\n\t}\n|\t\"BLOB\" OptFieldLen\n\t{\n\t\tx := types.NewFieldType(mysql.TypeBlob)\n\t\tx.Flen = $2.(int)\n\t\t$$ = x\n\t}\n|\t\"MEDIUMBLOB\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeMediumBlob)\n\t\t$$ = x\n\t}\n|\t\"LONGBLOB\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeLongBlob)\n\t\t$$ = x\n\t}\n|\t\"LONG\" \"VARBINARY\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeMediumBlob)\n\t\t$$ = x\n\t}\n\nTextType:\n\t\"TINYTEXT\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeTinyBlob)\n\t\t$$ = x\n\t}\n|\t\"TEXT\" OptFieldLen\n\t{\n\t\tx := types.NewFieldType(mysql.TypeBlob)\n\t\tx.Flen = $2.(int)\n\t\t$$ = x\n\t}\n|\t\"MEDIUMTEXT\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeMediumBlob)\n\t\t$$ = x\n\t}\n|\t\"LONGTEXT\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeLongBlob)\n\t\t$$ = x\n\t}\n\nOptCharsetWithOptBinary:\n\tOptBinary\n\t{\n\t\t$$ = $1\n\t}\n|\t\"ASCII\"\n\t{\n\t\t$$ = &ast.OptBinary{\n\t\t\tIsBinary: false,\n\t\t\tCharset:  charset.CharsetLatin1,\n\t\t}\n\t}\n|\t\"UNICODE\"\n\t{\n\t\tname, _, err := charset.GetCharsetInfo(\"ucs2\")\n\t\tif err != nil {\n\t\t\tyylex.AppendError(ErrUnknownCharacterSet.GenWithStackByArgs(\"ucs2\"))\n\t\t\treturn 1\n\t\t}\n\t\t$$ = &ast.OptBinary{\n\t\t\tIsBinary: false,\n\t\t\tCharset:  name,\n\t\t}\n\t}\n|\t\"BYTE\"\n\t{\n\t\t$$ = &ast.OptBinary{\n\t\t\tIsBinary: false,\n\t\t\tCharset:  \"\",\n\t\t}\n\t}\n\nDateAndTimeType:\n\t\"DATE\"\n\t{\n\t\tx := types.NewFieldType(mysql.TypeDate)\n\t\t$$ = x\n\t}\n|\t\"DATETIME\" OptFieldLen\n\t{\n\t\tx := types.NewFieldType(mysql.TypeDatetime)\n\t\tx.Flen = mysql.MaxDatetimeWidthNoFsp\n\t\tx.Decimal = $2.(int)\n\t\tif x.Decimal > 0 {\n\t\t\tx.Flen = x.Flen + 1 + x.Decimal\n\t\t}\n\t\t$$ = x\n\t}\n|\t\"TIMESTAMP\" OptFieldLen\n\t{\n\t\tx := types.NewFieldType(mysql.TypeTimestamp)\n\t\tx.Flen = mysql.MaxDatetimeWidthNoFsp\n\t\tx.Decimal = $2.(int)\n\t\tif x.Decimal > 0 {\n\t\t\tx.Flen = x.Flen + 1 + x.Decimal\n\t\t}\n\t\t$$ = x\n\t}\n|\t\"TIME\" OptFieldLen\n\t{\n\t\tx := types.NewFieldType(mysql.TypeDuration)\n\t\tx.Flen = mysql.MaxDurationWidthNoFsp\n\t\tx.Decimal = $2.(int)\n\t\tif x.Decimal > 0 {\n\t\t\tx.Flen = x.Flen + 1 + x.Decimal\n\t\t}\n\t\t$$ = x\n\t}\n|\tYear OptFieldLen FieldOpts\n\t{\n\t\tx := types.NewFieldType(mysql.TypeYear)\n\t\tx.Flen = $2.(int)\n\t\tif x.Flen != types.UnspecifiedLength && x.Flen != 4 {\n\t\t\tyylex.AppendError(ErrInvalidYearColumnLength.GenWithStackByArgs())\n\t\t\treturn -1\n\t\t}\n\t\t$$ = x\n\t}\n\nFieldLen:\n\t'(' LengthNum ')'\n\t{\n\t\t$$ = int($2.(uint64))\n\t}\n\nOptFieldLen:\n\t{\n\t\t$$ = types.UnspecifiedLength\n\t}\n|\tFieldLen\n\t{\n\t\t$$ = $1.(int)\n\t}\n\nFieldOpt:\n\t\"UNSIGNED\"\n\t{\n\t\t$$ = &ast.TypeOpt{IsUnsigned: true}\n\t}\n|\t\"SIGNED\"\n\t{\n\t\t$$ = &ast.TypeOpt{IsUnsigned: false}\n\t}\n|\t\"ZEROFILL\"\n\t{\n\t\t$$ = &ast.TypeOpt{IsZerofill: true, IsUnsigned: true}\n\t}\n\nFieldOpts:\n\t{\n\t\t$$ = []*ast.TypeOpt{}\n\t}\n|\tFieldOpts FieldOpt\n\t{\n\t\t$$ = append($1.([]*ast.TypeOpt), $2.(*ast.TypeOpt))\n\t}\n\nFloatOpt:\n\t{\n\t\t$$ = &ast.FloatOpt{Flen: types.UnspecifiedLength, Decimal: types.UnspecifiedLength}\n\t}\n|\tFieldLen\n\t{\n\t\t$$ = &ast.FloatOpt{Flen: $1.(int), Decimal: types.UnspecifiedLength}\n\t}\n|\tPrecision\n\t{\n\t\t$$ = $1.(*ast.FloatOpt)\n\t}\n\nPrecision:\n\t'(' LengthNum ',' LengthNum ')'\n\t{\n\t\t$$ = &ast.FloatOpt{Flen: int($2.(uint64)), Decimal: int($4.(uint64))}\n\t}\n\nOptBinMod:\n\t{\n\t\t$$ = false\n\t}\n|\t\"BINARY\"\n\t{\n\t\t$$ = true\n\t}\n\nOptBinary:\n\t{\n\t\t$$ = &ast.OptBinary{\n\t\t\tIsBinary: false,\n\t\t\tCharset:  \"\",\n\t\t}\n\t}\n|\t\"BINARY\" OptCharset\n\t{\n\t\t$$ = &ast.OptBinary{\n\t\t\tIsBinary: true,\n\t\t\tCharset:  $2.(string),\n\t\t}\n\t}\n|\tCharsetKw CharsetName OptBinMod\n\t{\n\t\t$$ = &ast.OptBinary{\n\t\t\tIsBinary: $3.(bool),\n\t\t\tCharset:  $2.(string),\n\t\t}\n\t}\n\nOptCharset:\n\t{\n\t\t$$ = \"\"\n\t}\n|\tCharsetKw CharsetName\n\t{\n\t\t$$ = $2.(string)\n\t}\n\nCharsetKw:\n\t\"CHARACTER\" \"SET\"\n|\t\"CHARSET\"\n|\t\"CHAR\" \"SET\"\n\nOptCollate:\n\t{\n\t\t$$ = \"\"\n\t}\n|\t\"COLLATE\" CollationName\n\t{\n\t\t$$ = $2.(string)\n\t}\n\nStringList:\n\tstringLit\n\t{\n\t\t$$ = []string{$1}\n\t}\n|\tStringList ',' stringLit\n\t{\n\t\t$$ = append($1.([]string), $3)\n\t}\n\nStringName:\n\tstringLit\n\t{\n\t\t$$ = $1\n\t}\n|\tIdentifier\n\t{\n\t\t$$ = $1\n\t}\n\n/***********************************************************************************\n * Update Statement\n * See https://dev.mysql.com/doc/refman/5.7/en/update.html\n ***********************************************************************************/\nUpdateStmt:\n\t\"UPDATE\" TableOptimizerHints PriorityOpt IgnoreOptional TableRef \"SET\" AssignmentList WhereClauseOptional OrderByOptional LimitClause\n\t{\n\t\tvar refs *ast.Join\n\t\tif x, ok := $5.(*ast.Join); ok {\n\t\t\trefs = x\n\t\t} else {\n\t\t\trefs = &ast.Join{Left: $5.(ast.ResultSetNode)}\n\t\t}\n\t\tst := &ast.UpdateStmt{\n\t\t\tPriority:  $3.(mysql.PriorityEnum),\n\t\t\tTableRefs: &ast.TableRefsClause{TableRefs: refs},\n\t\t\tList:      $7.([]*ast.Assignment),\n\t\t\tIgnoreErr: $4.(bool),\n\t\t}\n\t\tif $2 != nil {\n\t\t\tst.TableHints = $2.([]*ast.TableOptimizerHint)\n\t\t}\n\t\tif $8 != nil {\n\t\t\tst.Where = $8.(ast.ExprNode)\n\t\t}\n\t\tif $9 != nil {\n\t\t\tst.Order = $9.(*ast.OrderByClause)\n\t\t}\n\t\tif $10 != nil {\n\t\t\tst.Limit = $10.(*ast.Limit)\n\t\t}\n\t\t$$ = st\n\t}\n|\t\"UPDATE\" TableOptimizerHints PriorityOpt IgnoreOptional TableRefs \"SET\" AssignmentList WhereClauseOptional\n\t{\n\t\tst := &ast.UpdateStmt{\n\t\t\tPriority:  $3.(mysql.PriorityEnum),\n\t\t\tTableRefs: &ast.TableRefsClause{TableRefs: $5.(*ast.Join)},\n\t\t\tList:      $7.([]*ast.Assignment),\n\t\t\tIgnoreErr: $4.(bool),\n\t\t}\n\t\tif $2 != nil {\n\t\t\tst.TableHints = $2.([]*ast.TableOptimizerHint)\n\t\t}\n\t\tif $8 != nil {\n\t\t\tst.Where = $8.(ast.ExprNode)\n\t\t}\n\t\t$$ = st\n\t}\n\nUseStmt:\n\t\"USE\" DBName\n\t{\n\t\t$$ = &ast.UseStmt{DBName: $2.(string)}\n\t}\n\nWhereClause:\n\t\"WHERE\" Expression\n\t{\n\t\t$$ = $2\n\t}\n\nWhereClauseOptional:\n\t{\n\t\t$$ = nil\n\t}\n|\tWhereClause\n\t{\n\t\t$$ = $1\n\t}\n\nCommaOpt:\n\t{}\n|\t','\n\t{}\n\n/************************************************************************************\n *  Account Management Statements\n *  https://dev.mysql.com/doc/refman/5.7/en/account-management-sql.html\n ************************************************************************************/\nCreateUserStmt:\n\t\"CREATE\" \"USER\" IfNotExists UserSpecList RequireClauseOpt EngineOpt\n\t{\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/create-user.html\n\t\t$$ = &ast.CreateUserStmt{\n\t\t\tIsCreateRole: false,\n\t\t\tIfNotExists:  $3.(bool),\n\t\t\tSpecs:        $4.([]*ast.UserSpec),\n\t\t\tTLSOptions:   $5.([]*ast.TLSOption),\n\t\t\tEngineOpt:    $6.(*ast.EngineOption),\n\t\t}\n\t}\n\nCreateRoleStmt:\n\t\"CREATE\" \"ROLE\" IfNotExists RoleSpecList\n\t{\n\t\t// See https://dev.mysql.com/doc/refman/8.0/en/create-role.html\n\t\t$$ = &ast.CreateUserStmt{\n\t\t\tIsCreateRole: true,\n\t\t\tIfNotExists:  $3.(bool),\n\t\t\tSpecs:        $4.([]*ast.UserSpec),\n\t\t}\n\t}\n\n/* See http://dev.mysql.com/doc/refman/5.7/en/alter-user.html */\nAlterUserStmt:\n\t\"ALTER\" \"USER\" IfExists UserSpecList RequireClauseOpt EngineOpt\n\t{\n\t\t$$ = &ast.AlterUserStmt{\n\t\t\tIfExists:   $3.(bool),\n\t\t\tSpecs:      $4.([]*ast.UserSpec),\n\t\t\tTLSOptions: $5.([]*ast.TLSOption),\n\t\t\tEngineOpt:  $6.(*ast.EngineOption),\n\t\t}\n\t}\n|\t\"ALTER\" \"USER\" IfExists \"USER\" '(' ')' \"IDENTIFIED\" \"BY\" AuthString\n\t{\n\t\tauth := &ast.AuthOption{\n\t\t\tAuthString:   $9.(string),\n\t\t\tByAuthString: true,\n\t\t}\n\t\t$$ = &ast.AlterUserStmt{\n\t\t\tIfExists:    $3.(bool),\n\t\t\tCurrentAuth: auth,\n\t\t}\n\t}\n\nUserSpec:\n\tUsername PartyCodeOption AuthOption\n\t{\n\t\tuserSpec := &ast.UserSpec{\n\t\t\tUser:      $1.(*auth.UserIdentity),\n\t\t\tPartyCode: $2.(string),\n\t\t}\n\t\tif $3 != nil {\n\t\t\tuserSpec.AuthOpt = $3.(*ast.AuthOption)\n\t\t}\n\t\t$$ = userSpec\n\t}\n\nUserSpecList:\n\tUserSpec\n\t{\n\t\t$$ = []*ast.UserSpec{$1.(*ast.UserSpec)}\n\t}\n|\tUserSpecList ',' UserSpec\n\t{\n\t\t$$ = append($1.([]*ast.UserSpec), $3.(*ast.UserSpec))\n\t}\n\nEngineOpt:\n\t{\n\t\t$$ = (*ast.EngineOption)(nil)\n\t}\n|\t\"WITH\" \"TOKEN\" stringLit EndpointOpt\n\t{\n\t\t$$ = &ast.EngineOption{\n\t\t\tTokenAuth:  &ast.TokenAuthOption{Token: $3},\n\t\t\tPubKeyAuth: nil,\n\t\t\tEndpoints:  $4.([]string),\n\t\t}\n\t}\n|\t\"WITH\" stringLit stringLit stringLit EndpointOpt\n\t{\n\t\t$$ = &ast.EngineOption{\n\t\t\tTokenAuth: nil,\n\t\t\tPubKeyAuth: &ast.PubKeyAuthOption{\n\t\t\t\tMessage:   $2,\n\t\t\t\tSignature: $3,\n\t\t\t\tPubKey:    $4,\n\t\t\t},\n\t\t\tEndpoints: $5.([]string),\n\t\t}\n\t}\n// NOTE: alter user stmt can only contain endpoint in engineOption\n|\t\"WITH\" \"ENDPOINT\" StringList\n\t{\n\t\t$$ = &ast.EngineOption{\n\t\t\tTokenAuth:  nil,\n\t\t\tPubKeyAuth: nil,\n\t\t\tEndpoints:  $3.([]string),\n\t\t}\n\t}\n\nEndpointOpt:\n\t{\n\t\tl := []string{}\n\t\t$$ = l\n\t}\n|\t\"ENDPOINT\" StringList\n\t{\n\t\t$$ = $2\n\t}\n\nConnectionOptions:\n\t{\n\t\tl := []*ast.ResourceOption{}\n\t\t$$ = l\n\t}\n|\t\"WITH\" ConnectionOptionList\n\t{\n\t\t$$ = $2\n\t\tyylex.AppendError(yylex.Errorf(\"TiDB does not support WITH ConnectionOptions now, they would be parsed but ignored.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n\nConnectionOptionList:\n\tConnectionOption\n\t{\n\t\t$$ = []*ast.ResourceOption{$1.(*ast.ResourceOption)}\n\t}\n|\tConnectionOptionList ConnectionOption\n\t{\n\t\tl := $1.([]*ast.ResourceOption)\n\t\tl = append(l, $2.(*ast.ResourceOption))\n\t\t$$ = l\n\t}\n\nConnectionOption:\n\t\"MAX_QUERIES_PER_HOUR\" NUM\n\t{\n\t\t$$ = &ast.ResourceOption{\n\t\t\tType:  ast.MaxQueriesPerHour,\n\t\t\tCount: $2.(int64),\n\t\t}\n\t}\n|\t\"MAX_UPDATES_PER_HOUR\" NUM\n\t{\n\t\t$$ = &ast.ResourceOption{\n\t\t\tType:  ast.MaxUpdatesPerHour,\n\t\t\tCount: $2.(int64),\n\t\t}\n\t}\n|\t\"MAX_CONNECTIONS_PER_HOUR\" NUM\n\t{\n\t\t$$ = &ast.ResourceOption{\n\t\t\tType:  ast.MaxConnectionsPerHour,\n\t\t\tCount: $2.(int64),\n\t\t}\n\t}\n|\t\"MAX_USER_CONNECTIONS\" NUM\n\t{\n\t\t$$ = &ast.ResourceOption{\n\t\t\tType:  ast.MaxUserConnections,\n\t\t\tCount: $2.(int64),\n\t\t}\n\t}\n\nRequireClauseOpt:\n\t{\n\t\t$$ = []*ast.TLSOption{}\n\t}\n|\tRequireClause\n\t{\n\t\t$$ = $1\n\t}\n\nRequireClause:\n\t\"REQUIRE\" \"NONE\"\n\t{\n\t\tt := &ast.TLSOption{\n\t\t\tType: ast.TslNone,\n\t\t}\n\t\t$$ = []*ast.TLSOption{t}\n\t}\n|\t\"REQUIRE\" \"SSL\"\n\t{\n\t\tt := &ast.TLSOption{\n\t\t\tType: ast.Ssl,\n\t\t}\n\t\t$$ = []*ast.TLSOption{t}\n\t}\n|\t\"REQUIRE\" \"X509\"\n\t{\n\t\tt := &ast.TLSOption{\n\t\t\tType: ast.X509,\n\t\t}\n\t\t$$ = []*ast.TLSOption{t}\n\t}\n|\t\"REQUIRE\" RequireList\n\t{\n\t\t$$ = $2\n\t}\n\nRequireList:\n\tRequireListElement\n\t{\n\t\t$$ = []*ast.TLSOption{$1.(*ast.TLSOption)}\n\t}\n|\tRequireList \"AND\" RequireListElement\n\t{\n\t\tl := $1.([]*ast.TLSOption)\n\t\tl = append(l, $3.(*ast.TLSOption))\n\t\t$$ = l\n\t}\n|\tRequireList RequireListElement\n\t{\n\t\tl := $1.([]*ast.TLSOption)\n\t\tl = append(l, $2.(*ast.TLSOption))\n\t\t$$ = l\n\t}\n\nRequireListElement:\n\t\"ISSUER\" stringLit\n\t{\n\t\t$$ = &ast.TLSOption{\n\t\t\tType:  ast.Issuer,\n\t\t\tValue: $2,\n\t\t}\n\t}\n|\t\"SUBJECT\" stringLit\n\t{\n\t\t$$ = &ast.TLSOption{\n\t\t\tType:  ast.Subject,\n\t\t\tValue: $2,\n\t\t}\n\t}\n|\t\"CIPHER\" stringLit\n\t{\n\t\t$$ = &ast.TLSOption{\n\t\t\tType:  ast.Cipher,\n\t\t\tValue: $2,\n\t\t}\n\t}\n\nPasswordOrLockOptions:\n\t{\n\t\tl := []*ast.PasswordOrLockOption{}\n\t\t$$ = l\n\t}\n|\tPasswordOrLockOptionList\n\t{\n\t\t$$ = $1\n\t\tyylex.AppendError(yylex.Errorf(\"TiDB does not support PASSWORD EXPIRE and ACCOUNT LOCK now, they would be parsed but ignored.\"))\n\t\tparser.lastErrorAsWarn()\n\t}\n\nPasswordOrLockOptionList:\n\tPasswordOrLockOption\n\t{\n\t\t$$ = []*ast.PasswordOrLockOption{$1.(*ast.PasswordOrLockOption)}\n\t}\n|\tPasswordOrLockOptionList PasswordOrLockOption\n\t{\n\t\tl := $1.([]*ast.PasswordOrLockOption)\n\t\tl = append(l, $2.(*ast.PasswordOrLockOption))\n\t\t$$ = l\n\t}\n\nPasswordOrLockOption:\n\t\"ACCOUNT\" \"UNLOCK\"\n\t{\n\t\t$$ = &ast.PasswordOrLockOption{\n\t\t\tType: ast.Unlock,\n\t\t}\n\t}\n|\t\"ACCOUNT\" \"LOCK\"\n\t{\n\t\t$$ = &ast.PasswordOrLockOption{\n\t\t\tType: ast.Lock,\n\t\t}\n\t}\n|\tPasswordExpire\n\t{\n\t\t$$ = &ast.PasswordOrLockOption{\n\t\t\tType: ast.PasswordExpire,\n\t\t}\n\t}\n|\tPasswordExpire \"INTERVAL\" NUM \"DAY\"\n\t{\n\t\t$$ = &ast.PasswordOrLockOption{\n\t\t\tType:  ast.PasswordExpireInterval,\n\t\t\tCount: $3.(int64),\n\t\t}\n\t}\n|\tPasswordExpire \"NEVER\"\n\t{\n\t\t$$ = &ast.PasswordOrLockOption{\n\t\t\tType: ast.PasswordExpireNever,\n\t\t}\n\t}\n|\tPasswordExpire \"DEFAULT\"\n\t{\n\t\t$$ = &ast.PasswordOrLockOption{\n\t\t\tType: ast.PasswordExpireDefault,\n\t\t}\n\t}\n\nPasswordExpire:\n\t\"PASSWORD\" \"EXPIRE\" ClearPasswordExpireOptions\n\t{\n\t\t$$ = nil\n\t}\n\nClearPasswordExpireOptions:\n\t{\n\t\t$$ = nil\n\t}\n\nAuthOption:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"IDENTIFIED\" \"BY\" AuthString\n\t{\n\t\t$$ = &ast.AuthOption{\n\t\t\tAuthString:   $3.(string),\n\t\t\tByAuthString: true,\n\t\t}\n\t}\n|\t\"IDENTIFIED\" \"WITH\" StringName\n\t{\n\t\t$$ = nil\n\t}\n|\t\"IDENTIFIED\" \"WITH\" StringName \"BY\" AuthString\n\t{\n\t\t$$ = &ast.AuthOption{\n\t\t\tAuthString:   $5.(string),\n\t\t\tByAuthString: true,\n\t\t}\n\t}\n|\t\"IDENTIFIED\" \"WITH\" StringName \"AS\" HashString\n\t{\n\t\t$$ = &ast.AuthOption{\n\t\t\tHashString: $5.(string),\n\t\t}\n\t}\n|\t\"IDENTIFIED\" \"BY\" \"PASSWORD\" HashString\n\t{\n\t\t$$ = &ast.AuthOption{\n\t\t\tHashString: $4.(string),\n\t\t}\n\t}\n\nPartyCodeOption:\n\t/*empty*/\n\t{\n\t\t$$ = \"\"\n\t}\n|\t\"PARTY_CODE\" PartyCodeString\n\t{\n\t\t$$ = $2.(string)\n\t}\n\nHashString:\n\tstringLit\n\t{\n\t\t$$ = $1\n\t}\n\nRoleSpec:\n\tRolename\n\t{\n\t\trole := $1.(*auth.RoleIdentity)\n\t\troleSpec := &ast.UserSpec{\n\t\t\tUser: &auth.UserIdentity{\n\t\t\t\tUsername: role.Username,\n\t\t\t\tHostname: role.Hostname,\n\t\t\t},\n\t\t\tIsRole: true,\n\t\t}\n\t\t$$ = roleSpec\n\t}\n\nRoleSpecList:\n\tRoleSpec\n\t{\n\t\t$$ = []*ast.UserSpec{$1.(*ast.UserSpec)}\n\t}\n|\tRoleSpecList ',' RoleSpec\n\t{\n\t\t$$ = append($1.([]*ast.UserSpec), $3.(*ast.UserSpec))\n\t}\n\n/*******************************************************************\n *\n *  Create Binding Statement\n *\n *  Example:\n *      CREATE GLOBAL BINDING FOR select Col1,Col2 from table USING select Col1,Col2 from table use index(Col1)\n *******************************************************************/\nCreateBindingStmt:\n\t\"CREATE\" GlobalScope \"BINDING\" \"FOR\" SelectStmt \"USING\" SelectStmt\n\t{\n\t\tstartOffset := parser.startOffset(&yyS[yypt-2])\n\t\tendOffset := parser.startOffset(&yyS[yypt-1])\n\t\tselStmt := $5.(*ast.SelectStmt)\n\t\tselStmt.SetText(strings.TrimSpace(parser.src[startOffset:endOffset]))\n\n\t\tstartOffset = parser.startOffset(&yyS[yypt])\n\t\thintedSelStmt := $7.(*ast.SelectStmt)\n\t\thintedSelStmt.SetText(strings.TrimSpace(parser.src[startOffset:]))\n\n\t\tx := &ast.CreateBindingStmt{\n\t\t\tOriginSel:   selStmt,\n\t\t\tHintedSel:   hintedSelStmt,\n\t\t\tGlobalScope: $2.(bool),\n\t\t}\n\n\t\t$$ = x\n\t}\n\n/*******************************************************************\n *\n *  Drop Binding Statement\n *\n *  Example:\n *      DROP GLOBAL BINDING FOR select Col1,Col2 from table\n *******************************************************************/\nDropBindingStmt:\n\t\"DROP\" GlobalScope \"BINDING\" \"FOR\" SelectStmt\n\t{\n\t\tstartOffset := parser.startOffset(&yyS[yypt])\n\t\tselStmt := $5.(*ast.SelectStmt)\n\t\tselStmt.SetText(strings.TrimSpace(parser.src[startOffset:]))\n\n\t\tx := &ast.DropBindingStmt{\n\t\t\tOriginSel:   selStmt,\n\t\t\tGlobalScope: $2.(bool),\n\t\t}\n\n\t\t$$ = x\n\t}\n|\t\"DROP\" GlobalScope \"BINDING\" \"FOR\" SelectStmt \"USING\" SelectStmt\n\t{\n\t\tstartOffset := parser.startOffset(&yyS[yypt-2])\n\t\tendOffset := parser.startOffset(&yyS[yypt-1])\n\t\tselStmt := $5.(*ast.SelectStmt)\n\t\tselStmt.SetText(strings.TrimSpace(parser.src[startOffset:endOffset]))\n\n\t\tstartOffset = parser.startOffset(&yyS[yypt])\n\t\thintedSelStmt := $7.(*ast.SelectStmt)\n\t\thintedSelStmt.SetText(strings.TrimSpace(parser.src[startOffset:]))\n\n\t\tx := &ast.DropBindingStmt{\n\t\t\tOriginSel:   selStmt,\n\t\t\tHintedSel:   hintedSelStmt,\n\t\t\tGlobalScope: $2.(bool),\n\t\t}\n\n\t\t$$ = x\n\t}\n\n/*************************************************************************************\n * Grant statement\n * See https://dev.mysql.com/doc/refman/5.7/en/grant.html\n *************************************************************************************/\nGrantStmt:\n\t\"GRANT\" PrivElemList \"ON\" ObjectType PrivLevel \"TO\" UserSpecList RequireClauseOpt WithGrantOptionOpt\n\t{\n\t\t$$ = &ast.GrantStmt{\n\t\t\tPrivs:      $2.([]*ast.PrivElem),\n\t\t\tObjectType: $4.(ast.ObjectTypeType),\n\t\t\tLevel:      $5.(*ast.GrantLevel),\n\t\t\tUsers:      $7.([]*ast.UserSpec),\n\t\t\tTLSOptions: $8.([]*ast.TLSOption),\n\t\t\tWithGrant:  $9.(bool),\n\t\t}\n\t}\n\nGrantRoleStmt:\n\t\"GRANT\" RolenameList \"TO\" UsernameList\n\t{\n\t\t$$ = &ast.GrantRoleStmt{\n\t\t\tRoles: $2.([]*auth.RoleIdentity),\n\t\t\tUsers: $4.([]*auth.UserIdentity),\n\t\t}\n\t}\n\nWithGrantOptionOpt:\n\t{\n\t\t$$ = false\n\t}\n|\t\"WITH\" \"GRANT\" \"OPTION\"\n\t{\n\t\t$$ = true\n\t}\n|\t\"WITH\" \"MAX_QUERIES_PER_HOUR\" NUM\n\t{\n\t\t$$ = false\n\t}\n|\t\"WITH\" \"MAX_UPDATES_PER_HOUR\" NUM\n\t{\n\t\t$$ = false\n\t}\n|\t\"WITH\" \"MAX_CONNECTIONS_PER_HOUR\" NUM\n\t{\n\t\t$$ = false\n\t}\n|\t\"WITH\" \"MAX_USER_CONNECTIONS\" NUM\n\t{\n\t\t$$ = false\n\t}\n\nPrivElem:\n\tPrivType\n\t{\n\t\t$$ = &ast.PrivElem{\n\t\t\tPriv: $1.(mysql.PrivilegeType),\n\t\t}\n\t}\n|\tPrivType '(' ColumnNameList ')'\n\t{\n\t\t$$ = &ast.PrivElem{\n\t\t\tPriv: $1.(mysql.PrivilegeType),\n\t\t\tCols: $3.([]*ast.ColumnName),\n\t\t}\n\t}\n\nPrivElemList:\n\tPrivElem\n\t{\n\t\t$$ = []*ast.PrivElem{$1.(*ast.PrivElem)}\n\t}\n|\tPrivElemList ',' PrivElem\n\t{\n\t\t$$ = append($1.([]*ast.PrivElem), $3.(*ast.PrivElem))\n\t}\n\nPrivType:\n\t\"ALL\"\n\t{\n\t\t$$ = mysql.AllPriv\n\t}\n|\t\"ALL\" \"PRIVILEGES\"\n\t{\n\t\t$$ = mysql.AllPriv\n\t}\n|\t\"ALTER\"\n\t{\n\t\t$$ = mysql.AlterPriv\n\t}\n|\t\"CREATE\"\n\t{\n\t\t$$ = mysql.CreatePriv\n\t}\n|\t\"CREATE\" \"USER\"\n\t{\n\t\t$$ = mysql.CreateUserPriv\n\t}\n|\t\"TRIGGER\"\n\t{\n\t\t$$ = mysql.TriggerPriv\n\t}\n|\t\"DELETE\"\n\t{\n\t\t$$ = mysql.DeletePriv\n\t}\n|\t\"DROP\"\n\t{\n\t\t$$ = mysql.DropPriv\n\t}\n|\t\"PROCESS\"\n\t{\n\t\t$$ = mysql.ProcessPriv\n\t}\n|\t\"EXECUTE\"\n\t{\n\t\t$$ = mysql.ExecutePriv\n\t}\n|\t\"INDEX\"\n\t{\n\t\t$$ = mysql.IndexPriv\n\t}\n|\t\"INSERT\"\n\t{\n\t\t$$ = mysql.InsertPriv\n\t}\n|\t\"SELECT\"\n\t{\n\t\t$$ = mysql.SelectPriv\n\t}\n|\t\"SUPER\"\n\t{\n\t\t$$ = mysql.SuperPriv\n\t}\n|\t\"SHOW\" \"DATABASES\"\n\t{\n\t\t$$ = mysql.ShowDBPriv\n\t}\n|\t\"UPDATE\"\n\t{\n\t\t$$ = mysql.UpdatePriv\n\t}\n|\t\"GRANT\" \"OPTION\"\n\t{\n\t\t$$ = mysql.GrantPriv\n\t}\n|\t\"REFERENCES\"\n\t{\n\t\t$$ = mysql.ReferencesPriv\n\t}\n|\t\"REPLICATION\" \"SLAVE\"\n\t{\n\t\t$$ = mysql.PrivilegeType(0)\n\t}\n|\t\"REPLICATION\" \"CLIENT\"\n\t{\n\t\t$$ = mysql.PrivilegeType(0)\n\t}\n|\t\"USAGE\"\n\t{\n\t\t$$ = mysql.PrivilegeType(0)\n\t}\n|\t\"RELOAD\"\n\t{\n\t\t$$ = mysql.ReloadPriv\n\t}\n|\t\"FILE\"\n\t{\n\t\t$$ = mysql.FilePriv\n\t}\n|\t\"CREATE\" \"TEMPORARY\" \"TABLES\"\n\t{\n\t\t$$ = mysql.CreateTMPTablePriv\n\t}\n|\t\"LOCK\" \"TABLES\"\n\t{\n\t\t$$ = mysql.LockTablesPriv\n\t}\n|\t\"CREATE\" \"VIEW\"\n\t{\n\t\t$$ = mysql.CreateViewPriv\n\t}\n|\t\"SHOW\" \"VIEW\"\n\t{\n\t\t$$ = mysql.ShowViewPriv\n\t}\n|\t\"CREATE\" \"ROLE\"\n\t{\n\t\t$$ = mysql.CreateRolePriv\n\t}\n|\t\"DROP\" \"ROLE\"\n\t{\n\t\t$$ = mysql.DropRolePriv\n\t}\n|\t\"CREATE\" \"ROUTINE\"\n\t{\n\t\t$$ = mysql.CreateRoutinePriv\n\t}\n|\t\"ALTER\" \"ROUTINE\"\n\t{\n\t\t$$ = mysql.AlterRoutinePriv\n\t}\n|\t\"EVENT\"\n\t{\n\t\t$$ = mysql.EventPriv\n\t}\n|\t\"SHUTDOWN\"\n\t{\n\t\t$$ = mysql.ShutdownPriv\n\t}\n|\t\"SELECT\" \"PLAINTEXT\"\n\t{\n\t\t$$ = mysql.PlaintextPriv\n\t}\n|\t\"SELECT\" \"PLAINTEXT_AFTER_JOIN\"\n\t{\n\t\t$$ = mysql.PlaintextAfterJoinPriv\n\t}\n|\t\"SELECT\" \"PLAINTEXT_AS_JOIN_PAYLOAD\"\n\t{\n\t\t$$ = mysql.PlaintextAsJoinPayloadPriv\n\t}\n|\t\"SELECT\" \"REVEAL_RANK\"\n\t{\n\t\t$$ = mysql.RevealRankPriv\n\t}\n|\t\"SELECT\" \"PLAINTEXT_AFTER_GROUP_BY\"\n\t{\n\t\t$$ = mysql.PlaintextAfterGroupByPriv\n\t}\n|\t\"SELECT\" \"PLAINTEXT_AFTER_COMPARE\"\n\t{\n\t\t$$ = mysql.PlaintextAfterComparePriv\n\t}\n|\t\"SELECT\" \"PLAINTEXT_AFTER_AGGREGATE\"\n\t{\n\t\t$$ = mysql.PlaintextAfterAggregatePriv\n\t}\n|\t\"SELECT\" \"ENCRYPTED_ONLY\"\n\t{\n\t\t$$ = mysql.EncryptedOnlyPriv\n\t}\n|\t\"SHOW\"\n\t{\n\t\t$$ = mysql.ShowPriv\n\t}\n|\t\"DESCRIBE\"\n\t{\n\t\t$$ = mysql.DescribePriv\n\t}\n\nObjectType:\n\t{\n\t\t$$ = ast.ObjectTypeNone\n\t}\n|\t\"TABLE\"\n\t{\n\t\t$$ = ast.ObjectTypeTable\n\t}\n\nPrivLevel:\n\t'*'\n\t{\n\t\t$$ = &ast.GrantLevel{\n\t\t\tLevel: ast.GrantLevelDB,\n\t\t}\n\t}\n|\t'*' '.' '*'\n\t{\n\t\t$$ = &ast.GrantLevel{\n\t\t\tLevel: ast.GrantLevelGlobal,\n\t\t}\n\t}\n|\tIdentifier '.' '*'\n\t{\n\t\t$$ = &ast.GrantLevel{\n\t\t\tLevel:  ast.GrantLevelDB,\n\t\t\tDBName: $1,\n\t\t}\n\t}\n|\tIdentifier '.' Identifier\n\t{\n\t\t$$ = &ast.GrantLevel{\n\t\t\tLevel:     ast.GrantLevelTable,\n\t\t\tDBName:    $1,\n\t\t\tTableName: $3,\n\t\t}\n\t}\n|\tIdentifier\n\t{\n\t\t$$ = &ast.GrantLevel{\n\t\t\tLevel:     ast.GrantLevelTable,\n\t\t\tTableName: $1,\n\t\t}\n\t}\n\n/**************************************RevokeStmt*******************************************\n * See https://dev.mysql.com/doc/refman/5.7/en/revoke.html\n *******************************************************************************************/\nRevokeStmt:\n\t\"REVOKE\" PrivElemList \"ON\" ObjectType PrivLevel \"FROM\" UserSpecList\n\t{\n\t\t$$ = &ast.RevokeStmt{\n\t\t\tPrivs:      $2.([]*ast.PrivElem),\n\t\t\tObjectType: $4.(ast.ObjectTypeType),\n\t\t\tLevel:      $5.(*ast.GrantLevel),\n\t\t\tUsers:      $7.([]*ast.UserSpec),\n\t\t}\n\t}\n\nRevokeRoleStmt:\n\t\"REVOKE\" RolenameList \"FROM\" UsernameList\n\t{\n\t\t$$ = &ast.RevokeRoleStmt{\n\t\t\tRoles: $2.([]*auth.RoleIdentity),\n\t\t\tUsers: $4.([]*auth.UserIdentity),\n\t\t}\n\t}\n\n/**************************************LoadDataStmt*****************************************\n * See https://dev.mysql.com/doc/refman/5.7/en/load-data.html\n *******************************************************************************************/\nLoadDataStmt:\n\t\"LOAD\" \"DATA\" LocalOpt \"INFILE\" stringLit DuplicateOpt \"INTO\" \"TABLE\" TableName CharsetOpt Fields Lines IgnoreLines ColumnNameOrUserVarListOptWithBrackets LoadDataSetSpecOpt\n\t{\n\t\tx := &ast.LoadDataStmt{\n\t\t\tPath:               $5,\n\t\t\tOnDuplicate:        $6.(ast.OnDuplicateKeyHandlingType),\n\t\t\tTable:              $9.(*ast.TableName),\n\t\t\tColumnsAndUserVars: $14.([]*ast.ColumnNameOrUserVar),\n\t\t\tIgnoreLines:        $13.(uint64),\n\t\t}\n\t\tif $3 != nil {\n\t\t\tx.IsLocal = true\n\t\t\t// See https://dev.mysql.com/doc/refman/5.7/en/load-data.html#load-data-duplicate-key-handling\n\t\t\t// If you do not specify IGNORE or REPLACE modifier , then we set default behavior to IGNORE when LOCAL modifier is specified\n\t\t\tif x.OnDuplicate == ast.OnDuplicateKeyHandlingError {\n\t\t\t\tx.OnDuplicate = ast.OnDuplicateKeyHandlingIgnore\n\t\t\t}\n\t\t}\n\t\tif $11 != nil {\n\t\t\tx.FieldsInfo = $11.(*ast.FieldsClause)\n\t\t}\n\t\tif $12 != nil {\n\t\t\tx.LinesInfo = $12.(*ast.LinesClause)\n\t\t}\n\t\tif $15 != nil {\n\t\t\tx.ColumnAssignments = $15.([]*ast.Assignment)\n\t\t}\n\t\tcolumns := []*ast.ColumnName{}\n\t\tfor _, v := range x.ColumnsAndUserVars {\n\t\t\tif v.ColumnName != nil {\n\t\t\t\tcolumns = append(columns, v.ColumnName)\n\t\t\t}\n\t\t}\n\t\tx.Columns = columns\n\n\t\t$$ = x\n\t}\n\nIgnoreLines:\n\t{\n\t\t$$ = uint64(0)\n\t}\n|\t\"IGNORE\" NUM \"LINES\"\n\t{\n\t\t$$ = getUint64FromNUM($2)\n\t}\n\nCharsetOpt:\n\t{}\n|\t\"CHARACTER\" \"SET\" CharsetName\n\nLocalOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"LOCAL\"\n\t{\n\t\t$$ = $1\n\t}\n\nFields:\n\t{\n\t\tescape := \"\\\\\"\n\t\t$$ = &ast.FieldsClause{\n\t\t\tTerminated: \"\\t\",\n\t\t\tEscaped:    escape[0],\n\t\t}\n\t}\n|\tFieldsOrColumns FieldItemList\n\t{\n\t\tfieldsClause := &ast.FieldsClause{\n\t\t\tTerminated: \"\\t\",\n\t\t\tEscaped:    []byte(\"\\\\\")[0],\n\t\t}\n\t\tfieldItems := $2.([]*ast.FieldItem)\n\t\tfor _, item := range fieldItems {\n\t\t\tswitch item.Type {\n\t\t\tcase ast.Terminated:\n\t\t\t\tfieldsClause.Terminated = item.Value\n\t\t\tcase ast.Enclosed:\n\t\t\t\tvar enclosed byte\n\t\t\t\tif len(item.Value) > 0 {\n\t\t\t\t\tenclosed = item.Value[0]\n\t\t\t\t}\n\t\t\t\tfieldsClause.Enclosed = enclosed\n\t\t\t\tif item.OptEnclosed {\n\t\t\t\t\tfieldsClause.OptEnclosed = true\n\t\t\t\t}\n\t\t\tcase ast.Escaped:\n\t\t\t\tvar escaped byte\n\t\t\t\tif len(item.Value) > 0 {\n\t\t\t\t\tescaped = item.Value[0]\n\t\t\t\t}\n\t\t\t\tfieldsClause.Escaped = escaped\n\t\t\t}\n\t\t}\n\t\t$$ = fieldsClause\n\t}\n\nFieldsOrColumns:\n\t\"FIELDS\"\n|\t\"COLUMNS\"\n\nFieldItemList:\n\tFieldItemList FieldItem\n\t{\n\t\tfieldItems := $1.([]*ast.FieldItem)\n\t\t$$ = append(fieldItems, $2.(*ast.FieldItem))\n\t}\n|\tFieldItem\n\t{\n\t\tfieldItems := make([]*ast.FieldItem, 1, 1)\n\t\tfieldItems[0] = $1.(*ast.FieldItem)\n\t\t$$ = fieldItems\n\t}\n\nFieldItem:\n\t\"TERMINATED\" \"BY\" FieldTerminator\n\t{\n\t\t$$ = &ast.FieldItem{\n\t\t\tType:  ast.Terminated,\n\t\t\tValue: $3.(string),\n\t\t}\n\t}\n|\t\"OPTIONALLY\" \"ENCLOSED\" \"BY\" FieldTerminator\n\t{\n\t\tstr := $4.(string)\n\t\tif str != \"\\\\\" && len(str) > 1 {\n\t\t\tyylex.AppendError(ErrWrongFieldTerminators.GenWithStackByArgs())\n\t\t\treturn 1\n\t\t}\n\t\t$$ = &ast.FieldItem{\n\t\t\tType:        ast.Enclosed,\n\t\t\tValue:       str,\n\t\t\tOptEnclosed: true,\n\t\t}\n\t}\n|\t\"ENCLOSED\" \"BY\" FieldTerminator\n\t{\n\t\tstr := $3.(string)\n\t\tif str != \"\\\\\" && len(str) > 1 {\n\t\t\tyylex.AppendError(ErrWrongFieldTerminators.GenWithStackByArgs())\n\t\t\treturn 1\n\t\t}\n\t\t$$ = &ast.FieldItem{\n\t\t\tType:  ast.Enclosed,\n\t\t\tValue: str,\n\t\t}\n\t}\n|\t\"ESCAPED\" \"BY\" FieldTerminator\n\t{\n\t\tstr := $3.(string)\n\t\tif str != \"\\\\\" && len(str) > 1 {\n\t\t\tyylex.AppendError(ErrWrongFieldTerminators.GenWithStackByArgs())\n\t\t\treturn 1\n\t\t}\n\t\t$$ = &ast.FieldItem{\n\t\t\tType:  ast.Escaped,\n\t\t\tValue: str,\n\t\t}\n\t}\n\nFieldTerminator:\n\tstringLit\n\t{\n\t\t$$ = $1\n\t}\n|\thexLit\n\t{\n\t\t$$ = $1.(ast.BinaryLiteral).ToString()\n\t}\n|\tbitLit\n\t{\n\t\t$$ = $1.(ast.BinaryLiteral).ToString()\n\t}\n\nLines:\n\t{\n\t\t$$ = &ast.LinesClause{Terminated: \"\\n\"}\n\t}\n|\t\"LINES\" Starting LinesTerminated\n\t{\n\t\t$$ = &ast.LinesClause{Starting: $2.(string), Terminated: $3.(string)}\n\t}\n\nStarting:\n\t{\n\t\t$$ = \"\"\n\t}\n|\t\"STARTING\" \"BY\" stringLit\n\t{\n\t\t$$ = $3\n\t}\n\nLinesTerminated:\n\t{\n\t\t$$ = \"\\n\"\n\t}\n|\t\"TERMINATED\" \"BY\" stringLit\n\t{\n\t\t$$ = $3\n\t}\n\nLoadDataSetSpecOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"SET\" LoadDataSetList\n\t{\n\t\t$$ = $2\n\t}\n\nLoadDataSetList:\n\tLoadDataSetList ',' LoadDataSetItem\n\t{\n\t\tl := $1.([]*ast.Assignment)\n\t\t$$ = append(l, $3.(*ast.Assignment))\n\t}\n|\tLoadDataSetItem\n\t{\n\t\t$$ = []*ast.Assignment{$1.(*ast.Assignment)}\n\t}\n\nLoadDataSetItem:\n\tSimpleIdent \"=\" ExprOrDefault\n\t{\n\t\t$$ = &ast.Assignment{\n\t\t\tColumn: $1.(*ast.ColumnNameExpr).Name,\n\t\t\tExpr:   $3,\n\t\t}\n\t}\n\n/*********************************************************************\n * Lock/Unlock Tables\n * See http://dev.mysql.com/doc/refman/5.7/en/lock-tables.html\n * All the statement leaves empty. This is used to prevent mysqldump error.\n *********************************************************************/\nUnlockTablesStmt:\n\t\"UNLOCK\" TablesTerminalSym\n\t{\n\t\t$$ = &ast.UnlockTablesStmt{}\n\t}\n\nLockTablesStmt:\n\t\"LOCK\" TablesTerminalSym TableLockList\n\t{\n\t\t$$ = &ast.LockTablesStmt{\n\t\t\tTableLocks: $3.([]ast.TableLock),\n\t\t}\n\t}\n\nTablesTerminalSym:\n\t\"TABLES\"\n|\t\"TABLE\"\n\nTableLock:\n\tTableName LockType\n\t{\n\t\t$$ = ast.TableLock{\n\t\t\tTable: $1.(*ast.TableName),\n\t\t\tType:  $2.(model.TableLockType),\n\t\t}\n\t}\n\nLockType:\n\t\"READ\"\n\t{\n\t\t$$ = model.TableLockRead\n\t}\n|\t\"READ\" \"LOCAL\"\n\t{\n\t\t$$ = model.TableLockReadLocal\n\t}\n|\t\"WRITE\"\n\t{\n\t\t$$ = model.TableLockWrite\n\t}\n|\t\"WRITE\" \"LOCAL\"\n\t{\n\t\t$$ = model.TableLockWriteLocal\n\t}\n\nTableLockList:\n\tTableLock\n\t{\n\t\t$$ = []ast.TableLock{$1.(ast.TableLock)}\n\t}\n|\tTableLockList ',' TableLock\n\t{\n\t\t$$ = append($1.([]ast.TableLock), $3.(ast.TableLock))\n\t}\n\n/********************************************************************\n * Kill Statement\n * See https://dev.mysql.com/doc/refman/5.7/en/kill.html\n *******************************************************************/\nKillStmt:\n\tKillOrKillTiDB NUM\n\t{\n\t\t$$ = &ast.KillStmt{\n\t\t\tConnectionID:  getUint64FromNUM($2),\n\t\t\tTiDBExtension: $1.(bool),\n\t\t}\n\t}\n|\tKillOrKillTiDB \"CONNECTION\" NUM\n\t{\n\t\t$$ = &ast.KillStmt{\n\t\t\tConnectionID:  getUint64FromNUM($3),\n\t\t\tTiDBExtension: $1.(bool),\n\t\t}\n\t}\n|\tKillOrKillTiDB \"QUERY\" NUM\n\t{\n\t\t$$ = &ast.KillStmt{\n\t\t\tConnectionID:  getUint64FromNUM($3),\n\t\t\tQuery:         true,\n\t\t\tTiDBExtension: $1.(bool),\n\t\t}\n\t}\n\nKillOrKillTiDB:\n\t\"KILL\"\n\t{\n\t\t$$ = false\n\t}\n/* KILL TIDB is a special grammar extension in TiDB, it can be used only when\n   the client connect to TiDB directly, not proxied under LVS. */\n|\t\"KILL\" \"TIDB\"\n\t{\n\t\t$$ = true\n\t}\n\nLoadStatsStmt:\n\t\"LOAD\" \"STATS\" stringLit\n\t{\n\t\t$$ = &ast.LoadStatsStmt{\n\t\t\tPath: $3,\n\t\t}\n\t}\n\n/********************************************************************************************\n *\n *  Create Sequence Statement\n *\n *  Example:\n *\tCREATE [TEMPORARY] SEQUENCE [IF NOT EXISTS] sequence_name\n *\t[ INCREMENT [ BY | = ] increment ]\n *\t[ MINVALUE [=] minvalue | NO MINVALUE | NOMINVALUE ]\n *\t[ MAXVALUE [=] maxvalue | NO MAXVALUE | NOMAXVALUE ]\n *\t[ START [ WITH | = ] start ]\n *\t[ CACHE [=] cache | NOCACHE | NO CACHE]\n *\t[ CYCLE | NOCYCLE | NO CYCLE]\n *\t[ ORDER | NOORDER | NO ORDER]\n *\t[table_options]\n ********************************************************************************************/\nCreateSequenceStmt:\n\t\"CREATE\" OptTemporary \"SEQUENCE\" IfNotExists TableName CreateSequenceOptionListOpt CreateTableOptionListOpt\n\t{\n\t\t$$ = &ast.CreateSequenceStmt{\n\t\t\tIsTemporary: $2.(bool),\n\t\t\tIfNotExists: $4.(bool),\n\t\t\tName:        $5.(*ast.TableName),\n\t\t\tSeqOptions:  $6.([]*ast.SequenceOption),\n\t\t\tTblOptions:  $7.([]*ast.TableOption),\n\t\t}\n\t}\n\nCreateSequenceOptionListOpt:\n\t{\n\t\t$$ = []*ast.SequenceOption{}\n\t}\n|\tSequenceOptionList\n\nSequenceOptionList:\n\tSequenceOption\n\t{\n\t\t$$ = []*ast.SequenceOption{$1.(*ast.SequenceOption)}\n\t}\n|\tSequenceOptionList SequenceOption\n\t{\n\t\t$$ = append($1.([]*ast.SequenceOption), $2.(*ast.SequenceOption))\n\t}\n\nSequenceOption:\n\t\"INCREMENT\" EqOpt SignedNum\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceOptionIncrementBy, IntValue: $3.(int64)}\n\t}\n|\t\"INCREMENT\" \"BY\" SignedNum\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceOptionIncrementBy, IntValue: $3.(int64)}\n\t}\n|\t\"START\" EqOpt SignedNum\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceStartWith, IntValue: $3.(int64)}\n\t}\n|\t\"START\" \"WITH\" SignedNum\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceStartWith, IntValue: $3.(int64)}\n\t}\n|\t\"MINVALUE\" EqOpt SignedNum\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceMinValue, IntValue: $3.(int64)}\n\t}\n|\t\"NOMINVALUE\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceNoMinValue}\n\t}\n|\t\"NO\" \"MINVALUE\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceNoMinValue}\n\t}\n|\t\"MAXVALUE\" EqOpt SignedNum\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceMaxValue, IntValue: $3.(int64)}\n\t}\n|\t\"NOMAXVALUE\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceNoMaxValue}\n\t}\n|\t\"NO\" \"MAXVALUE\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceNoMaxValue}\n\t}\n|\t\"CACHE\" EqOpt SignedNum\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceCache, IntValue: $3.(int64)}\n\t}\n|\t\"NOCACHE\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceNoCache}\n\t}\n|\t\"NO\" \"CACHE\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceNoCache}\n\t}\n|\t\"CYCLE\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceCycle}\n\t}\n|\t\"NOCYCLE\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceNoCycle}\n\t}\n|\t\"NO\" \"CYCLE\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceNoCycle}\n\t}\n|\t\"ORDER\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceOrder}\n\t}\n|\t\"NOORDER\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceNoOrder}\n\t}\n|\t\"NO\" \"ORDER\"\n\t{\n\t\t$$ = &ast.SequenceOption{Tp: ast.SequenceNoOrder}\n\t}\n\nSignedNum:\n\tNUM\n\t{\n\t\t$$ = $1.(int64)\n\t}\n|\t'+' NUM\n\t{\n\t\t$$ = $2.(int64)\n\t}\n|\t'-' NUM\n\t{\n\t\t$$ = -$2.(int64)\n\t}\n\nDropSequenceStmt:\n\t\"DROP\" OptTemporary \"SEQUENCE\" IfExists TableNameList\n\t{\n\t\t$$ = &ast.DropSequenceStmt{\n\t\t\tIsTemporary: $2.(bool),\n\t\t\tIfExists:    $4.(bool),\n\t\t\tSequences:   $5.([]*ast.TableName),\n\t\t}\n\t}\n\n/********************************************************************\n * Index Advisor Statement\n *\n * INDEX ADVISE\n * \t[LOCAL]\n *\tINFILE 'file_name'\n *\t[MAX_MINUTES number]\n *\t[MAX_IDXNUM\n *  \t[PER_TABLE number]\n *  \t[PER_DB number]\n *\t]\n *\t[LINES\n *  \t[STARTING BY 'string']\n *  \t[TERMINATED BY 'string']\n *\t]\n *******************************************************************/\nIndexAdviseStmt:\n\t\"INDEX\" \"ADVISE\" LocalOpt \"INFILE\" stringLit MaxMinutesOpt MaxIndexNumOpt Lines\n\t{\n\t\tx := &ast.IndexAdviseStmt{\n\t\t\tPath:       $5,\n\t\t\tMaxMinutes: $6.(uint64),\n\t\t}\n\t\tif $3 != nil {\n\t\t\tx.IsLocal = true\n\t\t}\n\t\tif $7 != nil {\n\t\t\tx.MaxIndexNum = $7.(*ast.MaxIndexNumClause)\n\t\t}\n\t\tif $8 != nil {\n\t\t\tx.LinesInfo = $8.(*ast.LinesClause)\n\t\t}\n\t\t$$ = x\n\t}\n\nMaxMinutesOpt:\n\t{\n\t\t$$ = uint64(ast.UnspecifiedSize)\n\t}\n|\t\"MAX_MINUTES\" NUM\n\t{\n\t\t$$ = getUint64FromNUM($2)\n\t}\n\nMaxIndexNumOpt:\n\t{\n\t\t$$ = nil\n\t}\n|\t\"MAX_IDXNUM\" PerTable PerDB\n\t{\n\t\t$$ = &ast.MaxIndexNumClause{\n\t\t\tPerTable: $2.(uint64),\n\t\t\tPerDB:    $3.(uint64),\n\t\t}\n\t}\n\nPerTable:\n\t{\n\t\t$$ = uint64(ast.UnspecifiedSize)\n\t}\n|\t\"PER_TABLE\" NUM\n\t{\n\t\t$$ = getUint64FromNUM($2)\n\t}\n\nPerDB:\n\t{\n\t\t$$ = uint64(ast.UnspecifiedSize)\n\t}\n|\t\"PER_DB\" NUM\n\t{\n\t\t$$ = getUint64FromNUM($2)\n\t}\n%%\n"
  },
  {
    "path": "pkg/parser/parser_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strings\"\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t. \"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\t\"github.com/secretflow/scql/pkg/parser/test_driver\"\n)\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nvar _ = Suite(&testParserSuite{})\n\ntype testParserSuite struct {\n\tenableWindowFunc bool\n}\n\nfunc (s *testParserSuite) TestSimple(c *C) {\n\tparser := parser.New()\n\n\treservedKws := []string{\n\t\t\"add\", \"all\", \"alter\", \"analyze\", \"and\", \"as\", \"asc\", \"between\", \"bigint\",\n\t\t\"binary\", \"blob\", \"both\", \"by\", \"cascade\", \"case\", \"change\", \"character\", \"check\", \"collate\",\n\t\t\"column\", \"constraint\", \"convert\", \"create\", \"cross\", \"current_date\", \"current_time\",\n\t\t\"current_timestamp\", \"current_user\", \"database\", \"databases\", \"day_hour\", \"day_microsecond\",\n\t\t\"day_minute\", \"day_second\", \"decimal\", \"default\", \"delete\", \"desc\", \"describe\",\n\t\t\"distinct\", \"distinctRow\", \"div\", \"double\", \"drop\", \"dual\", \"else\", \"enclosed\", \"escaped\",\n\t\t\"exists\", \"explain\", \"false\", \"float\", \"for\", \"force\", \"foreign\", \"from\",\n\t\t\"fulltext\", \"grant\", \"group\", \"having\", \"hour_microsecond\", \"hour_minute\",\n\t\t\"hour_second\", \"if\", \"ignore\", \"in\", \"index\", \"infile\", \"inner\", \"insert\", \"int\", \"into\", \"integer\",\n\t\t\"interval\", \"is\", \"join\", \"key\", \"keys\", \"kill\", \"leading\", \"left\", \"like\", \"limit\", \"lines\", \"load\",\n\t\t\"localtime\", \"localtimestamp\", \"lock\", \"longblob\", \"longtext\", \"mediumblob\", \"maxvalue\", \"mediumint\", \"mediumtext\",\n\t\t\"minute_microsecond\", \"minute_second\", \"mod\", \"not\", \"no_write_to_binlog\", \"null\", \"numeric\",\n\t\t\"on\", \"option\", \"optionally\", \"or\", \"order\", \"outer\", \"partition\", \"precision\", \"primary\", \"procedure\", \"range\", \"read\", \"real\",\n\t\t\"references\", \"regexp\", \"rename\", \"repeat\", \"replace\", \"revoke\", \"restrict\", \"right\", \"rlike\",\n\t\t\"schema\", \"schemas\", \"second_microsecond\", \"select\", \"set\", \"show\", \"smallint\",\n\t\t\"starting\", \"table\", \"terminated\", \"then\", \"tinyblob\", \"tinyint\", \"tinytext\", \"to\",\n\t\t\"trailing\", \"true\", \"union\", \"unique\", \"unlock\", \"unsigned\",\n\t\t\"update\", \"use\", \"using\", \"utc_date\", \"values\", \"varbinary\", \"varchar\",\n\t\t\"when\", \"where\", \"write\", \"xor\", \"year_month\", \"zerofill\",\n\t\t\"generated\", \"virtual\", \"stored\", \"usage\",\n\t\t\"delayed\", \"high_priority\", \"low_priority\",\n\t\t\"cumeDist\", \"denseRank\", \"firstValue\", \"lag\", \"lastValue\", \"lead\", \"nthValue\", \"ntile\",\n\t\t\"over\", \"percentRank\", \"rank\", \"row\", \"rows\", \"rowNumber\", \"window\", \"linear\",\n\t\t\"match\", \"until\",\n\t\t// TODO: support the following keywords\n\t\t// \"with\",\n\t}\n\tfor _, kw := range reservedKws {\n\t\tsrc := fmt.Sprintf(\"SELECT * FROM db.%s;\", kw)\n\t\t_, err := parser.ParseOneStmt(src, \"\", \"\")\n\t\tc.Assert(err, IsNil, Commentf(\"source %s\", src))\n\n\t\tsrc = fmt.Sprintf(\"SELECT * FROM %s.desc\", kw)\n\t\t_, err = parser.ParseOneStmt(src, \"\", \"\")\n\t\tc.Assert(err, IsNil, Commentf(\"source %s\", src))\n\n\t\tsrc = fmt.Sprintf(\"SELECT t.%s FROM t\", kw)\n\t\t_, err = parser.ParseOneStmt(src, \"\", \"\")\n\t\tc.Assert(err, IsNil, Commentf(\"source %s\", src))\n\t}\n\n\t// Testcase for unreserved keywords\n\tunreservedKws := []string{\n\t\t\"auto_increment\", \"after\", \"begin\", \"bit\", \"bool\", \"boolean\", \"charset\", \"columns\", \"commit\",\n\t\t\"date\", \"datediff\", \"datetime\", \"deallocate\", \"do\", \"from_days\", \"end\", \"engine\", \"engines\", \"execute\", \"extended\", \"first\", \"file\", \"full\",\n\t\t\"local\", \"names\", \"offset\", \"password\", \"prepare\", \"quick\", \"rollback\", \"session\", \"signed\",\n\t\t\"start\", \"global\", \"tables\", \"tablespace\", \"text\", \"time\", \"timestamp\", \"tidb\", \"transaction\", \"truncate\", \"unknown\",\n\t\t\"value\", \"warnings\", \"year\", \"now\", \"substr\", \"subpartition\", \"subpartitions\", \"substring\", \"mode\", \"any\", \"some\", \"user\", \"identified\",\n\t\t\"collation\", \"comment\", \"avg_row_length\", \"checksum\", \"compression\", \"connection\", \"key_block_size\",\n\t\t\"max_rows\", \"min_rows\", \"national\", \"quarter\", \"escape\", \"grants\", \"status\", \"fields\", \"triggers\", \"language\",\n\t\t\"delay_key_write\", \"isolation\", \"partitions\", \"repeatable\", \"committed\", \"uncommitted\", \"only\", \"serializable\", \"level\",\n\t\t\"curtime\", \"variables\", \"dayname\", \"version\", \"btree\", \"hash\", \"row_format\", \"dynamic\", \"fixed\", \"compressed\",\n\t\t\"compact\", \"redundant\", \"sql_no_cache sql_no_cache\", \"sql_cache sql_cache\", \"action\", \"round\",\n\t\t\"enable\", \"disable\", \"reverse\", \"space\", \"privileges\", \"get_lock\", \"release_lock\", \"sleep\", \"no\", \"greatest\", \"least\",\n\t\t\"binlog\", \"hex\", \"unhex\", \"function\", \"indexes\", \"from_unixtime\", \"processlist\", \"events\", \"less\", \"than\", \"timediff\",\n\t\t\"ln\", \"log\", \"log2\", \"log10\", \"timestampdiff\", \"pi\", \"quote\", \"none\", \"super\", \"shared\", \"exclusive\",\n\t\t\"always\", \"stats\", \"stats_meta\", \"stats_histogram\", \"stats_buckets\", \"stats_healthy\", \"tidb_version\", \"replication\", \"slave\", \"client\",\n\t\t\"max_connections_per_hour\", \"max_queries_per_hour\", \"max_updates_per_hour\", \"max_user_connections\", \"event\", \"reload\", \"routine\", \"temporary\",\n\t\t\"following\", \"preceding\", \"unbounded\", \"respect\", \"nulls\", \"current\", \"last\", \"against\", \"expansion\",\n\t}\n\tfor _, kw := range unreservedKws {\n\t\tsrc := fmt.Sprintf(\"SELECT %s FROM tbl;\", kw)\n\t\t_, err := parser.ParseOneStmt(src, \"\", \"\")\n\t\tc.Assert(err, IsNil, Commentf(\"source %s\", src))\n\t}\n\n\t// Testcase for prepared statement\n\tsrc := \"SELECT id+{{param1}}, id+{{param2}} from t;\"\n\t_, err := parser.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\n\t// // Testcase for -- Comment and unary -- operator\n\t// src = \"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED); -- foo\\nSelect --1 from foo;\"\n\t// stmts, _, err := parser.Parse(src, \"\", \"\")\n\t// c.Assert(err, IsNil)\n\t// c.Assert(stmts, HasLen, 2)\n\n\t// Testcase for /*! xx */\n\t// See http://dev.mysql.com/doc/refman/5.7/en/comments.html\n\t// Fix: https://github.com/pingcap/tidb/issues/971\n\tsrc = \"/*!40101 SET character_set_client = utf8 */;\"\n\tstmts, _, err := parser.Parse(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(stmts, HasLen, 1)\n\tstmt := stmts[0]\n\t_, ok := stmt.(*ast.SetStmt)\n\tc.Assert(ok, IsTrue)\n\n\t// for issue #2017\n\tsrc = \"insert into blobtable (a) values ('/*! truncated */');\"\n\tstmt, err = parser.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tis, ok := stmt.(*ast.InsertStmt)\n\tc.Assert(ok, IsTrue)\n\tc.Assert(is.Lists, HasLen, 1)\n\tc.Assert(is.Lists[0], HasLen, 1)\n\tc.Assert(is.Lists[0][0].(ast.ValueExpr).GetDatumString(), Equals, \"/*! truncated */\")\n\n\t// Testcase for CONVERT(expr,type)\n\tsrc = \"SELECT CONVERT('111', SIGNED);\"\n\tst, err := parser.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tss, ok := st.(*ast.SelectStmt)\n\tc.Assert(ok, IsTrue)\n\tc.Assert(len(ss.Fields.Fields), Equals, 1)\n\tcv, ok := ss.Fields.Fields[0].Expr.(*ast.FuncCastExpr)\n\tc.Assert(ok, IsTrue)\n\tc.Assert(cv.FunctionType, Equals, ast.CastConvertFunction)\n\n\t// for query start with comment\n\tsrcs := []string{\n\t\t\"/* some comments */ SELECT CONVERT('111', SIGNED) ;\",\n\t\t\"/* some comments */ /*comment*/ SELECT CONVERT('111', SIGNED) ;\",\n\t\t\"SELECT /*comment*/ CONVERT('111', SIGNED) ;\",\n\t\t\"SELECT CONVERT('111', /*comment*/ SIGNED) ;\",\n\t\t\"SELECT CONVERT('111', SIGNED) /*comment*/;\",\n\t}\n\tfor _, src := range srcs {\n\t\tst, err = parser.ParseOneStmt(src, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\t\tss, ok = st.(*ast.SelectStmt)\n\t\tc.Assert(ok, IsTrue)\n\t}\n\n\t// for issue #961\n\tsrc = \"create table t (c int key);\"\n\tst, err = parser.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tcs, ok := st.(*ast.CreateTableStmt)\n\tc.Assert(ok, IsTrue)\n\tc.Assert(cs.Cols, HasLen, 1)\n\tc.Assert(cs.Cols[0].Options, HasLen, 1)\n\tc.Assert(cs.Cols[0].Options[0].Tp, Equals, ast.ColumnOptionPrimaryKey)\n\n\t// // for issue #4497\n\t// src = \"create table t1(a NVARCHAR(100));\"\n\t// _, err = parser.ParseOneStmt(src, \"\", \"\")\n\t// c.Assert(err, IsNil)\n\n\t// for issue 2803\n\tsrc = \"use quote;\"\n\t_, err = parser.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\n\t// issue #4354\n\tsrc = \"select b'';\"\n\t_, err = parser.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\n\tsrc = \"select B'';\"\n\t_, err = parser.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\n\t// src = \"select 0b'';\"\n\t// _, err = parser.ParseOneStmt(src, \"\", \"\")\n\t// c.Assert(err, NotNil)\n\n\t// // for #4909, support numericType `signed` filedOpt.\n\t// src = \"CREATE TABLE t(_sms smallint signed, _smu smallint unsigned);\"\n\t// _, err = parser.ParseOneStmt(src, \"\", \"\")\n\t// c.Assert(err, IsNil)\n\n\t// // for #7371, support NATIONAL CHARACTER\n\t// // reference link: https://dev.mysql.com/doc/refman/5.7/en/charset-national.html\n\t// src = \"CREATE TABLE t(c1 NATIONAL CHARACTER(10));\"\n\t// _, err = parser.ParseOneStmt(src, \"\", \"\")\n\t// c.Assert(err, IsNil)\n\n\t// src = `CREATE TABLE t(a tinyint signed,\n\t// \tb smallint signed,\n\t// \tc mediumint signed,\n\t// \td int signed,\n\t// \te int1 signed,\n\t// \tf int2 signed,\n\t// \tg int3 signed,\n\t// \th int4 signed,\n\t// \ti int8 signed,\n\t// \tj integer signed,\n\t// \tk bigint signed,\n\t// \tl bool signed,\n\t// \tm boolean signed\n\t// \t);`\n\n\t// st, err = parser.ParseOneStmt(src, \"\", \"\")\n\t// c.Assert(err, IsNil)\n\t// ct, ok := st.(*ast.CreateTableStmt)\n\t// c.Assert(ok, IsTrue)\n\t// for _, col := range ct.Cols {\n\t// \tc.Assert(col.Tp.Flag&mysql.UnsignedFlag, Equals, uint(0))\n\t// }\n\n\t// for issue #4006\n\tsrc = `insert into tb(v) (select v from tb);`\n\t_, err = parser.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\n\t// for issue #9823\n\tsrc = \"SELECT 9223372036854775807;\"\n\tst, err = parser.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tsel, ok := st.(*ast.SelectStmt)\n\tc.Assert(ok, IsTrue)\n\texpr := sel.Fields.Fields[0]\n\tvExpr := expr.Expr.(*test_driver.ValueExpr)\n\tc.Assert(vExpr.Kind(), Equals, test_driver.KindInt64)\n\tsrc = \"SELECT 9223372036854775808;\"\n\tst, err = parser.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tsel, ok = st.(*ast.SelectStmt)\n\tc.Assert(ok, IsTrue)\n\texpr = sel.Fields.Fields[0]\n\tvExpr = expr.Expr.(*test_driver.ValueExpr)\n\tc.Assert(vExpr.Kind(), Equals, test_driver.KindUint64)\n}\n\nfunc (s *testParserSuite) TestSpecialComments(c *C) {\n\tparser := parser.New()\n\n\t// 1. Make sure /*! ... */ respects the same SQL mode.\n\t_, err := parser.ParseOneStmt(`SELECT /*! '\\' */;`, \"\", \"\")\n\tc.Assert(err, NotNil)\n\n\tparser.SetSQLMode(mysql.ModeNoBackslashEscapes)\n\tst, err := parser.ParseOneStmt(`SELECT /*! '\\' */;`, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(st, FitsTypeOf, &ast.SelectStmt{})\n\n\t// 2. Make sure multiple statements inside /*! ... */ will not crash\n\t// (this is issue #330)\n\tstmts, _, err := parser.Parse(\"/*! SET x = 1; SELECT 2 */\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(stmts, HasLen, 2)\n\tc.Assert(stmts[0], FitsTypeOf, &ast.SetStmt{})\n\tc.Assert(stmts[0].Text(), Equals, \"/*! SET x = 1;\")\n\tc.Assert(stmts[1], FitsTypeOf, &ast.SelectStmt{})\n\tc.Assert(stmts[1].Text(), Equals, \" SELECT 2 */\")\n\t// ^ not sure if correct approach; having multiple statements in MySQL is a syntax error.\n\n\t// 3. Make sure invalid text won't cause infinite loop\n\t// (this is issue #336)\n\tst, err = parser.ParseOneStmt(\"SELECT /*+ 😅 */ SLEEP(1);\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tsel, ok := st.(*ast.SelectStmt)\n\tc.Assert(ok, IsTrue)\n\tc.Assert(sel.TableHints, HasLen, 0)\n}\n\ntype testCase struct {\n\tsrc     string\n\tok      bool\n\trestore string\n}\n\ntype testErrMsgCase struct {\n\tsrc string\n\tok  bool\n\terr error\n}\n\nfunc (s *testParserSuite) RunTest(c *C, table []testCase) {\n\tparser := parser.New()\n\tparser.EnableWindowFunc(s.enableWindowFunc)\n\tfor _, t := range table {\n\t\t_, _, err := parser.Parse(t.src, \"\", \"\")\n\t\tcomment := Commentf(\"source %v\", t.src)\n\t\tif !t.ok {\n\t\t\tc.Assert(err, NotNil, comment)\n\t\t\tcontinue\n\t\t}\n\t\tc.Assert(err, IsNil, comment)\n\t\t// restore correctness test\n\t\tif t.ok {\n\t\t\ts.RunRestoreTest(c, t.src, t.restore)\n\t\t}\n\t}\n}\n\nfunc (s *testParserSuite) RunRestoreTest(c *C, sourceSQLs, expectSQLs string) {\n\tvar sb strings.Builder\n\tparser := parser.New()\n\tparser.EnableWindowFunc(s.enableWindowFunc)\n\tcomment := Commentf(\"source %v\", sourceSQLs)\n\tstmts, _, err := parser.Parse(sourceSQLs, \"\", \"\")\n\tc.Assert(err, IsNil, comment)\n\trestoreSQLs := \"\"\n\tfor _, stmt := range stmts {\n\t\tsb.Reset()\n\t\terr = stmt.Restore(NewRestoreCtx(DefaultRestoreFlags, &sb))\n\t\tc.Assert(err, IsNil, comment)\n\t\trestoreSQL := sb.String()\n\t\tcomment = Commentf(\"source %v; restore %v\", sourceSQLs, restoreSQL)\n\t\tc.Assert(err, IsNil, comment)\n\t\tif restoreSQLs != \"\" {\n\t\t\trestoreSQLs += \"; \"\n\t\t}\n\t\trestoreSQLs += restoreSQL\n\t}\n\tcomment = Commentf(\"restore %v; expect %v\", restoreSQLs, expectSQLs)\n\tc.Assert(restoreSQLs, Equals, expectSQLs, comment)\n}\n\nfunc (s *testParserSuite) RunTestInRealAsFloatMode(c *C, table []testCase) {\n\tparser := parser.New()\n\tparser.EnableWindowFunc(s.enableWindowFunc)\n\tparser.SetSQLMode(mysql.ModeRealAsFloat)\n\tfor _, t := range table {\n\t\t_, _, err := parser.Parse(t.src, \"\", \"\")\n\t\tcomment := Commentf(\"source %v\", t.src)\n\t\tif !t.ok {\n\t\t\tc.Assert(err, NotNil, comment)\n\t\t\tcontinue\n\t\t}\n\t\tc.Assert(err, IsNil, comment)\n\t\t// restore correctness test\n\t\tif t.ok {\n\t\t\ts.RunRestoreTestInRealAsFloatMode(c, t.src, t.restore)\n\t\t}\n\t}\n}\n\nfunc (s *testParserSuite) RunRestoreTestInRealAsFloatMode(c *C, sourceSQLs, expectSQLs string) {\n\tvar sb strings.Builder\n\tparser := parser.New()\n\tparser.EnableWindowFunc(s.enableWindowFunc)\n\tparser.SetSQLMode(mysql.ModeRealAsFloat)\n\tcomment := Commentf(\"source %v\", sourceSQLs)\n\tstmts, _, err := parser.Parse(sourceSQLs, \"\", \"\")\n\tc.Assert(err, IsNil, comment)\n\trestoreSQLs := \"\"\n\tfor _, stmt := range stmts {\n\t\tsb.Reset()\n\t\terr = stmt.Restore(NewRestoreCtx(DefaultRestoreFlags, &sb))\n\t\tc.Assert(err, IsNil, comment)\n\t\trestoreSQL := sb.String()\n\t\tcomment = Commentf(\"source %v; restore %v\", sourceSQLs, restoreSQL)\n\t\trestoreStmt, err := parser.ParseOneStmt(restoreSQL, \"\", \"\")\n\t\tc.Assert(err, IsNil, comment)\n\t\tCleanNodeText(stmt)\n\t\tCleanNodeText(restoreStmt)\n\t\tc.Assert(restoreStmt, DeepEquals, stmt, comment)\n\t\tif restoreSQLs != \"\" {\n\t\t\trestoreSQLs += \"; \"\n\t\t}\n\t\trestoreSQLs += restoreSQL\n\t}\n\tcomment = Commentf(\"restore %v; expect %v\", restoreSQLs, expectSQLs)\n\tc.Assert(restoreSQLs, Equals, expectSQLs, comment)\n}\n\nfunc (s *testParserSuite) RunErrMsgTest(c *C, table []testErrMsgCase) {\n\tparser := parser.New()\n\tfor _, t := range table {\n\t\t_, _, err := parser.Parse(t.src, \"\", \"\")\n\t\tcomment := Commentf(\"source %v\", t.src)\n\t\tif t.err != nil {\n\t\t\tc.Assert(terror.ErrorEqual(err, t.err), IsTrue, comment)\n\t\t} else {\n\t\t\tc.Assert(err, IsNil, comment)\n\t\t}\n\t}\n}\n\nfunc (s *testParserSuite) TestDMLStmt(c *C) {\n\ttable := []testCase{\n\t\t{\"\", true, \"\"},\n\t\t{\";\", true, \"\"},\n\t\t{\"INSERT INTO foo VALUES (1234)\", true, \"INSERT INTO `foo` VALUES (1234)\"},\n\t\t{\"INSERT INTO foo VALUES (1234, 5678)\", true, \"INSERT INTO `foo` VALUES (1234,5678)\"},\n\t\t{\"INSERT INTO t1 (SELECT * FROM t2)\", true, \"INSERT INTO `t1` SELECT * FROM `t2`\"},\n\t\t// 15\n\t\t{\"INSERT INTO foo VALUES (1 || 2)\", true, \"INSERT INTO `foo` VALUES (1 OR 2)\"},\n\t\t{\"INSERT INTO foo VALUES (1 | 2)\", true, \"INSERT INTO `foo` VALUES (1|2)\"},\n\t\t{\"INSERT INTO foo VALUES (false || true)\", true, \"INSERT INTO `foo` VALUES (FALSE OR TRUE)\"},\n\t\t{\"INSERT INTO foo VALUES (bar(5678))\", true, \"INSERT INTO `foo` VALUES (BAR(5678))\"},\n\t\t// 20\n\t\t{\"INSERT INTO foo VALUES ()\", true, \"INSERT INTO `foo` VALUES ()\"},\n\t\t{\"SELECT * FROM t\", true, \"SELECT * FROM `t`\"},\n\t\t{\"SELECT * FROM t AS u\", true, \"SELECT * FROM `t` AS `u`\"},\n\t\t// 25\n\t\t{\"SELECT * FROM t, v\", true, \"SELECT * FROM `t` JOIN `v`\"},\n\t\t{\"SELECT * FROM t AS u, v\", true, \"SELECT * FROM `t` AS `u` JOIN `v`\"},\n\t\t{\"SELECT * FROM t, v AS w\", true, \"SELECT * FROM `t` JOIN `v` AS `w`\"},\n\t\t{\"SELECT * FROM t AS u, v AS w\", true, \"SELECT * FROM `t` AS `u` JOIN `v` AS `w`\"},\n\t\t{\"SELECT * FROM foo, bar, foo\", true, \"SELECT * FROM (`foo` JOIN `bar`) JOIN `foo`\"},\n\t\t// 30\n\t\t{\"SELECT DISTINCTS * FROM t\", false, \"\"},\n\t\t{\"SELECT DISTINCT * FROM t\", true, \"SELECT DISTINCT * FROM `t`\"},\n\t\t{\"SELECT DISTINCTROW * FROM t\", true, \"SELECT DISTINCT * FROM `t`\"},\n\t\t{\"SELECT ALL * FROM t\", true, \"SELECT * FROM `t`\"},\n\t\t{\"SELECT DISTINCT ALL * FROM t\", false, \"\"},\n\t\t{\"SELECT DISTINCTROW ALL * FROM t\", false, \"\"},\n\t\t{\"INSERT INTO foo (a) VALUES (42)\", true, \"INSERT INTO `foo` (`a`) VALUES (42)\"},\n\t\t{\"INSERT INTO foo (a,) VALUES (42,)\", false, \"\"},\n\t\t// 35\n\t\t{\"INSERT INTO foo (a,b) VALUES (42,314)\", true, \"INSERT INTO `foo` (`a`,`b`) VALUES (42,314)\"},\n\t\t{\"INSERT INTO foo (a,b,) VALUES (42,314)\", false, \"\"},\n\t\t{\"INSERT INTO foo (a,b,) VALUES (42,314,)\", false, \"\"},\n\t\t{\"INSERT INTO foo () VALUES ()\", true, \"INSERT INTO `foo` () VALUES ()\"},\n\t\t{\"INSERT INTO foo VALUE ()\", true, \"INSERT INTO `foo` VALUES ()\"},\n\n\t\t// for issue 2402\n\t\t{\"INSERT INTO tt VALUES (01000001783);\", true, \"INSERT INTO `tt` VALUES (1000001783)\"},\n\t\t{\"INSERT INTO tt VALUES (default);\", true, \"INSERT INTO `tt` VALUES (DEFAULT)\"},\n\n\t\t{\"REPLACE INTO foo VALUES (1 || 2)\", true, \"REPLACE INTO `foo` VALUES (1 OR 2)\"},\n\t\t{\"REPLACE INTO foo VALUES (1 | 2)\", true, \"REPLACE INTO `foo` VALUES (1|2)\"},\n\t\t{\"REPLACE INTO foo VALUES (false || true)\", true, \"REPLACE INTO `foo` VALUES (FALSE OR TRUE)\"},\n\t\t{\"REPLACE INTO foo VALUES (bar(5678))\", true, \"REPLACE INTO `foo` VALUES (BAR(5678))\"},\n\t\t{\"REPLACE INTO foo VALUES ()\", true, \"REPLACE INTO `foo` VALUES ()\"},\n\t\t{\"REPLACE INTO foo (a,b) VALUES (42,314)\", true, \"REPLACE INTO `foo` (`a`,`b`) VALUES (42,314)\"},\n\t\t{\"REPLACE INTO foo (a,b,) VALUES (42,314)\", false, \"\"},\n\t\t{\"REPLACE INTO foo (a,b,) VALUES (42,314,)\", false, \"\"},\n\t\t{\"REPLACE INTO foo () VALUES ()\", true, \"REPLACE INTO `foo` () VALUES ()\"},\n\t\t{\"REPLACE INTO foo VALUE ()\", true, \"REPLACE INTO `foo` VALUES ()\"},\n\t\t// 40\n\t\t{`SELECT stuff.id\n\t\t\tFROM stuff\n\t\t\tWHERE stuff.value >= ALL (SELECT stuff.value\n\t\t\tFROM stuff)`, true, \"SELECT `stuff`.`id` FROM `stuff` WHERE `stuff`.`value`>=ALL (SELECT `stuff`.`value` FROM `stuff`)\"},\n\t\t{\"BEGIN\", true, \"START TRANSACTION\"},\n\t\t{\"START TRANSACTION\", true, \"START TRANSACTION\"},\n\t\t// 45\n\t\t{\"COMMIT\", true, \"COMMIT\"},\n\t\t{\"ROLLBACK\", true, \"ROLLBACK\"},\n\t\t{`BEGIN;\n\t\t\tINSERT INTO foo VALUES (42, 3.14);\n\t\t\tINSERT INTO foo VALUES (-1, 2.78);\n\t\tCOMMIT;`, true, \"START TRANSACTION; INSERT INTO `foo` VALUES (42,3.14); INSERT INTO `foo` VALUES (-1,2.78); COMMIT\"},\n\t\t{`BEGIN;\n\t\t\tINSERT INTO tmp SELECT * from bar;\n\t\t\tSELECT * from tmp;\n\t\tROLLBACK;`, true, \"START TRANSACTION; INSERT INTO `tmp` SELECT * FROM `bar`; SELECT * FROM `tmp`; ROLLBACK\"},\n\n\t\t// qualified select\n\t\t{\"SELECT a.b.c FROM t\", true, \"SELECT `a`.`b`.`c` FROM `t`\"},\n\t\t{\"SELECT a.b.*.c FROM t\", false, \"\"},\n\t\t{\"SELECT a.b.* FROM t\", true, \"SELECT `a`.`b`.* FROM `t`\"},\n\t\t{\"SELECT a FROM t\", true, \"SELECT `a` FROM `t`\"},\n\t\t{\"SELECT a.b.c.d FROM t\", false, \"\"},\n\n\t\t// do statement\n\t\t{\"DO 1\", true, \"DO 1\"},\n\t\t{\"DO 1, sleep(1)\", true, \"DO 1, SLEEP(1)\"},\n\t\t{\"DO 1 from t\", false, \"\"},\n\n\t\t// load data\n\t\t{\"load data local infile '/tmp/t.csv' into table t1 fields terminated by ',' optionally enclosed by '\\\"' ignore 1 lines\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t1` FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\\\"' IGNORE 1 LINES\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t`\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t character set utf8\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t`\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t fields terminated by 'ab'\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t` FIELDS TERMINATED BY 'ab'\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t columns terminated by 'ab'\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t` FIELDS TERMINATED BY 'ab'\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b'\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b'\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b' escaped by '*'\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b' ESCAPED BY '*'\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t lines starting by 'ab'\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t` LINES STARTING BY 'ab'\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t lines starting by 'ab' terminated by 'xy'\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t` LINES STARTING BY 'ab' TERMINATED BY 'xy'\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t fields terminated by 'ab' lines terminated by 'xy'\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t` FIELDS TERMINATED BY 'ab' LINES TERMINATED BY 'xy'\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t terminated by 'xy' fields terminated by 'ab'\", false, \"\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t`\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab'\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab'\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t columns terminated by 'ab'\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab'\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b'\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b'\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b' escaped by '*'\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b' ESCAPED BY '*'\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t character set utf8 fields terminated by 'ab' enclosed by 'b' escaped by '*'\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b' ESCAPED BY '*'\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t lines starting by 'ab'\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` LINES STARTING BY 'ab'\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t lines starting by 'ab' terminated by 'xy'\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` LINES STARTING BY 'ab' TERMINATED BY 'xy'\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' lines terminated by 'xy'\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' LINES TERMINATED BY 'xy'\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t terminated by 'xy' fields terminated by 'ab'\", false, \"\"},\n\t\t{\"load data infile '/tmp/t.csv' into table t (a,b)\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t` (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t columns terminated by 'ab' (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b' (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b' (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b' escaped by '*' (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b' ESCAPED BY '*' (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t character set utf8 fields terminated by 'ab' enclosed by 'b' escaped by '*' (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b' ESCAPED BY '*' (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t lines starting by 'ab' (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` LINES STARTING BY 'ab' (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t lines starting by 'ab' terminated by 'xy' (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` LINES STARTING BY 'ab' TERMINATED BY 'xy' (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t character set utf8 fields terminated by 'ab' lines terminated by 'xy' (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' LINES TERMINATED BY 'xy' (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' lines terminated by 'xy' (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' LINES TERMINATED BY 'xy' (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t (a,b) fields terminated by 'ab'\", false, \"\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t ignore 1 lines\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` IGNORE 1 LINES\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t ignore -1 lines\", false, \"\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b' (a,b) ignore 1 lines\", false, \"\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t lines starting by 'ab' terminated by 'xy' ignore 1 lines\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` LINES STARTING BY 'ab' TERMINATED BY 'xy' IGNORE 1 LINES\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b' escaped by '*' ignore 1 lines (a,b)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b' ESCAPED BY '*' IGNORE 1 LINES (`a`,`b`)\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b' escaped by ''\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b' ESCAPED BY ''\"},\n\t\t{\"load data local infile '~/1.csv' into table `t_ascii` fields terminated by X'6B6B';\", true, \"LOAD DATA LOCAL INFILE '~/1.csv' IGNORE INTO TABLE `t_ascii` FIELDS TERMINATED BY 'kk'\"},\n\t\t{\"load data local infile '~/1.csv' into table `t_ascii` fields terminated by X'6B6B' enclosed by X'0D';\", true, \"LOAD DATA LOCAL INFILE '~/1.csv' IGNORE INTO TABLE `t_ascii` FIELDS TERMINATED BY 'kk' ENCLOSED BY '\\r'\"},\n\t\t{\"load data local infile '~/1.csv' into table `t_ascii` fields terminated by X'6B6B' enclosed by X'0D0D';\", false, \"\"},\n\t\t{\"load data local infile '~/1.csv' into table `t_ascii` fields terminated by B'110101101101011';\", true, \"LOAD DATA LOCAL INFILE '~/1.csv' IGNORE INTO TABLE `t_ascii` FIELDS TERMINATED BY 'kk'\"},\n\t\t{\"load data local infile '~/1.csv' into table `t_ascii` fields terminated by B'110101101101011' enclosed by B'1101';\", true, \"LOAD DATA LOCAL INFILE '~/1.csv' IGNORE INTO TABLE `t_ascii` FIELDS TERMINATED BY 'kk' ENCLOSED BY '\\r'\"},\n\t\t{\"load data local infile '~/1.csv' into table `t_ascii` fields terminated by B'110101101101011' enclosed by B'110100001101';\", false, \"\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' enclosed by 'b' enclosed by 'b'\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b'\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' escaped by '' enclosed by 'b'\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b' ESCAPED BY ''\"},\n\t\t{\"load data local infile '/tmp/t.csv' into table t fields terminated by 'ab' escaped by '' enclosed by 'b' SET b = CAST(CONV(MID(@var1, 3, LENGTH(@var1)-3), 2, 10) AS UNSIGNED)\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t` FIELDS TERMINATED BY 'ab' ENCLOSED BY 'b' ESCAPED BY '' SET `b`=CAST(CONV(MID(@`var1`, 3, LENGTH(@`var1`)-3), 2, 10) AS UNSIGNED)\"},\n\n\t\t{\"LOAD DATA INFILE 'file.txt' INTO TABLE t1 (column1, @dummy, column2, @dummy, column3)\", true, \"LOAD DATA INFILE 'file.txt' INTO TABLE `t1` (`column1`,@`dummy`,`column2`,@`dummy`,`column3`)\"},\n\t\t{\"LOAD DATA INFILE 'file.txt' INTO TABLE t1 (column1, @var1) SET column2 = @var1/100\", true, \"LOAD DATA INFILE 'file.txt' INTO TABLE `t1` (`column1`,@`var1`) SET `column2`=@`var1`/100\"},\n\t\t{\"LOAD DATA INFILE 'file.txt' INTO TABLE t1 (column1, @var1, @var2) SET column2 = @var1/100, column3 = DEFAULT, column4=CURRENT_TIMESTAMP, column5=@var2+1\", true, \"LOAD DATA INFILE 'file.txt' INTO TABLE `t1` (`column1`,@`var1`,@`var2`) SET `column2`=@`var1`/100, `column3`=DEFAULT, `column4`=CURRENT_TIMESTAMP(), `column5`=@`var2`+1\"},\n\n\t\t{\"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE t1 FIELDS TERMINATED BY ',' LINES TERMINATED BY '\\n';\", true, \"LOAD DATA INFILE '/tmp/t.csv' INTO TABLE `t1` FIELDS TERMINATED BY ','\"},\n\t\t{\"LOAD DATA LOCAL INFILE '/tmp/t.csv' INTO TABLE t1 FIELDS TERMINATED BY ',' LINES TERMINATED BY '\\n';\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t1` FIELDS TERMINATED BY ','\"},\n\t\t{\"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE t1 FIELDS TERMINATED BY ',' LINES TERMINATED BY '\\n';\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t1` FIELDS TERMINATED BY ','\"},\n\t\t{\"LOAD DATA LOCAL INFILE '/tmp/t.csv' REPLACE INTO TABLE t1 FIELDS TERMINATED BY ',' LINES TERMINATED BY '\\n';\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' REPLACE INTO TABLE `t1` FIELDS TERMINATED BY ','\"},\n\n\t\t// select for update\n\t\t{\"SELECT * from t for update\", true, \"SELECT * FROM `t` FOR UPDATE\"},\n\t\t{\"SELECT * from t lock in share mode\", true, \"SELECT * FROM `t` LOCK IN SHARE MODE\"},\n\t\t{\"SELECT * from t for update nowait\", true, \"SELECT * FROM `t` FOR UPDATE NOWAIT\"},\n\n\t\t// select into outfile\n\t\t{\"select a, b from t into outfile '/tmp/result.txt'\", true, \"SELECT `a`,`b` FROM `t` INTO OUTFILE '/tmp/result.txt'\"},\n\t\t{\"select a from t order by a into outfile '/tmp/abc'\", true, \"SELECT `a` FROM `t` ORDER BY `a` INTO OUTFILE '/tmp/abc'\"},\n\t\t{\"select 1 into outfile '/tmp/1.csv'\", true, \"SELECT 1 INTO OUTFILE '/tmp/1.csv'\"},\n\t\t{\"select 1 for update into outfile '/tmp/1.csv'\", true, \"SELECT 1 FOR UPDATE INTO OUTFILE '/tmp/1.csv'\"},\n\t\t{\"select a,b,a+b from t into outfile '/tmp/result.txt' fields terminated BY ','\", true, \"SELECT `a`,`b`,`a`+`b` FROM `t` INTO OUTFILE '/tmp/result.txt' FIELDS TERMINATED BY ','\"},\n\t\t{\"select a,b,a+b from t into outfile '/tmp/result.txt' fields terminated BY ',' enclosed BY '\\\"'\", true, \"SELECT `a`,`b`,`a`+`b` FROM `t` INTO OUTFILE '/tmp/result.txt' FIELDS TERMINATED BY ',' ENCLOSED BY '\\\"'\"},\n\t\t{\"select a,b,a+b from t into outfile '/tmp/result.txt' fields terminated BY ',' optionally enclosed BY '\\\"'\", true, \"SELECT `a`,`b`,`a`+`b` FROM `t` INTO OUTFILE '/tmp/result.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\\\"'\"},\n\t\t{\"select a,b,a+b from t into outfile '/tmp/result.txt' lines terminated BY '\\n'\", true, \"SELECT `a`,`b`,`a`+`b` FROM `t` INTO OUTFILE '/tmp/result.txt'\"},\n\t\t{\"select a,b,a+b from t into outfile '/tmp/result.txt' fields terminated BY ',' optionally enclosed BY '\\\"' lines terminated BY '\\r'\", true, \"SELECT `a`,`b`,`a`+`b` FROM `t` INTO OUTFILE '/tmp/result.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\\\"' LINES TERMINATED BY '\\r'\"},\n\t\t{\"select a,b,a+b from t into outfile '/tmp/result.txt' fields terminated BY ',' enclosed BY '\\\"' lines terminated BY '\\r'\", true, \"SELECT `a`,`b`,`a`+`b` FROM `t` INTO OUTFILE '/tmp/result.txt' FIELDS TERMINATED BY ',' ENCLOSED BY '\\\"' LINES TERMINATED BY '\\r'\"},\n\t\t{\"select a,b,a+b from t into outfile '/tmp/result.txt' fields terminated BY ',' optionally enclosed BY '\\\"' lines starting by 'xy' terminated BY '\\r'\", true, \"SELECT `a`,`b`,`a`+`b` FROM `t` INTO OUTFILE '/tmp/result.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\\\"' LINES STARTING BY 'xy' TERMINATED BY '\\r'\"},\n\t\t{\"select a,b,a+b from t into outfile '/tmp/result.txt' fields terminated BY ',' enclosed BY '\\\"' lines starting by 'xy' terminated BY '\\r'\", true, \"SELECT `a`,`b`,`a`+`b` FROM `t` INTO OUTFILE '/tmp/result.txt' FIELDS TERMINATED BY ',' ENCLOSED BY '\\\"' LINES STARTING BY 'xy' TERMINATED BY '\\r'\"},\n\t\t{\"select a, b from t into outfile party_code 'alice' '/tmp/result.txt'\", true, \"SELECT `a`,`b` FROM `t` INTO OUTFILE PARTY_CODE 'alice' '/tmp/result.txt'\"},\n\n\t\t// from join\n\t\t{\"SELECT * from t1, t2, t3\", true, \"SELECT * FROM (`t1` JOIN `t2`) JOIN `t3`\"},\n\t\t{\"select * from t1 join t2 left join t3 on t2.id = t3.id\", true, \"SELECT * FROM (`t1` JOIN `t2`) LEFT JOIN `t3` ON `t2`.`id`=`t3`.`id`\"},\n\t\t{\"select * from t1 right join t2 on t1.id = t2.id left join t3 on t3.id = t2.id\", true, \"SELECT * FROM (`t1` RIGHT JOIN `t2` ON `t1`.`id`=`t2`.`id`) LEFT JOIN `t3` ON `t3`.`id`=`t2`.`id`\"},\n\t\t{\"select * from t1 right join t2 on t1.id = t2.id left join t3\", false, \"\"},\n\t\t{\"select * from t1 join t2 left join t3 using (id)\", true, \"SELECT * FROM (`t1` JOIN `t2`) LEFT JOIN `t3` USING (`id`)\"},\n\t\t{\"select * from t1 right join t2 using (id) left join t3 using (id)\", true, \"SELECT * FROM (`t1` RIGHT JOIN `t2` USING (`id`)) LEFT JOIN `t3` USING (`id`)\"},\n\t\t{\"select * from t1 right join t2 using (id) left join t3\", false, \"\"},\n\t\t{\"select * from t1 natural join t2\", true, \"SELECT * FROM `t1` NATURAL JOIN `t2`\"},\n\t\t{\"select * from t1 natural right join t2\", true, \"SELECT * FROM `t1` NATURAL JOIN `t2`\"},\n\t\t{\"select * from t1 natural left outer join t2\", true, \"SELECT * FROM `t1` NATURAL JOIN `t2`\"},\n\t\t{\"select * from t1 natural inner join t2\", false, \"\"},\n\t\t{\"select * from t1 natural cross join t2\", false, \"\"},\n\n\t\t// for straight_join\n\t\t{\"select * from t1 straight_join t2 on t1.id = t2.id\", true, \"SELECT * FROM `t1` STRAIGHT_JOIN `t2` ON `t1`.`id`=`t2`.`id`\"},\n\t\t{\"select straight_join * from t1 join t2 on t1.id = t2.id\", true, \"SELECT STRAIGHT_JOIN * FROM `t1` JOIN `t2` ON `t1`.`id`=`t2`.`id`\"},\n\t\t{\"select straight_join * from t1 left join t2 on t1.id = t2.id\", true, \"SELECT STRAIGHT_JOIN * FROM `t1` LEFT JOIN `t2` ON `t1`.`id`=`t2`.`id`\"},\n\t\t{\"select straight_join * from t1 right join t2 on t1.id = t2.id\", true, \"SELECT STRAIGHT_JOIN * FROM `t1` RIGHT JOIN `t2` ON `t1`.`id`=`t2`.`id`\"},\n\t\t{\"select straight_join * from t1 straight_join t2 on t1.id = t2.id\", true, \"SELECT STRAIGHT_JOIN * FROM `t1` STRAIGHT_JOIN `t2` ON `t1`.`id`=`t2`.`id`\"},\n\n\t\t// delete statement\n\t\t// single table syntax\n\t\t{\"DELETE from t1\", true, \"DELETE FROM `t1`\"},\n\t\t{\"DELETE from t1.*\", false, \"\"},\n\t\t{\"DELETE quick from t1\", true, \"DELETE QUICK FROM `t1`\"},\n\t\t{\"DELETE ignore from t1\", true, \"DELETE IGNORE FROM `t1`\"},\n\t\t{\"DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a\", true, \"DELETE FROM `t1` WHERE `t1`.`a`>0 ORDER BY `t1`.`a`\"},\n\t\t{\"delete from t1 where a=26\", true, \"DELETE FROM `t1` WHERE `a`=26\"},\n\t\t{\"DELETE from t1 where a=1 limit 1\", true, \"DELETE FROM `t1` WHERE `a`=1 LIMIT 1\"},\n\t\t{\"DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a LIMIT 1\", true, \"DELETE FROM `t1` WHERE `t1`.`a`>0 ORDER BY `t1`.`a` LIMIT 1\"},\n\t\t{\"DELETE FROM x.y z WHERE z.a > 0\", true, \"DELETE FROM `x`.`y` AS `z` WHERE `z`.`a`>0\"},\n\t\t{\"DELETE FROM t1 AS w WHERE a > 0\", true, \"DELETE FROM `t1` AS `w` WHERE `a`>0\"},\n\n\t\t// multi table syntax: before from\n\t\t{\"delete quick t1, t2 from t1, t2\", true, \"DELETE QUICK `t1`,`t2` FROM `t1` JOIN `t2`\"},\n\t\t{\"delete ignore t1, t2 from t1, t2\", true, \"DELETE IGNORE `t1`,`t2` FROM `t1` JOIN `t2`\"},\n\t\t{\"delete t1, t2 from t1, t2\", true, \"DELETE `t1`,`t2` FROM `t1` JOIN `t2`\"},\n\t\t{\"delete t1, t2 from t1, t2 where t1.a = 1 and t2.b <> 1\", true, \"DELETE `t1`,`t2` FROM `t1` JOIN `t2` WHERE `t1`.`a`=1 AND `t2`.`b`!=1\"},\n\t\t{\"delete t1 from t1, t2\", true, \"DELETE `t1` FROM `t1` JOIN `t2`\"},\n\t\t{\"delete t2 from t1, t2\", true, \"DELETE `t2` FROM `t1` JOIN `t2`\"},\n\t\t{\"delete t1 from t1\", true, \"DELETE `t1` FROM `t1`\"},\n\t\t{\"delete t1,t2,t3 from t1, t2, t3\", true, \"DELETE `t1`,`t2`,`t3` FROM (`t1` JOIN `t2`) JOIN `t3`\"},\n\t\t{\"delete t1,t2,t3 from t1, t2, t3 where t3.c < 5 and t1.a = 3\", true, \"DELETE `t1`,`t2`,`t3` FROM (`t1` JOIN `t2`) JOIN `t3` WHERE `t3`.`c`<5 AND `t1`.`a`=3\"},\n\t\t{\"delete t1 from t1, t1 as t2 where t1.b = t2.b and t1.a > t2.a\", true, \"DELETE `t1` FROM `t1` JOIN `t1` AS `t2` WHERE `t1`.`b`=`t2`.`b` AND `t1`.`a`>`t2`.`a`\"},\n\t\t{\"delete t1.*,t2 from t1, t2\", true, \"DELETE `t1`,`t2` FROM `t1` JOIN `t2`\"},\n\t\t{\"delete t.t1.*,t2 from t1, t2\", true, \"DELETE `t`.`t1`,`t2` FROM `t1` JOIN `t2`\"},\n\t\t{\"delete t1.*, t2.* from t1, t2\", true, \"DELETE `t1`,`t2` FROM `t1` JOIN `t2`\"},\n\t\t{\"delete t11.*, t12.* from t11, t12 where t11.a = t12.a and t11.b <> 1\", true, \"DELETE `t11`,`t12` FROM `t11` JOIN `t12` WHERE `t11`.`a`=`t12`.`a` AND `t11`.`b`!=1\"},\n\n\t\t// multi table syntax: with using\n\t\t{\"DELETE quick FROM t1,t2 USING t1,t2\", true, \"DELETE QUICK FROM `t1`,`t2` USING `t1` JOIN `t2`\"},\n\t\t{\"DELETE FROM t1 USING t1 WHERE post='1'\", true, \"DELETE FROM `t1` USING `t1` WHERE `post`='1'\"},\n\t\t{\"DELETE FROM t1,t2 USING t1,t2\", true, \"DELETE FROM `t1`,`t2` USING `t1` JOIN `t2`\"},\n\t\t{\"DELETE FROM t1,t2,t3 USING t1,t2,t3 where t3.a = 1\", true, \"DELETE FROM `t1`,`t2`,`t3` USING (`t1` JOIN `t2`) JOIN `t3` WHERE `t3`.`a`=1\"},\n\t\t{\"DELETE FROM t2,t3 USING t1,t2,t3 where t1.a = 1\", true, \"DELETE FROM `t2`,`t3` USING (`t1` JOIN `t2`) JOIN `t3` WHERE `t1`.`a`=1\"},\n\t\t{\"DELETE FROM t2.*,t3.* USING t1,t2,t3 where t1.a = 1\", true, \"DELETE FROM `t2`,`t3` USING (`t1` JOIN `t2`) JOIN `t3` WHERE `t1`.`a`=1\"},\n\t\t{\"DELETE FROM t1,t2.*,t3.* USING t1,t2,t3 where t1.a = 1\", true, \"DELETE FROM `t1`,`t2`,`t3` USING (`t1` JOIN `t2`) JOIN `t3` WHERE `t1`.`a`=1\"},\n\n\t\t// for delete statement\n\t\t{\"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;\", true, \"DELETE `t1`,`t2` FROM (`t1` JOIN `t2`) JOIN `t3` WHERE `t1`.`id`=`t2`.`id` AND `t2`.`id`=`t3`.`id`\"},\n\t\t{\"DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;\", true, \"DELETE FROM `t1`,`t2` USING (`t1` JOIN `t2`) JOIN `t3` WHERE `t1`.`id`=`t2`.`id` AND `t2`.`id`=`t3`.`id`\"},\n\t\t// for optimizer hint in delete statement\n\t\t{\"DELETE /*+ TiDB_INLJ(t1, t2) */ t1, t2 from t1, t2 where t1.id=t2.id;\", true, \"DELETE /*+ TIDB_INLJ(`t1`, `t2`)*/ `t1`,`t2` FROM `t1` JOIN `t2` WHERE `t1`.`id`=`t2`.`id`\"},\n\t\t{\"DELETE /*+ TiDB_HJ(t1, t2) */ t1, t2 from t1, t2 where t1.id=t2.id\", true, \"DELETE /*+ TIDB_HJ(`t1`, `t2`)*/ `t1`,`t2` FROM `t1` JOIN `t2` WHERE `t1`.`id`=`t2`.`id`\"},\n\t\t{\"DELETE /*+ TiDB_SMJ(t1, t2) */ t1, t2 from t1, t2 where t1.id=t2.id\", true, \"DELETE /*+ TIDB_SMJ(`t1`, `t2`)*/ `t1`,`t2` FROM `t1` JOIN `t2` WHERE `t1`.`id`=`t2`.`id`\"},\n\t\t// for \"USE INDEX\" in delete statement\n\t\t{\"DELETE FROM t1 USE INDEX(idx_a) WHERE t1.id=1;\", true, \"DELETE FROM `t1` USE INDEX (`idx_a`) WHERE `t1`.`id`=1\"},\n\t\t{\"DELETE t1, t2 FROM t1 USE INDEX(idx_a) JOIN t2 WHERE t1.id=t2.id;\", true, \"DELETE `t1`,`t2` FROM `t1` USE INDEX (`idx_a`) JOIN `t2` WHERE `t1`.`id`=`t2`.`id`\"},\n\t\t{\"DELETE t1, t2 FROM t1 USE INDEX(idx_a) JOIN t2 USE INDEX(idx_a) WHERE t1.id=t2.id;\", true, \"DELETE `t1`,`t2` FROM `t1` USE INDEX (`idx_a`) JOIN `t2` USE INDEX (`idx_a`) WHERE `t1`.`id`=`t2`.`id`\"},\n\n\t\t// for fail case\n\t\t{\"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id limit 10;\", false, \"\"},\n\t\t{\"DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id order by t1.id;\", false, \"\"},\n\n\t\t// for admin\n\t\t{\"admin show ddl;\", true, \"ADMIN SHOW DDL\"},\n\t\t{\"admin show ddl jobs;\", true, \"ADMIN SHOW DDL JOBS\"},\n\t\t{\"admin show ddl jobs where id > 0;\", true, \"ADMIN SHOW DDL JOBS WHERE `id`>0\"},\n\t\t{\"admin show ddl jobs 20 where id=0;\", true, \"ADMIN SHOW DDL JOBS 20 WHERE `id`=0\"},\n\t\t{\"admin show ddl jobs -1;\", false, \"\"},\n\t\t{\"admin show ddl job queries 1\", true, \"ADMIN SHOW DDL JOB QUERIES 1\"},\n\t\t{\"admin show ddl job queries 1, 2, 3, 4\", true, \"ADMIN SHOW DDL JOB QUERIES 1, 2, 3, 4\"},\n\t\t{\"admin show t1 next_row_id\", true, \"ADMIN SHOW `t1` NEXT_ROW_ID\"},\n\t\t{\"admin check table t1, t2;\", true, \"ADMIN CHECK TABLE `t1`, `t2`\"},\n\t\t{\"admin check index tableName idxName;\", true, \"ADMIN CHECK INDEX `tableName` idxName\"},\n\t\t{\"admin check index tableName idxName (1, 2), (4, 5);\", true, \"ADMIN CHECK INDEX `tableName` idxName (1,2), (4,5)\"},\n\t\t{\"admin checksum table t1, t2;\", true, \"ADMIN CHECKSUM TABLE `t1`, `t2`\"},\n\t\t{\"admin cancel ddl jobs 1\", true, \"ADMIN CANCEL DDL JOBS 1\"},\n\t\t{\"admin cancel ddl jobs 1, 2\", true, \"ADMIN CANCEL DDL JOBS 1, 2\"},\n\t\t{\"admin recover index t1 idx_a\", true, \"ADMIN RECOVER INDEX `t1` idx_a\"},\n\t\t{\"admin cleanup index t1 idx_a\", true, \"ADMIN CLEANUP INDEX `t1` idx_a\"},\n\t\t{\"admin show slow top 3\", true, \"ADMIN SHOW SLOW TOP 3\"},\n\t\t{\"admin show slow top internal 7\", true, \"ADMIN SHOW SLOW TOP INTERNAL 7\"},\n\t\t{\"admin show slow top all 9\", true, \"ADMIN SHOW SLOW TOP ALL 9\"},\n\t\t{\"admin show slow recent 11\", true, \"ADMIN SHOW SLOW RECENT 11\"},\n\t\t{\"admin reload expr_pushdown_blacklist\", true, \"ADMIN RELOAD EXPR_PUSHDOWN_BLACKLIST\"},\n\t\t{\"admin plugins disable audit, whitelist\", true, \"ADMIN PLUGINS DISABLE audit, whitelist\"},\n\t\t{\"admin plugins enable audit, whitelist\", true, \"ADMIN PLUGINS ENABLE audit, whitelist\"},\n\t\t{\"admin flush bindings\", true, \"ADMIN FLUSH BINDINGS\"},\n\t\t{\"admin capture bindings\", true, \"ADMIN CAPTURE BINDINGS\"},\n\t\t{\"admin evolve bindings\", true, \"ADMIN EVOLVE BINDINGS\"},\n\n\t\t// for on duplicate key update\n\t\t{\"INSERT INTO t (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);\", true, \"INSERT INTO `t` (`a`,`b`,`c`) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE `c`=VALUES(`a`)+VALUES(`b`)\"},\n\t\t{\"INSERT IGNORE INTO t (a,b,c) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);\", true, \"INSERT IGNORE INTO `t` (`a`,`b`,`c`) VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE `c`=VALUES(`a`)+VALUES(`b`)\"},\n\n\t\t// for insert ... set\n\t\t{\"INSERT INTO t SET a=1,b=2\", true, \"INSERT INTO `t` SET `a`=1,`b`=2\"},\n\t\t{\"INSERT INTO t (a) SET a=1\", false, \"\"},\n\n\t\t// for update statement\n\t\t{\"UPDATE t SET id = id + 1 ORDER BY id DESC;\", true, \"UPDATE `t` SET `id`=`id`+1 ORDER BY `id` DESC\"},\n\t\t{\"UPDATE t SET id = id + 1 ORDER BY id DESC limit 3 ;\", true, \"UPDATE `t` SET `id`=`id`+1 ORDER BY `id` DESC LIMIT 3\"},\n\t\t{\"UPDATE t SET id = id + 1, name = 'jojo';\", true, \"UPDATE `t` SET `id`=`id`+1, `name`='jojo'\"},\n\t\t{\"UPDATE items,month SET items.price=month.price WHERE items.id=month.id;\", true, \"UPDATE `items` JOIN `month` SET `items`.`price`=`month`.`price` WHERE `items`.`id`=`month`.`id`\"},\n\t\t{\"UPDATE user T0 LEFT OUTER JOIN user_profile T1 ON T1.id = T0.profile_id SET T0.profile_id = 1 WHERE T0.profile_id IN (1);\", true, \"UPDATE `user` AS `T0` LEFT JOIN `user_profile` AS `T1` ON `T1`.`id`=`T0`.`profile_id` SET `T0`.`profile_id`=1 WHERE `T0`.`profile_id` IN (1)\"},\n\t\t{\"UPDATE t1, t2 set t1.profile_id = 1, t2.profile_id = 1 where ta.a=t.ba\", true, \"UPDATE `t1` JOIN `t2` SET `t1`.`profile_id`=1, `t2`.`profile_id`=1 WHERE `ta`.`a`=`t`.`ba`\"},\n\t\t// for optimizer hint in update statement\n\t\t{\"UPDATE /*+ TiDB_INLJ(t1, t2) */ t1, t2 set t1.profile_id = 1, t2.profile_id = 1 where ta.a=t.ba\", true, \"UPDATE /*+ TIDB_INLJ(`t1`, `t2`)*/ `t1` JOIN `t2` SET `t1`.`profile_id`=1, `t2`.`profile_id`=1 WHERE `ta`.`a`=`t`.`ba`\"},\n\t\t{\"UPDATE /*+ TiDB_SMJ(t1, t2) */ t1, t2 set t1.profile_id = 1, t2.profile_id = 1 where ta.a=t.ba\", true, \"UPDATE /*+ TIDB_SMJ(`t1`, `t2`)*/ `t1` JOIN `t2` SET `t1`.`profile_id`=1, `t2`.`profile_id`=1 WHERE `ta`.`a`=`t`.`ba`\"},\n\t\t{\"UPDATE /*+ TiDB_HJ(t1, t2) */ t1, t2 set t1.profile_id = 1, t2.profile_id = 1 where ta.a=t.ba\", true, \"UPDATE /*+ TIDB_HJ(`t1`, `t2`)*/ `t1` JOIN `t2` SET `t1`.`profile_id`=1, `t2`.`profile_id`=1 WHERE `ta`.`a`=`t`.`ba`\"},\n\t\t// fail case for update statement\n\t\t{\"UPDATE items,month SET items.price=month.price WHERE items.id=month.id LIMIT 10;\", false, \"\"},\n\t\t{\"UPDATE items,month SET items.price=month.price WHERE items.id=month.id order by month.id;\", false, \"\"},\n\t\t// for \"USE INDEX\" in delete statement\n\t\t{\"UPDATE t1 USE INDEX(idx_a) SET t1.price=3.25 WHERE t1.id=1;\", true, \"UPDATE `t1` USE INDEX (`idx_a`) SET `t1`.`price`=3.25 WHERE `t1`.`id`=1\"},\n\t\t{\"UPDATE t1 USE INDEX(idx_a) JOIN t2 SET t1.price=t2.price WHERE t1.id=t2.id;\", true, \"UPDATE `t1` USE INDEX (`idx_a`) JOIN `t2` SET `t1`.`price`=`t2`.`price` WHERE `t1`.`id`=`t2`.`id`\"},\n\t\t{\"UPDATE t1 USE INDEX(idx_a) JOIN t2 USE INDEX(idx_a) SET t1.price=t2.price WHERE t1.id=t2.id;\", true, \"UPDATE `t1` USE INDEX (`idx_a`) JOIN `t2` USE INDEX (`idx_a`) SET `t1`.`price`=`t2`.`price` WHERE `t1`.`id`=`t2`.`id`\"},\n\n\t\t// for select with where clause\n\t\t{\"SELECT * FROM t WHERE 1 = 1\", true, \"SELECT * FROM `t` WHERE 1=1\"},\n\n\t\t// for dual\n\t\t{\"select 1 from dual\", true, \"SELECT 1\"},\n\t\t{\"select 1 from dual limit 1\", true, \"SELECT 1 LIMIT 1\"},\n\t\t{\"select 1 where exists (select 2)\", false, \"\"},\n\t\t{\"select 1 from dual where not exists (select 2)\", true, \"SELECT 1 FROM DUAL WHERE NOT EXISTS (SELECT 2)\"},\n\t\t{\"select 1 as a from dual order by a\", true, \"SELECT 1 AS `a` ORDER BY `a`\"},\n\t\t{\"select 1 as a from dual where 1 < any (select 2) order by a\", true, \"SELECT 1 AS `a` FROM DUAL WHERE 1<ANY (SELECT 2) ORDER BY `a`\"},\n\t\t{\"select 1 order by 1\", true, \"SELECT 1 ORDER BY 1\"},\n\n\t\t// for https://github.com/pingcap/tidb/issues/320\n\t\t{`(select 1);`, true, \"SELECT 1\"},\n\n\t\t// for https://github.com/pingcap/tidb/issues/1050\n\t\t{`SELECT /*!40001 SQL_NO_CACHE */ * FROM test WHERE 1 limit 0, 2000;`, true, \"SELECT SQL_NO_CACHE * FROM `test` WHERE 1 LIMIT 2000 OFFSET 0\"},\n\n\t\t{`ANALYZE TABLE t`, true, \"ANALYZE TABLE `t`\"},\n\n\t\t// for comments\n\t\t{`/** 20180417 **/ show databases;`, true, \"SHOW DATABASES\"},\n\t\t{`/* 20180417 **/ show databases;`, true, \"SHOW DATABASES\"},\n\t\t{`/** 20180417 */ show databases;`, true, \"SHOW DATABASES\"},\n\t\t{`/** 20180417 ******/ show databases;`, true, \"SHOW DATABASES\"},\n\t\t{`/**/show databases;`, true, \"SHOW DATABASES\"},\n\t\t{`/*+*/show databases;`, true, \"SHOW DATABASES\"},\n\t\t{`select/*+*/1;`, true, \"SELECT 1\"},\n\t\t{`/*T*/show databases;`, true, \"SHOW DATABASES\"},\n\t\t{`/*M*/show databases;`, true, \"SHOW DATABASES\"},\n\t\t{`/*!*/show databases;`, true, \"SHOW DATABASES\"},\n\t\t{`/*T!*/show databases;`, true, \"SHOW DATABASES\"},\n\t\t{`/*M!*/show databases;`, true, \"SHOW DATABASES\"},\n\n\t\t// for Binlog stmt\n\t\t{`BINLOG '\nBxSFVw8JAAAA8QAAAPUAAAAAAAQANS41LjQ0LU1hcmlhREItbG9nAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA2QAEGggAAAAICAgCAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAA5gm5Mg==\n'/*!*/;`, true, `BINLOG '\nBxSFVw8JAAAA8QAAAPUAAAAAAAQANS41LjQ0LU1hcmlhREItbG9nAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA2QAEGggAAAAICAgCAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAA5gm5Mg==\n'`},\n\n\t\t// for partition table dml\n\t\t{\"select * from t1 partition (p1)\", true, \"SELECT * FROM `t1` PARTITION(`p1`)\"},\n\t\t{\"select * from t1 partition (p1,p2)\", true, \"SELECT * FROM `t1` PARTITION(`p1`, `p2`)\"},\n\t\t{\"select * from t1 partition (`p1`, p2, p3)\", true, \"SELECT * FROM `t1` PARTITION(`p1`, `p2`, `p3`)\"},\n\t\t{`select * from t1 partition ()`, false, \"\"},\n\n\t\t// for split table index region syntax\n\t\t{\"split table t1 index idx1 by ('a'),('b'),('c')\", true, \"SPLIT TABLE `t1` INDEX `idx1` BY ('a'),('b'),('c')\"},\n\t\t{\"split table t1 index idx1 by (1)\", true, \"SPLIT TABLE `t1` INDEX `idx1` BY (1)\"},\n\t\t{\"split table t1 index idx1 by ('abc',123), ('xyz'), ('yz', 1000)\", true, \"SPLIT TABLE `t1` INDEX `idx1` BY ('abc',123),('xyz'),('yz',1000)\"},\n\t\t{\"split table t1 index idx1 by \", false, \"\"},\n\t\t{\"split table t1 index idx1 between ('a') and ('z') regions 10\", true, \"SPLIT TABLE `t1` INDEX `idx1` BETWEEN ('a') AND ('z') REGIONS 10\"},\n\t\t{\"split table t1 index idx1 between ('a',1) and ('z',2) regions 10\", true, \"SPLIT TABLE `t1` INDEX `idx1` BETWEEN ('a',1) AND ('z',2) REGIONS 10\"},\n\t\t{\"split table t1 index idx1 between () and () regions 10\", true, \"SPLIT TABLE `t1` INDEX `idx1` BETWEEN () AND () REGIONS 10\"},\n\t\t{\"split table t1 index by (1)\", false, \"\"},\n\n\t\t{\"split region for table t1 index idx1 by ('a'),('b'),('c')\", true, \"SPLIT REGION FOR TABLE `t1` INDEX `idx1` BY ('a'),('b'),('c')\"},\n\t\t{\"split partition table t1 index idx1 by ('a'),('b'),('c')\", true, \"SPLIT PARTITION TABLE `t1` INDEX `idx1` BY ('a'),('b'),('c')\"},\n\t\t{\"split region for partition table t1 index idx1 by ('a'),('b'),('c')\", true, \"SPLIT REGION FOR PARTITION TABLE `t1` INDEX `idx1` BY ('a'),('b'),('c')\"},\n\t\t{\"split region for table t1 index idx1 between ('a') and ('z') regions 10\", true, \"SPLIT REGION FOR TABLE `t1` INDEX `idx1` BETWEEN ('a') AND ('z') REGIONS 10\"},\n\t\t{\"split partition table t1 index idx1 between ('a') and ('z') regions 10\", true, \"SPLIT PARTITION TABLE `t1` INDEX `idx1` BETWEEN ('a') AND ('z') REGIONS 10\"},\n\t\t{\"split region for partition table t1 index idx1 between ('a') and ('z') regions 10\", true, \"SPLIT REGION FOR PARTITION TABLE `t1` INDEX `idx1` BETWEEN ('a') AND ('z') REGIONS 10\"},\n\n\t\t{\"split region for table t1 partition (p0,p1) index idx1 by ('a'),('b'),('c')\", true, \"SPLIT REGION FOR TABLE `t1` PARTITION(`p0`, `p1`) INDEX `idx1` BY ('a'),('b'),('c')\"},\n\t\t{\"split partition table t1 partition (p0) index idx1 by ('a'),('b'),('c')\", true, \"SPLIT PARTITION TABLE `t1` PARTITION(`p0`) INDEX `idx1` BY ('a'),('b'),('c')\"},\n\t\t{\"split region for partition table t1 partition (p0) index idx1 by ('a'),('b'),('c')\", true, \"SPLIT REGION FOR PARTITION TABLE `t1` PARTITION(`p0`) INDEX `idx1` BY ('a'),('b'),('c')\"},\n\t\t{\"split region for table t1 partition (p0) index idx1 between ('a') and ('z') regions 10\", true, \"SPLIT REGION FOR TABLE `t1` PARTITION(`p0`) INDEX `idx1` BETWEEN ('a') AND ('z') REGIONS 10\"},\n\t\t{\"split partition table t1 partition (p0) index idx1 between ('a') and ('z') regions 10\", true, \"SPLIT PARTITION TABLE `t1` PARTITION(`p0`) INDEX `idx1` BETWEEN ('a') AND ('z') REGIONS 10\"},\n\t\t{\"split region for partition table t1 partition (p0) index idx1 between ('a') and ('z') regions 10\", true, \"SPLIT REGION FOR PARTITION TABLE `t1` PARTITION(`p0`) INDEX `idx1` BETWEEN ('a') AND ('z') REGIONS 10\"},\n\n\t\t// for split table region.\n\t\t{\"split table t1 by ('a'),('b'),('c')\", true, \"SPLIT TABLE `t1` BY ('a'),('b'),('c')\"},\n\t\t{\"split table t1 by (1)\", true, \"SPLIT TABLE `t1` BY (1)\"},\n\t\t{\"split table t1 by ('abc',123), ('xyz'), ('yz', 1000)\", true, \"SPLIT TABLE `t1` BY ('abc',123),('xyz'),('yz',1000)\"},\n\t\t{\"split table t1 by \", false, \"\"},\n\t\t{\"split table t1 between ('a') and ('z') regions 10\", true, \"SPLIT TABLE `t1` BETWEEN ('a') AND ('z') REGIONS 10\"},\n\t\t{\"split table t1 between ('a',1) and ('z',2) regions 10\", true, \"SPLIT TABLE `t1` BETWEEN ('a',1) AND ('z',2) REGIONS 10\"},\n\t\t{\"split table t1 between () and () regions 10\", true, \"SPLIT TABLE `t1` BETWEEN () AND () REGIONS 10\"},\n\n\t\t{\"split region for table t1 by ('a'),('b'),('c')\", true, \"SPLIT REGION FOR TABLE `t1` BY ('a'),('b'),('c')\"},\n\t\t{\"split partition table t1 by ('a'),('b'),('c')\", true, \"SPLIT PARTITION TABLE `t1` BY ('a'),('b'),('c')\"},\n\t\t{\"split region for partition table t1 by ('a'),('b'),('c')\", true, \"SPLIT REGION FOR PARTITION TABLE `t1` BY ('a'),('b'),('c')\"},\n\t\t{\"split region for table t1 between (1) and (1000) regions 10\", true, \"SPLIT REGION FOR TABLE `t1` BETWEEN (1) AND (1000) REGIONS 10\"},\n\t\t{\"split partition table t1 between (1) and (1000) regions 10\", true, \"SPLIT PARTITION TABLE `t1` BETWEEN (1) AND (1000) REGIONS 10\"},\n\t\t{\"split region for partition table t1 between (1) and (1000) regions 10\", true, \"SPLIT REGION FOR PARTITION TABLE `t1` BETWEEN (1) AND (1000) REGIONS 10\"},\n\n\t\t// for show table regions.\n\t\t{\"show table t1 regions\", true, \"SHOW TABLE `t1` REGIONS\"},\n\t\t{\"show table t1 regions where a=1\", true, \"SHOW TABLE `t1` REGIONS WHERE `a`=1\"},\n\t\t{\"show table t1\", false, \"\"},\n\t\t{\"show table t1 index idx1 regions\", true, \"SHOW TABLE `t1` INDEX `idx1` REGIONS\"},\n\t\t{\"show table t1 index idx1 regions where a=2\", true, \"SHOW TABLE `t1` INDEX `idx1` REGIONS WHERE `a`=2\"},\n\t\t{\"show table t1 index idx1\", false, \"\"},\n\n\t\t// for transaction mode\n\t\t{\"begin pessimistic\", true, \"BEGIN PESSIMISTIC\"},\n\t\t{\"begin optimistic\", true, \"BEGIN OPTIMISTIC\"},\n\n\t\t// for repair table mode.\n\t\t{\"ADMIN REPAIR TABLE t CREATE TABLE t (a int)\", true, \"ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`a` INT)\"},\n\t\t// {\"ADMIN REPAIR TABLE t CREATE TABLE t (a char(1))\", true, \"ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`a` CHAR(1))\"},\n\t\t// {\"ADMIN REPAIR TABLE t CREATE TABLE t (a char(1), b int)\", true, \"ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`a` CHAR(1),`b` INT)\"},\n\t\t// {\"ADMIN REPAIR TABLE t CREATE TABLE t (c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2));\", true, \"ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`c1` TIME(2),`c2` DATETIME(2),`c3` TIMESTAMP(2))\"},\n\t\t// {\"ADMIN REPAIR TABLE t CREATE TABLE t (a TINYINT UNSIGNED);\", true, \"ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`a` TINYINT UNSIGNED)\"},\n\t\t// {\"ADMIN REPAIR TABLE t CREATE TABLE t (name CHAR(50) CHARACTER SET UTF8)\", true, \"ADMIN REPAIR TABLE `t` CREATE TABLE `t` (`name` CHAR(50) CHARACTER SET UTF8)\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestDBAStmt(c *C) {\n\ttable := []testCase{\n\t\t// for SHOW statement\n\t\t{\"SHOW VARIABLES LIKE 'character_set_results'\", true, \"SHOW SESSION VARIABLES LIKE 'character_set_results'\"},\n\t\t{\"SHOW GLOBAL VARIABLES LIKE 'character_set_results'\", true, \"SHOW GLOBAL VARIABLES LIKE 'character_set_results'\"},\n\t\t{\"SHOW SESSION VARIABLES LIKE 'character_set_results'\", true, \"SHOW SESSION VARIABLES LIKE 'character_set_results'\"},\n\t\t{\"SHOW VARIABLES\", true, \"SHOW SESSION VARIABLES\"},\n\t\t{\"SHOW GLOBAL VARIABLES\", true, \"SHOW GLOBAL VARIABLES\"},\n\t\t{\"SHOW GLOBAL VARIABLES WHERE Variable_name = 'autocommit'\", true, \"SHOW GLOBAL VARIABLES WHERE `Variable_name`='autocommit'\"},\n\t\t{\"SHOW STATUS\", true, \"SHOW SESSION STATUS\"},\n\t\t{\"SHOW GLOBAL STATUS\", true, \"SHOW GLOBAL STATUS\"},\n\t\t{\"SHOW SESSION STATUS\", true, \"SHOW SESSION STATUS\"},\n\t\t{`SHOW STATUS LIKE 'Up%'`, true, \"SHOW SESSION STATUS LIKE 'Up%'\"},\n\t\t{`SHOW STATUS WHERE Variable_name`, true, \"SHOW SESSION STATUS WHERE `Variable_name`\"},\n\t\t{`SHOW STATUS WHERE Variable_name LIKE 'Up%'`, true, \"SHOW SESSION STATUS WHERE `Variable_name` LIKE 'Up%'\"},\n\t\t{`SHOW FULL TABLES FROM icar_qa LIKE play_evolutions`, true, \"SHOW FULL TABLES IN `icar_qa` LIKE `play_evolutions`\"},\n\t\t{`SHOW FULL TABLES WHERE Table_Type != 'VIEW'`, true, \"SHOW FULL TABLES WHERE `Table_Type`!='VIEW'\"},\n\t\t{`SHOW GRANTS ON DA`, true, \"SHOW GRANTS ON DA\"},\n\t\t{`SHOW GRANTS ON DA FOR 'test'@'localhost'`, true, \"SHOW GRANTS ON DA FOR `test`@`localhost`\"},\n\t\t{`SHOW GRANTS ON DA FOR current_user()`, true, \"SHOW GRANTS ON DA FOR CURRENT_USER\"},\n\t\t{`SHOW GRANTS ON DA FOR current_user`, true, \"SHOW GRANTS ON DA FOR CURRENT_USER\"},\n\t\t{`SHOW GRANTS ON DA FOR 'u1'@'localhost' USING 'r1'`, true, \"SHOW GRANTS ON DA FOR `u1`@`localhost` USING `r1`@`%`\"},\n\t\t{`SHOW GRANTS ON DA FOR 'u1'@'localhost' USING 'r1', 'r2'`, true, \"SHOW GRANTS ON DA FOR `u1`@`localhost` USING `r1`@`%`, `r2`@`%`\"},\n\t\t{`SHOW COLUMNS FROM City;`, true, \"SHOW COLUMNS IN `City`\"},\n\t\t{`SHOW COLUMNS FROM tv189.1_t_1_x;`, true, \"SHOW COLUMNS IN `tv189`.`1_t_1_x`\"},\n\t\t{`SHOW FIELDS FROM City;`, true, \"SHOW COLUMNS IN `City`\"},\n\t\t{`SHOW TRIGGERS LIKE 't'`, true, \"SHOW TRIGGERS LIKE 't'\"},\n\t\t{`SHOW DATABASES LIKE 'test2'`, true, \"SHOW DATABASES LIKE 'test2'\"},\n\t\t// PROCEDURE and FUNCTION are currently not supported.\n\t\t// And FUNCTION reuse show procedure status process logic.\n\t\t{`SHOW PROCEDURE STATUS WHERE Db='test'`, true, \"SHOW PROCEDURE STATUS WHERE `Db`='test'\"},\n\t\t{`SHOW FUNCTION STATUS WHERE Db='test'`, true, \"SHOW PROCEDURE STATUS WHERE `Db`='test'\"},\n\t\t{`SHOW INDEX FROM t;`, true, \"SHOW INDEX IN `t`\"},\n\t\t{`SHOW KEYS FROM t;`, true, \"SHOW INDEX IN `t`\"},\n\t\t{`SHOW INDEX IN t;`, true, \"SHOW INDEX IN `t`\"},\n\t\t{`SHOW KEYS IN t;`, true, \"SHOW INDEX IN `t`\"},\n\t\t{`SHOW INDEXES IN t where true;`, true, \"SHOW INDEX IN `t` WHERE TRUE\"},\n\t\t{`SHOW KEYS FROM t FROM test where true;`, true, \"SHOW INDEX IN `test`.`t` WHERE TRUE\"},\n\t\t{`SHOW EVENTS FROM test_db WHERE definer = 'current_user'`, true, \"SHOW EVENTS IN `test_db` WHERE `definer`='current_user'\"},\n\t\t{`SHOW PLUGINS`, true, \"SHOW PLUGINS\"},\n\t\t{`SHOW PROFILES`, true, \"SHOW PROFILES\"},\n\t\t{`SHOW PROFILE`, true, \"SHOW PROFILE\"},\n\t\t{`SHOW PROFILE FOR QUERY 1`, true, \"SHOW PROFILE FOR QUERY 1\"},\n\t\t{`SHOW PROFILE CPU FOR QUERY 2`, true, \"SHOW PROFILE CPU FOR QUERY 2\"},\n\t\t{`SHOW PROFILE CPU FOR QUERY 2 LIMIT 1,1`, true, \"SHOW PROFILE CPU FOR QUERY 2 LIMIT 1 OFFSET 1\"},\n\t\t{`SHOW PROFILE CPU, MEMORY, BLOCK IO, CONTEXT SWITCHES, PAGE FAULTS, IPC, SWAPS, SOURCE FOR QUERY 1 limit 100`, true, \"SHOW PROFILE CPU, MEMORY, BLOCK IO, CONTEXT SWITCHES, PAGE FAULTS, IPC, SWAPS, SOURCE FOR QUERY 1 LIMIT 100\"},\n\t\t{`SHOW MASTER STATUS`, true, \"SHOW MASTER STATUS\"},\n\t\t{`SHOW PRIVILEGES`, true, \"SHOW PRIVILEGES\"},\n\t\t// for show character set\n\t\t{\"show character set;\", true, \"SHOW CHARSET\"},\n\t\t{\"show charset\", true, \"SHOW CHARSET\"},\n\t\t// for show collation\n\t\t{\"show collation\", true, \"SHOW COLLATION\"},\n\t\t{`show collation like 'utf8%'`, true, \"SHOW COLLATION LIKE 'utf8%'\"},\n\t\t{\"show collation where Charset = 'utf8' and Collation = 'utf8_bin'\", true, \"SHOW COLLATION WHERE `Charset`='utf8' AND `Collation`='utf8_bin'\"},\n\t\t// for show full columns\n\t\t{\"show columns in t;\", true, \"SHOW COLUMNS IN `t`\"},\n\t\t{\"show full columns in t;\", true, \"SHOW FULL COLUMNS IN `t`\"},\n\t\t// for show extended columns\n\t\t{`SHOW COLUMNS FROM City;`, true, \"SHOW COLUMNS IN `City`\"},\n\t\t{`SHOW EXTENDED COLUMNS FROM City;`, true, \"SHOW EXTENDED COLUMNS IN `City`\"},\n\t\t{`SHOW EXTENDED FIELDS FROM City;`, true, \"SHOW EXTENDED COLUMNS IN `City`\"},\n\t\t// for show extended full columns\n\t\t{`SHOW EXTENDED FULL COLUMNS FROM City;`, true, \"SHOW EXTENDED FULL COLUMNS IN `City`\"},\n\t\t{`SHOW EXTENDED FULL FIELDS FROM City;`, true, \"SHOW EXTENDED FULL COLUMNS IN `City`\"},\n\t\t// for show create table\n\t\t{\"show create table test.t\", true, \"SHOW CREATE TABLE `test`.`t`\"},\n\t\t{\"show create table t\", true, \"SHOW CREATE TABLE `t`\"},\n\t\t// for show create view\n\t\t{\"show create view test.t\", true, \"SHOW CREATE VIEW `test`.`t`\"},\n\t\t{\"show create view t\", true, \"SHOW CREATE VIEW `t`\"},\n\t\t// for show create database\n\t\t{\"show create database d1\", true, \"SHOW CREATE DATABASE `d1`\"},\n\t\t{\"show create database if not exists d1\", true, \"SHOW CREATE DATABASE IF NOT EXISTS `d1`\"},\n\t\t// for show create sequence\n\t\t{\"show create sequence seq\", true, \"SHOW CREATE SEQUENCE `seq`\"},\n\t\t{\"show create sequence test.seq\", true, \"SHOW CREATE SEQUENCE `test`.`seq`\"},\n\t\t// for show stats_meta.\n\t\t{\"show stats_meta\", true, \"SHOW STATS_META\"},\n\t\t{\"show stats_meta where table_name = 't'\", true, \"SHOW STATS_META WHERE `table_name`='t'\"},\n\t\t// for show stats_histograms\n\t\t{\"show stats_histograms\", true, \"SHOW STATS_HISTOGRAMS\"},\n\t\t{\"show stats_histograms where col_name = 'a'\", true, \"SHOW STATS_HISTOGRAMS WHERE `col_name`='a'\"},\n\t\t// for show stats_buckets\n\t\t{\"show stats_buckets\", true, \"SHOW STATS_BUCKETS\"},\n\t\t{\"show stats_buckets where col_name = 'a'\", true, \"SHOW STATS_BUCKETS WHERE `col_name`='a'\"},\n\t\t// for show stats_healthy.\n\t\t{\"show stats_healthy\", true, \"SHOW STATS_HEALTHY\"},\n\t\t{\"show stats_healthy where table_name = 't'\", true, \"SHOW STATS_HEALTHY WHERE `table_name`='t'\"},\n\t\t// for show pump/drainer status.\n\t\t{\"show pump status\", true, \"SHOW PUMP STATUS\"},\n\t\t{\"show drainer status\", true, \"SHOW DRAINER STATUS\"},\n\t\t{\"show analyze status\", true, \"SHOW ANALYZE STATUS\"},\n\t\t{\"show analyze status where table_name = 't'\", true, \"SHOW ANALYZE STATUS WHERE `table_name`='t'\"},\n\t\t{\"show analyze status where table_name like '%'\", true, \"SHOW ANALYZE STATUS WHERE `table_name` LIKE '%'\"},\n\t\t// for show builtins\n\t\t{\"show builtins\", true, \"SHOW BUILTINS\"},\n\n\t\t// for load stats\n\t\t{\"load stats '/tmp/stats.json'\", true, \"LOAD STATS '/tmp/stats.json'\"},\n\t\t// set\n\t\t// user defined\n\t\t{\"SET @ = 1\", true, \"SET @``=1\"},\n\t\t{\"SET @' ' = 1\", true, \"SET @` `=1\"},\n\t\t{\"SET @! = 1\", false, \"\"},\n\t\t{\"SET @1 = 1\", true, \"SET @`1`=1\"},\n\t\t{\"SET @a = 1\", true, \"SET @`a`=1\"},\n\t\t{\"SET @b := 1\", true, \"SET @`b`=1\"},\n\t\t{\"SET @.c = 1\", true, \"SET @`.c`=1\"},\n\t\t{\"SET @_d = 1\", true, \"SET @`_d`=1\"},\n\t\t{\"SET @_e._$. = 1\", true, \"SET @`_e._$.`=1\"},\n\t\t{\"SET @~f = 1\", false, \"\"},\n\t\t{\"SET @`g,` = 1\", true, \"SET @`g,`=1\"},\n\t\t// session system variables\n\t\t{\"SET SESSION autocommit = 1\", true, \"SET @@SESSION.`autocommit`=1\"},\n\t\t{\"SET @@session.autocommit = 1\", true, \"SET @@SESSION.`autocommit`=1\"},\n\t\t{\"SET @@SESSION.autocommit = 1\", true, \"SET @@SESSION.`autocommit`=1\"},\n\t\t{\"SET @@GLOBAL.GTID_PURGED = '123'\", true, \"SET @@GLOBAL.`gtid_purged`='123'\"},\n\t\t{\"SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN\", true, \"SET @`MYSQLDUMP_TEMP_LOG_BIN`=@@SESSION.`sql_log_bin`\"},\n\t\t{\"SET LOCAL autocommit = 1\", true, \"SET @@SESSION.`autocommit`=1\"},\n\t\t{\"SET @@local.autocommit = 1\", true, \"SET @@SESSION.`autocommit`=1\"},\n\t\t{\"SET @@autocommit = 1\", true, \"SET @@SESSION.`autocommit`=1\"},\n\t\t{\"SET autocommit = 1\", true, \"SET @@SESSION.`autocommit`=1\"},\n\t\t// global system variables\n\t\t{\"SET GLOBAL autocommit = 1\", true, \"SET @@GLOBAL.`autocommit`=1\"},\n\t\t{\"SET @@global.autocommit = 1\", true, \"SET @@GLOBAL.`autocommit`=1\"},\n\t\t// set through mysql extension assignment syntax\n\t\t{\"SET autocommit := 1\", true, \"SET @@SESSION.`autocommit`=1\"},\n\t\t{\"SET @@session.autocommit := 1\", true, \"SET @@SESSION.`autocommit`=1\"},\n\t\t{\"SET @MYSQLDUMP_TEMP_LOG_BIN := @@SESSION.SQL_LOG_BIN\", true, \"SET @`MYSQLDUMP_TEMP_LOG_BIN`=@@SESSION.`sql_log_bin`\"},\n\t\t{\"SET LOCAL autocommit := 1\", true, \"SET @@SESSION.`autocommit`=1\"},\n\t\t{\"SET @@global.autocommit := default\", true, \"SET @@GLOBAL.`autocommit`=DEFAULT\"},\n\t\t// set default value\n\t\t{\"SET @@global.autocommit = default\", true, \"SET @@GLOBAL.`autocommit`=DEFAULT\"},\n\t\t{\"SET @@session.autocommit = default\", true, \"SET @@SESSION.`autocommit`=DEFAULT\"},\n\t\t// SET CHARACTER SET\n\t\t{\"SET CHARACTER SET utf8mb4;\", true, \"SET NAMES 'utf8mb4'\"},\n\t\t{\"SET CHARACTER SET 'utf8mb4';\", true, \"SET NAMES 'utf8mb4'\"},\n\t\t// set password\n\t\t{\"SET PASSWORD = 'password';\", true, \"SET PASSWORD='password'\"},\n\t\t{\"SET PASSWORD FOR 'root'@'localhost' = 'password';\", true, \"SET PASSWORD FOR `root`@`localhost`='password'\"},\n\t\t// SET TRANSACTION Syntax\n\t\t{\"SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ\", true, \"SET @@SESSION.`tx_isolation`='REPEATABLE-READ'\"},\n\t\t{\"SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ\", true, \"SET @@GLOBAL.`tx_isolation`='REPEATABLE-READ'\"},\n\t\t{\"SET SESSION TRANSACTION READ WRITE\", true, \"SET @@SESSION.`tx_read_only`='0'\"},\n\t\t{\"SET SESSION TRANSACTION READ ONLY\", true, \"SET @@SESSION.`tx_read_only`='1'\"},\n\t\t{\"SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED\", true, \"SET @@SESSION.`tx_isolation`='READ-COMMITTED'\"},\n\t\t{\"SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED\", true, \"SET @@SESSION.`tx_isolation`='READ-UNCOMMITTED'\"},\n\t\t{\"SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE\", true, \"SET @@SESSION.`tx_isolation`='SERIALIZABLE'\"},\n\t\t{\"SET TRANSACTION ISOLATION LEVEL REPEATABLE READ\", true, \"SET @@SESSION.`tx_isolation_one_shot`='REPEATABLE-READ'\"},\n\t\t{\"SET TRANSACTION READ WRITE\", true, \"SET @@SESSION.`tx_read_only`='0'\"},\n\t\t{\"SET TRANSACTION READ ONLY\", true, \"SET @@SESSION.`tx_read_only`='1'\"},\n\t\t{\"SET TRANSACTION ISOLATION LEVEL READ COMMITTED\", true, \"SET @@SESSION.`tx_isolation_one_shot`='READ-COMMITTED'\"},\n\t\t{\"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED\", true, \"SET @@SESSION.`tx_isolation_one_shot`='READ-UNCOMMITTED'\"},\n\t\t{\"SET TRANSACTION ISOLATION LEVEL SERIALIZABLE\", true, \"SET @@SESSION.`tx_isolation_one_shot`='SERIALIZABLE'\"},\n\t\t// for set names\n\t\t{\"set names utf8\", true, \"SET NAMES 'utf8'\"},\n\t\t{\"set names utf8 collate utf8_unicode_ci\", true, \"SET NAMES 'utf8' COLLATE 'utf8_unicode_ci'\"},\n\t\t{\"set names binary\", true, \"SET NAMES 'binary'\"},\n\n\t\t// for set character set | name default\n\t\t{\"set names default\", true, \"SET NAMES DEFAULT\"},\n\t\t{\"set character set default\", true, \"SET NAMES DEFAULT\"},\n\t\t{\"set charset default\", true, \"SET NAMES DEFAULT\"},\n\t\t{\"set char set default\", true, \"SET NAMES DEFAULT\"},\n\n\t\t{\"set role `role1`\", true, \"SET ROLE `role1`@`%`\"},\n\t\t{\"SET ROLE DEFAULT\", true, \"SET ROLE DEFAULT\"},\n\t\t{\"SET ROLE ALL\", true, \"SET ROLE ALL\"},\n\t\t{\"SET ROLE ALL EXCEPT `role1`, `role2`\", true, \"SET ROLE ALL EXCEPT `role1`@`%`, `role2`@`%`\"},\n\t\t{\"SET DEFAULT ROLE administrator, developer TO `joe`@`10.0.0.1`\", true, \"SET DEFAULT ROLE `administrator`@`%`, `developer`@`%` TO `joe`@`10.0.0.1`\"},\n\t\t// for set names and set vars\n\t\t{\"set names utf8, @@session.sql_mode=1;\", true, \"SET NAMES 'utf8', @@SESSION.`sql_mode`=1\"},\n\t\t{\"set @@session.sql_mode=1, names utf8, charset utf8;\", true, \"SET @@SESSION.`sql_mode`=1, NAMES 'utf8', NAMES 'utf8'\"},\n\n\t\t// for FLUSH statement\n\t\t{\"flush no_write_to_binlog tables tbl1 with read lock\", true, \"FLUSH NO_WRITE_TO_BINLOG TABLES `tbl1` WITH READ LOCK\"},\n\t\t{\"flush table\", true, \"FLUSH TABLES\"},\n\t\t{\"flush tables\", true, \"FLUSH TABLES\"},\n\t\t{\"flush tables tbl1\", true, \"FLUSH TABLES `tbl1`\"},\n\t\t{\"flush no_write_to_binlog tables tbl1\", true, \"FLUSH NO_WRITE_TO_BINLOG TABLES `tbl1`\"},\n\t\t{\"flush local tables tbl1\", true, \"FLUSH NO_WRITE_TO_BINLOG TABLES `tbl1`\"},\n\t\t{\"flush table with read lock\", true, \"FLUSH TABLES WITH READ LOCK\"},\n\t\t{\"flush tables tbl1, tbl2, tbl3\", true, \"FLUSH TABLES `tbl1`, `tbl2`, `tbl3`\"},\n\t\t{\"flush tables tbl1, tbl2, tbl3 with read lock\", true, \"FLUSH TABLES `tbl1`, `tbl2`, `tbl3` WITH READ LOCK\"},\n\t\t{\"flush privileges\", true, \"FLUSH PRIVILEGES\"},\n\t\t{\"flush status\", true, \"FLUSH STATUS\"},\n\t\t{\"flush tidb plugins plugin1\", true, \"FLUSH TIDB PLUGINS plugin1\"},\n\t\t{\"flush tidb plugins plugin1, plugin2\", true, \"FLUSH TIDB PLUGINS plugin1, plugin2\"},\n\t\t{\"flush hosts\", true, \"FLUSH HOSTS\"},\n\t\t{\"flush logs\", true, \"FLUSH LOGS\"},\n\t\t{\"flush binary logs\", true, \"FLUSH BINARY LOGS\"},\n\t\t{\"flush engine logs\", true, \"FLUSH ENGINE LOGS\"},\n\t\t{\"flush error logs\", true, \"FLUSH ERROR LOGS\"},\n\t\t{\"flush general logs\", true, \"FLUSH GENERAL LOGS\"},\n\t\t{\"flush slow logs\", true, \"FLUSH SLOW LOGS\"},\n\n\t\t// for change statement\n\t\t{\"change pump to node_state ='paused' for node_id '127.0.0.1:8250'\", true, \"CHANGE PUMP TO NODE_STATE ='paused' FOR NODE_ID '127.0.0.1:8250'\"},\n\t\t{\"change drainer to node_state ='paused' for node_id '127.0.0.1:8249'\", true, \"CHANGE DRAINER TO NODE_STATE ='paused' FOR NODE_ID '127.0.0.1:8249'\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestSetVariable(c *C) {\n\ttable := []struct {\n\t\tInput    string\n\t\tName     string\n\t\tIsGlobal bool\n\t\tIsSystem bool\n\t}{\n\n\t\t// Set system variable xx.xx, although xx.xx isn't a system variable, the parser should accept it.\n\t\t{\"set xx.xx = 666\", \"xx.xx\", false, true},\n\t\t// Set session system variable xx.xx\n\t\t{\"set session xx.xx = 666\", \"xx.xx\", false, true},\n\t\t{\"set global xx.xx = 666\", \"xx.xx\", true, true},\n\n\t\t{\"set @@xx.xx = 666\", \"xx.xx\", false, true},\n\t\t{\"set @@session.xx.xx = 666\", \"xx.xx\", false, true},\n\t\t{\"set @@global.xx.xx = 666\", \"xx.xx\", true, true},\n\n\t\t// Set user defined variable xx.xx\n\t\t{\"set @xx.xx = 666\", \"xx.xx\", false, false},\n\t}\n\n\tparser := parser.New()\n\tfor _, t := range table {\n\t\tstmt, err := parser.ParseOneStmt(t.Input, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\n\t\tsetStmt, ok := stmt.(*ast.SetStmt)\n\t\tc.Assert(ok, IsTrue)\n\t\tc.Assert(setStmt.Variables, HasLen, 1)\n\n\t\tv := setStmt.Variables[0]\n\t\tc.Assert(v.Name, Equals, t.Name)\n\t\tc.Assert(v.IsGlobal, Equals, t.IsGlobal)\n\t\tc.Assert(v.IsSystem, Equals, t.IsSystem)\n\t}\n\n\t_, err := parser.ParseOneStmt(\"set xx.xx.xx = 666\", \"\", \"\")\n\tc.Assert(err, NotNil)\n}\n\nfunc (s *testParserSuite) TestFlushTable(c *C) {\n\tparser := parser.New()\n\tstmt, _, err := parser.Parse(\"flush local tables tbl1,tbl2 with read lock\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tflushTable := stmt[0].(*ast.FlushStmt)\n\tc.Assert(flushTable.Tp, Equals, ast.FlushTables)\n\tc.Assert(flushTable.Tables[0].Name.L, Equals, \"tbl1\")\n\tc.Assert(flushTable.Tables[1].Name.L, Equals, \"tbl2\")\n\tc.Assert(flushTable.NoWriteToBinLog, IsTrue)\n\tc.Assert(flushTable.ReadLock, IsTrue)\n}\n\nfunc (s *testParserSuite) TestFlushPrivileges(c *C) {\n\tparser := parser.New()\n\tstmt, _, err := parser.Parse(\"flush privileges\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tflushPrivilege := stmt[0].(*ast.FlushStmt)\n\tc.Assert(flushPrivilege.Tp, Equals, ast.FlushPrivileges)\n}\n\nfunc (s *testParserSuite) TestExpression(c *C) {\n\ttable := []testCase{\n\t\t// sign expression\n\t\t{\"SELECT ++1\", true, \"SELECT ++1\"},\n\t\t{\"SELECT -*1\", false, \"SELECT -*1\"},\n\t\t{\"SELECT -+1\", true, \"SELECT -+1\"},\n\t\t{\"SELECT -1\", true, \"SELECT -1\"},\n\t\t{\"SELECT --1\", true, \"SELECT --1\"},\n\n\t\t// for string literal\n\t\t{`select '''a''', \"\"\"a\"\"\"`, true, \"SELECT '''a''','\\\"a\\\"'\"},\n\t\t{`select ''a''`, false, \"\"},\n\t\t{`select \"\"a\"\"`, false, \"\"},\n\t\t{`select '''a''';`, true, \"SELECT '''a'''\"},\n\t\t{`select '\\'a\\'';`, true, \"SELECT '''a'''\"},\n\t\t{`select \"\\\"a\\\"\";`, true, \"SELECT '\\\"a\\\"'\"},\n\t\t{`select \"\"\"a\"\"\";`, true, \"SELECT '\\\"a\\\"'\"},\n\t\t{`select _utf8\"string\";`, true, \"SELECT _UTF8'string'\"},\n\t\t{`select _binary\"string\";`, true, \"SELECT _BINARY'string'\"},\n\t\t{\"select N'string'\", true, \"SELECT _UTF8'string'\"},\n\t\t{\"select n'string'\", true, \"SELECT _UTF8'string'\"},\n\t\t// for comparison\n\t\t{\"select 1 <=> 0, 1 <=> null, 1 = null\", true, \"SELECT 1<=>0,1<=>NULL,1=NULL\"},\n\t\t// for date literal\n\t\t{\"select date'1989-09-10'\", true, \"SELECT DATE '1989-09-10'\"},\n\t\t{\"select date 19890910\", false, \"\"},\n\t\t// for time literal\n\t\t{\"select time '00:00:00.111'\", true, \"SELECT TIME '00:00:00.111'\"},\n\t\t{\"select time 19890910\", false, \"\"},\n\t\t// for timestamp literal\n\t\t{\"select timestamp '1989-09-10 11:11:11'\", true, \"SELECT TIMESTAMP '1989-09-10 11:11:11'\"},\n\t\t{\"select timestamp 19890910\", false, \"\"},\n\n\t\t// The ODBC syntax for time/date/timestamp literal.\n\t\t// See: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html\n\t\t{\"select {ts '1989-09-10 11:11:11'}\", true, \"SELECT '1989-09-10 11:11:11'\"},\n\t\t{\"select {d '1989-09-10'}\", true, \"SELECT '1989-09-10'\"},\n\t\t{\"select {t '00:00:00.111'}\", true, \"SELECT '00:00:00.111'\"},\n\t\t// If the identifier is not in (t, d, ts), we just ignore it and consider the following expression as the value.\n\t\t// See: https://dev.mysql.com/doc/refman/5.7/en/expressions.html\n\t\t{\"select {ts123 '1989-09-10 11:11:11'}\", true, \"SELECT '1989-09-10 11:11:11'\"},\n\t\t{\"select {ts123 123}\", true, \"SELECT 123\"},\n\t\t{\"select {ts123 1 xor 1}\", true, \"SELECT 1 XOR 1\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestBuiltin(c *C) {\n\ttable := []testCase{\n\t\t// for builtin functions\n\t\t{\"SELECT POW(1, 2)\", true, \"SELECT POW(1, 2)\"},\n\t\t{\"SELECT POW(1, 2, 1)\", true, \"SELECT POW(1, 2, 1)\"}, // illegal number of arguments shall pass too\n\t\t{\"SELECT POW(1, 0.5)\", true, \"SELECT POW(1, 0.5)\"},\n\t\t{\"SELECT POW(1, -1)\", true, \"SELECT POW(1, -1)\"},\n\t\t{\"SELECT POW(-1, 1)\", true, \"SELECT POW(-1, 1)\"},\n\t\t{\"SELECT RAND();\", true, \"SELECT RAND()\"},\n\t\t{\"SELECT RAND(1);\", true, \"SELECT RAND(1)\"},\n\t\t{\"SELECT MOD(10, 2);\", true, \"SELECT MOD(10, 2)\"},\n\t\t{\"SELECT ROUND(-1.23);\", true, \"SELECT ROUND(-1.23)\"},\n\t\t{\"SELECT ROUND(1.23, 1);\", true, \"SELECT ROUND(1.23, 1)\"},\n\t\t{\"SELECT ROUND(1.23, 1, 1);\", true, \"SELECT ROUND(1.23, 1, 1)\"},\n\t\t{\"SELECT CEIL(-1.23);\", true, \"SELECT CEIL(-1.23)\"},\n\t\t{\"SELECT CEILING(1.23);\", true, \"SELECT CEILING(1.23)\"},\n\t\t{\"SELECT FLOOR(-1.23);\", true, \"SELECT FLOOR(-1.23)\"},\n\t\t{\"SELECT LN(1);\", true, \"SELECT LN(1)\"},\n\t\t{\"SELECT LN(1, 2);\", true, \"SELECT LN(1, 2)\"},\n\t\t{\"SELECT LOG(-2);\", true, \"SELECT LOG(-2)\"},\n\t\t{\"SELECT LOG(2, 65536);\", true, \"SELECT LOG(2, 65536)\"},\n\t\t{\"SELECT LOG(2, 65536, 1);\", true, \"SELECT LOG(2, 65536, 1)\"},\n\t\t{\"SELECT LOG2(2);\", true, \"SELECT LOG2(2)\"},\n\t\t{\"SELECT LOG2(2, 2);\", true, \"SELECT LOG2(2, 2)\"},\n\t\t{\"SELECT LOG10(10);\", true, \"SELECT LOG10(10)\"},\n\t\t{\"SELECT LOG10(10, 1);\", true, \"SELECT LOG10(10, 1)\"},\n\t\t{\"SELECT ABS(10, 1);\", true, \"SELECT ABS(10, 1)\"},\n\t\t{\"SELECT ABS(10);\", true, \"SELECT ABS(10)\"},\n\t\t{\"SELECT ABS();\", true, \"SELECT ABS()\"},\n\t\t{\"SELECT CONV(10+'10'+'10'+X'0a',10,10);\", true, \"SELECT CONV(10+'10'+'10'+x'0a', 10, 10)\"},\n\t\t{\"SELECT CONV();\", true, \"SELECT CONV()\"},\n\t\t{\"SELECT CRC32('MySQL');\", true, \"SELECT CRC32('MySQL')\"},\n\t\t{\"SELECT CRC32();\", true, \"SELECT CRC32()\"},\n\t\t{\"SELECT SIGN();\", true, \"SELECT SIGN()\"},\n\t\t{\"SELECT SIGN(0);\", true, \"SELECT SIGN(0)\"},\n\t\t{\"SELECT SQRT(0);\", true, \"SELECT SQRT(0)\"},\n\t\t{\"SELECT SQRT();\", true, \"SELECT SQRT()\"},\n\t\t{\"SELECT ACOS();\", true, \"SELECT ACOS()\"},\n\t\t{\"SELECT ACOS(1);\", true, \"SELECT ACOS(1)\"},\n\t\t{\"SELECT ACOS(1, 2);\", true, \"SELECT ACOS(1, 2)\"},\n\t\t{\"SELECT ASIN();\", true, \"SELECT ASIN()\"},\n\t\t{\"SELECT ASIN(1);\", true, \"SELECT ASIN(1)\"},\n\t\t{\"SELECT ASIN(1, 2);\", true, \"SELECT ASIN(1, 2)\"},\n\t\t{\"SELECT ATAN(0), ATAN(1), ATAN(1, 2);\", true, \"SELECT ATAN(0),ATAN(1),ATAN(1, 2)\"},\n\t\t{\"SELECT ATAN2(), ATAN2(1,2);\", true, \"SELECT ATAN2(),ATAN2(1, 2)\"},\n\t\t{\"SELECT COS(0);\", true, \"SELECT COS(0)\"},\n\t\t{\"SELECT COS(1);\", true, \"SELECT COS(1)\"},\n\t\t{\"SELECT COS(1, 2);\", true, \"SELECT COS(1, 2)\"},\n\t\t{\"SELECT COT();\", true, \"SELECT COT()\"},\n\t\t{\"SELECT COT(1);\", true, \"SELECT COT(1)\"},\n\t\t{\"SELECT COT(1, 2);\", true, \"SELECT COT(1, 2)\"},\n\t\t{\"SELECT DEGREES();\", true, \"SELECT DEGREES()\"},\n\t\t{\"SELECT DEGREES(0);\", true, \"SELECT DEGREES(0)\"},\n\t\t{\"SELECT EXP();\", true, \"SELECT EXP()\"},\n\t\t{\"SELECT EXP(1);\", true, \"SELECT EXP(1)\"},\n\t\t{\"SELECT PI();\", true, \"SELECT PI()\"},\n\t\t{\"SELECT PI(1);\", true, \"SELECT PI(1)\"},\n\t\t{\"SELECT RADIANS();\", true, \"SELECT RADIANS()\"},\n\t\t{\"SELECT RADIANS(1);\", true, \"SELECT RADIANS(1)\"},\n\t\t{\"SELECT SIN();\", true, \"SELECT SIN()\"},\n\t\t{\"SELECT SIN(1);\", true, \"SELECT SIN(1)\"},\n\t\t{\"SELECT TAN(1);\", true, \"SELECT TAN(1)\"},\n\t\t{\"SELECT TAN();\", true, \"SELECT TAN()\"},\n\t\t{\"SELECT TRUNCATE(1.223,1);\", true, \"SELECT TRUNCATE(1.223, 1)\"},\n\t\t{\"SELECT TRUNCATE();\", true, \"SELECT TRUNCATE()\"},\n\n\t\t{\"SELECT SUBSTR('Quadratically',5);\", true, \"SELECT SUBSTR('Quadratically', 5)\"},\n\t\t{\"SELECT SUBSTR('Quadratically',5, 3);\", true, \"SELECT SUBSTR('Quadratically', 5, 3)\"},\n\t\t{\"SELECT SUBSTR('Quadratically' FROM 5);\", true, \"SELECT SUBSTR('Quadratically', 5)\"},\n\t\t{\"SELECT SUBSTR('Quadratically' FROM 5 FOR 3);\", true, \"SELECT SUBSTR('Quadratically', 5, 3)\"},\n\n\t\t{\"SELECT SUBSTRING('Quadratically',5);\", true, \"SELECT SUBSTRING('Quadratically', 5)\"},\n\t\t{\"SELECT SUBSTRING('Quadratically',5, 3);\", true, \"SELECT SUBSTRING('Quadratically', 5, 3)\"},\n\t\t{\"SELECT SUBSTRING('Quadratically' FROM 5);\", true, \"SELECT SUBSTRING('Quadratically', 5)\"},\n\t\t{\"SELECT SUBSTRING('Quadratically' FROM 5 FOR 3);\", true, \"SELECT SUBSTRING('Quadratically', 5, 3)\"},\n\n\t\t{\"SELECT CONVERT('111', SIGNED);\", true, \"SELECT CONVERT('111', SIGNED)\"},\n\n\t\t{\"SELECT LEAST(), LEAST(1, 2, 3);\", true, \"SELECT LEAST(),LEAST(1, 2, 3)\"},\n\n\t\t{\"SELECT INTERVAL(1, 0, 1, 2)\", true, \"SELECT INTERVAL(1, 0, 1, 2)\"},\n\t\t{\"SELECT DATE_ADD('2008-01-02', INTERVAL INTERVAL(1, 0, 1) DAY);\", true, \"SELECT DATE_ADD('2008-01-02', INTERVAL INTERVAL(1, 0, 1) DAY)\"},\n\n\t\t// information functions\n\t\t{\"SELECT DATABASE();\", true, \"SELECT DATABASE()\"},\n\t\t{\"SELECT SCHEMA();\", true, \"SELECT SCHEMA()\"},\n\t\t{\"SELECT USER();\", true, \"SELECT USER()\"},\n\t\t{\"SELECT USER(1);\", true, \"SELECT USER(1)\"},\n\t\t{\"SELECT CURRENT_USER();\", true, \"SELECT CURRENT_USER()\"},\n\t\t{\"SELECT CURRENT_ROLE();\", true, \"SELECT CURRENT_ROLE()\"},\n\t\t{\"SELECT CURRENT_USER;\", true, \"SELECT CURRENT_USER()\"},\n\t\t{\"SELECT CONNECTION_ID();\", true, \"SELECT CONNECTION_ID()\"},\n\t\t{\"SELECT VERSION();\", true, \"SELECT VERSION()\"},\n\t\t{\"SELECT BENCHMARK(1000000, AES_ENCRYPT('text',UNHEX('F3229A0B371ED2D9441B830D21A390C3')));\", true, \"SELECT BENCHMARK(1000000, AES_ENCRYPT('text', UNHEX('F3229A0B371ED2D9441B830D21A390C3')))\"},\n\t\t{\"SELECT BENCHMARK(AES_ENCRYPT('text',UNHEX('F3229A0B371ED2D9441B830D21A390C3')));\", true, \"SELECT BENCHMARK(AES_ENCRYPT('text', UNHEX('F3229A0B371ED2D9441B830D21A390C3')))\"},\n\t\t{\"SELECT CHARSET('abc');\", true, \"SELECT CHARSET('abc')\"},\n\t\t{\"SELECT COERCIBILITY('abc');\", true, \"SELECT COERCIBILITY('abc')\"},\n\t\t{\"SELECT COERCIBILITY('abc', 'a');\", true, \"SELECT COERCIBILITY('abc', 'a')\"},\n\t\t{\"SELECT COLLATION('abc');\", true, \"SELECT COLLATION('abc')\"},\n\t\t{\"SELECT ROW_COUNT();\", true, \"SELECT ROW_COUNT()\"},\n\t\t{\"SELECT SESSION_USER();\", true, \"SELECT SESSION_USER()\"},\n\t\t{\"SELECT SYSTEM_USER();\", true, \"SELECT SYSTEM_USER()\"},\n\n\t\t{\"SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2);\", true, \"SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2)\"},\n\t\t{\"SELECT SUBSTRING_INDEX('www.mysql.com', '.', -2);\", true, \"SELECT SUBSTRING_INDEX('www.mysql.com', '.', -2)\"},\n\n\t\t{`SELECT ASCII(), ASCII(\"\"), ASCII(\"A\"), ASCII(1);`, true, \"SELECT ASCII(),ASCII(''),ASCII('A'),ASCII(1)\"},\n\n\t\t{`SELECT LOWER(\"A\"), UPPER(\"a\")`, true, \"SELECT LOWER('A'),UPPER('a')\"},\n\t\t{`SELECT LCASE(\"A\"), UCASE(\"a\")`, true, \"SELECT LCASE('A'),UCASE('a')\"},\n\n\t\t{`SELECT REPLACE('www.mysql.com', 'w', 'Ww')`, true, \"SELECT REPLACE('www.mysql.com', 'w', 'Ww')\"},\n\n\t\t{`SELECT LOCATE('bar', 'foobarbar');`, true, \"SELECT LOCATE('bar', 'foobarbar')\"},\n\t\t{`SELECT LOCATE('bar', 'foobarbar', 5);`, true, \"SELECT LOCATE('bar', 'foobarbar', 5)\"},\n\n\t\t{`SELECT tidb_version();`, true, \"SELECT TIDB_VERSION()\"},\n\t\t{`SELECT tidb_is_ddl_owner();`, true, \"SELECT TIDB_IS_DDL_OWNER()\"},\n\t\t{`SELECT tidb_decode_plan();`, true, \"SELECT TIDB_DECODE_PLAN()\"},\n\t\t{`SELECT tidb_decode_key('abc');`, true, \"SELECT TIDB_DECODE_KEY('abc')\"},\n\n\t\t// // for time fsp\n\t\t// {\"CREATE TABLE t( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) );\", true, \"CREATE TABLE `t` (`c1` TIME(2),`c2` DATETIME(2),`c3` TIMESTAMP(2))\"},\n\n\t\t// for row\n\t\t{\"select row(1)\", false, \"\"},\n\t\t{\"select row(1, 1,)\", false, \"\"},\n\t\t{\"select (1, 1,)\", false, \"\"},\n\t\t{\"select row(1, 1) > row(1, 1), row(1, 1, 1) > row(1, 1, 1)\", true, \"SELECT ROW(1,1)>ROW(1,1),ROW(1,1,1)>ROW(1,1,1)\"},\n\t\t{\"Select (1, 1) > (1, 1)\", true, \"SELECT ROW(1,1)>ROW(1,1)\"},\n\t\t{\"create table t (`row` int)\", true, \"CREATE TABLE `t` (`row` INT)\"},\n\t\t{\"create table t (row int)\", false, \"\"},\n\n\t\t// for cast as JSON\n\t\t{\"SELECT *, CAST(data AS JSON) FROM t;\", true, \"SELECT *,CAST(`data` AS JSON) FROM `t`\"},\n\n\t\t// for cast as signed int, fix issue #3691.\n\t\t{\"select cast(1 as signed int);\", true, \"SELECT CAST(1 AS SIGNED)\"},\n\n\t\t// for cast as double\n\t\t{\"select cast(1 as double);\", true, \"SELECT CAST(1 AS DOUBLE)\"},\n\n\t\t// for cast as float\n\t\t{\"select cast(1 as float);\", true, \"SELECT CAST(1 AS FLOAT)\"},\n\t\t{\"select cast(1 as float(0));\", true, \"SELECT CAST(1 AS FLOAT)\"},\n\t\t{\"select cast(1 as float(24));\", true, \"SELECT CAST(1 AS FLOAT)\"},\n\t\t{\"select cast(1 as float(25));\", true, \"SELECT CAST(1 AS DOUBLE)\"},\n\t\t{\"select cast(1 as float(53));\", true, \"SELECT CAST(1 AS DOUBLE)\"},\n\t\t{\"select cast(1 as float(54));\", false, \"\"},\n\n\t\t// for cast as real\n\t\t{\"select cast(1 as real);\", true, \"SELECT CAST(1 AS DOUBLE)\"},\n\n\t\t// for last_insert_id\n\t\t{\"SELECT last_insert_id();\", true, \"SELECT LAST_INSERT_ID()\"},\n\t\t{\"SELECT last_insert_id(1);\", true, \"SELECT LAST_INSERT_ID(1)\"},\n\n\t\t// for binary operator\n\t\t{\"SELECT binary 'a';\", true, \"SELECT BINARY 'a'\"},\n\n\t\t// for bit_count\n\t\t{`SELECT BIT_COUNT(1);`, true, \"SELECT BIT_COUNT(1)\"},\n\n\t\t// select time\n\t\t{\"select current_timestamp\", true, \"SELECT CURRENT_TIMESTAMP()\"},\n\t\t{\"select current_timestamp()\", true, \"SELECT CURRENT_TIMESTAMP()\"},\n\t\t{\"select current_timestamp(6)\", true, \"SELECT CURRENT_TIMESTAMP(6)\"},\n\t\t{\"select current_timestamp(null)\", false, \"\"},\n\t\t{\"select current_timestamp(-1)\", false, \"\"},\n\t\t{\"select current_timestamp(1.0)\", false, \"\"},\n\t\t{\"select current_timestamp('2')\", false, \"\"},\n\t\t{\"select now()\", true, \"SELECT NOW()\"},\n\t\t{\"select sysdate(), sysdate(6)\", true, \"SELECT SYSDATE(),SYSDATE(6)\"},\n\t\t{\"SELECT time('01:02:03');\", true, \"SELECT TIME('01:02:03')\"},\n\t\t{\"SELECT time('01:02:03.1')\", true, \"SELECT TIME('01:02:03.1')\"},\n\t\t{\"SELECT time('20.1')\", true, \"SELECT TIME('20.1')\"},\n\t\t{\"SELECT TIMEDIFF('2000:01:01 00:00:00', '2000:01:01 00:00:00.000001');\", true, \"SELECT TIMEDIFF('2000:01:01 00:00:00', '2000:01:01 00:00:00.000001')\"},\n\t\t{\"SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01');\", true, \"SELECT TIMESTAMPDIFF(MONTH, '2003-02-01', '2003-05-01')\"},\n\t\t{\"SELECT TIMESTAMPDIFF(YEAR,'2002-05-01','2001-01-01');\", true, \"SELECT TIMESTAMPDIFF(YEAR, '2002-05-01', '2001-01-01')\"},\n\t\t{\"SELECT TIMESTAMPDIFF(MINUTE,'2003-02-01','2003-05-01 12:05:55');\", true, \"SELECT TIMESTAMPDIFF(MINUTE, '2003-02-01', '2003-05-01 12:05:55')\"},\n\n\t\t// select current_time\n\t\t{\"select current_time\", true, \"SELECT CURRENT_TIME()\"},\n\t\t{\"select current_time()\", true, \"SELECT CURRENT_TIME()\"},\n\t\t{\"select current_time(6)\", true, \"SELECT CURRENT_TIME(6)\"},\n\t\t{\"select current_time(-1)\", false, \"\"},\n\t\t{\"select current_time(1.0)\", false, \"\"},\n\t\t{\"select current_time('1')\", false, \"\"},\n\t\t{\"select current_time(null)\", false, \"\"},\n\t\t{\"select curtime()\", true, \"SELECT CURTIME()\"},\n\t\t{\"select curtime(6)\", true, \"SELECT CURTIME(6)\"},\n\t\t{\"select curtime(-1)\", false, \"\"},\n\t\t{\"select curtime(1.0)\", false, \"\"},\n\t\t{\"select curtime('1')\", false, \"\"},\n\t\t{\"select curtime(null)\", false, \"\"},\n\n\t\t// select utc_timestamp\n\t\t{\"select utc_timestamp\", true, \"SELECT UTC_TIMESTAMP()\"},\n\t\t{\"select utc_timestamp()\", true, \"SELECT UTC_TIMESTAMP()\"},\n\t\t{\"select utc_timestamp(6)\", true, \"SELECT UTC_TIMESTAMP(6)\"},\n\t\t{\"select utc_timestamp(-1)\", false, \"\"},\n\t\t{\"select utc_timestamp(1.0)\", false, \"\"},\n\t\t{\"select utc_timestamp('1')\", false, \"\"},\n\t\t{\"select utc_timestamp(null)\", false, \"\"},\n\n\t\t// select utc_time\n\t\t{\"select utc_time\", true, \"SELECT UTC_TIME()\"},\n\t\t{\"select utc_time()\", true, \"SELECT UTC_TIME()\"},\n\t\t{\"select utc_time(6)\", true, \"SELECT UTC_TIME(6)\"},\n\t\t{\"select utc_time(-1)\", false, \"\"},\n\t\t{\"select utc_time(1.0)\", false, \"\"},\n\t\t{\"select utc_time('1')\", false, \"\"},\n\t\t{\"select utc_time(null)\", false, \"\"},\n\n\t\t// for microsecond, second, minute, hour\n\t\t{\"SELECT MICROSECOND('2009-12-31 23:59:59.000010');\", true, \"SELECT MICROSECOND('2009-12-31 23:59:59.000010')\"},\n\t\t{\"SELECT SECOND('10:05:03');\", true, \"SELECT SECOND('10:05:03')\"},\n\t\t{\"SELECT MINUTE('2008-02-03 10:05:03');\", true, \"SELECT MINUTE('2008-02-03 10:05:03')\"},\n\t\t{\"SELECT HOUR(), HOUR('10:05:03');\", true, \"SELECT HOUR(),HOUR('10:05:03')\"},\n\n\t\t// for date, day, weekday\n\t\t{\"SELECT CURRENT_DATE, CURRENT_DATE(), CURDATE()\", true, \"SELECT CURRENT_DATE(),CURRENT_DATE(),CURDATE()\"},\n\t\t{\"SELECT CURRENT_DATE, CURRENT_DATE(), CURDATE(1)\", false, \"\"},\n\t\t{\"SELECT DATEDIFF('2003-12-31', '2003-12-30');\", true, \"SELECT DATEDIFF('2003-12-31', '2003-12-30')\"},\n\t\t{\"SELECT DATE('2003-12-31 01:02:03');\", true, \"SELECT DATE('2003-12-31 01:02:03')\"},\n\t\t{\"SELECT DATE();\", true, \"SELECT DATE()\"},\n\t\t{\"SELECT DATE('2003-12-31 01:02:03', '');\", true, \"SELECT DATE('2003-12-31 01:02:03', '')\"},\n\t\t{`SELECT DATE_FORMAT('2003-12-31 01:02:03', '%W %M %Y');`, true, \"SELECT DATE_FORMAT('2003-12-31 01:02:03', '%W %M %Y')\"},\n\t\t{\"SELECT DAY('2007-02-03');\", true, \"SELECT DAY('2007-02-03')\"},\n\t\t{\"SELECT DAYOFMONTH('2007-02-03');\", true, \"SELECT DAYOFMONTH('2007-02-03')\"},\n\t\t{\"SELECT DAYOFWEEK('2007-02-03');\", true, \"SELECT DAYOFWEEK('2007-02-03')\"},\n\t\t{\"SELECT DAYOFYEAR('2007-02-03');\", true, \"SELECT DAYOFYEAR('2007-02-03')\"},\n\t\t{\"SELECT DAYNAME('2007-02-03');\", true, \"SELECT DAYNAME('2007-02-03')\"},\n\t\t{\"SELECT FROM_DAYS(1423);\", true, \"SELECT FROM_DAYS(1423)\"},\n\t\t{\"SELECT WEEKDAY('2007-02-03');\", true, \"SELECT WEEKDAY('2007-02-03')\"},\n\n\t\t// for utc_date\n\t\t{\"SELECT UTC_DATE, UTC_DATE();\", true, \"SELECT UTC_DATE(),UTC_DATE()\"},\n\t\t{\"SELECT UTC_DATE(), UTC_DATE()+0\", true, \"SELECT UTC_DATE(),UTC_DATE()+0\"},\n\n\t\t// for week, month, year\n\t\t{\"SELECT WEEK();\", true, \"SELECT WEEK()\"},\n\t\t{\"SELECT WEEK('2007-02-03');\", true, \"SELECT WEEK('2007-02-03')\"},\n\t\t{\"SELECT WEEK('2007-02-03', 0);\", true, \"SELECT WEEK('2007-02-03', 0)\"},\n\t\t{\"SELECT WEEKOFYEAR('2007-02-03');\", true, \"SELECT WEEKOFYEAR('2007-02-03')\"},\n\t\t{\"SELECT MONTH('2007-02-03');\", true, \"SELECT MONTH('2007-02-03')\"},\n\t\t{\"SELECT MONTHNAME('2007-02-03');\", true, \"SELECT MONTHNAME('2007-02-03')\"},\n\t\t{\"SELECT YEAR('2007-02-03');\", true, \"SELECT YEAR('2007-02-03')\"},\n\t\t{\"SELECT YEARWEEK('2007-02-03');\", true, \"SELECT YEARWEEK('2007-02-03')\"},\n\t\t{\"SELECT YEARWEEK('2007-02-03', 0);\", true, \"SELECT YEARWEEK('2007-02-03', 0)\"},\n\n\t\t// for ADDTIME, SUBTIME\n\t\t{\"SELECT ADDTIME('01:00:00.999999', '02:00:00.999998');\", true, \"SELECT ADDTIME('01:00:00.999999', '02:00:00.999998')\"},\n\t\t{\"SELECT ADDTIME('02:00:00.999998');\", true, \"SELECT ADDTIME('02:00:00.999998')\"},\n\t\t{\"SELECT ADDTIME();\", true, \"SELECT ADDTIME()\"},\n\t\t{\"SELECT SUBTIME('01:00:00.999999', '02:00:00.999998');\", true, \"SELECT SUBTIME('01:00:00.999999', '02:00:00.999998')\"},\n\n\t\t// for CONVERT_TZ\n\t\t{\"SELECT CONVERT_TZ();\", true, \"SELECT CONVERT_TZ()\"},\n\t\t{\"SELECT CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00');\", true, \"SELECT CONVERT_TZ('2004-01-01 12:00:00', '+00:00', '+10:00')\"},\n\t\t{\"SELECT CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00', '+10:00');\", true, \"SELECT CONVERT_TZ('2004-01-01 12:00:00', '+00:00', '+10:00', '+10:00')\"},\n\n\t\t// for GET_FORMAT\n\t\t{\"SELECT GET_FORMAT(DATE, 'USA');\", true, \"SELECT GET_FORMAT(DATE, 'USA')\"},\n\t\t{\"SELECT GET_FORMAT(DATETIME, 'USA');\", true, \"SELECT GET_FORMAT(DATETIME, 'USA')\"},\n\t\t{\"SELECT GET_FORMAT(TIME, 'USA');\", true, \"SELECT GET_FORMAT(TIME, 'USA')\"},\n\t\t{\"SELECT GET_FORMAT(TIMESTAMP, 'USA');\", true, \"SELECT GET_FORMAT(DATETIME, 'USA')\"},\n\n\t\t// for LOCALTIME, LOCALTIMESTAMP\n\t\t{\"SELECT LOCALTIME(), LOCALTIME(1)\", true, \"SELECT LOCALTIME(),LOCALTIME(1)\"},\n\t\t{\"SELECT LOCALTIMESTAMP(), LOCALTIMESTAMP(2)\", true, \"SELECT LOCALTIMESTAMP(),LOCALTIMESTAMP(2)\"},\n\n\t\t// for MAKEDATE, MAKETIME\n\t\t{\"SELECT MAKEDATE(2011,31);\", true, \"SELECT MAKEDATE(2011, 31)\"},\n\t\t{\"SELECT MAKETIME(12,15,30);\", true, \"SELECT MAKETIME(12, 15, 30)\"},\n\t\t{\"SELECT MAKEDATE();\", true, \"SELECT MAKEDATE()\"},\n\t\t{\"SELECT MAKETIME();\", true, \"SELECT MAKETIME()\"},\n\n\t\t// for PERIOD_ADD, PERIOD_DIFF\n\t\t{\"SELECT PERIOD_ADD(200801,2)\", true, \"SELECT PERIOD_ADD(200801, 2)\"},\n\t\t{\"SELECT PERIOD_DIFF(200802,200703)\", true, \"SELECT PERIOD_DIFF(200802, 200703)\"},\n\n\t\t// for QUARTER\n\t\t{\"SELECT QUARTER('2008-04-01');\", true, \"SELECT QUARTER('2008-04-01')\"},\n\n\t\t// for SEC_TO_TIME\n\t\t{\"SELECT SEC_TO_TIME(2378)\", true, \"SELECT SEC_TO_TIME(2378)\"},\n\n\t\t// for TIME_FORMAT\n\t\t{`SELECT TIME_FORMAT('100:00:00', '%H %k %h %I %l')`, true, \"SELECT TIME_FORMAT('100:00:00', '%H %k %h %I %l')\"},\n\n\t\t// for TIME_TO_SEC\n\t\t{\"SELECT TIME_TO_SEC('22:23:00')\", true, \"SELECT TIME_TO_SEC('22:23:00')\"},\n\n\t\t// for TIMESTAMPADD\n\t\t{\"SELECT TIMESTAMPADD(WEEK,1,'2003-01-02');\", true, \"SELECT TIMESTAMPADD(WEEK, 1, '2003-01-02')\"},\n\t\t{\"SELECT TIMESTAMPADD(SQL_TSI_SECOND,1,'2003-01-02');\", true, \"SELECT TIMESTAMPADD(SECOND, 1, '2003-01-02')\"},\n\t\t{\"SELECT TIMESTAMPADD(SQL_TSI_MINUTE,1,'2003-01-02');\", true, \"SELECT TIMESTAMPADD(MINUTE, 1, '2003-01-02')\"},\n\t\t{\"SELECT TIMESTAMPADD(SQL_TSI_HOUR,1,'2003-01-02');\", true, \"SELECT TIMESTAMPADD(HOUR, 1, '2003-01-02')\"},\n\t\t{\"SELECT TIMESTAMPADD(SQL_TSI_DAY,1,'2003-01-02');\", true, \"SELECT TIMESTAMPADD(DAY, 1, '2003-01-02')\"},\n\t\t{\"SELECT TIMESTAMPADD(SQL_TSI_WEEK,1,'2003-01-02');\", true, \"SELECT TIMESTAMPADD(WEEK, 1, '2003-01-02')\"},\n\t\t{\"SELECT TIMESTAMPADD(SQL_TSI_MONTH,1,'2003-01-02');\", true, \"SELECT TIMESTAMPADD(MONTH, 1, '2003-01-02')\"},\n\t\t{\"SELECT TIMESTAMPADD(SQL_TSI_QUARTER,1,'2003-01-02');\", true, \"SELECT TIMESTAMPADD(QUARTER, 1, '2003-01-02')\"},\n\t\t{\"SELECT TIMESTAMPADD(SQL_TSI_YEAR,1,'2003-01-02');\", true, \"SELECT TIMESTAMPADD(YEAR, 1, '2003-01-02')\"},\n\t\t{\"SELECT TIMESTAMPADD(SQL_TSI_MICROSECOND,1,'2003-01-02');\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPADD(MICROSECOND,1,'2003-01-02');\", true, \"SELECT TIMESTAMPADD(MICROSECOND, 1, '2003-01-02')\"},\n\n\t\t// for TO_DAYS, TO_SECONDS\n\t\t{\"SELECT TO_DAYS('2007-10-07')\", true, \"SELECT TO_DAYS('2007-10-07')\"},\n\t\t{\"SELECT TO_SECONDS('2009-11-29')\", true, \"SELECT TO_SECONDS('2009-11-29')\"},\n\n\t\t// for LAST_DAY\n\t\t{\"SELECT LAST_DAY('2003-02-05');\", true, \"SELECT LAST_DAY('2003-02-05')\"},\n\n\t\t// for UTC_TIME\n\t\t{\"SELECT UTC_TIME(), UTC_TIME(1)\", true, \"SELECT UTC_TIME(),UTC_TIME(1)\"},\n\n\t\t// for time extract\n\t\t{`select extract(microsecond from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(MICROSECOND FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(second from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(SECOND FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(minute from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(MINUTE FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(hour from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(HOUR FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(day from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(DAY FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(week from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(WEEK FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(month from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(MONTH FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(quarter from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(QUARTER FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(year from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(YEAR FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(second_microsecond from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(SECOND_MICROSECOND FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(minute_microsecond from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(MINUTE_MICROSECOND FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(minute_second from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(MINUTE_SECOND FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(hour_microsecond from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(HOUR_MICROSECOND FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(hour_second from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(HOUR_SECOND FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(hour_minute from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(HOUR_MINUTE FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(day_microsecond from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(DAY_MICROSECOND FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(day_second from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(DAY_SECOND FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(day_minute from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(DAY_MINUTE FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(day_hour from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(DAY_HOUR FROM '2011-11-11 10:10:10.123456')\"},\n\t\t{`select extract(year_month from \"2011-11-11 10:10:10.123456\")`, true, \"SELECT EXTRACT(YEAR_MONTH FROM '2011-11-11 10:10:10.123456')\"},\n\n\t\t// for from_unixtime\n\t\t{`select from_unixtime(1447430881)`, true, \"SELECT FROM_UNIXTIME(1447430881)\"},\n\t\t{`select from_unixtime(1447430881.123456)`, true, \"SELECT FROM_UNIXTIME(1447430881.123456)\"},\n\t\t{`select from_unixtime(1447430881.1234567)`, true, \"SELECT FROM_UNIXTIME(1447430881.1234567)\"},\n\t\t{`select from_unixtime(1447430881.9999999)`, true, \"SELECT FROM_UNIXTIME(1447430881.9999999)\"},\n\t\t{`select from_unixtime(1447430881, \"%Y %D %M %h:%i:%s %x\")`, true, \"SELECT FROM_UNIXTIME(1447430881, '%Y %D %M %h:%i:%s %x')\"},\n\t\t{`select from_unixtime(1447430881.123456, \"%Y %D %M %h:%i:%s %x\")`, true, \"SELECT FROM_UNIXTIME(1447430881.123456, '%Y %D %M %h:%i:%s %x')\"},\n\t\t{`select from_unixtime(1447430881.1234567, \"%Y %D %M %h:%i:%s %x\")`, true, \"SELECT FROM_UNIXTIME(1447430881.1234567, '%Y %D %M %h:%i:%s %x')\"},\n\n\t\t// for string functions\n\t\t// trim\n\t\t{`SELECT TRIM('  bar   ');`, true, \"SELECT TRIM('  bar   ')\"},\n\t\t{`SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx');`, true, \"SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx')\"},\n\t\t{`SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx');`, true, \"SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx')\"},\n\t\t{`SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz');`, true, \"SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz')\"},\n\t\t{`SELECT LTRIM(' foo ');`, true, \"SELECT LTRIM(' foo ')\"},\n\t\t{`SELECT RTRIM(' bar ');`, true, \"SELECT RTRIM(' bar ')\"},\n\n\t\t{`SELECT RPAD('hi', 6, 'c');`, true, \"SELECT RPAD('hi', 6, 'c')\"},\n\t\t{`SELECT BIT_LENGTH('hi');`, true, \"SELECT BIT_LENGTH('hi')\"},\n\t\t{`SELECT CHAR(65);`, true, \"SELECT CHAR_FUNC(65, NULL)\"},\n\t\t{`SELECT CHAR_LENGTH('abc');`, true, \"SELECT CHAR_LENGTH('abc')\"},\n\t\t{`SELECT CHARACTER_LENGTH('abc');`, true, \"SELECT CHARACTER_LENGTH('abc')\"},\n\t\t{`SELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo');`, true, \"SELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo')\"},\n\t\t{`SELECT FIND_IN_SET('foo', 'foo,bar')`, true, \"SELECT FIND_IN_SET('foo', 'foo,bar')\"},\n\t\t{`SELECT FIND_IN_SET('foo')`, true, \"SELECT FIND_IN_SET('foo')\"}, // illegal number of argument still pass\n\t\t{`SELECT MAKE_SET(1,'a'), MAKE_SET(1,'a','b','c')`, true, \"SELECT MAKE_SET(1, 'a'),MAKE_SET(1, 'a', 'b', 'c')\"},\n\t\t{`SELECT MID('Sakila', -5, 3)`, true, \"SELECT MID('Sakila', -5, 3)\"},\n\t\t{`SELECT OCT(12)`, true, \"SELECT OCT(12)\"},\n\t\t{`SELECT OCTET_LENGTH('text')`, true, \"SELECT OCTET_LENGTH('text')\"},\n\t\t{`SELECT ORD('2')`, true, \"SELECT ORD('2')\"},\n\t\t{`SELECT POSITION('bar' IN 'foobarbar')`, true, \"SELECT POSITION('bar' IN 'foobarbar')\"},\n\t\t{`SELECT QUOTE('Don\\'t!')`, true, \"SELECT QUOTE('Don''t!')\"},\n\t\t{`SELECT BIN(12)`, true, \"SELECT BIN(12)\"},\n\t\t{`SELECT ELT(1, 'ej', 'Heja', 'hej', 'foo')`, true, \"SELECT ELT(1, 'ej', 'Heja', 'hej', 'foo')\"},\n\t\t{`SELECT EXPORT_SET(5,'Y','N'), EXPORT_SET(5,'Y','N',','), EXPORT_SET(5,'Y','N',',',4)`, true, \"SELECT EXPORT_SET(5, 'Y', 'N'),EXPORT_SET(5, 'Y', 'N', ','),EXPORT_SET(5, 'Y', 'N', ',', 4)\"},\n\t\t{`SELECT FORMAT(), FORMAT(12332.2,2,'de_DE'), FORMAT(12332.123456, 4)`, true, \"SELECT FORMAT(),FORMAT(12332.2, 2, 'de_DE'),FORMAT(12332.123456, 4)\"},\n\t\t{`SELECT FROM_BASE64('abc')`, true, \"SELECT FROM_BASE64('abc')\"},\n\t\t{`SELECT TO_BASE64('abc')`, true, \"SELECT TO_BASE64('abc')\"},\n\t\t{`SELECT INSERT(), INSERT('Quadratic', 3, 4, 'What'), INSTR('foobarbar', 'bar')`, true, \"SELECT INSERT_FUNC(),INSERT_FUNC('Quadratic', 3, 4, 'What'),INSTR('foobarbar', 'bar')\"},\n\t\t{`SELECT LOAD_FILE('/tmp/picture')`, true, \"SELECT LOAD_FILE('/tmp/picture')\"},\n\t\t{`SELECT LPAD('hi',4,'??')`, true, \"SELECT LPAD('hi', 4, '??')\"},\n\t\t{`SELECT LEFT(\"foobar\", 3)`, true, \"SELECT LEFT('foobar', 3)\"},\n\t\t{`SELECT RIGHT(\"foobar\", 3)`, true, \"SELECT RIGHT('foobar', 3)\"},\n\n\t\t// repeat\n\t\t{`SELECT REPEAT(\"a\", 10);`, true, \"SELECT REPEAT('a', 10)\"},\n\n\t\t// for miscellaneous functions\n\t\t{`SELECT SLEEP(10);`, true, \"SELECT SLEEP(10)\"},\n\t\t{`SELECT ANY_VALUE(@arg);`, true, \"SELECT ANY_VALUE(@`arg`)\"},\n\t\t{`SELECT INET_ATON('10.0.5.9');`, true, \"SELECT INET_ATON('10.0.5.9')\"},\n\t\t{`SELECT INET_NTOA(167773449);`, true, \"SELECT INET_NTOA(167773449)\"},\n\t\t{`SELECT INET6_ATON('fdfe::5a55:caff:fefa:9089');`, true, \"SELECT INET6_ATON('fdfe::5a55:caff:fefa:9089')\"},\n\t\t{`SELECT INET6_NTOA(INET_NTOA(167773449));`, true, \"SELECT INET6_NTOA(INET_NTOA(167773449))\"},\n\t\t{`SELECT IS_FREE_LOCK(@str);`, true, \"SELECT IS_FREE_LOCK(@`str`)\"},\n\t\t{`SELECT IS_IPV4('10.0.5.9');`, true, \"SELECT IS_IPV4('10.0.5.9')\"},\n\t\t{`SELECT IS_IPV4_COMPAT(INET6_ATON('::10.0.5.9'));`, true, \"SELECT IS_IPV4_COMPAT(INET6_ATON('::10.0.5.9'))\"},\n\t\t{`SELECT IS_IPV4_MAPPED(INET6_ATON('::10.0.5.9'));`, true, \"SELECT IS_IPV4_MAPPED(INET6_ATON('::10.0.5.9'))\"},\n\t\t{`SELECT IS_IPV6('10.0.5.9');`, true, \"SELECT IS_IPV6('10.0.5.9')\"},\n\t\t{`SELECT IS_USED_LOCK(@str);`, true, \"SELECT IS_USED_LOCK(@`str`)\"},\n\t\t{`SELECT MASTER_POS_WAIT(@log_name, @log_pos), MASTER_POS_WAIT(@log_name, @log_pos, @timeout), MASTER_POS_WAIT(@log_name, @log_pos, @timeout, @channel_name);`, true, \"SELECT MASTER_POS_WAIT(@`log_name`, @`log_pos`),MASTER_POS_WAIT(@`log_name`, @`log_pos`, @`timeout`),MASTER_POS_WAIT(@`log_name`, @`log_pos`, @`timeout`, @`channel_name`)\"},\n\t\t{`SELECT NAME_CONST('myname', 14);`, true, \"SELECT NAME_CONST('myname', 14)\"},\n\t\t{`SELECT RELEASE_ALL_LOCKS();`, true, \"SELECT RELEASE_ALL_LOCKS()\"},\n\t\t{`SELECT UUID();`, true, \"SELECT UUID()\"},\n\t\t{`SELECT UUID_SHORT()`, true, \"SELECT UUID_SHORT()\"},\n\t\t// test illegal arguments\n\t\t{`SELECT SLEEP();`, true, \"SELECT SLEEP()\"},\n\t\t{`SELECT ANY_VALUE();`, true, \"SELECT ANY_VALUE()\"},\n\t\t{`SELECT INET_ATON();`, true, \"SELECT INET_ATON()\"},\n\t\t{`SELECT INET_NTOA();`, true, \"SELECT INET_NTOA()\"},\n\t\t{`SELECT INET6_ATON();`, true, \"SELECT INET6_ATON()\"},\n\t\t{`SELECT INET6_NTOA(INET_NTOA());`, true, \"SELECT INET6_NTOA(INET_NTOA())\"},\n\t\t{`SELECT IS_FREE_LOCK();`, true, \"SELECT IS_FREE_LOCK()\"},\n\t\t{`SELECT IS_IPV4();`, true, \"SELECT IS_IPV4()\"},\n\t\t{`SELECT IS_IPV4_COMPAT(INET6_ATON());`, true, \"SELECT IS_IPV4_COMPAT(INET6_ATON())\"},\n\t\t{`SELECT IS_IPV4_MAPPED(INET6_ATON());`, true, \"SELECT IS_IPV4_MAPPED(INET6_ATON())\"},\n\t\t{`SELECT IS_IPV6()`, true, \"SELECT IS_IPV6()\"},\n\t\t{`SELECT IS_USED_LOCK();`, true, \"SELECT IS_USED_LOCK()\"},\n\t\t{`SELECT MASTER_POS_WAIT();`, true, \"SELECT MASTER_POS_WAIT()\"},\n\t\t{`SELECT NAME_CONST();`, true, \"SELECT NAME_CONST()\"},\n\t\t{`SELECT RELEASE_ALL_LOCKS(1);`, true, \"SELECT RELEASE_ALL_LOCKS(1)\"},\n\t\t{`SELECT UUID(1);`, true, \"SELECT UUID(1)\"},\n\t\t{`SELECT UUID_SHORT(1)`, true, \"SELECT UUID_SHORT(1)\"},\n\t\t// interval\n\t\t{`select \"2011-11-11 10:10:10.123456\" + interval 10 second`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10 SECOND)\"},\n\t\t{`select \"2011-11-11 10:10:10.123456\" - interval 10 second`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 10 SECOND)\"},\n\t\t// for date_add\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10 microsecond)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10 MICROSECOND)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10 second)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10 SECOND)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10 minute)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10 MINUTE)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10 hour)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10 HOUR)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10 day)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10 DAY)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 1 week)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 1 WEEK)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 1 month)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 1 MONTH)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 1 quarter)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 1 QUARTER)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 1 year)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 1 YEAR)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"10.10\" second_microsecond)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '10.10' SECOND_MICROSECOND)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"10:10.10\" minute_microsecond)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '10:10.10' MINUTE_MICROSECOND)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"10:10\" minute_second)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '10:10' MINUTE_SECOND)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"10:10:10.10\" hour_microsecond)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '10:10:10.10' HOUR_MICROSECOND)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"10:10:10\" hour_second)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '10:10:10' HOUR_SECOND)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"10:10\" hour_minute)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '10:10' HOUR_MINUTE)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10.10 hour_minute)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10.10 HOUR_MINUTE)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"11 10:10:10.10\" day_microsecond)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '11 10:10:10.10' DAY_MICROSECOND)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"11 10:10:10\" day_second)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '11 10:10:10' DAY_SECOND)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"11 10:10\" day_minute)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '11 10:10' DAY_MINUTE)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"11 10\" day_hour)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '11 10' DAY_HOUR)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval \"11-11\" year_month)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL '11-11' YEAR_MONTH)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", 10)`, false, \"\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", 0.10)`, false, \"\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", \"11,11\")`, false, \"\"},\n\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10 sql_tsi_microsecond)`, false, \"\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10 sql_tsi_second)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10 SECOND)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10 sql_tsi_minute)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10 MINUTE)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10 sql_tsi_hour)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10 HOUR)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 10 sql_tsi_day)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 10 DAY)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 1 sql_tsi_week)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 1 WEEK)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 1 sql_tsi_month)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 1 MONTH)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 1 sql_tsi_quarter)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 1 QUARTER)\"},\n\t\t{`select date_add(\"2011-11-11 10:10:10.123456\", interval 1 sql_tsi_year)`, true, \"SELECT DATE_ADD('2011-11-11 10:10:10.123456', INTERVAL 1 YEAR)\"},\n\n\t\t// for strcmp\n\t\t{`select strcmp('abc', 'def')`, true, \"SELECT STRCMP('abc', 'def')\"},\n\n\t\t// for adddate\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval 10 microsecond)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 10 MICROSECOND)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval 10 second)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 10 SECOND)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval 10 minute)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 10 MINUTE)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval 10 hour)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 10 HOUR)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval 10 day)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 10 DAY)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval 1 week)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 1 WEEK)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval 1 month)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 1 MONTH)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval 1 quarter)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 1 QUARTER)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval 1 year)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 1 YEAR)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"10.10\" second_microsecond)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '10.10' SECOND_MICROSECOND)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"10:10.10\" minute_microsecond)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '10:10.10' MINUTE_MICROSECOND)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"10:10\" minute_second)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '10:10' MINUTE_SECOND)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"10:10:10.10\" hour_microsecond)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '10:10:10.10' HOUR_MICROSECOND)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"10:10:10\" hour_second)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '10:10:10' HOUR_SECOND)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"10:10\" hour_minute)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '10:10' HOUR_MINUTE)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval 10.10 hour_minute)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 10.10 HOUR_MINUTE)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"11 10:10:10.10\" day_microsecond)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '11 10:10:10.10' DAY_MICROSECOND)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"11 10:10:10\" day_second)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '11 10:10:10' DAY_SECOND)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"11 10:10\" day_minute)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '11 10:10' DAY_MINUTE)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"11 10\" day_hour)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '11 10' DAY_HOUR)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", interval \"11-11\" year_month)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '11-11' YEAR_MONTH)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", 10)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 10 DAY)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", 0.10)`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL 0.10 DAY)\"},\n\t\t{`select adddate(\"2011-11-11 10:10:10.123456\", \"11,11\")`, true, \"SELECT ADDDATE('2011-11-11 10:10:10.123456', INTERVAL '11,11' DAY)\"},\n\n\t\t// for date_sub\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval 10 microsecond)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 10 MICROSECOND)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval 10 second)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 10 SECOND)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval 10 minute)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 10 MINUTE)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval 10 hour)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 10 HOUR)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval 10 day)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 10 DAY)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval 1 week)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 1 WEEK)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval 1 month)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 1 MONTH)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval 1 quarter)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 1 QUARTER)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval 1 year)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 1 YEAR)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"10.10\" second_microsecond)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '10.10' SECOND_MICROSECOND)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"10:10.10\" minute_microsecond)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '10:10.10' MINUTE_MICROSECOND)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"10:10\" minute_second)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '10:10' MINUTE_SECOND)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"10:10:10.10\" hour_microsecond)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '10:10:10.10' HOUR_MICROSECOND)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"10:10:10\" hour_second)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '10:10:10' HOUR_SECOND)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"10:10\" hour_minute)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '10:10' HOUR_MINUTE)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval 10.10 hour_minute)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL 10.10 HOUR_MINUTE)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"11 10:10:10.10\" day_microsecond)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '11 10:10:10.10' DAY_MICROSECOND)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"11 10:10:10\" day_second)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '11 10:10:10' DAY_SECOND)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"11 10:10\" day_minute)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '11 10:10' DAY_MINUTE)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"11 10\" day_hour)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '11 10' DAY_HOUR)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", interval \"11-11\" year_month)`, true, \"SELECT DATE_SUB('2011-11-11 10:10:10.123456', INTERVAL '11-11' YEAR_MONTH)\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", 10)`, false, \"\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", 0.10)`, false, \"\"},\n\t\t{`select date_sub(\"2011-11-11 10:10:10.123456\", \"11,11\")`, false, \"\"},\n\n\t\t// for subdate\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval 10 microsecond)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 10 MICROSECOND)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval 10 second)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 10 SECOND)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval 10 minute)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 10 MINUTE)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval 10 hour)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 10 HOUR)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval 10 day)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 10 DAY)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval 1 week)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 1 WEEK)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval 1 month)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 1 MONTH)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval 1 quarter)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 1 QUARTER)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval 1 year)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 1 YEAR)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"10.10\" second_microsecond)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '10.10' SECOND_MICROSECOND)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"10:10.10\" minute_microsecond)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '10:10.10' MINUTE_MICROSECOND)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"10:10\" minute_second)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '10:10' MINUTE_SECOND)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"10:10:10.10\" hour_microsecond)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '10:10:10.10' HOUR_MICROSECOND)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"10:10:10\" hour_second)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '10:10:10' HOUR_SECOND)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"10:10\" hour_minute)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '10:10' HOUR_MINUTE)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval 10.10 hour_minute)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 10.10 HOUR_MINUTE)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"11 10:10:10.10\" day_microsecond)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '11 10:10:10.10' DAY_MICROSECOND)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"11 10:10:10\" day_second)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '11 10:10:10' DAY_SECOND)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"11 10:10\" day_minute)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '11 10:10' DAY_MINUTE)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"11 10\" day_hour)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '11 10' DAY_HOUR)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", interval \"11-11\" year_month)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '11-11' YEAR_MONTH)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", 10)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 10 DAY)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", 0.10)`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL 0.10 DAY)\"},\n\t\t{`select subdate(\"2011-11-11 10:10:10.123456\", \"11,11\")`, true, \"SELECT SUBDATE('2011-11-11 10:10:10.123456', INTERVAL '11,11' DAY)\"},\n\n\t\t// for unix_timestamp\n\t\t{`select unix_timestamp()`, true, \"SELECT UNIX_TIMESTAMP()\"},\n\t\t{`select unix_timestamp('2015-11-13 10:20:19.012')`, true, \"SELECT UNIX_TIMESTAMP('2015-11-13 10:20:19.012')\"},\n\n\t\t// for misc functions\n\t\t{`SELECT GET_LOCK('lock1',10);`, true, \"SELECT GET_LOCK('lock1', 10)\"},\n\t\t{`SELECT RELEASE_LOCK('lock1');`, true, \"SELECT RELEASE_LOCK('lock1')\"},\n\n\t\t// for aggregate functions\n\t\t{`select avg(), avg(c1,c2) from t;`, false, \"SELECT AVG(),AVG(`c1`, `c2`) FROM `t`\"},\n\t\t{`select avg(distinct c1) from t;`, true, \"SELECT AVG(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select avg(distinctrow c1) from t;`, true, \"SELECT AVG(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select avg(distinct all c1) from t;`, true, \"SELECT AVG(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select avg(distinctrow all c1) from t;`, true, \"SELECT AVG(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select avg(c2) from t;`, true, \"SELECT AVG(`c2`) FROM `t`\"},\n\t\t{`select bit_and(c1) from t;`, true, \"SELECT BIT_AND(`c1`) FROM `t`\"},\n\t\t{`select bit_and(all c1) from t;`, true, \"SELECT BIT_AND(`c1`) FROM `t`\"},\n\t\t{`select bit_and(distinct c1) from t;`, false, \"\"},\n\t\t{`select bit_and(distinctrow c1) from t;`, false, \"\"},\n\t\t{`select bit_and(distinctrow all c1) from t;`, false, \"\"},\n\t\t{`select bit_and(distinct all c1) from t;`, false, \"\"},\n\t\t{`select bit_and(), bit_and(distinct c1) from t;`, false, \"\"},\n\t\t{`select bit_and(), bit_and(distinctrow c1) from t;`, false, \"\"},\n\t\t{`select bit_and(), bit_and(all c1) from t;`, false, \"\"},\n\t\t{`select bit_or(c1) from t;`, true, \"SELECT BIT_OR(`c1`) FROM `t`\"},\n\t\t{`select bit_or(all c1) from t;`, true, \"SELECT BIT_OR(`c1`) FROM `t`\"},\n\t\t{`select bit_or(distinct c1) from t;`, false, \"\"},\n\t\t{`select bit_or(distinctrow c1) from t;`, false, \"\"},\n\t\t{`select bit_or(distinctrow all c1) from t;`, false, \"\"},\n\t\t{`select bit_or(distinct all c1) from t;`, false, \"\"},\n\t\t{`select bit_or(), bit_or(distinct c1) from t;`, false, \"\"},\n\t\t{`select bit_or(), bit_or(distinctrow c1) from t;`, false, \"\"},\n\t\t{`select bit_or(), bit_or(all c1) from t;`, false, \"\"},\n\t\t{`select bit_xor(c1) from t;`, true, \"SELECT BIT_XOR(`c1`) FROM `t`\"},\n\t\t{`select bit_xor(all c1) from t;`, true, \"SELECT BIT_XOR(`c1`) FROM `t`\"},\n\t\t{`select bit_xor(distinct c1) from t;`, false, \"\"},\n\t\t{`select bit_xor(distinctrow c1) from t;`, false, \"\"},\n\t\t{`select bit_xor(distinctrow all c1) from t;`, false, \"\"},\n\t\t{`select bit_xor(), bit_xor(distinct c1) from t;`, false, \"\"},\n\t\t{`select bit_xor(), bit_xor(distinctrow c1) from t;`, false, \"\"},\n\t\t{`select bit_xor(), bit_xor(all c1) from t;`, false, \"\"},\n\t\t{`select max(c1,c2) from t;`, false, \"\"},\n\t\t{`select max(distinct c1) from t;`, true, \"SELECT MAX(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select max(distinctrow c1) from t;`, true, \"SELECT MAX(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select max(distinct all c1) from t;`, true, \"SELECT MAX(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select max(distinctrow all c1) from t;`, true, \"SELECT MAX(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select max(c2) from t;`, true, \"SELECT MAX(`c2`) FROM `t`\"},\n\t\t{`select min(c1,c2) from t;`, false, \"\"},\n\t\t{`select min(distinct c1) from t;`, true, \"SELECT MIN(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select min(distinctrow c1) from t;`, true, \"SELECT MIN(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select min(distinct all c1) from t;`, true, \"SELECT MIN(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select min(distinctrow all c1) from t;`, true, \"SELECT MIN(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select min(c2) from t;`, true, \"SELECT MIN(`c2`) FROM `t`\"},\n\t\t{`select sum(c1,c2) from t;`, false, \"\"},\n\t\t{`select sum(distinct c1) from t;`, true, \"SELECT SUM(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select sum(distinctrow c1) from t;`, true, \"SELECT SUM(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select sum(distinct all c1) from t;`, true, \"SELECT SUM(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select sum(distinctrow all c1) from t;`, true, \"SELECT SUM(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select sum(c2) from t;`, true, \"SELECT SUM(`c2`) FROM `t`\"},\n\t\t{`select count(c1) from t;`, true, \"SELECT COUNT(`c1`) FROM `t`\"},\n\t\t{`select count(distinct *) from t;`, false, \"\"},\n\t\t{`select count(distinctrow *) from t;`, false, \"\"},\n\t\t{`select count(*) from t;`, true, \"SELECT COUNT(1) FROM `t`\"},\n\t\t{`select count(distinct c1, c2) from t;`, true, \"SELECT COUNT(DISTINCT `c1`, `c2`) FROM `t`\"},\n\t\t{`select count(distinctrow c1, c2) from t;`, true, \"SELECT COUNT(DISTINCT `c1`, `c2`) FROM `t`\"},\n\t\t{`select count(c1, c2) from t;`, false, \"\"},\n\t\t{`select count(all c1) from t;`, true, \"SELECT COUNT(`c1`) FROM `t`\"},\n\t\t{`select count(distinct all c1) from t;`, false, \"\"},\n\t\t{`select count(distinctrow all c1) from t;`, false, \"\"},\n\t\t{`select group_concat(c2,c1) from t group by c1;`, true, \"SELECT GROUP_CONCAT(`c2`, `c1` SEPARATOR ',') FROM `t` GROUP BY `c1`\"},\n\t\t{`select group_concat(c2,c1 SEPARATOR ';') from t group by c1;`, true, \"SELECT GROUP_CONCAT(`c2`, `c1` SEPARATOR ';') FROM `t` GROUP BY `c1`\"},\n\t\t{`select group_concat(distinct c2,c1) from t group by c1;`, true, \"SELECT GROUP_CONCAT(DISTINCT `c2`, `c1` SEPARATOR ',') FROM `t` GROUP BY `c1`\"},\n\t\t{`select group_concat(distinctrow c2,c1) from t group by c1;`, true, \"SELECT GROUP_CONCAT(DISTINCT `c2`, `c1` SEPARATOR ',') FROM `t` GROUP BY `c1`\"},\n\t\t{`SELECT student_name, GROUP_CONCAT(DISTINCT test_score ORDER BY test_score DESC SEPARATOR ' ') FROM student GROUP BY student_name;`, true, \"SELECT `student_name`,GROUP_CONCAT(DISTINCT `test_score` SEPARATOR ' ') FROM `student` GROUP BY `student_name`\"},\n\t\t{`select std(c1), std(all c1), std(distinct c1) from t`, true, \"SELECT STDDEV_POP(`c1`),STDDEV_POP(`c1`),STDDEV_POP(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select std(c1, c2) from t`, false, \"\"},\n\t\t{`select stddev(c1), stddev(all c1), stddev(distinct c1) from t`, true, \"SELECT STDDEV_POP(`c1`),STDDEV_POP(`c1`),STDDEV_POP(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select stddev(c1, c2) from t`, false, \"\"},\n\t\t{`select stddev_pop(c1), stddev_pop(all c1), stddev_pop(distinct c1) from t`, true, \"SELECT STDDEV_POP(`c1`),STDDEV_POP(`c1`),STDDEV_POP(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select stddev_pop(c1, c2) from t`, false, \"\"},\n\t\t{`select stddev_samp(c1), stddev_samp(all c1), stddev_samp(distinct c1) from t`, true, \"SELECT STDDEV_SAMP(`c1`),STDDEV_SAMP(`c1`),STDDEV_SAMP(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select stddev_samp(c1, c2) from t`, false, \"\"},\n\t\t{`select variance(c1), variance(all c1), variance(distinct c1) from t`, true, \"SELECT VAR_POP(`c1`),VAR_POP(`c1`),VAR_POP(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select variance(c1, c2) from t`, false, \"\"},\n\t\t{`select var_pop(c1), var_pop(all c1), var_pop(distinct c1) from t`, true, \"SELECT VAR_POP(`c1`),VAR_POP(`c1`),VAR_POP(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select var_pop(c1, c2) from t`, false, \"\"},\n\t\t{`select var_samp(c1), var_samp(all c1), var_samp(distinct c1) from t`, true, \"SELECT VAR_SAMP(`c1`),VAR_SAMP(`c1`),VAR_SAMP(DISTINCT `c1`) FROM `t`\"},\n\t\t{`select var_samp(c1, c2) from t`, false, \"\"},\n\n\t\t// for encryption and compression functions\n\t\t{`select AES_ENCRYPT('text',UNHEX('F3229A0B371ED2D9441B830D21A390C3'))`, true, \"SELECT AES_ENCRYPT('text', UNHEX('F3229A0B371ED2D9441B830D21A390C3'))\"},\n\t\t{`select AES_DECRYPT(@crypt_str,@key_str)`, true, \"SELECT AES_DECRYPT(@`crypt_str`, @`key_str`)\"},\n\t\t{`select AES_DECRYPT(@crypt_str,@key_str,@init_vector);`, true, \"SELECT AES_DECRYPT(@`crypt_str`, @`key_str`, @`init_vector`)\"},\n\t\t{`SELECT COMPRESS('');`, true, \"SELECT COMPRESS('')\"},\n\t\t{`SELECT DECODE(@crypt_str, @pass_str);`, true, \"SELECT DECODE(@`crypt_str`, @`pass_str`)\"},\n\t\t{`SELECT DES_DECRYPT(@crypt_str), DES_DECRYPT(@crypt_str, @key_str);`, true, \"SELECT DES_DECRYPT(@`crypt_str`),DES_DECRYPT(@`crypt_str`, @`key_str`)\"},\n\t\t{`SELECT DES_ENCRYPT(@str), DES_ENCRYPT(@key_num);`, true, \"SELECT DES_ENCRYPT(@`str`),DES_ENCRYPT(@`key_num`)\"},\n\t\t{`SELECT ENCODE('cleartext', CONCAT('my_random_salt','my_secret_password'));`, true, \"SELECT ENCODE('cleartext', CONCAT('my_random_salt', 'my_secret_password'))\"},\n\t\t{`SELECT ENCRYPT('hello'), ENCRYPT('hello', @salt);`, true, \"SELECT ENCRYPT('hello'),ENCRYPT('hello', @`salt`)\"},\n\t\t{`SELECT MD5('testing');`, true, \"SELECT MD5('testing')\"},\n\t\t{`SELECT OLD_PASSWORD(@str);`, true, \"SELECT OLD_PASSWORD(@`str`)\"},\n\t\t{`SELECT PASSWORD(@str);`, true, \"SELECT PASSWORD_FUNC(@`str`)\"},\n\t\t{`SELECT RANDOM_BYTES(@len);`, true, \"SELECT RANDOM_BYTES(@`len`)\"},\n\t\t{`SELECT SHA1('abc');`, true, \"SELECT SHA1('abc')\"},\n\t\t{`SELECT SHA('abc');`, true, \"SELECT SHA('abc')\"},\n\t\t{`SELECT SHA2('abc', 224);`, true, \"SELECT SHA2('abc', 224)\"},\n\t\t{`SELECT UNCOMPRESS('any string');`, true, \"SELECT UNCOMPRESS('any string')\"},\n\t\t{`SELECT UNCOMPRESSED_LENGTH(@compressed_string);`, true, \"SELECT UNCOMPRESSED_LENGTH(@`compressed_string`)\"},\n\t\t{`SELECT VALIDATE_PASSWORD_STRENGTH(@str);`, true, \"SELECT VALIDATE_PASSWORD_STRENGTH(@`str`)\"},\n\n\t\t// For JSON functions.\n\t\t{`SELECT JSON_EXTRACT();`, true, \"SELECT JSON_EXTRACT()\"},\n\t\t{`SELECT JSON_UNQUOTE();`, true, \"SELECT JSON_UNQUOTE()\"},\n\t\t{`SELECT JSON_TYPE('[123]');`, true, \"SELECT JSON_TYPE('[123]')\"},\n\t\t{`SELECT JSON_TYPE();`, true, \"SELECT JSON_TYPE()\"},\n\n\t\t// For two json grammar sugar.\n\t\t{`SELECT a->'$.a' FROM t`, true, \"SELECT JSON_EXTRACT(`a`, '$.a') FROM `t`\"},\n\t\t{`SELECT a->>'$.a' FROM t`, true, \"SELECT JSON_UNQUOTE(JSON_EXTRACT(`a`, '$.a')) FROM `t`\"},\n\t\t{`SELECT '{}'->'$.a' FROM t`, false, \"\"},\n\t\t{`SELECT '{}'->>'$.a' FROM t`, false, \"\"},\n\t\t{`SELECT a->3 FROM t`, false, \"\"},\n\t\t{`SELECT a->>3 FROM t`, false, \"\"},\n\n\t\t// Test that quoted identifier can be a function name.\n\t\t{\"SELECT `uuid`()\", true, \"SELECT UUID()\"},\n\t}\n\ts.RunTest(c, table)\n\n\t// Test in REAL_AS_FLOAT SQL mode.\n\ttable2 := []testCase{\n\t\t// for cast as float\n\t\t{\"select cast(1 as float);\", true, \"SELECT CAST(1 AS FLOAT)\"},\n\t\t{\"select cast(1 as float(0));\", true, \"SELECT CAST(1 AS FLOAT)\"},\n\t\t{\"select cast(1 as float(24));\", true, \"SELECT CAST(1 AS FLOAT)\"},\n\t\t{\"select cast(1 as float(25));\", true, \"SELECT CAST(1 AS DOUBLE)\"},\n\t\t{\"select cast(1 as float(53));\", true, \"SELECT CAST(1 AS DOUBLE)\"},\n\t\t{\"select cast(1 as float(54));\", false, \"\"},\n\n\t\t// for cast as real\n\t\t{\"select cast(1 as real);\", true, \"SELECT CAST(1 AS FLOAT)\"},\n\t}\n\ts.RunTestInRealAsFloatMode(c, table2)\n}\n\nfunc (s *testParserSuite) TestIdentifier(c *C) {\n\ttable := []testCase{\n\t\t// for quote identifier\n\t\t{\"select `a`, `a.b`, `a b` from t\", true, \"SELECT `a`,`a.b`,`a b` FROM `t`\"},\n\t\t// for unquoted identifier\n\t\t// {\"create table MergeContextTest$Simple (value integer not null, primary key (value))\", true, \"CREATE TABLE `MergeContextTest$Simple` (`value` INT NOT NULL,PRIMARY KEY(`value`))\"},\n\t\t// for as\n\t\t{\"select 1 as a, 1 as `a`, 1 as \\\"a\\\", 1 as 'a'\", true, \"SELECT 1 AS `a`,1 AS `a`,1 AS `a`,1 AS `a`\"},\n\t\t{`select 1 as a, 1 as \"a\", 1 as 'a'`, true, \"SELECT 1 AS `a`,1 AS `a`,1 AS `a`\"},\n\t\t{`select 1 a, 1 \"a\", 1 'a'`, true, \"SELECT 1 AS `a`,1 AS `a`,1 AS `a`\"},\n\t\t{`select * from t as \"a\"`, false, \"\"},\n\t\t{`select * from t a`, true, \"SELECT * FROM `t` AS `a`\"},\n\t\t// reserved keyword can't be used as identifier directly, but A.B pattern is an exception\n\t\t{`select COUNT from DESC`, false, \"\"},\n\t\t{`select COUNT from SELECT.DESC`, true, \"SELECT `COUNT` FROM `SELECT`.`DESC`\"},\n\t\t{\"use `select`\", true, \"USE `select`\"},\n\t\t{\"use `sel``ect`\", true, \"USE `sel``ect`\"},\n\t\t{\"use select\", false, \"USE `select`\"},\n\t\t{`select * from t as a`, true, \"SELECT * FROM `t` AS `a`\"},\n\t\t{\"select 1 full, 1 row, 1 abs\", false, \"\"},\n\t\t{\"select 1 full, 1 `row`, 1 abs\", true, \"SELECT 1 AS `full`,1 AS `row`,1 AS `abs`\"},\n\t\t{\"select * from t full, t1 row, t2 abs\", false, \"\"},\n\t\t{\"select * from t full, t1 `row`, t2 abs\", true, \"SELECT * FROM (`t` AS `full` JOIN `t1` AS `row`) JOIN `t2` AS `abs`\"},\n\t\t// for issue 1878, identifiers may begin with digit.\n\t\t{\"create database 123test\", true, \"CREATE DATABASE `123test`\"},\n\t\t{\"create database 123\", false, \"CREATE DATABASE `123`\"},\n\t\t{\"create database `123`\", true, \"CREATE DATABASE `123`\"},\n\t\t{\"create database `12``3`\", true, \"CREATE DATABASE `12``3`\"},\n\t\t{\"create table `123` (123a1 int)\", true, \"CREATE TABLE `123` (`123a1` INT)\"},\n\t\t{\"create table 123 (123a1 int)\", false, \"\"},\n\t\t{fmt.Sprintf(\"select * from t%cble\", 0), false, \"\"},\n\t\t// for issue 3954, should NOT be recognized as identifiers.\n\t\t{`select .78+123`, true, \"SELECT 0.78+123\"},\n\t\t{`select .78+.21`, true, \"SELECT 0.78+0.21\"},\n\t\t{`select .78-123`, true, \"SELECT 0.78-123\"},\n\t\t{`select .78-.21`, true, \"SELECT 0.78-0.21\"},\n\t\t{`select .78--123`, true, \"SELECT 0.78--123\"},\n\t\t{`select .78*123`, true, \"SELECT 0.78*123\"},\n\t\t{`select .78*.21`, true, \"SELECT 0.78*0.21\"},\n\t\t{`select .78/123`, true, \"SELECT 0.78/123\"},\n\t\t{`select .78/.21`, true, \"SELECT 0.78/0.21\"},\n\t\t{`select .78,123`, true, \"SELECT 0.78,123\"},\n\t\t{`select .78,.21`, true, \"SELECT 0.78,0.21\"},\n\t\t{`select .78 , 123`, true, \"SELECT 0.78,123\"},\n\t\t{`select .78.123`, false, \"\"},\n\t\t{`select .78#123`, true, \"SELECT 0.78\"},\n\t\t{`insert float_test values(.67, 'string');`, true, \"INSERT INTO `float_test` VALUES (0.67,'string')\"},\n\t\t{`select .78'123'`, true, \"SELECT 0.78 AS `123`\"},\n\t\t{\"select .78`123`\", true, \"SELECT 0.78 AS `123`\"},\n\t\t{`select .78\"123\"`, true, \"SELECT 0.78 AS `123`\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestDDL(c *C) {\n\ttable := []testCase{\n\t\t{\"CREATE\", false, \"\"},\n\t\t{\"CREATE TABLE\", false, \"\"},\n\t\t{\"CREATE TABLE foo (\", false, \"\"},\n\t\t{\"CREATE TABLE foo ()\", false, \"\"},\n\t\t{\"CREATE TABLE foo ();\", false, \"\"},\n\t\t{\"CREATE TABLE foo.* (a varchar(50), b int);\", false, \"\"},\n\t\t// {\"CREATE TABLE foo (a varchar(50), b int);\", true, \"CREATE TABLE `foo` (`a` VARCHAR(50),`b` INT)\"},\n\t\t// {\"CREATE TABLE foo (a TINYINT UNSIGNED);\", true, \"CREATE TABLE `foo` (`a` TINYINT UNSIGNED)\"},\n\t\t// {\"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED)\", true, \"CREATE TABLE `foo` (`a` SMALLINT UNSIGNED,`b` INT UNSIGNED)\"},\n\t\t// {\"CREATE TABLE foo (a bigint unsigned, b bool);\", true, \"CREATE TABLE `foo` (`a` BIGINT UNSIGNED,`b` TINYINT(1))\"},\n\t\t// {\"CREATE TABLE foo (a TINYINT, b SMALLINT) CREATE TABLE bar (x INT, y int64)\", false, \"\"},\n\t\t{\"CREATE TABLE foo (a int, b float); CREATE TABLE bar (x double, y float)\", true, \"CREATE TABLE `foo` (`a` INT,`b` FLOAT); CREATE TABLE `bar` (`x` DOUBLE,`y` FLOAT)\"},\n\t\t// {\"CREATE TABLE foo (a bytes)\", false, \"\"},\n\t\t// {\"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED)\", true, \"CREATE TABLE `foo` (`a` SMALLINT UNSIGNED,`b` INT UNSIGNED)\"},\n\t\t// {\"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) -- foo\", true, \"CREATE TABLE `foo` (`a` SMALLINT UNSIGNED,`b` INT UNSIGNED)\"},\n\t\t// {\"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) // foo\", false, \"\"},\n\t\t// {\"CREATE TABLE foo (a SMALLINT UNSIGNED, b INT UNSIGNED) /* foo */\", true, \"CREATE TABLE `foo` (`a` SMALLINT UNSIGNED,`b` INT UNSIGNED)\"},\n\t\t// {\"CREATE TABLE foo /* foo */ (a SMALLINT UNSIGNED, b INT UNSIGNED) /* foo */\", true, \"CREATE TABLE `foo` (`a` SMALLINT UNSIGNED,`b` INT UNSIGNED)\"},\n\t\t// {\"CREATE TABLE foo (name CHAR(50) BINARY);\", true, \"CREATE TABLE `foo` (`name` CHAR(50) BINARY)\"},\n\t\t// {\"CREATE TABLE foo (name CHAR(50) COLLATE utf8_bin)\", true, \"CREATE TABLE `foo` (`name` CHAR(50) COLLATE utf8_bin)\"},\n\t\t// {\"CREATE TABLE foo (id varchar(50) collate utf8_bin);\", true, \"CREATE TABLE `foo` (`id` VARCHAR(50) COLLATE utf8_bin)\"},\n\t\t// {\"CREATE TABLE foo (name CHAR(50) CHARACTER SET UTF8)\", true, \"CREATE TABLE `foo` (`name` CHAR(50) CHARACTER SET UTF8)\"},\n\t\t// {\"CREATE TABLE foo (name CHAR(50) CHARACTER SET utf8 BINARY)\", true, \"CREATE TABLE `foo` (`name` CHAR(50) BINARY CHARACTER SET UTF8)\"},\n\t\t// {\"CREATE TABLE foo (name CHAR(50) CHARACTER SET utf8 BINARY CHARACTER set utf8)\", false, \"\"},\n\t\t// {\"CREATE TABLE foo (name CHAR(50) BINARY CHARACTER SET utf8 COLLATE utf8_bin)\", true, \"CREATE TABLE `foo` (`name` CHAR(50) BINARY CHARACTER SET UTF8 COLLATE utf8_bin)\"},\n\t\t// {\"CREATE TABLE foo (name CHAR(50) CHARACTER SET utf8 COLLATE utf8_bin COLLATE ascii_bin)\", true, \"CREATE TABLE `foo` (`name` CHAR(50) CHARACTER SET UTF8 COLLATE utf8_bin COLLATE ascii_bin)\"},\n\t\t// {\"CREATE TABLE foo (name CHAR(50) COLLATE ascii_bin COLLATE latin1_bin)\", true, \"CREATE TABLE `foo` (`name` CHAR(50) COLLATE ascii_bin COLLATE latin1_bin)\"},\n\t\t// {\"CREATE TABLE foo (name CHAR(50) COLLATE ascii_bin PRIMARY KEY COLLATE latin1_bin)\", true, \"CREATE TABLE `foo` (`name` CHAR(50) COLLATE ascii_bin PRIMARY KEY COLLATE latin1_bin)\"},\n\t\t// {\"CREATE TABLE foo (a.b, b);\", false, \"\"},\n\t\t// {\"CREATE TABLE foo (a, b.c);\", false, \"\"},\n\t\t// {\"CREATE TABLE (name CHAR(50) BINARY)\", false, \"\"},\n\t\t// // for create temporary table\n\t\t// {\"CREATE TEMPORARY TABLE t (a varchar(50), b int);\", true, \"CREATE TEMPORARY TABLE `t` (`a` VARCHAR(50),`b` INT)\"},\n\t\t{\"CREATE TEMPORARY TABLE t LIKE t1\", true, \"CREATE TEMPORARY TABLE `t` LIKE `t1`\"},\n\t\t{\"DROP TEMPORARY TABLE t\", true, \"DROP TEMPORARY TABLE `t`\"},\n\t\t// test use key word as column name\n\t\t// {\"CREATE TABLE foo (pump varchar(50), b int);\", true, \"CREATE TABLE `foo` (`pump` VARCHAR(50),`b` INT)\"},\n\t\t// {\"CREATE TABLE foo (drainer varchar(50), b int);\", true, \"CREATE TABLE `foo` (`drainer` VARCHAR(50),`b` INT)\"},\n\t\t// {\"CREATE TABLE foo (node_id varchar(50), b int);\", true, \"CREATE TABLE `foo` (`node_id` VARCHAR(50),`b` INT)\"},\n\t\t// {\"CREATE TABLE foo (node_state varchar(50), b int);\", true, \"CREATE TABLE `foo` (`node_state` VARCHAR(50),`b` INT)\"},\n\t\t// for table option\n\t\t{\"create table t (c int) avg_row_length = 3\", true, \"CREATE TABLE `t` (`c` INT) AVG_ROW_LENGTH = 3\"},\n\t\t{\"create table t (c int) avg_row_length 3\", true, \"CREATE TABLE `t` (`c` INT) AVG_ROW_LENGTH = 3\"},\n\t\t{\"create table t (c int) checksum = 0\", true, \"CREATE TABLE `t` (`c` INT) CHECKSUM = 0\"},\n\t\t{\"create table t (c int) checksum 1\", true, \"CREATE TABLE `t` (`c` INT) CHECKSUM = 1\"},\n\t\t{\"create table t (c int) table_checksum = 0\", true, \"CREATE TABLE `t` (`c` INT) TABLE_CHECKSUM = 0\"},\n\t\t{\"create table t (c int) table_checksum 1\", true, \"CREATE TABLE `t` (`c` INT) TABLE_CHECKSUM = 1\"},\n\t\t{\"create table t (c int) compression = 'NONE'\", true, \"CREATE TABLE `t` (`c` INT) COMPRESSION = 'NONE'\"},\n\t\t{\"create table t (c int) compression 'lz4'\", true, \"CREATE TABLE `t` (`c` INT) COMPRESSION = 'lz4'\"},\n\t\t{\"create table t (c int) connection = 'abc'\", true, \"CREATE TABLE `t` (`c` INT) CONNECTION = 'abc'\"},\n\t\t{\"create table t (c int) connection 'abc'\", true, \"CREATE TABLE `t` (`c` INT) CONNECTION = 'abc'\"},\n\t\t{\"create table t (c int) key_block_size = 1024\", true, \"CREATE TABLE `t` (`c` INT) KEY_BLOCK_SIZE = 1024\"},\n\t\t{\"create table t (c int) key_block_size 1024\", true, \"CREATE TABLE `t` (`c` INT) KEY_BLOCK_SIZE = 1024\"},\n\t\t{\"create table t (c int) max_rows = 1000\", true, \"CREATE TABLE `t` (`c` INT) MAX_ROWS = 1000\"},\n\t\t{\"create table t (c int) max_rows 1000\", true, \"CREATE TABLE `t` (`c` INT) MAX_ROWS = 1000\"},\n\t\t{\"create table t (c int) min_rows = 1000\", true, \"CREATE TABLE `t` (`c` INT) MIN_ROWS = 1000\"},\n\t\t{\"create table t (c int) min_rows 1000\", true, \"CREATE TABLE `t` (`c` INT) MIN_ROWS = 1000\"},\n\t\t{\"create table t (c int) password = 'abc'\", true, \"CREATE TABLE `t` (`c` INT) PASSWORD = 'abc'\"},\n\t\t{\"create table t (c int) password 'abc'\", true, \"CREATE TABLE `t` (`c` INT) PASSWORD = 'abc'\"},\n\t\t{\"create table t (c int) DELAY_KEY_WRITE=1\", true, \"CREATE TABLE `t` (`c` INT) DELAY_KEY_WRITE = 1\"},\n\t\t{\"create table t (c int) DELAY_KEY_WRITE 1\", true, \"CREATE TABLE `t` (`c` INT) DELAY_KEY_WRITE = 1\"},\n\t\t{\"create table t (c int) ROW_FORMAT = default\", true, \"CREATE TABLE `t` (`c` INT) ROW_FORMAT = DEFAULT\"},\n\t\t{\"create table t (c int) ROW_FORMAT default\", true, \"CREATE TABLE `t` (`c` INT) ROW_FORMAT = DEFAULT\"},\n\t\t{\"create table t (c int) ROW_FORMAT = fixed\", true, \"CREATE TABLE `t` (`c` INT) ROW_FORMAT = FIXED\"},\n\t\t{\"create table t (c int) ROW_FORMAT = compressed\", true, \"CREATE TABLE `t` (`c` INT) ROW_FORMAT = COMPRESSED\"},\n\t\t{\"create table t (c int) ROW_FORMAT = compact\", true, \"CREATE TABLE `t` (`c` INT) ROW_FORMAT = COMPACT\"},\n\t\t{\"create table t (c int) ROW_FORMAT = redundant\", true, \"CREATE TABLE `t` (`c` INT) ROW_FORMAT = REDUNDANT\"},\n\t\t{\"create table t (c int) ROW_FORMAT = dynamic\", true, \"CREATE TABLE `t` (`c` INT) ROW_FORMAT = DYNAMIC\"},\n\t\t{\"create table t (c int) STATS_PERSISTENT = default\", true, \"CREATE TABLE `t` (`c` INT) STATS_PERSISTENT = DEFAULT /* TableOptionStatsPersistent is not supported */ \"},\n\t\t{\"create table t (c int) STATS_PERSISTENT = 0\", true, \"CREATE TABLE `t` (`c` INT) STATS_PERSISTENT = DEFAULT /* TableOptionStatsPersistent is not supported */ \"},\n\t\t{\"create table t (c int) STATS_PERSISTENT = 1\", true, \"CREATE TABLE `t` (`c` INT) STATS_PERSISTENT = DEFAULT /* TableOptionStatsPersistent is not supported */ \"},\n\t\t{\"create table t (c int) STATS_SAMPLE_PAGES 0\", true, \"CREATE TABLE `t` (`c` INT) STATS_SAMPLE_PAGES = 0\"},\n\t\t{\"create table t (c int) STATS_SAMPLE_PAGES 10\", true, \"CREATE TABLE `t` (`c` INT) STATS_SAMPLE_PAGES = 10\"},\n\t\t{\"create table t (c int) STATS_SAMPLE_PAGES = 10\", true, \"CREATE TABLE `t` (`c` INT) STATS_SAMPLE_PAGES = 10\"},\n\t\t{\"create table t (c int) STATS_SAMPLE_PAGES = default\", true, \"CREATE TABLE `t` (`c` INT) STATS_SAMPLE_PAGES = DEFAULT\"},\n\t\t{\"create table t (c int) PACK_KEYS = 1\", true, \"CREATE TABLE `t` (`c` INT) PACK_KEYS = DEFAULT /* TableOptionPackKeys is not supported */ \"},\n\t\t{\"create table t (c int) PACK_KEYS = 0\", true, \"CREATE TABLE `t` (`c` INT) PACK_KEYS = DEFAULT /* TableOptionPackKeys is not supported */ \"},\n\t\t{\"create table t (c int) PACK_KEYS = DEFAULT\", true, \"CREATE TABLE `t` (`c` INT) PACK_KEYS = DEFAULT /* TableOptionPackKeys is not supported */ \"},\n\t\t{\"create table t (c int) STORAGE DISK\", true, \"CREATE TABLE `t` (`c` INT) STORAGE DISK\"},\n\t\t{\"create table t (c int) STORAGE MEMORY\", true, \"CREATE TABLE `t` (`c` INT) STORAGE MEMORY\"},\n\t\t{\"create table t (c int) SECONDARY_ENGINE null\", true, \"CREATE TABLE `t` (`c` INT) SECONDARY_ENGINE = NULL\"},\n\t\t{\"create table t (c int) SECONDARY_ENGINE = innodb\", true, \"CREATE TABLE `t` (`c` INT) SECONDARY_ENGINE = 'innodb'\"},\n\t\t{\"create table t (c int) SECONDARY_ENGINE 'null'\", true, \"CREATE TABLE `t` (`c` INT) SECONDARY_ENGINE = 'null'\"},\n\t\t// {`create table testTableCompression (c VARCHAR(15000)) compression=\"ZLIB\";`, true, \"CREATE TABLE `testTableCompression` (`c` VARCHAR(15000)) COMPRESSION = 'ZLIB'\"},\n\t\t{`create table t1 (c1 int) compression=\"zlib\";`, true, \"CREATE TABLE `t1` (`c1` INT) COMPRESSION = 'zlib'\"},\n\n\t\t// for table option `UNION`\n\t\t{\"ALTER TABLE t_n UNION ( ), KEY_BLOCK_SIZE = 1\", true, \"ALTER TABLE `t_n` UNION = (), KEY_BLOCK_SIZE = 1\"},\n\t\t{\"ALTER TABLE d_n.t_n UNION ( t_n ) REMOVE PARTITIONING\", true, \"ALTER TABLE `d_n`.`t_n` UNION = (`t_n`) REMOVE PARTITIONING\"},\n\t\t{\"ALTER TABLE d_n.t_n LOCK DEFAULT , UNION = ( t_n , d_n.t_n ) REMOVE PARTITIONING\", true, \"ALTER TABLE `d_n`.`t_n` LOCK = DEFAULT, UNION = (`t_n`,`d_n`.`t_n`) REMOVE PARTITIONING\"},\n\t\t{\"ALTER TABLE d_n.t_n ALGORITHM = DEFAULT , MAX_ROWS 10, UNION ( d_n.t_n ) , ROW_FORMAT REDUNDANT, STATS_PERSISTENT = DEFAULT\", true, \"ALTER TABLE `d_n`.`t_n` ALGORITHM = DEFAULT, MAX_ROWS = 10, UNION = (`d_n`.`t_n`), ROW_FORMAT = REDUNDANT, STATS_PERSISTENT = DEFAULT /* TableOptionStatsPersistent is not supported */ \"},\n\n\t\t// partition option\n\t\t{\"CREATE TABLE t (id int) ENGINE = INNDB PARTITION BY RANGE (id) (PARTITION p0 VALUES LESS THAN (10), PARTITION p1 VALUES LESS THAN (20));\", true, \"CREATE TABLE `t` (`id` INT) ENGINE = INNDB PARTITION BY RANGE (`id`) (PARTITION `p0` VALUES LESS THAN (10),PARTITION `p1` VALUES LESS THAN (20))\"},\n\t\t{\"create table t (c int) PARTITION BY HASH (c) PARTITIONS 32;\", true, \"CREATE TABLE `t` (`c` INT) PARTITION BY HASH (`c`) PARTITIONS 32\"},\n\t\t{\"create table t (c int) PARTITION BY HASH (Year(VDate)) (PARTITION p1980 VALUES LESS THAN (1980) ENGINE = MyISAM, PARTITION p1990 VALUES LESS THAN (1990) ENGINE = MyISAM, PARTITION pothers VALUES LESS THAN MAXVALUE ENGINE = MyISAM)\", false, \"\"},\n\t\t{\"create table t (c int) PARTITION BY RANGE (Year(VDate)) (PARTITION p1980 VALUES LESS THAN (1980) ENGINE = MyISAM, PARTITION p1990 VALUES LESS THAN (1990) ENGINE = MyISAM, PARTITION pothers VALUES LESS THAN MAXVALUE ENGINE = MyISAM)\", true, \"CREATE TABLE `t` (`c` INT) PARTITION BY RANGE (YEAR(`VDate`)) (PARTITION `p1980` VALUES LESS THAN (1980) ENGINE = MyISAM,PARTITION `p1990` VALUES LESS THAN (1990) ENGINE = MyISAM,PARTITION `pothers` VALUES LESS THAN (MAXVALUE) ENGINE = MyISAM)\"},\n\t\t{\"create table t (c int, `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '') PARTITION BY RANGE (UNIX_TIMESTAMP(create_time)) (PARTITION p201610 VALUES LESS THAN(1477929600), PARTITION p201611 VALUES LESS THAN(1480521600),PARTITION p201612 VALUES LESS THAN(1483200000),PARTITION p201701 VALUES LESS THAN(1485878400),PARTITION p201702 VALUES LESS THAN(1488297600),PARTITION p201703 VALUES LESS THAN(1490976000))\", true, \"CREATE TABLE `t` (`c` INT,`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() COMMENT '') PARTITION BY RANGE (UNIX_TIMESTAMP(`create_time`)) (PARTITION `p201610` VALUES LESS THAN (1477929600),PARTITION `p201611` VALUES LESS THAN (1480521600),PARTITION `p201612` VALUES LESS THAN (1483200000),PARTITION `p201701` VALUES LESS THAN (1485878400),PARTITION `p201702` VALUES LESS THAN (1488297600),PARTITION `p201703` VALUES LESS THAN (1490976000))\"},\n\t\t// \t\t{\"CREATE TABLE `md_product_shop` (`shopCode` varchar(4) DEFAULT NULL COMMENT '地点') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 /*!50100 PARTITION BY KEY (shopCode) PARTITIONS 19 */;\", true, \"CREATE TABLE `md_product_shop` (`shopCode` VARCHAR(4) DEFAULT NULL COMMENT '地点') ENGINE = InnoDB DEFAULT CHARACTER SET = UTF8MB4 PARTITION BY KEY (`shopCode`) PARTITIONS 19\"},\n\t\t// \t\t{\"CREATE TABLE `payinfo1` (`id` bigint(20) NOT NULL AUTO_INCREMENT, `oderTime` datetime NOT NULL) ENGINE=InnoDB AUTO_INCREMENT=641533032 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8 /*!50500 PARTITION BY RANGE COLUMNS(oderTime) (PARTITION P2011 VALUES LESS THAN ('2012-01-01 00:00:00') ENGINE = InnoDB, PARTITION P1201 VALUES LESS THAN ('2012-02-01 00:00:00') ENGINE = InnoDB, PARTITION PMAX VALUES LESS THAN (MAXVALUE) ENGINE = InnoDB)*/;\", true, \"CREATE TABLE `payinfo1` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT,`oderTime` DATETIME NOT NULL) ENGINE = InnoDB AUTO_INCREMENT = 641533032 DEFAULT CHARACTER SET = UTF8 ROW_FORMAT = COMPRESSED KEY_BLOCK_SIZE = 8 PARTITION BY RANGE COLUMNS (`oderTime`) (PARTITION `P2011` VALUES LESS THAN ('2012-01-01 00:00:00') ENGINE = InnoDB,PARTITION `P1201` VALUES LESS THAN ('2012-02-01 00:00:00') ENGINE = InnoDB,PARTITION `PMAX` VALUES LESS THAN (MAXVALUE) ENGINE = InnoDB)\"},\n\t\t// \t\t{`CREATE TABLE app_channel_daily_report (id bigint(20) NOT NULL AUTO_INCREMENT, app_version varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'default', gmt_create datetime NOT NULL COMMENT '创建时间', PRIMARY KEY (id)) ENGINE=InnoDB AUTO_INCREMENT=33703438 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci\n\t\t// /*!50100 PARTITION BY RANGE (month(gmt_create)-1)\n\t\t// (PARTITION part0 VALUES LESS THAN (1) COMMENT = '1月份' ENGINE = InnoDB,\n\t\t//  PARTITION part1 VALUES LESS THAN (2) COMMENT = '2月份' ENGINE = InnoDB,\n\t\t//  PARTITION part2 VALUES LESS THAN (3) COMMENT = '3月份' ENGINE = InnoDB,\n\t\t//  PARTITION part3 VALUES LESS THAN (4) COMMENT = '4月份' ENGINE = InnoDB,\n\t\t//  PARTITION part4 VALUES LESS THAN (5) COMMENT = '5月份' ENGINE = InnoDB,\n\t\t//  PARTITION part5 VALUES LESS THAN (6) COMMENT = '6月份' ENGINE = InnoDB,\n\t\t//  PARTITION part6 VALUES LESS THAN (7) COMMENT = '7月份' ENGINE = InnoDB,\n\t\t//  PARTITION part7 VALUES LESS THAN (8) COMMENT = '8月份' ENGINE = InnoDB,\n\t\t//  PARTITION part8 VALUES LESS THAN (9) COMMENT = '9月份' ENGINE = InnoDB,\n\t\t//  PARTITION part9 VALUES LESS THAN (10) COMMENT = '10月份' ENGINE = InnoDB,\n\t\t//  PARTITION part10 VALUES LESS THAN (11) COMMENT = '11月份' ENGINE = InnoDB,\n\t\t//  PARTITION part11 VALUES LESS THAN (12) COMMENT = '12月份' ENGINE = InnoDB) */ ;`, true, \"CREATE TABLE `app_channel_daily_report` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT,`app_version` VARCHAR(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'default',`gmt_create` DATETIME NOT NULL COMMENT '创建时间',PRIMARY KEY(`id`)) ENGINE = InnoDB AUTO_INCREMENT = 33703438 DEFAULT CHARACTER SET = UTF8 DEFAULT COLLATE = UTF8_UNICODE_CI PARTITION BY RANGE (MONTH(`gmt_create`)-1) (PARTITION `part0` VALUES LESS THAN (1) COMMENT = '1月份' ENGINE = InnoDB,PARTITION `part1` VALUES LESS THAN (2) COMMENT = '2月份' ENGINE = InnoDB,PARTITION `part2` VALUES LESS THAN (3) COMMENT = '3月份' ENGINE = InnoDB,PARTITION `part3` VALUES LESS THAN (4) COMMENT = '4月份' ENGINE = InnoDB,PARTITION `part4` VALUES LESS THAN (5) COMMENT = '5月份' ENGINE = InnoDB,PARTITION `part5` VALUES LESS THAN (6) COMMENT = '6月份' ENGINE = InnoDB,PARTITION `part6` VALUES LESS THAN (7) COMMENT = '7月份' ENGINE = InnoDB,PARTITION `part7` VALUES LESS THAN (8) COMMENT = '8月份' ENGINE = InnoDB,PARTITION `part8` VALUES LESS THAN (9) COMMENT = '9月份' ENGINE = InnoDB,PARTITION `part9` VALUES LESS THAN (10) COMMENT = '10月份' ENGINE = InnoDB,PARTITION `part10` VALUES LESS THAN (11) COMMENT = '11月份' ENGINE = InnoDB,PARTITION `part11` VALUES LESS THAN (12) COMMENT = '12月份' ENGINE = InnoDB)\"},\n\n\t\t// // for check clause\n\t\t// {\"create table t (c1 bool, c2 bool, check (c1 in (0, 1)) not enforced, check (c2 in (0, 1)))\", true, \"CREATE TABLE `t` (`c1` TINYINT(1),`c2` TINYINT(1),CHECK(`c1` IN (0,1)) NOT ENFORCED,CHECK(`c2` IN (0,1)) ENFORCED)\"},\n\t\t// {\"CREATE TABLE Customer (SD integer CHECK (SD > 0), First_Name varchar(30));\", true, \"CREATE TABLE `Customer` (`SD` INT CHECK(`SD`>0) ENFORCED,`First_Name` VARCHAR(30))\"},\n\t\t// {\"CREATE TABLE Customer (SD integer CHECK (SD > 0) not enforced, SS varchar(30) check(ss='test') enforced);\", true, \"CREATE TABLE `Customer` (`SD` INT CHECK(`SD`>0) NOT ENFORCED,`SS` VARCHAR(30) CHECK(`ss`='test') ENFORCED)\"},\n\t\t// {\"CREATE TABLE Customer (SD integer CHECK (SD > 0) not null, First_Name varchar(30) comment 'string' not null);\", true, \"CREATE TABLE `Customer` (`SD` INT CHECK(`SD`>0) ENFORCED NOT NULL,`First_Name` VARCHAR(30) COMMENT 'string' NOT NULL)\"},\n\t\t// {\"CREATE TABLE Customer (SD integer comment 'string' CHECK (SD > 0) not null);\", true, \"CREATE TABLE `Customer` (`SD` INT COMMENT 'string' CHECK(`SD`>0) ENFORCED NOT NULL)\"},\n\t\t// {\"CREATE TABLE Customer (SD integer comment 'string' not enforced, First_Name varchar(30));\", false, \"\"},\n\t\t// {\"CREATE TABLE Customer (SD integer not enforced, First_Name varchar(30));\", false, \"\"},\n\n\t\t// {\"create database xxx\", true, \"CREATE DATABASE `xxx`\"},\n\t\t// {\"create database if exists xxx\", false, \"\"},\n\t\t// {\"create database if not exists xxx\", true, \"CREATE DATABASE IF NOT EXISTS `xxx`\"},\n\n\t\t// for create database with encryption\n\t\t{\"create database xxx encryption = 'N'\", true, \"CREATE DATABASE `xxx` ENCRYPTION = 'N'\"},\n\t\t{\"create database xxx encryption 'N'\", true, \"CREATE DATABASE `xxx` ENCRYPTION = 'N'\"},\n\t\t{\"create database xxx default encryption = 'N'\", true, \"CREATE DATABASE `xxx` ENCRYPTION = 'N'\"},\n\t\t{\"create database xxx default encryption 'N'\", true, \"CREATE DATABASE `xxx` ENCRYPTION = 'N'\"},\n\t\t{\"create database xxx encryption = 'Y'\", true, \"CREATE DATABASE `xxx` ENCRYPTION = 'Y'\"},\n\t\t{\"create database xxx encryption 'Y'\", true, \"CREATE DATABASE `xxx` ENCRYPTION = 'Y'\"},\n\t\t{\"create database xxx default encryption = 'Y'\", true, \"CREATE DATABASE `xxx` ENCRYPTION = 'Y'\"},\n\t\t{\"create database xxx default encryption 'Y'\", true, \"CREATE DATABASE `xxx` ENCRYPTION = 'Y'\"},\n\t\t{\"create database xxx encryption = N\", false, \"\"},\n\n\t\t{\"create schema xxx\", true, \"CREATE DATABASE `xxx`\"},\n\t\t{\"create schema if exists xxx\", false, \"\"},\n\t\t{\"create schema if not exists xxx\", true, \"CREATE DATABASE IF NOT EXISTS `xxx`\"},\n\t\t// for drop database/schema/table/view/stats\n\t\t{\"drop database xxx\", true, \"DROP DATABASE `xxx`\"},\n\t\t{\"drop database if exists xxx\", true, \"DROP DATABASE IF EXISTS `xxx`\"},\n\t\t{\"drop database if not exists xxx\", false, \"\"},\n\t\t{\"drop schema xxx\", true, \"DROP DATABASE `xxx`\"},\n\t\t{\"drop schema if exists xxx\", true, \"DROP DATABASE IF EXISTS `xxx`\"},\n\t\t{\"drop schema if not exists xxx\", false, \"\"},\n\t\t{\"drop table\", false, \"DROP TABLE\"},\n\t\t{\"drop table xxx\", true, \"DROP TABLE `xxx`\"},\n\t\t{\"drop table xxx, yyy\", true, \"DROP TABLE `xxx`, `yyy`\"},\n\t\t{\"drop tables xxx\", true, \"DROP TABLE `xxx`\"},\n\t\t{\"drop tables xxx, yyy\", true, \"DROP TABLE `xxx`, `yyy`\"},\n\t\t{\"drop table if exists xxx\", true, \"DROP TABLE IF EXISTS `xxx`\"},\n\t\t{\"drop table if exists xxx, yyy\", true, \"DROP TABLE IF EXISTS `xxx`, `yyy`\"},\n\t\t{\"drop table if not exists xxx\", false, \"\"},\n\t\t{\"drop table xxx restrict\", true, \"DROP TABLE `xxx`\"},\n\t\t{\"drop table xxx, yyy cascade\", true, \"DROP TABLE `xxx`, `yyy`\"},\n\t\t{\"drop table if exists xxx restrict\", true, \"DROP TABLE IF EXISTS `xxx`\"},\n\t\t{\"drop view\", false, \"DROP VIEW\"},\n\t\t{\"drop view xxx\", true, \"DROP VIEW `xxx`\"},\n\t\t{\"drop view xxx, yyy\", true, \"DROP VIEW `xxx`, `yyy`\"},\n\t\t{\"drop view if exists xxx\", true, \"DROP VIEW IF EXISTS `xxx`\"},\n\t\t{\"drop view if exists xxx, yyy\", true, \"DROP VIEW IF EXISTS `xxx`, `yyy`\"},\n\t\t{\"drop stats t\", true, \"DROP STATS `t`\"},\n\t\t// // for issue 974\n\t\t// {`CREATE TABLE address (\n\t\t// id bigint(20) NOT NULL AUTO_INCREMENT,\n\t\t// create_at datetime NOT NULL,\n\t\t// deleted tinyint(1) NOT NULL,\n\t\t// update_at datetime NOT NULL,\n\t\t// version bigint(20) DEFAULT NULL,\n\t\t// address varchar(128) NOT NULL,\n\t\t// address_detail varchar(128) NOT NULL,\n\t\t// cellphone varchar(16) NOT NULL,\n\t\t// latitude double NOT NULL,\n\t\t// longitude double NOT NULL,\n\t\t// name varchar(16) NOT NULL,\n\t\t// sex tinyint(1) NOT NULL,\n\t\t// user_id bigint(20) NOT NULL,\n\t\t// PRIMARY KEY (id),\n\t\t// CONSTRAINT FK_7rod8a71yep5vxasb0ms3osbg FOREIGN KEY (user_id) REFERENCES waimaiqa.user (id),\n\t\t// INDEX FK_7rod8a71yep5vxasb0ms3osbg (user_id) comment ''\n\t\t// ) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARACTER SET UTF8 COLLATE UTF8_GENERAL_CI ROW_FORMAT=COMPACT COMMENT='' CHECKSUM=0 DELAY_KEY_WRITE=0;`, true, \"CREATE TABLE `address` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT,`create_at` DATETIME NOT NULL,`deleted` TINYINT(1) NOT NULL,`update_at` DATETIME NOT NULL,`version` BIGINT(20) DEFAULT NULL,`address` VARCHAR(128) NOT NULL,`address_detail` VARCHAR(128) NOT NULL,`cellphone` VARCHAR(16) NOT NULL,`latitude` DOUBLE NOT NULL,`longitude` DOUBLE NOT NULL,`name` VARCHAR(16) NOT NULL,`sex` TINYINT(1) NOT NULL,`user_id` BIGINT(20) NOT NULL,PRIMARY KEY(`id`),CONSTRAINT `FK_7rod8a71yep5vxasb0ms3osbg` FOREIGN KEY (`user_id`) REFERENCES `waimaiqa`.`user`(`id`),INDEX `FK_7rod8a71yep5vxasb0ms3osbg`(`user_id`) ) ENGINE = InnoDB AUTO_INCREMENT = 30 DEFAULT CHARACTER SET = UTF8 DEFAULT COLLATE = UTF8_GENERAL_CI ROW_FORMAT = COMPACT COMMENT = '' CHECKSUM = 0 DELAY_KEY_WRITE = 0\"},\n\t\t// // for issue 975\n\t\t// {`CREATE TABLE test_data (\n\t\t// id bigint(20) NOT NULL AUTO_INCREMENT,\n\t\t// create_at datetime NOT NULL,\n\t\t// deleted tinyint(1) NOT NULL,\n\t\t// update_at datetime NOT NULL,\n\t\t// version bigint(20) DEFAULT NULL,\n\t\t// address varchar(255) NOT NULL,\n\t\t// amount decimal(19,2) DEFAULT NULL,\n\t\t// charge_id varchar(32) DEFAULT NULL,\n\t\t// paid_amount decimal(19,2) DEFAULT NULL,\n\t\t// transaction_no varchar(64) DEFAULT NULL,\n\t\t// wx_mp_app_id varchar(32) DEFAULT NULL,\n\t\t// contacts varchar(50) DEFAULT NULL,\n\t\t// deliver_fee decimal(19,2) DEFAULT NULL,\n\t\t// deliver_info varchar(255) DEFAULT NULL,\n\t\t// deliver_time varchar(255) DEFAULT NULL,\n\t\t// description varchar(255) DEFAULT NULL,\n\t\t// invoice varchar(255) DEFAULT NULL,\n\t\t// order_from int(11) DEFAULT NULL,\n\t\t// order_state int(11) NOT NULL,\n\t\t// packing_fee decimal(19,2) DEFAULT NULL,\n\t\t// payment_time datetime DEFAULT NULL,\n\t\t// payment_type int(11) DEFAULT NULL,\n\t\t// phone varchar(50) NOT NULL,\n\t\t// store_employee_id bigint(20) DEFAULT NULL,\n\t\t// store_id bigint(20) NOT NULL,\n\t\t// user_id bigint(20) NOT NULL,\n\t\t// payment_mode int(11) NOT NULL,\n\t\t// current_latitude double NOT NULL,\n\t\t// current_longitude double NOT NULL,\n\t\t// address_latitude double NOT NULL,\n\t\t// address_longitude double NOT NULL,\n\t\t// PRIMARY KEY (id),\n\t\t// CONSTRAINT food_order_ibfk_1 FOREIGN KEY (user_id) REFERENCES waimaiqa.user (id),\n\t\t// CONSTRAINT food_order_ibfk_2 FOREIGN KEY (store_id) REFERENCES waimaiqa.store (id),\n\t\t// CONSTRAINT food_order_ibfk_3 FOREIGN KEY (store_employee_id) REFERENCES waimaiqa.store_employee (id),\n\t\t// UNIQUE FK_UNIQUE_charge_id USING BTREE (charge_id) comment '',\n\t\t// INDEX FK_eqst2x1xisn3o0wbrlahnnqq8 USING BTREE (store_employee_id) comment '',\n\t\t// INDEX FK_8jcmec4kb03f4dod0uqwm54o9 USING BTREE (store_id) comment '',\n\t\t// INDEX FK_a3t0m9apja9jmrn60uab30pqd USING BTREE (user_id) comment ''\n\t\t// ) ENGINE=InnoDB AUTO_INCREMENT=95 DEFAULT CHARACTER SET utf8 COLLATE UTF8_GENERAL_CI ROW_FORMAT=COMPACT COMMENT='' CHECKSUM=0 DELAY_KEY_WRITE=0;`, true, \"CREATE TABLE `test_data` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT,`create_at` DATETIME NOT NULL,`deleted` TINYINT(1) NOT NULL,`update_at` DATETIME NOT NULL,`version` BIGINT(20) DEFAULT NULL,`address` VARCHAR(255) NOT NULL,`amount` DECIMAL(19,2) DEFAULT NULL,`charge_id` VARCHAR(32) DEFAULT NULL,`paid_amount` DECIMAL(19,2) DEFAULT NULL,`transaction_no` VARCHAR(64) DEFAULT NULL,`wx_mp_app_id` VARCHAR(32) DEFAULT NULL,`contacts` VARCHAR(50) DEFAULT NULL,`deliver_fee` DECIMAL(19,2) DEFAULT NULL,`deliver_info` VARCHAR(255) DEFAULT NULL,`deliver_time` VARCHAR(255) DEFAULT NULL,`description` VARCHAR(255) DEFAULT NULL,`invoice` VARCHAR(255) DEFAULT NULL,`order_from` INT(11) DEFAULT NULL,`order_state` INT(11) NOT NULL,`packing_fee` DECIMAL(19,2) DEFAULT NULL,`payment_time` DATETIME DEFAULT NULL,`payment_type` INT(11) DEFAULT NULL,`phone` VARCHAR(50) NOT NULL,`store_employee_id` BIGINT(20) DEFAULT NULL,`store_id` BIGINT(20) NOT NULL,`user_id` BIGINT(20) NOT NULL,`payment_mode` INT(11) NOT NULL,`current_latitude` DOUBLE NOT NULL,`current_longitude` DOUBLE NOT NULL,`address_latitude` DOUBLE NOT NULL,`address_longitude` DOUBLE NOT NULL,PRIMARY KEY(`id`),CONSTRAINT `food_order_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `waimaiqa`.`user`(`id`),CONSTRAINT `food_order_ibfk_2` FOREIGN KEY (`store_id`) REFERENCES `waimaiqa`.`store`(`id`),CONSTRAINT `food_order_ibfk_3` FOREIGN KEY (`store_employee_id`) REFERENCES `waimaiqa`.`store_employee`(`id`),UNIQUE `FK_UNIQUE_charge_id`(`charge_id`) USING BTREE,INDEX `FK_eqst2x1xisn3o0wbrlahnnqq8`(`store_employee_id`) USING BTREE,INDEX `FK_8jcmec4kb03f4dod0uqwm54o9`(`store_id`) USING BTREE,INDEX `FK_a3t0m9apja9jmrn60uab30pqd`(`user_id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 95 DEFAULT CHARACTER SET = UTF8 DEFAULT COLLATE = UTF8_GENERAL_CI ROW_FORMAT = COMPACT COMMENT = '' CHECKSUM = 0 DELAY_KEY_WRITE = 0\"},\n\t\t// {`create table t (c int KEY);`, true, \"CREATE TABLE `t` (`c` INT PRIMARY KEY)\"},\n\t\t// {`CREATE TABLE address (\n\t\t// id bigint(20) NOT NULL AUTO_INCREMENT,\n\t\t// create_at datetime NOT NULL,\n\t\t// deleted tinyint(1) NOT NULL,\n\t\t// update_at datetime NOT NULL,\n\t\t// version bigint(20) DEFAULT NULL,\n\t\t// address varchar(128) NOT NULL,\n\t\t// address_detail varchar(128) NOT NULL,\n\t\t// cellphone varchar(16) NOT NULL,\n\t\t// latitude double NOT NULL,\n\t\t// longitude double NOT NULL,\n\t\t// name varchar(16) NOT NULL,\n\t\t// sex tinyint(1) NOT NULL,\n\t\t// user_id bigint(20) NOT NULL,\n\t\t// PRIMARY KEY (id),\n\t\t// CONSTRAINT FK_7rod8a71yep5vxasb0ms3osbg FOREIGN KEY (user_id) REFERENCES waimaiqa.user (id) ON DELETE CASCADE ON UPDATE NO ACTION,\n\t\t// INDEX FK_7rod8a71yep5vxasb0ms3osbg (user_id) comment ''\n\t\t// ) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARACTER SET utf8 COLLATE UTF8_GENERAL_CI ROW_FORMAT=COMPACT COMMENT='' CHECKSUM=0 DELAY_KEY_WRITE=0;`, true, \"CREATE TABLE `address` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT,`create_at` DATETIME NOT NULL,`deleted` TINYINT(1) NOT NULL,`update_at` DATETIME NOT NULL,`version` BIGINT(20) DEFAULT NULL,`address` VARCHAR(128) NOT NULL,`address_detail` VARCHAR(128) NOT NULL,`cellphone` VARCHAR(16) NOT NULL,`latitude` DOUBLE NOT NULL,`longitude` DOUBLE NOT NULL,`name` VARCHAR(16) NOT NULL,`sex` TINYINT(1) NOT NULL,`user_id` BIGINT(20) NOT NULL,PRIMARY KEY(`id`),CONSTRAINT `FK_7rod8a71yep5vxasb0ms3osbg` FOREIGN KEY (`user_id`) REFERENCES `waimaiqa`.`user`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION,INDEX `FK_7rod8a71yep5vxasb0ms3osbg`(`user_id`) ) ENGINE = InnoDB AUTO_INCREMENT = 30 DEFAULT CHARACTER SET = UTF8 DEFAULT COLLATE = UTF8_GENERAL_CI ROW_FORMAT = COMPACT COMMENT = '' CHECKSUM = 0 DELAY_KEY_WRITE = 0\"},\n\t\t// {\"CREATE TABLE address (\\r\\nid bigint(20) NOT NULL AUTO_INCREMENT,\\r\\ncreate_at datetime NOT NULL,\\r\\ndeleted tinyint(1) NOT NULL,\\r\\nupdate_at datetime NOT NULL,\\r\\nversion bigint(20) DEFAULT NULL,\\r\\naddress varchar(128) NOT NULL,\\r\\naddress_detail varchar(128) NOT NULL,\\r\\ncellphone varchar(16) NOT NULL,\\r\\nlatitude double NOT NULL,\\r\\nlongitude double NOT NULL,\\r\\nname varchar(16) NOT NULL,\\r\\nsex tinyint(1) NOT NULL,\\r\\nuser_id bigint(20) NOT NULL,\\r\\nPRIMARY KEY (id),\\r\\nCONSTRAINT FK_7rod8a71yep5vxasb0ms3osbg FOREIGN KEY (user_id) REFERENCES waimaiqa.user (id) ON DELETE CASCADE ON UPDATE NO ACTION,\\r\\nINDEX FK_7rod8a71yep5vxasb0ms3osbg (user_id) comment ''\\r\\n) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ROW_FORMAT=COMPACT COMMENT='' CHECKSUM=0 DELAY_KEY_WRITE=0;\", true, \"CREATE TABLE `address` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT,`create_at` DATETIME NOT NULL,`deleted` TINYINT(1) NOT NULL,`update_at` DATETIME NOT NULL,`version` BIGINT(20) DEFAULT NULL,`address` VARCHAR(128) NOT NULL,`address_detail` VARCHAR(128) NOT NULL,`cellphone` VARCHAR(16) NOT NULL,`latitude` DOUBLE NOT NULL,`longitude` DOUBLE NOT NULL,`name` VARCHAR(16) NOT NULL,`sex` TINYINT(1) NOT NULL,`user_id` BIGINT(20) NOT NULL,PRIMARY KEY(`id`),CONSTRAINT `FK_7rod8a71yep5vxasb0ms3osbg` FOREIGN KEY (`user_id`) REFERENCES `waimaiqa`.`user`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION,INDEX `FK_7rod8a71yep5vxasb0ms3osbg`(`user_id`) ) ENGINE = InnoDB AUTO_INCREMENT = 30 DEFAULT CHARACTER SET = UTF8 DEFAULT COLLATE = UTF8_GENERAL_CI ROW_FORMAT = COMPACT COMMENT = '' CHECKSUM = 0 DELAY_KEY_WRITE = 0\"},\n\t\t// for issue 1802\n\t\t// {`CREATE TABLE t1 (\n\t\t// accout_id int(11) DEFAULT '0',\n\t\t// summoner_id int(11) DEFAULT '0',\n\t\t// union_name varbinary(52) NOT NULL,\n\t\t// union_id int(11) DEFAULT '0',\n\t\t// PRIMARY KEY (union_name)) ENGINE=MyISAM DEFAULT CHARSET=binary;`, true, \"CREATE TABLE `t1` (`accout_id` INT(11) DEFAULT '0',`summoner_id` INT(11) DEFAULT '0',`union_name` VARBINARY(52) NOT NULL,`union_id` INT(11) DEFAULT '0',PRIMARY KEY(`union_name`)) ENGINE = MyISAM DEFAULT CHARACTER SET = BINARY\"},\n\t\t// // for issue pingcap/parser#310\n\t\t// {`CREATE TABLE t (a DECIMAL(20,0), b DECIMAL(30), c FLOAT(25,0))`, true, \"CREATE TABLE `t` (`a` DECIMAL(20,0),`b` DECIMAL(30),`c` FLOAT(25,0))\"},\n\t\t// // Create table with multiple index options.\n\t\t// {`create table t (c int, index ci (c) USING BTREE COMMENT \"123\");`, true, \"CREATE TABLE `t` (`c` INT,INDEX `ci`(`c`) USING BTREE COMMENT '123')\"},\n\t\t// // for default value\n\t\t// {\"CREATE TABLE sbtest (id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, k integer UNSIGNED DEFAULT '0' NOT NULL, c char(120) DEFAULT '' NOT NULL, pad char(60) DEFAULT '' NOT NULL, PRIMARY KEY  (id) )\", true, \"CREATE TABLE `sbtest` (`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,`k` INT UNSIGNED DEFAULT '0' NOT NULL,`c` CHAR(120) DEFAULT '' NOT NULL,`pad` CHAR(60) DEFAULT '' NOT NULL,PRIMARY KEY(`id`))\"},\n\t\t// {\"create table test (create_date TIMESTAMP NOT NULL COMMENT '创建日期 create date' DEFAULT now());\", true, \"CREATE TABLE `test` (`create_date` TIMESTAMP NOT NULL COMMENT '创建日期 create date' DEFAULT CURRENT_TIMESTAMP())\"},\n\t\t// {\"create table ts (t int, v timestamp(3) default CURRENT_TIMESTAMP(3));\", true, \"CREATE TABLE `ts` (`t` INT,`v` TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3))\"}, //TODO: The number yacc in parentheses has not been implemented yet.\n\t\t// // Create table with primary key name.\n\t\t// {\"create table if not exists `t` (`id` int not null auto_increment comment '消息ID', primary key `pk_id` (`id`) );\", true, \"CREATE TABLE IF NOT EXISTS `t` (`id` INT NOT NULL AUTO_INCREMENT COMMENT '消息ID',PRIMARY KEY `pk_id`(`id`))\"},\n\t\t// // Create table with like.\n\t\t// {\"create table a like b\", true, \"CREATE TABLE `a` LIKE `b`\"},\n\t\t// {\"create table a (id int REFERENCES a (id) ON delete NO ACTION )\", true, \"CREATE TABLE `a` (`id` INT REFERENCES `a`(`id`) ON DELETE NO ACTION)\"},\n\t\t// {\"create table a (id int REFERENCES a (id) ON update set default )\", true, \"CREATE TABLE `a` (`id` INT REFERENCES `a`(`id`) ON UPDATE SET DEFAULT)\"},\n\t\t// {\"create table a (id int REFERENCES a (id) ON delete set null on update CASCADE)\", true, \"CREATE TABLE `a` (`id` INT REFERENCES `a`(`id`) ON DELETE SET NULL ON UPDATE CASCADE)\"},\n\t\t// {\"create table a (id int REFERENCES a (id) ON update set default on delete RESTRICT)\", true, \"CREATE TABLE `a` (`id` INT REFERENCES `a`(`id`) ON DELETE RESTRICT ON UPDATE SET DEFAULT)\"},\n\t\t// {\"create table a (id int REFERENCES a (id) MATCH FULL ON delete NO ACTION )\", true, \"CREATE TABLE `a` (`id` INT REFERENCES `a`(`id`) MATCH FULL ON DELETE NO ACTION)\"},\n\t\t// {\"create table a (id int REFERENCES a (id) MATCH PARTIAL ON update NO ACTION )\", true, \"CREATE TABLE `a` (`id` INT REFERENCES `a`(`id`) MATCH PARTIAL ON UPDATE NO ACTION)\"},\n\t\t// {\"create table a (id int REFERENCES a (id) MATCH SIMPLE ON update NO ACTION )\", true, \"CREATE TABLE `a` (`id` INT REFERENCES `a`(`id`) MATCH SIMPLE ON UPDATE NO ACTION)\"},\n\t\t// {\"create table a (id int REFERENCES a (id) ON update set default )\", true, \"CREATE TABLE `a` (`id` INT REFERENCES `a`(`id`) ON UPDATE SET DEFAULT)\"},\n\t\t// {\"create table a (id int REFERENCES a (id) ON update set default on update CURRENT_TIMESTAMP)\", false, \"\"},\n\t\t// {\"create table a (id int REFERENCES a (id) ON delete set default on update CURRENT_TIMESTAMP)\", false, \"\"},\n\t\t// {\"create table a (like b)\", true, \"CREATE TABLE `a` LIKE `b`\"},\n\t\t// {\"create table if not exists a like b\", true, \"CREATE TABLE IF NOT EXISTS `a` LIKE `b`\"},\n\t\t// {\"create table if not exists a (like b)\", true, \"CREATE TABLE IF NOT EXISTS `a` LIKE `b`\"},\n\t\t// {\"create table if not exists a like (b)\", false, \"\"},\n\t\t// {\"create table a (t int) like b\", false, \"\"},\n\t\t// {\"create table a (t int) like (b)\", false, \"\"},\n\t\t// Create table with select statement\n\t\t{\"create table a select * from b\", true, \"CREATE TABLE `a`  AS SELECT * FROM `b`\"},\n\t\t{\"create table a as select * from b\", true, \"CREATE TABLE `a`  AS SELECT * FROM `b`\"},\n\t\t{\"create table a (m int, n datetime) as select * from b\", true, \"CREATE TABLE `a` (`m` INT,`n` DATETIME) AS SELECT * FROM `b`\"},\n\t\t// {\"create table a (unique(n)) as select n from b\", true, \"CREATE TABLE `a` (UNIQUE(`n`)) AS SELECT `n` FROM `b`\"},\n\t\t{\"create table a ignore as select n from b\", true, \"CREATE TABLE `a`  IGNORE AS SELECT `n` FROM `b`\"},\n\t\t{\"create table a replace as select n from b\", true, \"CREATE TABLE `a`  REPLACE AS SELECT `n` FROM `b`\"},\n\t\t{\"create table a (m int) replace as (select n as m from b union select n+1 as m from c group by 1 limit 2)\", true, \"CREATE TABLE `a` (`m` INT) REPLACE AS (SELECT `n` AS `m` FROM `b` UNION SELECT `n`+1 AS `m` FROM `c` GROUP BY 1 LIMIT 2)\"},\n\n\t\t// Create table with no option is valid for parser\n\t\t// {\"create table a\", true, \"CREATE TABLE `a` \"},\n\n\t\t// {\"create table t (a timestamp default now)\", false, \"\"},\n\t\t// {\"create table t (a timestamp default now())\", true, \"CREATE TABLE `t` (`a` TIMESTAMP DEFAULT CURRENT_TIMESTAMP())\"},\n\t\t// {\"create table t (a timestamp default now() on update now)\", false, \"\"},\n\t\t// {\"create table t (a timestamp default now() on update now())\", true, \"CREATE TABLE `t` (`a` TIMESTAMP DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP())\"},\n\t\t// {\"CREATE TABLE t (c TEXT) default CHARACTER SET utf8, default COLLATE utf8_general_ci;\", true, \"CREATE TABLE `t` (`c` TEXT) DEFAULT CHARACTER SET = UTF8 DEFAULT COLLATE = UTF8_GENERAL_CI\"},\n\t\t// {\"CREATE TABLE t (c TEXT) shard_row_id_bits = 1;\", true, \"CREATE TABLE `t` (`c` TEXT) SHARD_ROW_ID_BITS = 1\"},\n\t\t// {\"CREATE TABLE t (c TEXT) shard_row_id_bits = 1, PRE_SPLIT_REGIONS = 1;\", true, \"CREATE TABLE `t` (`c` TEXT) SHARD_ROW_ID_BITS = 1 PRE_SPLIT_REGIONS = 1\"},\n\t\t// // Create table with ON UPDATE CURRENT_TIMESTAMP(6), specify fraction part.\n\t\t// {\"CREATE TABLE IF NOT EXISTS `general_log` (`event_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),`user_host` mediumtext NOT NULL,`thread_id` bigint(20) unsigned NOT NULL,`server_id` int(10) unsigned NOT NULL,`command_type` varchar(64) NOT NULL,`argument` mediumblob NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='General log'\", true, \"CREATE TABLE IF NOT EXISTS `general_log` (`event_time` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),`user_host` MEDIUMTEXT NOT NULL,`thread_id` BIGINT(20) UNSIGNED NOT NULL,`server_id` INT(10) UNSIGNED NOT NULL,`command_type` VARCHAR(64) NOT NULL,`argument` MEDIUMBLOB NOT NULL) ENGINE = CSV DEFAULT CHARACTER SET = UTF8 COMMENT = 'General log'\"}, //TODO: The number yacc in parentheses has not been implemented yet.\n\t\t// // For reference_definition in column_definition.\n\t\t// {\"CREATE TABLE followers ( f1 int NOT NULL REFERENCES user_profiles (uid) );\", true, \"CREATE TABLE `followers` (`f1` INT NOT NULL REFERENCES `user_profiles`(`uid`))\"},\n\n\t\t// // For table option `ENCRYPTION`\n\t\t// {\"create table t (a int) encryption = 'n';\", true, \"CREATE TABLE `t` (`a` INT) ENCRYPTION = 'n'\"},\n\t\t// {\"create table t (a int) encryption 'n';\", true, \"CREATE TABLE `t` (`a` INT) ENCRYPTION = 'n'\"},\n\t\t// {\"alter table t encryption = 'y';\", true, \"ALTER TABLE `t` ENCRYPTION = 'y'\"},\n\t\t// {\"alter table t encryption 'y';\", true, \"ALTER TABLE `t` ENCRYPTION = 'y'\"},\n\n\t\t// for alter database/schema/table\n\t\t{\"ALTER DATABASE t CHARACTER SET = 'utf8'\", true, \"ALTER DATABASE `t` CHARACTER SET = utf8\"},\n\t\t{\"ALTER DATABASE CHARACTER SET = 'utf8'\", true, \"ALTER DATABASE CHARACTER SET = utf8\"},\n\t\t{\"ALTER DATABASE t DEFAULT CHARACTER SET = 'utf8'\", true, \"ALTER DATABASE `t` CHARACTER SET = utf8\"},\n\t\t{\"ALTER SCHEMA t DEFAULT CHARACTER SET = 'utf8'\", true, \"ALTER DATABASE `t` CHARACTER SET = utf8\"},\n\t\t{\"ALTER SCHEMA DEFAULT CHARACTER SET = 'utf8'\", true, \"ALTER DATABASE CHARACTER SET = utf8\"},\n\t\t{\"ALTER SCHEMA t DEFAULT CHARSET = 'UTF8'\", true, \"ALTER DATABASE `t` CHARACTER SET = utf8\"},\n\n\t\t{\"ALTER DATABASE t COLLATE = 'utf8_bin'\", true, \"ALTER DATABASE `t` COLLATE = utf8_bin\"},\n\t\t{\"ALTER DATABASE COLLATE = 'utf8_bin'\", true, \"ALTER DATABASE COLLATE = utf8_bin\"},\n\t\t{\"ALTER DATABASE t DEFAULT COLLATE = 'utf8_bin'\", true, \"ALTER DATABASE `t` COLLATE = utf8_bin\"},\n\t\t{\"ALTER SCHEMA t DEFAULT COLLATE = 'UTF8_BiN'\", true, \"ALTER DATABASE `t` COLLATE = utf8_bin\"},\n\t\t{\"ALTER SCHEMA DEFAULT COLLATE = 'UTF8_BiN'\", true, \"ALTER DATABASE COLLATE = utf8_bin\"},\n\t\t{\"ALTER SCHEMA `` DEFAULT COLLATE = 'UTF8_BiN'\", true, \"ALTER DATABASE `` COLLATE = utf8_bin\"},\n\n\t\t{\"ALTER DATABASE t CHARSET = 'utf8mb4' COLLATE = 'utf8_bin'\", true, \"ALTER DATABASE `t` CHARACTER SET = utf8mb4 COLLATE = utf8_bin\"},\n\t\t{\n\t\t\t\"ALTER DATABASE t DEFAULT CHARSET = 'utf8mb4' DEFAULT COLLATE = 'utf8mb4_general_ci' CHARACTER SET = 'utf8' COLLATE = 'utf8mb4_bin'\",\n\t\t\ttrue,\n\t\t\t\"ALTER DATABASE `t` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci CHARACTER SET = utf8 COLLATE = utf8mb4_bin\",\n\t\t},\n\t\t{\"ALTER DATABASE DEFAULT CHARSET = 'utf8mb4' COLLATE = 'utf8_bin'\", true, \"ALTER DATABASE CHARACTER SET = utf8mb4 COLLATE = utf8_bin\"},\n\t\t{\n\t\t\t\"ALTER DATABASE DEFAULT CHARSET = 'utf8mb4' DEFAULT COLLATE = 'utf8mb4_general_ci' CHARACTER SET = 'utf8' COLLATE = 'utf8mb4_bin'\",\n\t\t\ttrue,\n\t\t\t\"ALTER DATABASE CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci CHARACTER SET = utf8 COLLATE = utf8mb4_bin\",\n\t\t},\n\n\t\t// {\"ALTER TABLE t ADD COLUMN (a SMALLINT UNSIGNED)\", true, \"ALTER TABLE `t` ADD COLUMN (`a` SMALLINT UNSIGNED)\"},\n\t\t// {\"ALTER TABLE t.* ADD COLUMN (a SMALLINT UNSIGNED)\", false, \"\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN IF NOT EXISTS (a SMALLINT UNSIGNED)\", true, \"ALTER TABLE `t` ADD COLUMN IF NOT EXISTS (`a` SMALLINT UNSIGNED)\"},\n\t\t// {\"ALTER TABLE ADD COLUMN (a SMALLINT UNSIGNED)\", false, \"\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN (a SMALLINT UNSIGNED, b varchar(255))\", true, \"ALTER TABLE `t` ADD COLUMN (`a` SMALLINT UNSIGNED, `b` VARCHAR(255))\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN IF NOT EXISTS (a SMALLINT UNSIGNED, b varchar(255))\", true, \"ALTER TABLE `t` ADD COLUMN IF NOT EXISTS (`a` SMALLINT UNSIGNED, `b` VARCHAR(255))\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN (a SMALLINT UNSIGNED FIRST)\", false, \"\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED FIRST\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED FIRST\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED AFTER b\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED AFTER `b`\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN IF NOT EXISTS a SMALLINT UNSIGNED AFTER b\", true, \"ALTER TABLE `t` ADD COLUMN IF NOT EXISTS `a` SMALLINT UNSIGNED AFTER `b`\"},\n\t\t// {\"ALTER TABLE employees ADD PARTITION\", true, \"ALTER TABLE `employees` ADD PARTITION\"},\n\t\t// {\"ALTER TABLE employees ADD PARTITION ( PARTITION P1 VALUES LESS THAN (2010))\", true, \"ALTER TABLE `employees` ADD PARTITION (PARTITION `P1` VALUES LESS THAN (2010))\"},\n\t\t// {\"ALTER TABLE employees ADD PARTITION ( PARTITION P2 VALUES LESS THAN MAXVALUE)\", true, \"ALTER TABLE `employees` ADD PARTITION (PARTITION `P2` VALUES LESS THAN (MAXVALUE))\"},\n\t\t// {\"ALTER TABLE employees ADD PARTITION IF NOT EXISTS ( PARTITION P2 VALUES LESS THAN MAXVALUE)\", true, \"ALTER TABLE `employees` ADD PARTITION IF NOT EXISTS (PARTITION `P2` VALUES LESS THAN (MAXVALUE))\"},\n\t\t// {\"ALTER TABLE employees ADD PARTITION IF NOT EXISTS PARTITIONS 5\", true, \"ALTER TABLE `employees` ADD PARTITION IF NOT EXISTS PARTITIONS 5\"},\n\t\t// {`ALTER TABLE employees ADD PARTITION (\n\t\t// \t\tPARTITION P1 VALUES LESS THAN (2010),\n\t\t// \t\tPARTITION P2 VALUES LESS THAN (2015),\n\t\t// \t\tPARTITION P3 VALUES LESS THAN MAXVALUE)`, true, \"ALTER TABLE `employees` ADD PARTITION (PARTITION `P1` VALUES LESS THAN (2010), PARTITION `P2` VALUES LESS THAN (2015), PARTITION `P3` VALUES LESS THAN (MAXVALUE))\"},\n\t\t// {\"alter table t add partition (partition x values in ((3, 4), (5, 6)))\", true, \"ALTER TABLE `t` ADD PARTITION (PARTITION `x` VALUES IN ((3, 4), (5, 6)))\"},\n\t\t// {\"ALTER TABLE employees ADD PARTITION NO_WRITE_TO_BINLOG\", true, \"ALTER TABLE `employees` ADD PARTITION NO_WRITE_TO_BINLOG\"},\n\t\t// {\"ALTER TABLE employees ADD PARTITION NO_WRITE_TO_BINLOG PARTITIONS 10\", true, \"ALTER TABLE `employees` ADD PARTITION NO_WRITE_TO_BINLOG PARTITIONS 10\"},\n\t\t// // LOCAL is alias to NO_WRITE_TO_BINLOG\n\t\t// {\"ALTER TABLE employees ADD PARTITION LOCAL\", true, \"ALTER TABLE `employees` ADD PARTITION NO_WRITE_TO_BINLOG\"},\n\t\t// {\"ALTER TABLE employees ADD PARTITION LOCAL PARTITIONS 10\", true, \"ALTER TABLE `employees` ADD PARTITION NO_WRITE_TO_BINLOG PARTITIONS 10\"},\n\n\t\t// For rebuild table partition statement.\n\t\t{\"ALTER TABLE t_n REBUILD PARTITION ALL\", true, \"ALTER TABLE `t_n` REBUILD PARTITION ALL\"},\n\t\t{\"ALTER TABLE d_n.t_n REBUILD PARTITION LOCAL ALL\", true, \"ALTER TABLE `d_n`.`t_n` REBUILD PARTITION NO_WRITE_TO_BINLOG ALL\"},\n\t\t{\"ALTER TABLE t_n REBUILD PARTITION LOCAL ident\", true, \"ALTER TABLE `t_n` REBUILD PARTITION NO_WRITE_TO_BINLOG `ident`\"},\n\t\t{\"ALTER TABLE t_n REBUILD PARTITION NO_WRITE_TO_BINLOG ident , ident\", true, \"ALTER TABLE `t_n` REBUILD PARTITION NO_WRITE_TO_BINLOG `ident`,`ident`\"},\n\t\t// The first `LOCAL` should be recognized as unreserved keyword `LOCAL` (alias to `NO_WRITE_TO_BINLOG`),\n\t\t// and the remains should re recognized as identifier, used as partition name here.\n\t\t{\"ALTER TABLE t_n REBUILD PARTITION LOCAL\", false, \"\"},\n\t\t{\"ALTER TABLE t_n REBUILD PARTITION LOCAL local\", true, \"ALTER TABLE `t_n` REBUILD PARTITION NO_WRITE_TO_BINLOG `local`\"},\n\t\t{\"ALTER TABLE t_n REBUILD PARTITION LOCAL local, local\", true, \"ALTER TABLE `t_n` REBUILD PARTITION NO_WRITE_TO_BINLOG `local`,`local`\"},\n\n\t\t// For drop table partition statement.\n\t\t{\"alter table t drop partition p1;\", true, \"ALTER TABLE `t` DROP PARTITION `p1`\"},\n\t\t{\"alter table t drop partition p2;\", true, \"ALTER TABLE `t` DROP PARTITION `p2`\"},\n\t\t{\"alter table t drop partition if exists p2;\", true, \"ALTER TABLE `t` DROP PARTITION IF EXISTS `p2`\"},\n\t\t{\"alter table t drop partition p1, p2;\", true, \"ALTER TABLE `t` DROP PARTITION `p1`,`p2`\"},\n\t\t{\"alter table t drop partition if exists p1, p2;\", true, \"ALTER TABLE `t` DROP PARTITION IF EXISTS `p1`,`p2`\"},\n\t\t// For check table partition statement\n\t\t{\"alter table t check partition all;\", true, \"ALTER TABLE `t` CHECK PARTITION ALL\"},\n\t\t{\"alter table t check partition p;\", true, \"ALTER TABLE `t` CHECK PARTITION `p`\"},\n\t\t{\"alter table t check partition p1, p2;\", true, \"ALTER TABLE `t` CHECK PARTITION `p1`,`p2`\"},\n\t\t{\"alter table employees add partition partitions 1;\", true, \"ALTER TABLE `employees` ADD PARTITION PARTITIONS 1\"},\n\t\t{\"alter table employees add partition partitions 2;\", true, \"ALTER TABLE `employees` ADD PARTITION PARTITIONS 2\"},\n\t\t{\"alter table clients coalesce partition 3;\", true, \"ALTER TABLE `clients` COALESCE PARTITION 3\"},\n\t\t{\"alter table clients coalesce partition 4;\", true, \"ALTER TABLE `clients` COALESCE PARTITION 4\"},\n\t\t{\"alter table clients coalesce partition no_write_to_binlog 4;\", true, \"ALTER TABLE `clients` COALESCE PARTITION NO_WRITE_TO_BINLOG 4\"},\n\t\t{\"alter table clients coalesce partition local 4;\", true, \"ALTER TABLE `clients` COALESCE PARTITION NO_WRITE_TO_BINLOG 4\"},\n\t\t{\"ALTER TABLE t DISABLE KEYS\", true, \"ALTER TABLE `t` DISABLE KEYS\"},\n\t\t{\"ALTER TABLE t ENABLE KEYS\", true, \"ALTER TABLE `t` ENABLE KEYS\"},\n\t\t// {\"ALTER TABLE t MODIFY COLUMN a varchar(255)\", true, \"ALTER TABLE `t` MODIFY COLUMN `a` VARCHAR(255)\"},\n\t\t// {\"ALTER TABLE t MODIFY COLUMN IF EXISTS a varchar(255)\", true, \"ALTER TABLE `t` MODIFY COLUMN IF EXISTS `a` VARCHAR(255)\"},\n\t\t// {\"ALTER TABLE t CHANGE COLUMN a b varchar(255)\", true, \"ALTER TABLE `t` CHANGE COLUMN `a` `b` VARCHAR(255)\"},\n\t\t// {\"ALTER TABLE t CHANGE COLUMN IF EXISTS a b varchar(255)\", true, \"ALTER TABLE `t` CHANGE COLUMN IF EXISTS `a` `b` VARCHAR(255)\"},\n\t\t// {\"ALTER TABLE t CHANGE COLUMN a b varchar(255) CHARACTER SET UTF8 BINARY\", true, \"ALTER TABLE `t` CHANGE COLUMN `a` `b` VARCHAR(255) BINARY CHARACTER SET UTF8\"},\n\t\t// {\"ALTER TABLE t CHANGE COLUMN a b varchar(255) FIRST\", true, \"ALTER TABLE `t` CHANGE COLUMN `a` `b` VARCHAR(255) FIRST\"},\n\n\t\t// For alter table rename statement.\n\t\t{\"ALTER TABLE db.t RENAME to db1.t1\", true, \"ALTER TABLE `db`.`t` RENAME AS `db1`.`t1`\"},\n\t\t{\"ALTER TABLE db.t RENAME db1.t1\", true, \"ALTER TABLE `db`.`t` RENAME AS `db1`.`t1`\"},\n\t\t{\"ALTER TABLE db.t RENAME = db1.t1\", true, \"ALTER TABLE `db`.`t` RENAME AS `db1`.`t1`\"},\n\t\t{\"ALTER TABLE db.t RENAME as db1.t1\", true, \"ALTER TABLE `db`.`t` RENAME AS `db1`.`t1`\"},\n\t\t{\"ALTER TABLE t RENAME to t1\", true, \"ALTER TABLE `t` RENAME AS `t1`\"},\n\t\t{\"ALTER TABLE t RENAME t1\", true, \"ALTER TABLE `t` RENAME AS `t1`\"},\n\t\t{\"ALTER TABLE t RENAME = t1\", true, \"ALTER TABLE `t` RENAME AS `t1`\"},\n\t\t{\"ALTER TABLE t RENAME as t1\", true, \"ALTER TABLE `t` RENAME AS `t1`\"},\n\n\t\t// For #499, alter table order by\n\t\t{\"ALTER TABLE t_n ORDER BY ident\", true, \"ALTER TABLE `t_n` ORDER BY `ident`\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident ASC\", true, \"ALTER TABLE `t_n` ORDER BY `ident`\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident DESC\", true, \"ALTER TABLE `t_n` ORDER BY `ident` DESC\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1, ident2\", true, \"ALTER TABLE `t_n` ORDER BY `ident1`,`ident2`\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1 ASC, ident2\", true, \"ALTER TABLE `t_n` ORDER BY `ident1`,`ident2`\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1 ASC, ident2 ASC\", true, \"ALTER TABLE `t_n` ORDER BY `ident1`,`ident2`\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1 ASC, ident2 DESC\", true, \"ALTER TABLE `t_n` ORDER BY `ident1`,`ident2` DESC\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1 DESC, ident2\", true, \"ALTER TABLE `t_n` ORDER BY `ident1` DESC,`ident2`\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1 DESC, ident2 ASC\", true, \"ALTER TABLE `t_n` ORDER BY `ident1` DESC,`ident2`\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1 DESC, ident2 DESC\", true, \"ALTER TABLE `t_n` ORDER BY `ident1` DESC,`ident2` DESC\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1, ident2, ident3\", true, \"ALTER TABLE `t_n` ORDER BY `ident1`,`ident2`,`ident3`\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1, ident2, ident3 ASC\", true, \"ALTER TABLE `t_n` ORDER BY `ident1`,`ident2`,`ident3`\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1, ident2, ident3 DESC\", true, \"ALTER TABLE `t_n` ORDER BY `ident1`,`ident2`,`ident3` DESC\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1 ASC, ident2 ASC, ident3 ASC\", true, \"ALTER TABLE `t_n` ORDER BY `ident1`,`ident2`,`ident3`\"},\n\t\t{\"ALTER TABLE t_n ORDER BY ident1 DESC, ident2 DESC, ident3 DESC\", true, \"ALTER TABLE `t_n` ORDER BY `ident1` DESC,`ident2` DESC,`ident3` DESC\"},\n\n\t\t// For alter table rename column statement.\n\t\t{\"ALTER TABLE t RENAME COLUMN a TO b\", true, \"ALTER TABLE `t` RENAME COLUMN `a` TO `b`\"},\n\t\t{\"ALTER TABLE t RENAME COLUMN t.a TO t.b\", false, \"\"},\n\t\t{\"ALTER TABLE t RENAME COLUMN a TO t.b\", false, \"\"},\n\t\t{\"ALTER TABLE t RENAME COLUMN t.a TO b\", false, \"\"},\n\n\t\t{\"ALTER TABLE t ALTER COLUMN a SET DEFAULT 1\", true, \"ALTER TABLE `t` ALTER COLUMN `a` SET DEFAULT 1\"},\n\t\t{\"ALTER TABLE t ALTER a SET DEFAULT 1\", true, \"ALTER TABLE `t` ALTER COLUMN `a` SET DEFAULT 1\"},\n\t\t{\"ALTER TABLE t ALTER COLUMN a SET DEFAULT CURRENT_TIMESTAMP\", false, \"\"},\n\t\t{\"ALTER TABLE t ALTER COLUMN a SET DEFAULT NOW()\", false, \"\"},\n\t\t{\"ALTER TABLE t ALTER COLUMN a SET DEFAULT 1+1\", false, \"\"},\n\t\t{\"ALTER TABLE t ALTER COLUMN a SET DEFAULT (CURRENT_TIMESTAMP())\", true, \"ALTER TABLE `t` ALTER COLUMN `a` SET DEFAULT (CURRENT_TIMESTAMP())\"},\n\t\t{\"ALTER TABLE t ALTER COLUMN a SET DEFAULT (NOW())\", true, \"ALTER TABLE `t` ALTER COLUMN `a` SET DEFAULT (NOW())\"},\n\t\t{\"ALTER TABLE t ALTER COLUMN a SET DEFAULT (1+1)\", true, \"ALTER TABLE `t` ALTER COLUMN `a` SET DEFAULT (1+1)\"},\n\t\t{\"ALTER TABLE t ALTER COLUMN a SET DEFAULT (1)\", true, \"ALTER TABLE `t` ALTER COLUMN `a` SET DEFAULT 1\"},\n\t\t{\"ALTER TABLE t ALTER COLUMN a DROP DEFAULT\", true, \"ALTER TABLE `t` ALTER COLUMN `a` DROP DEFAULT\"},\n\t\t{\"ALTER TABLE t ALTER a DROP DEFAULT\", true, \"ALTER TABLE `t` ALTER COLUMN `a` DROP DEFAULT\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, lock=none\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = NONE\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, lock=default\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = DEFAULT\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, lock=shared\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = SHARED\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, lock=exclusive\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = EXCLUSIVE\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, lock none\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = NONE\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, lock default\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = DEFAULT\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, lock shared\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = SHARED\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, lock exclusive\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = EXCLUSIVE\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, LOCK=NONE\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = NONE\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, LOCK=DEFAULT\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = DEFAULT\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, LOCK=SHARED\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = SHARED\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, LOCK=EXCLUSIVE\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, LOCK = EXCLUSIVE\"},\n\t\t{\"ALTER TABLE t ADD FULLTEXT KEY `FullText` (`name` ASC)\", true, \"ALTER TABLE `t` ADD FULLTEXT `FullText`(`name`)\"},\n\t\t{\"ALTER TABLE t ADD FULLTEXT `FullText` (`name` ASC)\", true, \"ALTER TABLE `t` ADD FULLTEXT `FullText`(`name`)\"},\n\t\t{\"ALTER TABLE t ADD FULLTEXT INDEX `FullText` (`name` ASC)\", true, \"ALTER TABLE `t` ADD FULLTEXT `FullText`(`name`)\"},\n\t\t{\"ALTER TABLE t ADD INDEX (a) USING BTREE COMMENT 'a'\", true, \"ALTER TABLE `t` ADD INDEX(`a`) USING BTREE COMMENT 'a'\"},\n\t\t{\"ALTER TABLE t ADD INDEX IF NOT EXISTS (a) USING BTREE COMMENT 'a'\", true, \"ALTER TABLE `t` ADD INDEX IF NOT EXISTS(`a`) USING BTREE COMMENT 'a'\"},\n\t\t{\"ALTER TABLE t ADD INDEX (a) USING RTREE COMMENT 'a'\", true, \"ALTER TABLE `t` ADD INDEX(`a`) USING RTREE COMMENT 'a'\"},\n\t\t{\"ALTER TABLE t ADD KEY (a) USING HASH COMMENT 'a'\", true, \"ALTER TABLE `t` ADD INDEX(`a`) USING HASH COMMENT 'a'\"},\n\t\t{\"ALTER TABLE t ADD KEY IF NOT EXISTS (a) USING HASH COMMENT 'a'\", true, \"ALTER TABLE `t` ADD INDEX IF NOT EXISTS(`a`) USING HASH COMMENT 'a'\"},\n\t\t{\"ALTER TABLE t ADD PRIMARY KEY ident USING RTREE ( a DESC , b   )\", true, \"ALTER TABLE `t` ADD PRIMARY KEY `ident`(`a`, `b`) USING RTREE\"},\n\t\t{\"ALTER TABLE t ADD KEY USING RTREE   ( a ) \", true, \"ALTER TABLE `t` ADD INDEX(`a`) USING RTREE\"},\n\t\t{\"ALTER TABLE t ADD KEY USING RTREE ( ident ASC , ident ( 123 ) )\", true, \"ALTER TABLE `t` ADD INDEX(`ident`, `ident`(123)) USING RTREE\"},\n\t\t{\"ALTER TABLE t ADD PRIMARY KEY (a) COMMENT 'a'\", true, \"ALTER TABLE `t` ADD PRIMARY KEY(`a`) COMMENT 'a'\"},\n\t\t{\"ALTER TABLE t ADD UNIQUE (a) COMMENT 'a'\", true, \"ALTER TABLE `t` ADD UNIQUE(`a`) COMMENT 'a'\"},\n\t\t{\"ALTER TABLE t ADD UNIQUE KEY (a) COMMENT 'a'\", true, \"ALTER TABLE `t` ADD UNIQUE(`a`) COMMENT 'a'\"},\n\t\t{\"ALTER TABLE t ADD UNIQUE INDEX (a) COMMENT 'a'\", true, \"ALTER TABLE `t` ADD UNIQUE(`a`) COMMENT 'a'\"},\n\t\t{\"ALTER TABLE t ADD CONSTRAINT fk_t2_id FOREIGN KEY (t2_id) REFERENCES t(id)\", true, \"ALTER TABLE `t` ADD CONSTRAINT `fk_t2_id` FOREIGN KEY (`t2_id`) REFERENCES `t`(`id`)\"},\n\t\t{\"ALTER TABLE t ADD CONSTRAINT fk_t2_id FOREIGN KEY IF NOT EXISTS (t2_id) REFERENCES t(id)\", true, \"ALTER TABLE `t` ADD CONSTRAINT `fk_t2_id` FOREIGN KEY IF NOT EXISTS (`t2_id`) REFERENCES `t`(`id`)\"},\n\t\t{\"ALTER TABLE t ADD CONSTRAINT c_1 CHECK (1+1) NOT ENFORCED, ADD UNIQUE (a)\", true, \"ALTER TABLE `t` ADD CONSTRAINT `c_1` CHECK(1+1) NOT ENFORCED, ADD UNIQUE(`a`)\"},\n\t\t{\"ALTER TABLE t ADD CONSTRAINT c_1 CHECK (1+1) ENFORCED, ADD UNIQUE (a)\", true, \"ALTER TABLE `t` ADD CONSTRAINT `c_1` CHECK(1+1) ENFORCED, ADD UNIQUE(`a`)\"},\n\t\t{\"ALTER TABLE t ADD CONSTRAINT c_1 CHECK (1+1), ADD UNIQUE (a)\", true, \"ALTER TABLE `t` ADD CONSTRAINT `c_1` CHECK(1+1) ENFORCED, ADD UNIQUE(`a`)\"},\n\t\t{\"ALTER TABLE t ENGINE ''\", true, \"ALTER TABLE `t` ENGINE = ''\"},\n\t\t{\"ALTER TABLE t ENGINE = ''\", true, \"ALTER TABLE `t` ENGINE = ''\"},\n\t\t{\"ALTER TABLE t ENGINE = 'innodb'\", true, \"ALTER TABLE `t` ENGINE = innodb\"},\n\t\t{\"ALTER TABLE t ENGINE = innodb\", true, \"ALTER TABLE `t` ENGINE = innodb\"},\n\t\t{\"ALTER TABLE `db`.`t` ENGINE = ``\", true, \"ALTER TABLE `db`.`t` ENGINE = ''\"},\n\t\t{\"ALTER TABLE t INSERT_METHOD = FIRST\", true, \"ALTER TABLE `t` INSERT_METHOD = 'FIRST'\"},\n\t\t{\"ALTER TABLE t INSERT_METHOD LAST\", true, \"ALTER TABLE `t` INSERT_METHOD = 'LAST'\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT UNSIGNED, ADD COLUMN a SMALLINT\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT UNSIGNED, ADD COLUMN `a` SMALLINT\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a SMALLINT, ENGINE = '', default COLLATE = UTF8_GENERAL_CI\", true, \"ALTER TABLE `t` ADD COLUMN `a` SMALLINT, ENGINE = '', DEFAULT COLLATE = UTF8_GENERAL_CI\"},\n\t\t{\"ALTER TABLE t ENGINE = '', COMMENT='', default COLLATE = UTF8_GENERAL_CI\", true, \"ALTER TABLE `t` ENGINE = '', COMMENT = '', DEFAULT COLLATE = UTF8_GENERAL_CI\"},\n\t\t// {\"ALTER TABLE t ENGINE = '', ADD COLUMN a SMALLINT\", true, \"ALTER TABLE `t` ENGINE = '', ADD COLUMN `a` SMALLINT\"},\n\t\t// {\"ALTER TABLE t default COLLATE = UTF8_GENERAL_CI, ENGINE = '', ADD COLUMN a SMALLINT\", true, \"ALTER TABLE `t` DEFAULT COLLATE = UTF8_GENERAL_CI, ENGINE = '', ADD COLUMN `a` SMALLINT\"},\n\t\t{\"ALTER TABLE t shard_row_id_bits = 1\", true, \"ALTER TABLE `t` SHARD_ROW_ID_BITS = 1\"},\n\t\t{\"ALTER TABLE t AUTO_INCREMENT 3\", true, \"ALTER TABLE `t` AUTO_INCREMENT = 3\"},\n\t\t{\"ALTER TABLE t AUTO_INCREMENT = 3\", true, \"ALTER TABLE `t` AUTO_INCREMENT = 3\"},\n\t\t// alter table convert to character set default, issue #498\n\t\t{\"alter table d_n.t_n convert to character set default\", true, \"ALTER TABLE `d_n`.`t_n` CONVERT TO CHARACTER SET DEFAULT\"},\n\t\t{\"alter table d_n.t_n convert to charset default\", true, \"ALTER TABLE `d_n`.`t_n` CONVERT TO CHARACTER SET DEFAULT\"},\n\t\t{\"alter table d_n.t_n convert to char set default\", true, \"ALTER TABLE `d_n`.`t_n` CONVERT TO CHARACTER SET DEFAULT\"},\n\t\t{\"alter table d_n.t_n convert to character set default collate utf8mb4_0900_ai_ci\", true, \"ALTER TABLE `d_n`.`t_n` CONVERT TO CHARACTER SET DEFAULT COLLATE UTF8MB4_0900_AI_CI\"},\n\n\t\t{\"ALTER TABLE t FORCE\", true, \"ALTER TABLE `t` FORCE /* AlterTableForce is not supported */ \"},\n\t\t{\"ALTER TABLE t DROP INDEX;\", false, \"ALTER TABLE `t` DROP INDEX\"},\n\t\t{\"ALTER TABLE t DROP INDEX a\", true, \"ALTER TABLE `t` DROP INDEX `a`\"},\n\t\t{\"ALTER TABLE t DROP INDEX IF EXISTS a\", true, \"ALTER TABLE `t` DROP INDEX IF EXISTS `a`\"},\n\n\t\t// For alter table alter index statement\n\t\t{\"ALTER TABLE t ALTER INDEX a INVISIBLE\", true, \"ALTER TABLE `t` ALTER INDEX `a` INVISIBLE\"},\n\t\t{\"ALTER TABLE t ALTER INDEX a VISIBLE\", true, \"ALTER TABLE `t` ALTER INDEX `a` VISIBLE\"},\n\n\t\t{\"ALTER TABLE t DROP FOREIGN KEY a\", true, \"ALTER TABLE `t` DROP FOREIGN KEY `a`\"},\n\t\t{\"ALTER TABLE t DROP FOREIGN KEY IF EXISTS a\", true, \"ALTER TABLE `t` DROP FOREIGN KEY IF EXISTS `a`\"},\n\t\t{\"ALTER TABLE t DROP COLUMN a CASCADE\", true, \"ALTER TABLE `t` DROP COLUMN `a`\"},\n\t\t{\"ALTER TABLE t DROP COLUMN IF EXISTS a CASCADE\", true, \"ALTER TABLE `t` DROP COLUMN IF EXISTS `a`\"},\n\t\t{`ALTER TABLE testTableCompression COMPRESSION=\"LZ4\";`, true, \"ALTER TABLE `testTableCompression` COMPRESSION = 'LZ4'\"},\n\t\t{`ALTER TABLE t1 COMPRESSION=\"zlib\";`, true, \"ALTER TABLE `t1` COMPRESSION = 'zlib'\"},\n\t\t{\"ALTER TABLE t1\", true, \"ALTER TABLE `t1`\"},\n\t\t{\"ALTER TABLE t1 ,\", false, \"\"},\n\n\t\t// For #6405\n\t\t{\"ALTER TABLE t RENAME KEY a TO b;\", true, \"ALTER TABLE `t` RENAME INDEX `a` TO `b`\"},\n\t\t{\"ALTER TABLE t RENAME INDEX a TO b;\", true, \"ALTER TABLE `t` RENAME INDEX `a` TO `b`\"},\n\n\t\t// For #497, support `ALTER TABLE ALTER CHECK` and `ALTER TABLE DROP CHECK` syntax\n\t\t{\"ALTER TABLE d_n.t_n DROP CHECK ident;\", true, \"ALTER TABLE `d_n`.`t_n` DROP CHECK `ident`\"},\n\t\t{\"ALTER TABLE t_n LOCK = DEFAULT , DROP CHECK ident;\", true, \"ALTER TABLE `t_n` LOCK = DEFAULT, DROP CHECK `ident`\"},\n\t\t{\"ALTER TABLE t_n ALTER CHECK ident ENFORCED;\", true, \"ALTER TABLE `t_n` ALTER CHECK `ident` ENFORCED\"},\n\t\t{\"ALTER TABLE t_n ALTER CHECK ident NOT ENFORCED;\", true, \"ALTER TABLE `t_n` ALTER CHECK `ident` NOT ENFORCED\"},\n\n\t\t{\"alter table t analyze partition a\", true, \"ANALYZE TABLE `t` PARTITION `a`\"},\n\t\t{\"alter table t analyze partition a with 4 buckets\", true, \"ANALYZE TABLE `t` PARTITION `a` WITH 4 BUCKETS\"},\n\t\t{\"alter table t analyze partition a index b\", true, \"ANALYZE TABLE `t` PARTITION `a` INDEX `b`\"},\n\t\t{\"alter table t analyze partition a index b with 4 buckets\", true, \"ANALYZE TABLE `t` PARTITION `a` INDEX `b` WITH 4 BUCKETS\"},\n\n\t\t{\"alter table t partition by hash(a)\", true, \"ALTER TABLE `t` PARTITION BY HASH (`a`) PARTITIONS 1\"},\n\t\t{\"alter table t partition by range(a)\", false, \"\"},\n\t\t{\"alter table t partition by range(a) (partition x values less than (75))\", true, \"ALTER TABLE `t` PARTITION BY RANGE (`a`) (PARTITION `x` VALUES LESS THAN (75))\"},\n\t\t{\"alter table t comment 'cmt' partition by hash(a)\", true, \"ALTER TABLE `t` COMMENT = 'cmt' PARTITION BY HASH (`a`) PARTITIONS 1\"},\n\t\t{\"alter table t enable keys, comment = 'cmt' partition by hash(a)\", true, \"ALTER TABLE `t` ENABLE KEYS, COMMENT = 'cmt' PARTITION BY HASH (`a`) PARTITIONS 1\"},\n\t\t{\"alter table t enable keys, comment = 'cmt', partition by hash(a)\", false, \"\"},\n\n\t\t// Test keyword `FIELDS`\n\t\t{\"alter table t partition by range FIELDS(a) (partition x values less than maxvalue)\", true, \"ALTER TABLE `t` PARTITION BY RANGE COLUMNS (`a`) (PARTITION `x` VALUES LESS THAN (MAXVALUE))\"},\n\t\t{\"alter table t partition by list FIELDS(a) (PARTITION p0 VALUES IN (5, 10, 15))\", true, \"ALTER TABLE `t` PARTITION BY LIST COLUMNS (`a`) (PARTITION `p0` VALUES IN (5, 10, 15))\"},\n\t\t{\"alter table t partition by range FIELDS(a,b,c) (partition p1 values less than (1,1,1));\", true, \"ALTER TABLE `t` PARTITION BY RANGE COLUMNS (`a`,`b`,`c`) (PARTITION `p1` VALUES LESS THAN (1, 1, 1))\"},\n\t\t{\"alter table t partition by list FIELDS(a,b,c) (PARTITION p0 VALUES IN ((5, 10, 15)))\", true, \"ALTER TABLE `t` PARTITION BY LIST COLUMNS (`a`,`b`,`c`) (PARTITION `p0` VALUES IN ((5, 10, 15)))\"},\n\n\t\t{\"alter table t with validation, add column b int as (a + 1)\", true, \"ALTER TABLE `t` WITH VALIDATION, ADD COLUMN `b` INT GENERATED ALWAYS AS(`a`+1) VIRTUAL\"},\n\t\t{\"alter table t without validation, add column b int as (a + 1)\", true, \"ALTER TABLE `t` WITHOUT VALIDATION, ADD COLUMN `b` INT GENERATED ALWAYS AS(`a`+1) VIRTUAL\"},\n\t\t{\"alter table t without validation, with validation, add column b int as (a + 1)\", true, \"ALTER TABLE `t` WITHOUT VALIDATION, WITH VALIDATION, ADD COLUMN `b` INT GENERATED ALWAYS AS(`a`+1) VIRTUAL\"},\n\t\t{\"alter table t with validation, modify column b int as (a + 2) \", true, \"ALTER TABLE `t` WITH VALIDATION, MODIFY COLUMN `b` INT GENERATED ALWAYS AS(`a`+2) VIRTUAL\"},\n\t\t{\"alter table t with validation, change column b c int as (a + 2)\", true, \"ALTER TABLE `t` WITH VALIDATION, CHANGE COLUMN `b` `c` INT GENERATED ALWAYS AS(`a`+2) VIRTUAL\"},\n\n\t\t{\"ALTER TABLE d_n.t_n ADD PARTITION NO_WRITE_TO_BINLOG\", true, \"ALTER TABLE `d_n`.`t_n` ADD PARTITION NO_WRITE_TO_BINLOG\"},\n\t\t{\"ALTER TABLE d_n.t_n ADD PARTITION LOCAL\", true, \"ALTER TABLE `d_n`.`t_n` ADD PARTITION NO_WRITE_TO_BINLOG\"},\n\n\t\t{\"alter table t with validation, exchange partition p with table nt without validation;\", true, \"ALTER TABLE `t` WITH VALIDATION, EXCHANGE PARTITION `p` WITH TABLE `nt` WITHOUT VALIDATION\"},\n\t\t{\"alter table t exchange partition p with table nt with validation;\", true, \"ALTER TABLE `t` EXCHANGE PARTITION `p` WITH TABLE `nt`\"},\n\n\t\t// For reorganize partition statement\n\t\t{\"alter table t reorganize partition;\", true, \"ALTER TABLE `t` REORGANIZE PARTITION\"},\n\t\t{\"alter table t reorganize partition local;\", true, \"ALTER TABLE `t` REORGANIZE PARTITION NO_WRITE_TO_BINLOG\"},\n\t\t{\"alter table t reorganize partition no_write_to_binlog;\", true, \"ALTER TABLE `t` REORGANIZE PARTITION NO_WRITE_TO_BINLOG\"},\n\t\t{\"ALTER TABLE members REORGANIZE PARTITION n0 INTO (PARTITION s0 VALUES LESS THAN (1960), PARTITION s1 VALUES LESS THAN (1970));\", true, \"ALTER TABLE `members` REORGANIZE PARTITION `n0` INTO (PARTITION `s0` VALUES LESS THAN (1960), PARTITION `s1` VALUES LESS THAN (1970))\"},\n\t\t{\"ALTER TABLE members REORGANIZE PARTITION LOCAL n0 INTO (PARTITION s0 VALUES LESS THAN (1960), PARTITION s1 VALUES LESS THAN (1970));\", true, \"ALTER TABLE `members` REORGANIZE PARTITION NO_WRITE_TO_BINLOG `n0` INTO (PARTITION `s0` VALUES LESS THAN (1960), PARTITION `s1` VALUES LESS THAN (1970))\"},\n\t\t{\"ALTER TABLE members REORGANIZE PARTITION p1,p2,p3 INTO ( PARTITION s0 VALUES LESS THAN (1960), PARTITION s1 VALUES LESS THAN (1970));\", true, \"ALTER TABLE `members` REORGANIZE PARTITION `p1`,`p2`,`p3` INTO (PARTITION `s0` VALUES LESS THAN (1960), PARTITION `s1` VALUES LESS THAN (1970))\"},\n\t\t{\"alter table t reorganize partition remove partition;\", false, \"\"},\n\t\t{\"alter table t reorganize partition no_write_to_binlog remove into (partition p0 VALUES LESS THAN (1991));\", true, \"ALTER TABLE `t` REORGANIZE PARTITION NO_WRITE_TO_BINLOG `remove` INTO (PARTITION `p0` VALUES LESS THAN (1991))\"},\n\n\t\t// For create index statement\n\t\t{\"CREATE INDEX idx ON t (a)\", true, \"CREATE INDEX `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE INDEX IF NOT EXISTS idx ON t (a)\", true, \"CREATE INDEX IF NOT EXISTS `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE UNIQUE INDEX idx ON t (a)\", true, \"CREATE UNIQUE INDEX `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE UNIQUE INDEX IF NOT EXISTS idx ON t (a)\", true, \"CREATE UNIQUE INDEX IF NOT EXISTS `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE UNIQUE INDEX ident ON d_n.t_n ( ident , ident ASC ) TYPE BTREE\", true, \"CREATE UNIQUE INDEX `ident` ON `d_n`.`t_n` (`ident`, `ident`) USING BTREE\"},\n\t\t{\"CREATE UNIQUE INDEX ident ON d_n.t_n ( ident , ident ASC ) TYPE HASH\", true, \"CREATE UNIQUE INDEX `ident` ON `d_n`.`t_n` (`ident`, `ident`) USING HASH\"},\n\t\t{\"CREATE UNIQUE INDEX ident ON d_n.t_n ( ident , ident ASC ) TYPE RTREE\", true, \"CREATE UNIQUE INDEX `ident` ON `d_n`.`t_n` (`ident`, `ident`) USING RTREE\"},\n\t\t{\"CREATE UNIQUE INDEX ident TYPE BTREE ON d_n.t_n ( ident , ident ASC )\", true, \"CREATE UNIQUE INDEX `ident` ON `d_n`.`t_n` (`ident`, `ident`) USING BTREE\"},\n\t\t{\"CREATE UNIQUE INDEX ident USING BTREE ON d_n.t_n ( ident , ident ASC )\", true, \"CREATE UNIQUE INDEX `ident` ON `d_n`.`t_n` (`ident`, `ident`) USING BTREE\"},\n\t\t{\"CREATE SPATIAL INDEX idx ON t (a)\", true, \"CREATE SPATIAL INDEX `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE SPATIAL INDEX IF NOT EXISTS idx ON t (a)\", true, \"CREATE SPATIAL INDEX IF NOT EXISTS `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE FULLTEXT INDEX idx ON t (a)\", true, \"CREATE FULLTEXT INDEX `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE FULLTEXT INDEX IF NOT EXISTS idx ON t (a)\", true, \"CREATE FULLTEXT INDEX IF NOT EXISTS `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE FULLTEXT INDEX idx ON t (a) WITH PARSER ident\", true, \"CREATE FULLTEXT INDEX `idx` ON `t` (`a`) WITH PARSER `ident`\"},\n\t\t{\"CREATE FULLTEXT INDEX idx ON t (a) WITH PARSER ident comment 'string'\", true, \"CREATE FULLTEXT INDEX `idx` ON `t` (`a`) WITH PARSER `ident` COMMENT 'string'\"},\n\t\t{\"CREATE FULLTEXT INDEX idx ON t (a) comment 'string' with parser ident\", true, \"CREATE FULLTEXT INDEX `idx` ON `t` (`a`) WITH PARSER `ident` COMMENT 'string'\"},\n\t\t{\"CREATE FULLTEXT INDEX idx ON t (a) WITH PARSER ident comment 'string' lock default\", true, \"CREATE FULLTEXT INDEX `idx` ON `t` (`a`) WITH PARSER `ident` COMMENT 'string'\"},\n\t\t{\"CREATE INDEX idx ON t (a) USING HASH\", true, \"CREATE INDEX `idx` ON `t` (`a`) USING HASH\"},\n\t\t{\"CREATE INDEX idx ON t (a) COMMENT 'foo'\", true, \"CREATE INDEX `idx` ON `t` (`a`) COMMENT 'foo'\"},\n\t\t{\"CREATE INDEX idx ON t (a) USING HASH COMMENT 'foo'\", true, \"CREATE INDEX `idx` ON `t` (`a`) USING HASH COMMENT 'foo'\"},\n\t\t{\"CREATE INDEX idx ON t (a) LOCK=NONE\", true, \"CREATE INDEX `idx` ON `t` (`a`) LOCK = NONE\"},\n\t\t{\"CREATE INDEX idx USING BTREE ON t (a) USING HASH COMMENT 'foo'\", true, \"CREATE INDEX `idx` ON `t` (`a`) USING HASH COMMENT 'foo'\"},\n\t\t{\"CREATE INDEX idx USING BTREE ON t (a)\", true, \"CREATE INDEX `idx` ON `t` (`a`) USING BTREE\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) VISIBLE\", true, \"CREATE INDEX `idx` ON `t` (`a`) VISIBLE\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) INVISIBLE\", true, \"CREATE INDEX `idx` ON `t` (`a`) INVISIBLE\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) INVISIBLE VISIBLE\", true, \"CREATE INDEX `idx` ON `t` (`a`) VISIBLE\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) VISIBLE INVISIBLE\", true, \"CREATE INDEX `idx` ON `t` (`a`) INVISIBLE\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) USING HASH VISIBLE\", true, \"CREATE INDEX `idx` ON `t` (`a`) USING HASH VISIBLE\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) USING HASH INVISIBLE\", true, \"CREATE INDEX `idx` ON `t` (`a`) USING HASH INVISIBLE\"},\n\n\t\t// For create index with algorithm\n\t\t{\"CREATE INDEX idx ON t ( a ) ALGORITHM = DEFAULT\", true, \"CREATE INDEX `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) ALGORITHM DEFAULT\", true, \"CREATE INDEX `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) ALGORITHM = INPLACE\", true, \"CREATE INDEX `idx` ON `t` (`a`) ALGORITHM = INPLACE\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) ALGORITHM INPLACE\", true, \"CREATE INDEX `idx` ON `t` (`a`) ALGORITHM = INPLACE\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) ALGORITHM = COPY\", true, \"CREATE INDEX `idx` ON `t` (`a`) ALGORITHM = COPY\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) ALGORITHM COPY\", true, \"CREATE INDEX `idx` ON `t` (`a`) ALGORITHM = COPY\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) ALGORITHM = DEFAULT LOCK = DEFAULT\", true, \"CREATE INDEX `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) LOCK = DEFAULT ALGORITHM = DEFAULT\", true, \"CREATE INDEX `idx` ON `t` (`a`)\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) ALGORITHM = INPLACE LOCK = EXCLUSIVE\", true, \"CREATE INDEX `idx` ON `t` (`a`) ALGORITHM = INPLACE LOCK = EXCLUSIVE\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) LOCK = EXCLUSIVE ALGORITHM = INPLACE\", true, \"CREATE INDEX `idx` ON `t` (`a`) ALGORITHM = INPLACE LOCK = EXCLUSIVE\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) ALGORITHM = ident\", false, \"\"},\n\t\t{\"CREATE INDEX idx ON t ( a ) ALGORITHM ident\", false, \"\"},\n\n\t\t//For dorp index statement\n\t\t{\"drop index a on t\", true, \"DROP INDEX `a` ON `t`\"},\n\t\t{\"drop index a on db.t\", true, \"DROP INDEX `a` ON `db`.`t`\"},\n\t\t{\"drop index a on db.`tb-ttb`\", true, \"DROP INDEX `a` ON `db`.`tb-ttb`\"},\n\t\t{\"drop index if exists a on t\", true, \"DROP INDEX IF EXISTS `a` ON `t`\"},\n\t\t{\"drop index if exists a on db.t\", true, \"DROP INDEX IF EXISTS `a` ON `db`.`t`\"},\n\t\t{\"drop index if exists a on db.`tb-ttb`\", true, \"DROP INDEX IF EXISTS `a` ON `db`.`tb-ttb`\"},\n\t\t{\"drop index idx on t algorithm = default\", true, \"DROP INDEX `idx` ON `t`\"},\n\t\t{\"drop index idx on t algorithm default\", true, \"DROP INDEX `idx` ON `t`\"},\n\t\t{\"drop index idx on t algorithm = inplace\", true, \"DROP INDEX `idx` ON `t` ALGORITHM = INPLACE\"},\n\t\t{\"drop index idx on t algorithm inplace\", true, \"DROP INDEX `idx` ON `t` ALGORITHM = INPLACE\"},\n\t\t{\"drop index idx on t lock = default\", true, \"DROP INDEX `idx` ON `t`\"},\n\t\t{\"drop index idx on t lock default\", true, \"DROP INDEX `idx` ON `t`\"},\n\t\t{\"drop index idx on t lock = shared\", true, \"DROP INDEX `idx` ON `t` LOCK = SHARED\"},\n\t\t{\"drop index idx on t lock shared\", true, \"DROP INDEX `idx` ON `t` LOCK = SHARED\"},\n\t\t{\"drop index idx on t algorithm = default lock = default\", true, \"DROP INDEX `idx` ON `t`\"},\n\t\t{\"drop index idx on t lock = default algorithm = default\", true, \"DROP INDEX `idx` ON `t`\"},\n\t\t{\"drop index idx on t algorithm = inplace lock = exclusive\", true, \"DROP INDEX `idx` ON `t` ALGORITHM = INPLACE LOCK = EXCLUSIVE\"},\n\t\t{\"drop index idx on t lock = exclusive algorithm = inplace\", true, \"DROP INDEX `idx` ON `t` ALGORITHM = INPLACE LOCK = EXCLUSIVE\"},\n\t\t{\"drop index idx on t algorithm = algorithm_type\", false, \"\"},\n\t\t{\"drop index idx on t algorithm algorithm_type\", false, \"\"},\n\t\t{\"drop index idx on t lock = lock_type\", false, \"\"},\n\t\t{\"drop index idx on t lock lock_type\", false, \"\"},\n\n\t\t// for rename table statement\n\t\t{\"RENAME TABLE t TO t1\", true, \"RENAME TABLE `t` TO `t1`\"},\n\t\t{\"RENAME TABLE t t1\", false, \"RENAME TABLE `t` TO `t1`\"},\n\t\t{\"RENAME TABLE d.t TO d1.t1\", true, \"RENAME TABLE `d`.`t` TO `d1`.`t1`\"},\n\t\t{\"RENAME TABLE t1 TO t2, t3 TO t4\", true, \"RENAME TABLE `t1` TO `t2`, `t3` TO `t4`\"},\n\n\t\t// for truncate statement\n\t\t{\"TRUNCATE TABLE t1\", true, \"TRUNCATE TABLE `t1`\"},\n\t\t{\"TRUNCATE t1\", true, \"TRUNCATE TABLE `t1`\"},\n\n\t\t// for empty alert table index\n\t\t{\"ALTER TABLE t ADD INDEX () \", false, \"\"},\n\t\t{\"ALTER TABLE t ADD UNIQUE ()\", false, \"\"},\n\t\t{\"ALTER TABLE t ADD UNIQUE INDEX ()\", false, \"\"},\n\t\t{\"ALTER TABLE t ADD UNIQUE KEY ()\", false, \"\"},\n\n\t\t// for keyword `SECONDARY_LOAD`, `SECONDARY_UNLOAD`\n\t\t{\"ALTER TABLE d_n.t_n SECONDARY_LOAD\", true, \"ALTER TABLE `d_n`.`t_n` SECONDARY_LOAD\"},\n\t\t{\"ALTER TABLE d_n.t_n SECONDARY_UNLOAD\", true, \"ALTER TABLE `d_n`.`t_n` SECONDARY_UNLOAD\"},\n\t\t{\"ALTER TABLE t_n LOCK = DEFAULT , SECONDARY_LOAD\", true, \"ALTER TABLE `t_n` LOCK = DEFAULT, SECONDARY_LOAD\"},\n\t\t{\"ALTER TABLE d_n.t_n ALGORITHM = DEFAULT , SECONDARY_LOAD\", true, \"ALTER TABLE `d_n`.`t_n` ALGORITHM = DEFAULT, SECONDARY_LOAD\"},\n\t\t{\"ALTER TABLE d_n.t_n ALGORITHM = DEFAULT , SECONDARY_UNLOAD\", true, \"ALTER TABLE `d_n`.`t_n` ALGORITHM = DEFAULT, SECONDARY_UNLOAD\"},\n\n\t\t// for issue 4538\n\t\t{\"create table a (process double)\", true, \"CREATE TABLE `a` (`process` DOUBLE)\"},\n\n\t\t// // for issue 4740\n\t\t// {\"create table t (a int1, b int2, c int3, d int4, e int8)\", true, \"CREATE TABLE `t` (`a` TINYINT,`b` SMALLINT,`c` MEDIUMINT,`d` INT,`e` BIGINT)\"},\n\n\t\t// // for issue 5918\n\t\t// {\"create table t (lv long varchar null)\", true, \"CREATE TABLE `t` (`lv` MEDIUMTEXT NULL)\"},\n\n\t\t// special table name\n\t\t// {\"CREATE TABLE cdp_test.`test2-1` (id int(11) DEFAULT NULL,key(id));\", true, \"CREATE TABLE `cdp_test`.`test2-1` (`id` INT(11) DEFAULT NULL,INDEX(`id`))\"},\n\t\t// {\"CREATE TABLE miantiao (`扁豆焖面`       INT(11));\", true, \"CREATE TABLE `miantiao` (`扁豆焖面` INT(11))\"},\n\n\t\t// for create table select\n\t\t{\"CREATE TABLE bar (m INT)  SELECT n FROM foo;\", true, \"CREATE TABLE `bar` (`m` INT) AS SELECT `n` FROM `foo`\"},\n\t\t{\"CREATE TABLE bar (m INT) IGNORE SELECT n FROM foo;\", true, \"CREATE TABLE `bar` (`m` INT) IGNORE AS SELECT `n` FROM `foo`\"},\n\t\t{\"CREATE TABLE bar (m INT) REPLACE SELECT n FROM foo;\", true, \"CREATE TABLE `bar` (`m` INT) REPLACE AS SELECT `n` FROM `foo`\"},\n\n\t\t// for generated column definition\n\t\t{\"create table t (a timestamp, b timestamp as (a) not null on update current_timestamp);\", false, \"\"},\n\t\t// {\"create table t (a bigint, b bigint as (a) primary key auto_increment);\", false, \"\"},\n\t\t// {\"create table t (a bigint, b bigint as (a) not null default 10);\", false, \"\"},\n\t\t// {\"create table t (a bigint, b bigint as (a+1) not null);\", true, \"CREATE TABLE `t` (`a` BIGINT,`b` BIGINT GENERATED ALWAYS AS(`a`+1) VIRTUAL NOT NULL)\"},\n\t\t// {\"create table t (a bigint, b bigint as (a+1) not null);\", true, \"CREATE TABLE `t` (`a` BIGINT,`b` BIGINT GENERATED ALWAYS AS(`a`+1) VIRTUAL NOT NULL)\"},\n\t\t// {\"create table t (a bigint, b bigint as (a+1) not null comment 'ttt');\", true, \"CREATE TABLE `t` (`a` BIGINT,`b` BIGINT GENERATED ALWAYS AS(`a`+1) VIRTUAL NOT NULL COMMENT 'ttt')\"},\n\t\t{\"alter table t add column (f timestamp as (a+1) default '2019-01-01 11:11:11');\", false, \"\"},\n\t\t{\"alter table t modify column f int as (a+1) default 55;\", false, \"\"},\n\n\t\t// for column format\n\t\t{\"create table t (a int column_format fixed)\", true, \"CREATE TABLE `t` (`a` INT COLUMN_FORMAT FIXED)\"},\n\t\t{\"create table t (a int column_format default)\", true, \"CREATE TABLE `t` (`a` INT COLUMN_FORMAT DEFAULT)\"},\n\t\t{\"create table t (a int column_format dynamic)\", true, \"CREATE TABLE `t` (`a` INT COLUMN_FORMAT DYNAMIC)\"},\n\t\t// {\"alter table t modify column a bigint column_format default\", true, \"ALTER TABLE `t` MODIFY COLUMN `a` BIGINT COLUMN_FORMAT DEFAULT\"},\n\n\t\t// for recover table\n\t\t{\"recover table by job 11\", true, \"RECOVER TABLE BY JOB 11\"},\n\t\t{\"recover table by job 11,12,13\", false, \"\"},\n\t\t{\"recover table by job\", false, \"\"},\n\t\t{\"recover table t1\", true, \"RECOVER TABLE `t1`\"},\n\t\t{\"recover table t1,t2\", false, \"\"},\n\t\t{\"recover table \", false, \"\"},\n\t\t{\"recover table t1 100\", true, \"RECOVER TABLE `t1` 100\"},\n\t\t{\"recover table t1 abc\", false, \"\"},\n\n\t\t// for flashback table.\n\t\t{\"flashback table t until timestamp '2019-09-24 20:16:31.124 +0800 CST'\", true, \"FLASHBACK TABLE `t` UNTIL TIMESTAMP '2019-09-24 20:16:31.124 +0800 CST'\"},\n\t\t{\"flashback table t until timestamp '2019-09-24 20:16:31.124 +0800 CST' TO t1\", true, \"FLASHBACK TABLE `t` UNTIL TIMESTAMP '2019-09-24 20:16:31.124 +0800 CST' TO `t1`\"},\n\n\t\t// for remove partitioning\n\t\t{\"alter table t remove partitioning\", true, \"ALTER TABLE `t` REMOVE PARTITIONING\"},\n\t\t{\"alter table db.ident remove partitioning\", true, \"ALTER TABLE `db`.`ident` REMOVE PARTITIONING\"},\n\t\t{\"alter table t lock = default remove partitioning\", true, \"ALTER TABLE `t` LOCK = DEFAULT REMOVE PARTITIONING\"},\n\n\t\t// for references without IndexColNameList\n\t\t// {\"alter table t add column a double (4,2) zerofill references b match full on update set null first\", true, \"ALTER TABLE `t` ADD COLUMN `a` DOUBLE(4,2) UNSIGNED ZEROFILL REFERENCES `b` MATCH FULL ON UPDATE SET NULL FIRST\"},\n\t\t{\"alter table d_n.t_n add constraint foreign key ident (ident(1)) references d_n.t_n match full on delete set null\", true, \"ALTER TABLE `d_n`.`t_n` ADD CONSTRAINT `ident` FOREIGN KEY (`ident`(1)) REFERENCES `d_n`.`t_n` MATCH FULL ON DELETE SET NULL\"},\n\t\t{\"alter table t_n add constraint ident foreign key (ident,ident(1)) references t_n match full on update set null on delete restrict\", true, \"ALTER TABLE `t_n` ADD CONSTRAINT `ident` FOREIGN KEY (`ident`, `ident`(1)) REFERENCES `t_n` MATCH FULL ON DELETE RESTRICT ON UPDATE SET NULL\"},\n\t\t{\"alter table d_n.t_n add foreign key ident (ident, ident(1) asc) references t_n match partial on delete cascade remove partitioning\", true, \"ALTER TABLE `d_n`.`t_n` ADD CONSTRAINT `ident` FOREIGN KEY (`ident`, `ident`(1)) REFERENCES `t_n` MATCH PARTIAL ON DELETE CASCADE REMOVE PARTITIONING\"},\n\t\t{\"alter table d_n.t_n add constraint foreign key (ident asc) references d_n.t_n match simple on update cascade on delete cascade\", true, \"ALTER TABLE `d_n`.`t_n` ADD CONSTRAINT FOREIGN KEY (`ident`) REFERENCES `d_n`.`t_n` MATCH SIMPLE ON DELETE CASCADE ON UPDATE CASCADE\"},\n\n\t\t// for character vary syntax\n\t\t// {\"create table t (a character varying(1));\", true, \"CREATE TABLE `t` (`a` VARCHAR(1))\"},\n\t\t// {\"create table t (a character varying(255));\", true, \"CREATE TABLE `t` (`a` VARCHAR(255))\"},\n\t\t// {\"create table t (a char varying(50));\", true, \"CREATE TABLE `t` (`a` VARCHAR(50))\"},\n\t\t// {\"create table t (a varcharacter(1));\", true, \"CREATE TABLE `t` (`a` VARCHAR(1))\"},\n\t\t// {\"create table t (a varcharacter(50));\", true, \"CREATE TABLE `t` (`a` VARCHAR(50))\"},\n\t\t// {\"create table t (a varcharacter(1), b varcharacter(255));\", true, \"CREATE TABLE `t` (`a` VARCHAR(1),`b` VARCHAR(255))\"},\n\t\t// {\"create table t (a char);\", true, \"CREATE TABLE `t` (`a` CHAR)\"},\n\t\t// {\"create table t (a character);\", true, \"CREATE TABLE `t` (`a` CHAR)\"},\n\t\t// {\"create table t (a character varying(50), b int);\", true, \"CREATE TABLE `t` (`a` VARCHAR(50),`b` INT)\"},\n\t\t// {\"create table t (a character, b int);\", true, \"CREATE TABLE `t` (`a` CHAR,`b` INT)\"},\n\t\t// {\"create table t (a national character varying(50));\", true, \"CREATE TABLE `t` (`a` VARCHAR(50))\"},\n\t\t// {\"create table t (a national char varying(50));\", true, \"CREATE TABLE `t` (`a` VARCHAR(50))\"},\n\t\t// {\"create table t (a national char);\", true, \"CREATE TABLE `t` (`a` CHAR)\"},\n\t\t// {\"create table t (a national character);\", true, \"CREATE TABLE `t` (`a` CHAR)\"},\n\t\t// {\"create table t (a nchar);\", true, \"CREATE TABLE `t` (`a` CHAR)\"},\n\t\t// {\"create table t (a nchar varchar(50));\", true, \"CREATE TABLE `t` (`a` VARCHAR(50))\"},\n\t\t// {\"create table t (a nchar varcharacter(50));\", true, \"CREATE TABLE `t` (`a` VARCHAR(50))\"},\n\t\t// {\"create table t (a national varchar);\", false, \"\"},\n\t\t// {\"create table t (a national varchar(50));\", true, \"CREATE TABLE `t` (`a` VARCHAR(50))\"},\n\t\t// {\"create table t (a national varcharacter(50));\", true, \"CREATE TABLE `t` (`a` VARCHAR(50))\"},\n\t\t// {\"create table t (a nchar varying(50));\", true, \"CREATE TABLE `t` (`a` VARCHAR(50))\"},\n\t\t// {\"create table t (a nvarchar(50));\", true, \"CREATE TABLE `t` (`a` VARCHAR(50))\"},\n\t\t// {\"create table nchar (a int);\", true, \"CREATE TABLE `nchar` (`a` INT)\"},\n\t\t// {\"create table nchar (a int, b nchar);\", true, \"CREATE TABLE `nchar` (`a` INT,`b` CHAR)\"},\n\t\t// {\"create table nchar (a int, b nchar(50));\", true, \"CREATE TABLE `nchar` (`a` INT,`b` CHAR(50))\"},\n\t\t// {\"alter table t_n storage disk , modify ident national varcharacter(12) column_format fixed first;\", true, \"ALTER TABLE `t_n` STORAGE DISK, MODIFY COLUMN `ident` VARCHAR(12) COLUMN_FORMAT FIXED FIRST\"},\n\n\t\t// // Test keyword `SERIAL`\n\t\t// {\"create table t (a serial);\", true, \"CREATE TABLE `t` (`a` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE KEY)\"},\n\t\t// {\"create table t (a serial null);\", true, \"CREATE TABLE `t` (`a` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE KEY NULL)\"},\n\t\t// {\"create table t (b int, a serial);\", true, \"CREATE TABLE `t` (`b` INT,`a` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE KEY)\"},\n\t\t// {\"create table t (a int serial default value);\", true, \"CREATE TABLE `t` (`a` INT NOT NULL AUTO_INCREMENT UNIQUE KEY)\"},\n\t\t// {\"create table t (a int serial default value null);\", true, \"CREATE TABLE `t` (`a` INT NOT NULL AUTO_INCREMENT UNIQUE KEY NULL)\"},\n\t\t// {\"create table t (a bigint serial default value);\", true, \"CREATE TABLE `t` (`a` BIGINT NOT NULL AUTO_INCREMENT UNIQUE KEY)\"},\n\t\t// {\"create table t (a smallint serial default value);\", true, \"CREATE TABLE `t` (`a` SMALLINT NOT NULL AUTO_INCREMENT UNIQUE KEY)\"},\n\n\t\t// for LONG syntax\n\t\t// {\"create table t (a long);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT)\"},\n\t\t// {\"create table t (a long varchar);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT)\"},\n\t\t// {\"create table t (a long varcharacter);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT)\"},\n\t\t// {\"create table t (a long char varying);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT)\"},\n\t\t// {\"create table t (a long character varying);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT)\"},\n\t\t// {\"create table t (a mediumtext, b long varchar, c long, d long varcharacter, e long char varying, f long character varying, g long);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT,`b` MEDIUMTEXT,`c` MEDIUMTEXT,`d` MEDIUMTEXT,`e` MEDIUMTEXT,`f` MEDIUMTEXT,`g` MEDIUMTEXT)\"},\n\t\t// {\"create table t (a long varbinary);\", true, \"CREATE TABLE `t` (`a` MEDIUMBLOB)\"},\n\t\t// {\"create table t (a long char varying, b long varbinary);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT,`b` MEDIUMBLOB)\"},\n\t\t// {\"create table t (a long char set utf8);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT CHARACTER SET UTF8)\"},\n\t\t// {\"create table t (a long char varying char set utf8);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT CHARACTER SET UTF8)\"},\n\t\t// {\"create table t (a long character set utf8);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT CHARACTER SET UTF8)\"},\n\t\t// {\"create table t (a long character varying character set utf8);\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT CHARACTER SET UTF8)\"},\n\t\t// {\"alter table d_n.t_n modify column ident long after ident remove partitioning\", true, \"ALTER TABLE `d_n`.`t_n` MODIFY COLUMN `ident` MEDIUMTEXT AFTER `ident` REMOVE PARTITIONING\"},\n\t\t// {\"alter table d_n.t_n modify column ident long char varying after ident remove partitioning\", true, \"ALTER TABLE `d_n`.`t_n` MODIFY COLUMN `ident` MEDIUMTEXT AFTER `ident` REMOVE PARTITIONING\"},\n\t\t// {\"alter table d_n.t_n modify column ident long character varying after ident remove partitioning\", true, \"ALTER TABLE `d_n`.`t_n` MODIFY COLUMN `ident` MEDIUMTEXT AFTER `ident` REMOVE PARTITIONING\"},\n\t\t// {\"alter table d_n.t_n modify column ident long varchar after ident remove partitioning\", true, \"ALTER TABLE `d_n`.`t_n` MODIFY COLUMN `ident` MEDIUMTEXT AFTER `ident` REMOVE PARTITIONING\"},\n\t\t// {\"alter table d_n.t_n modify column ident long varcharacter after ident remove partitioning\", true, \"ALTER TABLE `d_n`.`t_n` MODIFY COLUMN `ident` MEDIUMTEXT AFTER `ident` REMOVE PARTITIONING\"},\n\t\t// {\"alter table t_n change column ident ident long char varying binary charset utf8 first , tablespace ident\", true, \"ALTER TABLE `t_n` CHANGE COLUMN `ident` `ident` MEDIUMTEXT BINARY CHARACTER SET UTF8 FIRST, TABLESPACE = `ident`\"},\n\t\t// {\"alter table t_n change column ident ident long character varying binary charset utf8 first , tablespace ident\", true, \"ALTER TABLE `t_n` CHANGE COLUMN `ident` `ident` MEDIUMTEXT BINARY CHARACTER SET UTF8 FIRST, TABLESPACE = `ident`\"},\n\n\t\t// for STATS_AUTO_RECALC syntax\n\t\t{\"create table t (a int) stats_auto_recalc 2;\", false, \"\"},\n\t\t{\"create table t (a int) stats_auto_recalc = 10;\", false, \"\"},\n\t\t{\"create table t (a int) stats_auto_recalc 0;\", true, \"CREATE TABLE `t` (`a` INT) STATS_AUTO_RECALC = 0\"},\n\t\t{\"create table t (a int) stats_auto_recalc default;\", true, \"CREATE TABLE `t` (`a` INT) STATS_AUTO_RECALC = DEFAULT\"},\n\t\t{\"create table t (a int) stats_auto_recalc = 0;\", true, \"CREATE TABLE `t` (`a` INT) STATS_AUTO_RECALC = 0\"},\n\t\t{\"create table t (a int) stats_auto_recalc = 1;\", true, \"CREATE TABLE `t` (`a` INT) STATS_AUTO_RECALC = 1\"},\n\t\t{\"create table t (a int) stats_auto_recalc=default;\", true, \"CREATE TABLE `t` (`a` INT) STATS_AUTO_RECALC = DEFAULT\"},\n\t\t{\"create table t (a int) stats_persistent = 1, stats_auto_recalc = 1;\", true, \"CREATE TABLE `t` (`a` INT) STATS_PERSISTENT = DEFAULT /* TableOptionStatsPersistent is not supported */  STATS_AUTO_RECALC = 1\"},\n\t\t{\"create table t (a int) stats_auto_recalc = 1, stats_sample_pages = 25;\", true, \"CREATE TABLE `t` (`a` INT) STATS_AUTO_RECALC = 1 STATS_SAMPLE_PAGES = 25\"},\n\t\t// {\"alter table t modify a bigint, ENGINE=InnoDB, stats_auto_recalc = 0\", true, \"ALTER TABLE `t` MODIFY COLUMN `a` BIGINT, ENGINE = InnoDB, STATS_AUTO_RECALC = 0\"},\n\t\t{\"create table stats_auto_recalc (a int);\", true, \"CREATE TABLE `stats_auto_recalc` (`a` INT)\"},\n\t\t{\"create table stats_auto_recalc (a int) stats_auto_recalc=1;\", true, \"CREATE TABLE `stats_auto_recalc` (`a` INT) STATS_AUTO_RECALC = 1\"},\n\n\t\t// // for TYPE/USING syntax\n\t\t// {\"create table t (a int, primary key type type btree (a));\", true, \"CREATE TABLE `t` (`a` INT,PRIMARY KEY `type`(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, primary key type btree (a));\", false, \"\"},\n\t\t// {\"create table t (a int, primary key using btree (a));\", true, \"CREATE TABLE `t` (`a` INT,PRIMARY KEY(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, primary key (a) type btree);\", true, \"CREATE TABLE `t` (`a` INT,PRIMARY KEY(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, primary key (a) using btree);\", true, \"CREATE TABLE `t` (`a` INT,PRIMARY KEY(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, unique index type type btree (a));\", true, \"CREATE TABLE `t` (`a` INT,UNIQUE `type`(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, unique index type using btree (a));\", true, \"CREATE TABLE `t` (`a` INT,UNIQUE `type`(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, unique index type btree (a));\", false, \"\"},\n\t\t// {\"create table t (a int, unique index using btree (a));\", true, \"CREATE TABLE `t` (`a` INT,UNIQUE(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, unique index (a) using btree);\", true, \"CREATE TABLE `t` (`a` INT,UNIQUE(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, unique key (a) using btree);\", true, \"CREATE TABLE `t` (`a` INT,UNIQUE(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, index type type btree (a));\", true, \"CREATE TABLE `t` (`a` INT,INDEX `type`(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, index type btree (a));\", false, \"\"},\n\t\t// {\"create table t (a int, index type using btree (a));\", true, \"CREATE TABLE `t` (`a` INT,INDEX `type`(`a`) USING BTREE)\"},\n\t\t// {\"create table t (a int, index using btree (a));\", true, \"CREATE TABLE `t` (`a` INT,INDEX(`a`) USING BTREE)\"},\n\n\t\t// for issue 500\n\t\t{`ALTER TABLE d_n.t_n WITHOUT VALIDATION , ADD PARTITION ( PARTITION ident VALUES LESS THAN ( MAXVALUE ) STORAGE ENGINE text_string MAX_ROWS 12 )`, true, \"ALTER TABLE `d_n`.`t_n` WITHOUT VALIDATION, ADD PARTITION (PARTITION `ident` VALUES LESS THAN (MAXVALUE) ENGINE = text_string MAX_ROWS = 12)\"},\n\t\t{`ALTER TABLE d_n.t_n WITH VALIDATION , ADD PARTITION NO_WRITE_TO_BINLOG (PARTITION ident VALUES LESS THAN MAXVALUE STORAGE ENGINE = text_string, PARTITION ident VALUES LESS THAN ( MAXVALUE ) (SUBPARTITION text_string MIN_ROWS 11))`, true, \"ALTER TABLE `d_n`.`t_n` WITH VALIDATION, ADD PARTITION NO_WRITE_TO_BINLOG (PARTITION `ident` VALUES LESS THAN (MAXVALUE) ENGINE = text_string, PARTITION `ident` VALUES LESS THAN (MAXVALUE) (SUBPARTITION `text_string` MIN_ROWS = 11))\"},\n\t\t// for test VALUE IN\n\t\t{`ALTER TABLE d_n.t_n WITHOUT VALIDATION , ADD PARTITION ( PARTITION ident VALUES IN ( MAXVALUE ) STORAGE ENGINE text_string MAX_ROWS 12 )`, true, \"ALTER TABLE `d_n`.`t_n` WITHOUT VALIDATION, ADD PARTITION (PARTITION `ident` VALUES IN (MAXVALUE) ENGINE = text_string MAX_ROWS = 12)\"},\n\t\t{`ALTER TABLE d_n.t_n WITH VALIDATION , ADD PARTITION NO_WRITE_TO_BINLOG ( PARTITION ident VALUES IN ( MAXVALUE ) STORAGE ENGINE text_string MAX_ROWS 12 )`, true, \"ALTER TABLE `d_n`.`t_n` WITH VALIDATION, ADD PARTITION NO_WRITE_TO_BINLOG (PARTITION `ident` VALUES IN (MAXVALUE) ENGINE = text_string MAX_ROWS = 12)\"},\n\t\t{`ALTER TABLE d_n.t_n WITH VALIDATION , ADD PARTITION NO_WRITE_TO_BINLOG (PARTITION ident VALUES LESS THAN MAXVALUE STORAGE ENGINE = text_string, PARTITION ident VALUES IN ( MAXVALUE ) (SUBPARTITION text_string MIN_ROWS 11))`, true, \"ALTER TABLE `d_n`.`t_n` WITH VALIDATION, ADD PARTITION NO_WRITE_TO_BINLOG (PARTITION `ident` VALUES LESS THAN (MAXVALUE) ENGINE = text_string, PARTITION `ident` VALUES IN (MAXVALUE) (SUBPARTITION `text_string` MIN_ROWS = 11))\"},\n\t\t// for issue 501\n\t\t{\"ALTER TABLE t IMPORT TABLESPACE;\", true, \"ALTER TABLE `t` IMPORT TABLESPACE\"},\n\t\t{\"ALTER TABLE t DISCARD TABLESPACE;\", true, \"ALTER TABLE `t` DISCARD TABLESPACE\"},\n\t\t{\"ALTER TABLE db.t IMPORT TABLESPACE;\", true, \"ALTER TABLE `db`.`t` IMPORT TABLESPACE\"},\n\t\t{\"ALTER TABLE db.t DISCARD TABLESPACE;\", true, \"ALTER TABLE `db`.`t` DISCARD TABLESPACE\"},\n\n\t\t// for CONSTRAINT syntax, see issue 413\n\t\t// {\"ALTER TABLE t ADD ( CHECK ( true ) )\", true, \"ALTER TABLE `t` ADD COLUMN (CHECK(TRUE) ENFORCED)\"},\n\t\t// {\"ALTER TABLE t ADD ( CONSTRAINT CHECK ( true ) )\", true, \"ALTER TABLE `t` ADD COLUMN (CHECK(TRUE) ENFORCED)\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN ( CONSTRAINT ident CHECK ( 1>2 ) NOT ENFORCED )\", true, \"ALTER TABLE `t` ADD COLUMN (CONSTRAINT `ident` CHECK(1>2) NOT ENFORCED)\"},\n\t\t// {\"alter table t add column (b int, constraint c unique key (b))\", true, \"ALTER TABLE `t` ADD COLUMN (`b` INT, UNIQUE `c`(`b`))\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN ( CONSTRAINT CHECK ( true ) )\", true, \"ALTER TABLE `t` ADD COLUMN (CHECK(TRUE) ENFORCED)\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN ( CONSTRAINT CHECK ( true ) ENFORCED , CHECK ( true ) )\", true, \"ALTER TABLE `t` ADD COLUMN (CHECK(TRUE) ENFORCED, CHECK(TRUE) ENFORCED)\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN (a1 int, CONSTRAINT b1 CHECK (a1>0))\", true, \"ALTER TABLE `t` ADD COLUMN (`a1` INT, CONSTRAINT `b1` CHECK(`a1`>0) ENFORCED)\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN (a1 int, a2 int, CONSTRAINT b1 CHECK (a1>0), CONSTRAINT b2 CHECK (a2<10))\", true, \"ALTER TABLE `t` ADD COLUMN (`a1` INT, `a2` INT, CONSTRAINT `b1` CHECK(`a1`>0) ENFORCED, CONSTRAINT `b2` CHECK(`a2`<10) ENFORCED)\"},\n\t\t// {\"ALTER TABLE `t` ADD COLUMN (`a1` INT, PRIMARY KEY (`a1`))\", true, \"ALTER TABLE `t` ADD COLUMN (`a1` INT, PRIMARY KEY(`a1`))\"},\n\t\t// {\"ALTER TABLE t ADD (a1 int, CONSTRAINT PRIMARY KEY (a1))\", true, \"ALTER TABLE `t` ADD COLUMN (`a1` INT, PRIMARY KEY(`a1`))\"},\n\t\t// {\"ALTER TABLE t ADD (a1 int, a2 int, PRIMARY KEY (a1), UNIQUE (a2))\", true, \"ALTER TABLE `t` ADD COLUMN (`a1` INT, `a2` INT, PRIMARY KEY(`a1`), UNIQUE(`a2`))\"},\n\t\t// {\"ALTER TABLE t ADD (a1 int, a2 int, PRIMARY KEY (a1), CONSTRAINT b2 UNIQUE (a2))\", true, \"ALTER TABLE `t` ADD COLUMN (`a1` INT, `a2` INT, PRIMARY KEY(`a1`), UNIQUE `b2`(`a2`))\"},\n\t\t// {\"ALTER TABLE ident ADD ( CONSTRAINT FOREIGN KEY ident ( EXECUTE ( 123 ) ) REFERENCES t ( a ) MATCH SIMPLE ON DELETE CASCADE ON UPDATE SET NULL )\", true, \"ALTER TABLE `ident` ADD COLUMN (CONSTRAINT `ident` FOREIGN KEY (`EXECUTE`(123)) REFERENCES `t`(`a`) MATCH SIMPLE ON DELETE CASCADE ON UPDATE SET NULL)\"},\n\t\t// // for CONSTRAINT cont'd, the following tests are for another aspect of the incompatibility\n\t\t// {\"ALTER TABLE t ADD COLUMN a DATE CHECK ( a > 0 ) FIRST\", true, \"ALTER TABLE `t` ADD COLUMN `a` DATE CHECK(`a`>0) ENFORCED FIRST\"},\n\t\t// {\"ALTER TABLE t ADD a1 int CONSTRAINT ident CHECK ( a1 > 1 ) REFERENCES b ON DELETE CASCADE ON UPDATE CASCADE;\", true, \"ALTER TABLE `t` ADD COLUMN `a1` INT CHECK(`a1`>1) ENFORCED REFERENCES `b` ON DELETE CASCADE ON UPDATE CASCADE\"},\n\t\t// {\"ALTER TABLE t ADD COLUMN a DATE CONSTRAINT CHECK ( a > 0 ) FIRST\", true, \"ALTER TABLE `t` ADD COLUMN `a` DATE CHECK(`a`>0) ENFORCED FIRST\"},\n\t\t// {\"ALTER TABLE t ADD a TINYBLOB CONSTRAINT ident CHECK ( 1>2 ) REFERENCES b ON DELETE CASCADE ON UPDATE CASCADE\", true, \"ALTER TABLE `t` ADD COLUMN `a` TINYBLOB CHECK(1>2) ENFORCED REFERENCES `b` ON DELETE CASCADE ON UPDATE CASCADE\"},\n\t\t// {\"ALTER TABLE t ADD a2 int CONSTRAINT ident CHECK (a2 > 1) ENFORCED\", true, \"ALTER TABLE `t` ADD COLUMN `a2` INT CHECK(`a2`>1) ENFORCED\"},\n\t\t// {\"ALTER TABLE t ADD a2 int CONSTRAINT ident CHECK (a2 > 1) NOT ENFORCED\", true, \"ALTER TABLE `t` ADD COLUMN `a2` INT CHECK(`a2`>1) NOT ENFORCED\"},\n\t\t// {\"ALTER TABLE t ADD a2 int CONSTRAINT ident primary key REFERENCES b ON DELETE CASCADE ON UPDATE CASCADE;\", false, \"\"},\n\t\t// {\"ALTER TABLE t ADD a2 int CONSTRAINT ident primary key (a2))\", false, \"\"},\n\t\t// {\"ALTER TABLE t ADD a2 int CONSTRAINT ident unique key (a2))\", false, \"\"},\n\n\t\t// {\"ALTER TABLE t SET TIFLASH REPLICA 2 LOCATION LABELS 'a','b'\", true, \"ALTER TABLE `t` SET TIFLASH REPLICA 2 LOCATION LABELS 'a', 'b'\"},\n\t\t// {\"ALTER TABLE t SET TIFLASH REPLICA 0\", true, \"ALTER TABLE `t` SET TIFLASH REPLICA 0\"},\n\n\t\t// // for issue 537\n\t\t// {\"CREATE TABLE IF NOT EXISTS table_ident (a SQL_TSI_YEAR(4), b SQL_TSI_YEAR);\", true, \"CREATE TABLE IF NOT EXISTS `table_ident` (`a` YEAR(4),`b` YEAR)\"},\n\t\t// {`CREATE TABLE IF NOT EXISTS table_ident (ident1 BOOL COMMENT \"text_string\" unique, ident2 SQL_TSI_YEAR(4) ZEROFILL);`, true, \"CREATE TABLE IF NOT EXISTS `table_ident` (`ident1` TINYINT(1) COMMENT 'text_string' UNIQUE KEY,`ident2` YEAR(4))\"},\n\t\t// {\"create table t (y sql_tsi_year(4), y1 sql_tsi_year)\", true, \"CREATE TABLE `t` (`y` YEAR(4),`y1` YEAR)\"},\n\t\t// {\"create table t (y sql_tsi_year(4) unsigned zerofill zerofill, y1 sql_tsi_year signed unsigned zerofill)\", true, \"CREATE TABLE `t` (`y` YEAR(4),`y1` YEAR)\"},\n\n\t\t// for issue 549\n\t\t{\"insert into t set a = default\", true, \"INSERT INTO `t` SET `a`=DEFAULT\"},\n\t\t{\"replace t set a = default\", true, \"REPLACE INTO `t` SET `a`=DEFAULT\"},\n\t\t{\"update t set a = default\", true, \"UPDATE `t` SET `a`=DEFAULT\"},\n\t\t{\"insert into t set a = default on duplicate key update a = default\", true, \"INSERT INTO `t` SET `a`=DEFAULT ON DUPLICATE KEY UPDATE `a`=DEFAULT\"},\n\n\t\t// // for issue 529\n\t\t// {\"create table t (a text byte ascii)\", false, \"\"},\n\t\t// {\"create table t (a text byte charset latin1)\", false, \"\"},\n\t\t// {\"create table t (a longtext ascii)\", true, \"CREATE TABLE `t` (`a` LONGTEXT CHARACTER SET LATIN1)\"},\n\t\t// {\"create table t (a mediumtext ascii)\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT CHARACTER SET LATIN1)\"},\n\t\t// {\"create table t (a tinytext ascii)\", true, \"CREATE TABLE `t` (`a` TINYTEXT CHARACTER SET LATIN1)\"},\n\t\t// {\"create table t (a text byte)\", true, \"CREATE TABLE `t` (`a` TEXT)\"},\n\t\t// {\"create table t (a long byte, b text ascii)\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT,`b` TEXT CHARACTER SET LATIN1)\"},\n\t\t// {\"create table t (a text ascii, b mediumtext ascii, c int)\", true, \"CREATE TABLE `t` (`a` TEXT CHARACTER SET LATIN1,`b` MEDIUMTEXT CHARACTER SET LATIN1,`c` INT)\"},\n\t\t// {\"create table t (a int, b text ascii, c mediumtext ascii)\", true, \"CREATE TABLE `t` (`a` INT,`b` TEXT CHARACTER SET LATIN1,`c` MEDIUMTEXT CHARACTER SET LATIN1)\"},\n\t\t// {\"create table t (a long ascii, b long ascii)\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT CHARACTER SET LATIN1,`b` MEDIUMTEXT CHARACTER SET LATIN1)\"},\n\t\t// {\"create table t (a long character set utf8mb4, b long charset utf8mb4, c long char set utf8mb4)\", true, \"CREATE TABLE `t` (`a` MEDIUMTEXT CHARACTER SET UTF8MB4,`b` MEDIUMTEXT CHARACTER SET UTF8MB4,`c` MEDIUMTEXT CHARACTER SET UTF8MB4)\"},\n\n\t\t// {\"create table t (a int STORAGE MEMORY, b varchar(255) STORAGE MEMORY)\", true, \"CREATE TABLE `t` (`a` INT STORAGE MEMORY,`b` VARCHAR(255) STORAGE MEMORY)\"},\n\t\t// {\"create table t (a int storage DISK, b varchar(255) STORAGE DEFAULT)\", true, \"CREATE TABLE `t` (`a` INT STORAGE DISK,`b` VARCHAR(255) STORAGE DEFAULT)\"},\n\t\t// {\"create table t (a int STORAGE DEFAULT, b varchar(255) STORAGE DISK)\", true, \"CREATE TABLE `t` (`a` INT STORAGE DEFAULT,`b` VARCHAR(255) STORAGE DISK)\"},\n\n\t\t// // for issue 555\n\t\t// {\"create table t (a fixed(6, 3), b fixed key)\", true, \"CREATE TABLE `t` (`a` DECIMAL(6,3),`b` DECIMAL PRIMARY KEY)\"},\n\t\t// {\"create table t (a numeric, b fixed(6))\", true, \"CREATE TABLE `t` (`a` DECIMAL,`b` DECIMAL(6))\"},\n\t\t// {\"create table t (a fixed(65, 30) zerofill, b numeric, c fixed(65) unsigned zerofill)\", true, \"CREATE TABLE `t` (`a` DECIMAL(65,30) UNSIGNED ZEROFILL,`b` DECIMAL,`c` DECIMAL(65) UNSIGNED ZEROFILL)\"},\n\n\t\t// // create table with expression index\n\t\t// {\"create table a(a int, key(lower(a)));\", false, \"\"},\n\t\t// {\"create table a(a int, key(a+1));\", false, \"\"},\n\t\t// {\"create table a(a int, key(a, a+1));\", false, \"\"},\n\t\t// {\"create table a(a int, b int, key((a+1), (b+1)));\", true, \"CREATE TABLE `a` (`a` INT,`b` INT,INDEX((`a`+1), (`b`+1)))\"},\n\t\t// {\"create table a(a int, b int, key(a, (b+1)));\", true, \"CREATE TABLE `a` (`a` INT,`b` INT,INDEX(`a`, (`b`+1)))\"},\n\t\t// {\"create table a(a int, b int, key((a+1), b));\", true, \"CREATE TABLE `a` (`a` INT,`b` INT,INDEX((`a`+1), `b`))\"},\n\t\t// {\"create table a(a int, b int, key((a + 1) desc));\", true, \"CREATE TABLE `a` (`a` INT,`b` INT,INDEX((`a`+1)))\"},\n\n\t\t// for create sequence\n\t\t{\"create sequence sequence\", true, \"CREATE SEQUENCE `sequence`\"},\n\t\t{\"create sequence seq\", true, \"CREATE SEQUENCE `seq`\"},\n\t\t{\"create sequence if not exists seq\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq`\"},\n\t\t{\"create temporary sequence seq\", true, \"CREATE TEMPORARY SEQUENCE `seq`\"},\n\t\t{\"create temporary sequence seq\", true, \"CREATE TEMPORARY SEQUENCE `seq`\"},\n\t\t{\"create temporary sequence if not exists seq\", true, \"CREATE TEMPORARY SEQUENCE IF NOT EXISTS `seq`\"},\n\t\t{\"create temporary sequence if not exists seq\", true, \"CREATE TEMPORARY SEQUENCE IF NOT EXISTS `seq`\"},\n\t\t{\"create sequence if not exists seq increment\", false, \"\"},\n\t\t{\"create sequence if not exists seq increment 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` INCREMENT BY 1\"},\n\t\t{\"create sequence if not exists seq increment = 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` INCREMENT BY 1\"},\n\t\t{\"create sequence if not exists seq increment by 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` INCREMENT BY 1\"},\n\t\t{\"create sequence if not exists seq minvalue\", false, \"\"},\n\t\t{\"create sequence if not exists seq minvalue 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` MINVALUE 1\"},\n\t\t{\"create sequence if not exists seq minvalue = 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` MINVALUE 1\"},\n\t\t{\"create sequence if not exists seq no\", false, \"\"},\n\t\t{\"create sequence if not exists seq nominvalue\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` NO MINVALUE\"},\n\t\t{\"create sequence if not exists seq no minvalue\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` NO MINVALUE\"},\n\t\t{\"create sequence if not exists seq maxvalue\", false, \"\"},\n\t\t{\"create sequence if not exists seq maxvalue 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` MAXVALUE 1\"},\n\t\t{\"create sequence if not exists seq maxvalue = 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` MAXVALUE 1\"},\n\t\t{\"create sequence if not exists seq no\", false, \"\"},\n\t\t{\"create sequence if not exists seq nomaxvalue\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` NO MAXVALUE\"},\n\t\t{\"create sequence if not exists seq no maxvalue\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` NO MAXVALUE\"},\n\t\t{\"create sequence if not exists seq start\", false, \"\"},\n\t\t{\"create sequence if not exists seq start with\", false, \"\"},\n\t\t{\"create sequence if not exists seq start =\", false, \"\"},\n\t\t{\"create sequence if not exists seq start with\", false, \"\"},\n\t\t{\"create sequence if not exists seq start 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` START WITH 1\"},\n\t\t{\"create sequence if not exists seq start = 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` START WITH 1\"},\n\t\t{\"create sequence if not exists seq start with 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` START WITH 1\"},\n\t\t{\"create sequence if not exists seq cache\", false, \"\"},\n\t\t{\"create sequence if not exists seq cache 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` CACHE 1\"},\n\t\t{\"create sequence if not exists seq cache = 1\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` CACHE 1\"},\n\t\t{\"create sequence if not exists seq nocache\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` NOCACHE\"},\n\t\t{\"create sequence if not exists seq no cache\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` NOCACHE\"},\n\t\t{\"create sequence if not exists seq cycle\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` CYCLE\"},\n\t\t{\"create sequence if not exists seq nocycle\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` NOCYCLE\"},\n\t\t{\"create sequence if not exists seq no cycle\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` NOCYCLE\"},\n\t\t{\"create sequence if not exists seq order\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` ORDER\"},\n\t\t{\"create sequence if not exists seq noorder\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` NOORDER\"},\n\t\t{\"create sequence if not exists seq no order\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` NOORDER\"},\n\t\t{\"create sequence seq increment 1 start with 0 minvalue 0 maxvalue 1000\", true, \"CREATE SEQUENCE `seq` INCREMENT BY 1 START WITH 0 MINVALUE 0 MAXVALUE 1000\"},\n\t\t{\"create sequence seq increment 1 start with 0 minvalue 0 maxvalue 1000\", true, \"CREATE SEQUENCE `seq` INCREMENT BY 1 START WITH 0 MINVALUE 0 MAXVALUE 1000\"},\n\t\t// TODO : support or replace if need : care for it will conflict on temporary.\n\t\t{\"create temporary sequence seq increment 10 start with 0 minvalue 0 maxvalue 1000\", true, \"CREATE TEMPORARY SEQUENCE `seq` INCREMENT BY 10 START WITH 0 MINVALUE 0 MAXVALUE 1000\"},\n\t\t{\"create temporary sequence if not exists seq cache 1 increment 1 start with -1 minvalue 0 maxvalue 1000\", true, \"CREATE TEMPORARY SEQUENCE IF NOT EXISTS `seq` CACHE 1 INCREMENT BY 1 START WITH -1 MINVALUE 0 MAXVALUE 1000\"},\n\t\t{\"create temporary sequence sEq order start with 0 minvalue 0 maxvalue 1000\", true, \"CREATE TEMPORARY SEQUENCE `sEq` ORDER START WITH 0 MINVALUE 0 MAXVALUE 1000\"},\n\t\t{\"create sequence if not exists seq increment 1 start with 0 minvalue -2 maxvalue 1000\", true, \"CREATE SEQUENCE IF NOT EXISTS `seq` INCREMENT BY 1 START WITH 0 MINVALUE -2 MAXVALUE 1000\"},\n\t\t{\"create sequence seq increment -1 start with -1 minvalue -1 maxvalue -1000 cache = 10 nocycle noorder\", true, \"CREATE SEQUENCE `seq` INCREMENT BY -1 START WITH -1 MINVALUE -1 MAXVALUE -1000 CACHE 10 NOCYCLE NOORDER\"},\n\n\t\t// test sequence is not a reserved keyword\n\t\t{\"create table sequence (a int)\", true, \"CREATE TABLE `sequence` (`a` INT)\"},\n\t\t{\"create table t (sequence int)\", true, \"CREATE TABLE `t` (`sequence` INT)\"},\n\n\t\t// test drop sequence\n\t\t{\"drop sequence\", false, \"\"},\n\t\t{\"drop sequence seq\", true, \"DROP SEQUENCE `seq`\"},\n\t\t{\"drop sequence if exists seq\", true, \"DROP SEQUENCE IF EXISTS `seq`\"},\n\t\t{\"drop temporary sequence seq\", true, \"DROP TEMPORARY SEQUENCE `seq`\"},\n\t\t{\"drop temporary sequence if exists seq\", true, \"DROP TEMPORARY SEQUENCE IF EXISTS `seq`\"},\n\t\t{\"drop temporary sequence if exists seq, seq2, seq3\", true, \"DROP TEMPORARY SEQUENCE IF EXISTS `seq`, `seq2`, `seq3`\"},\n\t\t{\"drop sequence seq seq2\", false, \"\"},\n\t\t{\"drop sequence seq, seq2\", true, \"DROP SEQUENCE `seq`, `seq2`\"},\n\n\t\t// // for auto_random\n\t\t// {\"create table t (a bigint auto_random(3) primary key, b varchar(255))\", true, \"CREATE TABLE `t` (`a` BIGINT AUTO_RANDOM(3) PRIMARY KEY,`b` VARCHAR(255))\"},\n\t\t// {\"create table t (a bigint auto_random primary key, b varchar(255))\", true, \"CREATE TABLE `t` (`a` BIGINT AUTO_RANDOM PRIMARY KEY,`b` VARCHAR(255))\"},\n\t\t// {\"create table t (a bigint primary key auto_random(4), b varchar(255))\", true, \"CREATE TABLE `t` (`a` BIGINT PRIMARY KEY AUTO_RANDOM(4),`b` VARCHAR(255))\"},\n\t\t// {\"create table t (a bigint primary key auto_random(3) primary key unique, b varchar(255))\", true, \"CREATE TABLE `t` (`a` BIGINT PRIMARY KEY AUTO_RANDOM(3) PRIMARY KEY UNIQUE KEY,`b` VARCHAR(255))\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestHintError(c *C) {\n\tparser := parser.New()\n\tstmt, warns, err := parser.Parse(\"select /*+ tidb_unknown(T1,t2) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(len(warns), Equals, 1)\n\tc.Assert(warns[0], ErrorMatches, `.*Optimizer hint syntax error at line 1 column 23 near \"tidb_unknown\\(T1,t2\\) \\*/\" `)\n\tc.Assert(len(stmt[0].(*ast.SelectStmt).TableHints), Equals, 0)\n\tstmt, warns, err = parser.Parse(\"select /*+ TIDB_INLJ(t1, T2) tidb_unknow(T1,t2, 1) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(len(stmt[0].(*ast.SelectStmt).TableHints), Equals, 0)\n\tc.Assert(err, IsNil)\n\tc.Assert(len(warns), Equals, 1)\n\tc.Assert(warns[0], ErrorMatches, `.*Optimizer hint syntax error at line 1 column 40 near \"tidb_unknow\\(T1,t2, 1\\) \\*/\" `)\n\tstmt, _, err = parser.Parse(\"select c1, c2 from /*+ tidb_unknow(T1,t2) */ t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil) // Hints are ignored after the \"FROM\" keyword!\n\tstmt, _, err = parser.Parse(\"select1 /*+ TIDB_INLJ(t1, T2) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, NotNil)\n\tc.Assert(err.Error(), Equals, \"line 1 column 7 near \\\"select1 /*+ TIDB_INLJ(t1, T2) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\\\" \")\n\tstmt, _, err = parser.Parse(\"select /*+ TIDB_INLJ(t1, T2) */ c1, c2 fromt t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, NotNil)\n\tc.Assert(err.Error(), Equals, \"line 1 column 47 near \\\"t1, t2 where t1.c1 = t2.c1\\\" \")\n\t_, _, err = parser.Parse(\"SELECT 1 FROM DUAL WHERE 1 IN (SELECT /*+ DEBUG_HINT3 */ 1)\", \"\", \"\")\n\tc.Assert(err, IsNil)\n}\n\nfunc (s *testParserSuite) TestErrorMsg(c *C) {\n\tparser := parser.New()\n\t_, _, err := parser.Parse(\"select1 1\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"line 1 column 7 near \\\"select1 1\\\" \")\n\t_, _, err = parser.Parse(\"select 1 from1 dual\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"line 1 column 19 near \\\"dual\\\" \")\n\t_, _, err = parser.Parse(\"select * from t1 join t2 from t1.a = t2.a;\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"line 1 column 29 near \\\"from t1.a = t2.a;\\\" \")\n\t_, _, err = parser.Parse(\"select * from t1 join t2 one t1.a = t2.a;\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"line 1 column 31 near \\\"t1.a = t2.a;\\\" \")\n\t_, _, err = parser.Parse(\"select * from t1 join t2 on t1.a >>> t2.a;\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"line 1 column 36 near \\\"> t2.a;\\\" \")\n\n\t// _, _, err = parser.Parse(\"create table t(f_year year(5))ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;\", \"\", \"\")\n\t// c.Assert(err.Error(), Equals, \"[parser:1818]Supports only YEAR or YEAR(4) column\")\n\n\t_, _, err = parser.Parse(\"select ifnull(a,0) & ifnull(a,0) like '55' ESCAPE '\\\\\\\\a' from t;\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1210]Incorrect arguments to ESCAPE\")\n\n\t_, _, err = parser.Parse(\"load data infile 'aaa' into table aaa FIELDS  Enclosed by '\\\\\\\\b';\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1083]Field separator argument is not what is expected; check the manual\")\n\n\t_, _, err = parser.Parse(\"load data infile 'aaa' into table aaa FIELDS  Escaped by '\\\\\\\\b';\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1083]Field separator argument is not what is expected; check the manual\")\n\n\t_, _, err = parser.Parse(\"load data infile 'aaa' into table aaa FIELDS  Enclosed by '\\\\\\\\b' Escaped by '\\\\\\\\b' ;\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1083]Field separator argument is not what is expected; check the manual\")\n\n\t_, _, err = parser.Parse(\"ALTER DATABASE `` CHARACTER SET = ''\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1115]Unknown character set: ''\")\n\n\t_, _, err = parser.Parse(\"ALTER DATABASE t CHARACTER SET = ''\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1115]Unknown character set: ''\")\n\n\t_, _, err = parser.Parse(\"ALTER SCHEMA t CHARACTER SET = 'SOME_INVALID_CHARSET'\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1115]Unknown character set: 'SOME_INVALID_CHARSET'\")\n\n\t_, _, err = parser.Parse(\"ALTER DATABASE t COLLATE = ''\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[ddl:1273]Unknown collation: ''\")\n\n\t_, _, err = parser.Parse(\"ALTER SCHEMA t COLLATE = 'SOME_INVALID_COLLATION'\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[ddl:1273]Unknown collation: 'SOME_INVALID_COLLATION'\")\n\n\t_, _, err = parser.Parse(\"ALTER DATABASE CHARSET = 'utf8mb4' COLLATE = 'utf8_bin'\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"line 1 column 24 near \\\"= 'utf8mb4' COLLATE = 'utf8_bin'\\\" \")\n\n\t_, _, err = parser.Parse(\"ALTER DATABASE\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"line 1 column 14 near \\\"\\\" \")\n\n\t_, _, err = parser.Parse(\"ALTER SCHEMA `ANY_DB_NAME`\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"line 1 column 26 near \\\"\\\" \")\n\n\t_, _, err = parser.Parse(\"alter table t partition by range FIELDS(a)\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[ddl:1492]For RANGE partitions each partition must be defined\")\n\n\t_, _, err = parser.Parse(\"alter table t partition by list FIELDS(a)\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[ddl:1492]For LIST partitions each partition must be defined\")\n\n\t_, _, err = parser.Parse(\"alter table t partition by list FIELDS(a)\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[ddl:1492]For LIST partitions each partition must be defined\")\n\n\t_, _, err = parser.Parse(\"alter table t partition by list FIELDS(a,b,c)\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[ddl:1492]For LIST partitions each partition must be defined\")\n\n\t_, _, err = parser.Parse(\"alter table t lock = first\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1801]Unknown LOCK type 'first'\")\n\n\t_, _, err = parser.Parse(\"alter table t lock = start\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1801]Unknown LOCK type 'start'\")\n\n\t_, _, err = parser.Parse(\"alter table t lock = commit\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1801]Unknown LOCK type 'commit'\")\n\n\t_, _, err = parser.Parse(\"alter table t lock = binlog\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1801]Unknown LOCK type 'binlog'\")\n\n\t_, _, err = parser.Parse(\"alter table t lock = randomStr123\", \"\", \"\")\n\tc.Assert(err.Error(), Equals, \"[parser:1801]Unknown LOCK type 'randomStr123'\")\n\n\t// _, _, err = parser.Parse(\"create table t (a longtext unicode)\", \"\", \"\")\n\t// c.Assert(err.Error(), Equals, \"[parser:1115]Unknown character set: 'ucs2'\")\n\n\t// _, _, err = parser.Parse(\"create table t (a long byte, b text unicode)\", \"\", \"\")\n\t// c.Assert(err.Error(), Equals, \"[parser:1115]Unknown character set: 'ucs2'\")\n\n\t// _, _, err = parser.Parse(\"create table t (a long ascii, b long unicode)\", \"\", \"\")\n\t// c.Assert(err.Error(), Equals, \"[parser:1115]Unknown character set: 'ucs2'\")\n\n\t// _, _, err = parser.Parse(\"create table t (a text unicode, b mediumtext ascii, c int)\", \"\", \"\")\n\t// c.Assert(err.Error(), Equals, \"[parser:1115]Unknown character set: 'ucs2'\")\n}\n\nfunc (s *testParserSuite) TestOptimizerHints(c *C) {\n\tparser := parser.New()\n\t// Test USE_INDEX\n\tstmt, _, err := parser.Parse(\"select /*+ USE_INDEX(T1,T2), use_index(t3,t4) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt := stmt[0].(*ast.SelectStmt)\n\n\thints := selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"use_index\")\n\tc.Assert(hints[0].Tables, HasLen, 1)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Indexes, HasLen, 1)\n\tc.Assert(hints[0].Indexes[0].L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"use_index\")\n\tc.Assert(hints[1].Tables, HasLen, 1)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Indexes, HasLen, 1)\n\tc.Assert(hints[1].Indexes[0].L, Equals, \"t4\")\n\n\t// Test IGNORE_INDEX\n\tstmt, _, err = parser.Parse(\"select /*+ IGNORE_INDEX(T1,T2), ignore_index(t3,t4) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"ignore_index\")\n\tc.Assert(hints[0].Tables, HasLen, 1)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Indexes, HasLen, 1)\n\tc.Assert(hints[0].Indexes[0].L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"ignore_index\")\n\tc.Assert(hints[1].Tables, HasLen, 1)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Indexes, HasLen, 1)\n\tc.Assert(hints[1].Indexes[0].L, Equals, \"t4\")\n\n\t// Test TIDB_SMJ\n\tstmt, _, err = parser.Parse(\"select /*+ TIDB_SMJ(T1,t2), tidb_smj(T3,t4) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"tidb_smj\")\n\tc.Assert(hints[0].Tables, HasLen, 2)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Tables[1].TableName.L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"tidb_smj\")\n\tc.Assert(hints[1].Tables, HasLen, 2)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Tables[1].TableName.L, Equals, \"t4\")\n\n\t// Test SM_JOIN\n\tstmt, _, err = parser.Parse(\"select /*+ SM_JOIN(t1, T2), sm_join(t3, t4) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"sm_join\")\n\tc.Assert(hints[0].Tables, HasLen, 2)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Tables[1].TableName.L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"sm_join\")\n\tc.Assert(hints[1].Tables, HasLen, 2)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Tables[1].TableName.L, Equals, \"t4\")\n\n\t// Test TIDB_INLJ\n\tstmt, _, err = parser.Parse(\"select /*+ TIDB_INLJ(t1, T2), tidb_inlj(t3, t4) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"tidb_inlj\")\n\tc.Assert(hints[0].Tables, HasLen, 2)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Tables[1].TableName.L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"tidb_inlj\")\n\tc.Assert(hints[1].Tables, HasLen, 2)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Tables[1].TableName.L, Equals, \"t4\")\n\n\t// Test INL_JOIN\n\tstmt, _, err = parser.Parse(\"select /*+ INL_JOIN(t1, T2), inl_join(t3, t4) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"inl_join\")\n\tc.Assert(hints[0].Tables, HasLen, 2)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Tables[1].TableName.L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"inl_join\")\n\tc.Assert(hints[1].Tables, HasLen, 2)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Tables[1].TableName.L, Equals, \"t4\")\n\n\t// Test INL_HASH_JOIN\n\tstmt, _, err = parser.Parse(\"select /*+ INL_HASH_JOIN(t1, T2), inl_hash_join(t3, t4) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"inl_hash_join\")\n\tc.Assert(hints[0].Tables, HasLen, 2)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Tables[1].TableName.L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"inl_hash_join\")\n\tc.Assert(hints[1].Tables, HasLen, 2)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Tables[1].TableName.L, Equals, \"t4\")\n\n\t// Test INL_MERGE_JOIN\n\tstmt, _, err = parser.Parse(\"select /*+ INL_MERGE_JOIN(t1, T2), inl_merge_join(t3, t4) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"inl_merge_join\")\n\tc.Assert(hints[0].Tables, HasLen, 2)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Tables[1].TableName.L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"inl_merge_join\")\n\tc.Assert(hints[1].Tables, HasLen, 2)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Tables[1].TableName.L, Equals, \"t4\")\n\n\t// Test TIDB_HJ\n\tstmt, _, err = parser.Parse(\"select /*+ TIDB_HJ(t1, T2), tidb_hj(t3, t4) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"tidb_hj\")\n\tc.Assert(hints[0].Tables, HasLen, 2)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Tables[1].TableName.L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"tidb_hj\")\n\tc.Assert(hints[1].Tables, HasLen, 2)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Tables[1].TableName.L, Equals, \"t4\")\n\n\t// Test HASH_JOIN\n\tstmt, _, err = parser.Parse(\"select /*+ HASH_JOIN(t1, T2), hash_join(t3, t4) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"hash_join\")\n\tc.Assert(hints[0].Tables, HasLen, 2)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Tables[1].TableName.L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"hash_join\")\n\tc.Assert(hints[1].Tables, HasLen, 2)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Tables[1].TableName.L, Equals, \"t4\")\n\n\t// Test HASH_JOIN with SWAP_JOIN_INPUTS/NO_SWAP_JOIN_INPUTS\n\t// t1 for build, t4 for probe\n\tstmt, _, err = parser.Parse(\"select /*+ HASH_JOIN(t1, T2), hash_join(t3, t4), SWAP_JOIN_INPUTS(t1), NO_SWAP_JOIN_INPUTS(t4)  */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 4)\n\tc.Assert(hints[0].HintName.L, Equals, \"hash_join\")\n\tc.Assert(hints[0].Tables, HasLen, 2)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Tables[1].TableName.L, Equals, \"t2\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"hash_join\")\n\tc.Assert(hints[1].Tables, HasLen, 2)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[1].Tables[1].TableName.L, Equals, \"t4\")\n\n\tc.Assert(hints[2].HintName.L, Equals, \"swap_join_inputs\")\n\tc.Assert(hints[2].Tables, HasLen, 1)\n\tc.Assert(hints[2].Tables[0].TableName.L, Equals, \"t1\")\n\n\tc.Assert(hints[3].HintName.L, Equals, \"no_swap_join_inputs\")\n\tc.Assert(hints[3].Tables, HasLen, 1)\n\tc.Assert(hints[3].Tables[0].TableName.L, Equals, \"t4\")\n\n\t// Test MAX_EXECUTION_TIME\n\tqueries := []string{\n\t\t\"SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM t1 INNER JOIN t2 where t1.c1 = t2.c1\",\n\t\t\"SELECT /*+ MAX_EXECUTION_TIME(1000) */ 1\",\n\t\t\"SELECT /*+ MAX_EXECUTION_TIME(1000) */ SLEEP(20)\",\n\t\t\"SELECT /*+ MAX_EXECUTION_TIME(1000) */ 1 FROM DUAL\",\n\t}\n\tfor i, query := range queries {\n\t\tstmt, _, err = parser.Parse(query, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\t\tselectStmt = stmt[0].(*ast.SelectStmt)\n\t\thints = selectStmt.TableHints\n\t\tc.Assert(len(hints), Equals, 1)\n\t\tc.Assert(hints[0].HintName.L, Equals, \"max_execution_time\", Commentf(\"case\", i))\n\t\tc.Assert(hints[0].MaxExecutionTime, Equals, uint64(1000))\n\t}\n\n\t// Test USE_INDEX_MERGE\n\tstmt, _, err = parser.Parse(\"select /*+ USE_INDEX_MERGE(t1, c1), use_index_merge(t2, c1), use_index_merge(t3, c1, primary, c2) */ c1, c2 from t1, t2, t3 where t1.c1 = t2.c1 and t3.c2 = t1.c2\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 3)\n\tc.Assert(hints[0].HintName.L, Equals, \"use_index_merge\")\n\tc.Assert(hints[0].Tables, HasLen, 1)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Indexes, HasLen, 1)\n\tc.Assert(hints[0].Indexes[0].L, Equals, \"c1\")\n\n\tc.Assert(hints[1].HintName.L, Equals, \"use_index_merge\")\n\tc.Assert(hints[1].Tables, HasLen, 1)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t2\")\n\tc.Assert(hints[1].Indexes, HasLen, 1)\n\tc.Assert(hints[1].Indexes[0].L, Equals, \"c1\")\n\n\tc.Assert(hints[2].HintName.L, Equals, \"use_index_merge\")\n\tc.Assert(hints[2].Tables, HasLen, 1)\n\tc.Assert(hints[2].Tables[0].TableName.L, Equals, \"t3\")\n\tc.Assert(hints[2].Indexes, HasLen, 3)\n\tc.Assert(hints[2].Indexes[0].L, Equals, \"c1\")\n\tc.Assert(hints[2].Indexes[1].L, Equals, \"primary\")\n\tc.Assert(hints[2].Indexes[2].L, Equals, \"c2\")\n\n\t// Test READ_FROM_STORAGE\n\tstmt, _, err = parser.Parse(\"select /*+ READ_FROM_STORAGE(tiflash[t1, t2], tikv[t3]) */ c1, c2 from t1, t2, t1 t3 where t1.c1 = t2.c1 and t2.c1 = t3.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"read_from_storage\")\n\tc.Assert(hints[0].StoreType.L, Equals, \"tiflash\")\n\tc.Assert(hints[0].Tables, HasLen, 2)\n\tc.Assert(hints[0].Tables[0].TableName.L, Equals, \"t1\")\n\tc.Assert(hints[0].Tables[1].TableName.L, Equals, \"t2\")\n\tc.Assert(hints[1].HintName.L, Equals, \"read_from_storage\")\n\tc.Assert(hints[1].StoreType.L, Equals, \"tikv\")\n\tc.Assert(hints[1].Tables, HasLen, 1)\n\tc.Assert(hints[1].Tables[0].TableName.L, Equals, \"t3\")\n\n\t// Test USE_TOJA\n\tstmt, _, err = parser.Parse(\"select /*+ USE_TOJA(true), use_toja(false) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"use_toja\")\n\tc.Assert(hints[0].HintFlag, IsTrue)\n\n\tc.Assert(hints[1].HintName.L, Equals, \"use_toja\")\n\tc.Assert(hints[1].HintFlag, IsFalse)\n\n\t// Test ENABLE_PLAN_CACHE\n\tstmt, _, err = parser.Parse(\"select /*+ ENABLE_PLAN_CACHE(true), enable_plan_cache(false) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"enable_plan_cache\")\n\tc.Assert(hints[0].HintFlag, IsTrue)\n\n\tc.Assert(hints[1].HintName.L, Equals, \"enable_plan_cache\")\n\tc.Assert(hints[1].HintFlag, IsFalse)\n\n\t// Test USE_PLAN_CACHE\n\tstmt, _, err = parser.Parse(\"select /*+ USE_PLAN_CACHE(), use_plan_cache() */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"use_plan_cache\")\n\tc.Assert(hints[1].HintName.L, Equals, \"use_plan_cache\")\n\n\t// Test QUERY_TYPE\n\tstmt, _, err = parser.Parse(\"select /*+ QUERY_TYPE(OLAP), query_type(OLTP) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"query_type\")\n\tc.Assert(hints[0].QueryType.L, Equals, \"olap\")\n\tc.Assert(hints[1].HintName.L, Equals, \"query_type\")\n\tc.Assert(hints[1].QueryType.L, Equals, \"oltp\")\n\n\t// Test MEMORY_QUOTA\n\tstmt, _, err = parser.Parse(\"select /*+ MEMORY_QUOTA(1 MB), memory_quota(1 GB) */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"memory_quota\")\n\tc.Assert(hints[0].MemoryQuota, Equals, int64(1024*1024))\n\tc.Assert(hints[1].HintName.L, Equals, \"memory_quota\")\n\tc.Assert(hints[1].MemoryQuota, Equals, int64(1024*1024*1024))\n\n\tstmt, _, err = parser.Parse(\"select /*+ MEMORY_QUOTA(18446744073709551612 MB), memory_quota(8689934592 GB) */ 1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\n\t// Test HASH_AGG\n\tstmt, _, err = parser.Parse(\"select /*+ HASH_AGG(), hash_agg() */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"hash_agg\")\n\tc.Assert(hints[1].HintName.L, Equals, \"hash_agg\")\n\n\t// Test STREAM_AGG\n\tstmt, _, err = parser.Parse(\"select /*+ STREAM_AGG(), stream_agg() */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"stream_agg\")\n\tc.Assert(hints[1].HintName.L, Equals, \"stream_agg\")\n\n\t// Test AGG_TO_COP\n\tstmt, _, err = parser.Parse(\"select /*+ AGG_TO_COP(), agg_to_cop() */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"agg_to_cop\")\n\tc.Assert(hints[1].HintName.L, Equals, \"agg_to_cop\")\n\n\t// Test NO_INDEX_MERGE\n\tstmt, _, err = parser.Parse(\"select /*+ NO_INDEX_MERGE(), no_index_merge() */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"no_index_merge\")\n\tc.Assert(hints[1].HintName.L, Equals, \"no_index_merge\")\n\n\t// Test READ_CONSISTENT_REPLICA\n\tstmt, _, err = parser.Parse(\"select /*+ READ_CONSISTENT_REPLICA(), read_consistent_replica() */ c1, c2 from t1, t2 where t1.c1 = t2.c1\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tselectStmt = stmt[0].(*ast.SelectStmt)\n\n\thints = selectStmt.TableHints\n\tc.Assert(hints, HasLen, 2)\n\tc.Assert(hints[0].HintName.L, Equals, \"read_consistent_replica\")\n\tc.Assert(hints[1].HintName.L, Equals, \"read_consistent_replica\")\n}\n\nfunc (s *testParserSuite) TestType(c *C) {\n\ttable := []testCase{\n\t\t// // for time fsp\n\t\t// {\"CREATE TABLE t( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) );\", true, \"CREATE TABLE `t` (`c1` TIME(2),`c2` DATETIME(2),`c3` TIMESTAMP(2))\"},\n\n\t\t// for hexadecimal\n\t\t{\"select x'0a', X'11', 0x11\", true, \"SELECT x'0a',x'11',x'11'\"},\n\t\t{\"select x'13181C76734725455A'\", true, \"SELECT x'13181c76734725455a'\"},\n\t\t{\"select x'0xaa'\", false, \"\"},\n\t\t{\"select 0X11\", false, \"\"},\n\t\t{\"select 0x4920616D2061206C6F6E672068657820737472696E67\", true, \"SELECT x'4920616d2061206c6f6e672068657820737472696e67'\"},\n\n\t\t// for bit\n\t\t{\"select 0b01, 0b0, b'11', B'11'\", true, \"SELECT b'1',b'0',b'11',b'11'\"},\n\t\t// 0B01 and 0b21 are identifiers, the following two statement could parse.\n\t\t// {\"select 0B01\", false, \"\"},\n\t\t// {\"select 0b21\", false, \"\"},\n\n\t\t// // for enum and set type\n\t\t// {\"create table t (c1 enum('a', 'b'), c2 set('a', 'b'))\", true, \"CREATE TABLE `t` (`c1` ENUM('a','b'),`c2` SET('a','b'))\"},\n\t\t// {\"create table t (c1 enum)\", false, \"\"},\n\t\t// {\"create table t (c1 set)\", false, \"\"},\n\n\t\t// // for blob and text field length\n\t\t// {\"create table t (c1 blob(1024), c2 text(1024))\", true, \"CREATE TABLE `t` (`c1` BLOB(1024),`c2` TEXT(1024))\"},\n\n\t\t// // for year\n\t\t// {\"create table t (y year(4), y1 year)\", true, \"CREATE TABLE `t` (`y` YEAR(4),`y1` YEAR)\"},\n\t\t// {\"create table t (y year(4) unsigned zerofill zerofill, y1 year signed unsigned zerofill)\", true, \"CREATE TABLE `t` (`y` YEAR(4),`y1` YEAR)\"},\n\n\t\t// // for national\n\t\t// {\"create table t (c1 national char(2), c2 national varchar(2))\", true, \"CREATE TABLE `t` (`c1` CHAR(2),`c2` VARCHAR(2))\"},\n\n\t\t// // for json type\n\t\t// {`create table t (a JSON);`, true, \"CREATE TABLE `t` (`a` JSON)\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestPrivilege(c *C) {\n\ttable := []testCase{\n\t\t// for create user\n\t\t{`CREATE USER 'ttt' REQUIRE X509;`, true, \"CREATE USER `ttt`@`%` REQUIRE X509\"},\n\t\t{`CREATE USER 'ttt' REQUIRE SSL;`, true, \"CREATE USER `ttt`@`%` REQUIRE SSL\"},\n\t\t{`CREATE USER 'ttt' REQUIRE NONE;`, true, \"CREATE USER `ttt`@`%` REQUIRE NONE\"},\n\t\t{`CREATE USER 'ttt' REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/O=MySQL/CN=CA/emailAddress=ca@example.com' AND CIPHER 'EDH-RSA-DES-CBC3-SHA';`, true, \"CREATE USER `ttt`@`%` REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/O=MySQL/CN=CA/emailAddress=ca@example.com' AND CIPHER 'EDH-RSA-DES-CBC3-SHA'\"},\n\t\t{`CREATE USER 'ttt' REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/O=MySQL/CN=CA/emailAddress=ca@example.com' CIPHER 'EDH-RSA-DES-CBC3-SHA' SUBJECT '/C=SE/ST=Stockholm/L=Stockholm/O=MySQL/CN=CA/emailAddress=ca@example.com';`, true, \"CREATE USER `ttt`@`%` REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/O=MySQL/CN=CA/emailAddress=ca@example.com' AND CIPHER 'EDH-RSA-DES-CBC3-SHA' AND SUBJECT '/C=SE/ST=Stockholm/L=Stockholm/O=MySQL/CN=CA/emailAddress=ca@example.com'\"},\n\t\t// {`CREATE USER 'ttt' WITH MAX_QUERIES_PER_HOUR 2;`, true, \"CREATE USER `ttt`@`%` WITH MAX_QUERIES_PER_HOUR 2\"},\n\t\t// {`CREATE USER 'ttt'@'localhost' REQUIRE NONE WITH MAX_QUERIES_PER_HOUR 1 MAX_UPDATES_PER_HOUR 10 PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK;`, true, \"CREATE USER `ttt`@`localhost` REQUIRE NONE WITH MAX_QUERIES_PER_HOUR 1 MAX_UPDATES_PER_HOUR 10 PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK\"},\n\t\t// {`CREATE USER 'u1'@'%' IDENTIFIED WITH 'mysql_native_password' AS '' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK ;`, true, \"CREATE USER `u1`@`%` IDENTIFIED BY PASSWORD '' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK\"},\n\t\t{`CREATE USER 'test'`, true, \"CREATE USER `test`@`%`\"},\n\t\t{`CREATE USER test`, true, \"CREATE USER `test`@`%`\"},\n\t\t{\"CREATE USER `test`\", true, \"CREATE USER `test`@`%`\"},\n\t\t{\"CREATE USER test-user\", false, \"\"},\n\t\t{\"CREATE USER test.user\", false, \"\"},\n\t\t{\"CREATE USER 'test-user'\", true, \"CREATE USER `test-user`@`%`\"},\n\t\t{\"CREATE USER `test-user`\", true, \"CREATE USER `test-user`@`%`\"},\n\t\t{\"CREATE USER test.user\", false, \"\"},\n\t\t{\"CREATE USER 'test.user'\", true, \"CREATE USER `test.user`@`%`\"},\n\t\t{\"CREATE USER `test.user`\", true, \"CREATE USER `test.user`@`%`\"},\n\t\t{\"CREATE USER uesr1@localhost\", true, \"CREATE USER `uesr1`@`localhost`\"},\n\t\t{\"CREATE USER `uesr1`@localhost\", true, \"CREATE USER `uesr1`@`localhost`\"},\n\t\t{\"CREATE USER uesr1@`localhost`\", true, \"CREATE USER `uesr1`@`localhost`\"},\n\t\t{\"CREATE USER `uesr1`@`localhost`\", true, \"CREATE USER `uesr1`@`localhost`\"},\n\t\t{\"CREATE USER 'uesr1'@localhost\", true, \"CREATE USER `uesr1`@`localhost`\"},\n\t\t{\"CREATE USER uesr1@'localhost'\", true, \"CREATE USER `uesr1`@`localhost`\"},\n\t\t{\"CREATE USER 'uesr1'@'localhost'\", true, \"CREATE USER `uesr1`@`localhost`\"},\n\t\t{\"CREATE USER 'uesr1'@`localhost`\", true, \"CREATE USER `uesr1`@`localhost`\"},\n\t\t{\"CREATE USER `uesr1`@'localhost'\", true, \"CREATE USER `uesr1`@`localhost`\"},\n\t\t// {\"create user 'test@localhost' password expire;\", true, \"CREATE USER `test@localhost`@`%` PASSWORD EXPIRE\"},\n\t\t// {\"create user 'test@localhost' password expire never;\", true, \"CREATE USER `test@localhost`@`%` PASSWORD EXPIRE NEVER\"},\n\t\t// {\"create user 'test@localhost' password expire default;\", true, \"CREATE USER `test@localhost`@`%` PASSWORD EXPIRE DEFAULT\"},\n\t\t// {\"create user 'test@localhost' password expire interval 3 day;\", true, \"CREATE USER `test@localhost`@`%` PASSWORD EXPIRE INTERVAL 3 DAY\"},\n\t\t{\"CREATE ROLE `test-role`, `role1`@'localhost'\", true, \"CREATE ROLE `test-role`@`%`, `role1`@`localhost`\"},\n\t\t{\"CREATE ROLE `test-role`\", true, \"CREATE ROLE `test-role`@`%`\"},\n\t\t{\"CREATE ROLE role1\", true, \"CREATE ROLE `role1`@`%`\"},\n\t\t{\"CREATE ROLE `role1`@'localhost'\", true, \"CREATE ROLE `role1`@`localhost`\"},\n\t\t{\"create user 'bug19354014user'@'%' identified WITH mysql_native_password\", true, \"CREATE USER `bug19354014user`@`%`\"},\n\t\t{\"create user 'bug19354014user'@'%' identified WITH mysql_native_password by 'new-password'\", true, \"CREATE USER `bug19354014user`@`%` IDENTIFIED BY 'new-password'\"},\n\t\t{\"create user 'bug19354014user'@'%' PARTY_CODE 'party1' identified WITH mysql_native_password by 'new-password'\", true, \"CREATE USER `bug19354014user`@`%` PARTY_CODE 'party1' IDENTIFIED BY 'new-password'\"},\n\t\t{\"create user 'bug19354014user'@'%' identified WITH mysql_native_password as 'hashstring'\", true, \"CREATE USER `bug19354014user`@`%` IDENTIFIED BY PASSWORD 'hashstring'\"},\n\t\t{`CREATE USER IF NOT EXISTS 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, \"CREATE USER IF NOT EXISTS `root`@`localhost` IDENTIFIED BY 'new-password'\"},\n\t\t{`CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, \"CREATE USER `root`@`localhost` IDENTIFIED BY 'new-password'\"},\n\t\t{`CREATE USER 'root'@'localhost' IDENTIFIED BY PASSWORD 'hashstring'`, true, \"CREATE USER `root`@`localhost` IDENTIFIED BY PASSWORD 'hashstring'\"},\n\t\t{`CREATE USER 'root'@'localhost' IDENTIFIED BY 'new-password', 'root'@'127.0.0.1' IDENTIFIED BY PASSWORD 'hashstring'`, true, \"CREATE USER `root`@`localhost` IDENTIFIED BY 'new-password', `root`@`127.0.0.1` IDENTIFIED BY PASSWORD 'hashstring'\"},\n\t\t{`ALTER USER IF EXISTS 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, \"ALTER USER IF EXISTS `root`@`localhost` IDENTIFIED BY 'new-password'\"},\n\t\t{`ALTER USER 'root'@'localhost' IDENTIFIED BY 'new-password'`, true, \"ALTER USER `root`@`localhost` IDENTIFIED BY 'new-password'\"},\n\t\t{`ALTER USER 'root'@'localhost' IDENTIFIED BY PASSWORD 'hashstring'`, true, \"ALTER USER `root`@`localhost` IDENTIFIED BY PASSWORD 'hashstring'\"},\n\t\t{`ALTER USER 'root'@'localhost' IDENTIFIED BY 'new-password', 'root'@'127.0.0.1' IDENTIFIED BY PASSWORD 'hashstring'`, true, \"ALTER USER `root`@`localhost` IDENTIFIED BY 'new-password', `root`@`127.0.0.1` IDENTIFIED BY PASSWORD 'hashstring'\"},\n\t\t{`ALTER USER USER() IDENTIFIED BY 'new-password'`, true, \"ALTER USER USER() IDENTIFIED BY 'new-password'\"},\n\t\t{`ALTER USER IF EXISTS USER() IDENTIFIED BY 'new-password'`, true, \"ALTER USER IF EXISTS USER() IDENTIFIED BY 'new-password'\"},\n\t\t// {\"alter user 'test@localhost' password expire;\", true, \"ALTER USER `test@localhost`@`%` PASSWORD EXPIRE\"},\n\t\t// {\"alter user 'test@localhost' password expire never;\", true, \"ALTER USER `test@localhost`@`%` PASSWORD EXPIRE NEVER\"},\n\t\t// {\"alter user 'test@localhost' password expire default;\", true, \"ALTER USER `test@localhost`@`%` PASSWORD EXPIRE DEFAULT\"},\n\t\t// {\"alter user 'test@localhost' password expire interval 3 day;\", true, \"ALTER USER `test@localhost`@`%` PASSWORD EXPIRE INTERVAL 3 DAY\"},\n\t\t{\"ALTER USER 'ttt' REQUIRE X509;\", true, \"ALTER USER `ttt`@`%` REQUIRE X509\"},\n\t\t{\"ALTER USER 'ttt' REQUIRE SSL;\", true, \"ALTER USER `ttt`@`%` REQUIRE SSL\"},\n\t\t{\"ALTER USER 'ttt' REQUIRE NONE;\", true, \"ALTER USER `ttt`@`%` REQUIRE NONE\"},\n\t\t{\"ALTER USER 'ttt' REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/O=MySQL/CN=CA/emailAddress=ca@example.com' AND CIPHER 'EDH-RSA-DES-CBC3-SHA';\", true, \"ALTER USER `ttt`@`%` REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/O=MySQL/CN=CA/emailAddress=ca@example.com' AND CIPHER 'EDH-RSA-DES-CBC3-SHA'\"},\n\t\t// {\"ALTER USER 'ttt' WITH MAX_QUERIES_PER_HOUR 2;\", true, \"ALTER USER `ttt`@`%` WITH MAX_QUERIES_PER_HOUR 2\"},\n\t\t// {\"ALTER USER 'ttt' WITH MAX_UPDATES_PER_HOUR 2;\", true, \"ALTER USER `ttt`@`%` WITH MAX_UPDATES_PER_HOUR 2\"},\n\t\t// {\"ALTER USER 'ttt' WITH MAX_CONNECTIONS_PER_HOUR 2;\", true, \"ALTER USER `ttt`@`%` WITH MAX_CONNECTIONS_PER_HOUR 2\"},\n\t\t// {\"ALTER USER 'ttt' WITH MAX_USER_CONNECTIONS 2;\", true, \"ALTER USER `ttt`@`%` WITH MAX_USER_CONNECTIONS 2\"},\n\t\t// {\"ALTER USER 'ttt'@'localhost' REQUIRE NONE WITH MAX_QUERIES_PER_HOUR 1 MAX_UPDATES_PER_HOUR 10 PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK;\", true, \"ALTER USER `ttt`@`localhost` REQUIRE NONE WITH MAX_QUERIES_PER_HOUR 1 MAX_UPDATES_PER_HOUR 10 PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK\"},\n\t\t{`DROP USER 'root'@'localhost', 'root1'@'localhost'`, true, \"DROP USER `root`@`localhost`, `root1`@`localhost`\"},\n\t\t{`DROP USER IF EXISTS 'root'@'localhost'`, true, \"DROP USER IF EXISTS `root`@`localhost`\"},\n\t\t{`DROP ROLE 'role'@'localhost', 'role1'@'localhost'`, true, \"DROP ROLE `role`@`localhost`, `role1`@`localhost`\"},\n\t\t{`DROP ROLE 'administrator', 'developer';`, true, \"DROP ROLE `administrator`@`%`, `developer`@`%`\"},\n\t\t{`DROP ROLE IF EXISTS 'role'@'localhost'`, true, \"DROP ROLE IF EXISTS `role`@`localhost`\"},\n\n\t\t// for grant statement\n\t\t{\"GRANT ALL ON db1.* TO 'jeffrey'@'localhost' REQUIRE X509;\", true, \"GRANT ALL ON `db1`.* TO `jeffrey`@`localhost` REQUIRE X509\"},\n\t\t{\"GRANT ALL ON db1.* TO 'jeffrey'@'localhost' REQUIRE SSL;\", true, \"GRANT ALL ON `db1`.* TO `jeffrey`@`localhost` REQUIRE SSL\"},\n\t\t{\"GRANT ALL ON db1.* TO 'jeffrey'@'localhost' REQUIRE NONE;\", true, \"GRANT ALL ON `db1`.* TO `jeffrey`@`localhost` REQUIRE NONE\"},\n\t\t{\"GRANT ALL ON db1.* TO 'jeffrey'@'localhost' REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/O=MySQL/CN=CA/emailAddress=ca@example.com' AND CIPHER 'EDH-RSA-DES-CBC3-SHA';\", true, \"GRANT ALL ON `db1`.* TO `jeffrey`@`localhost` REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/O=MySQL/CN=CA/emailAddress=ca@example.com' AND CIPHER 'EDH-RSA-DES-CBC3-SHA'\"},\n\t\t{\"GRANT ALL ON db1.* TO 'jeffrey'@'localhost';\", true, \"GRANT ALL ON `db1`.* TO `jeffrey`@`localhost`\"},\n\t\t{\"GRANT ALL ON TABLE db1.* TO 'jeffrey'@'localhost';\", true, \"GRANT ALL ON TABLE `db1`.* TO `jeffrey`@`localhost`\"},\n\t\t{\"GRANT ALL ON db1.* TO 'jeffrey'@'localhost' WITH GRANT OPTION;\", true, \"GRANT ALL ON `db1`.* TO `jeffrey`@`localhost` WITH GRANT OPTION\"},\n\t\t{\"GRANT SELECT ON db2.invoice TO 'jeffrey'@'localhost';\", true, \"GRANT SELECT ON `db2`.`invoice` TO `jeffrey`@`localhost`\"},\n\t\t{\"GRANT ALL ON *.* TO 'someuser'@'somehost';\", true, \"GRANT ALL ON *.* TO `someuser`@`somehost`\"},\n\t\t{\"GRANT SELECT, INSERT ON *.* TO 'someuser'@'somehost';\", true, \"GRANT SELECT, INSERT ON *.* TO `someuser`@`somehost`\"},\n\t\t{\"GRANT ALL ON mydb.* TO 'someuser'@'somehost';\", true, \"GRANT ALL ON `mydb`.* TO `someuser`@`somehost`\"},\n\t\t{\"GRANT SELECT, INSERT ON mydb.* TO 'someuser'@'somehost';\", true, \"GRANT SELECT, INSERT ON `mydb`.* TO `someuser`@`somehost`\"},\n\t\t{\"GRANT ALL ON mydb.mytbl TO 'someuser'@'somehost';\", true, \"GRANT ALL ON `mydb`.`mytbl` TO `someuser`@`somehost`\"},\n\t\t{\"GRANT SELECT, INSERT ON mydb.mytbl TO 'someuser'@'somehost';\", true, \"GRANT SELECT, INSERT ON `mydb`.`mytbl` TO `someuser`@`somehost`\"},\n\t\t{\"GRANT SELECT (col1), INSERT (col1,col2) ON mydb.mytbl TO 'someuser'@'somehost';\", true, \"GRANT SELECT (`col1`), INSERT (`col1`,`col2`) ON `mydb`.`mytbl` TO `someuser`@`somehost`\"},\n\t\t{\"grant all privileges on zabbix.* to 'zabbix'@'localhost' identified by 'password';\", true, \"GRANT ALL ON `zabbix`.* TO `zabbix`@`localhost` IDENTIFIED BY 'password'\"},\n\t\t{\"GRANT SELECT ON test.* to 'test'\", true, \"GRANT SELECT ON `test`.* TO `test`@`%`\"}, // For issue 2654.\n\t\t{\"grant PROCESS,usage, REPLICATION SLAVE, REPLICATION CLIENT on *.* to 'xxxxxxxxxx'@'%' identified by password 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'\", true, \"GRANT PROCESS /* UNSUPPORTED TYPE */ /* UNSUPPORTED TYPE */ /* UNSUPPORTED TYPE */ ON *.* TO `xxxxxxxxxx`@`%` IDENTIFIED BY PASSWORD 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'\"}, // For issue 4865\n\t\t{\"/* rds internal mark */ GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, RELOAD, PROCESS, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES,      EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT,      TRIGGER on *.* to 'root2'@'%' identified by password '*sdsadsdsadssadsadsadsadsada' with grant option\", true, \"GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, RELOAD, PROCESS, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE /* UNSUPPORTED TYPE */ /* UNSUPPORTED TYPE */, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER ON *.* TO `root2`@`%` IDENTIFIED BY PASSWORD '*sdsadsdsadssadsadsadsadsada' WITH GRANT OPTION\"},\n\t\t{\"GRANT 'role1', 'role2' TO 'user1'@'localhost', 'user2'@'localhost';\", true, \"GRANT `role1`@`%`, `role2`@`%` TO `user1`@`localhost`, `user2`@`localhost`\"},\n\t\t{\"GRANT 'u1' TO 'u1';\", true, \"GRANT `u1`@`%` TO `u1`@`%`\"},\n\t\t{\"GRANT 'app_developer' TO 'dev1'@'localhost';\", true, \"GRANT `app_developer`@`%` TO `dev1`@`localhost`\"},\n\t\t{\"GRANT SHUTDOWN ON *.* TO 'dev1'@'localhost';\", true, \"GRANT SHUTDOWN ON *.* TO `dev1`@`localhost`\"},\n\n\t\t// for revoke statement\n\t\t{\"REVOKE ALL ON db1.* FROM 'jeffrey'@'localhost';\", true, \"REVOKE ALL ON `db1`.* FROM `jeffrey`@`localhost`\"},\n\t\t{\"REVOKE SELECT ON db2.invoice FROM 'jeffrey'@'localhost';\", true, \"REVOKE SELECT ON `db2`.`invoice` FROM `jeffrey`@`localhost`\"},\n\t\t{\"REVOKE ALL ON *.* FROM 'someuser'@'somehost';\", true, \"REVOKE ALL ON *.* FROM `someuser`@`somehost`\"},\n\t\t{\"REVOKE SELECT, INSERT ON *.* FROM 'someuser'@'somehost';\", true, \"REVOKE SELECT, INSERT ON *.* FROM `someuser`@`somehost`\"},\n\t\t{\"REVOKE ALL ON mydb.* FROM 'someuser'@'somehost';\", true, \"REVOKE ALL ON `mydb`.* FROM `someuser`@`somehost`\"},\n\t\t{\"REVOKE SELECT, INSERT ON mydb.* FROM 'someuser'@'somehost';\", true, \"REVOKE SELECT, INSERT ON `mydb`.* FROM `someuser`@`somehost`\"},\n\t\t{\"REVOKE ALL ON mydb.mytbl FROM 'someuser'@'somehost';\", true, \"REVOKE ALL ON `mydb`.`mytbl` FROM `someuser`@`somehost`\"},\n\t\t{\"REVOKE SELECT, INSERT ON mydb.mytbl FROM 'someuser'@'somehost';\", true, \"REVOKE SELECT, INSERT ON `mydb`.`mytbl` FROM `someuser`@`somehost`\"},\n\t\t{\"REVOKE SELECT (col1), INSERT (col1,col2) ON mydb.mytbl FROM 'someuser'@'somehost';\", true, \"REVOKE SELECT (`col1`), INSERT (`col1`,`col2`) ON `mydb`.`mytbl` FROM `someuser`@`somehost`\"},\n\t\t{\"REVOKE all privileges on zabbix.* FROM 'zabbix'@'localhost' identified by 'password';\", true, \"REVOKE ALL ON `zabbix`.* FROM `zabbix`@`localhost` IDENTIFIED BY 'password'\"},\n\t\t{\"REVOKE 'role1', 'role2' FROM 'user1'@'localhost', 'user2'@'localhost';\", true, \"REVOKE `role1`@`%`, `role2`@`%` FROM `user1`@`localhost`, `user2`@`localhost`\"},\n\t\t{\"REVOKE SHUTDOWN ON *.* FROM 'dev1'@'localhost';\", true, \"REVOKE SHUTDOWN ON *.* FROM `dev1`@`localhost`\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestComment(c *C) {\n\ttable := []testCase{\n\t\t{\"create table t (c int comment 'comment')\", true, \"CREATE TABLE `t` (`c` INT COMMENT 'comment')\"},\n\t\t{\"create table t (c int) comment = 'comment'\", true, \"CREATE TABLE `t` (`c` INT) COMMENT = 'comment'\"},\n\t\t{\"create table t (c int) comment 'comment'\", true, \"CREATE TABLE `t` (`c` INT) COMMENT = 'comment'\"},\n\t\t{\"create table t (c int) comment comment\", false, \"\"},\n\t\t{\"create table t (comment text)\", true, \"CREATE TABLE `t` (`comment` TEXT)\"},\n\t\t{\"START TRANSACTION /*!40108 WITH CONSISTENT SNAPSHOT */\", true, \"START TRANSACTION\"},\n\t\t// for comment in query\n\t\t{\"/*comment*/ /*comment*/ select c /* this is a comment */ from t;\", true, \"SELECT `c` FROM `t`\"},\n\t\t// for unclosed comment\n\t\t{\"delete from t where a = 7 or 1=1/*' and b = 'p'\", false, \"\"},\n\n\t\t{\"create table t (ssl int)\", false, \"\"},\n\t\t{\"create table t (require int)\", false, \"\"},\n\t\t{\"create table t (account int)\", true, \"CREATE TABLE `t` (`account` INT)\"},\n\t\t{\"create table t (expire int)\", true, \"CREATE TABLE `t` (`expire` INT)\"},\n\t\t{\"create table t (cipher int)\", true, \"CREATE TABLE `t` (`cipher` INT)\"},\n\t\t{\"create table t (issuer int)\", true, \"CREATE TABLE `t` (`issuer` INT)\"},\n\t\t{\"create table t (never int)\", true, \"CREATE TABLE `t` (`never` INT)\"},\n\t\t{\"create table t (subject int)\", true, \"CREATE TABLE `t` (`subject` INT)\"},\n\t\t{\"create table t (x509 int)\", true, \"CREATE TABLE `t` (`x509` INT)\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestCommentErrMsg(c *C) {\n\ttable := []testErrMsgCase{\n\t\t{\"delete from t where a = 7 or 1=1/*' and b = 'p'\", false, errors.New(\"near '/*' and b = 'p'' at line 1\")},\n\t\t{\"delete from t where a = 7 or\\n 1=1/*' and b = 'p'\", false, errors.New(\"near '/*' and b = 'p'' at line 2\")},\n\t\t{\"select 1/*\", false, errors.New(\"near '/*' at line 1\")},\n\t\t{\"select 1/* comment */\", false, nil},\n\t}\n\ts.RunErrMsgTest(c, table)\n}\n\ntype subqueryChecker struct {\n\ttext string\n\tc    *C\n}\n\n// Enter implements ast.Visitor interface.\nfunc (sc *subqueryChecker) Enter(inNode ast.Node) (outNode ast.Node, skipChildren bool) {\n\tif expr, ok := inNode.(*ast.SubqueryExpr); ok {\n\t\tsc.c.Assert(expr.Query.Text(), Equals, sc.text)\n\t\treturn inNode, true\n\t}\n\treturn inNode, false\n}\n\n// Leave implements ast.Visitor interface.\nfunc (sc *subqueryChecker) Leave(inNode ast.Node) (node ast.Node, ok bool) {\n\treturn inNode, true\n}\n\nfunc (s *testParserSuite) TestSubquery(c *C) {\n\ttable := []testCase{\n\t\t// for compare subquery\n\t\t{\"SELECT 1 > (select 1)\", true, \"SELECT 1>(SELECT 1)\"},\n\t\t{\"SELECT 1 > ANY (select 1)\", true, \"SELECT 1>ANY (SELECT 1)\"},\n\t\t{\"SELECT 1 > ALL (select 1)\", true, \"SELECT 1>ALL (SELECT 1)\"},\n\t\t{\"SELECT 1 > SOME (select 1)\", true, \"SELECT 1>ANY (SELECT 1)\"},\n\n\t\t// for exists subquery\n\t\t{\"SELECT EXISTS select 1\", false, \"\"},\n\t\t{\"SELECT EXISTS (select 1)\", true, \"SELECT EXISTS (SELECT 1)\"},\n\t\t{\"SELECT + EXISTS (select 1)\", true, \"SELECT +EXISTS (SELECT 1)\"},\n\t\t{\"SELECT - EXISTS (select 1)\", true, \"SELECT -EXISTS (SELECT 1)\"},\n\t\t{\"SELECT NOT EXISTS (select 1)\", true, \"SELECT NOT EXISTS (SELECT 1)\"},\n\t\t{\"SELECT + NOT EXISTS (select 1)\", false, \"\"},\n\t\t{\"SELECT - NOT EXISTS (select 1)\", false, \"\"},\n\t}\n\ts.RunTest(c, table)\n\n\ttests := []struct {\n\t\tinput string\n\t\ttext  string\n\t}{\n\t\t{\"SELECT 1 > (select 1)\", \"select 1\"},\n\t\t{\"SELECT 1 > (select 1 union select 2)\", \"select 1 union select 2\"},\n\t}\n\tparser := parser.New()\n\tfor _, t := range tests {\n\t\tstmt, err := parser.ParseOneStmt(t.input, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\t\tstmt.Accept(&subqueryChecker{\n\t\t\ttext: t.text,\n\t\t\tc:    c,\n\t\t})\n\t}\n}\nfunc (s *testParserSuite) TestUnion(c *C) {\n\ttable := []testCase{\n\t\t{\"select c1 from t1 union select c2 from t2\", true, \"SELECT `c1` FROM `t1` UNION SELECT `c2` FROM `t2`\"},\n\t\t{\"select c1 from t1 union (select c2 from t2)\", true, \"SELECT `c1` FROM `t1` UNION (SELECT `c2` FROM `t2`)\"},\n\t\t{\"select c1 from t1 union (select c2 from t2) order by c1\", true, \"SELECT `c1` FROM `t1` UNION (SELECT `c2` FROM `t2`) ORDER BY `c1`\"},\n\t\t{\"select c1 from t1 union select c2 from t2 order by c2\", true, \"SELECT `c1` FROM `t1` UNION SELECT `c2` FROM `t2` ORDER BY `c2`\"},\n\t\t{\"select c1 from t1 union (select c2 from t2) limit 1\", true, \"SELECT `c1` FROM `t1` UNION (SELECT `c2` FROM `t2`) LIMIT 1\"},\n\t\t{\"select c1 from t1 union (select c2 from t2) limit 1, 1\", true, \"SELECT `c1` FROM `t1` UNION (SELECT `c2` FROM `t2`) LIMIT 1 OFFSET 1\"},\n\t\t{\"select c1 from t1 union (select c2 from t2) order by c1 limit 1\", true, \"SELECT `c1` FROM `t1` UNION (SELECT `c2` FROM `t2`) ORDER BY `c1` LIMIT 1\"},\n\t\t{\"(select c1 from t1) union distinct select c2 from t2\", true, \"(SELECT `c1` FROM `t1`) UNION SELECT `c2` FROM `t2`\"},\n\t\t{\"(select c1 from t1) union distinctrow select c2 from t2\", true, \"(SELECT `c1` FROM `t1`) UNION SELECT `c2` FROM `t2`\"},\n\t\t{\"(select c1 from t1) union all select c2 from t2\", true, \"(SELECT `c1` FROM `t1`) UNION ALL SELECT `c2` FROM `t2`\"},\n\t\t{\"(select c1 from t1) union distinct all select c2 from t2\", false, \"\"},\n\t\t{\"(select c1 from t1) union distinctrow all select c2 from t2\", false, \"\"},\n\t\t{\"(select c1 from t1) union (select c2 from t2) order by c1 union select c3 from t3\", false, \"\"},\n\t\t{\"(select c1 from t1) union (select c2 from t2) limit 1 union select c3 from t3\", false, \"\"},\n\t\t{\"(select c1 from t1) union select c2 from t2 union (select c3 from t3) order by c1 limit 1\", true, \"(SELECT `c1` FROM `t1`) UNION SELECT `c2` FROM `t2` UNION (SELECT `c3` FROM `t3`) ORDER BY `c1` LIMIT 1\"},\n\t\t{\"select (select 1 union select 1) as a\", true, \"SELECT (SELECT 1 UNION SELECT 1) AS `a`\"},\n\t\t{\"select * from (select 1 union select 2) as a\", true, \"SELECT * FROM (SELECT 1 UNION SELECT 2) AS `a`\"},\n\t\t{\"insert into t select c1 from t1 union select c2 from t2\", true, \"INSERT INTO `t` SELECT `c1` FROM `t1` UNION SELECT `c2` FROM `t2`\"},\n\t\t{\"insert into t (c) select c1 from t1 union select c2 from t2\", true, \"INSERT INTO `t` (`c`) SELECT `c1` FROM `t1` UNION SELECT `c2` FROM `t2`\"},\n\t\t{\"select 2 as a from dual union select 1 as b from dual order by a\", true, \"SELECT 2 AS `a` UNION SELECT 1 AS `b` ORDER BY `a`\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestUnionOrderBy(c *C) {\n\tparser := parser.New()\n\tparser.EnableWindowFunc(s.enableWindowFunc)\n\n\ttests := []struct {\n\t\tsrc        string\n\t\thasOrderBy []bool\n\t}{\n\t\t{\"select 2 as a from dual union select 1 as b from dual order by a\", []bool{false, false, true}},\n\t\t{\"select 2 as a from dual union (select 1 as b from dual order by a)\", []bool{false, true, false}},\n\t\t{\"(select 2 as a from dual order by a) union select 1 as b from dual order by a\", []bool{true, false, true}},\n\t\t{\"select 1 a, 2 b from dual order by a\", []bool{true}},\n\t\t{\"select 1 a, 2 b from dual\", []bool{false}},\n\t}\n\n\tfor _, t := range tests {\n\t\tstmt, _, err := parser.Parse(t.src, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\t\tus, ok := stmt[0].(*ast.UnionStmt)\n\t\tif ok {\n\t\t\tvar i int\n\t\t\tfor _, s := range us.SelectList.Selects {\n\t\t\t\tc.Assert(s.OrderBy != nil, Equals, t.hasOrderBy[i])\n\t\t\t\ti++\n\t\t\t}\n\t\t\tc.Assert(us.OrderBy != nil, Equals, t.hasOrderBy[i])\n\t\t}\n\t\tss, ok := stmt[0].(*ast.SelectStmt)\n\t\tif ok {\n\t\t\tc.Assert(ss.OrderBy != nil, Equals, t.hasOrderBy[0])\n\t\t}\n\t}\n}\n\nfunc (s *testParserSuite) TestLikeEscape(c *C) {\n\ttable := []testCase{\n\t\t// for like escape\n\t\t{`select \"abc_\" like \"abc\\\\_\" escape ''`, true, \"SELECT 'abc_' LIKE 'abc\\\\_'\"},\n\t\t{`select \"abc_\" like \"abc\\\\_\" escape '\\\\'`, true, \"SELECT 'abc_' LIKE 'abc\\\\_'\"},\n\t\t{`select \"abc_\" like \"abc\\\\_\" escape '||'`, false, \"\"},\n\t\t{`select \"abc\" like \"escape\" escape '+'`, true, \"SELECT 'abc' LIKE 'escape' ESCAPE '+'\"},\n\t\t{\"select '''_' like '''_' escape ''''\", true, \"SELECT '''_' LIKE '''_' ESCAPE ''''\"},\n\t}\n\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestLockUnlockTables(c *C) {\n\ttable := []testCase{\n\t\t{`UNLOCK TABLES;`, true, \"UNLOCK TABLES\"},\n\t\t{`LOCK TABLES t1 READ;`, true, \"LOCK TABLES `t1` READ\"},\n\t\t{`LOCK TABLES t1 READ LOCAL;`, true, \"LOCK TABLES `t1` READ LOCAL\"},\n\t\t{`show table status like 't'`, true, \"SHOW TABLE STATUS LIKE 't'\"},\n\t\t{`LOCK TABLES t2 WRITE`, true, \"LOCK TABLES `t2` WRITE\"},\n\t\t{`LOCK TABLES t2 WRITE LOCAL;`, true, \"LOCK TABLES `t2` WRITE LOCAL\"},\n\t\t{`LOCK TABLES t1 WRITE, t2 READ;`, true, \"LOCK TABLES `t1` WRITE, `t2` READ\"},\n\t\t{`LOCK TABLES t1 WRITE LOCAL, t2 READ LOCAL;`, true, \"LOCK TABLES `t1` WRITE LOCAL, `t2` READ LOCAL\"},\n\n\t\t// for unlock table and lock table\n\t\t{`UNLOCK TABLE;`, true, \"UNLOCK TABLES\"},\n\t\t{`LOCK TABLE t1 READ;`, true, \"LOCK TABLES `t1` READ\"},\n\t\t{`LOCK TABLE t1 READ LOCAL;`, true, \"LOCK TABLES `t1` READ LOCAL\"},\n\t\t{`show table status like 't'`, true, \"SHOW TABLE STATUS LIKE 't'\"},\n\t\t{`LOCK TABLE t2 WRITE`, true, \"LOCK TABLES `t2` WRITE\"},\n\t\t{`LOCK TABLE t2 WRITE LOCAL;`, true, \"LOCK TABLES `t2` WRITE LOCAL\"},\n\t\t{`LOCK TABLE t1 WRITE, t2 READ;`, true, \"LOCK TABLES `t1` WRITE, `t2` READ\"},\n\n\t\t// for cleanup table lock.\n\t\t{\"ADMIN CLEANUP TABLE LOCK\", false, \"\"},\n\t\t{\"ADMIN CLEANUP TABLE LOCK t\", true, \"ADMIN CLEANUP TABLE LOCK `t`\"},\n\t\t{\"ADMIN CLEANUP TABLE LOCK t1,t2\", true, \"ADMIN CLEANUP TABLE LOCK `t1`, `t2`\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestIndexHint(c *C) {\n\ttable := []testCase{\n\t\t{`select * from t use index (primary)`, true, \"SELECT * FROM `t` USE INDEX (`primary`)\"},\n\t\t{\"select * from t use index (`primary`)\", true, \"SELECT * FROM `t` USE INDEX (`primary`)\"},\n\t\t{`select * from t use index ();`, true, \"SELECT * FROM `t` USE INDEX ()\"},\n\t\t{`select * from t use index (idx);`, true, \"SELECT * FROM `t` USE INDEX (`idx`)\"},\n\t\t{`select * from t use index (idx1, idx2);`, true, \"SELECT * FROM `t` USE INDEX (`idx1`, `idx2`)\"},\n\t\t{`select * from t ignore key (idx1)`, true, \"SELECT * FROM `t` IGNORE INDEX (`idx1`)\"},\n\t\t{`select * from t force index for join (idx1)`, true, \"SELECT * FROM `t` FORCE INDEX FOR JOIN (`idx1`)\"},\n\t\t{`select * from t use index for order by (idx1)`, true, \"SELECT * FROM `t` USE INDEX FOR ORDER BY (`idx1`)\"},\n\t\t{`select * from t force index for group by (idx1)`, true, \"SELECT * FROM `t` FORCE INDEX FOR GROUP BY (`idx1`)\"},\n\t\t{`select * from t use index for group by (idx1) use index for order by (idx2), t2`, true, \"SELECT * FROM `t` USE INDEX FOR GROUP BY (`idx1`) USE INDEX FOR ORDER BY (`idx2`) JOIN `t2`\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestSQLResult(c *C) {\n\ttable := []testCase{\n\t\t{`select SQL_BIG_RESULT c1 from t group by c1`, true, \"SELECT SQL_BIG_RESULT `c1` FROM `t` GROUP BY `c1`\"},\n\t\t{`select SQL_SMALL_RESULT c1 from t group by c1`, true, \"SELECT SQL_SMALL_RESULT `c1` FROM `t` GROUP BY `c1`\"},\n\t\t{`select SQL_BUFFER_RESULT * from t`, true, \"SELECT SQL_BUFFER_RESULT * FROM `t`\"},\n\t\t{`select sql_small_result sql_big_result sql_buffer_result 1`, true, \"SELECT SQL_SMALL_RESULT SQL_BIG_RESULT SQL_BUFFER_RESULT 1\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestSQLNoCache(c *C) {\n\ttable := []testCase{\n\t\t{`select SQL_NO_CACHE * from t`, false, \"\"},\n\t\t{`select SQL_CACHE * from t`, true, \"SELECT * FROM `t`\"},\n\t\t{`select * from t`, true, \"SELECT * FROM `t`\"},\n\t}\n\n\tparser := parser.New()\n\tfor _, tt := range table {\n\t\tstmt, _, err := parser.Parse(tt.src, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\n\t\tsel := stmt[0].(*ast.SelectStmt)\n\t\tc.Assert(sel.SelectStmtOpts.SQLCache, Equals, tt.ok)\n\t}\n}\n\nfunc (s *testParserSuite) TestEscape(c *C) {\n\ttable := []testCase{\n\t\t{`select \"\"\";`, false, \"\"},\n\t\t{`select \"\"\"\";`, true, \"SELECT '\\\"'\"},\n\t\t{`select \"汉字\";`, true, \"SELECT '汉字'\"},\n\t\t{`select 'abc\"def';`, true, \"SELECT 'abc\\\"def'\"},\n\t\t{`select 'a\\r\\n';`, true, \"SELECT 'a\\r\\n'\"},\n\t\t{`select \"\\a\\r\\n\"`, true, \"SELECT 'a\\r\\n'\"},\n\t\t{`select \"\\xFF\"`, true, \"SELECT 'xFF'\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestInsertStatementMemoryAllocation(c *C) {\n\tsql := \"insert t values (1)\" + strings.Repeat(\",(1)\", 1000)\n\tvar oldStats, newStats runtime.MemStats\n\truntime.ReadMemStats(&oldStats)\n\t_, err := parser.New().ParseOneStmt(sql, \"\", \"\")\n\tc.Assert(err, IsNil)\n\truntime.ReadMemStats(&newStats)\n\tc.Assert(int(newStats.TotalAlloc-oldStats.TotalAlloc), Less, 1024*500)\n}\n\nfunc (s *testParserSuite) TestExplain(c *C) {\n\ttable := []testCase{\n\t\t{\"explain select c1 from t1\", true, \"EXPLAIN FORMAT = 'row' SELECT `c1` FROM `t1`\"},\n\t\t{\"explain delete t1, t2 from t1 inner join t2 inner join t3 where t1.id=t2.id and t2.id=t3.id;\", true, \"EXPLAIN FORMAT = 'row' DELETE `t1`,`t2` FROM (`t1` JOIN `t2`) JOIN `t3` WHERE `t1`.`id`=`t2`.`id` AND `t2`.`id`=`t3`.`id`\"},\n\t\t{\"explain insert into t values (1), (2), (3)\", true, \"EXPLAIN FORMAT = 'row' INSERT INTO `t` VALUES (1),(2),(3)\"},\n\t\t{\"explain replace into foo values (1 || 2)\", true, \"EXPLAIN FORMAT = 'row' REPLACE INTO `foo` VALUES (1 OR 2)\"},\n\t\t{\"explain update t set id = id + 1 order by id desc;\", true, \"EXPLAIN FORMAT = 'row' UPDATE `t` SET `id`=`id`+1 ORDER BY `id` DESC\"},\n\t\t{\"explain select c1 from t1 union (select c2 from t2) limit 1, 1\", true, \"EXPLAIN FORMAT = 'row' SELECT `c1` FROM `t1` UNION (SELECT `c2` FROM `t2`) LIMIT 1 OFFSET 1\"},\n\t\t{`explain format = \"row\" select c1 from t1 union (select c2 from t2) limit 1, 1`, true, \"EXPLAIN FORMAT = 'row' SELECT `c1` FROM `t1` UNION (SELECT `c2` FROM `t2`) LIMIT 1 OFFSET 1\"},\n\t\t{\"DESC SCHE.TABL\", true, \"DESC `SCHE`.`TABL`\"},\n\t\t{\"DESC SCHE.TABL COLUM\", true, \"DESC `SCHE`.`TABL` `COLUM`\"},\n\t\t{\"DESCRIBE SCHE.TABL COLUM\", true, \"DESC `SCHE`.`TABL` `COLUM`\"},\n\t\t{\"EXPLAIN ANALYZE SELECT 1\", true, \"EXPLAIN ANALYZE SELECT 1\"},\n\t\t{\"EXPLAIN FORMAT = 'dot' SELECT 1\", true, \"EXPLAIN FORMAT = 'dot' SELECT 1\"},\n\t\t{\"EXPLAIN FORMAT = 'row' SELECT 1\", true, \"EXPLAIN FORMAT = 'row' SELECT 1\"},\n\t\t{\"EXPLAIN FORMAT = 'ROW' SELECT 1\", true, \"EXPLAIN FORMAT = 'ROW' SELECT 1\"},\n\t\t{\"EXPLAIN SELECT 1\", true, \"EXPLAIN FORMAT = 'row' SELECT 1\"},\n\t\t{\"EXPLAIN FOR CONNECTION 1\", true, \"EXPLAIN FORMAT = 'row' FOR CONNECTION 1\"},\n\t\t{\"EXPLAIN FOR connection 42\", true, \"EXPLAIN FORMAT = 'row' FOR CONNECTION 42\"},\n\t\t{\"EXPLAIN FORMAT = 'dot' FOR CONNECTION 1\", true, \"EXPLAIN FORMAT = 'dot' FOR CONNECTION 1\"},\n\t\t{\"EXPLAIN FORMAT = 'row' FOR connection 1\", true, \"EXPLAIN FORMAT = 'row' FOR CONNECTION 1\"},\n\t\t{\"EXPLAIN FORMAT = TRADITIONAL FOR CONNECTION 1\", true, \"EXPLAIN FORMAT = 'row' FOR CONNECTION 1\"},\n\t\t{\"EXPLAIN FORMAT = TRADITIONAL SELECT 1\", true, \"EXPLAIN FORMAT = 'row' SELECT 1\"},\n\t\t{\"EXPLAIN FORMAT = JSON FOR CONNECTION 1\", true, \"EXPLAIN FORMAT = 'json' FOR CONNECTION 1\"},\n\t\t{\"EXPLAIN FORMAT = JSON SELECT 1\", true, \"EXPLAIN FORMAT = 'json' SELECT 1\"},\n\t\t{\"EXPLAIN FORMAT = 'hint' SELECT 1\", true, \"EXPLAIN FORMAT = 'hint' SELECT 1\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestPrepare(c *C) {\n\ttable := []testCase{\n\t\t{\"PREPARE pname FROM 'SELECT ?'\", true, \"PREPARE `pname` FROM 'SELECT ?'\"},\n\t\t{\"PREPARE pname FROM @test\", true, \"PREPARE `pname` FROM @`test`\"},\n\t\t{\"PREPARE `` FROM @test\", true, \"PREPARE `` FROM @`test`\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestDeallocate(c *C) {\n\ttable := []testCase{\n\t\t{\"DEALLOCATE PREPARE test\", true, \"DEALLOCATE PREPARE `test`\"},\n\t\t{\"DEALLOCATE PREPARE ``\", true, \"DEALLOCATE PREPARE ``\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestExecute(c *C) {\n\ttable := []testCase{\n\t\t{\"EXECUTE test\", true, \"EXECUTE `test`\"},\n\t\t{\"EXECUTE test USING @var1,@var2\", true, \"EXECUTE `test` USING @`var1`,@`var2`\"},\n\t\t{\"EXECUTE `` USING @var1,@var2\", true, \"EXECUTE `` USING @`var1`,@`var2`\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestTrace(c *C) {\n\ttable := []testCase{\n\t\t{\"trace begin\", true, \"TRACE START TRANSACTION\"},\n\t\t{\"trace commit\", true, \"TRACE COMMIT\"},\n\t\t{\"trace rollback\", true, \"TRACE ROLLBACK\"},\n\t\t{\"trace set a = 1\", true, \"TRACE SET @@SESSION.`a`=1\"},\n\t\t{\"trace select c1 from t1\", true, \"TRACE SELECT `c1` FROM `t1`\"},\n\t\t{\"trace delete t1, t2 from t1 inner join t2 inner join t3 where t1.id=t2.id and t2.id=t3.id;\", true, \"TRACE DELETE `t1`,`t2` FROM (`t1` JOIN `t2`) JOIN `t3` WHERE `t1`.`id`=`t2`.`id` AND `t2`.`id`=`t3`.`id`\"},\n\t\t{\"trace insert into t values (1), (2), (3)\", true, \"TRACE INSERT INTO `t` VALUES (1),(2),(3)\"},\n\t\t{\"trace replace into foo values (1 || 2)\", true, \"TRACE REPLACE INTO `foo` VALUES (1 OR 2)\"},\n\t\t{\"trace update t set id = id + 1 order by id desc;\", true, \"TRACE UPDATE `t` SET `id`=`id`+1 ORDER BY `id` DESC\"},\n\t\t{\"trace select c1 from t1 union (select c2 from t2) limit 1, 1\", true, \"TRACE SELECT `c1` FROM `t1` UNION (SELECT `c2` FROM `t2`) LIMIT 1 OFFSET 1\"},\n\t\t{\"trace format = 'row' select c1 from t1 union (select c2 from t2) limit 1, 1\", true, \"TRACE FORMAT = 'row' SELECT `c1` FROM `t1` UNION (SELECT `c2` FROM `t2`) LIMIT 1 OFFSET 1\"},\n\t\t{\"trace format = 'json' update t set id = id + 1 order by id desc;\", true, \"TRACE UPDATE `t` SET `id`=`id`+1 ORDER BY `id` DESC\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestBinding(c *C) {\n\ttable := []testCase{\n\t\t{\"create global binding for select * from t using select * from t use index(a)\", true, \"CREATE GLOBAL BINDING FOR SELECT * FROM `t` USING SELECT * FROM `t` USE INDEX (`a`)\"},\n\t\t{\"create session binding for select * from t using select * from t use index(a)\", true, \"CREATE SESSION BINDING FOR SELECT * FROM `t` USING SELECT * FROM `t` USE INDEX (`a`)\"},\n\t\t{\"drop global binding for select * from t\", true, \"DROP GLOBAL BINDING FOR SELECT * FROM `t`\"},\n\t\t{\"drop session binding for select * from t\", true, \"DROP SESSION BINDING FOR SELECT * FROM `t`\"},\n\t\t{\"drop global binding for select * from t using select * from t use index(a)\", true, \"DROP GLOBAL BINDING FOR SELECT * FROM `t` USING SELECT * FROM `t` USE INDEX (`a`)\"},\n\t\t{\"drop session binding for select * from t using select * from t use index(a)\", true, \"DROP SESSION BINDING FOR SELECT * FROM `t` USING SELECT * FROM `t` USE INDEX (`a`)\"},\n\t\t{\"show global bindings\", true, \"SHOW GLOBAL BINDINGS\"},\n\t\t{\"show session bindings\", true, \"SHOW SESSION BINDINGS\"},\n\t}\n\ts.RunTest(c, table)\n\n\tp := parser.New()\n\tsms, _, err := p.Parse(\"create global binding for select * from t using select * from t use index(a)\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tv, ok := sms[0].(*ast.CreateBindingStmt)\n\tc.Assert(ok, IsTrue)\n\tc.Assert(v.OriginSel.Text(), Equals, \"select * from t\")\n\tc.Assert(v.HintedSel.Text(), Equals, \"select * from t use index(a)\")\n\tc.Assert(v.GlobalScope, IsTrue)\n}\n\nfunc (s *testParserSuite) TestView(c *C) {\n\ttable := []testCase{\n\t\t{\"create view v as select * from t\", true, \"CREATE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace view v as select * from t\", true, \"CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = undefined view v as select * from t\", true, \"CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge view v as select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = temptable view v as select * from t\", true, \"CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' view v as select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security definer view v as select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v as select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as select * from t with local check option\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` WITH LOCAL CHECK OPTION\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as select * from t with cascaded check option\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = current_user view v as select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\n\t\t// create view with `(` select statement `)`\n\t\t{\"create view v as (select * from t)\", true, \"CREATE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace view v as (select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = undefined view v as (select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge view v as (select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = temptable view v as (select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' view v as (select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security definer view v as (select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v as (select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as (select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as (select * from t) with local check option\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` WITH LOCAL CHECK OPTION\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as (select * from t) with cascaded check option\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = current_user view v as (select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t`\"},\n\n\t\t// create view with union statement\n\t\t{\"create view v as select * from t union select * from t\", true, \"CREATE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\t\t{\"create or replace view v as select * from t union select * from t\", true, \"CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = undefined view v as select * from t union select * from t\", true, \"CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge view v as select * from t union select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = temptable view v as select * from t union select * from t\", true, \"CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' view v as select * from t union select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security definer view v as select * from t union select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v as select * from t union select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as select * from t union select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as select * from t union select * from t with local check option\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` UNION SELECT * FROM `t` WITH LOCAL CHECK OPTION\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as select * from t union select * from t with cascaded check option\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = current_user view v as select * from t union select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION SELECT * FROM `t`\"},\n\n\t\t// create view with union all statement\n\t\t{\"create view v as select * from t union all select * from t\", true, \"CREATE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace view v as select * from t union all select * from t\", true, \"CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = undefined view v as select * from t union all select * from t\", true, \"CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge view v as select * from t union all select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = temptable view v as select * from t union all select * from t\", true, \"CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' view v as select * from t union all select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security definer view v as select * from t union all select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v as select * from t union all select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as select * from t union all select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as select * from t union all select * from t with local check option\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` UNION ALL SELECT * FROM `t` WITH LOCAL CHECK OPTION\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as select * from t union all select * from t with cascaded check option\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = current_user view v as select * from t union all select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\n\t\t// create view with `(` union statement `)`\n\t\t{\"create view v as (select * from t union all select * from t)\", true, \"CREATE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace view v as (select * from t union all select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = undefined view v as (select * from t union all select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge view v as (select * from t union all select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = temptable view v as (select * from t union all select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' view v as (select * from t union all select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security definer view v as (select * from t union all select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v as (select * from t union all select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as (select * from t union all select * from t)\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as (select * from t union all select * from t) with local check option\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` UNION ALL SELECT * FROM `t` WITH LOCAL CHECK OPTION\"},\n\t\t{\"create or replace algorithm = merge definer = 'root' sql security invoker view v(a,b) as (select * from t union all select * from t) with cascaded check option\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = `root`@`%` SQL SECURITY INVOKER VIEW `v` (`a`,`b`) AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t\t{\"create or replace algorithm = merge definer = current_user view v as select * from t union all select * from t\", true, \"CREATE OR REPLACE ALGORITHM = MERGE DEFINER = CURRENT_USER SQL SECURITY DEFINER VIEW `v` AS SELECT * FROM `t` UNION ALL SELECT * FROM `t`\"},\n\t}\n\ts.RunTest(c, table)\n\n\t// Test case for the text of the select statement in create view statement.\n\tp := parser.New()\n\tsms, _, err := p.Parse(\"create view v as select * from t\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tv, ok := sms[0].(*ast.CreateViewStmt)\n\tc.Assert(ok, IsTrue)\n\tc.Assert(v.Algorithm, Equals, model.AlgorithmUndefined)\n\tc.Assert(v.Select.Text(), Equals, \"select * from t\")\n\tc.Assert(v.Security, Equals, model.SecurityDefiner)\n\tc.Assert(v.CheckOption, Equals, model.CheckOptionCascaded)\n\n\tsrc := `CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = root@localhost\n                  SQL SECURITY DEFINER\n\t\t\t      VIEW V(a,b,c) AS select c,d,e from t\n                  WITH CASCADED CHECK OPTION;`\n\n\tvar st ast.StmtNode\n\tst, err = p.ParseOneStmt(src, \"\", \"\")\n\tc.Assert(err, IsNil)\n\tv, ok = st.(*ast.CreateViewStmt)\n\tc.Assert(ok, IsTrue)\n\tc.Assert(v.OrReplace, IsTrue)\n\tc.Assert(v.Algorithm, Equals, model.AlgorithmUndefined)\n\tc.Assert(v.Definer.Username, Equals, \"root\")\n\tc.Assert(v.Definer.Hostname, Equals, \"localhost\")\n\tc.Assert(v.Cols[0], Equals, model.NewCIStr(\"a\"))\n\tc.Assert(v.Cols[1], Equals, model.NewCIStr(\"b\"))\n\tc.Assert(v.Cols[2], Equals, model.NewCIStr(\"c\"))\n\tc.Assert(v.Select.Text(), Equals, \"select c,d,e from t\")\n\tc.Assert(v.Security, Equals, model.SecurityDefiner)\n\tc.Assert(v.CheckOption, Equals, model.CheckOptionCascaded)\n}\n\nfunc (s *testParserSuite) TestTimestampDiffUnit(c *C) {\n\t// Test case for timestampdiff unit.\n\t// TimeUnit should be unified to upper case.\n\tparser := parser.New()\n\tstmt, _, err := parser.Parse(\"SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01'), TIMESTAMPDIFF(month,'2003-02-01','2003-05-01');\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tss := stmt[0].(*ast.SelectStmt)\n\tfields := ss.Fields.Fields\n\tc.Assert(len(fields), Equals, 2)\n\texpr := fields[0].Expr\n\tf, ok := expr.(*ast.FuncCallExpr)\n\tc.Assert(ok, IsTrue)\n\tc.Assert(f.Args[0].(*ast.TimeUnitExpr).Unit, Equals, ast.TimeUnitMonth)\n\n\texpr = fields[1].Expr\n\tf, ok = expr.(*ast.FuncCallExpr)\n\tc.Assert(ok, IsTrue)\n\tc.Assert(f.Args[0].(*ast.TimeUnitExpr).Unit, Equals, ast.TimeUnitMonth)\n\n\t// Test Illegal TimeUnit for TimestampDiff\n\ttable := []testCase{\n\t\t{\"SELECT TIMESTAMPDIFF(SECOND_MICROSECOND,'2003-02-01','2003-05-01')\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPDIFF(MINUTE_MICROSECOND,'2003-02-01','2003-05-01')\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPDIFF(MINUTE_SECOND,'2003-02-01','2003-05-01')\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPDIFF(HOUR_MICROSECOND,'2003-02-01','2003-05-01')\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPDIFF(HOUR_SECOND,'2003-02-01','2003-05-01')\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPDIFF(HOUR_MINUTE,'2003-02-01','2003-05-01')\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPDIFF(DAY_MICROSECOND,'2003-02-01','2003-05-01')\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPDIFF(DAY_SECOND,'2003-02-01','2003-05-01')\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPDIFF(DAY_MINUTE,'2003-02-01','2003-05-01')\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPDIFF(DAY_HOUR,'2003-02-01','2003-05-01')\", false, \"\"},\n\t\t{\"SELECT TIMESTAMPDIFF(YEAR_MONTH,'2003-02-01','2003-05-01')\", false, \"\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestSessionManage(c *C) {\n\ttable := []testCase{\n\t\t// Kill statement.\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/kill.html\n\t\t{\"kill 23123\", true, \"KILL 23123\"},\n\t\t{\"kill connection 23123\", true, \"KILL 23123\"},\n\t\t{\"kill query 23123\", true, \"KILL QUERY 23123\"},\n\t\t{\"kill tidb 23123\", true, \"KILL TIDB 23123\"},\n\t\t{\"kill tidb connection 23123\", true, \"KILL TIDB 23123\"},\n\t\t{\"kill tidb query 23123\", true, \"KILL TIDB QUERY 23123\"},\n\t\t{\"show processlist\", true, \"SHOW PROCESSLIST\"},\n\t\t{\"show full processlist\", true, \"SHOW FULL PROCESSLIST\"},\n\t\t{\"shutdown\", true, \"SHUTDOWN\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestParseShowOpenTables(c *C) {\n\ttable := []testCase{\n\t\t{\"SHOW OPEN TABLES\", true, \"SHOW OPEN TABLES\"},\n\t\t{\"SHOW OPEN TABLES IN test\", true, \"SHOW OPEN TABLES IN `test`\"},\n\t\t{\"SHOW OPEN TABLES FROM test\", true, \"SHOW OPEN TABLES IN `test`\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestSQLModeANSIQuotes(c *C) {\n\tparser := parser.New()\n\tparser.SetSQLMode(mysql.ModeANSIQuotes)\n\ttests := []string{\n\t\t`CREATE TABLE \"table\" (\"id\" int)`,\n\t\t`select * from t \"tt\"`,\n\t}\n\tfor _, test := range tests {\n\t\t_, _, err := parser.Parse(test, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\t}\n}\n\n// func (s *testParserSuite) TestDDLStatements(c *C) {\n// \tparser := parser.New()\n// \t// Tests that whatever the charset it is define, we always assign utf8 charset and utf8_bin collate.\n// \tcreateTableStr := `CREATE TABLE t (\n// \t\ta varchar(64) binary,\n// \t\tb char(10) charset utf8 collate utf8_general_ci,\n// \t\tc text charset latin1) ENGINE=innoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin`\n// \tstmts, _, err := parser.Parse(createTableStr, \"\", \"\")\n// \tc.Assert(err, IsNil)\n// \tstmt := stmts[0].(*ast.CreateTableStmt)\n// \tc.Assert(mysql.HasBinaryFlag(stmt.Cols[0].Tp.Flag), IsTrue)\n// \tfor _, colDef := range stmt.Cols[1:] {\n// \t\tc.Assert(mysql.HasBinaryFlag(colDef.Tp.Flag), IsFalse)\n// \t}\n// \tfor _, tblOpt := range stmt.Options {\n// \t\tswitch tblOpt.Tp {\n// \t\tcase ast.TableOptionCharset:\n// \t\t\tc.Assert(tblOpt.StrValue, Equals, \"utf8\")\n// \t\tcase ast.TableOptionCollate:\n// \t\t\tc.Assert(tblOpt.StrValue, Equals, \"utf8_bin\")\n// \t\t}\n// \t}\n// \tcreateTableStr = `CREATE TABLE t (\n// \t\ta varbinary(64),\n// \t\tb binary(10),\n// \t\tc blob)`\n// \tstmts, _, err = parser.Parse(createTableStr, \"\", \"\")\n// \tc.Assert(err, IsNil)\n// \tstmt = stmts[0].(*ast.CreateTableStmt)\n// \tfor _, colDef := range stmt.Cols {\n// \t\tc.Assert(colDef.Tp.Charset, Equals, charset.CharsetBin)\n// \t\tc.Assert(colDef.Tp.Collate, Equals, charset.CollationBin)\n// \t\tc.Assert(mysql.HasBinaryFlag(colDef.Tp.Flag), IsTrue)\n// \t}\n// \t// Test set collate for all column types\n// \tcreateTableStr = `CREATE TABLE t (\n// \t\tc_int int collate utf8_bin,\n// \t\tc_real real collate utf8_bin,\n// \t\tc_float float collate utf8_bin,\n// \t\tc_bool bool collate utf8_bin,\n// \t\tc_char char collate utf8_bin,\n// \t\tc_binary binary collate utf8_bin,\n// \t\tc_varchar varchar(2) collate utf8_bin,\n// \t\tc_year year collate utf8_bin,\n// \t\tc_date date collate utf8_bin,\n// \t\tc_time time collate utf8_bin,\n// \t\tc_datetime datetime collate utf8_bin,\n// \t\tc_timestamp timestamp collate utf8_bin,\n// \t\tc_tinyblob tinyblob collate utf8_bin,\n// \t\tc_blob blob collate utf8_bin,\n// \t\tc_mediumblob mediumblob collate utf8_bin,\n// \t\tc_longblob longblob collate utf8_bin,\n// \t\tc_bit bit collate utf8_bin,\n// \t\tc_long_varchar long varchar collate utf8_bin,\n// \t\tc_tinytext tinytext collate utf8_bin,\n// \t\tc_text text collate utf8_bin,\n// \t\tc_mediumtext mediumtext collate utf8_bin,\n// \t\tc_longtext longtext collate utf8_bin,\n// \t\tc_decimal decimal collate utf8_bin,\n// \t\tc_numeric numeric collate utf8_bin,\n// \t\tc_enum enum('1') collate utf8_bin,\n// \t\tc_set set('1') collate utf8_bin,\n// \t\tc_json json collate utf8_bin)`\n// \tstmts, _, err = parser.Parse(createTableStr, \"\", \"\")\n// \tc.Assert(err, IsNil)\n// }\n\nfunc (s *testParserSuite) TestAnalyze(c *C) {\n\ttable := []testCase{\n\t\t{\"analyze table t1\", true, \"ANALYZE TABLE `t1`\"},\n\t\t{\"analyze table t1.*\", false, \"\"},\n\t\t{\"analyze table t,t1\", true, \"ANALYZE TABLE `t`,`t1`\"},\n\t\t{\"analyze table t1 index\", true, \"ANALYZE TABLE `t1` INDEX\"},\n\t\t{\"analyze table t1 index a\", true, \"ANALYZE TABLE `t1` INDEX `a`\"},\n\t\t{\"analyze table t1 index a,b\", true, \"ANALYZE TABLE `t1` INDEX `a`,`b`\"},\n\t\t{\"analyze table t with 4 buckets\", true, \"ANALYZE TABLE `t` WITH 4 BUCKETS\"},\n\t\t{\"analyze table t with 4 topn\", true, \"ANALYZE TABLE `t` WITH 4 TOPN\"},\n\t\t{\"analyze table t with 4 cmsketch width\", true, \"ANALYZE TABLE `t` WITH 4 CMSKETCH WIDTH\"},\n\t\t{\"analyze table t with 4 cmsketch depth\", true, \"ANALYZE TABLE `t` WITH 4 CMSKETCH DEPTH\"},\n\t\t{\"analyze table t with 4 samples\", true, \"ANALYZE TABLE `t` WITH 4 SAMPLES\"},\n\t\t{\"analyze table t with 4 buckets, 4 topn, 4 cmsketch width, 4 cmsketch depth, 4 samples\", true, \"ANALYZE TABLE `t` WITH 4 BUCKETS, 4 TOPN, 4 CMSKETCH WIDTH, 4 CMSKETCH DEPTH, 4 SAMPLES\"},\n\t\t{\"analyze table t index a with 4 buckets\", true, \"ANALYZE TABLE `t` INDEX `a` WITH 4 BUCKETS\"},\n\t\t{\"analyze table t partition a\", true, \"ANALYZE TABLE `t` PARTITION `a`\"},\n\t\t{\"analyze table t partition a with 4 buckets\", true, \"ANALYZE TABLE `t` PARTITION `a` WITH 4 BUCKETS\"},\n\t\t{\"analyze table t partition a index b\", true, \"ANALYZE TABLE `t` PARTITION `a` INDEX `b`\"},\n\t\t{\"analyze table t partition a index b with 4 buckets\", true, \"ANALYZE TABLE `t` PARTITION `a` INDEX `b` WITH 4 BUCKETS\"},\n\t\t{\"analyze incremental table t index\", true, \"ANALYZE INCREMENTAL TABLE `t` INDEX\"},\n\t\t{\"analyze incremental table t index idx\", true, \"ANALYZE INCREMENTAL TABLE `t` INDEX `idx`\"},\n\t}\n\ts.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestGeneratedColumn(c *C) {\n\ttests := []struct {\n\t\tinput string\n\t\tok    bool\n\t\texpr  string\n\t}{\n\t\t{\"create table t (c int, d int generated always as (c + 1) virtual)\", true, \"c + 1\"},\n\t\t{\"create table t (c int, d int as (   c + 1   ) virtual)\", true, \"c + 1\"},\n\t\t{\"create table t (c int, d int as (1 + 1) stored)\", true, \"1 + 1\"},\n\t}\n\tparser := parser.New()\n\tfor _, tt := range tests {\n\t\tstmtNodes, _, err := parser.Parse(tt.input, \"\", \"\")\n\t\tif tt.ok {\n\t\t\tc.Assert(err, IsNil)\n\t\t\tstmtNode := stmtNodes[0]\n\t\t\tfor _, col := range stmtNode.(*ast.CreateTableStmt).Cols {\n\t\t\t\tfor _, opt := range col.Options {\n\t\t\t\t\tif opt.Tp == ast.ColumnOptionGenerated {\n\t\t\t\t\t\tc.Assert(opt.Expr.Text(), Equals, tt.expr)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tc.Assert(err, NotNil)\n\t\t}\n\t}\n\n}\n\nfunc (s *testParserSuite) TestSetTransaction(c *C) {\n\t// Set transaction is equivalent to setting the global or session value of tx_isolation.\n\t// For example:\n\t// SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED\n\t// SET SESSION tx_isolation='READ-COMMITTED'\n\ttests := []struct {\n\t\tinput    string\n\t\tisGlobal bool\n\t\tvalue    string\n\t}{\n\t\t{\n\t\t\t\"SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED\",\n\t\t\tfalse, \"READ-COMMITTED\",\n\t\t},\n\t\t{\n\t\t\t\"SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ\",\n\t\t\ttrue, \"REPEATABLE-READ\",\n\t\t},\n\t}\n\tparser := parser.New()\n\tfor _, t := range tests {\n\t\tstmt1, err := parser.ParseOneStmt(t.input, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\t\tsetStmt := stmt1.(*ast.SetStmt)\n\t\tvars := setStmt.Variables[0]\n\t\tc.Assert(vars.Name, Equals, \"tx_isolation\")\n\t\tc.Assert(vars.IsGlobal, Equals, t.isGlobal)\n\t\tc.Assert(vars.IsSystem, Equals, true)\n\t\tc.Assert(vars.Value.(ast.ValueExpr).GetValue(), Equals, t.value)\n\t}\n}\n\nfunc (s *testParserSuite) TestSideEffect(c *C) {\n\t// This test cover a bug that parse an error SQL doesn't leave the parser in a\n\t// clean state, cause the following SQL parse fail.\n\tparser := parser.New()\n\t_, err := parser.ParseOneStmt(\"create table t /*!50100 'abc', 'abc' */;\", \"\", \"\")\n\tc.Assert(err, NotNil)\n\n\t_, err = parser.ParseOneStmt(\"show tables;\", \"\", \"\")\n\tc.Assert(err, IsNil)\n}\n\nfunc (s *testParserSuite) TestTablePartition(c *C) {\n\ttable := []testCase{\n\t\t{\"ALTER TABLE t1 TRUNCATE PARTITION p0\", true, \"ALTER TABLE `t1` TRUNCATE PARTITION `p0`\"},\n\t\t{\"ALTER TABLE t1 TRUNCATE PARTITION p0, p1\", true, \"ALTER TABLE `t1` TRUNCATE PARTITION `p0`,`p1`\"},\n\t\t{\"ALTER TABLE t1 TRUNCATE PARTITION ALL\", true, \"ALTER TABLE `t1` TRUNCATE PARTITION ALL\"},\n\t\t{\"ALTER TABLE t1 TRUNCATE PARTITION ALL, p0\", false, \"\"},\n\t\t{\"ALTER TABLE t1 TRUNCATE PARTITION p0, ALL\", false, \"\"},\n\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION p0\", true, \"ALTER TABLE `t1` OPTIMIZE PARTITION `p0`\"},\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION NO_WRITE_TO_BINLOG p0\", true, \"ALTER TABLE `t1` OPTIMIZE PARTITION NO_WRITE_TO_BINLOG `p0`\"},\n\t\t// LOCAL is alias to NO_WRITE_TO_BINLOG\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION LOCAL p0\", true, \"ALTER TABLE `t1` OPTIMIZE PARTITION NO_WRITE_TO_BINLOG `p0`\"},\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION p0, p1\", true, \"ALTER TABLE `t1` OPTIMIZE PARTITION `p0`,`p1`\"},\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION NO_WRITE_TO_BINLOG p0, p1\", true, \"ALTER TABLE `t1` OPTIMIZE PARTITION NO_WRITE_TO_BINLOG `p0`,`p1`\"},\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION LOCAL p0, p1\", true, \"ALTER TABLE `t1` OPTIMIZE PARTITION NO_WRITE_TO_BINLOG `p0`,`p1`\"},\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION ALL\", true, \"ALTER TABLE `t1` OPTIMIZE PARTITION ALL\"},\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION NO_WRITE_TO_BINLOG ALL\", true, \"ALTER TABLE `t1` OPTIMIZE PARTITION NO_WRITE_TO_BINLOG ALL\"},\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION LOCAL ALL\", true, \"ALTER TABLE `t1` OPTIMIZE PARTITION NO_WRITE_TO_BINLOG ALL\"},\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION ALL, p0\", false, \"\"},\n\t\t{\"ALTER TABLE t1 OPTIMIZE PARTITION p0, ALL\", false, \"\"},\n\t\t// The first `LOCAL` should be recognized as unreserved keyword `LOCAL` (alias to `NO_WRITE_TO_BINLOG`),\n\t\t// and the remains should re recognized as identifier, used as partition name here.\n\t\t{\"ALTER TABLE t_n OPTIMIZE PARTITION LOCAL\", false, \"\"},\n\t\t{\"ALTER TABLE t_n OPTIMIZE PARTITION LOCAL local\", true, \"ALTER TABLE `t_n` OPTIMIZE PARTITION NO_WRITE_TO_BINLOG `local`\"},\n\t\t{\"ALTER TABLE t_n OPTIMIZE PARTITION LOCAL local, local\", true, \"ALTER TABLE `t_n` OPTIMIZE PARTITION NO_WRITE_TO_BINLOG `local`,`local`\"},\n\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION p0\", true, \"ALTER TABLE `t1` REPAIR PARTITION `p0`\"},\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION NO_WRITE_TO_BINLOG p0\", true, \"ALTER TABLE `t1` REPAIR PARTITION NO_WRITE_TO_BINLOG `p0`\"},\n\t\t// LOCAL is alias to NO_WRITE_TO_BINLOG\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION LOCAL p0\", true, \"ALTER TABLE `t1` REPAIR PARTITION NO_WRITE_TO_BINLOG `p0`\"},\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION p0, p1\", true, \"ALTER TABLE `t1` REPAIR PARTITION `p0`,`p1`\"},\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION NO_WRITE_TO_BINLOG p0, p1\", true, \"ALTER TABLE `t1` REPAIR PARTITION NO_WRITE_TO_BINLOG `p0`,`p1`\"},\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION LOCAL p0, p1\", true, \"ALTER TABLE `t1` REPAIR PARTITION NO_WRITE_TO_BINLOG `p0`,`p1`\"},\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION ALL\", true, \"ALTER TABLE `t1` REPAIR PARTITION ALL\"},\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION NO_WRITE_TO_BINLOG ALL\", true, \"ALTER TABLE `t1` REPAIR PARTITION NO_WRITE_TO_BINLOG ALL\"},\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION LOCAL ALL\", true, \"ALTER TABLE `t1` REPAIR PARTITION NO_WRITE_TO_BINLOG ALL\"},\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION ALL, p0\", false, \"\"},\n\t\t{\"ALTER TABLE t1 REPAIR PARTITION p0, ALL\", false, \"\"},\n\t\t// The first `LOCAL` should be recognized as unreserved keyword `LOCAL` (alias to `NO_WRITE_TO_BINLOG`),\n\t\t// and the remains should re recognized as identifier, used as partition name here.\n\t\t{\"ALTER TABLE t_n REPAIR PARTITION LOCAL\", false, \"\"},\n\t\t{\"ALTER TABLE t_n REPAIR PARTITION LOCAL local\", true, \"ALTER TABLE `t_n` REPAIR PARTITION NO_WRITE_TO_BINLOG `local`\"},\n\t\t{\"ALTER TABLE t_n REPAIR PARTITION LOCAL local, local\", true, \"ALTER TABLE `t_n` REPAIR PARTITION NO_WRITE_TO_BINLOG `local`,`local`\"},\n\n\t\t{\"ALTER TABLE t1 IMPORT PARTITION p0 TABLESPACE\", true, \"ALTER TABLE `t1` IMPORT PARTITION `p0` TABLESPACE\"},\n\t\t{\"ALTER TABLE t1 IMPORT PARTITION p0, p1 TABLESPACE\", true, \"ALTER TABLE `t1` IMPORT PARTITION `p0`,`p1` TABLESPACE\"},\n\t\t{\"ALTER TABLE t1 IMPORT PARTITION ALL TABLESPACE\", true, \"ALTER TABLE `t1` IMPORT PARTITION ALL TABLESPACE\"},\n\t\t{\"ALTER TABLE t1 IMPORT PARTITION ALL, p0 TABLESPACE\", false, \"\"},\n\t\t{\"ALTER TABLE t1 IMPORT PARTITION p0, ALL TABLESPACE\", false, \"\"},\n\n\t\t{\"ALTER TABLE t1 DISCARD PARTITION p0 TABLESPACE\", true, \"ALTER TABLE `t1` DISCARD PARTITION `p0` TABLESPACE\"},\n\t\t{\"ALTER TABLE t1 DISCARD PARTITION p0, p1 TABLESPACE\", true, \"ALTER TABLE `t1` DISCARD PARTITION `p0`,`p1` TABLESPACE\"},\n\t\t{\"ALTER TABLE t1 DISCARD PARTITION ALL TABLESPACE\", true, \"ALTER TABLE `t1` DISCARD PARTITION ALL TABLESPACE\"},\n\t\t{\"ALTER TABLE t1 DISCARD PARTITION ALL, p0 TABLESPACE\", false, \"\"},\n\t\t{\"ALTER TABLE t1 DISCARD PARTITION p0, ALL TABLESPACE\", false, \"\"},\n\n\t\t{\"ALTER TABLE t1 ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT 'APSTART \\\\' APEND')\", true, \"ALTER TABLE `t1` ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'APSTART '' APEND')\"},\n\t\t{\"ALTER TABLE t1 ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'xxx')\", true, \"ALTER TABLE `t1` ADD PARTITION (PARTITION `p5` VALUES LESS THAN (2010) COMMENT = 'xxx')\"},\n\t\t// {`CREATE TABLE t1 (a int not null,b int not null,c int not null,primary key(a,b))\n\t\t// partition by range (a)\n\t\t// partitions 3\n\t\t// (partition x1 values less than (5),\n\t\t//  partition x2 values less than (10),\n\t\t//  partition x3 values less than maxvalue);`, true, \"CREATE TABLE `t1` (`a` INT NOT NULL,`b` INT NOT NULL,`c` INT NOT NULL,PRIMARY KEY(`a`, `b`)) PARTITION BY RANGE (`a`) (PARTITION `x1` VALUES LESS THAN (5),PARTITION `x2` VALUES LESS THAN (10),PARTITION `x3` VALUES LESS THAN (MAXVALUE))\"},\n\t\t{\"CREATE TABLE t1 (a int not null) partition by range (a) (partition x1 values less than (5) tablespace ts1)\", true, \"CREATE TABLE `t1` (`a` INT NOT NULL) PARTITION BY RANGE (`a`) (PARTITION `x1` VALUES LESS THAN (5) TABLESPACE = `ts1`)\"},\n\t\t{`create table t (a int) partition by range (a)\n\t\t  (PARTITION p0 VALUES LESS THAN (63340531200) ENGINE = MyISAM,\n\t\t   PARTITION p1 VALUES LESS THAN (63342604800) ENGINE MyISAM)`, true, \"CREATE TABLE `t` (`a` INT) PARTITION BY RANGE (`a`) (PARTITION `p0` VALUES LESS THAN (63340531200) ENGINE = MyISAM,PARTITION `p1` VALUES LESS THAN (63342604800) ENGINE = MyISAM)\"},\n\t\t{`create table t (a int) partition by range (a)\n\t\t  (PARTITION p0 VALUES LESS THAN (63340531200) ENGINE = MyISAM COMMENT 'xxx',\n\t\t   PARTITION p1 VALUES LESS THAN (63342604800) ENGINE = MyISAM)`, true, \"CREATE TABLE `t` (`a` INT) PARTITION BY RANGE (`a`) (PARTITION `p0` VALUES LESS THAN (63340531200) ENGINE = MyISAM COMMENT = 'xxx',PARTITION `p1` VALUES LESS THAN (63342604800) ENGINE = MyISAM)\"},\n\t\t{`create table t1 (a int) partition by range (a)\n\t\t  (PARTITION p0 VALUES LESS THAN (63340531200) COMMENT 'xxx' ENGINE = MyISAM ,\n\t\t   PARTITION p1 VALUES LESS THAN (63342604800) ENGINE = MyISAM)`, true, \"CREATE TABLE `t1` (`a` INT) PARTITION BY RANGE (`a`) (PARTITION `p0` VALUES LESS THAN (63340531200) COMMENT = 'xxx' ENGINE = MyISAM,PARTITION `p1` VALUES LESS THAN (63342604800) ENGINE = MyISAM)\"},\n\t\t{`create table t (id int)\n\t\t    partition by range (id)\n\t\t    subpartition by key (id) subpartitions 2\n\t\t    (partition p0 values less than (42))`, true, \"CREATE TABLE `t` (`id` INT) PARTITION BY RANGE (`id`) SUBPARTITION BY KEY (`id`) SUBPARTITIONS 2 (PARTITION `p0` VALUES LESS THAN (42))\"},\n\t\t{`create table t (id int)\n\t\t    partition by range (id)\n\t\t    subpartition by hash (id)\n\t\t    (partition p0 values less than (42))`, true, \"CREATE TABLE `t` (`id` INT) PARTITION BY RANGE (`id`) SUBPARTITION BY HASH (`id`) (PARTITION `p0` VALUES LESS THAN (42))\"},\n\t\t// \t\t{`create table t1 (a varchar(5), b int signed, c varchar(10), d datetime)\n\t\t// \t\tpartition by range columns(b,c)\n\t\t// \t\tsubpartition by hash(to_seconds(d))\n\t\t// \t\t( partition p0 values less than (2, 'b'),\n\t\t// \t\t  partition p1 values less than (4, 'd'),\n\t\t// \t\t  partition p2 values less than (10, 'za'));`, true,\n\t\t// \t\t\t\"CREATE TABLE `t1` (`a` VARCHAR(5),`b` INT,`c` VARCHAR(10),`d` DATETIME) PARTITION BY RANGE COLUMNS (`b`,`c`) SUBPARTITION BY HASH (TO_SECONDS(`d`)) (PARTITION `p0` VALUES LESS THAN (2, 'b'),PARTITION `p1` VALUES LESS THAN (4, 'd'),PARTITION `p2` VALUES LESS THAN (10, 'za'))\"},\n\t\t// \t\t{`CREATE TABLE t1 (a INT, b TIMESTAMP DEFAULT '0000-00-00 00:00:00')\n\t\t// ENGINE=INNODB PARTITION BY LINEAR HASH (a) PARTITIONS 1;`, true, \"CREATE TABLE `t1` (`a` INT,`b` TIMESTAMP DEFAULT '0000-00-00 00:00:00') ENGINE = INNODB PARTITION BY LINEAR HASH (`a`) PARTITIONS 1\"},\n\n\t\t// empty clause is valid only for HASH/KEY partitions\n\t\t{\"create table t1 (a int) partition by hash (a) (partition x, partition y)\", true, \"CREATE TABLE `t1` (`a` INT) PARTITION BY HASH (`a`) (PARTITION `x`,PARTITION `y`)\"},\n\t\t{\"create table t1 (a int) partition by key (a) (partition x, partition y)\", true, \"CREATE TABLE `t1` (`a` INT) PARTITION BY KEY (`a`) (PARTITION `x`,PARTITION `y`)\"},\n\t\t{\"create table t1 (a int) partition by range (a) (partition x, partition y)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by list (a) (partition x, partition y)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by system_time (partition x, partition y)\", false, \"\"},\n\t\t// VALUES LESS THAN clause is valid only for RANGE partitions\n\t\t{\"create table t1 (a int) partition by hash (a) (partition x values less than (10))\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by key (a) (partition x values less than (10))\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by range (a) (partition x values less than (10))\", true, \"CREATE TABLE `t1` (`a` INT) PARTITION BY RANGE (`a`) (PARTITION `x` VALUES LESS THAN (10))\"},\n\t\t{\"create table t1 (a int) partition by list (a) (partition x values less than (10))\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by system_time (partition x values less than (10))\", false, \"\"},\n\t\t// VALUES IN clause is valid only for LIST partitions\n\t\t{\"create table t1 (a int) partition by hash (a) (partition x values in (10))\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by key (a) (partition x values in (10))\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by range (a) (partition x values in (10))\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by list (a) (partition x values in (10))\", true, \"CREATE TABLE `t1` (`a` INT) PARTITION BY LIST (`a`) (PARTITION `x` VALUES IN (10))\"},\n\t\t{\"create table t1 (a int) partition by system_time (partition x values in (10))\", false, \"\"},\n\t\t// HISTORY/CURRENT clauses are valid only for SYSTEM_TIME partitions\n\t\t{\"create table t1 (a int) partition by hash (a) (partition x history, partition y current)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by key (a) (partition x history, partition y current)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by range (a) (partition x history, partition y current)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by list (a) (partition x history, partition y current)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by system_time (partition x history, partition y current)\", true, \"CREATE TABLE `t1` (`a` INT) PARTITION BY SYSTEM_TIME (PARTITION `x` HISTORY,PARTITION `y` CURRENT)\"},\n\n\t\t// LIST, RANGE and SYSTEM_TIME partitions all required definitions\n\t\t{\"create table t1 (a int) partition by hash (a)\", true, \"CREATE TABLE `t1` (`a` INT) PARTITION BY HASH (`a`) PARTITIONS 1\"},\n\t\t{\"create table t1 (a int) partition by key (a)\", true, \"CREATE TABLE `t1` (`a` INT) PARTITION BY KEY (`a`) PARTITIONS 1\"},\n\t\t{\"create table t1 (a int) partition by range (a)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by list (a)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by system_time\", false, \"\"},\n\t\t// SYSTEM_TIME required 2 or more partitions\n\t\t{\"create table t1 (a int) partition by system_time (partition x history)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by system_time (partition x current)\", false, \"\"},\n\n\t\t// number of columns and number of values in VALUES clauses must match\n\t\t{\"create table t1 (a int, b int) partition by range (a) (partition x values less than (10, 20))\", false, \"\"},\n\t\t{\"create table t (id int) partition by range columns (id) (partition p0 values less than (1, 2))\", false, \"\"},\n\t\t{\"create table t1 (a int, b int) partition by range columns (a, b) (partition x values less than (10, 20))\", true, \"CREATE TABLE `t1` (`a` INT,`b` INT) PARTITION BY RANGE COLUMNS (`a`,`b`) (PARTITION `x` VALUES LESS THAN (10, 20))\"},\n\t\t{\"create table t1 (a int, b int) partition by range columns (a, b) (partition x values less than (10))\", false, \"\"},\n\t\t{\"create table t1 (a int, b int) partition by range columns (a, b) (partition x values less than maxvalue)\", false, \"\"},\n\t\t{\"create table t1 (a int, b int) partition by list (a) (partition x values in ((10, 20)))\", false, \"\"},\n\t\t{\"create table t1 (a int, b int) partition by list columns (a, b) (partition x values in ((10, 20)))\", true, \"CREATE TABLE `t1` (`a` INT,`b` INT) PARTITION BY LIST COLUMNS (`a`,`b`) (PARTITION `x` VALUES IN ((10, 20)))\"},\n\t\t{\"create table t1 (a int, b int) partition by list columns (a, b) (partition x values in (10, 20))\", false, \"\"},\n\t\t{\"create table t1 (a int, b int) partition by list columns (a, b) (partition x values in (10, (20, 30)))\", false, \"\"},\n\t\t{\"create table t1 (a int, b int) partition by list columns (a, b) (partition x values in ((10, 20), 30))\", false, \"\"},\n\t\t{\"create table t1 (a int, b int) partition by list columns (a, b) (partition x values in ((10, 20), (30, 40, 50)))\", false, \"\"},\n\n\t\t// there must be at least one column/partition/value inside (...)\n\t\t{\"create table t1 (a int) partition by hash (a) ()\", false, \"\"},\n\t\t{\"create table t1 (a int primary key) partition by key ()\", true, \"CREATE TABLE `t1` (`a` INT PRIMARY KEY) PARTITION BY KEY () PARTITIONS 1\"},\n\t\t{\"create table t1 (a int) partition by range columns () (partition x values less than maxvalue)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by list columns () (partition x default)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by range (a) (partition x values less than ())\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by list (a) (partition x values in ())\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by list (a) (partition x default)\", true, \"CREATE TABLE `t1` (`a` INT) PARTITION BY LIST (`a`) (PARTITION `x` DEFAULT)\"},\n\n\t\t// only hash and key subpartitions are allowed\n\t\t{\"create table t1 (a int, b int) partition by range (a) subpartition by range (b) (partition x values less than maxvalue)\", false, \"\"},\n\n\t\t// number of partitions/subpartitions must be matching\n\t\t{\"create table t1 (a int) partition by hash (a) partitions 2 (partition x)\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by hash (a) partitions 2 (partition x, partition y)\", true, \"CREATE TABLE `t1` (`a` INT) PARTITION BY HASH (`a`) (PARTITION `x`,PARTITION `y`)\"},\n\t\t{\"create table t1 (a int, b int) partition by range (a) subpartition by hash (b) subpartitions 2 (partition x values less than maxvalue (subpartition y))\", false, \"\"},\n\t\t{\n\t\t\t\"create table t1 (a int, b int) partition by range (a) subpartition by hash (b) subpartitions 2 (partition x values less than maxvalue (subpartition y, subpartition z))\", true,\n\t\t\t\"CREATE TABLE `t1` (`a` INT,`b` INT) PARTITION BY RANGE (`a`) SUBPARTITION BY HASH (`b`) SUBPARTITIONS 2 (PARTITION `x` VALUES LESS THAN (MAXVALUE) (SUBPARTITION `y`,SUBPARTITION `z`))\",\n\t\t},\n\t\t{\n\t\t\t\"create table t1 (a int, b int) partition by range (a) subpartition by hash (b) (partition x values less than (10) (subpartition y,subpartition z),partition a values less than (20) (subpartition b,subpartition c))\", true,\n\t\t\t\"CREATE TABLE `t1` (`a` INT,`b` INT) PARTITION BY RANGE (`a`) SUBPARTITION BY HASH (`b`) SUBPARTITIONS 2 (PARTITION `x` VALUES LESS THAN (10) (SUBPARTITION `y`,SUBPARTITION `z`),PARTITION `a` VALUES LESS THAN (20) (SUBPARTITION `b`,SUBPARTITION `c`))\",\n\t\t},\n\t\t{\"create table t1 (a int, b int) partition by range (a) subpartition by hash (b) (partition x values less than (10) (subpartition y),partition a values less than (20) (subpartition b,subpartition c))\", false, \"\"},\n\t\t{\"create table t1 (a int, b int) partition by range (a) (partition x values less than (10) (subpartition y))\", false, \"\"},\n\t\t{\"create table t1 (a int) partition by hash (a) partitions 0\", false, \"\"},\n\t\t{\"create table t1 (a int, b int) partition by range (a) subpartition by hash (b) subpartitions 0 (partition x values less than (10))\", false, \"\"},\n\n\t\t// other partition tests\n\t\t{\"create table t1 (a int) partition by system_time interval 7 day limit 50000 (partition x history, partition y current)\", false, \"\"},\n\t\t{\n\t\t\t\"create table t1 (a int) partition by system_time interval 7 day (partition x history, partition y current)\", true,\n\t\t\t\"CREATE TABLE `t1` (`a` INT) PARTITION BY SYSTEM_TIME INTERVAL 7 DAY (PARTITION `x` HISTORY,PARTITION `y` CURRENT)\",\n\t\t},\n\t\t{\n\t\t\t\"create table t1 (a int) partition by system_time limit 50000 (partition x history, partition y current)\", true,\n\t\t\t\"CREATE TABLE `t1` (`a` INT) PARTITION BY SYSTEM_TIME LIMIT 50000 (PARTITION `x` HISTORY,PARTITION `y` CURRENT)\",\n\t\t},\n\t\t{\n\t\t\t\"create table t1 (a int) partition by hash(a) (partition x engine InnoDB comment 'xxxx' data directory '/var/data' index directory '/var/index' max_rows 70000 min_rows 50 tablespace `innodb_file_per_table` nodegroup 255)\", true,\n\t\t\t\"CREATE TABLE `t1` (`a` INT) PARTITION BY HASH (`a`) (PARTITION `x` ENGINE = InnoDB COMMENT = 'xxxx' DATA DIRECTORY = '/var/data' INDEX DIRECTORY = '/var/index' MAX_ROWS = 70000 MIN_ROWS = 50 TABLESPACE = `innodb_file_per_table` NODEGROUP = 255)\",\n\t\t},\n\t\t{\n\t\t\t\"create table t1 (a int, b int) partition by range(a) subpartition by hash(b) (partition x values less than maxvalue (subpartition y engine InnoDB comment 'xxxx' data directory '/var/data' index directory '/var/index' max_rows 70000 min_rows 50 tablespace `innodb_file_per_table` nodegroup 255))\", true,\n\t\t\t\"CREATE TABLE `t1` (`a` INT,`b` INT) PARTITION BY RANGE (`a`) SUBPARTITION BY HASH (`b`) SUBPARTITIONS 1 (PARTITION `x` VALUES LESS THAN (MAXVALUE) (SUBPARTITION `y` ENGINE = InnoDB COMMENT = 'xxxx' DATA DIRECTORY = '/var/data' INDEX DIRECTORY = '/var/index' MAX_ROWS = 70000 MIN_ROWS = 50 TABLESPACE = `innodb_file_per_table` NODEGROUP = 255))\",\n\t\t},\n\t}\n\ts.RunTest(c, table)\n\n\t// Check comment content.\n\tparser := parser.New()\n\tstmt, err := parser.ParseOneStmt(\"create table t (id int) partition by range (id) (partition p0 values less than (10) comment 'check')\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tcreateTable := stmt.(*ast.CreateTableStmt)\n\tcomment, ok := createTable.Partition.Definitions[0].Comment()\n\tc.Assert(ok, IsTrue)\n\tc.Assert(comment, Equals, \"check\")\n}\n\nfunc (s *testParserSuite) TestTablePartitionNameList(c *C) {\n\ttable := []testCase{\n\t\t{`select * from t partition (p0,p1)`, true, \"\"},\n\t}\n\n\tparser := parser.New()\n\tfor _, tt := range table {\n\t\tstmt, _, err := parser.Parse(tt.src, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\n\t\tsel := stmt[0].(*ast.SelectStmt)\n\t\tsource, ok := sel.From.TableRefs.Left.(*ast.TableSource)\n\t\tc.Assert(ok, IsTrue)\n\t\ttableName, ok := source.Source.(*ast.TableName)\n\t\tc.Assert(ok, IsTrue)\n\t\tc.Assert(len(tableName.PartitionNames), Equals, 2)\n\t\tc.Assert(tableName.PartitionNames[0], Equals, model.CIStr{O: \"p0\", L: \"p0\"})\n\t\tc.Assert(tableName.PartitionNames[1], Equals, model.CIStr{O: \"p1\", L: \"p1\"})\n\t}\n}\n\nfunc (s *testParserSuite) TestNotExistsSubquery(c *C) {\n\ttable := []testCase{\n\t\t{`select * from t1 where not exists (select * from t2 where t1.a = t2.a)`, true, \"\"},\n\t}\n\n\tparser := parser.New()\n\tfor _, tt := range table {\n\t\tstmt, _, err := parser.Parse(tt.src, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\n\t\tsel := stmt[0].(*ast.SelectStmt)\n\t\texists, ok := sel.Where.(*ast.ExistsSubqueryExpr)\n\t\tc.Assert(ok, IsTrue)\n\t\tc.Assert(exists.Not, Equals, tt.ok)\n\t}\n}\n\nfunc (s *testParserSuite) TestWindowFunctionIdentifier(c *C) {\n\tvar table []testCase\n\ts.enableWindowFunc = true\n\tfor key := range parser.WindowFuncTokenMapForTest {\n\t\ttable = append(table, testCase{fmt.Sprintf(\"select 1 %s\", key), false, fmt.Sprintf(\"SELECT 1 AS `%s`\", key)})\n\t}\n\ts.RunTest(c, table)\n\n\t// s.enableWindowFunc = false\n\t// for i := range table {\n\t// \ttable[i].ok = true\n\t// }\n\t// s.RunTest(c, table)\n}\n\nfunc (s *testParserSuite) TestWindowFunctions(c *C) {\n\ttable := []testCase{\n\t\t// For window function descriptions.\n\t\t// See https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html\n\t\t{`SELECT CUME_DIST() OVER w FROM t;`, true, \"SELECT CUME_DIST() OVER `w` FROM `t`\"},\n\t\t{`SELECT DENSE_RANK() OVER (w) FROM t;`, true, \"SELECT DENSE_RANK() OVER (`w`) FROM `t`\"},\n\t\t{`SELECT FIRST_VALUE(val) OVER w FROM t;`, true, \"SELECT FIRST_VALUE(`val`) OVER `w` FROM `t`\"},\n\t\t{`SELECT FIRST_VALUE(val) RESPECT NULLS OVER w FROM t;`, true, \"SELECT FIRST_VALUE(`val`) OVER `w` FROM `t`\"},\n\t\t{`SELECT FIRST_VALUE(val) IGNORE NULLS OVER w FROM t;`, true, \"SELECT FIRST_VALUE(`val`) IGNORE NULLS OVER `w` FROM `t`\"},\n\t\t{`SELECT LAG(val) OVER (w) FROM t;`, true, \"SELECT LAG(`val`) OVER (`w`) FROM `t`\"},\n\t\t{`SELECT LAG(val, 1) OVER (w) FROM t;`, true, \"SELECT LAG(`val`, 1) OVER (`w`) FROM `t`\"},\n\t\t{`SELECT LAG(val, 1, def) OVER (w) FROM t;`, true, \"SELECT LAG(`val`, 1, `def`) OVER (`w`) FROM `t`\"},\n\t\t{`SELECT LAST_VALUE(val) OVER (w) FROM t;`, true, \"SELECT LAST_VALUE(`val`) OVER (`w`) FROM `t`\"},\n\t\t{`SELECT LEAD(val) OVER w FROM t;`, true, \"SELECT LEAD(`val`) OVER `w` FROM `t`\"},\n\t\t{`SELECT LEAD(val, 1) OVER w FROM t;`, true, \"SELECT LEAD(`val`, 1) OVER `w` FROM `t`\"},\n\t\t{`SELECT LEAD(val, 1, def) OVER w FROM t;`, true, \"SELECT LEAD(`val`, 1, `def`) OVER `w` FROM `t`\"},\n\t\t{`SELECT NTH_VALUE(val, 233) OVER w FROM t;`, true, \"SELECT NTH_VALUE(`val`, 233) OVER `w` FROM `t`\"},\n\t\t{`SELECT NTH_VALUE(val, 233) FROM FIRST OVER w FROM t;`, true, \"SELECT NTH_VALUE(`val`, 233) OVER `w` FROM `t`\"},\n\t\t{`SELECT NTH_VALUE(val, 233) FROM LAST OVER w FROM t;`, true, \"SELECT NTH_VALUE(`val`, 233) FROM LAST OVER `w` FROM `t`\"},\n\t\t{`SELECT NTH_VALUE(val, 233) FROM LAST IGNORE NULLS OVER w FROM t;`, true, \"SELECT NTH_VALUE(`val`, 233) FROM LAST IGNORE NULLS OVER `w` FROM `t`\"},\n\t\t{`SELECT NTH_VALUE(val) OVER w FROM t;`, false, \"\"},\n\t\t{`SELECT NTILE(233) OVER (w) FROM t;`, true, \"SELECT NTILE(233) OVER (`w`) FROM `t`\"},\n\t\t{`SELECT PERCENT_RANK() OVER (w) FROM t;`, true, \"SELECT PERCENT_RANK() OVER (`w`) FROM `t`\"},\n\t\t{`SELECT RANK() OVER (w) FROM t;`, true, \"SELECT RANK() OVER (`w`) FROM `t`\"},\n\t\t{`SELECT ROW_NUMBER() OVER (w) FROM t;`, true, \"SELECT ROW_NUMBER() OVER (`w`) FROM `t`\"},\n\t\t{`SELECT n, LAG(n, 1, 0) OVER (w), LEAD(n, 1, 0) OVER w, n + LAG(n, 1, 0) OVER (w) FROM fib;`, true, \"SELECT `n`,LAG(`n`, 1, 0) OVER (`w`),LEAD(`n`, 1, 0) OVER `w`,`n`+LAG(`n`, 1, 0) OVER (`w`) FROM `fib`\"},\n\n\t\t// For window function concepts and syntax.\n\t\t// See https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html\n\t\t{`SELECT SUM(profit) OVER(PARTITION BY country) AS country_profit FROM sales;`, true, \"SELECT SUM(`profit`) OVER (PARTITION BY `country`) AS `country_profit` FROM `sales`\"},\n\t\t{`SELECT SUM(profit) OVER() AS country_profit FROM sales;`, true, \"SELECT SUM(`profit`) OVER () AS `country_profit` FROM `sales`\"},\n\t\t{`SELECT AVG(profit) OVER() AS country_profit FROM sales;`, true, \"SELECT AVG(`profit`) OVER () AS `country_profit` FROM `sales`\"},\n\t\t{`SELECT BIT_XOR(profit) OVER() AS country_profit FROM sales;`, true, \"SELECT BIT_XOR(`profit`) OVER () AS `country_profit` FROM `sales`\"},\n\t\t{`SELECT COUNT(profit) OVER() AS country_profit FROM sales;`, true, \"SELECT COUNT(`profit`) OVER () AS `country_profit` FROM `sales`\"},\n\t\t{`SELECT COUNT(ALL profit) OVER() AS country_profit FROM sales;`, true, \"SELECT COUNT(`profit`) OVER () AS `country_profit` FROM `sales`\"},\n\t\t{`SELECT COUNT(*) OVER() AS country_profit FROM sales;`, true, \"SELECT COUNT(1) OVER () AS `country_profit` FROM `sales`\"},\n\t\t{`SELECT MAX(profit) OVER() AS country_profit FROM sales;`, true, \"SELECT MAX(`profit`) OVER () AS `country_profit` FROM `sales`\"},\n\t\t{`SELECT MIN(profit) OVER() AS country_profit FROM sales;`, true, \"SELECT MIN(`profit`) OVER () AS `country_profit` FROM `sales`\"},\n\t\t{`SELECT SUM(profit) OVER() AS country_profit FROM sales;`, true, \"SELECT SUM(`profit`) OVER () AS `country_profit` FROM `sales`\"},\n\t\t{`SELECT ROW_NUMBER() OVER(PARTITION BY country) AS row_num1 FROM sales;`, true, \"SELECT ROW_NUMBER() OVER (PARTITION BY `country`) AS `row_num1` FROM `sales`\"},\n\t\t{`SELECT ROW_NUMBER() OVER(PARTITION BY country, d ORDER BY year, product) AS row_num2 FROM sales;`, true, \"SELECT ROW_NUMBER() OVER (PARTITION BY `country`, `d` ORDER BY `year`,`product`) AS `row_num2` FROM `sales`\"},\n\t\t{`SELECT ROW_NUMBER() OVER(ORDER BY year, product) AS row_num2 FROM sales;`, true, \"SELECT ROW_NUMBER() OVER (ORDER BY `year`,`product`) AS `row_num2` FROM `sales`\"},\n\t\t{`SELECT RANK() OVER(ORDER BY year, product) AS row_num2 FROM sales;`, true, \"SELECT RANK() OVER (ORDER BY `year`,`product`) AS `row_num2` FROM `sales`\"},\n\n\t\t// For window function frame specification.\n\t\t// See https://dev.mysql.com/doc/refman/8.0/en/window-functions-frames.html\n\t\t{`SELECT SUM(val) OVER (PARTITION BY subject ORDER BY time ROWS UNBOUNDED PRECEDING) FROM t;`, true, \"SELECT SUM(`val`) OVER (PARTITION BY `subject` ORDER BY `time` ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM `t`\"},\n\t\t{`SELECT AVG(val) OVER (PARTITION BY subject ORDER BY time ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t;`, true, \"SELECT AVG(`val`) OVER (PARTITION BY `subject` ORDER BY `time` ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM `t`\"},\n\t\t{`SELECT AVG(val) OVER (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t;`, true, \"SELECT AVG(`val`) OVER (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM `t`\"},\n\t\t{`SELECT AVG(val) OVER (ROWS BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING) FROM t;`, true, \"SELECT AVG(`val`) OVER (ROWS BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING) FROM `t`\"},\n\t\t{`SELECT AVG(val) OVER (RANGE BETWEEN INTERVAL 5 DAY PRECEDING AND INTERVAL '2:30' MINUTE_SECOND FOLLOWING) FROM t;`, true, \"SELECT AVG(`val`) OVER (RANGE BETWEEN INTERVAL 5 DAY PRECEDING AND INTERVAL '2:30' MINUTE_SECOND FOLLOWING) FROM `t`\"},\n\t\t{`SELECT AVG(val) OVER (RANGE BETWEEN CURRENT ROW AND CURRENT ROW) FROM t;`, true, \"SELECT AVG(`val`) OVER (RANGE BETWEEN CURRENT ROW AND CURRENT ROW) FROM `t`\"},\n\t\t{`SELECT AVG(val) OVER (RANGE CURRENT ROW) FROM t;`, true, \"SELECT AVG(`val`) OVER (RANGE BETWEEN CURRENT ROW AND CURRENT ROW) FROM `t`\"},\n\n\t\t// For named windows.\n\t\t// See https://dev.mysql.com/doc/refman/8.0/en/window-functions-named-windows.html\n\t\t{`SELECT RANK() OVER (w) FROM t WINDOW w AS (ORDER BY val);`, true, \"SELECT RANK() OVER (`w`) FROM `t` WINDOW `w` AS (ORDER BY `val`)\"},\n\t\t{`SELECT RANK() OVER w FROM t WINDOW w AS ();`, true, \"SELECT RANK() OVER `w` FROM `t` WINDOW `w` AS ()\"},\n\t\t{`SELECT FIRST_VALUE(year) OVER (w ORDER BY year ASC) AS first FROM sales WINDOW w AS (PARTITION BY country);`, true, \"SELECT FIRST_VALUE(`year`) OVER (`w` ORDER BY `year`) AS `first` FROM `sales` WINDOW `w` AS (PARTITION BY `country`)\"},\n\t\t{`SELECT RANK() OVER (w1) FROM t WINDOW w1 AS (w2), w2 AS (), w3 AS (w1);`, true, \"SELECT RANK() OVER (`w1`) FROM `t` WINDOW `w1` AS (`w2`),`w2` AS (),`w3` AS (`w1`)\"},\n\t\t{`SELECT RANK() OVER w1 FROM t WINDOW w1 AS (w2), w2 AS (w3), w3 AS (w1);`, true, \"SELECT RANK() OVER `w1` FROM `t` WINDOW `w1` AS (`w2`),`w2` AS (`w3`),`w3` AS (`w1`)\"},\n\n\t\t// For tidb_parse_tso\n\t\t{`select tidb_parse_tso(1)`, true, \"SELECT TIDB_PARSE_TSO(1)\"},\n\t\t{`select from_unixtime(404411537129996288)`, true, \"SELECT FROM_UNIXTIME(404411537129996288)\"},\n\t\t{`select from_unixtime(404411537129996288.22)`, true, \"SELECT FROM_UNIXTIME(404411537129996288.22)\"},\n\t}\n\ts.enableWindowFunc = true\n\ts.RunTest(c, table)\n}\n\ntype windowFrameBoundChecker struct {\n\tfb     *ast.FrameBound\n\texprRc int\n\tunit   ast.TimeUnitType\n\tc      *C\n}\n\n// Enter implements ast.Visitor interface.\nfunc (wfc *windowFrameBoundChecker) Enter(inNode ast.Node) (outNode ast.Node, skipChildren bool) {\n\tif _, ok := inNode.(*ast.FrameBound); ok {\n\t\twfc.fb = inNode.(*ast.FrameBound)\n\t\tif wfc.fb.Unit != ast.TimeUnitInvalid {\n\t\t\t_, ok := wfc.fb.Expr.(ast.ValueExpr)\n\t\t\twfc.c.Assert(ok, IsFalse)\n\t\t}\n\t}\n\treturn inNode, false\n}\n\n// Leave implements ast.Visitor interface.\nfunc (wfc *windowFrameBoundChecker) Leave(inNode ast.Node) (node ast.Node, ok bool) {\n\tif _, ok := inNode.(*ast.FrameBound); ok {\n\t\twfc.fb = nil\n\t}\n\tif wfc.fb != nil {\n\t\tif inNode == wfc.fb.Expr {\n\t\t\twfc.exprRc++\n\t\t}\n\t\twfc.unit = wfc.fb.Unit\n\t}\n\treturn inNode, true\n}\n\n// For issue #51\n// See https://github.com/pingcap/parser/pull/51 for details\nfunc (s *testParserSuite) TestVisitFrameBound(c *C) {\n\tparser := parser.New()\n\tparser.EnableWindowFunc(true)\n\ttable := []struct {\n\t\ts      string\n\t\texprRc int\n\t\tunit   ast.TimeUnitType\n\t}{\n\t\t{`SELECT AVG(val) OVER (RANGE INTERVAL 1+3 MINUTE_SECOND PRECEDING) FROM t;`, 1, ast.TimeUnitMinuteSecond},\n\t\t{`SELECT AVG(val) OVER (RANGE 5 PRECEDING) FROM t;`, 1, ast.TimeUnitInvalid},\n\t\t{`SELECT AVG(val) OVER () FROM t;`, 0, ast.TimeUnitInvalid},\n\t}\n\tfor _, t := range table {\n\t\tstmt, err := parser.ParseOneStmt(t.s, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\t\tchecker := windowFrameBoundChecker{c: c}\n\t\tstmt.Accept(&checker)\n\t\tc.Assert(checker.exprRc, Equals, t.exprRc)\n\t\tc.Assert(checker.unit, Equals, t.unit)\n\t}\n\n}\n\nfunc (s *testParserSuite) TestFieldText(c *C) {\n\tparser := parser.New()\n\tstmts, _, err := parser.Parse(\"select a from t\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\ttmp := stmts[0].(*ast.SelectStmt)\n\tc.Assert(tmp.Fields.Fields[0].Text(), Equals, \"a\")\n\n\tsqls := []string{\n\t\t\"trace select a from t\",\n\t\t\"trace format = 'row' select a from t\",\n\t\t\"trace format = 'json' select a from t\",\n\t}\n\tfor _, sql := range sqls {\n\t\tstmts, _, err = parser.Parse(sql, \"\", \"\")\n\t\tc.Assert(err, IsNil)\n\t\ttraceStmt := stmts[0].(*ast.TraceStmt)\n\t\tc.Assert(traceStmt.Text(), Equals, sql)\n\t\tc.Assert(traceStmt.Stmt.Text(), Equals, \"select a from t\")\n\t}\n}\n\nfunc (s *testParserSuite) TestQuotedSystemVariables(c *C) {\n\tparser := parser.New()\n\n\tst, err := parser.ParseOneStmt(\n\t\t\"select @@Sql_Mode, @@`SQL_MODE`, @@session.`sql_mode`, @@global.`s ql``mode`, @@session.'sql\\\\nmode', @@local.\\\"sql\\\\\\\"mode\\\";\",\n\t\t\"\",\n\t\t\"\",\n\t)\n\tc.Assert(err, IsNil)\n\tss := st.(*ast.SelectStmt)\n\texpected := []*ast.VariableExpr{\n\t\t{\n\t\t\tName:          \"sql_mode\",\n\t\t\tIsGlobal:      false,\n\t\t\tIsSystem:      true,\n\t\t\tExplicitScope: false,\n\t\t},\n\t\t{\n\t\t\tName:          \"sql_mode\",\n\t\t\tIsGlobal:      false,\n\t\t\tIsSystem:      true,\n\t\t\tExplicitScope: false,\n\t\t},\n\t\t{\n\t\t\tName:          \"sql_mode\",\n\t\t\tIsGlobal:      false,\n\t\t\tIsSystem:      true,\n\t\t\tExplicitScope: true,\n\t\t},\n\t\t{\n\t\t\tName:          \"s ql`mode\",\n\t\t\tIsGlobal:      true,\n\t\t\tIsSystem:      true,\n\t\t\tExplicitScope: true,\n\t\t},\n\t\t{\n\t\t\tName:          \"sql\\nmode\",\n\t\t\tIsGlobal:      false,\n\t\t\tIsSystem:      true,\n\t\t\tExplicitScope: true,\n\t\t},\n\t\t{\n\t\t\tName:          `sql\"mode`,\n\t\t\tIsGlobal:      false,\n\t\t\tIsSystem:      true,\n\t\t\tExplicitScope: true,\n\t\t},\n\t}\n\n\tc.Assert(len(ss.Fields.Fields), Equals, len(expected))\n\tfor i, field := range ss.Fields.Fields {\n\t\tve := field.Expr.(*ast.VariableExpr)\n\t\tcmt := Commentf(\"field %d, ve = %v\", i, ve)\n\t\tc.Assert(ve.Name, Equals, expected[i].Name, cmt)\n\t\tc.Assert(ve.IsGlobal, Equals, expected[i].IsGlobal, cmt)\n\t\tc.Assert(ve.IsSystem, Equals, expected[i].IsSystem, cmt)\n\t\tc.Assert(ve.ExplicitScope, Equals, expected[i].ExplicitScope, cmt)\n\t}\n}\n\n// See https://github.com/pingcap/parser/issues/95\nfunc (s *testParserSuite) TestQuotedVariableColumnName(c *C) {\n\tparser := parser.New()\n\n\tst, err := parser.ParseOneStmt(\n\t\t\"select @abc, @`abc`, @'aBc', @\\\"AbC\\\", @6, @`6`, @'6', @\\\"6\\\", @@sql_mode, @@`sql_mode`, @;\",\n\t\t\"\",\n\t\t\"\",\n\t)\n\tc.Assert(err, IsNil)\n\tss := st.(*ast.SelectStmt)\n\texpected := []string{\n\t\t\"@abc\",\n\t\t\"@`abc`\",\n\t\t\"@'aBc'\",\n\t\t`@\"AbC\"`,\n\t\t\"@6\",\n\t\t\"@`6`\",\n\t\t\"@'6'\",\n\t\t`@\"6\"`,\n\t\t\"@@sql_mode\",\n\t\t\"@@`sql_mode`\",\n\t\t\"@\",\n\t}\n\n\tc.Assert(len(ss.Fields.Fields), Equals, len(expected))\n\tfor i, field := range ss.Fields.Fields {\n\t\tc.Assert(field.Text(), Equals, expected[i])\n\t}\n}\n\nfunc (s *testParserSuite) TestCharset(c *C) {\n\tparser := parser.New()\n\n\tst, err := parser.ParseOneStmt(\"ALTER SCHEMA GLOBAL DEFAULT CHAR SET utf8mb4\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(st.(*ast.AlterDatabaseStmt), NotNil)\n\tst, err = parser.ParseOneStmt(\"ALTER DATABASE CHAR SET = utf8mb4\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(st.(*ast.AlterDatabaseStmt), NotNil)\n\tst, err = parser.ParseOneStmt(\"ALTER DATABASE DEFAULT CHAR SET = utf8mb4\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(st.(*ast.AlterDatabaseStmt), NotNil)\n}\n\nfunc (s *testParserSuite) TestFulltextSearch(c *C) {\n\tparser := parser.New()\n\n\tst, err := parser.ParseOneStmt(\"SELECT * FROM fulltext_test WHERE MATCH(content) AGAINST('search')\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(st.(*ast.SelectStmt), NotNil)\n\n\tst, err = parser.ParseOneStmt(\"SELECT * FROM fulltext_test WHERE MATCH() AGAINST('search')\", \"\", \"\")\n\tc.Assert(err, NotNil)\n\tc.Assert(st, IsNil)\n\n\tst, err = parser.ParseOneStmt(\"SELECT * FROM fulltext_test WHERE MATCH(content) AGAINST()\", \"\", \"\")\n\tc.Assert(err, NotNil)\n\tc.Assert(st, IsNil)\n\n\tst, err = parser.ParseOneStmt(\"SELECT * FROM fulltext_test WHERE MATCH(content) AGAINST('search' IN)\", \"\", \"\")\n\tc.Assert(err, NotNil)\n\tc.Assert(st, IsNil)\n\n\tst, err = parser.ParseOneStmt(\"SELECT * FROM fulltext_test WHERE MATCH(content) AGAINST('search' IN BOOLEAN MODE WITH QUERY EXPANSION)\", \"\", \"\")\n\tc.Assert(err, NotNil)\n\tc.Assert(st, IsNil)\n\n\tst, err = parser.ParseOneStmt(\"SELECT * FROM fulltext_test WHERE MATCH(title,content) AGAINST('search' IN NATURAL LANGUAGE MODE)\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(st.(*ast.SelectStmt), NotNil)\n\twriter := bytes.NewBufferString(\"\")\n\tst.(*ast.SelectStmt).Where.Format(writer)\n\tc.Assert(writer.String(), Equals, \"MATCH(title,content) AGAINST(\\\"search\\\")\")\n\n\tst, err = parser.ParseOneStmt(\"SELECT * FROM fulltext_test WHERE MATCH(title,content) AGAINST('search' IN BOOLEAN MODE)\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(st.(*ast.SelectStmt), NotNil)\n\twriter.Reset()\n\tst.(*ast.SelectStmt).Where.Format(writer)\n\tc.Assert(writer.String(), Equals, \"MATCH(title,content) AGAINST(\\\"search\\\" IN BOOLEAN MODE)\")\n\n\tst, err = parser.ParseOneStmt(\"SELECT * FROM fulltext_test WHERE MATCH(title,content) AGAINST('search' WITH QUERY EXPANSION)\", \"\", \"\")\n\tc.Assert(err, IsNil)\n\tc.Assert(st.(*ast.SelectStmt), NotNil)\n\twriter.Reset()\n\tst.(*ast.SelectStmt).Where.Format(writer)\n\tc.Assert(writer.String(), Equals, \"MATCH(title,content) AGAINST(\\\"search\\\" WITH QUERY EXPANSION)\")\n}\n\nfunc (s *testParserSuite) TestStartTransaction(c *C) {\n\tcases := []testCase{\n\t\t{\"START TRANSACTION READ WRITE\", true, \"START TRANSACTION\"},\n\t\t{\"START TRANSACTION READ ONLY\", true, \"START TRANSACTION READ ONLY\"},\n\t\t{\"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND\", false, \"\"},\n\t\t{\"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND STRONG\", true, \"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND STRONG\"},\n\t\t{\"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MAX STALENESS '00:00:10'\", true, \"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MAX STALENESS '00:00:10'\"},\n\t\t{\"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND EXACT STALENESS '00:00:05'\", true, \"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND EXACT STALENESS '00:00:05'\"},\n\t\t{\"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND READ TIMESTAMP '2019-11-04 00:00:00'\", true, \"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND READ TIMESTAMP '2019-11-04 00:00:00'\"},\n\t\t{\"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MIN READ TIMESTAMP '2019-11-04 00:00:00'\", true, \"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MIN READ TIMESTAMP '2019-11-04 00:00:00'\"},\n\t\t{\"START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MIN TIMESTAMP '2019-11-04 00:00:00'\", false, \"\"},\n\t}\n\n\ts.RunTest(c, cases)\n}\n\n// CleanNodeText set the text of node and all child node empty.\n// For test only.\nfunc CleanNodeText(node ast.Node) {\n\tvar cleaner nodeTextCleaner\n\tnode.Accept(&cleaner)\n}\n\n// nodeTextCleaner clean the text of a node and it's child node.\n// For test only.\ntype nodeTextCleaner struct {\n}\n\n// Enter implements Visitor interface.\nfunc (checker *nodeTextCleaner) Enter(in ast.Node) (out ast.Node, skipChildren bool) {\n\tin.SetText(\"\")\n\tswitch node := in.(type) {\n\tcase *ast.CreateTableStmt:\n\t\tfor _, opt := range node.Options {\n\t\t\tswitch opt.Tp {\n\t\t\tcase ast.TableOptionCharset:\n\t\t\t\topt.StrValue = strings.ToUpper(opt.StrValue)\n\t\t\tcase ast.TableOptionCollate:\n\t\t\t\topt.StrValue = strings.ToUpper(opt.StrValue)\n\t\t\t}\n\t\t}\n\t\tfor _, col := range node.Cols {\n\t\t\t// col.Tp.Charset = strings.ToUpper(col.Tp.Charset)\n\t\t\t// col.Tp.Collate = strings.ToUpper(col.Tp.Collate)\n\n\t\t\tinvalidOption := func(option *ast.ColumnOption) bool {\n\t\t\t\treturn option.Tp == 0 && option.Expr == nil && option.Stored == false && option.Refer == nil\n\t\t\t}\n\t\t\tcol.Options = slices.DeleteFunc(col.Options, invalidOption)\n\t\t}\n\t\tif node.Partition != nil && node.Partition.Expr != nil {\n\t\t\tvar tmpCleaner nodeTextCleaner\n\t\t\tnode.Partition.Expr.Accept(&tmpCleaner)\n\t\t}\n\tcase *ast.DeleteStmt:\n\t\tfor _, tableHint := range node.TableHints {\n\t\t\ttableHint.HintName.O = \"\"\n\t\t}\n\tcase *ast.UpdateStmt:\n\t\tfor _, tableHint := range node.TableHints {\n\t\t\ttableHint.HintName.O = \"\"\n\t\t}\n\tcase *ast.Constraint:\n\t\tif node.Option != nil {\n\t\t\tif node.Option.KeyBlockSize == 0x0 && node.Option.Tp == 0 && node.Option.Comment == \"\" {\n\t\t\t\tnode.Option = nil\n\t\t\t}\n\t\t}\n\tcase *ast.FuncCallExpr:\n\t\tnode.FnName.O = strings.ToLower(node.FnName.O)\n\tcase *ast.AggregateFuncExpr:\n\t\tnode.F = strings.ToLower(node.F)\n\tcase *ast.SelectField:\n\t\tnode.Offset = 0\n\tcase *test_driver.ValueExpr:\n\t\tif node.Kind() == test_driver.KindMysqlDecimal {\n\t\t\tnode.GetMysqlDecimal().FromString(node.GetMysqlDecimal().ToString())\n\t\t}\n\tcase *ast.GrantStmt:\n\t\tvar privs []*ast.PrivElem\n\t\tfor _, v := range node.Privs {\n\t\t\tif v.Priv != 0 {\n\t\t\t\tprivs = append(privs, v)\n\t\t\t}\n\t\t}\n\t\tnode.Privs = privs\n\tcase *ast.AlterTableStmt:\n\t\tvar specs []*ast.AlterTableSpec\n\t\tfor _, v := range node.Specs {\n\t\t\tif v.Tp != 0 && !(v.Tp == ast.AlterTableOption && len(v.Options) == 0) {\n\t\t\t\tspecs = append(specs, v)\n\t\t\t}\n\t\t}\n\t\tnode.Specs = specs\n\t}\n\treturn in, false\n}\n\n// Leave implements Visitor interface.\nfunc (checker *nodeTextCleaner) Leave(in ast.Node) (out ast.Node, ok bool) {\n\treturn in, true\n}\n\n// For index advisor\nfunc (s *testParserSuite) TestIndexAdviseStmt(c *C) {\n\ttable := []testCase{\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql'\"},\n\t\t{\"INDEX ADVISE LOCAL INFILE '/tmp/t.sql'\", true, \"INDEX ADVISE LOCAL INFILE '/tmp/t.sql'\"},\n\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1\", false, \"\"},\n\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_TABLE 4\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_TABLE 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_DB 4\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_DB 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_TABLE 8 PER_DB 4\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_TABLE 8 PER_DB 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_IDXNUM PER_DB 4 PER_TABLE 8\", false, \"\"},\n\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' LINES TERMINATED BY '\\n'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' LINES TERMINATED BY 'cd'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' LINES TERMINATED BY 'cd'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab' TERMINATED BY '\\n'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab' TERMINATED BY 'cd'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' LINES STARTING BY 'ab' TERMINATED BY 'cd'\"},\n\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 4\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_DB 4\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_DB 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 4\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_DB 4\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_DB 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 MAX_IDXNUM PER_TABLE 4\", false, \"\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 MAX_IDXNUM PER_DB 4\", false, \"\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 MAX_IDXNUM PER_TABLE 8 PER_DB 4\", false, \"\"},\n\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES TERMINATED BY '\\n'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES TERMINATED BY 'cd'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES TERMINATED BY 'cd'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab' TERMINATED BY '\\n'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES TERMINATED BY '\\n'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES TERMINATED BY 'cd'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES TERMINATED BY 'cd'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab' TERMINATED BY '\\n'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab' TERMINATED BY 'cd'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 LINES STARTING BY 'ab' TERMINATED BY 'cd'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 LINES STARTING BY 'ab' TERMINATED BY '\\n'\", false, \"\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 LINES STARTING BY 'ab' TERMINATED BY 'cd'\", false, \"\"},\n\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 4 LINES STARTING BY 'ab'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 4 LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_DB 4 LINES STARTING BY 'ab'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_DB 4 LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES TERMINATED BY '\\n'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES TERMINATED BY 'cd'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES TERMINATED BY 'cd'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY '\\n'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 3 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY '\\n'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'\", true, \"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES 0 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY '\\n'\", false, \"\"},\n\t\t{\"INDEX ADVISE INFILE '/tmp/t.sql' MAX_MINUTES -1 MAX_IDXNUM PER_TABLE 8 PER_DB 4 LINES STARTING BY 'ab' TERMINATED BY 'cd'\", false, \"\"},\n\t}\n\n\ts.RunTest(c, table)\n}\n"
  },
  {
    "path": "pkg/parser/terror/terror.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage terror\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/pingcap/errors\"\n\t\"github.com/pingcap/log\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n)\n\n// Global error instances.\nvar (\n\tErrCritical           = ClassGlobal.New(CodeExecResultIsEmpty, \"critical error %v\")\n\tErrResultUndetermined = ClassGlobal.New(CodeResultUndetermined, \"execution result undetermined\")\n)\n\n// ErrCode represents a specific error type in a error class.\n// Same error code can be used in different error classes.\ntype ErrCode int\n\nconst (\n\t// Executor error codes.\n\n\t// CodeUnknown is for errors of unknown reason.\n\tCodeUnknown ErrCode = -1\n\t// CodeExecResultIsEmpty indicates execution result is empty.\n\tCodeExecResultIsEmpty ErrCode = 3\n\n\t// Expression error codes.\n\n\t// CodeMissConnectionID indicates connection id is missing.\n\tCodeMissConnectionID ErrCode = 1\n\n\t// Special error codes.\n\n\t// CodeResultUndetermined indicates the sql execution result is undetermined.\n\tCodeResultUndetermined ErrCode = 2\n)\n\n// ErrClass represents a class of errors.\ntype ErrClass int\n\n// Error classes.\nconst (\n\tClassAutoid ErrClass = iota + 1\n\tClassDDL\n\tClassDomain\n\tClassEvaluator\n\tClassExecutor\n\tClassExpression\n\tClassAdmin\n\tClassKV\n\tClassMeta\n\tClassOptimizer\n\tClassParser\n\tClassPerfSchema\n\tClassPrivilege\n\tClassSchema\n\tClassServer\n\tClassStructure\n\tClassVariable\n\tClassXEval\n\tClassTable\n\tClassTypes\n\tClassGlobal\n\tClassMockTikv\n\tClassJSON\n\tClassTiKV\n\tClassSession\n\tClassPlugin\n\tClassUtil\n\t// Add more as needed.\n)\n\nvar errClz2Str = map[ErrClass]string{\n\tClassAutoid:     \"autoid\",\n\tClassDDL:        \"ddl\",\n\tClassDomain:     \"domain\",\n\tClassExecutor:   \"executor\",\n\tClassExpression: \"expression\",\n\tClassAdmin:      \"admin\",\n\tClassMeta:       \"meta\",\n\tClassKV:         \"kv\",\n\tClassOptimizer:  \"planner\",\n\tClassParser:     \"parser\",\n\tClassPerfSchema: \"perfschema\",\n\tClassPrivilege:  \"privilege\",\n\tClassSchema:     \"schema\",\n\tClassServer:     \"server\",\n\tClassStructure:  \"structure\",\n\tClassVariable:   \"variable\",\n\tClassTable:      \"table\",\n\tClassTypes:      \"types\",\n\tClassGlobal:     \"global\",\n\tClassMockTikv:   \"mocktikv\",\n\tClassJSON:       \"json\",\n\tClassTiKV:       \"tikv\",\n\tClassSession:    \"session\",\n\tClassPlugin:     \"plugin\",\n\tClassUtil:       \"util\",\n}\n\n// String implements fmt.Stringer interface.\nfunc (ec ErrClass) String() string {\n\tif s, exists := errClz2Str[ec]; exists {\n\t\treturn s\n\t}\n\treturn strconv.Itoa(int(ec))\n}\n\n// EqualClass returns true if err is *Error with the same class.\nfunc (ec ErrClass) EqualClass(err error) bool {\n\te := errors.Cause(err)\n\tif e == nil {\n\t\treturn false\n\t}\n\tif te, ok := e.(*Error); ok {\n\t\treturn te.class == ec\n\t}\n\treturn false\n}\n\n// NotEqualClass returns true if err is not *Error with the same class.\nfunc (ec ErrClass) NotEqualClass(err error) bool {\n\treturn !ec.EqualClass(err)\n}\n\n// New creates an *Error with an error code and an error message.\n// Usually used to create base *Error.\nfunc (ec ErrClass) New(code ErrCode, message string) *Error {\n\treturn &Error{\n\t\tclass:   ec,\n\t\tcode:    code,\n\t\tmessage: message,\n\t}\n}\n\n// NewStd calls New using the standard message for the error code\nfunc (ec ErrClass) NewStd(code ErrCode) *Error {\n\treturn ec.New(code, mysql.MySQLErrName[uint16(code)])\n}\n\n// Error implements error interface and adds integer Class and Code, so\n// errors with different message can be compared.\ntype Error struct {\n\tclass   ErrClass\n\tcode    ErrCode\n\tmessage string\n\targs    []interface{}\n\tfile    string\n\tline    int\n}\n\n// Class returns ErrClass\nfunc (e *Error) Class() ErrClass {\n\treturn e.class\n}\n\n// Code returns ErrCode\nfunc (e *Error) Code() ErrCode {\n\treturn e.code\n}\n\n// MarshalJSON implements json.Marshaler interface.\nfunc (e *Error) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(&struct {\n\t\tClass ErrClass `json:\"class\"`\n\t\tCode  ErrCode  `json:\"code\"`\n\t\tMsg   string   `json:\"message\"`\n\t}{\n\t\tClass: e.class,\n\t\tCode:  e.code,\n\t\tMsg:   e.getMsg(),\n\t})\n}\n\n// UnmarshalJSON implements json.Unmarshaler interface.\nfunc (e *Error) UnmarshalJSON(data []byte) error {\n\terr := &struct {\n\t\tClass ErrClass `json:\"class\"`\n\t\tCode  ErrCode  `json:\"code\"`\n\t\tMsg   string   `json:\"message\"`\n\t}{}\n\n\tif err := json.Unmarshal(data, &err); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\n\te.class = err.Class\n\te.code = err.Code\n\te.message = err.Msg\n\treturn nil\n}\n\n// Location returns the location where the error is created,\n// implements juju/errors locationer interface.\nfunc (e *Error) Location() (file string, line int) {\n\treturn e.file, e.line\n}\n\n// Error implements error interface.\nfunc (e *Error) Error() string {\n\treturn fmt.Sprintf(\"[%s:%d]%s\", e.class, e.code, e.getMsg())\n}\n\nfunc (e *Error) getMsg() string {\n\tif len(e.args) > 0 {\n\t\treturn fmt.Sprintf(e.message, e.args...)\n\t}\n\treturn e.message\n}\n\n// GenWithStack generates a new *Error with the same class and code, and a new formatted message.\nfunc (e *Error) GenWithStack(format string, args ...interface{}) error {\n\terr := *e\n\terr.message = format\n\terr.args = args\n\treturn errors.AddStack(&err)\n}\n\n// GenWithStackByArgs generates a new *Error with the same class and code, and new arguments.\nfunc (e *Error) GenWithStackByArgs(args ...interface{}) error {\n\terr := *e\n\terr.args = args\n\treturn errors.AddStack(&err)\n}\n\n// FastGen generates a new *Error with the same class and code, and a new formatted message.\n// This will not call runtime.Caller to get file and line.\nfunc (e *Error) FastGen(format string, args ...interface{}) error {\n\terr := *e\n\terr.message = format\n\terr.args = args\n\treturn errors.SuspendStack(&err)\n}\n\n// FastGen generates a new *Error with the same class and code, and a new arguments.\n// This will not call runtime.Caller to get file and line.\nfunc (e *Error) FastGenByArgs(args ...interface{}) error {\n\terr := *e\n\terr.args = args\n\treturn errors.SuspendStack(&err)\n}\n\n// Equal checks if err is equal to e.\nfunc (e *Error) Equal(err error) bool {\n\toriginErr := errors.Cause(err)\n\tif originErr == nil {\n\t\treturn false\n\t}\n\n\tif error(e) == originErr {\n\t\treturn true\n\t}\n\tinErr, ok := originErr.(*Error)\n\treturn ok && e.class == inErr.class && e.code == inErr.code\n}\n\n// NotEqual checks if err is not equal to e.\nfunc (e *Error) NotEqual(err error) bool {\n\treturn !e.Equal(err)\n}\n\n// ToSQLError convert Error to mysql.SQLError.\nfunc (e *Error) ToSQLError() *mysql.SQLError {\n\tcode := e.getMySQLErrorCode()\n\treturn mysql.NewErrf(code, \"%s\", e.getMsg())\n}\n\nvar defaultMySQLErrorCode uint16\n\nfunc (e *Error) getMySQLErrorCode() uint16 {\n\tcodeMap, ok := ErrClassToMySQLCodes[e.class]\n\tif !ok {\n\t\tlog.Warn(\"Unknown error class\", zap.Int(\"class\", int(e.class)))\n\t\treturn defaultMySQLErrorCode\n\t}\n\tcode, ok := codeMap[e.code]\n\tif !ok {\n\t\tlog.Debug(\"Unknown error code\", zap.Int(\"class\", int(e.class)), zap.Uint16(\"code\", code))\n\t\treturn defaultMySQLErrorCode\n\t}\n\treturn code\n}\n\nvar (\n\t// ErrClassToMySQLCodes is the map of ErrClass to code-map.\n\tErrClassToMySQLCodes map[ErrClass]map[ErrCode]uint16\n)\n\nfunc init() {\n\tErrClassToMySQLCodes = make(map[ErrClass]map[ErrCode]uint16)\n\tdefaultMySQLErrorCode = mysql.ErrUnknown\n}\n\n// ErrorEqual returns a boolean indicating whether err1 is equal to err2.\nfunc ErrorEqual(err1, err2 error) bool {\n\te1 := errors.Cause(err1)\n\te2 := errors.Cause(err2)\n\n\tif e1 == e2 {\n\t\treturn true\n\t}\n\n\tif e1 == nil || e2 == nil {\n\t\treturn e1 == e2\n\t}\n\n\tte1, ok1 := e1.(*Error)\n\tte2, ok2 := e2.(*Error)\n\tif ok1 && ok2 {\n\t\treturn te1.class == te2.class && te1.code == te2.code\n\t}\n\n\treturn e1.Error() == e2.Error()\n}\n\n// ErrorNotEqual returns a boolean indicating whether err1 isn't equal to err2.\nfunc ErrorNotEqual(err1, err2 error) bool {\n\treturn !ErrorEqual(err1, err2)\n}\n\n// MustNil cleans up and fatals if err is not nil.\nfunc MustNil(err error, closeFuns ...func()) {\n\tif err != nil {\n\t\tfor _, f := range closeFuns {\n\t\t\tf()\n\t\t}\n\t\tlog.Fatal(\"unexpected error\", zap.Error(err))\n\t}\n}\n\n// Call executes a function and checks the returned err.\nfunc Call(fn func() error) {\n\terr := fn()\n\tif err != nil {\n\t\tlog.Error(\"function call errored\", zap.Error(err))\n\t}\n}\n\n// Log logs the error if it is not nil.\nfunc Log(err error) {\n\tif err != nil {\n\t\tlog.Error(\"encountered error\", zap.Error(err))\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/terror/terror_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage terror\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n\t\"github.com/pingcap/errors\"\n)\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nvar _ = Suite(&testTErrorSuite{})\n\ntype testTErrorSuite struct {\n}\n\nfunc (s *testTErrorSuite) TestErrCode(c *C) {\n\tc.Assert(CodeMissConnectionID, Equals, ErrCode(1))\n\tc.Assert(CodeResultUndetermined, Equals, ErrCode(2))\n}\n\nfunc (s *testTErrorSuite) TestTError(c *C) {\n\tc.Assert(ClassParser.String(), Not(Equals), \"\")\n\tc.Assert(ClassOptimizer.String(), Not(Equals), \"\")\n\tc.Assert(ClassKV.String(), Not(Equals), \"\")\n\tc.Assert(ClassServer.String(), Not(Equals), \"\")\n\n\tparserErr := ClassParser.New(ErrCode(1), \"error 1\")\n\tc.Assert(parserErr.Error(), Not(Equals), \"\")\n\tc.Assert(ClassParser.EqualClass(parserErr), IsTrue)\n\tc.Assert(ClassParser.NotEqualClass(parserErr), IsFalse)\n\n\tc.Assert(ClassOptimizer.EqualClass(parserErr), IsFalse)\n\toptimizerErr := ClassOptimizer.New(ErrCode(2), \"abc\")\n\tc.Assert(ClassOptimizer.EqualClass(errors.New(\"abc\")), IsFalse)\n\tc.Assert(ClassOptimizer.EqualClass(nil), IsFalse)\n\tc.Assert(optimizerErr.Equal(optimizerErr.GenWithStack(\"def\")), IsTrue)\n\tc.Assert(optimizerErr.Equal(nil), IsFalse)\n\tc.Assert(optimizerErr.Equal(errors.New(\"abc\")), IsFalse)\n\n\t// Test case for FastGen.\n\tc.Assert(optimizerErr.Equal(optimizerErr.FastGen(\"def\")), IsTrue)\n\tc.Assert(optimizerErr.Equal(optimizerErr.FastGen(\"def: %s\", \"def\")), IsTrue)\n\tkvErr := ClassKV.New(1062, \"key already exist\")\n\te := kvErr.FastGen(\"Duplicate entry '%d' for key 'PRIMARY'\", 1)\n\tc.Assert(e.Error(), Equals, \"[kv:1062]Duplicate entry '1' for key 'PRIMARY'\")\n\tkvMySQLErrCodes := map[ErrCode]uint16{\n\t\t1062: uint16(1062),\n\t}\n\tErrClassToMySQLCodes[ClassKV] = kvMySQLErrCodes\n\tsqlErr := errors.Cause(e).(*Error).ToSQLError()\n\tc.Assert(sqlErr.Message, Equals, \"Duplicate entry '1' for key 'PRIMARY'\")\n\tc.Assert(sqlErr.Code, Equals, uint16(1062))\n\n\terr := errors.Trace(ErrCritical.GenWithStackByArgs(\"test\"))\n\tc.Assert(ErrCritical.Equal(err), IsTrue)\n\n\terr = errors.Trace(ErrCritical)\n\tc.Assert(ErrCritical.Equal(err), IsTrue)\n}\n\nfunc (s *testTErrorSuite) TestJson(c *C) {\n\tprevTErr := &Error{\n\t\tclass:   ClassTable,\n\t\tcode:    CodeExecResultIsEmpty,\n\t\tmessage: \"json test\",\n\t}\n\tbuf, err := json.Marshal(prevTErr)\n\tc.Assert(err, IsNil)\n\tvar curTErr Error\n\terr = json.Unmarshal(buf, &curTErr)\n\tc.Assert(err, IsNil)\n\tisEqual := prevTErr.Equal(&curTErr)\n\tc.Assert(isEqual, IsTrue)\n}\n\nvar predefinedErr = ClassExecutor.New(ErrCode(123), \"predefiend error\")\n\nfunc example() error {\n\terr := call()\n\treturn errors.Trace(err)\n}\n\nfunc call() error {\n\treturn predefinedErr.GenWithStack(\"error message:%s\", \"abc\")\n}\n\n// func (s *testTErrorSuite) TestTraceAndLocation(c *C) {\n// \terr := example()\n// \tstack := errors.ErrorStack(err)\n// \tlines := strings.Split(stack, \"\\n\")\n// \tgoroot := strings.ReplaceAll(runtime.GOROOT(), string(os.PathSeparator), \"/\")\n// \tvar sysStack = 0\n// \tfor _, line := range lines {\n// \t\tif strings.Contains(line, goroot) {\n// \t\t\tsysStack++\n// \t\t}\n// \t}\n// \tc.Assert(len(lines)-(2*sysStack), Equals, 15, Commentf(\"stack =\\n%s\", stack))\n// \tvar containTerr bool\n// \tfor _, v := range lines {\n// \t\tif strings.Contains(v, \"terror_test.go\") {\n// \t\t\tcontainTerr = true\n// \t\t\tbreak\n// \t\t}\n// \t}\n// \tc.Assert(containTerr, IsTrue)\n// }\n\nfunc (s *testTErrorSuite) TestErrorEqual(c *C) {\n\te1 := errors.New(\"test error\")\n\tc.Assert(e1, NotNil)\n\n\te2 := errors.Trace(e1)\n\tc.Assert(e2, NotNil)\n\n\te3 := errors.Trace(e2)\n\tc.Assert(e3, NotNil)\n\n\tc.Assert(errors.Cause(e2), Equals, e1)\n\tc.Assert(errors.Cause(e3), Equals, e1)\n\tc.Assert(errors.Cause(e2), Equals, errors.Cause(e3))\n\n\te4 := errors.New(\"test error\")\n\tc.Assert(errors.Cause(e4), Not(Equals), e1)\n\n\te5 := errors.Errorf(\"test error\")\n\tc.Assert(errors.Cause(e5), Not(Equals), e1)\n\n\tc.Assert(ErrorEqual(e1, e2), IsTrue)\n\tc.Assert(ErrorEqual(e1, e3), IsTrue)\n\tc.Assert(ErrorEqual(e1, e4), IsTrue)\n\tc.Assert(ErrorEqual(e1, e5), IsTrue)\n\n\tvar e6 error\n\n\tc.Assert(ErrorEqual(nil, nil), IsTrue)\n\tc.Assert(ErrorNotEqual(e1, e6), IsTrue)\n\tcode1 := ErrCode(1)\n\tcode2 := ErrCode(2)\n\tte1 := ClassParser.New(code1, \"abc\")\n\tte2 := ClassParser.New(code1, \"def\")\n\tte3 := ClassKV.New(code1, \"abc\")\n\tte4 := ClassKV.New(code2, \"abc\")\n\tc.Assert(ErrorEqual(te1, te2), IsTrue)\n\tc.Assert(ErrorEqual(te1, te3), IsFalse)\n\tc.Assert(ErrorEqual(te3, te4), IsFalse)\n}\n"
  },
  {
    "path": "pkg/parser/test.sh",
    "content": "GO111MODULE=on go test -p 1 -race -covermode=atomic -coverprofile=coverage.txt -coverpkg=./... ./...\n"
  },
  {
    "path": "pkg/parser/test_driver/test_driver.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n//go:build !codes\n// +build !codes\n\npackage test_driver\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n)\n\nfunc init() {\n\tast.NewValueExpr = newValueExpr\n\tast.NewParamMarkerExpr = newParamMarkerExpr\n\tast.NewDecimal = func(str string) (interface{}, error) {\n\t\tdec := new(MyDecimal)\n\t\terr := dec.FromString([]byte(str))\n\t\treturn dec, err\n\t}\n\tast.NewHexLiteral = func(str string) (interface{}, error) {\n\t\th, err := NewHexLiteral(str)\n\t\treturn h, err\n\t}\n\tast.NewBitLiteral = func(str string) (interface{}, error) {\n\t\tb, err := NewBitLiteral(str)\n\t\treturn b, err\n\t}\n}\n\nvar (\n\t_ ast.ParamMarkerExpr = &ParamMarkerExpr{}\n\t_ ast.ValueExpr       = &ValueExpr{}\n)\n\n// ValueExpr is the simple value expression.\ntype ValueExpr struct {\n\tast.TexprNode\n\tDatum\n\tprojectionOffset int\n}\n\n// Restore implements Node interface.\nfunc (n *ValueExpr) Restore(ctx *format.RestoreCtx) error {\n\tswitch n.Kind() {\n\tcase KindNull:\n\t\tctx.WriteKeyWord(\"NULL\")\n\tcase KindInt64:\n\t\tif n.Type.Flag&mysql.IsBooleanFlag != 0 {\n\t\t\tif n.GetInt64() > 0 {\n\t\t\t\tctx.WriteKeyWord(\"TRUE\")\n\t\t\t} else {\n\t\t\t\tctx.WriteKeyWord(\"FALSE\")\n\t\t\t}\n\t\t} else {\n\t\t\tctx.WritePlain(strconv.FormatInt(n.GetInt64(), 10))\n\t\t}\n\tcase KindUint64:\n\t\tctx.WritePlain(strconv.FormatUint(n.GetUint64(), 10))\n\tcase KindFloat32:\n\t\tctx.WritePlain(strconv.FormatFloat(n.GetFloat64(), 'e', -1, 32))\n\tcase KindFloat64:\n\t\tctx.WritePlain(strconv.FormatFloat(n.GetFloat64(), 'e', -1, 64))\n\tcase KindString:\n\t\tif n.Type.Charset != \"\" && n.Type.Charset != mysql.DefaultCharset {\n\t\t\tctx.WritePlain(\"_\")\n\t\t\tctx.WriteKeyWord(n.Type.Charset)\n\t\t}\n\t\tctx.WriteString(n.GetString())\n\tcase KindBytes:\n\t\tctx.WriteString(n.GetString())\n\tcase KindMysqlDecimal:\n\t\tctx.WritePlain(n.GetMysqlDecimal().String())\n\tcase KindBinaryLiteral:\n\t\tif n.Type.Flag&mysql.UnsignedFlag != 0 {\n\t\t\tctx.WritePlainf(\"x'%x'\", n.GetBytes())\n\t\t} else {\n\t\t\tctx.WritePlain(n.GetBinaryLiteral().ToBitLiteralString(true))\n\t\t}\n\tcase KindMysqlDuration,\n\t\tKindMysqlBit, KindMysqlTime,\n\t\tKindInterface, KindMinNotNull, KindMaxValue,\n\t\tKindRaw:\n\t\t// TODO implement Restore function\n\t\treturn fmt.Errorf(\"not implemented\")\n\tdefault:\n\t\treturn fmt.Errorf(\"can't format to string\")\n\t}\n\treturn nil\n}\n\n// GetDatumString implements the ValueExpr interface.\nfunc (n *ValueExpr) GetDatumString() string {\n\treturn n.GetString()\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *ValueExpr) Format(w io.Writer) {\n\tvar s string\n\tswitch n.Kind() {\n\tcase KindNull:\n\t\ts = \"NULL\"\n\tcase KindInt64:\n\t\tif n.Type.Flag&mysql.IsBooleanFlag != 0 {\n\t\t\tif n.GetInt64() > 0 {\n\t\t\t\ts = \"TRUE\"\n\t\t\t} else {\n\t\t\t\ts = \"FALSE\"\n\t\t\t}\n\t\t} else {\n\t\t\ts = strconv.FormatInt(n.GetInt64(), 10)\n\t\t}\n\tcase KindUint64:\n\t\ts = strconv.FormatUint(n.GetUint64(), 10)\n\tcase KindFloat32:\n\t\ts = strconv.FormatFloat(n.GetFloat64(), 'e', -1, 32)\n\tcase KindFloat64:\n\t\ts = strconv.FormatFloat(n.GetFloat64(), 'e', -1, 64)\n\tcase KindString, KindBytes:\n\t\ts = strconv.Quote(n.GetString())\n\tcase KindMysqlDecimal:\n\t\ts = n.GetMysqlDecimal().String()\n\tcase KindBinaryLiteral:\n\t\tif n.Type.Flag&mysql.UnsignedFlag != 0 {\n\t\t\ts = fmt.Sprintf(\"x'%x'\", n.GetBytes())\n\t\t} else {\n\t\t\ts = n.GetBinaryLiteral().ToBitLiteralString(true)\n\t\t}\n\tdefault:\n\t\tpanic(\"Can't format to string\")\n\t}\n\t_, _ = fmt.Fprint(w, s)\n}\n\n// newValueExpr creates a ValueExpr with value, and sets default field type.\nfunc newValueExpr(value interface{}) ast.ValueExpr {\n\tif ve, ok := value.(*ValueExpr); ok {\n\t\treturn ve\n\t}\n\tve := &ValueExpr{}\n\tve.SetValue(value)\n\tDefaultTypeForValue(value, &ve.Type)\n\tve.projectionOffset = -1\n\treturn ve\n}\n\n// SetProjectionOffset sets ValueExpr.projectionOffset for logical plan builder.\nfunc (n *ValueExpr) SetProjectionOffset(offset int) {\n\tn.projectionOffset = offset\n}\n\n// GetProjectionOffset returns ValueExpr.projectionOffset.\nfunc (n *ValueExpr) GetProjectionOffset() int {\n\treturn n.projectionOffset\n}\n\n// Accept implements Node interface.\nfunc (n *ValueExpr) Accept(v ast.Visitor) (ast.Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ValueExpr)\n\treturn v.Leave(n)\n}\n\n// ParamMarkerExpr expression holds a place for another expression.\n// Used in parsing prepare statement.\ntype ParamMarkerExpr struct {\n\tValueExpr\n\tOffset    int\n\tOrder     int\n\tParamName string\n\tInExecute bool\n}\n\nfunc newParamMarkerExpr(offset int, paramName string) ast.ParamMarkerExpr {\n\treturn &ParamMarkerExpr{\n\t\tOffset:    offset,\n\t\tParamName: paramName,\n\t}\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *ParamMarkerExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ParamMarkerExpr) Accept(v ast.Visitor) (ast.Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ParamMarkerExpr)\n\treturn v.Leave(n)\n}\n\n// SetOrder implements the ParamMarkerExpr interface.\nfunc (n *ParamMarkerExpr) SetOrder(order int) {\n\tn.Order = order\n}\n"
  },
  {
    "path": "pkg/parser/test_driver/test_driver_datum.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n//go:build !codes\n// +build !codes\n\npackage test_driver\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/types\"\n)\n\n// Kind constants.\nconst (\n\tKindNull          byte = 0\n\tKindInt64         byte = 1\n\tKindUint64        byte = 2\n\tKindFloat32       byte = 3\n\tKindFloat64       byte = 4\n\tKindString        byte = 5\n\tKindBytes         byte = 6\n\tKindBinaryLiteral byte = 7 // Used for BIT / HEX literals.\n\tKindMysqlDecimal  byte = 8\n\tKindMysqlDuration byte = 9\n\t// KindMysqlEnum     byte = 10\t\t// not supported by scql\n\tKindMysqlBit byte = 11 // Used for BIT table column values.\n\t// KindMysqlSet      byte = 12\t\t// not supported by scql\n\tKindMysqlTime  byte = 13\n\tKindInterface  byte = 14\n\tKindMinNotNull byte = 15\n\tKindMaxValue   byte = 16\n\tKindRaw        byte = 17\n\t// KindMysqlJSON     byte = 18      // not supported by scql\n)\n\n// Datum is a data box holds different kind of data.\n// It has better performance and is easier to use than `interface{}`.\ntype Datum struct {\n\tk         byte        // datum kind.\n\tcollation uint8       // collation can hold uint8 values.\n\tdecimal   uint16      // decimal can hold uint16 values.\n\tlength    uint32      // length can hold uint32 values.\n\ti         int64       // i can hold int64 uint64 float64 values.\n\tb         []byte      // b can hold string or []byte values.\n\tx         interface{} // x hold all other types.\n}\n\n// Kind gets the kind of the datum.\nfunc (d *Datum) Kind() byte {\n\treturn d.k\n}\n\n// GetInt64 gets int64 value.\nfunc (d *Datum) GetInt64() int64 {\n\treturn d.i\n}\n\n// SetInt64 sets int64 value.\nfunc (d *Datum) SetInt64(i int64) {\n\td.k = KindInt64\n\td.i = i\n}\n\n// GetUint64 gets uint64 value.\nfunc (d *Datum) GetUint64() uint64 {\n\treturn uint64(d.i)\n}\n\n// SetUint64 sets uint64 value.\nfunc (d *Datum) SetUint64(i uint64) {\n\td.k = KindUint64\n\td.i = int64(i)\n}\n\n// GetFloat64 gets float64 value.\nfunc (d *Datum) GetFloat64() float64 {\n\treturn math.Float64frombits(uint64(d.i))\n}\n\n// SetFloat64 sets float64 value.\nfunc (d *Datum) SetFloat64(f float64) {\n\td.k = KindFloat64\n\td.i = int64(math.Float64bits(f))\n}\n\n// GetFloat32 gets float32 value.\nfunc (d *Datum) GetFloat32() float32 {\n\treturn float32(math.Float64frombits(uint64(d.i)))\n}\n\n// SetFloat32 sets float32 value.\nfunc (d *Datum) SetFloat32(f float32) {\n\td.k = KindFloat32\n\td.i = int64(math.Float64bits(float64(f)))\n}\n\n// GetString gets string value.\nfunc (d *Datum) GetString() string {\n\treturn string(d.b)\n}\n\n// SetString sets string value.\nfunc (d *Datum) SetString(s string) {\n\td.k = KindString\n\td.b = []byte(s)\n}\n\n// GetBytes gets bytes value.\nfunc (d *Datum) GetBytes() []byte {\n\treturn d.b\n}\n\n// SetBytes sets bytes value to datum.\nfunc (d *Datum) SetBytes(b []byte) {\n\td.k = KindBytes\n\td.b = b\n}\n\n// SetBytesAsString sets bytes value to datum as string type.\nfunc (d *Datum) SetBytesAsString(b []byte) {\n\td.k = KindString\n\td.b = b\n}\n\n// GetInterface gets interface value.\nfunc (d *Datum) GetInterface() interface{} {\n\treturn d.x\n}\n\n// SetInterface sets interface to datum.\nfunc (d *Datum) SetInterface(x interface{}) {\n\td.k = KindInterface\n\td.x = x\n}\n\n// SetNull sets datum to nil.\nfunc (d *Datum) SetNull() {\n\td.k = KindNull\n\td.x = nil\n}\n\n// GetBinaryLiteral gets Bit value\nfunc (d *Datum) GetBinaryLiteral() BinaryLiteral {\n\treturn d.b\n}\n\n// SetBinaryLiteral sets Bit value\nfunc (d *Datum) SetBinaryLiteral(b BinaryLiteral) {\n\td.k = KindBinaryLiteral\n\td.b = b\n}\n\n// GetMysqlDecimal gets Decimal value\nfunc (d *Datum) GetMysqlDecimal() *MyDecimal {\n\treturn d.x.(*MyDecimal)\n}\n\n// SetMysqlDecimal sets Decimal value\nfunc (d *Datum) SetMysqlDecimal(b *MyDecimal) {\n\td.k = KindMysqlDecimal\n\td.x = b\n}\n\n// GetValue gets the value of the datum of any kind.\nfunc (d *Datum) GetValue() interface{} {\n\tswitch d.k {\n\tcase KindInt64:\n\t\treturn d.GetInt64()\n\tcase KindUint64:\n\t\treturn d.GetUint64()\n\tcase KindFloat32:\n\t\treturn d.GetFloat32()\n\tcase KindFloat64:\n\t\treturn d.GetFloat64()\n\tcase KindString:\n\t\treturn d.GetString()\n\tcase KindBytes:\n\t\treturn d.GetBytes()\n\tcase KindMysqlDecimal:\n\t\treturn d.GetMysqlDecimal()\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\treturn d.GetBinaryLiteral()\n\tdefault:\n\t\treturn d.GetInterface()\n\t}\n}\n\n// SetValue sets any kind of value.\nfunc (d *Datum) SetValue(val interface{}) {\n\tswitch x := val.(type) {\n\tcase nil:\n\t\td.SetNull()\n\tcase bool:\n\t\tif x {\n\t\t\td.SetInt64(1)\n\t\t} else {\n\t\t\td.SetInt64(0)\n\t\t}\n\tcase int:\n\t\td.SetInt64(int64(x))\n\tcase int64:\n\t\td.SetInt64(x)\n\tcase uint64:\n\t\td.SetUint64(x)\n\tcase float32:\n\t\td.SetFloat32(x)\n\tcase float64:\n\t\td.SetFloat64(x)\n\tcase string:\n\t\td.SetString(x)\n\tcase []byte:\n\t\td.SetBytes(x)\n\tcase *MyDecimal:\n\t\td.SetMysqlDecimal(x)\n\tcase BinaryLiteral:\n\t\td.SetBinaryLiteral(x)\n\tcase BitLiteral: // Store as BinaryLiteral for Bit and Hex literals\n\t\td.SetBinaryLiteral(BinaryLiteral(x))\n\tcase HexLiteral:\n\t\td.SetBinaryLiteral(BinaryLiteral(x))\n\tdefault:\n\t\td.SetInterface(x)\n\t}\n}\n\n// NewDatum creates a new Datum from an interface{}.\nfunc NewDatum(in interface{}) (d Datum) {\n\tswitch x := in.(type) {\n\tcase []interface{}:\n\t\td.SetValue(MakeDatums(x...))\n\tdefault:\n\t\td.SetValue(in)\n\t}\n\treturn d\n}\n\n// NewBytesDatum creates a new Datum from a byte slice.\nfunc NewBytesDatum(b []byte) (d Datum) {\n\td.SetBytes(b)\n\treturn d\n}\n\n// NewStringDatum creates a new Datum from a string.\nfunc NewStringDatum(s string) (d Datum) {\n\td.SetString(s)\n\treturn d\n}\n\n// MakeDatums creates datum slice from interfaces.\nfunc MakeDatums(args ...interface{}) []Datum {\n\tdatums := make([]Datum, len(args))\n\tfor i, v := range args {\n\t\tdatums[i] = NewDatum(v)\n\t}\n\treturn datums\n}\n\n// BinaryLiteral is the internal type for storing bit / hex literal type.\ntype BinaryLiteral []byte\n\n// BitLiteral is the bit literal type.\ntype BitLiteral BinaryLiteral\n\n// HexLiteral is the hex literal type.\ntype HexLiteral BinaryLiteral\n\n// ZeroBinaryLiteral is a BinaryLiteral literal with zero value.\nvar ZeroBinaryLiteral = BinaryLiteral{}\n\n// String implements fmt.Stringer interface.\nfunc (b BinaryLiteral) String() string {\n\tif len(b) == 0 {\n\t\treturn \"\"\n\t}\n\treturn \"0x\" + hex.EncodeToString(b)\n}\n\n// ToString returns the string representation for the literal.\nfunc (b BinaryLiteral) ToString() string {\n\treturn string(b)\n}\n\n// ToBitLiteralString returns the bit literal representation for the literal.\nfunc (b BinaryLiteral) ToBitLiteralString(trimLeadingZero bool) string {\n\tif len(b) == 0 {\n\t\treturn \"b''\"\n\t}\n\tvar buf bytes.Buffer\n\tfor _, data := range b {\n\t\tfmt.Fprintf(&buf, \"%08b\", data)\n\t}\n\tret := buf.Bytes()\n\tif trimLeadingZero {\n\t\tret = bytes.TrimLeft(ret, \"0\")\n\t\tif len(ret) == 0 {\n\t\t\tret = []byte{'0'}\n\t\t}\n\t}\n\treturn fmt.Sprintf(\"b'%s'\", string(ret))\n}\n\n// ParseBitStr parses bit string.\n// The string format can be b'val', B'val' or 0bval, val must be 0 or 1.\n// See https://dev.mysql.com/doc/refman/5.7/en/bit-value-literals.html\nfunc ParseBitStr(s string) (BinaryLiteral, error) {\n\tif len(s) == 0 {\n\t\treturn nil, errors.Errorf(\"invalid empty string for parsing bit type\")\n\t}\n\n\tif s[0] == 'b' || s[0] == 'B' {\n\t\t// format is b'val' or B'val'\n\t\ts = strings.Trim(s[1:], \"'\")\n\t} else if strings.HasPrefix(s, \"0b\") {\n\t\ts = s[2:]\n\t} else {\n\t\t// here means format is not b'val', B'val' or 0bval.\n\t\treturn nil, errors.Errorf(\"invalid bit type format %s\", s)\n\t}\n\n\tif len(s) == 0 {\n\t\treturn ZeroBinaryLiteral, nil\n\t}\n\n\talignedLength := (len(s) + 7) &^ 7\n\ts = (\"00000000\" + s)[len(s)+8-alignedLength:] // Pad with zero (slice from `-alignedLength`)\n\tbyteLength := len(s) >> 3\n\tbuf := make([]byte, byteLength)\n\n\tfor i := 0; i < byteLength; i++ {\n\t\tstrPosition := i << 3\n\t\tval, err := strconv.ParseUint(s[strPosition:strPosition+8], 2, 8)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Trace(err)\n\t\t}\n\t\tbuf[i] = byte(val)\n\t}\n\n\treturn buf, nil\n}\n\n// NewBitLiteral parses bit string as BitLiteral type.\nfunc NewBitLiteral(s string) (BitLiteral, error) {\n\tb, err := ParseBitStr(s)\n\tif err != nil {\n\t\treturn BitLiteral{}, err\n\t}\n\treturn BitLiteral(b), nil\n}\n\n// ToString implement ast.BinaryLiteral interface\nfunc (b BitLiteral) ToString() string {\n\treturn BinaryLiteral(b).ToString()\n}\n\n// ParseHexStr parses hexadecimal string literal.\n// See https://dev.mysql.com/doc/refman/5.7/en/hexadecimal-literals.html\nfunc ParseHexStr(s string) (BinaryLiteral, error) {\n\tif len(s) == 0 {\n\t\treturn nil, errors.Errorf(\"invalid empty string for parsing hexadecimal literal\")\n\t}\n\n\tif s[0] == 'x' || s[0] == 'X' {\n\t\t// format is x'val' or X'val'\n\t\ts = strings.Trim(s[1:], \"'\")\n\t\tif len(s)%2 != 0 {\n\t\t\treturn nil, errors.Errorf(\"invalid hexadecimal format, must even numbers, but %d\", len(s))\n\t\t}\n\t} else if strings.HasPrefix(s, \"0x\") {\n\t\ts = s[2:]\n\t} else {\n\t\t// here means format is not x'val', X'val' or 0xval.\n\t\treturn nil, errors.Errorf(\"invalid hexadecimal format %s\", s)\n\t}\n\n\tif len(s) == 0 {\n\t\treturn ZeroBinaryLiteral, nil\n\t}\n\n\tif len(s)%2 != 0 {\n\t\ts = \"0\" + s\n\t}\n\tbuf, err := hex.DecodeString(s)\n\tif err != nil {\n\t\treturn nil, errors.Trace(err)\n\t}\n\treturn buf, nil\n}\n\n// NewHexLiteral parses hexadecimal string as HexLiteral type.\nfunc NewHexLiteral(s string) (HexLiteral, error) {\n\th, err := ParseHexStr(s)\n\tif err != nil {\n\t\treturn HexLiteral{}, err\n\t}\n\treturn HexLiteral(h), nil\n}\n\n// ToString implement ast.BinaryLiteral interface\nfunc (b HexLiteral) ToString() string {\n\treturn BinaryLiteral(b).ToString()\n}\n\n// SetBinChsClnFlag sets charset, collation as 'binary' and adds binaryFlag to FieldType.\nfunc SetBinChsClnFlag(ft *types.FieldType) {\n\tft.Charset = charset.CharsetBin\n\tft.Collate = charset.CollationBin\n\tft.Flag |= mysql.BinaryFlag\n}\n\n// DefaultFsp is the default digit of fractional seconds part.\n// MySQL use 0 as the default Fsp.\nconst DefaultFsp = int8(0)\n\n// DefaultTypeForValue returns the default FieldType for the value.\nfunc DefaultTypeForValue(value interface{}, tp *types.FieldType) {\n\tswitch x := value.(type) {\n\tcase nil:\n\t\ttp.Tp = mysql.TypeNull\n\t\ttp.Flen = 0\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\tcase bool:\n\t\ttp.Tp = mysql.TypeLonglong\n\t\ttp.Flen = 1\n\t\ttp.Decimal = 0\n\t\ttp.Flag |= mysql.IsBooleanFlag\n\t\tSetBinChsClnFlag(tp)\n\tcase int:\n\t\ttp.Tp = mysql.TypeLonglong\n\t\ttp.Flen = StrLenOfInt64Fast(int64(x))\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\tcase int64:\n\t\ttp.Tp = mysql.TypeLonglong\n\t\ttp.Flen = StrLenOfInt64Fast(x)\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\tcase uint64:\n\t\ttp.Tp = mysql.TypeLonglong\n\t\ttp.Flag |= mysql.UnsignedFlag\n\t\ttp.Flen = StrLenOfUint64Fast(x)\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\tcase string:\n\t\ttp.Tp = mysql.TypeVarString\n\t\t// TODO: tp.Flen should be len(x) * 3 (max bytes length of CharsetUTF8)\n\t\ttp.Flen = len(x)\n\t\ttp.Decimal = types.UnspecifiedLength\n\t\ttp.Charset, tp.Collate = charset.GetDefaultCharsetAndCollate()\n\tcase float32:\n\t\ttp.Tp = mysql.TypeFloat\n\t\ts := strconv.FormatFloat(float64(x), 'f', -1, 32)\n\t\ttp.Flen = len(s)\n\t\ttp.Decimal = types.UnspecifiedLength\n\t\tSetBinChsClnFlag(tp)\n\tcase float64:\n\t\ttp.Tp = mysql.TypeDouble\n\t\ts := strconv.FormatFloat(x, 'f', -1, 64)\n\t\ttp.Flen = len(s)\n\t\ttp.Decimal = types.UnspecifiedLength\n\t\tSetBinChsClnFlag(tp)\n\tcase []byte:\n\t\ttp.Tp = mysql.TypeBlob\n\t\ttp.Flen = len(x)\n\t\ttp.Decimal = types.UnspecifiedLength\n\t\tSetBinChsClnFlag(tp)\n\tcase BitLiteral:\n\t\ttp.Tp = mysql.TypeVarString\n\t\ttp.Flen = len(x)\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\tcase HexLiteral:\n\t\ttp.Tp = mysql.TypeVarString\n\t\ttp.Flen = len(x) * 3\n\t\ttp.Decimal = 0\n\t\ttp.Flag |= mysql.UnsignedFlag\n\t\tSetBinChsClnFlag(tp)\n\tcase BinaryLiteral:\n\t\ttp.Tp = mysql.TypeBit\n\t\ttp.Flen = len(x) * 8\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\t\ttp.Flag &= ^mysql.BinaryFlag\n\t\ttp.Flag |= mysql.UnsignedFlag\n\tcase *MyDecimal:\n\t\ttp.Tp = mysql.TypeNewDecimal\n\t\ttp.Flen = len(x.ToString())\n\t\ttp.Decimal = int(x.digitsFrac)\n\t\tSetBinChsClnFlag(tp)\n\tdefault:\n\t\ttp.Tp = mysql.TypeUnspecified\n\t\ttp.Flen = types.UnspecifiedLength\n\t\ttp.Decimal = types.UnspecifiedLength\n\t}\n}\n"
  },
  {
    "path": "pkg/parser/test_driver/test_driver_helper.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n//go:build !codes\n// +build !codes\n\npackage test_driver\n\nimport (\n\t\"math\"\n)\n\nfunc isSpace(c byte) bool {\n\treturn c == ' ' || c == '\\t'\n}\n\nfunc isDigit(c byte) bool {\n\treturn c >= '0' && c <= '9'\n}\n\nfunc myMin(a, b int) int {\n\tif a < b {\n\t\treturn a\n\t}\n\treturn b\n}\n\nfunc pow10(x int) int32 {\n\treturn int32(math.Pow10(x))\n}\n\nfunc Abs(n int64) int64 {\n\ty := n >> 63\n\treturn (n ^ y) - y\n}\n\n// uintSizeTable is used as a table to do comparison to get uint length is faster than doing loop on division with 10\nvar uintSizeTable = [21]uint64{\n\t0, // redundant 0 here, so to make function StrLenOfUint64Fast to count from 1 and return i directly\n\t9, 99, 999, 9999, 99999,\n\t999999, 9999999, 99999999, 999999999, 9999999999,\n\t99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999,\n\t9999999999999999, 99999999999999999, 999999999999999999, 9999999999999999999,\n\tmath.MaxUint64,\n} // math.MaxUint64 is 18446744073709551615 and it has 20 digits\n\n// StrLenOfUint64Fast efficiently calculate the string character lengths of an uint64 as input\nfunc StrLenOfUint64Fast(x uint64) int {\n\tfor i := 1; ; i++ {\n\t\tif x <= uintSizeTable[i] {\n\t\t\treturn i\n\t\t}\n\t}\n}\n\n// StrLenOfInt64Fast efficiently calculate the string character lengths of an int64 as input\nfunc StrLenOfInt64Fast(x int64) int {\n\tsize := 0\n\tif x < 0 {\n\t\tsize = 1 // add \"-\" sign on the length count\n\t}\n\treturn size + StrLenOfUint64Fast(uint64(Abs(x)))\n}\n"
  },
  {
    "path": "pkg/parser/test_driver/test_driver_mydecimal.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n//go:build !codes\n// +build !codes\n\npackage test_driver\n\nconst panicInfo = \"This branch is not implemented. \" +\n\t\"This is because you are trying to test something specific to TiDB's MyDecimal implementation. \" +\n\t\"It is recommended to do this in TiDB repository.\"\n\n// constant values.\nconst (\n\tmaxWordBufLen = 9 // A MyDecimal holds 9 words.\n\tdigitsPerWord = 9 // A word holds 9 digits.\n\tdigMask       = 100000000\n)\n\nvar (\n\twordBufLen = 9\n)\n\n// fixWordCntError limits word count in wordBufLen, and returns overflow or truncate error.\nfunc fixWordCntError(wordsInt, wordsFrac int) (newWordsInt int, newWordsFrac int, err error) {\n\tif wordsInt+wordsFrac > wordBufLen {\n\t\tpanic(panicInfo)\n\t}\n\treturn wordsInt, wordsFrac, nil\n}\n\n/*\ncountLeadingZeroes returns the number of leading zeroes that can be removed from fraction.\n\n@param   i    start index\n@param   word value to compare against list of powers of 10\n*/\nfunc countLeadingZeroes(i int, word int32) int {\n\tleading := 0\n\tfor word < pow10(i) {\n\t\ti--\n\t\tleading++\n\t}\n\treturn leading\n}\n\nfunc digitsToWords(digits int) int {\n\treturn (digits + digitsPerWord - 1) / digitsPerWord\n}\n\n// MyDecimal represents a decimal value.\ntype MyDecimal struct {\n\tdigitsInt int8 // the number of *decimal* digits before the point.\n\n\tdigitsFrac int8 // the number of decimal digits after the point.\n\n\tresultFrac int8 // result fraction digits.\n\n\tnegative bool\n\n\t// wordBuf is an array of int32 words.\n\t// A word is an int32 value can hold 9 digits.(0 <= word < wordBase)\n\twordBuf [maxWordBufLen]int32\n}\n\n// String returns the decimal string representation rounded to resultFrac.\nfunc (d *MyDecimal) String() string {\n\ttmp := *d\n\treturn string(tmp.ToString())\n}\n\nfunc (d *MyDecimal) stringSize() int {\n\t// sign, zero integer and dot.\n\treturn int(d.digitsInt + d.digitsFrac + 3)\n}\n\nfunc (d *MyDecimal) removeLeadingZeros() (wordIdx int, digitsInt int) {\n\tdigitsInt = int(d.digitsInt)\n\ti := ((digitsInt - 1) % digitsPerWord) + 1\n\tfor digitsInt > 0 && d.wordBuf[wordIdx] == 0 {\n\t\tdigitsInt -= i\n\t\ti = digitsPerWord\n\t\twordIdx++\n\t}\n\tif digitsInt > 0 {\n\t\tdigitsInt -= countLeadingZeroes((digitsInt-1)%digitsPerWord, d.wordBuf[wordIdx])\n\t} else {\n\t\tdigitsInt = 0\n\t}\n\treturn\n}\n\n// ToString converts decimal to its printable string representation without rounding.\n//\n//\tRETURN VALUE\n//\n//\t    str       - result string\n//\t    errCode   - eDecOK/eDecTruncate/eDecOverflow\nfunc (d *MyDecimal) ToString() (str []byte) {\n\tstr = make([]byte, d.stringSize())\n\tdigitsFrac := int(d.digitsFrac)\n\twordStartIdx, digitsInt := d.removeLeadingZeros()\n\tif digitsInt+digitsFrac == 0 {\n\t\tdigitsInt = 1\n\t\twordStartIdx = 0\n\t}\n\n\tdigitsIntLen := digitsInt\n\tif digitsIntLen == 0 {\n\t\tdigitsIntLen = 1\n\t}\n\tdigitsFracLen := digitsFrac\n\tlength := digitsIntLen + digitsFracLen\n\tif d.negative {\n\t\tlength++\n\t}\n\tif digitsFrac > 0 {\n\t\tlength++\n\t}\n\tstr = str[:length]\n\tstrIdx := 0\n\tif d.negative {\n\t\tstr[strIdx] = '-'\n\t\tstrIdx++\n\t}\n\tvar fill int\n\tif digitsFrac > 0 {\n\t\tfracIdx := strIdx + digitsIntLen\n\t\tfill = digitsFracLen - digitsFrac\n\t\twordIdx := wordStartIdx + digitsToWords(digitsInt)\n\t\tstr[fracIdx] = '.'\n\t\tfracIdx++\n\t\tfor ; digitsFrac > 0; digitsFrac -= digitsPerWord {\n\t\t\tx := d.wordBuf[wordIdx]\n\t\t\twordIdx++\n\t\t\tfor i := myMin(digitsFrac, digitsPerWord); i > 0; i-- {\n\t\t\t\ty := x / digMask\n\t\t\t\tstr[fracIdx] = byte(y) + '0'\n\t\t\t\tfracIdx++\n\t\t\t\tx -= y * digMask\n\t\t\t\tx *= 10\n\t\t\t}\n\t\t}\n\t\tfor ; fill > 0; fill-- {\n\t\t\tstr[fracIdx] = '0'\n\t\t\tfracIdx++\n\t\t}\n\t}\n\tfill = digitsIntLen - digitsInt\n\tif digitsInt == 0 {\n\t\tfill-- /* symbol 0 before digital point */\n\t}\n\tfor ; fill > 0; fill-- {\n\t\tstr[strIdx] = '0'\n\t\tstrIdx++\n\t}\n\tif digitsInt > 0 {\n\t\tstrIdx += digitsInt\n\t\twordIdx := wordStartIdx + digitsToWords(digitsInt)\n\t\tfor ; digitsInt > 0; digitsInt -= digitsPerWord {\n\t\t\twordIdx--\n\t\t\tx := d.wordBuf[wordIdx]\n\t\t\tfor i := myMin(digitsInt, digitsPerWord); i > 0; i-- {\n\t\t\t\ty := x / 10\n\t\t\t\tstrIdx--\n\t\t\t\tstr[strIdx] = '0' + byte(x-y*10)\n\t\t\t\tx = y\n\t\t\t}\n\t\t}\n\t} else {\n\t\tstr[strIdx] = '0'\n\t}\n\treturn\n}\n\n// FromString parses decimal from string.\nfunc (d *MyDecimal) FromString(str []byte) error {\n\tfor i := 0; i < len(str); i++ {\n\t\tif !isSpace(str[i]) {\n\t\t\tstr = str[i:]\n\t\t\tbreak\n\t\t}\n\t}\n\tif len(str) == 0 {\n\t\tpanic(panicInfo)\n\t}\n\tswitch str[0] {\n\tcase '-':\n\t\td.negative = true\n\t\tfallthrough\n\tcase '+':\n\t\tstr = str[1:]\n\t}\n\tvar strIdx int\n\tfor strIdx < len(str) && isDigit(str[strIdx]) {\n\t\tstrIdx++\n\t}\n\tdigitsInt := strIdx\n\tvar digitsFrac int\n\tvar endIdx int\n\tif strIdx < len(str) && str[strIdx] == '.' {\n\t\tendIdx = strIdx + 1\n\t\tfor endIdx < len(str) && isDigit(str[endIdx]) {\n\t\t\tendIdx++\n\t\t}\n\t\tdigitsFrac = endIdx - strIdx - 1\n\t} else {\n\t\tdigitsFrac = 0\n\t\tendIdx = strIdx\n\t}\n\tif digitsInt+digitsFrac == 0 {\n\t\tpanic(panicInfo)\n\t}\n\twordsInt := digitsToWords(digitsInt)\n\twordsFrac := digitsToWords(digitsFrac)\n\twordsInt, wordsFrac, err := fixWordCntError(wordsInt, wordsFrac)\n\tif err != nil {\n\t\tpanic(panicInfo)\n\t}\n\td.digitsInt = int8(digitsInt)\n\td.digitsFrac = int8(digitsFrac)\n\twordIdx := wordsInt\n\tstrIdxTmp := strIdx\n\tvar word int32\n\tvar innerIdx int\n\tfor digitsInt > 0 {\n\t\tdigitsInt--\n\t\tstrIdx--\n\t\tword += int32(str[strIdx]-'0') * pow10(innerIdx)\n\t\tinnerIdx++\n\t\tif innerIdx == digitsPerWord {\n\t\t\twordIdx--\n\t\t\td.wordBuf[wordIdx] = word\n\t\t\tword = 0\n\t\t\tinnerIdx = 0\n\t\t}\n\t}\n\tif innerIdx != 0 {\n\t\twordIdx--\n\t\td.wordBuf[wordIdx] = word\n\t}\n\n\twordIdx = wordsInt\n\tstrIdx = strIdxTmp\n\tword = 0\n\tinnerIdx = 0\n\tfor digitsFrac > 0 {\n\t\tdigitsFrac--\n\t\tstrIdx++\n\t\tword = int32(str[strIdx]-'0') + word*10\n\t\tinnerIdx++\n\t\tif innerIdx == digitsPerWord {\n\t\t\td.wordBuf[wordIdx] = word\n\t\t\twordIdx++\n\t\t\tword = 0\n\t\t\tinnerIdx = 0\n\t\t}\n\t}\n\tif innerIdx != 0 {\n\t\td.wordBuf[wordIdx] = word * pow10(digitsPerWord-innerIdx)\n\t}\n\tif endIdx+1 <= len(str) && (str[endIdx] == 'e' || str[endIdx] == 'E') {\n\t\tpanic(panicInfo)\n\t}\n\tallZero := true\n\tfor i := 0; i < wordBufLen; i++ {\n\t\tif d.wordBuf[i] != 0 {\n\t\t\tallZero = false\n\t\t\tbreak\n\t\t}\n\t}\n\tif allZero {\n\t\td.negative = false\n\t}\n\td.resultFrac = d.digitsFrac\n\treturn err\n}\n"
  },
  {
    "path": "pkg/parser/types/etc.go",
    "content": "// Copyright 2014 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n)\n\n// IsTypeBlob returns a boolean indicating whether the tp is a blob type.\nfunc IsTypeBlob(tp byte) bool {\n\tswitch tp {\n\tcase mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeBlob, mysql.TypeLongBlob:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// IsTypeChar returns a boolean indicating\n// whether the tp is the char type like a string type or a varchar type.\nfunc IsTypeChar(tp byte) bool {\n\treturn tp == mysql.TypeString || tp == mysql.TypeVarchar\n}\n\nvar type2Str = map[byte]string{\n\tmysql.TypeBit:        \"bit\",\n\tmysql.TypeBlob:       \"text\",\n\tmysql.TypeDate:       \"date\",\n\tmysql.TypeDatetime:   \"datetime\",\n\tmysql.TypeDecimal:    \"unspecified\",\n\tmysql.TypeNewDecimal: \"decimal\",\n\tmysql.TypeDouble:     \"double\",\n\tmysql.TypeEnum:       \"enum\",\n\tmysql.TypeFloat:      \"float\",\n\tmysql.TypeGeometry:   \"geometry\",\n\tmysql.TypeInt24:      \"mediumint\",\n\tmysql.TypeJSON:       \"json\",\n\tmysql.TypeLong:       \"int\",\n\tmysql.TypeLonglong:   \"bigint\",\n\tmysql.TypeLongBlob:   \"longtext\",\n\tmysql.TypeMediumBlob: \"mediumtext\",\n\tmysql.TypeNull:       \"null\",\n\tmysql.TypeSet:        \"set\",\n\tmysql.TypeShort:      \"smallint\",\n\tmysql.TypeString:     \"char\",\n\tmysql.TypeDuration:   \"time\",\n\tmysql.TypeTimestamp:  \"timestamp\",\n\tmysql.TypeTiny:       \"tinyint\",\n\tmysql.TypeTinyBlob:   \"tinytext\",\n\tmysql.TypeVarchar:    \"varchar\",\n\tmysql.TypeVarString:  \"var_string\",\n\tmysql.TypeYear:       \"year\",\n}\n\n// TypeStr converts tp to a string.\nfunc TypeStr(tp byte) (r string) {\n\treturn type2Str[tp]\n}\n\n// TypeToStr converts a field to a string.\n// It is used for converting Text to Blob,\n// or converting Char to Binary.\n// Args:\n//\n//\ttp: type enum\n//\tcs: charset\nfunc TypeToStr(tp byte, cs string) (r string) {\n\tts := type2Str[tp]\n\tif cs != \"binary\" {\n\t\treturn ts\n\t}\n\tif IsTypeBlob(tp) {\n\t\tts = strings.Replace(ts, \"text\", \"blob\", 1)\n\t} else if IsTypeChar(tp) {\n\t\tts = strings.Replace(ts, \"char\", \"binary\", 1)\n\t}\n\treturn ts\n}\n\nvar (\n\tdig2bytes = [10]int{0, 1, 1, 2, 2, 3, 3, 4, 4, 4}\n)\n\n// constant values.\nconst (\n\tdigitsPerWord = 9 // A word holds 9 digits.\n\twordSize      = 4 // A word is 4 bytes int32.\n)\n\n// ErrInvalidDefault is returned when meet a invalid default value.\nvar ErrInvalidDefault = terror.ClassTypes.New(mysql.ErrInvalidDefault, mysql.MySQLErrName[mysql.ErrInvalidDefault])\n"
  },
  {
    "path": "pkg/parser/types/eval_type.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\n// EvalType indicates the specified types that arguments and result of a built-in function should be.\ntype EvalType byte\n\nconst (\n\t// ETInt represents type INT in evaluation.\n\tETInt EvalType = iota\n\t// ETReal represents type REAL in evaluation.\n\tETReal\n\t// ETDecimal represents type DECIMAL in evaluation.\n\tETDecimal\n\t// ETString represents type STRING in evaluation.\n\tETString\n\t// ETDatetime represents type DATETIME in evaluation.\n\tETDatetime\n\t// ETTimestamp represents type TIMESTAMP in evaluation.\n\tETTimestamp\n\t// ETDuration represents type DURATION in evaluation.\n\tETDuration\n\t// ETJson represents type JSON in evaluation.\n\tETJson\n)\n\n// IsStringKind returns true for ETString, ETDatetime, ETTimestamp, ETDuration, ETJson EvalTypes.\nfunc (et EvalType) IsStringKind() bool {\n\treturn et == ETString || et == ETDatetime ||\n\t\tet == ETTimestamp || et == ETDuration || et == ETJson\n}\n"
  },
  {
    "path": "pkg/parser/types/field_type.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n)\n\n// UnspecifiedLength is unspecified length.\nconst (\n\tUnspecifiedLength = -1\n)\n\n// FieldType records field type information.\ntype FieldType struct {\n\tTp      byte\n\tFlag    uint\n\tFlen    int\n\tDecimal int\n\tCharset string\n\tCollate string\n\t// Elems is the element list for enum and set type.\n\tElems []string\n}\n\n// NewFieldType returns a FieldType,\n// with a type and other information about field type.\nfunc NewFieldType(tp byte) *FieldType {\n\treturn &FieldType{\n\t\tTp:      tp,\n\t\tFlen:    UnspecifiedLength,\n\t\tDecimal: UnspecifiedLength,\n\t}\n}\n\n// Clone returns a copy of itself.\nfunc (ft *FieldType) Clone() *FieldType {\n\tret := *ft\n\treturn &ret\n}\n\n// Equal checks whether two FieldType objects are equal.\nfunc (ft *FieldType) Equal(other *FieldType) bool {\n\t// We do not need to compare whole `ft.Flag == other.Flag` when wrapping cast upon an Expression.\n\t// but need compare unsigned_flag of ft.Flag.\n\tpartialEqual := ft.Tp == other.Tp &&\n\t\tft.Flen == other.Flen &&\n\t\tft.Decimal == other.Decimal &&\n\t\tmysql.HasUnsignedFlag(ft.Flag) == mysql.HasUnsignedFlag(other.Flag)\n\tif !partialEqual || len(ft.Elems) != len(other.Elems) {\n\t\treturn false\n\t}\n\tfor i := range ft.Elems {\n\t\tif ft.Elems[i] != other.Elems[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// EvalType gets the type in evaluation.\nfunc (ft *FieldType) EvalType() EvalType {\n\tswitch ft.Tp {\n\tcase mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong,\n\t\tmysql.TypeBit, mysql.TypeYear:\n\t\treturn ETInt\n\tcase mysql.TypeFloat, mysql.TypeDouble:\n\t\treturn ETReal\n\tcase mysql.TypeNewDecimal:\n\t\treturn ETDecimal\n\tcase mysql.TypeDate, mysql.TypeDatetime:\n\t\treturn ETDatetime\n\tcase mysql.TypeTimestamp:\n\t\treturn ETTimestamp\n\tcase mysql.TypeDuration:\n\t\treturn ETDuration\n\tcase mysql.TypeJSON:\n\t\treturn ETJson\n\t}\n\treturn ETString\n}\n\nfunc (ft *FieldType) IsInt() bool {\n\tswitch ft.Tp {\n\tcase mysql.TypeTiny, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeShort:\n\t\treturn true\n\tcase mysql.TypeDecimal, mysql.TypeNewDecimal:\n\t\tif ft.Decimal == 0 {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Hybrid checks whether a type is a hybrid type, which can represent different types of value in specific context.\nfunc (ft *FieldType) Hybrid() bool {\n\treturn ft.Tp == mysql.TypeEnum || ft.Tp == mysql.TypeBit || ft.Tp == mysql.TypeSet\n}\n\n// Init initializes the FieldType data.\nfunc (ft *FieldType) Init(tp byte) {\n\tft.Tp = tp\n\tft.Flen = UnspecifiedLength\n\tft.Decimal = UnspecifiedLength\n}\n\n// CompactStr only considers Tp/CharsetBin/Flen/Deimal.\n// This is used for showing column type in infoschema.\nfunc (ft *FieldType) CompactStr() string {\n\tts := TypeToStr(ft.Tp, ft.Charset)\n\tsuffix := \"\"\n\n\tdefaultFlen, defaultDecimal := mysql.GetDefaultFieldLengthAndDecimal(ft.Tp)\n\tisDecimalNotDefault := ft.Decimal != defaultDecimal && ft.Decimal != 0 && ft.Decimal != UnspecifiedLength\n\n\t// displayFlen and displayDecimal are flen and decimal values with `-1` substituted with default value.\n\tdisplayFlen, displayDecimal := ft.Flen, ft.Decimal\n\tif displayFlen == 0 || displayFlen == UnspecifiedLength {\n\t\tdisplayFlen = defaultFlen\n\t}\n\tif displayDecimal == 0 || displayDecimal == UnspecifiedLength {\n\t\tdisplayDecimal = defaultDecimal\n\t}\n\n\tswitch ft.Tp {\n\tcase mysql.TypeEnum, mysql.TypeSet:\n\t\t// Format is ENUM ('e1', 'e2') or SET ('e1', 'e2')\n\t\tes := make([]string, 0, len(ft.Elems))\n\t\tfor _, e := range ft.Elems {\n\t\t\te = format.OutputFormat(e)\n\t\t\tes = append(es, e)\n\t\t}\n\t\tsuffix = fmt.Sprintf(\"('%s')\", strings.Join(es, \"','\"))\n\tcase mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDuration:\n\t\tif isDecimalNotDefault {\n\t\t\tsuffix = fmt.Sprintf(\"(%d)\", displayDecimal)\n\t\t}\n\tcase mysql.TypeDouble, mysql.TypeFloat:\n\t\t// 1. Flen Not Default, Decimal Not Default -> Valid\n\t\t// 2. Flen Not Default, Decimal Default (-1) -> Invalid\n\t\t// 3. Flen Default, Decimal Not Default -> Valid\n\t\t// 4. Flen Default, Decimal Default -> Valid (hide)\n\t\tif isDecimalNotDefault {\n\t\t\tsuffix = fmt.Sprintf(\"(%d,%d)\", displayFlen, displayDecimal)\n\t\t}\n\tcase mysql.TypeNewDecimal:\n\t\tsuffix = fmt.Sprintf(\"(%d,%d)\", displayFlen, displayDecimal)\n\tcase mysql.TypeBit, mysql.TypeShort, mysql.TypeTiny, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeVarchar, mysql.TypeString, mysql.TypeVarString:\n\t\t// Flen is always shown.\n\t\tsuffix = fmt.Sprintf(\"(%d)\", displayFlen)\n\tcase mysql.TypeYear:\n\t\tsuffix = fmt.Sprintf(\"(%d)\", ft.Flen)\n\t}\n\treturn ts + suffix\n}\n\n// InfoSchemaStr joins the CompactStr with unsigned flag and\n// returns a string.\nfunc (ft *FieldType) InfoSchemaStr() string {\n\tsuffix := \"\"\n\tif mysql.HasUnsignedFlag(ft.Flag) {\n\t\tsuffix = \" unsigned\"\n\t}\n\treturn ft.CompactStr() + suffix\n}\n\n// String joins the information of FieldType and returns a string.\n// Note: when flen or decimal is unspecified, this function will use the default value instead of -1.\nfunc (ft *FieldType) String() string {\n\tstrs := []string{ft.CompactStr()}\n\tif mysql.HasUnsignedFlag(ft.Flag) {\n\t\tstrs = append(strs, \"UNSIGNED\")\n\t}\n\tif mysql.HasZerofillFlag(ft.Flag) {\n\t\tstrs = append(strs, \"ZEROFILL\")\n\t}\n\tif mysql.HasBinaryFlag(ft.Flag) && ft.Tp != mysql.TypeString {\n\t\tstrs = append(strs, \"BINARY\")\n\t}\n\n\tif IsTypeChar(ft.Tp) || IsTypeBlob(ft.Tp) {\n\t\tif ft.Charset != \"\" && ft.Charset != charset.CharsetBin {\n\t\t\tstrs = append(strs, fmt.Sprintf(\"CHARACTER SET %s\", ft.Charset))\n\t\t}\n\t\tif ft.Collate != \"\" && ft.Collate != charset.CharsetBin {\n\t\t\tstrs = append(strs, fmt.Sprintf(\"COLLATE %s\", ft.Collate))\n\t\t}\n\t}\n\n\treturn strings.Join(strs, \" \")\n}\n\n// Restore implements Node interface.\nfunc (ft *FieldType) Restore(ctx *format.RestoreCtx) error {\n\tctx.WriteKeyWord(TypeToStr(ft.Tp, ft.Charset))\n\n\tprecision := UnspecifiedLength\n\tscale := UnspecifiedLength\n\n\tswitch ft.Tp {\n\tcase mysql.TypeEnum, mysql.TypeSet:\n\t\tctx.WritePlain(\"(\")\n\t\tfor i, e := range ft.Elems {\n\t\t\tif i != 0 {\n\t\t\t\tctx.WritePlain(\",\")\n\t\t\t}\n\t\t\tctx.WriteString(e)\n\t\t}\n\t\tctx.WritePlain(\")\")\n\tcase mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDuration:\n\t\tprecision = ft.Decimal\n\tcase mysql.TypeDecimal, mysql.TypeFloat, mysql.TypeDouble, mysql.TypeNewDecimal:\n\t\tprecision = ft.Flen\n\t\tscale = ft.Decimal\n\tdefault:\n\t\tprecision = ft.Flen\n\t}\n\n\tif precision != UnspecifiedLength {\n\t\tctx.WritePlainf(\"(%d\", precision)\n\t\tif scale != UnspecifiedLength {\n\t\t\tctx.WritePlainf(\",%d\", scale)\n\t\t}\n\t\tctx.WritePlain(\")\")\n\t}\n\n\tif mysql.HasUnsignedFlag(ft.Flag) {\n\t\tctx.WriteKeyWord(\" UNSIGNED\")\n\t}\n\tif mysql.HasZerofillFlag(ft.Flag) {\n\t\tctx.WriteKeyWord(\" ZEROFILL\")\n\t}\n\tif mysql.HasBinaryFlag(ft.Flag) && ft.Charset != charset.CharsetBin {\n\t\tctx.WriteKeyWord(\" BINARY\")\n\t}\n\n\tif IsTypeChar(ft.Tp) || IsTypeBlob(ft.Tp) {\n\t\tif ft.Charset != \"\" && ft.Charset != charset.CharsetBin {\n\t\t\tctx.WriteKeyWord(\" CHARACTER SET \" + ft.Charset)\n\t\t}\n\t\tif ft.Collate != \"\" && ft.Collate != charset.CharsetBin {\n\t\t\tctx.WriteKeyWord(\" COLLATE \")\n\t\t\tctx.WritePlain(ft.Collate)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// RestoreAsCastType is used for write AST back to string.\nfunc (ft *FieldType) RestoreAsCastType(ctx *format.RestoreCtx) error {\n\tkeyword, plainWord, err := ctx.Dialect.ConvertCastTypeToString(ft.Tp, ft.Flen, ft.Decimal, ft.Flag)\n\tif err != nil {\n\t\treturn err\n\t}\n\tctx.WriteKeyWord(keyword)\n\tif plainWord != \"\" {\n\t\tctx.WritePlain(plainWord)\n\t}\n\treturn nil\n}\n\n// FormatAsCastType is used for write AST back to string.\nfunc (ft *FieldType) FormatAsCastType(w io.Writer) error {\n\tvar sb strings.Builder\n\trestoreCtx := format.NewRestoreCtx(format.DefaultRestoreFlags, &sb)\n\terr := ft.RestoreAsCastType(restoreCtx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfmt.Fprint(w, sb.String())\n\treturn nil\n}\n\n// VarStorageLen indicates this column is a variable length column.\nconst VarStorageLen = -1\n\n// StorageLength is the length of stored value for the type.\nfunc (ft *FieldType) StorageLength() int {\n\tswitch ft.Tp {\n\tcase mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong,\n\t\tmysql.TypeLonglong, mysql.TypeDouble, mysql.TypeFloat, mysql.TypeYear, mysql.TypeDuration,\n\t\tmysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp, mysql.TypeEnum, mysql.TypeSet,\n\t\tmysql.TypeBit:\n\t\t// This may not be the accurate length, because we may encode them as varint.\n\t\treturn 8\n\tcase mysql.TypeNewDecimal:\n\t\tprecision, frac := ft.Flen-ft.Decimal, ft.Decimal\n\t\treturn precision/digitsPerWord*wordSize + dig2bytes[precision%digitsPerWord] + frac/digitsPerWord*wordSize + dig2bytes[frac%digitsPerWord]\n\tdefault:\n\t\treturn VarStorageLen\n\t}\n}\n\n// HasCharset indicates if a COLUMN has an associated charset. Returning false here prevents some information\n// statements(like `SHOW CREATE TABLE`) from attaching a CHARACTER SET clause to the column.\nfunc HasCharset(ft *FieldType) bool {\n\tswitch ft.Tp {\n\tcase mysql.TypeVarchar, mysql.TypeString, mysql.TypeVarString, mysql.TypeBlob,\n\t\tmysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob:\n\t\treturn !mysql.HasBinaryFlag(ft.Flag)\n\tcase mysql.TypeEnum, mysql.TypeSet:\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "pkg/parser/types/field_type_test.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t. \"github.com/secretflow/scql/pkg/parser/types\"\n\n\t// import parser_driver\n\t_ \"github.com/secretflow/scql/pkg/parser/test_driver\"\n)\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nvar _ = Suite(&testFieldTypeSuite{})\n\ntype testFieldTypeSuite struct {\n}\n\nfunc (s *testFieldTypeSuite) TestFieldType(c *C) {\n\tft := NewFieldType(mysql.TypeDuration)\n\tc.Assert(ft.Flen, Equals, UnspecifiedLength)\n\tc.Assert(ft.Decimal, Equals, UnspecifiedLength)\n\tft.Decimal = 5\n\tc.Assert(ft.String(), Equals, \"time(5)\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\n\tft = NewFieldType(mysql.TypeLong)\n\tft.Flen = 5\n\tft.Flag = mysql.UnsignedFlag | mysql.ZerofillFlag\n\tc.Assert(ft.String(), Equals, \"int(5) UNSIGNED ZEROFILL\")\n\tc.Assert(ft.InfoSchemaStr(), Equals, \"int(5) unsigned\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\n\tft = NewFieldType(mysql.TypeFloat)\n\tft.Flen = 12   // Default\n\tft.Decimal = 3 // Not Default\n\tc.Assert(ft.String(), Equals, \"float(12,3)\")\n\tft = NewFieldType(mysql.TypeFloat)\n\tft.Flen = 12    // Default\n\tft.Decimal = -1 // Default\n\tc.Assert(ft.String(), Equals, \"float\")\n\tft = NewFieldType(mysql.TypeFloat)\n\tft.Flen = 5     // Not Default\n\tft.Decimal = -1 // Default\n\tc.Assert(ft.String(), Equals, \"float\")\n\tft = NewFieldType(mysql.TypeFloat)\n\tft.Flen = 7    // Not Default\n\tft.Decimal = 3 // Not Default\n\tc.Assert(ft.String(), Equals, \"float(7,3)\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\n\tft = NewFieldType(mysql.TypeDouble)\n\tft.Flen = 22   // Default\n\tft.Decimal = 3 // Not Default\n\tc.Assert(ft.String(), Equals, \"double(22,3)\")\n\tft = NewFieldType(mysql.TypeDouble)\n\tft.Flen = 22    // Default\n\tft.Decimal = -1 // Default\n\tc.Assert(ft.String(), Equals, \"double\")\n\tft = NewFieldType(mysql.TypeDouble)\n\tft.Flen = 5     // Not Default\n\tft.Decimal = -1 // Default\n\tc.Assert(ft.String(), Equals, \"double\")\n\tft = NewFieldType(mysql.TypeDouble)\n\tft.Flen = 7    // Not Default\n\tft.Decimal = 3 // Not Default\n\tc.Assert(ft.String(), Equals, \"double(7,3)\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\n\tft = NewFieldType(mysql.TypeBlob)\n\tft.Flen = 10\n\tft.Charset = \"UTF8\"\n\tft.Collate = \"UTF8_UNICODE_GI\"\n\tc.Assert(ft.String(), Equals, \"text CHARACTER SET UTF8 COLLATE UTF8_UNICODE_GI\")\n\tc.Assert(HasCharset(ft), IsTrue)\n\n\tft = NewFieldType(mysql.TypeVarchar)\n\tft.Flen = 10\n\tft.Flag |= mysql.BinaryFlag\n\tc.Assert(ft.String(), Equals, \"varchar(10) BINARY\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\n\tft = NewFieldType(mysql.TypeString)\n\tft.Charset = charset.CollationBin\n\tft.Flag |= mysql.BinaryFlag\n\tc.Assert(ft.String(), Equals, \"binary(1)\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\n\tft = NewFieldType(mysql.TypeEnum)\n\tft.Elems = []string{\"a\", \"b\"}\n\tc.Assert(ft.String(), Equals, \"enum('a','b')\")\n\tc.Assert(HasCharset(ft), IsTrue)\n\n\tft = NewFieldType(mysql.TypeEnum)\n\tft.Elems = []string{\"'a'\", \"'b'\"}\n\tc.Assert(ft.String(), Equals, \"enum('''a''','''b''')\")\n\tc.Assert(HasCharset(ft), IsTrue)\n\n\tft = NewFieldType(mysql.TypeEnum)\n\tft.Elems = []string{\"a\\nb\", \"a\\tb\", \"a\\rb\"}\n\tc.Assert(ft.String(), Equals, \"enum('a\\\\nb','a\\tb','a\\\\rb')\")\n\tc.Assert(HasCharset(ft), IsTrue)\n\n\tft = NewFieldType(mysql.TypeEnum)\n\tft.Elems = []string{\"a\\nb\", \"a'\\t\\r\\nb\", \"a\\rb\"}\n\tc.Assert(ft.String(), Equals, \"enum('a\\\\nb','a''\t\\\\r\\\\nb','a\\\\rb')\")\n\tc.Assert(HasCharset(ft), IsTrue)\n\n\tft = NewFieldType(mysql.TypeSet)\n\tft.Elems = []string{\"a\", \"b\"}\n\tc.Assert(ft.String(), Equals, \"set('a','b')\")\n\tc.Assert(HasCharset(ft), IsTrue)\n\n\tft = NewFieldType(mysql.TypeSet)\n\tft.Elems = []string{\"'a'\", \"'b'\"}\n\tc.Assert(ft.String(), Equals, \"set('''a''','''b''')\")\n\tc.Assert(HasCharset(ft), IsTrue)\n\n\tft = NewFieldType(mysql.TypeSet)\n\tft.Elems = []string{\"a\\nb\", \"a'\\t\\r\\nb\", \"a\\rb\"}\n\tc.Assert(ft.String(), Equals, \"set('a\\\\nb','a''\t\\\\r\\\\nb','a\\\\rb')\")\n\tc.Assert(HasCharset(ft), IsTrue)\n\n\tft = NewFieldType(mysql.TypeSet)\n\tft.Elems = []string{\"a'\\nb\", \"a'b\\tc\"}\n\tc.Assert(ft.String(), Equals, \"set('a''\\\\nb','a''b\tc')\")\n\tc.Assert(HasCharset(ft), IsTrue)\n\n\tft = NewFieldType(mysql.TypeTimestamp)\n\tft.Flen = 8\n\tft.Decimal = 2\n\tc.Assert(ft.String(), Equals, \"timestamp(2)\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\tft = NewFieldType(mysql.TypeTimestamp)\n\tft.Flen = 8\n\tft.Decimal = 0\n\tc.Assert(ft.String(), Equals, \"timestamp\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\n\tft = NewFieldType(mysql.TypeDatetime)\n\tft.Flen = 8\n\tft.Decimal = 2\n\tc.Assert(ft.String(), Equals, \"datetime(2)\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\tft = NewFieldType(mysql.TypeDatetime)\n\tft.Flen = 8\n\tft.Decimal = 0\n\tc.Assert(ft.String(), Equals, \"datetime\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\n\tft = NewFieldType(mysql.TypeDate)\n\tft.Flen = 8\n\tft.Decimal = 2\n\tc.Assert(ft.String(), Equals, \"date\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\tft = NewFieldType(mysql.TypeDate)\n\tft.Flen = 8\n\tft.Decimal = 0\n\tc.Assert(ft.String(), Equals, \"date\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\n\tft = NewFieldType(mysql.TypeYear)\n\tft.Flen = 4\n\tft.Decimal = 0\n\tc.Assert(ft.String(), Equals, \"year(4)\")\n\tc.Assert(HasCharset(ft), IsFalse)\n\tft = NewFieldType(mysql.TypeYear)\n\tft.Flen = 2\n\tft.Decimal = 2\n\tc.Assert(ft.String(), Equals, \"year(2)\") // Note: Invalid year.\n\tc.Assert(HasCharset(ft), IsFalse)\n}\n\n// func (s *testFieldTypeSuite) TestHasCharsetFromStmt(c *C) {\n// \ttemplate := \"CREATE TABLE t(a %s)\"\n\n// \ttypes := []struct {\n// \t\tstrType    string\n// \t\thasCharset bool\n// \t}{\n// \t\t{\"int\", false},\n// \t\t{\"real\", false},\n// \t\t{\"float\", false},\n// \t\t{\"bit\", false},\n// \t\t{\"bool\", false},\n// \t\t{\"char(1)\", true},\n// \t\t{\"national char(1)\", true},\n// \t\t{\"binary\", false},\n// \t\t{\"varchar(1)\", true},\n// \t\t{\"national varchar(1)\", true},\n// \t\t{\"varbinary(1)\", false},\n// \t\t{\"year\", false},\n// \t\t{\"date\", false},\n// \t\t{\"time\", false},\n// \t\t{\"datetime\", false},\n// \t\t{\"timestamp\", false},\n// \t\t{\"blob\", false},\n// \t\t{\"tinyblob\", false},\n// \t\t{\"mediumblob\", false},\n// \t\t{\"longblob\", false},\n// \t\t{\"bit\", false},\n// \t\t{\"text\", true},\n// \t\t{\"tinytext\", true},\n// \t\t{\"mediumtext\", true},\n// \t\t{\"longtext\", true},\n// \t\t{\"json\", false},\n// \t\t{\"enum('1')\", true},\n// \t\t{\"set('1')\", true},\n// \t}\n\n// \tp := parser.New()\n// \tfor _, t := range types {\n// \t\tsql := fmt.Sprintf(template, t.strType)\n// \t\tstmt, err := p.ParseOneStmt(sql, \"\", \"\")\n// \t\tc.Assert(err, IsNil)\n\n// \t\tcol := stmt.(*ast.CreateTableStmt).Cols[0]\n// \t\tc.Assert(HasCharset(col.Tp), Equals, t.hasCharset)\n// \t}\n// }\n"
  },
  {
    "path": "pkg/parser/yy_parser.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"unicode\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n)\n\nvar (\n\t// ErrSyntax returns for sql syntax error.\n\tErrSyntax = terror.ClassParser.New(mysql.ErrSyntax, mysql.MySQLErrName[mysql.ErrSyntax])\n\t// ErrParse returns for sql parse error.\n\tErrParse = terror.ClassParser.New(mysql.ErrParse, mysql.MySQLErrName[mysql.ErrParse])\n\t// ErrUnknownCharacterSet returns for no character set found error.\n\tErrUnknownCharacterSet = terror.ClassParser.New(mysql.ErrUnknownCharacterSet, mysql.MySQLErrName[mysql.ErrUnknownCharacterSet])\n\t// ErrInvalidYearColumnLength returns for illegal column length for year type.\n\tErrInvalidYearColumnLength = terror.ClassParser.New(mysql.ErrInvalidYearColumnLength, mysql.MySQLErrName[mysql.ErrInvalidYearColumnLength])\n\t// ErrWrongArguments returns for illegal argument.\n\tErrWrongArguments = terror.ClassParser.New(mysql.ErrWrongArguments, mysql.MySQLErrName[mysql.ErrWrongArguments])\n\t// ErrWrongFieldTerminators returns for illegal field terminators.\n\tErrWrongFieldTerminators = terror.ClassParser.New(mysql.ErrWrongFieldTerminators, mysql.MySQLErrName[mysql.ErrWrongFieldTerminators])\n\t// ErrTooBigDisplayWidth returns for data display width exceed limit .\n\tErrTooBigDisplayWidth = terror.ClassParser.New(mysql.ErrTooBigDisplaywidth, mysql.MySQLErrName[mysql.ErrTooBigDisplaywidth])\n\t// ErrTooBigPrecision returns for data precision exceed limit.\n\tErrTooBigPrecision = terror.ClassParser.New(mysql.ErrTooBigPrecision, mysql.MySQLErrName[mysql.ErrTooBigPrecision])\n\t// ErrUnknownAlterLock returns for no alter lock type found error.\n\tErrUnknownAlterLock = terror.ClassParser.New(mysql.ErrUnknownAlterLock, mysql.MySQLErrName[mysql.ErrUnknownAlterLock])\n\t// ErrUnknownAlterAlgorithm returns for no alter algorithm found error.\n\tErrUnknownAlterAlgorithm = terror.ClassParser.New(mysql.ErrUnknownAlterAlgorithm, mysql.MySQLErrName[mysql.ErrUnknownAlterAlgorithm])\n\t// SpecFieldPattern special result field pattern\n\tSpecFieldPattern = regexp.MustCompile(`(\\/\\*!(M?[0-9]{5,6})?|\\*\\/)`)\n\tspecCodePattern  = regexp.MustCompile(`\\/\\*!(M?[0-9]{5,6})?([^*]|\\*+[^*/])*\\*+\\/`)\n\tspecCodeStart    = regexp.MustCompile(`^\\/\\*!(M?[0-9]{5,6})?[ \\t]*`)\n\tspecCodeEnd      = regexp.MustCompile(`[ \\t]*\\*\\/$`)\n\t// SpecVersionCodePattern is a pattern for special comments with version.\n\tSpecVersionCodePattern = regexp.MustCompile(`\\/\\*T![0-9]{5,6}([^*]|\\*+[^*/])*\\*+\\/`)\n\tspecVersionCodeStart   = regexp.MustCompile(`^\\/\\*T![0-9]{5,6}[ \\t]*`)\n\tspecVersionCodeValue   = regexp.MustCompile(`[0-9]{5,6}`)\n)\n\nfunc init() {\n\tparserMySQLErrCodes := map[terror.ErrCode]uint16{\n\t\tmysql.ErrSyntax:                  mysql.ErrSyntax,\n\t\tmysql.ErrParse:                   mysql.ErrParse,\n\t\tmysql.ErrUnknownCharacterSet:     mysql.ErrUnknownCharacterSet,\n\t\tmysql.ErrInvalidYearColumnLength: mysql.ErrInvalidYearColumnLength,\n\t\tmysql.ErrWrongArguments:          mysql.ErrWrongArguments,\n\t\tmysql.ErrWrongFieldTerminators:   mysql.ErrWrongFieldTerminators,\n\t\tmysql.ErrTooBigDisplaywidth:      mysql.ErrTooBigDisplaywidth,\n\t\tmysql.ErrUnknownAlterLock:        mysql.ErrUnknownAlterLock,\n\t\tmysql.ErrUnknownAlterAlgorithm:   mysql.ErrUnknownAlterAlgorithm,\n\t\tmysql.ErrTooBigPrecision:         mysql.ErrTooBigPrecision,\n\t}\n\tterror.ErrClassToMySQLCodes[terror.ClassParser] = parserMySQLErrCodes\n}\n\n// TrimComment trim comment for special comment code of MySQL.\nfunc TrimComment(txt string) string {\n\ttxt = specCodeStart.ReplaceAllString(txt, \"\")\n\treturn specCodeEnd.ReplaceAllString(txt, \"\")\n}\n\nfunc TrimCodeVersionComment(txt string) string {\n\ttxt = specVersionCodeStart.ReplaceAllString(txt, \"\")\n\treturn specCodeEnd.ReplaceAllString(txt, \"\")\n}\n\n// Parser represents a parser instance. Some temporary objects are stored in it to reduce object allocation during Parse function.\ntype Parser struct {\n\tcharset    string\n\tcollation  string\n\tresult     []ast.StmtNode\n\tsrc        string\n\tlexer      Scanner\n\thintParser *hintParser\n\n\t// the following fields are used by yyParse to reduce allocation.\n\tcache  []yySymType\n\tyylval yySymType\n\tyyVAL  *yySymType\n}\n\ntype stmtTexter interface {\n\tstmtText() string\n}\n\n// New returns a Parser object.\nfunc New() *Parser {\n\t// FIXME(yang.y): bring back the following check\n\t//if ast.NewValueExpr == nil ||\n\t//\tast.NewParamMarkerExpr == nil ||\n\t//\tast.NewHexLiteral == nil ||\n\t//\tast.NewBitLiteral == nil {\n\t//\tpanic(\"no parser driver (forgotten import?) https://github.com/pingcap/parser/issues/43\")\n\t//}\n\n\treturn &Parser{\n\t\tcache: make([]yySymType, 200),\n\t}\n}\n\n// Parse parses a query string to raw ast.StmtNode.\n// If charset or collation is \"\", default charset and collation will be used.\nfunc (parser *Parser) Parse(sql, charset, collation string) (stmt []ast.StmtNode, warns []error, err error) {\n\tif charset == \"\" {\n\t\tcharset = mysql.DefaultCharset\n\t}\n\tif collation == \"\" {\n\t\tcollation = mysql.DefaultCollationName\n\t}\n\tparser.charset = charset\n\tparser.collation = collation\n\tparser.src = sql\n\tparser.result = parser.result[:0]\n\n\tvar l yyLexer\n\tparser.lexer.EnableWindowFunc(true)\n\tparser.lexer.reset(sql)\n\tl = &parser.lexer\n\tyyParse(l, parser)\n\n\twarns, errs := l.Errors()\n\tif len(warns) > 0 {\n\t\twarns = append([]error(nil), warns...)\n\t} else {\n\t\twarns = nil\n\t}\n\tif len(errs) != 0 {\n\t\treturn nil, warns, errors.Trace(errs[0])\n\t}\n\tfor _, stmt := range parser.result {\n\t\tast.SetFlag(stmt)\n\t}\n\treturn parser.result, warns, nil\n}\n\nfunc (parser *Parser) lastErrorAsWarn() {\n\tparser.lexer.lastErrorAsWarn()\n}\n\n// ParseOneStmt parses a query and returns an ast.StmtNode.\n// The query must have one statement, otherwise ErrSyntax is returned.\nfunc (parser *Parser) ParseOneStmt(sql, charset, collation string) (ast.StmtNode, error) {\n\tstmts, _, err := parser.Parse(sql, charset, collation)\n\tif err != nil {\n\t\treturn nil, errors.Trace(err)\n\t}\n\tif len(stmts) != 1 {\n\t\treturn nil, ErrSyntax\n\t}\n\tast.SetFlag(stmts[0])\n\treturn stmts[0], nil\n}\n\n// SetSQLMode sets the SQL mode for parser.\nfunc (parser *Parser) SetSQLMode(mode mysql.SQLMode) {\n\tparser.lexer.SetSQLMode(mode)\n}\n\n// EnableWindowFunc controls whether the parser to parse syntax related with window function.\nfunc (parser *Parser) EnableWindowFunc(val bool) {\n\tparser.lexer.EnableWindowFunc(val)\n}\n\n// ParseErrorWith returns \"You have a syntax error near...\" error message compatible with mysql.\nfunc ParseErrorWith(errstr string, lineno int) error {\n\tif len(errstr) > mysql.ErrTextLength {\n\t\terrstr = errstr[:mysql.ErrTextLength]\n\t}\n\treturn fmt.Errorf(\"near '%-.80s' at line %d\", errstr, lineno)\n}\n\n// The select statement is not at the end of the whole statement, if the last\n// field text was set from its offset to the end of the src string, update\n// the last field text.\nfunc (parser *Parser) setLastSelectFieldText(st *ast.SelectStmt, lastEnd int) {\n\tlastField := st.Fields.Fields[len(st.Fields.Fields)-1]\n\tif lastField.Offset+len(lastField.Text()) >= len(parser.src)-1 {\n\t\tlastField.SetText(parser.src[lastField.Offset:lastEnd])\n\t}\n}\n\nfunc (parser *Parser) startOffset(v *yySymType) int {\n\treturn v.offset\n}\n\nfunc (parser *Parser) endOffset(v *yySymType) int {\n\toffset := v.offset\n\tfor offset > 0 && unicode.IsSpace(rune(parser.src[offset-1])) {\n\t\toffset--\n\t}\n\treturn offset\n}\n\nfunc (parser *Parser) parseHint(input string) ([]*ast.TableOptimizerHint, []error) {\n\tif parser.hintParser == nil {\n\t\tparser.hintParser = newHintParser()\n\t}\n\treturn parser.hintParser.parse(input, parser.lexer.GetSQLMode(), parser.lexer.lastHintPos)\n}\n\nfunc toInt(l yyLexer, lval *yySymType, str string) int {\n\tn, err := strconv.ParseUint(str, 10, 64)\n\tif err != nil {\n\t\te := err.(*strconv.NumError)\n\t\tif e.Err == strconv.ErrRange {\n\t\t\t// TODO: toDecimal maybe out of range still.\n\t\t\t// This kind of error should be throw to higher level, because truncated data maybe legal.\n\t\t\t// For example, this SQL returns error:\n\t\t\t// create table test (id decimal(30, 0));\n\t\t\t// insert into test values(123456789012345678901234567890123094839045793405723406801943850);\n\t\t\t// While this SQL:\n\t\t\t// select 1234567890123456789012345678901230948390457934057234068019438509023041874359081325875128590860234789847359871045943057;\n\t\t\t// get value 99999999999999999999999999999999999999999999999999999999999999999\n\t\t\treturn toDecimal(l, lval, str)\n\t\t}\n\t\tl.AppendError(l.Errorf(\"integer literal: %v\", err))\n\t\treturn int(unicode.ReplacementChar)\n\t}\n\n\tswitch {\n\tcase n <= math.MaxInt64:\n\t\tlval.item = int64(n)\n\tdefault:\n\t\tlval.item = n\n\t}\n\treturn intLit\n}\n\nfunc toDecimal(l yyLexer, lval *yySymType, str string) int {\n\tdec, err := ast.NewDecimal(str)\n\tif err != nil {\n\t\tl.AppendError(l.Errorf(\"decimal literal: %v\", err))\n\t}\n\tlval.item = dec\n\treturn decLit\n}\n\nfunc toFloat(l yyLexer, lval *yySymType, str string) int {\n\tn, err := strconv.ParseFloat(str, 64)\n\tif err != nil {\n\t\tl.AppendError(l.Errorf(\"float literal: %v\", err))\n\t\treturn int(unicode.ReplacementChar)\n\t}\n\n\tlval.item = n\n\treturn floatLit\n}\n\n// See https://dev.mysql.com/doc/refman/5.7/en/hexadecimal-literals.html\nfunc toHex(l yyLexer, lval *yySymType, str string) int {\n\th, err := ast.NewHexLiteral(str)\n\tif err != nil {\n\t\tl.AppendError(l.Errorf(\"hex literal: %v\", err))\n\t\treturn int(unicode.ReplacementChar)\n\t}\n\tlval.item = h\n\treturn hexLit\n}\n\n// See https://dev.mysql.com/doc/refman/5.7/en/bit-type.html\nfunc toBit(l yyLexer, lval *yySymType, str string) int {\n\tb, err := ast.NewBitLiteral(str)\n\tif err != nil {\n\t\tl.AppendError(l.Errorf(\"bit literal: %v\", err))\n\t\treturn int(unicode.ReplacementChar)\n\t}\n\tlval.item = b\n\treturn bitLit\n}\n\nfunc getUint64FromNUM(num interface{}) uint64 {\n\tswitch v := num.(type) {\n\tcase int64:\n\t\treturn uint64(v)\n\tcase uint64:\n\t\treturn v\n\t}\n\treturn 0\n}\n\nfunc getInt64FromNUM(num interface{}) int64 {\n\tswitch v := num.(type) {\n\tcase int64:\n\t\treturn v\n\t}\n\treturn -1\n}\n"
  },
  {
    "path": "pkg/planner/README.md",
    "content": "# Example planner usage\n\n## There are two execution paths in tidb build physical plan from ast node\n\n1. AST -> Physical Plan Step-by-step through multiple functions\n\n        ```go\n        import (\n        plannercore \"github.com/pingcap/tidb/planner/core\"\n        )\n\n        func main() {\n        stmts, _, err := parser.Parse(SQL_STRING)\n        is := getInfoSchema()\n        logical_plan, _, err := plannercore.BuildLogicalPlan(stmts[0], is)\n        physical_plan, err = plannercore.DoOptimize(\n                context.TODO(),\n                flagPredicatePushDown|flagDecorrelate|flagPrunColumns,\n                logical_plan.(LogicalPlan))\n        }\n        ```\n\n2. AST -> Physical Plan in one function (AST -> logical plan -> optimize -> physical plan)\n\n        ```go\n        import (\n        \"github.com/pingcap/tidb/planner\"\n        )\n\n        func main() {\n        stmts, _, err := parser.Parse(SQL_STRING)\n        is := getInfoSchema()\n        physical_plan, _, err := planner.Optimize(\n                context.TODO(),\n                sessionctx.Context,\n                stmts[0],\n                is)\n        }\n        ```\n\n## So, there are several entry functions in planner\n\n1. In `planner/optimize.go`\n\n        ```go\n        func Optimize(\n                ctx context.Context,\n                sctx sessionctx.Context,\n                node ast.Node,\n                is infoschema.InfoSchema) (plannercore.Plan, types.NameSlice, error)\n        ```\n\n2. In `planner/core/planbuilder.go`\n\n        ```go\n        func (b *PlanBuilder) Build(\n                ctx context.Context,\n                node ast.Node) (Plan, error) // Returns LogicalPlan\n        ```\n\n3. In `planner/core/optimizer.go`\n\n        ```go\n        func DoOptimize(\n                ctx context.Context,\n                flag uint64,\n                logic LogicalPlan) (PhysicalPlan, float64, error)\n        ```\n\n4. In `planner/core/optimizer.go`\n\n        ```go\n        func BuildLogicalPlan(\n                ctx context.Context,\n                sctx sessionctx.Context,\n                node ast.Node,\n                is infoschema.InfoSchema) (Plan, types.NameSlice, error) // Also returns LogicalPlan.\n        {\n                // Simply invokes Build() function above in 2\n        }\n        ```\n"
  },
  {
    "path": "pkg/planner/core/common_plans.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\n// Simple represents a simple statement plan which doesn't need any optimization.\ntype Simple struct {\n\tbaseSchemaProducer\n\n\tStatement ast.StmtNode\n}\n\n// DDL represents a DDL statement plan.\ntype DDL struct {\n\tbaseSchemaProducer\n\n\tStatement ast.DDLNode\n}\n\n// Explain represents a explain plan.\ntype Explain struct {\n\tbaseSchemaProducer\n\n\tTargetPlan Plan\n\tFormat     string\n\tAnalyze    bool\n\tExecStmt   ast.StmtNode\n\n\tRows           [][]string\n\texplainedPlans map[int]bool\n}\n\ntype Set struct {\n\tbaseSchemaProducer\n\n\tVarAssigns []*expression.VarAssignment\n}\n"
  },
  {
    "path": "pkg/planner/core/database_dialect.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n)\n\ntype DBType int\n\nconst (\n\tDBTypeUnknown DBType = iota\n\tDBTypeMySQL\n\tDBTypeSQLite\n\tDBTypePostgres\n\tDBTypeCSVDB\n\tDBTypeODPS\n)\n\nvar DbTypeMap = map[string]DBType{\n\t\"mysql\":      DBTypeMySQL,\n\t\"sqlite\":     DBTypeSQLite,\n\t\"postgresql\": DBTypePostgres,\n\t\"csvdb\":      DBTypeCSVDB,\n\t\"odps\":       DBTypeODPS,\n}\n\nvar DbTypeNameMap = map[DBType]string{\n\tDBTypeUnknown:  \"unknown\",\n\tDBTypeMySQL:    \"mysql\",\n\tDBTypeSQLite:   \"sqlite\",\n\tDBTypePostgres: \"postgresql\",\n\tDBTypeCSVDB:    \"csvdb\",\n\tDBTypeODPS:     \"odps\",\n}\n\nfunc (t DBType) String() string {\n\tif name, exists := DbTypeNameMap[t]; exists {\n\t\treturn name\n\t}\n\treturn \"unknown\"\n}\n\nfunc ParseDBType(tp string) (DBType, error) {\n\tif v, ok := DbTypeMap[strings.ToLower(tp)]; ok {\n\t\treturn v, nil\n\t}\n\treturn DBTypeUnknown, fmt.Errorf(\"unknown db type: %s\", tp)\n}\n\nvar (\n\t_ Dialect = &MySQLDialect{}\n\t_ Dialect = &PostgresDialect{}\n\t_ Dialect = &CVSDBDialect{}\n\t_ Dialect = &OdpsDialect{}\n)\n\nvar (\n\tDBDialectMap = map[DBType]Dialect{\n\t\tDBTypeUnknown:  NewMySQLDialect(),\n\t\tDBTypeCSVDB:    NewCVSDBDialect(),\n\t\tDBTypeMySQL:    NewMySQLDialect(),\n\t\tDBTypePostgres: NewPostgresDialect(),\n\t\tDBTypeSQLite:   NewMySQLDialect(),\n\t\tDBTypeODPS:     NewOdpsDialect(),\n\t}\n)\n\ntype Dialect interface {\n\tGetRestoreFlags() format.RestoreFlags\n\tGetFormatDialect() format.Dialect\n\tSupportAnyValue() bool\n}\n\ntype MySQLDialect struct {\n\tflags         format.RestoreFlags\n\tformatDialect format.Dialect\n}\n\nfunc NewMySQLDialect() *MySQLDialect {\n\treturn &MySQLDialect{\n\t\tflags:         format.RestoreStringSingleQuotes | format.RestoreKeyWordLowercase,\n\t\tformatDialect: format.NewMySQLDialect(),\n\t}\n}\n\nfunc (d *MySQLDialect) GetRestoreFlags() format.RestoreFlags {\n\treturn d.flags\n}\n\nfunc (d *MySQLDialect) GetFormatDialect() format.Dialect {\n\treturn d.formatDialect\n}\n\nfunc (d *MySQLDialect) SupportAnyValue() bool {\n\treturn true\n}\n\ntype PostgresDialect struct {\n\tMySQLDialect\n}\n\nfunc NewPostgresDialect() *PostgresDialect {\n\treturn &PostgresDialect{\n\t\tMySQLDialect{flags: format.RestoreStringSingleQuotes | format.RestoreKeyWordLowercase, formatDialect: format.NewPostgresDialect()},\n\t}\n}\n\nfunc (d *PostgresDialect) GetRestoreFlags() format.RestoreFlags {\n\treturn d.flags\n}\n\nfunc (d *PostgresDialect) GetFormatDialect() format.Dialect {\n\treturn d.formatDialect\n}\n\nfunc (d *PostgresDialect) SupportAnyValue() bool {\n\treturn false\n}\n\ntype CVSDBDialect struct {\n\tMySQLDialect\n}\n\nfunc NewCVSDBDialect() *CVSDBDialect {\n\treturn &CVSDBDialect{\n\t\tMySQLDialect{flags: format.RestoreStringSingleQuotes | format.RestoreKeyWordLowercase | format.RestoreNameDoubleQuotes, formatDialect: format.NewCVSDBDialect()},\n\t}\n}\n\nfunc (d *CVSDBDialect) GetRestoreFlags() format.RestoreFlags {\n\treturn d.flags\n}\n\nfunc (d *CVSDBDialect) GetFormatDialect() format.Dialect {\n\treturn d.formatDialect\n}\n\nfunc (d *CVSDBDialect) SupportAnyValue() bool {\n\treturn false\n}\n\ntype OdpsDialect struct {\n\tMySQLDialect\n}\n\nfunc NewOdpsDialect() *OdpsDialect {\n\treturn &OdpsDialect{\n\t\tMySQLDialect{flags: format.RestoreStringSingleQuotes | format.RestoreKeyWordLowercase, formatDialect: format.NewOdpsDialect()},\n\t}\n}\n\nfunc (d *OdpsDialect) GetRestoreFlags() format.RestoreFlags {\n\treturn d.flags\n}\n\nfunc (d *OdpsDialect) GetFormatDialect() format.Dialect {\n\treturn d.formatDialect\n}\n\nfunc (d *OdpsDialect) SupportAnyValue() bool {\n\treturn false\n}\n"
  },
  {
    "path": "pkg/planner/core/dot.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// DrawLogicalPlan draws a logical plan in Graphviz format.\n// One can visualize the returned string at http://www.webgraphviz.com/\nfunc DrawLogicalPlan(lp LogicalPlan) string {\n\tnodeDeps := map[int][]int{}   // node# -> {node#, node#, ...}\n\tnodeLabel := map[int]string{} // node# -> node_info\n\n\ttraverseLogicalPlan(lp, nodeDeps, nodeLabel)\n\n\tvar allNodeIds []int\n\tfor id := range nodeLabel {\n\t\tallNodeIds = append(allNodeIds, id)\n\t}\n\tsort.Ints(allNodeIds)\n\n\tvar builder strings.Builder\n\n\tfmt.Fprintln(&builder, \"digraph G {\")\n\tfor _, id := range allNodeIds {\n\t\tfmt.Fprintf(&builder, \"%d [label=\\\"%s\\\"]\\n\", id, nodeLabel[id])\n\t}\n\tfor _, id := range allNodeIds {\n\t\tif cs, ok := nodeDeps[id]; ok {\n\t\t\tfor _, c := range cs {\n\t\t\t\tfmt.Fprintf(&builder, \"%d -> %d\\n\", id, c)\n\t\t\t}\n\t\t}\n\t}\n\tfmt.Fprint(&builder, \"}\")\n\n\treturn builder.String()\n}\n\nfunc traverseLogicalPlan(lp LogicalPlan, nodeDeps map[int][]int, nodeLabel map[int]string) {\n\tif _, exist := nodeDeps[lp.ID()]; !exist && len(lp.Children()) > 0 {\n\t\tvar cid []int\n\t\tfor _, c := range lp.Children() {\n\t\t\tcid = append(cid, c.ID())\n\t\t}\n\t\tnodeDeps[lp.ID()] = cid\n\t}\n\n\tif _, exist := nodeLabel[lp.ID()]; !exist {\n\t\tvar str string\n\t\tswitch x := lp.(type) {\n\t\tcase *LogicalApply:\n\t\t\tstr = x.JoinType.String()\n\t\t\tvar conds []string\n\t\t\tif len(x.EqualConditions) > 0 {\n\t\t\t\tconds = append(conds, fmt.Sprintf(\"%s,\", x.EqualConditions))\n\t\t\t}\n\t\t\tif len(x.LeftConditions) > 0 {\n\t\t\t\tconds = append(conds, fmt.Sprintf(\"l%s,\", x.LeftConditions))\n\t\t\t}\n\t\t\tif len(x.RightConditions) > 0 {\n\t\t\t\tconds = append(conds, fmt.Sprintf(\"r%s,\", x.RightConditions))\n\t\t\t}\n\t\t\tif len(x.OtherConditions) > 0 {\n\t\t\t\tconds = append(conds, fmt.Sprintf(\"o%s,\", x.OtherConditions))\n\t\t\t}\n\t\t\tif len(conds) > 0 {\n\t\t\t\tstr += \"(\" + strings.Join(conds, \",\") + \")\"\n\t\t\t}\n\t\tcase *LogicalJoin:\n\t\t\tstr = x.JoinType.String()\n\t\t\tvar conds []string\n\t\t\tif len(x.EqualConditions) > 0 {\n\t\t\t\tconds = append(conds, fmt.Sprintf(\"%s,\", x.EqualConditions))\n\t\t\t}\n\t\t\tif len(x.LeftConditions) > 0 {\n\t\t\t\tconds = append(conds, fmt.Sprintf(\"l%s,\", x.LeftConditions))\n\t\t\t}\n\t\t\tif len(x.RightConditions) > 0 {\n\t\t\t\tconds = append(conds, fmt.Sprintf(\"r%s,\", x.RightConditions))\n\t\t\t}\n\t\t\tif len(x.OtherConditions) > 0 {\n\t\t\t\tconds = append(conds, fmt.Sprintf(\"o%s,\", x.OtherConditions))\n\t\t\t}\n\t\t\tif len(conds) > 0 {\n\t\t\t\tstr += \"(\" + strings.Join(conds, \",\") + \")\"\n\t\t\t}\n\t\tcase *DataSource:\n\t\t\tstr = ToString(x)\n\t\tcase *LogicalProjection:\n\t\t\tstr = fmt.Sprintf(\"Projection(%s)\", x.Exprs)\n\t\tcase *LogicalSelection:\n\t\t\tstr = fmt.Sprintf(\"Sel(%s)\", x.Conditions)\n\t\tcase *LogicalAggregation:\n\t\t\tstr = fmt.Sprintf(\"Agg(%s)\", x.AggFuncs)\n\t\tcase *LogicalWindow:\n\t\t\tstr = fmt.Sprintf(\"Window(%s)\", x.Schema().Columns)\n\t\tdefault:\n\t\t\tstr = lp.TP()\n\t\t}\n\t\tnodeLabel[lp.ID()] = str\n\t}\n\n\tfor _, child := range lp.Children() {\n\t\ttraverseLogicalPlan(child, nodeDeps, nodeLabel)\n\t}\n}\n"
  },
  {
    "path": "pkg/planner/core/dot_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/util/mock\"\n\t\"github.com/secretflow/scql/pkg/util/testutil\"\n)\n\nvar _ = Suite(&testDotSuite{})\n\ntype testDotSuite struct {\n\t*parser.Parser\n\n\tis  infoschema.InfoSchema\n\tctx sessionctx.Context\n\n\ttestData testutil.TestData\n}\n\nfunc (s *testDotSuite) SetUpSuite(c *C) {\n\tmockTables, err := mock.MockAllTables()\n\tc.Assert(err, IsNil)\n\ts.is = infoschema.MockInfoSchema(mockTables)\n\ts.ctx = mock.MockContext()\n\ts.Parser = parser.New()\n}\n\nfunc (s *testDotSuite) TearDownSuite(c *C) {\n\tc.Assert(s.testData.GenerateOutputIfNeeded(), IsNil)\n}\n\nfunc (s *testDotSuite) TestDrawLogicalPlan(c *C) {\n\tcases := map[string]string{\n\t\t`select plain_int_1, plain_int_2 from alice.tbl_0 where alice.tbl_0.plain_int_0 = 1`: `digraph G {\n1 [label=\"DataScan(tbl_0)\"]\n2 [label=\"Sel([eq(alice.tbl_0.plain_int_0, 1)])\"]\n3 [label=\"Projection([alice.tbl_0.plain_int_1 alice.tbl_0.plain_int_2])\"]\n2 -> 1\n3 -> 2\n}`,\n\n\t\t`select count(distinct (alice.tbl_1.plain_float_0)) as co,sum(distinct (alice.tbl_1.plain_int_0)) as su from alice.tbl_1;`: `digraph G {\n1 [label=\"DataScan(tbl_1)\"]\n2 [label=\"Agg([count(alice.tbl_1.plain_float_0) sum(alice.tbl_1.plain_int_0) firstrow(alice.tbl_1.aggregate_datetime_0) firstrow(alice.tbl_1.aggregate_datetime_1) firstrow(alice.tbl_1.aggregate_datetime_2) firstrow(alice.tbl_1.aggregate_float_0) firstrow(alice.tbl_1.aggregate_float_1) firstrow(alice.tbl_1.aggregate_float_2) firstrow(alice.tbl_1.aggregate_int_0) firstrow(alice.tbl_1.aggregate_int_1) firstrow(alice.tbl_1.aggregate_int_2) firstrow(alice.tbl_1.aggregate_string_0) firstrow(alice.tbl_1.aggregate_string_1) firstrow(alice.tbl_1.aggregate_string_2) firstrow(alice.tbl_1.aggregate_timestamp_0) firstrow(alice.tbl_1.aggregate_timestamp_1) firstrow(alice.tbl_1.aggregate_timestamp_2) firstrow(alice.tbl_1.compare_datetime_0) firstrow(alice.tbl_1.compare_datetime_1) firstrow(alice.tbl_1.compare_datetime_2) firstrow(alice.tbl_1.compare_float_0) firstrow(alice.tbl_1.compare_float_1) firstrow(alice.tbl_1.compare_float_2) firstrow(alice.tbl_1.compare_int_0) firstrow(alice.tbl_1.compare_int_1) firstrow(alice.tbl_1.compare_int_2) firstrow(alice.tbl_1.compare_string_0) firstrow(alice.tbl_1.compare_string_1) firstrow(alice.tbl_1.compare_string_2) firstrow(alice.tbl_1.compare_timestamp_0) firstrow(alice.tbl_1.compare_timestamp_1) firstrow(alice.tbl_1.compare_timestamp_2) firstrow(alice.tbl_1.encrypt_datetime_0) firstrow(alice.tbl_1.encrypt_datetime_1) firstrow(alice.tbl_1.encrypt_datetime_2) firstrow(alice.tbl_1.encrypt_float_0) firstrow(alice.tbl_1.encrypt_float_1) firstrow(alice.tbl_1.encrypt_float_2) firstrow(alice.tbl_1.encrypt_int_0) firstrow(alice.tbl_1.encrypt_int_1) firstrow(alice.tbl_1.encrypt_int_2) firstrow(alice.tbl_1.encrypt_string_0) firstrow(alice.tbl_1.encrypt_string_1) firstrow(alice.tbl_1.encrypt_string_2) firstrow(alice.tbl_1.encrypt_timestamp_0) firstrow(alice.tbl_1.encrypt_timestamp_1) firstrow(alice.tbl_1.encrypt_timestamp_2) firstrow(alice.tbl_1.groupby_datetime_0) firstrow(alice.tbl_1.groupby_datetime_1) firstrow(alice.tbl_1.groupby_datetime_2) firstrow(alice.tbl_1.groupby_float_0) firstrow(alice.tbl_1.groupby_float_1) firstrow(alice.tbl_1.groupby_float_2) firstrow(alice.tbl_1.groupby_int_0) firstrow(alice.tbl_1.groupby_int_1) firstrow(alice.tbl_1.groupby_int_2) firstrow(alice.tbl_1.groupby_string_0) firstrow(alice.tbl_1.groupby_string_1) firstrow(alice.tbl_1.groupby_string_2) firstrow(alice.tbl_1.groupby_timestamp_0) firstrow(alice.tbl_1.groupby_timestamp_1) firstrow(alice.tbl_1.groupby_timestamp_2) firstrow(alice.tbl_1.join_datetime_0) firstrow(alice.tbl_1.join_datetime_1) firstrow(alice.tbl_1.join_datetime_2) firstrow(alice.tbl_1.join_float_0) firstrow(alice.tbl_1.join_float_1) firstrow(alice.tbl_1.join_float_2) firstrow(alice.tbl_1.join_int_0) firstrow(alice.tbl_1.join_int_1) firstrow(alice.tbl_1.join_int_2) firstrow(alice.tbl_1.join_string_0) firstrow(alice.tbl_1.join_string_1) firstrow(alice.tbl_1.join_string_2) firstrow(alice.tbl_1.join_timestamp_0) firstrow(alice.tbl_1.join_timestamp_1) firstrow(alice.tbl_1.join_timestamp_2) firstrow(alice.tbl_1.joinpayload_datetime_0) firstrow(alice.tbl_1.joinpayload_datetime_1) firstrow(alice.tbl_1.joinpayload_datetime_2) firstrow(alice.tbl_1.joinpayload_float_0) firstrow(alice.tbl_1.joinpayload_float_1) firstrow(alice.tbl_1.joinpayload_float_2) firstrow(alice.tbl_1.joinpayload_int_0) firstrow(alice.tbl_1.joinpayload_int_1) firstrow(alice.tbl_1.joinpayload_int_2) firstrow(alice.tbl_1.joinpayload_string_0) firstrow(alice.tbl_1.joinpayload_string_1) firstrow(alice.tbl_1.joinpayload_string_2) firstrow(alice.tbl_1.joinpayload_timestamp_0) firstrow(alice.tbl_1.joinpayload_timestamp_1) firstrow(alice.tbl_1.joinpayload_timestamp_2) firstrow(alice.tbl_1.plain_datetime_0) firstrow(alice.tbl_1.plain_datetime_1) firstrow(alice.tbl_1.plain_datetime_2) firstrow(alice.tbl_1.plain_float_0) firstrow(alice.tbl_1.plain_float_1) firstrow(alice.tbl_1.plain_float_2) firstrow(alice.tbl_1.plain_int_0) firstrow(alice.tbl_1.plain_int_1) firstrow(alice.tbl_1.plain_int_2) firstrow(alice.tbl_1.plain_string_0) firstrow(alice.tbl_1.plain_string_1) firstrow(alice.tbl_1.plain_string_2) firstrow(alice.tbl_1.plain_timestamp_0) firstrow(alice.tbl_1.plain_timestamp_1) firstrow(alice.tbl_1.plain_timestamp_2) firstrow(alice.tbl_1.rank_datetime_0) firstrow(alice.tbl_1.rank_datetime_1) firstrow(alice.tbl_1.rank_datetime_2) firstrow(alice.tbl_1.rank_float_0) firstrow(alice.tbl_1.rank_float_1) firstrow(alice.tbl_1.rank_float_2) firstrow(alice.tbl_1.rank_int_0) firstrow(alice.tbl_1.rank_int_1) firstrow(alice.tbl_1.rank_int_2) firstrow(alice.tbl_1.rank_string_0) firstrow(alice.tbl_1.rank_string_1) firstrow(alice.tbl_1.rank_string_2) firstrow(alice.tbl_1.rank_timestamp_0) firstrow(alice.tbl_1.rank_timestamp_1) firstrow(alice.tbl_1.rank_timestamp_2)])\"]\n3 [label=\"Projection([Column#121 Column#122])\"]\n2 -> 1\n3 -> 2\n}`,\n\t}\n\tfor ca, expected := range cases {\n\t\tcomment := Commentf(\"for %s\", ca)\n\t\tstmt, err := s.ParseOneStmt(ca, \"\", \"\")\n\t\tc.Assert(err, IsNil, comment)\n\n\t\terr = Preprocess(s.ctx, stmt, s.is)\n\t\tc.Assert(err, IsNil)\n\n\t\tp, _, err := BuildLogicalPlan(context.Background(), s.ctx, stmt, s.is)\n\t\tc.Assert(err, IsNil)\n\n\t\tlp, ok := p.(LogicalPlan)\n\t\tc.Assert(ok, IsTrue)\n\t\tdotStr := DrawLogicalPlan(lp)\n\t\tc.Assert(dotStr, Equals, expected, Commentf(\"for %s\", ca))\n\t}\n}\n"
  },
  {
    "path": "pkg/planner/core/errors.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n)\n\nvar (\n\tErrUnknown                         = terror.ClassOptimizer.New(mysql.ErrUnknown, mysql.MySQLErrName[mysql.ErrUnknown])\n\tErrUnknownColumn                   = terror.ClassOptimizer.New(mysql.ErrBadField, mysql.MySQLErrName[mysql.ErrBadField])\n\tErrAmbiguous                       = terror.ClassOptimizer.New(mysql.ErrNonUniq, mysql.MySQLErrName[mysql.ErrNonUniq])\n\tErrUnsupportedType                 = terror.ClassOptimizer.New(mysql.ErrUnsupportedType, mysql.MySQLErrName[mysql.ErrUnsupportedType])\n\tErrDupFieldName                    = terror.ClassOptimizer.New(mysql.ErrDupFieldName, mysql.MySQLErrName[mysql.ErrDupFieldName])\n\tErrInvalidWildCard                 = terror.ClassOptimizer.New(mysql.ErrInvalidWildCard, mysql.MySQLErrName[mysql.ErrInvalidWildCard])\n\tErrNoDB                            = terror.ClassOptimizer.New(mysql.ErrNoDB, mysql.MySQLErrName[mysql.ErrNoDB])\n\tErrBadTable                        = terror.ClassOptimizer.New(mysql.ErrBadTable, mysql.MySQLErrName[mysql.ErrBadTable])\n\tErrNonUniqTable                    = terror.ClassOptimizer.New(mysql.ErrNonuniqTable, mysql.MySQLErrName[mysql.ErrNonuniqTable])\n\tErrIllegalReference                = terror.ClassOptimizer.New(mysql.ErrIllegalReference, mysql.MySQLErrName[mysql.ErrIllegalReference])\n\tErrWrongGroupField                 = terror.ClassOptimizer.New(mysql.ErrWrongGroupField, mysql.MySQLErrName[mysql.ErrWrongGroupField])\n\tErrInvalidGroupFuncUse             = terror.ClassOptimizer.New(mysql.ErrInvalidGroupFuncUse, mysql.MySQLErrName[mysql.ErrInvalidGroupFuncUse])\n\tErrWrongUsage                      = terror.ClassOptimizer.New(mysql.ErrWrongUsage, mysql.MySQLErrName[mysql.ErrWrongUsage])\n\tErrWindowInvalidWindowFuncAliasUse = terror.ClassOptimizer.New(mysql.ErrWindowInvalidWindowFuncAliasUse, mysql.MySQLErrName[mysql.ErrWindowInvalidWindowFuncAliasUse])\n\tErrWrongArguments                  = terror.ClassOptimizer.New(mysql.ErrWrongArguments, mysql.MySQLErrName[mysql.ErrWrongArguments])\n\tErrTablenameNotAllowedHere         = terror.ClassOptimizer.New(mysql.ErrTablenameNotAllowedHere, mysql.MySQLErrName[mysql.ErrTablenameNotAllowedHere])\n\tErrWrongNumberOfColumnsInSelect    = terror.ClassOptimizer.New(mysql.ErrWrongNumberOfColumnsInSelect, mysql.MySQLErrName[mysql.ErrWrongNumberOfColumnsInSelect])\n\tErrDBaccessDenied                  = terror.ClassOptimizer.New(mysql.ErrDBaccessDenied, mysql.MySQLErrName[mysql.ErrDBaccessDenied])\n\tErrTableaccessDenied               = terror.ClassOptimizer.New(mysql.ErrTableaccessDenied, mysql.MySQLErrName[mysql.ErrTableaccessDenied])\n\tErrPrivilegeCheckFail              = terror.ClassOptimizer.New(mysql.ErrPrivilegeCheckFail, mysql.MySQLErrName[mysql.ErrPrivilegeCheckFail])\n\tErrSpecificAccessDenied            = terror.ClassOptimizer.New(mysql.ErrSpecificAccessDenied, mysql.MySQLErrName[mysql.ErrSpecificAccessDenied])\n\tErrViewInvalid                     = terror.ClassOptimizer.New(mysql.ErrViewInvalid, mysql.MySQLErrName[mysql.ErrViewInvalid])\n\tErrWindowInvalidWindowFuncUse      = terror.ClassOptimizer.New(mysql.ErrWindowInvalidWindowFuncUse, mysql.MySQLErrName[mysql.ErrWindowInvalidWindowFuncUse])\n\tErrWindowNoSuchWindow              = terror.ClassOptimizer.New(mysql.ErrWindowNoSuchWindow, mysql.MySQLErrName[mysql.ErrWindowNoSuchWindow])\n\tErrWindowCircularityInWindowGraph  = terror.ClassOptimizer.New(mysql.ErrWindowCircularityInWindowGraph, mysql.MySQLErrName[mysql.ErrWindowCircularityInWindowGraph])\n\tErrWindowNoChildPartitioning       = terror.ClassOptimizer.New(mysql.ErrWindowNoChildPartitioning, mysql.MySQLErrName[mysql.ErrWindowNoChildPartitioning])\n\tErrWindowNoInherentFrame           = terror.ClassOptimizer.New(mysql.ErrWindowNoInherentFrame, mysql.MySQLErrName[mysql.ErrWindowNoInherentFrame])\n\tErrWindowNoRedefineOrderBy         = terror.ClassOptimizer.New(mysql.ErrWindowNoRedefineOrderBy, mysql.MySQLErrName[mysql.ErrWindowNoRedefineOrderBy])\n\tErrWindowDuplicateName             = terror.ClassOptimizer.New(mysql.ErrWindowDuplicateName, mysql.MySQLErrName[mysql.ErrWindowDuplicateName])\n\tErrPartitionClauseOnNonpartitioned = terror.ClassOptimizer.New(mysql.ErrPartitionClauseOnNonpartitioned, mysql.MySQLErrName[mysql.ErrPartitionClauseOnNonpartitioned])\n\tErrWindowFrameStartIllegal         = terror.ClassOptimizer.New(mysql.ErrWindowFrameStartIllegal, mysql.MySQLErrName[mysql.ErrWindowFrameStartIllegal])\n\tErrWindowFrameEndIllegal           = terror.ClassOptimizer.New(mysql.ErrWindowFrameEndIllegal, mysql.MySQLErrName[mysql.ErrWindowFrameEndIllegal])\n\tErrWindowFrameIllegal              = terror.ClassOptimizer.New(mysql.ErrWindowFrameIllegal, mysql.MySQLErrName[mysql.ErrWindowFrameIllegal])\n\tErrWindowRangeFrameOrderType       = terror.ClassOptimizer.New(mysql.ErrWindowRangeFrameOrderType, mysql.MySQLErrName[mysql.ErrWindowRangeFrameOrderType])\n\tErrWindowRangeFrameTemporalType    = terror.ClassOptimizer.New(mysql.ErrWindowRangeFrameTemporalType, mysql.MySQLErrName[mysql.ErrWindowRangeFrameTemporalType])\n\tErrWindowRangeFrameNumericType     = terror.ClassOptimizer.New(mysql.ErrWindowRangeFrameNumericType, mysql.MySQLErrName[mysql.ErrWindowRangeFrameNumericType])\n\tErrWindowRangeBoundNotConstant     = terror.ClassOptimizer.New(mysql.ErrWindowRangeBoundNotConstant, mysql.MySQLErrName[mysql.ErrWindowRangeBoundNotConstant])\n\tErrWindowRowsIntervalUse           = terror.ClassOptimizer.New(mysql.ErrWindowRowsIntervalUse, mysql.MySQLErrName[mysql.ErrWindowRowsIntervalUse])\n\tErrWindowFunctionIgnoresFrame      = terror.ClassOptimizer.New(mysql.ErrWindowFunctionIgnoresFrame, mysql.MySQLErrName[mysql.ErrWindowFunctionIgnoresFrame])\n\tErrNotSupportedYet                 = terror.ClassOptimizer.New(mysql.ErrNotSupportedYet, mysql.MySQLErrName[mysql.ErrNotSupportedYet])\n)\n"
  },
  {
    "path": "pkg/planner/core/explain.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n)\n\nfunc formatWindowFuncDescs(buffer *bytes.Buffer, descs []*aggregation.WindowFuncDesc, schema *expression.Schema) *bytes.Buffer {\n\twinFuncStartIdx := len(schema.Columns) - len(descs)\n\tfor i, desc := range descs {\n\t\tif i != 0 {\n\t\t\tbuffer.WriteString(\", \")\n\t\t}\n\t\tfmt.Fprintf(buffer, \"%v->%v\", desc, schema.Columns[winFuncStartIdx+i])\n\t}\n\treturn buffer\n}\n"
  },
  {
    "path": "pkg/planner/core/expression_rewriter.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\tdriver \"github.com/secretflow/scql/pkg/types/parser_driver\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n\t\"github.com/secretflow/scql/pkg/util/stringutil\"\n)\n\n// evalAstExpr evaluates ast expression directly.\nfunc evalAstExpr(sctx sessionctx.Context, expr ast.ExprNode) (types.Datum, error) {\n\tif val, ok := expr.(*driver.ValueExpr); ok {\n\t\treturn val.Datum, nil\n\t}\n\tvar is infoschema.InfoSchema\n\t// if sctx.GetSessionVars().TxnCtx.InfoSchema != nil {\n\t// \tis = sctx.GetSessionVars().TxnCtx.InfoSchema.(infoschema.InfoSchema)\n\t// }\n\tb := NewPlanBuilder(sctx, is)\n\tfakePlan := LogicalTableDual{}.Init(sctx, 0)\n\tnewExpr, _, err := b.rewrite(context.TODO(), expr, fakePlan, nil, true)\n\tif err != nil {\n\t\treturn types.Datum{}, err\n\t}\n\treturn newExpr.Eval(chunk.Row{})\n}\n\n// rewrite function rewrites ast expr to expression.Expression.\n// aggMapper maps ast.AggregateFuncExpr to the columns offset in p's output schema.\n// asScalar means whether this expression must be treated as a scalar expression.\n// And this function returns a result expression, a new plan that may have apply or semi-join.\nfunc (b *PlanBuilder) rewrite(\n\tctx context.Context,\n\texprNode ast.ExprNode,\n\tp LogicalPlan,\n\taggMapper map[*ast.AggregateFuncExpr]int,\n\tasScalar bool) (expression.Expression, LogicalPlan, error) {\n\texpr, resultPlan, err := b.rewriteWithPreprocess(ctx, exprNode, p, aggMapper, nil, asScalar)\n\treturn expr, resultPlan, err\n}\n\n// rewriteWithPreprocess is for handling the situation that we need to adjust the input ast tree\n// before really using its node in `expressionRewriter.Leave`. In that case, we first call\n// er.preprocess(expr), which returns a new expr. Then we use the new expr in `Leave`.\nfunc (b *PlanBuilder) rewriteWithPreprocess(\n\tctx context.Context,\n\texprNode ast.ExprNode,\n\tp LogicalPlan,\n\taggMapper map[*ast.AggregateFuncExpr]int,\n\twindowMapper map[*ast.WindowFuncExpr]int,\n\tasScalar bool,\n) (expression.Expression, LogicalPlan, error) {\n\tb.rewriterCounter++\n\tdefer func() { b.rewriterCounter-- }()\n\n\trewriter := b.getExpressionRewriter(ctx, p)\n\t// The rewriter maybe is obtained from \"b.rewriterPool\", \"rewriter.err\" is\n\t// not nil means certain previous procedure has not handled this error.\n\t// Here we give us one more chance to make a correct behavior by handling\n\t// this missed error.\n\tif rewriter.err != nil {\n\t\treturn nil, nil, rewriter.err\n\t}\n\n\trewriter.aggrMap = aggMapper\n\trewriter.windowMap = windowMapper\n\trewriter.asScalar = asScalar\n\n\texpr, resultPlan, err := b.rewriteExprNode(rewriter, exprNode, asScalar)\n\treturn expr, resultPlan, err\n}\n\nfunc (b *PlanBuilder) getExpressionRewriter(ctx context.Context, p LogicalPlan) (rewriter *expressionRewriter) {\n\tdefer func() {\n\t\tif p != nil {\n\t\t\trewriter.schema = p.Schema()\n\t\t\trewriter.names = p.OutputNames()\n\t\t}\n\t}()\n\n\tif len(b.rewriterPool) < b.rewriterCounter {\n\t\trewriter = &expressionRewriter{p: p, b: b, sctx: b.ctx, ctx: ctx}\n\t\tb.rewriterPool = append(b.rewriterPool, rewriter)\n\t\treturn\n\t}\n\n\trewriter = b.rewriterPool[b.rewriterCounter-1]\n\trewriter.p = p\n\trewriter.aggrMap = nil\n\trewriter.disableFoldCounter = 0\n\trewriter.ctxStack = rewriter.ctxStack[:0]\n\trewriter.ctxNameStk = rewriter.ctxNameStk[:0]\n\trewriter.ctx = ctx\n\treturn\n}\n\nfunc (b *PlanBuilder) rewriteExprNode(rewriter *expressionRewriter, exprNode ast.ExprNode, asScalar bool) (expression.Expression, LogicalPlan, error) {\n\tif rewriter.p != nil {\n\t\tcurColLen := rewriter.p.Schema().Len()\n\t\tdefer func() {\n\t\t\tnames := rewriter.p.OutputNames().Shallow()[:curColLen]\n\t\t\tfor i := curColLen; i < rewriter.p.Schema().Len(); i++ {\n\t\t\t\tnames = append(names, types.EmptyName)\n\t\t\t}\n\t\t\t// After rewriting finished, only old columns are visible.\n\t\t\t// e.g. select * from t where t.a in (select t1.a from t1);\n\t\t\t// The output columns before we enter the subquery are the columns from t.\n\t\t\t// But when we leave the subquery `t.a in (select t1.a from t1)`, we got a Apply operator\n\t\t\t// and the output columns become [t.*, t1.*]. But t1.* is used only inside the subquery. If there's another filter\n\t\t\t// which is also a subquery where t1 is involved. The name resolving will fail if we still expose the column from\n\t\t\t// the previous subquery.\n\t\t\t// So here we just reset the names to empty to avoid this situation.\n\t\t\t// TODO: implement ScalarSubQuery and resolve it during optimizing. In building phase, we will not change the plan's structure.\n\t\t\trewriter.p.SetOutputNames(names)\n\t\t}()\n\t}\n\texprNode.Accept(rewriter)\n\tif rewriter.err != nil {\n\t\treturn nil, nil, errors.Trace(rewriter.err)\n\t}\n\tif !asScalar && len(rewriter.ctxStack) == 0 {\n\t\treturn nil, rewriter.p, nil\n\t}\n\tif len(rewriter.ctxStack) != 1 {\n\t\treturn nil, nil, errors.Errorf(\"context len %v is invalid\", len(rewriter.ctxStack))\n\t}\n\trewriter.err = expression.CheckArgsNotMultiColumnRow(rewriter.ctxStack[0])\n\tif rewriter.err != nil {\n\t\treturn nil, nil, errors.Trace(rewriter.err)\n\t}\n\treturn rewriter.ctxStack[0], rewriter.p, nil\n}\n\ntype expressionRewriter struct {\n\tctxStack   []expression.Expression\n\tctxNameStk []*types.FieldName\n\tp          LogicalPlan\n\tschema     *expression.Schema\n\tnames      []*types.FieldName\n\terr        error\n\taggrMap    map[*ast.AggregateFuncExpr]int\n\twindowMap  map[*ast.WindowFuncExpr]int\n\tb          *PlanBuilder\n\tsctx       sessionctx.Context\n\tctx        context.Context\n\n\t// asScalar indicates the return value must be a scalar value.\n\t// NOTE: This value can be changed during expression rewritten.\n\tasScalar bool\n\n\t// disableFoldCounter controls fold-disabled scope. If > 0, rewriter will NOT do constant folding.\n\t// Typically, during visiting AST, while entering the scope(disable), the counter will +1; while\n\t// leaving the scope(enable again), the counter will -1.\n\t// NOTE: This value can be changed during expression rewritten.\n\tdisableFoldCounter int\n}\n\nfunc (er *expressionRewriter) ctxStackLen() int {\n\treturn len(er.ctxStack)\n}\n\nfunc (er *expressionRewriter) ctxStackPop(num int) {\n\tl := er.ctxStackLen()\n\ter.ctxStack = er.ctxStack[:l-num]\n\ter.ctxNameStk = er.ctxNameStk[:l-num]\n}\n\nfunc (er *expressionRewriter) ctxStackAppend(col expression.Expression, name *types.FieldName) {\n\ter.ctxStack = append(er.ctxStack, col)\n\ter.ctxNameStk = append(er.ctxNameStk, name)\n}\n\n// constructBinaryOpFunction converts binary operator functions\n// 1. If op are EQ or NE or NullEQ, constructBinaryOpFunctions converts (a0,a1,a2) op (b0,b1,b2) to (a0 op b0) and (a1 op b1) and (a2 op b2)\n// 2. Else constructBinaryOpFunctions converts (a0,a1,a2) op (b0,b1,b2) to\n// `IF( a0 NE b0, a0 op b0,\n//\n//\tIF ( isNull(a0 NE b0), Null,\n//\t        IF ( a1 NE b1, a1 op b1,\n//\t                IF ( isNull(a1 NE b1), Null, a2 op b2))))`\nfunc (er *expressionRewriter) constructBinaryOpFunction(l expression.Expression, r expression.Expression, op string) (expression.Expression, error) {\n\tlLen, rLen := expression.GetRowLen(l), expression.GetRowLen(r)\n\tif lLen == 1 && rLen == 1 {\n\t\treturn er.newFunction(op, types.NewFieldType(mysql.TypeTiny), l, r)\n\t} else if rLen != lLen {\n\t\treturn nil, expression.ErrOperandColumns.GenWithStackByArgs(lLen)\n\t}\n\tswitch op {\n\tcase ast.EQ, ast.NE, ast.NullEQ:\n\t\tfuncs := make([]expression.Expression, lLen)\n\t\tfor i := 0; i < lLen; i++ {\n\t\t\tvar err error\n\t\t\tfuncs[i], err = er.constructBinaryOpFunction(expression.GetFuncArg(l, i), expression.GetFuncArg(r, i), op)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tif op == ast.NE {\n\t\t\treturn expression.ComposeDNFCondition(er.sctx, funcs...), nil\n\t\t}\n\t\treturn expression.ComposeCNFCondition(er.sctx, funcs...), nil\n\tdefault:\n\t\tlarg0, rarg0 := expression.GetFuncArg(l, 0), expression.GetFuncArg(r, 0)\n\t\tvar expr1, expr2, expr3, expr4, expr5 expression.Expression\n\t\texpr1 = expression.NewFunctionInternal(er.sctx, ast.NE, types.NewFieldType(mysql.TypeTiny), larg0, rarg0)\n\t\texpr2 = expression.NewFunctionInternal(er.sctx, op, types.NewFieldType(mysql.TypeTiny), larg0, rarg0)\n\t\texpr3 = expression.NewFunctionInternal(er.sctx, ast.IsNull, types.NewFieldType(mysql.TypeTiny), expr1)\n\t\tvar err error\n\t\tl, err = expression.PopRowFirstArg(er.sctx, l)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tr, err = expression.PopRowFirstArg(er.sctx, r)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\texpr4, err = er.constructBinaryOpFunction(l, r, op)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\texpr5, err = er.newFunction(ast.If, types.NewFieldType(mysql.TypeTiny), expr3, expression.Null, expr4)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn er.newFunction(ast.If, types.NewFieldType(mysql.TypeTiny), expr1, expr2, expr5)\n\t}\n}\n\nfunc (er *expressionRewriter) buildSubquery(ctx context.Context, subq *ast.SubqueryExpr) (LogicalPlan, error) {\n\tif er.schema != nil {\n\t\touterSchema := er.schema.Clone()\n\t\ter.b.outerSchemas = append(er.b.outerSchemas, outerSchema)\n\t\ter.b.outerNames = append(er.b.outerNames, er.names)\n\t\tdefer func() {\n\t\t\ter.b.outerSchemas = er.b.outerSchemas[0 : len(er.b.outerSchemas)-1]\n\t\t\ter.b.outerNames = er.b.outerNames[0 : len(er.b.outerNames)-1]\n\t\t}()\n\t}\n\n\tnp, err := er.b.buildResultSetNode(ctx, subq.Query)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn np, nil\n}\n\n// Enter implements Visitor interface.\nfunc (er *expressionRewriter) Enter(inNode ast.Node) (ast.Node, bool) {\n\tswitch v := inNode.(type) {\n\tcase *ast.AggregateFuncExpr:\n\t\tindex, ok := -1, false\n\t\tif er.aggrMap != nil {\n\t\t\tindex, ok = er.aggrMap[v]\n\t\t}\n\t\tif !ok {\n\t\t\ter.err = ErrInvalidGroupFuncUse\n\t\t\treturn inNode, true\n\t\t}\n\t\ter.ctxStackAppend(er.schema.Columns[index], er.names[index])\n\t\treturn inNode, true\n\tcase *ast.ColumnNameExpr:\n\t\tif index, ok := er.b.colMapper[v]; ok {\n\t\t\ter.ctxStackAppend(er.schema.Columns[index], er.names[index])\n\t\t\treturn inNode, true\n\t\t}\n\tcase *ast.PatternInExpr:\n\t\tif v.Sel != nil {\n\t\t\treturn er.handleInSubquery(er.ctx, v)\n\t\t}\n\t\tif len(v.List) != 1 {\n\t\t\tbreak\n\t\t}\n\t\t// NOTE(yang.y): original implementation also handles double parentheses\n\t\t// like `10 in ((select * from t))`. We skip for now.\n\t\t// ref: https://github.com/pingcap/tidb/blob/6cb4230c8f2e59bf46497738c99cfacd2e967850/planner/core/expression_rewriter.go#L335\n\t\tx := v.List[0]\n\t\tfor {\n\t\t\tswitch y := x.(type) {\n\t\t\tcase *ast.SubqueryExpr:\n\t\t\t\tv.Sel = y\n\t\t\t\treturn er.handleInSubquery(er.ctx, v)\n\t\t\tcase *ast.ParenthesesExpr:\n\t\t\t\tx = y.Expr\n\t\t\tdefault:\n\t\t\t\treturn inNode, false\n\t\t\t}\n\t\t}\n\tcase *ast.WindowFuncExpr:\n\t\tindex, ok := -1, false\n\t\tif er.windowMap != nil {\n\t\t\tindex, ok = er.windowMap[v]\n\t\t}\n\t\tif !ok {\n\t\t\ter.err = ErrWindowInvalidWindowFuncUse.GenWithStackByArgs(strings.ToLower(v.F))\n\t\t\treturn inNode, true\n\t\t}\n\t\ter.ctxStackAppend(er.schema.Columns[index], er.names[index])\n\t\treturn inNode, true\n\tcase *ast.FuncCallExpr:\n\t\tif _, ok := expression.DisableFoldFunctions[v.FnName.L]; ok {\n\t\t\ter.disableFoldCounter++\n\t\t}\n\tcase *ast.SubqueryExpr:\n\t\treturn er.handleScalarSubquery(er.ctx, v)\n\tcase *ast.CompareSubqueryExpr:\n\t\treturn er.handleCompareSubquery(er.ctx, v)\n\tcase *ast.ParenthesesExpr: // do nothing\n\tcase *ast.ExistsSubqueryExpr:\n\t\treturn er.handleExistSubquery(er.ctx, v)\n\tcase *ast.ValuesExpr:\n\t\ter.err = fmt.Errorf(\"unsupported expression type %T\", v)\n\tdefault:\n\t\ter.asScalar = true\n\t}\n\treturn inNode, false\n}\n\nfunc (er *expressionRewriter) handleScalarSubquery(ctx context.Context, v *ast.SubqueryExpr) (ast.Node, bool) {\n\tnp, err := er.buildSubquery(ctx, v)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn v, true\n\t}\n\n\t// below code are from tidb\n\tnp = er.b.buildMaxOneRow(np)\n\t// if len(np.extractCorrelatedCols()) > 0 {\n\ter.p = er.b.buildApplyWithJoinType(er.p, np, LeftOuterJoin)\n\tif np.Schema().Len() > 1 {\n\t\tnewCols := make([]expression.Expression, 0, np.Schema().Len())\n\t\tfor _, col := range np.Schema().Columns {\n\t\t\tnewCols = append(newCols, col)\n\t\t}\n\t\texpr, err1 := er.newFunction(ast.RowFunc, newCols[0].GetType(), newCols...)\n\t\tif err1 != nil {\n\t\t\ter.err = err1\n\t\t\treturn v, true\n\t\t}\n\t\ter.ctxStackAppend(expr, types.EmptyName)\n\t} else {\n\t\ter.ctxStackAppend(er.p.Schema().Columns[er.p.Schema().Len()-1], er.p.OutputNames()[er.p.Schema().Len()-1])\n\t}\n\treturn v, true\n\t// }\n\t// physicalPlan, _, err := DoOptimize(ctx, er.b.optFlag, np)\n\t// if err != nil {\n\t// \ter.err = err\n\t// \treturn v, true\n\t// }\n\t// rows, err := EvalSubquery(ctx, physicalPlan, er.b.is, er.b.ctx)\n\t// if err != nil {\n\t// \ter.err = err\n\t// \treturn v, true\n\t// }\n\t// if np.Schema().Len() > 1 {\n\t// \tnewCols := make([]expression.Expression, 0, np.Schema().Len())\n\t// \tfor i, data := range rows[0] {\n\t// \t\tnewCols = append(newCols, &expression.Constant{\n\t// \t\t\tValue:   data,\n\t// \t\t\tRetType: np.Schema().Columns[i].GetType()})\n\t// \t}\n\t// \texpr, err1 := er.newFunction(ast.RowFunc, newCols[0].GetType(), newCols...)\n\t// \tif err1 != nil {\n\t// \t\ter.err = err1\n\t// \t\treturn v, true\n\t// \t}\n\t// \ter.ctxStackAppend(expr, types.EmptyName)\n\t// } else {\n\t// \ter.ctxStackAppend(&expression.Constant{\n\t// \t\tValue:   rows[0][0],\n\t// \t\tRetType: np.Schema().Columns[0].GetType(),\n\t// \t}, types.EmptyName)\n\t// }\n\t// return v, true\n}\n\nfunc (er *expressionRewriter) handleExistSubquery(ctx context.Context, v *ast.ExistsSubqueryExpr) (ast.Node, bool) {\n\tsubq, ok := v.Sel.(*ast.SubqueryExpr)\n\tif !ok {\n\t\ter.err = errors.Errorf(\"Unknown exists type %T.\", v.Sel)\n\t\treturn v, true\n\t}\n\tnp, err := er.buildSubquery(ctx, subq)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn v, true\n\t}\n\tnp = er.popExistsSubPlan(np)\n\tif len(np.extractCorrelatedCols()) > 0 {\n\t\ter.p, er.err = er.b.buildSemiApply(er.p, np, nil, er.asScalar, v.Not)\n\t\tif er.err != nil || !er.asScalar {\n\t\t\treturn v, true\n\t\t}\n\t\ter.ctxStackAppend(er.p.Schema().Columns[er.p.Schema().Len()-1], er.p.OutputNames()[er.p.Schema().Len()-1])\n\t} else {\n\t\t// NOTE: different from TiDB, temporarily return not supported error\n\t\ter.err = errors.New(\"not supported exists subquery without correlated columns\")\n\t}\n\treturn v, true\n}\n\n// popExistsSubPlan will remove the useless plan in exist's child.\n// See comments inside the method for more details.\nfunc (er *expressionRewriter) popExistsSubPlan(p LogicalPlan) LogicalPlan {\nout:\n\tfor {\n\t\tswitch plan := p.(type) {\n\t\t// This can be removed when in exists clause,\n\t\t// e.g. exists(select count(*) from t order by a) is equal to exists t.\n\t\tcase *LogicalProjection, *LogicalSort:\n\t\t\tp = p.Children()[0]\n\t\tcase *LogicalAggregation:\n\t\t\tif len(plan.GroupByItems) == 0 {\n\t\t\t\tp = LogicalTableDual{RowCount: 1}.Init(er.sctx, er.b.getSelectOffset())\n\t\t\t\tbreak out\n\t\t\t}\n\t\t\tp = p.Children()[0]\n\t\tdefault:\n\t\t\tbreak out\n\t\t}\n\t}\n\treturn p\n}\n\nfunc (er *expressionRewriter) handleInSubquery(ctx context.Context, v *ast.PatternInExpr) (ast.Node, bool) {\n\tasScalar := er.asScalar\n\ter.asScalar = true\n\tv.Expr.Accept(er)\n\tif er.err != nil {\n\t\treturn v, true\n\t}\n\tlexpr := er.ctxStack[len(er.ctxStack)-1]\n\tsubq, ok := v.Sel.(*ast.SubqueryExpr)\n\tif !ok {\n\t\ter.err = errors.Errorf(\"Unknown compare type %T.\", v.Sel)\n\t\treturn v, true\n\t}\n\tnp, err := er.buildSubquery(ctx, subq)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn v, true\n\t}\n\tlLen := expression.GetRowLen(lexpr)\n\tif lLen != np.Schema().Len() {\n\t\ter.err = expression.ErrOperandColumns.GenWithStackByArgs(lLen)\n\t\treturn v, true\n\t}\n\tvar rexpr expression.Expression\n\tif np.Schema().Len() == 1 {\n\t\trexpr = np.Schema().Columns[0]\n\t\trCol := rexpr.(*expression.Column)\n\t\t// For AntiSemiJoin/LeftOuterSemiJoin/AntiLeftOuterSemiJoin, we cannot treat `in` expression as\n\t\t// normal column equal condition, so we specially mark the inner operand here.\n\t\tif v.Not || asScalar {\n\t\t\trCol.InOperand = true\n\t\t\t// If both input columns of `in` expression are not null, we can treat the expression\n\t\t\t// as normal column equal condition instead.\n\t\t\tlCol, ok := lexpr.(*expression.Column)\n\t\t\tif ok && mysql.HasNotNullFlag(lCol.GetType().Flag) && mysql.HasNotNullFlag(rCol.GetType().Flag) {\n\t\t\t\trCol.InOperand = false\n\t\t\t}\n\t\t}\n\t} else {\n\t\targs := make([]expression.Expression, 0, np.Schema().Len())\n\t\tfor _, col := range np.Schema().Columns {\n\t\t\targs = append(args, col)\n\t\t}\n\t\trexpr, er.err = er.newFunction(ast.RowFunc, args[0].GetType(), args...)\n\t\tif er.err != nil {\n\t\t\treturn v, true\n\t\t}\n\t}\n\tcheckCondition, err := er.constructBinaryOpFunction(lexpr, rexpr, ast.EQ)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn v, true\n\t}\n\t// NOTE(yang.y): the original implementation would check co-related column\n\t// to see if the apply can be rewritten as inner join. However, it is unclear if\n\t// need this optimization.\n\t// ref: https://github.com/pingcap/tidb/blob/6cb4230c8f2e59bf46497738c99cfacd2e967850/planner/core/expression_rewriter.go#L799-L828\n\ter.p, er.err = er.b.buildSemiApply(er.p, np, expression.SplitCNFItems(checkCondition), asScalar, v.Not)\n\tif er.err != nil {\n\t\treturn v, true\n\t}\n\n\ter.ctxStackPop(1)\n\tif asScalar {\n\t\tcol := er.p.Schema().Columns[er.p.Schema().Len()-1]\n\t\ter.ctxStackAppend(col, er.p.OutputNames()[er.p.Schema().Len()-1])\n\t}\n\treturn v, true\n}\n\nfunc (er *expressionRewriter) toParamMarker(sctx sessionctx.Context, v *driver.ParamMarkerExpr) {\n\tvar value *expression.Constant\n\tvalue, er.err = expression.ParamMarkerExpression(sctx, v)\n\tif er.err != nil {\n\t\treturn\n\t}\n\ter.ctxStackAppend(value, types.EmptyName)\n}\n\n// Leave implements Visitor interface.\nfunc (er *expressionRewriter) Leave(originInNode ast.Node) (retNode ast.Node, ok bool) {\n\tif er.err != nil {\n\t\treturn retNode, false\n\t}\n\tvar inNode = originInNode\n\tswitch v := inNode.(type) {\n\tcase *ast.AggregateFuncExpr, *ast.ColumnNameExpr, *ast.ParenthesesExpr, *ast.SubqueryExpr, *ast.WhenClause, *ast.WindowFuncExpr, *ast.CompareSubqueryExpr, *ast.ExistsSubqueryExpr: // do nothing\n\tcase *driver.ValueExpr:\n\t\tvalue := &expression.Constant{Value: v.Datum, RetType: &v.Type}\n\t\ter.ctxStackAppend(value, types.EmptyName)\n\tcase *ast.CaseExpr:\n\t\ter.caseToExpression(v)\n\tcase *ast.FuncCastExpr:\n\t\targ := er.ctxStack[len(er.ctxStack)-1]\n\t\ter.err = expression.CheckArgsNotMultiColumnRow(arg)\n\t\tif er.err != nil {\n\t\t\treturn retNode, false\n\t\t}\n\n\t\t// check the decimal precision of \"CAST(AS TIME)\".\n\t\t// er.err = er.checkTimePrecision(v.Tp)\n\t\t// if er.err != nil {\n\t\t// \treturn retNode, false\n\t\t// }\n\n\t\t// if v.Tp.EvalType() == types.ETString {\n\t\t// \targ.SetCoercibility(expression.CoercibilityImplicit)\n\t\t// }\n\n\t\ter.ctxStack[len(er.ctxStack)-1] = expression.BuildCastFunction(er.sctx, arg, v.Tp)\n\t\ter.ctxNameStk[len(er.ctxNameStk)-1] = types.EmptyName\n\tcase *ast.ColumnName:\n\t\ter.toColumn(v)\n\tcase *ast.UnaryOperationExpr:\n\t\ter.unaryOpToExpression(v)\n\tcase *ast.BinaryOperationExpr:\n\t\ter.binaryOpToExpression(v)\n\tcase *ast.BetweenExpr:\n\t\ter.betweenToExpression(v)\n\tcase *ast.PatternInExpr:\n\t\tif v.Sel == nil {\n\t\t\ter.inToExpression(len(v.List), v.Not, &v.Type)\n\t\t}\n\tcase *ast.PatternLikeExpr:\n\t\ter.patternLikeToExpression(v)\n\tcase *ast.PatternRegexpExpr:\n\t\ter.regexpToScalarFunc(v)\n\tcase *ast.IsNullExpr:\n\t\ter.isNullToExpression(v)\n\tcase *ast.FuncCallExpr:\n\t\ter.funcCallToExpression(v)\n\t\tif _, ok := expression.DisableFoldFunctions[v.FnName.L]; ok {\n\t\t\ter.disableFoldCounter--\n\t\t}\n\tcase *ast.TimeUnitExpr:\n\t\ter.ctxStackAppend(&expression.Constant{\n\t\t\tValue:   types.NewStringDatum(v.Unit.String()),\n\t\t\tRetType: types.NewFieldType(mysql.TypeVarchar),\n\t\t}, types.EmptyName)\n\tcase *driver.ParamMarkerExpr:\n\t\ter.toParamMarker(er.sctx, v)\n\tdefault:\n\t\ter.err = errors.Errorf(\"UnknownType: %T\", v)\n\t\treturn retNode, false\n\t}\n\n\tif er.err != nil {\n\t\treturn retNode, false\n\t}\n\treturn originInNode, true\n}\n\n// newFunction chooses which expression.NewFunctionImpl() will be used.\nfunc (er *expressionRewriter) newFunction(funcName string, retType *types.FieldType, args ...expression.Expression) (expression.Expression, error) {\n\treturn expression.NewFunction(er.sctx, funcName, retType, args...)\n}\n\nfunc (er *expressionRewriter) useCache() bool {\n\t// return er.sctx.GetSessionVars().StmtCtx.UseCache\n\t// NOTE(@qijun) return false directly\n\treturn false\n}\n\nfunc (er *expressionRewriter) unaryOpToExpression(v *ast.UnaryOperationExpr) {\n\tstkLen := len(er.ctxStack)\n\tvar op string\n\tswitch v.Op {\n\tcase opcode.Plus:\n\t\t// expression (+ a) is equal to a\n\t\treturn\n\tcase opcode.Minus:\n\t\tif value, ok := v.V.(*driver.ValueExpr); ok {\n\t\t\tswitch value.Datum.Kind() {\n\t\t\tcase types.KindInt64:\n\t\t\t\tvalue.Datum.SetValue(-value.Datum.GetInt64())\n\t\t\tcase types.KindUint64:\n\t\t\t\tvalue.Datum.SetValue(-value.Datum.GetUint64())\n\t\t\tcase types.KindFloat32:\n\t\t\t\tvalue.Datum.SetValue(-value.Datum.GetFloat32())\n\t\t\tcase types.KindFloat64:\n\t\t\t\tvalue.Datum.SetValue(-value.Datum.GetFloat64())\n\t\t\tcase types.KindMysqlDecimal:\n\t\t\t\tvalue.GetMysqlDecimal().SetNegative(!value.Datum.GetMysqlDecimal().IsNegative())\n\t\t\tdefault:\n\t\t\t\ter.err = errors.Errorf(\"UnSupported UnaryMinus arg %v\", value)\n\t\t\t\treturn\n\t\t\t}\n\t\t\ter.ctxStack[stkLen-1] = &expression.Constant{Value: value.Datum, RetType: er.ctxStack[stkLen-1].GetType()}\n\t\t\tv.Op = opcode.Plus\n\t\t\treturn\n\t\t}\n\t\top = ast.UnaryMinus\n\tcase opcode.BitNeg:\n\t\top = ast.BitNeg\n\tcase opcode.Not:\n\t\top = ast.UnaryNot\n\tdefault:\n\t\ter.err = errors.Errorf(\"Unknown Unary Op %T\", v.Op)\n\t\treturn\n\t}\n\tif expression.GetRowLen(er.ctxStack[stkLen-1]) != 1 {\n\t\ter.err = expression.ErrOperandColumns.GenWithStackByArgs(1)\n\t\treturn\n\t}\n\ter.ctxStack[stkLen-1], er.err = er.newFunction(op, &v.Type, er.ctxStack[stkLen-1])\n\ter.ctxNameStk[stkLen-1] = types.EmptyName\n}\n\nfunc (er *expressionRewriter) binaryOpToExpression(v *ast.BinaryOperationExpr) {\n\tstkLen := len(er.ctxStack)\n\tvar function expression.Expression\n\tswitch v.Op {\n\tcase opcode.EQ, opcode.NE, opcode.NullEQ, opcode.GT, opcode.GE, opcode.LT, opcode.LE:\n\t\tfunction, er.err = er.constructBinaryOpFunction(er.ctxStack[stkLen-2], er.ctxStack[stkLen-1],\n\t\t\tv.Op.String())\n\tdefault:\n\t\tlLen := expression.GetRowLen(er.ctxStack[stkLen-2])\n\t\trLen := expression.GetRowLen(er.ctxStack[stkLen-1])\n\t\tif lLen != 1 || rLen != 1 {\n\t\t\ter.err = expression.ErrOperandColumns.GenWithStackByArgs(1)\n\t\t\treturn\n\t\t}\n\t\tif v.Op == opcode.Div {\n\t\t\targL := er.ctxStack[stkLen-2]\n\t\t\targR := er.ctxStack[stkLen-1]\n\t\t\tif argL.GetType().IsInt() && argR.GetType().IsInt() {\n\t\t\t\ter.ctxStack[stkLen-2] = expression.BuildCastFunction(er.sctx, argL, types.NewFieldType(mysql.TypeDouble))\n\t\t\t}\n\t\t}\n\t\tfunction, er.err = er.newFunction(v.Op.String(), types.NewFieldType(mysql.TypeUnspecified), er.ctxStack[stkLen-2:]...)\n\t}\n\tif er.err != nil {\n\t\treturn\n\t}\n\ter.ctxStackPop(2)\n\ter.ctxStackAppend(function, types.EmptyName)\n}\n\nfunc (er *expressionRewriter) betweenToExpression(v *ast.BetweenExpr) {\n\tstkLen := len(er.ctxStack)\n\ter.err = expression.CheckArgsNotMultiColumnRow(er.ctxStack[stkLen-3:]...)\n\tif er.err != nil {\n\t\treturn\n\t}\n\n\texpr, lexp, rexp := er.ctxStack[stkLen-3], er.ctxStack[stkLen-2], er.ctxStack[stkLen-1]\n\tvar l, r expression.Expression\n\tl, er.err = expression.NewFunction(er.sctx, ast.GE, &v.Type, expr, lexp)\n\tif er.err != nil {\n\t\treturn\n\t}\n\tr, er.err = expression.NewFunction(er.sctx, ast.LE, &v.Type, expr, rexp)\n\tif er.err != nil {\n\t\treturn\n\t}\n\tfunction, err := er.newFunction(ast.LogicAnd, &v.Type, l, r)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn\n\t}\n\tif v.Not {\n\t\tfunction, err = er.newFunction(ast.UnaryNot, &v.Type, function)\n\t\tif err != nil {\n\t\t\ter.err = err\n\t\t\treturn\n\t\t}\n\t}\n\ter.ctxStackPop(3)\n\ter.ctxStackAppend(function, types.EmptyName)\n}\n\nfunc (er *expressionRewriter) notToExpression(hasNot bool, op string, tp *types.FieldType,\n\targs ...expression.Expression) expression.Expression {\n\topFunc, err := er.newFunction(op, tp, args...)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn nil\n\t}\n\tif !hasNot {\n\t\treturn opFunc\n\t}\n\n\topFunc, err = er.newFunction(ast.UnaryNot, tp, opFunc)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn nil\n\t}\n\treturn opFunc\n}\n\nfunc (er *expressionRewriter) isNullToExpression(v *ast.IsNullExpr) {\n\tstkLen := len(er.ctxStack)\n\tif expression.GetRowLen(er.ctxStack[stkLen-1]) != 1 {\n\t\ter.err = expression.ErrOperandColumns.GenWithStackByArgs(1)\n\t\treturn\n\t}\n\tfunction := er.notToExpression(v.Not, ast.IsNull, &v.Type, er.ctxStack[stkLen-1])\n\ter.ctxStackPop(1)\n\ter.ctxStackAppend(function, types.EmptyName)\n}\n\n// inToExpression converts in expression to a scalar function. The argument lLen means the length of in list.\n// The argument not means if the expression is not in. The tp stands for the expression type, which is always bool.\n// a in (b, c, d) will be rewritten as `(a = b) or (a = c) or (a = d)`.\nfunc (er *expressionRewriter) inToExpression(lLen int, not bool, tp *types.FieldType) {\n\tstkLen := len(er.ctxStack)\n\tl := expression.GetRowLen(er.ctxStack[stkLen-lLen-1])\n\tfor i := 0; i < lLen; i++ {\n\t\tif l != expression.GetRowLen(er.ctxStack[stkLen-lLen+i]) {\n\t\t\ter.err = expression.ErrOperandColumns.GenWithStackByArgs(l)\n\t\t\treturn\n\t\t}\n\t}\n\targs := er.ctxStack[stkLen-lLen-1:]\n\tleftFt := args[0].GetType()\n\tleftEt, leftIsNull := leftFt.EvalType(), leftFt.Tp == mysql.TypeNull\n\tif leftIsNull {\n\t\ter.ctxStackPop(lLen + 1)\n\t\ter.ctxStackAppend(expression.Null.Clone(), types.EmptyName)\n\t\treturn\n\t}\n\tif leftEt == types.ETInt {\n\t\tfor i := 1; i < len(args); i++ {\n\t\t\tif c, ok := args[i].(*expression.Constant); ok {\n\t\t\t\tvar isExceptional bool\n\t\t\t\targs[i], isExceptional = expression.RefineComparedConstant(er.sctx, *leftFt, c, opcode.EQ)\n\t\t\t\tif isExceptional {\n\t\t\t\t\targs[i] = c\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// in this place, no need to check type\n\t// convert in to equal and or then equal will check type and convert input parameters into same type\n\t// for example int in float\n\t// firstly int in float -> int equal float\n\t// secondly int -> float then int equal float -> float equal float\n\t// so check type is useless in this place\n\tvar function expression.Expression\n\teqFunctions := make([]expression.Expression, 0, lLen)\n\tfor i := stkLen - lLen; i < stkLen; i++ {\n\t\texpr, err := er.constructBinaryOpFunction(args[0], er.ctxStack[i], ast.EQ)\n\t\tif err != nil {\n\t\t\ter.err = err\n\t\t\treturn\n\t\t}\n\t\teqFunctions = append(eqFunctions, expr)\n\t}\n\tfunction = expression.ComposeDNFCondition(er.sctx, eqFunctions...)\n\tif not {\n\t\tvar err error\n\t\tfunction, err = er.newFunction(ast.UnaryNot, tp, function)\n\t\tif err != nil {\n\t\t\ter.err = err\n\t\t\treturn\n\t\t}\n\t}\n\ter.ctxStackPop(lLen + 1)\n\ter.ctxStackAppend(function, types.EmptyName)\n}\n\nfunc (er *expressionRewriter) caseToExpression(v *ast.CaseExpr) {\n\tstkLen := len(er.ctxStack)\n\targsLen := 2 * len(v.WhenClauses)\n\tif v.ElseClause != nil {\n\t\targsLen++\n\t}\n\ter.err = expression.CheckArgsNotMultiColumnRow(er.ctxStack[stkLen-argsLen:]...)\n\tif er.err != nil {\n\t\treturn\n\t}\n\n\t// value                          -> ctxStack[stkLen-argsLen-1]\n\t// when clause(condition, result) -> ctxStack[stkLen-argsLen:stkLen-1];\n\t// else clause                    -> ctxStack[stkLen-1]\n\tvar args []expression.Expression\n\tif v.Value != nil {\n\t\t// args:  eq scalar func(args: value, condition1), result1,\n\t\t//        eq scalar func(args: value, condition2), result2,\n\t\t//        ...\n\t\t//        else clause\n\t\tvalue := er.ctxStack[stkLen-argsLen-1]\n\t\targs = make([]expression.Expression, 0, argsLen)\n\t\tfor i := stkLen - argsLen; i < stkLen-1; i += 2 {\n\t\t\targ, err := er.newFunction(ast.EQ, types.NewFieldType(mysql.TypeTiny), value, er.ctxStack[i])\n\t\t\tif err != nil {\n\t\t\t\ter.err = err\n\t\t\t\treturn\n\t\t\t}\n\t\t\targs = append(args, arg)\n\t\t\targs = append(args, er.ctxStack[i+1])\n\t\t}\n\t\tif v.ElseClause != nil {\n\t\t\targs = append(args, er.ctxStack[stkLen-1])\n\t\t}\n\t\targsLen++ // for trimming the value element later\n\t} else {\n\t\t// args:  condition1, result1,\n\t\t//        condition2, result2,\n\t\t//        ...\n\t\t//        else clause\n\t\targs = er.ctxStack[stkLen-argsLen:]\n\t}\n\tfunction, err := er.newFunction(ast.Case, &v.Type, args...)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn\n\t}\n\ter.ctxStackPop(argsLen)\n\ter.ctxStackAppend(function, types.EmptyName)\n}\n\nfunc (er *expressionRewriter) patternLikeToExpression(v *ast.PatternLikeExpr) {\n\tl := len(er.ctxStack)\n\ter.err = expression.CheckArgsNotMultiColumnRow(er.ctxStack[l-2:]...)\n\tif er.err != nil {\n\t\treturn\n\t}\n\n\tvar function expression.Expression\n\tfieldType := &types.FieldType{}\n\tisPatternExactMatch := false\n\t// Treat predicate 'like' the same way as predicate '=' when it is an exact match and new collation is not enabled.\n\tif patExpression, ok := er.ctxStack[l-1].(*expression.Constant); ok {\n\t\tpatString, isNull, err := patExpression.EvalString(nil, chunk.Row{})\n\t\tif err != nil {\n\t\t\ter.err = err\n\t\t\treturn\n\t\t}\n\t\tif !isNull {\n\t\t\tpatValue, patTypes := stringutil.CompilePattern(patString, v.Escape)\n\t\t\tif stringutil.IsExactMatch(patTypes) && er.ctxStack[l-2].GetType().EvalType() == types.ETString {\n\t\t\t\top := ast.EQ\n\t\t\t\tif v.Not {\n\t\t\t\t\top = ast.NE\n\t\t\t\t}\n\t\t\t\ttypes.DefaultTypeForValue(string(patValue), fieldType)\n\t\t\t\tfunction, er.err = er.constructBinaryOpFunction(er.ctxStack[l-2],\n\t\t\t\t\t&expression.Constant{Value: types.NewStringDatum(string(patValue)), RetType: fieldType},\n\t\t\t\t\top)\n\t\t\t\tisPatternExactMatch = true\n\t\t\t}\n\t\t}\n\t}\n\tif !isPatternExactMatch {\n\t\ttypes.DefaultTypeForValue(int(v.Escape), fieldType)\n\t\tfunction = er.notToExpression(v.Not, ast.Like, &v.Type,\n\t\t\ter.ctxStack[l-2], er.ctxStack[l-1], &expression.Constant{Value: types.NewIntDatum(int64(v.Escape)), RetType: fieldType})\n\t}\n\n\ter.ctxStackPop(2)\n\ter.ctxStackAppend(function, types.EmptyName)\n}\n\nfunc (er *expressionRewriter) regexpToScalarFunc(v *ast.PatternRegexpExpr) {\n\tl := len(er.ctxStack)\n\ter.err = expression.CheckArgsNotMultiColumnRow(er.ctxStack[l-2:]...)\n\tif er.err != nil {\n\t\treturn\n\t}\n\tfunction := er.notToExpression(v.Not, ast.Regexp, &v.Type, er.ctxStack[l-2], er.ctxStack[l-1])\n\ter.ctxStackPop(2)\n\ter.ctxStackAppend(function, types.EmptyName)\n}\n\n// rewriteFuncCall handles a FuncCallExpr and generates a customized function.\n// It should return true if for the given FuncCallExpr a rewrite is performed so that original behavior is skipped.\n// Otherwise it should return false to indicate (the caller) that original behavior needs to be performed.\nfunc (er *expressionRewriter) rewriteFuncCall(v *ast.FuncCallExpr) bool {\n\tswitch v.FnName.L {\n\t// when column is not null, ifnull on such column is not necessary.\n\tcase ast.Ifnull:\n\t\tif len(v.Args) != 2 {\n\t\t\ter.err = expression.ErrIncorrectParameterCount.GenWithStackByArgs(v.FnName.O)\n\t\t\treturn true\n\t\t}\n\t\tstackLen := len(er.ctxStack)\n\t\targ1 := er.ctxStack[stackLen-2]\n\t\tcol, isColumn := arg1.(*expression.Column)\n\t\t// if expr1 is a column and column has not null flag, then we can eliminate ifnull on\n\t\t// this column.\n\t\tif isColumn && mysql.HasNotNullFlag(col.RetType.Flag) {\n\t\t\tname := er.ctxNameStk[stackLen-2]\n\t\t\tnewCol := col.Clone().(*expression.Column)\n\t\t\ter.ctxStackPop(len(v.Args))\n\t\t\ter.ctxStackAppend(newCol, name)\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\tcase ast.Nullif:\n\t\tif len(v.Args) != 2 {\n\t\t\ter.err = expression.ErrIncorrectParameterCount.GenWithStackByArgs(v.FnName.O)\n\t\t\treturn true\n\t\t}\n\t\tstackLen := len(er.ctxStack)\n\t\tparam1 := er.ctxStack[stackLen-2]\n\t\tparam2 := er.ctxStack[stackLen-1]\n\t\t// param1 = param2\n\t\tfuncCompare, err := er.constructBinaryOpFunction(param1, param2, ast.EQ)\n\t\tif err != nil {\n\t\t\ter.err = err\n\t\t\treturn true\n\t\t}\n\t\t// NULL\n\t\tnullTp := types.NewFieldType(mysql.TypeNull)\n\t\tnullTp.Flen, nullTp.Decimal = mysql.GetDefaultFieldLengthAndDecimal(mysql.TypeNull)\n\t\tparamNull := &expression.Constant{\n\t\t\tValue:   types.NewDatum(nil),\n\t\t\tRetType: nullTp,\n\t\t}\n\t\t// if(param1 = param2, NULL, param1)\n\t\tfuncIf, err := er.newFunction(ast.If, &v.Type, funcCompare, paramNull, param1)\n\t\tif err != nil {\n\t\t\ter.err = err\n\t\t\treturn true\n\t\t}\n\t\ter.ctxStackPop(len(v.Args))\n\t\ter.ctxStackAppend(funcIf, types.EmptyName)\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (er *expressionRewriter) funcCallToExpression(v *ast.FuncCallExpr) {\n\tstackLen := len(er.ctxStack)\n\targs := er.ctxStack[stackLen-len(v.Args):]\n\ter.err = expression.CheckArgsNotMultiColumnRow(args...)\n\tif er.err != nil {\n\t\treturn\n\t}\n\n\tif er.rewriteFuncCall(v) {\n\t\treturn\n\t}\n\n\tvar function expression.Expression\n\ter.ctxStackPop(len(v.Args))\n\tif _, ok := expression.DeferredFunctions[v.FnName.L]; er.useCache() && ok {\n\t\tfunction, er.err = expression.NewFunctionBase(er.sctx, v.FnName.L, &v.Type, args...)\n\t\tc := &expression.Constant{Value: types.NewDatum(nil), RetType: function.GetType().Clone(), DeferredExpr: function}\n\t\ter.ctxStackAppend(c, types.EmptyName)\n\t} else {\n\t\tfunction, er.err = er.newFunction(v.FnName.L, &v.Type, args...)\n\t\ter.ctxStackAppend(function, types.EmptyName)\n\t}\n}\n\nfunc (er *expressionRewriter) toColumn(v *ast.ColumnName) {\n\tidx, err := expression.FindFieldName(er.names, v)\n\tif err != nil {\n\t\ter.err = ErrAmbiguous.GenWithStackByArgs(v.Name, clauseMsg[fieldList])\n\t\treturn\n\t}\n\tif idx >= 0 {\n\t\tcolumn := er.schema.Columns[idx]\n\t\ter.ctxStackAppend(column, er.names[idx])\n\t\treturn\n\t}\n\tfor i := len(er.b.outerSchemas) - 1; i >= 0; i-- {\n\t\touterSchema, outerName := er.b.outerSchemas[i], er.b.outerNames[i]\n\t\tidx, err = expression.FindFieldName(outerName, v)\n\t\tif idx >= 0 {\n\t\t\tcolumn := outerSchema.Columns[idx]\n\t\t\ter.ctxStackAppend(&expression.CorrelatedColumn{Column: *column, Data: new(types.Datum)}, outerName[idx])\n\t\t\treturn\n\t\t}\n\t\tif err != nil {\n\t\t\ter.err = ErrAmbiguous.GenWithStackByArgs(v.Name, clauseMsg[fieldList])\n\t\t\treturn\n\t\t}\n\t}\n\tif join, ok := er.p.(*LogicalJoin); ok && join.redundantSchema != nil {\n\t\tidx, err := expression.FindFieldName(join.redundantNames, v)\n\t\tif err != nil {\n\t\t\ter.err = err\n\t\t\treturn\n\t\t}\n\t\tif idx >= 0 {\n\t\t\ter.ctxStackAppend(join.redundantSchema.Columns[idx], join.redundantNames[idx])\n\t\t\treturn\n\t\t}\n\t}\n\tif _, ok := er.p.(*LogicalUnionAll); ok && v.Table.O != \"\" {\n\t\ter.err = ErrTablenameNotAllowedHere.GenWithStackByArgs(v.Table.O, \"SELECT\", clauseMsg[er.b.curClause])\n\t\treturn\n\t}\n\tif er.b.curClause == globalOrderByClause {\n\t\ter.b.curClause = orderByClause\n\t}\n\ter.err = ErrUnknownColumn.GenWithStackByArgs(v.String(), clauseMsg[er.b.curClause])\n}\n\nfunc (er *expressionRewriter) handleCompareSubquery(ctx context.Context, v *ast.CompareSubqueryExpr) (ast.Node, bool) {\n\tv.L.Accept(er)\n\tif er.err != nil {\n\t\treturn v, true\n\t}\n\tlexpr := er.ctxStack[len(er.ctxStack)-1]\n\tsubq, ok := v.R.(*ast.SubqueryExpr)\n\tif !ok {\n\t\ter.err = errors.Errorf(\"Unknown compare type %T.\", v.R)\n\t\treturn v, true\n\t}\n\tnp, err := er.buildSubquery(ctx, subq)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn v, true\n\t}\n\t// Only (a,b,c) = any (...) and (a,b,c) != all (...) can use row expression.\n\tcanMultiCol := (!v.All && v.Op == opcode.EQ) || (v.All && v.Op == opcode.NE)\n\tif !canMultiCol && (expression.GetRowLen(lexpr) != 1 || np.Schema().Len() != 1) {\n\t\ter.err = expression.ErrOperandColumns.GenWithStackByArgs(1)\n\t\treturn v, true\n\t}\n\tlLen := expression.GetRowLen(lexpr)\n\tif lLen != np.Schema().Len() {\n\t\ter.err = expression.ErrOperandColumns.GenWithStackByArgs(lLen)\n\t\treturn v, true\n\t}\n\tvar rexpr expression.Expression\n\tif np.Schema().Len() == 1 {\n\t\trexpr = np.Schema().Columns[0]\n\t} else {\n\t\targs := make([]expression.Expression, 0, np.Schema().Len())\n\t\tfor _, col := range np.Schema().Columns {\n\t\t\targs = append(args, col)\n\t\t}\n\t\trexpr, er.err = er.newFunction(ast.RowFunc, args[0].GetType(), args...)\n\t\tif er.err != nil {\n\t\t\treturn v, true\n\t\t}\n\t}\n\tswitch v.Op {\n\t// Only EQ, NE and NullEQ can be composed with and.\n\tcase opcode.EQ, opcode.NE, opcode.NullEQ:\n\t\tif v.Op == opcode.EQ {\n\t\t\tif v.All {\n\t\t\t\ter.handleEQAll(lexpr, rexpr, np)\n\t\t\t} else {\n\t\t\t\t// `a = any(subq)` will be rewriten as `a in (subq)`.\n\t\t\t\ter.buildSemiApplyFromEqualSubq(np, lexpr, rexpr, false)\n\t\t\t\tif er.err != nil {\n\t\t\t\t\treturn v, true\n\t\t\t\t}\n\t\t\t}\n\t\t} else if v.Op == opcode.NE {\n\t\t\tif v.All {\n\t\t\t\t// `a != all(subq)` will be rewriten as `a not in (subq)`.\n\t\t\t\ter.buildSemiApplyFromEqualSubq(np, lexpr, rexpr, true)\n\t\t\t\tif er.err != nil {\n\t\t\t\t\treturn v, true\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ter.handleNEAny(lexpr, rexpr, np)\n\t\t\t}\n\t\t} else {\n\t\t\t// TODO: Support this in future.\n\t\t\ter.err = errors.New(\"We don't support <=> all or <=> any now\")\n\t\t\treturn v, true\n\t\t}\n\tdefault:\n\t\t// When < all or > any , the agg function should use min.\n\t\tuseMin := ((v.Op == opcode.LT || v.Op == opcode.LE) && v.All) || ((v.Op == opcode.GT || v.Op == opcode.GE) && !v.All)\n\t\ter.handleOtherComparableSubq(lexpr, rexpr, np, useMin, v.Op.String(), v.All)\n\t}\n\tif er.asScalar {\n\t\t// The parent expression only use the last column in schema, which represents whether the condition is matched.\n\t\ter.ctxStack[len(er.ctxStack)-1] = er.p.Schema().Columns[er.p.Schema().Len()-1]\n\t\ter.ctxNameStk[len(er.ctxNameStk)-1] = er.p.OutputNames()[er.p.Schema().Len()-1]\n\t}\n\treturn v, true\n}\n\nfunc (er *expressionRewriter) buildSemiApplyFromEqualSubq(np LogicalPlan, l, r expression.Expression, not bool) {\n\tvar condition expression.Expression\n\tif rCol, ok := r.(*expression.Column); ok && (er.asScalar || not) {\n\t\trCol.InOperand = true\n\t\t// If both input columns of `!= all / = any` expression are not null, we can treat the expression\n\t\t// as normal column equal condition.\n\t\tif lCol, ok := l.(*expression.Column); ok && mysql.HasNotNullFlag(lCol.GetType().Flag) && mysql.HasNotNullFlag(rCol.GetType().Flag) {\n\t\t\trCol.InOperand = false\n\t\t}\n\t}\n\tcondition, er.err = er.constructBinaryOpFunction(l, r, ast.EQ)\n\tif er.err != nil {\n\t\treturn\n\t}\n\ter.asScalar = true // scql change\n\ter.p, er.err = er.b.buildSemiApply(er.p, np, []expression.Expression{condition}, er.asScalar, not)\n}\n\n// handleNEAny handles the case of != any. For example, if the query is t.id != any (select s.id from s), it will be rewrote to\n// t.id != s.id or count(distinct s.id) > 1 or [any checker]. If there are two different values in s.id ,\n// there must exist a s.id that doesn't equal to t.id.\nfunc (er *expressionRewriter) handleNEAny(lexpr, rexpr expression.Expression, np LogicalPlan) {\n\tfirstRowFunc, err := aggregation.NewAggFuncDesc(er.sctx, ast.AggFuncFirstRow, []expression.Expression{rexpr}, false)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn\n\t}\n\tcountFunc, err := aggregation.NewAggFuncDesc(er.sctx, ast.AggFuncCount, []expression.Expression{rexpr}, true)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn\n\t}\n\tplan4Agg := LogicalAggregation{\n\t\tAggFuncs: []*aggregation.AggFuncDesc{firstRowFunc, countFunc},\n\t}.Init(er.sctx, er.b.getSelectOffset())\n\tif hint := er.b.TableHints(); hint != nil {\n\t\tplan4Agg.aggHints = hint.aggHints\n\t}\n\tplan4Agg.SetChildren(np)\n\tfirstRowResultCol := &expression.Column{\n\t\tUniqueID: er.sctx.GetSessionVars().AllocPlanColumnID(),\n\t\tRetType:  firstRowFunc.RetTp,\n\t}\n\tcount := &expression.Column{\n\t\tUniqueID: er.sctx.GetSessionVars().AllocPlanColumnID(),\n\t\tRetType:  countFunc.RetTp,\n\t}\n\tplan4Agg.names = append(plan4Agg.names, types.EmptyName, types.EmptyName)\n\tplan4Agg.SetSchema(expression.NewSchema(firstRowResultCol, count))\n\tgtFunc := expression.NewFunctionInternal(er.sctx, ast.GT, types.NewFieldType(mysql.TypeTiny), count, expression.One)\n\tneCond := expression.NewFunctionInternal(er.sctx, ast.NE, types.NewFieldType(mysql.TypeTiny), lexpr, firstRowResultCol)\n\tcond := expression.ComposeDNFCondition(er.sctx, gtFunc, neCond)\n\ter.buildQuantifierPlan(plan4Agg, cond, lexpr, rexpr, false)\n}\n\n// handleOtherComparableSubq handles the queries like < any, < max, etc. For example, if the query is t.id < any (select s.id from s),\n// it will be rewrote to t.id < (select max(s.id) from s).\nfunc (er *expressionRewriter) handleOtherComparableSubq(lexpr, rexpr expression.Expression, np LogicalPlan, useMin bool, cmpFunc string, all bool) {\n\tplan4Agg := LogicalAggregation{}.Init(er.sctx, er.b.getSelectOffset())\n\tif hint := er.b.TableHints(); hint != nil {\n\t\tplan4Agg.aggHints = hint.aggHints\n\t}\n\tplan4Agg.SetChildren(np)\n\n\t// Create a \"max\" or \"min\" aggregation.\n\tfuncName := ast.AggFuncMax\n\tif useMin {\n\t\tfuncName = ast.AggFuncMin\n\t}\n\tfuncMaxOrMin, err := aggregation.NewAggFuncDesc(er.sctx, funcName, []expression.Expression{rexpr}, false)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn\n\t}\n\n\t// Create a column and append it to the schema of that aggregation.\n\tcolMaxOrMin := &expression.Column{\n\t\tUniqueID: er.sctx.GetSessionVars().AllocPlanColumnID(),\n\t\tRetType:  funcMaxOrMin.RetTp,\n\t}\n\tschema := expression.NewSchema(colMaxOrMin)\n\n\tplan4Agg.names = append(plan4Agg.names, types.EmptyName)\n\tplan4Agg.SetSchema(schema)\n\tplan4Agg.AggFuncs = []*aggregation.AggFuncDesc{funcMaxOrMin}\n\n\tcond := expression.NewFunctionInternal(er.sctx, cmpFunc, types.NewFieldType(mysql.TypeTiny), lexpr, colMaxOrMin)\n\ter.buildQuantifierPlan(plan4Agg, cond, lexpr, rexpr, all)\n}\n\n// handleEQAll handles the case of = all. For example, if the query is t.id = all (select s.id from s), it will be rewrote to\n// t.id = (select s.id from s having count(distinct s.id) <= 1 and [all checker]).\nfunc (er *expressionRewriter) handleEQAll(lexpr, rexpr expression.Expression, np LogicalPlan) {\n\tfirstRowFunc, err := aggregation.NewAggFuncDesc(er.sctx, ast.AggFuncFirstRow, []expression.Expression{rexpr}, false)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn\n\t}\n\tcountFunc, err := aggregation.NewAggFuncDesc(er.sctx, ast.AggFuncCount, []expression.Expression{rexpr}, true)\n\tif err != nil {\n\t\ter.err = err\n\t\treturn\n\t}\n\tplan4Agg := LogicalAggregation{\n\t\tAggFuncs: []*aggregation.AggFuncDesc{firstRowFunc, countFunc},\n\t}.Init(er.sctx, er.b.getSelectOffset())\n\tif hint := er.b.TableHints(); hint != nil {\n\t\tplan4Agg.aggHints = hint.aggHints\n\t}\n\tplan4Agg.SetChildren(np)\n\tplan4Agg.names = append(plan4Agg.names, types.EmptyName)\n\tfirstRowResultCol := &expression.Column{\n\t\tUniqueID: er.sctx.GetSessionVars().AllocPlanColumnID(),\n\t\tRetType:  firstRowFunc.RetTp,\n\t}\n\tplan4Agg.names = append(plan4Agg.names, types.EmptyName)\n\tcount := &expression.Column{\n\t\tUniqueID: er.sctx.GetSessionVars().AllocPlanColumnID(),\n\t\tRetType:  countFunc.RetTp,\n\t}\n\tplan4Agg.SetSchema(expression.NewSchema(firstRowResultCol, count))\n\tleFunc := expression.NewFunctionInternal(er.sctx, ast.LE, types.NewFieldType(mysql.TypeTiny), count, expression.One)\n\teqCond := expression.NewFunctionInternal(er.sctx, ast.EQ, types.NewFieldType(mysql.TypeTiny), lexpr, firstRowResultCol)\n\tcond := expression.ComposeCNFCondition(er.sctx, leFunc, eqCond)\n\ter.buildQuantifierPlan(plan4Agg, cond, lexpr, rexpr, true)\n}\n"
  },
  {
    "path": "pkg/planner/core/hashcode.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"encoding/binary\"\n)\n\nfunc encodeIntAsUint32(result []byte, value int) []byte {\n\tvar buf [4]byte\n\tbinary.BigEndian.PutUint32(buf[:], uint32(value))\n\treturn append(result, buf[:]...)\n}\n\n// HashCode implements LogicalPlan interface.\nfunc (p *baseLogicalPlan) HashCode() []byte {\n\t// We use PlanID for the default hash, so if two plans do not have\n\t// the same id, the hash value will never be the same.\n\tresult := make([]byte, 0, 4)\n\tresult = encodeIntAsUint32(result, p.id)\n\treturn result\n}\n"
  },
  {
    "path": "pkg/planner/core/initialize.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/util/plancodec\"\n)\n\n// Init initializes LogicalAggregation.\nfunc (la LogicalAggregation) Init(ctx sessionctx.Context, offset int) *LogicalAggregation {\n\tla.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeAgg, &la, offset)\n\treturn &la\n}\n\nfunc (p LogicalJoin) Init(ctx sessionctx.Context, offset int) *LogicalJoin {\n\tp.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeJoin, &p, offset)\n\treturn &p\n}\n\n// Init initializes LogicalTableDual.\nfunc (p LogicalTableDual) Init(ctx sessionctx.Context, offset int) *LogicalTableDual {\n\tp.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeDual, &p, offset)\n\treturn &p\n}\n\n// Init initializes DataSource.\nfunc (ds DataSource) Init(ctx sessionctx.Context, offset int) *DataSource {\n\tds.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeTableScan, &ds, offset)\n\treturn &ds\n}\n\n// Init initializes LogicalTableScan.\nfunc (ts LogicalTableScan) Init(ctx sessionctx.Context, offset int) *LogicalTableScan {\n\tts.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeTableScan, &ts, offset)\n\treturn &ts\n}\n\n// Init initializes LogicalSelection.\nfunc (p LogicalSelection) Init(ctx sessionctx.Context, offset int) *LogicalSelection {\n\tp.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeSel, &p, offset)\n\treturn &p\n}\n\n// Init initializes LogicalProjection.\nfunc (p LogicalProjection) Init(ctx sessionctx.Context, offset int) *LogicalProjection {\n\tp.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeProj, &p, offset)\n\treturn &p\n}\n\n// Init initializes LogicalSort.\nfunc (ls LogicalSort) Init(ctx sessionctx.Context, offset int) *LogicalSort {\n\tls.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeSort, &ls, offset)\n\treturn &ls\n}\n\n// Init initializes LogicalLimit.\nfunc (p LogicalLimit) Init(ctx sessionctx.Context, offset int) *LogicalLimit {\n\tp.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeLimit, &p, offset)\n\treturn &p\n}\n\n// Init initializes LogicalWindow.\nfunc (p LogicalWindow) Init(ctx sessionctx.Context, offset int) *LogicalWindow {\n\tp.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeWindow, &p, offset)\n\treturn &p\n}\n\n// Init initializes LogicalUnionAll.\nfunc (p LogicalUnionAll) Init(ctx sessionctx.Context, offset int) *LogicalUnionAll {\n\tp.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeUnion, &p, offset)\n\treturn &p\n}\n\n// Init initializes LogicalShow.\nfunc (p LogicalShow) Init(ctx sessionctx.Context) *LogicalShow {\n\tp.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeShow, &p, 0)\n\treturn &p\n}\n\n// Init initializes LogicalApply.\nfunc (la LogicalApply) Init(ctx sessionctx.Context, offset int) *LogicalApply {\n\tla.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeApply, &la, offset)\n\treturn &la\n}\n\n// Init initializes LogicalMaxOneRow.\nfunc (p LogicalMaxOneRow) Init(ctx sessionctx.Context, offset int) *LogicalMaxOneRow {\n\tp.baseLogicalPlan = newBaseLogicalPlan(ctx, plancodec.TypeMaxOneRow, &p, offset)\n\treturn &p\n}\n"
  },
  {
    "path": "pkg/planner/core/logical_plan_builder.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"cmp\"\n\t\"context\"\n\t\"fmt\"\n\t\"math\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\t\"github.com/secretflow/scql/pkg/planner/property\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\tdriver \"github.com/secretflow/scql/pkg/types/parser_driver\"\n\t\"github.com/secretflow/scql/pkg/util/chunk\"\n\t\"github.com/secretflow/scql/pkg/util/mathutil\"\n\t\"github.com/secretflow/scql/pkg/util/plancodec\"\n)\n\nfunc (ds *DataSource) newExtraHandleSchemaCol() *expression.Column {\n\treturn &expression.Column{\n\t\tRetType:  types.NewFieldType(mysql.TypeLonglong),\n\t\tUniqueID: ds.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\tID:       model.ExtraHandleID,\n\t\tOrigName: fmt.Sprintf(\"%v.%v.%v\", ds.DBName, ds.tableInfo.Name, model.ExtraHandleName),\n\t}\n}\n\nfunc (b *PlanBuilder) buildDataSource(ctx context.Context, tn *ast.TableName,\n\tasName *model.CIStr) (LogicalPlan, error) {\n\tdbName := tn.Schema\n\tif dbName.L == \"\" {\n\t\tdbName = model.NewCIStr(b.ctx.GetSessionVars().CurrentDB)\n\t}\n\n\ttbl, err := b.is.TableByName(dbName, tn.Name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttableInfo := tbl.Meta()\n\n\tif tableInfo.IsView() {\n\t\treturn b.BuildDataSourceFromView(ctx, dbName, tableInfo)\n\t}\n\n\ttblName := *asName\n\tif tblName.L == \"\" {\n\t\ttblName = tn.Name\n\t}\n\tcolumns := tbl.Cols() // []table.Column\n\tds := DataSource{\n\t\tDBName:      dbName,\n\t\tTableAsName: asName,\n\t\ttable:       tbl,\n\t\ttableInfo:   tableInfo,\n\t\tColumns:     make([]*model.ColumnInfo, 0, len(columns)),\n\t\tTblCols:     make([]*expression.Column, 0, len(columns)),\n\t}.Init(b.ctx, b.getSelectOffset())\n\n\tschema := expression.NewSchema(make([]*expression.Column, 0, len(columns))...)\n\tnames := make([]*types.FieldName, 0, len(columns))\n\tfor i, col := range columns { // table.Column -> expression.Column\n\t\tds.Columns = append(ds.Columns, col.ToInfo())\n\t\tnames = append(names, &types.FieldName{\n\t\t\tDBName:      dbName,\n\t\t\tTblName:     tableInfo.Name,\n\t\t\tColName:     col.Name,\n\t\t\tOrigTblName: tableInfo.Name,\n\t\t\tOrigColName: col.Name,\n\t\t})\n\t\tnewCol := &expression.Column{\n\t\t\tUniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t\tID:       col.ID,\n\t\t\tRetType:  &col.FieldType,\n\t\t\tOrigName: names[i].String(),\n\t\t\tIsHidden: col.Hidden,\n\t\t}\n\n\t\tschema.Append(newCol)\n\t\tds.TblCols = append(ds.TblCols, newCol)\n\t}\n\tds.SetSchema(schema)\n\tds.names = names\n\tds.SetOwnerPartyCodes([]string{tableInfo.PartyCode})\n\n\treturn ds, nil\n}\n\n// BuildDataSourceFromView is used to build LogicalPlan from view\nfunc (b *PlanBuilder) BuildDataSourceFromView(ctx context.Context, dbName model.CIStr, tableInfo *model.TableInfo) (LogicalPlan, error) {\n\tviewParser := parser.New()\n\tselectNode, err := viewParser.ParseOneStmt(tableInfo.View.SelectStmt, \"\", \"\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tselectLogicalPlan, err := b.Build(ctx, selectNode)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"buildDataSourceFromView: %v\", err)\n\t}\n\n\tif len(tableInfo.Columns) != selectLogicalPlan.Schema().Len() {\n\t\treturn nil, fmt.Errorf(\"columns length is wrong table info(%d) != logicalplan schema(%d)\", len(tableInfo.Columns), selectLogicalPlan.Schema().Len())\n\t}\n\n\treturn b.buildProjUponView(ctx, dbName, tableInfo, selectLogicalPlan)\n}\n\nfunc (b *PlanBuilder) buildProjUponView(ctx context.Context, dbName model.CIStr, tableInfo *model.TableInfo, selectLogicalPlan Plan) (LogicalPlan, error) {\n\tcolumnInfo := tableInfo.Cols()\n\tcols := selectLogicalPlan.Schema().Clone().Columns\n\toutputNamesOfUnderlyingSelect := selectLogicalPlan.OutputNames().Shallow()\n\t// In the old version of VIEW implementation, tableInfo.View.Cols is used to\n\t// store the origin columns' names of the underlying SelectStmt used when\n\t// creating the view.\n\tif tableInfo.View.Cols != nil {\n\t\tcols = cols[:0]\n\t\toutputNamesOfUnderlyingSelect = outputNamesOfUnderlyingSelect[:0]\n\t\tfor _, info := range columnInfo {\n\t\t\tidx := expression.FindFieldNameIdxByColName(selectLogicalPlan.OutputNames(), info.Name.L)\n\t\t\tif idx == -1 {\n\t\t\t\treturn nil, ErrViewInvalid.GenWithStackByArgs(dbName.O, tableInfo.Name.O)\n\t\t\t}\n\t\t\tcols = append(cols, selectLogicalPlan.Schema().Columns[idx])\n\t\t\toutputNamesOfUnderlyingSelect = append(outputNamesOfUnderlyingSelect, selectLogicalPlan.OutputNames()[idx])\n\t\t}\n\t}\n\n\tprojSchema := expression.NewSchema(make([]*expression.Column, 0, len(tableInfo.Columns))...)\n\tprojExprs := make([]expression.Expression, 0, len(tableInfo.Columns))\n\tprojNames := make(types.NameSlice, 0, len(tableInfo.Columns))\n\tfor i, name := range outputNamesOfUnderlyingSelect {\n\t\torigColName := name.ColName\n\t\tif tableInfo.View.Cols != nil {\n\t\t\torigColName = tableInfo.View.Cols[i]\n\t\t}\n\t\tprojName := &types.FieldName{\n\t\t\t// TblName is the of view instead of the name of the underlying table.\n\t\t\tTblName:     tableInfo.Name,\n\t\t\tOrigTblName: name.OrigTblName,\n\t\t\tColName:     columnInfo[i].Name,\n\t\t\tOrigColName: origColName,\n\t\t\tDBName:      name.DBName,\n\t\t}\n\t\tprojNames = append(projNames, projName)\n\t\tprojSchema.Append(&expression.Column{\n\t\t\tUniqueID: cols[i].UniqueID,\n\t\t\tRetType:  cols[i].GetType(),\n\t\t\tOrigName: projName.String(),\n\t\t})\n\t\tprojExprs = append(projExprs, cols[i])\n\t}\n\tprojUponView := LogicalProjection{Exprs: projExprs}.Init(b.ctx, b.getSelectOffset())\n\tprojUponView.names = projNames\n\tprojUponView.SetChildren(selectLogicalPlan.(LogicalPlan))\n\tprojUponView.SetSchema(projSchema)\n\treturn projUponView, nil\n}\n\nfunc getInnerFromParenthesesAndUnaryPlus(expr ast.ExprNode) ast.ExprNode {\n\tif pexpr, ok := expr.(*ast.ParenthesesExpr); ok {\n\t\treturn getInnerFromParenthesesAndUnaryPlus(pexpr.Expr)\n\t}\n\tif uexpr, ok := expr.(*ast.UnaryOperationExpr); ok && uexpr.Op == opcode.Plus {\n\t\treturn getInnerFromParenthesesAndUnaryPlus(uexpr.V)\n\t}\n\treturn expr\n}\n\n// buildProjectionFieldNameFromColumns builds the field name, table name and database name when field expression is a column reference.\nfunc (b *PlanBuilder) buildProjectionFieldNameFromColumns(\n\torigField *ast.SelectField, colNameField *ast.ColumnNameExpr,\n\tname *types.FieldName) (\n\tcolName, origColName, tblName, origTblName, dbName model.CIStr) {\n\torigTblName, origColName, dbName = name.OrigTblName, name.OrigColName, name.DBName\n\tif origField.AsName.L == \"\" {\n\t\tcolName = colNameField.Name.Name\n\t} else {\n\t\tcolName = origField.AsName\n\t}\n\tif tblName.L == \"\" {\n\t\ttblName = name.TblName\n\t} else {\n\t\ttblName = colNameField.Name.Table\n\t}\n\treturn\n}\n\n// buildProjectionField builds the field object according to SelectField in\n// projection.\nfunc (b *PlanBuilder) buildProjectionField(\n\tctx context.Context, p LogicalPlan, field *ast.SelectField,\n\texpr expression.Expression) (\n\t*expression.Column, *types.FieldName, error) {\n\tvar origTblName, tblName, origColName, colName, dbName model.CIStr\n\tinnerNode := getInnerFromParenthesesAndUnaryPlus(field.Expr)\n\tcol, isCol := expr.(*expression.Column)\n\t// Correlated column won't affect the final output names. So we can put\n\t// it in any of the three logic block.\n\t// Don't put it into the first block just for simplifying the codes.\n\tif colNameField, ok := innerNode.(*ast.ColumnNameExpr); ok && isCol {\n\t\t// Field is a column reference.\n\t\tidx := p.Schema().ColumnIndex(col)\n\t\tvar name *types.FieldName\n\t\t// The column maybe the one from join's redundant part.\n\t\t// TODO: Fully support USING/NATURAL JOIN, refactor here.\n\t\tif idx == -1 {\n\t\t\tif join, ok := p.(*LogicalJoin); ok {\n\t\t\t\tidx = join.redundantSchema.ColumnIndex(col)\n\t\t\t\tname = join.redundantNames[idx]\n\t\t\t}\n\t\t} else {\n\t\t\tname = p.OutputNames()[idx]\n\t\t}\n\t\tcolName, origColName, tblName, origTblName, dbName =\n\t\t\tb.buildProjectionFieldNameFromColumns(\n\t\t\t\tfield, colNameField, name)\n\t} else if field.AsName.L != \"\" {\n\t\t// Field has alias.\n\t\tcolName = field.AsName\n\t}\n\tname := &types.FieldName{\n\t\tTblName:     tblName,\n\t\tOrigTblName: origTblName,\n\t\tColName:     colName,\n\t\tOrigColName: origColName,\n\t\tDBName:      dbName,\n\t}\n\tif isCol {\n\t\treturn col, name, nil\n\t}\n\tnewCol := &expression.Column{\n\t\tUniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\tRetType:  expr.GetType(),\n\t}\n\treturn newCol, name, nil\n}\n\n// buildProjection returns a Projection plan and non-aux columns length.\nfunc (b *PlanBuilder) buildProjection(\n\tctx context.Context, p LogicalPlan, fields []*ast.SelectField, mapper map[*ast.AggregateFuncExpr]int, windowMapper map[*ast.WindowFuncExpr]int, considerWindow bool) (LogicalPlan, int, error) {\n\tb.optFlag |= flagEliminateProjection\n\tb.curClause = fieldList\n\tproj := LogicalProjection{\n\t\tExprs: make([]expression.Expression, 0, len(fields))}.Init(\n\t\tb.ctx, b.getSelectOffset())\n\tschema := expression.NewSchema(\n\t\tmake([]*expression.Column, 0, len(fields))...)\n\toldLen := 0\n\tnewNames := make([]*types.FieldName, 0, len(fields))\n\tfor i, field := range fields {\n\t\tif !field.Auxiliary {\n\t\t\toldLen++\n\t\t}\n\t\tisWindowFuncField := ast.HasWindowFlag(field.Expr)\n\t\t// Although window functions occurs in the select fields, but it has to be processed after having clause.\n\t\t// So when we build the projection for select fields, we need to skip the window function.\n\t\t// When `considerWindow` is false, we will only build fields for non-window functions, so we add fake placeholders.\n\t\t// for window functions. These fake placeholders will be erased in column pruning.\n\t\t// When `considerWindow` is true, all the non-window fields have been built, so we just use the schema columns.\n\t\tif considerWindow && !isWindowFuncField {\n\t\t\tcol := p.Schema().Columns[i]\n\t\t\tproj.Exprs = append(proj.Exprs, col)\n\t\t\tschema.Append(col)\n\t\t\tnewNames = append(newNames, p.OutputNames()[i])\n\t\t\tcontinue\n\t\t} else if !considerWindow && isWindowFuncField {\n\t\t\texpr := expression.Zero\n\t\t\tproj.Exprs = append(proj.Exprs, expr)\n\t\t\tcol, name, err := b.buildProjectionField(ctx, p, field, expr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, 0, err\n\t\t\t}\n\t\t\tschema.Append(col)\n\t\t\tnewNames = append(newNames, name)\n\t\t\tcontinue\n\t\t}\n\n\t\tnewExpr, np, err := b.rewriteWithPreprocess(ctx, field.Expr, p, mapper, windowMapper, true)\n\t\tif err != nil {\n\t\t\treturn nil, 0, err\n\t\t}\n\t\tp = np\n\t\tproj.Exprs = append(proj.Exprs, newExpr)\n\t\tcol, name, err := b.buildProjectionField(ctx, p, field, newExpr)\n\t\tif err != nil {\n\t\t\treturn nil, 0, err\n\t\t}\n\t\tschema.Append(col)\n\t\tnewNames = append(newNames, name)\n\t}\n\tproj.SetSchema(schema)\n\tproj.SetChildren(p)\n\tproj.names = newNames\n\treturn proj, oldLen, nil\n}\n\nfunc (b *PlanBuilder) buildResultSetNode(ctx context.Context, node ast.ResultSetNode) (p LogicalPlan, err error) {\n\tswitch x := node.(type) {\n\tcase *ast.Join:\n\t\treturn b.buildJoin(ctx, x)\n\tcase *ast.TableSource:\n\t\tswitch v := x.Source.(type) {\n\t\tcase *ast.SelectStmt:\n\t\t\tp, err = b.buildSelect(ctx, v) // FROM sub query\n\t\tcase *ast.UnionStmt:\n\t\t\tp, err = b.buildUnion(ctx, v)\n\t\tcase *ast.TableName:\n\t\t\tp, err = b.buildDataSource(ctx, v, &x.AsName)\n\t\tdefault:\n\t\t\terr = ErrUnsupportedType.GenWithStackByArgs(v)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfor _, name := range p.OutputNames() {\n\t\t\tif name.Hidden {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif x.AsName.L != \"\" {\n\t\t\t\tname.TblName = x.AsName\n\t\t\t}\n\t\t}\n\t\t// Duplicate column name in one table is not allowed.\n\t\t// \"select * from (select 1, 1) as a;\" is duplicate\n\t\tdupNames := make(map[string]struct{}, len(p.Schema().Columns))\n\t\tfor _, name := range p.OutputNames() {\n\t\t\tcolName := name.ColName.O\n\t\t\tif _, ok := dupNames[colName]; ok {\n\t\t\t\treturn nil, ErrDupFieldName.GenWithStackByArgs(colName)\n\t\t\t}\n\t\t\tdupNames[colName] = struct{}{}\n\t\t}\n\t\treturn p, nil\n\tcase *ast.SelectStmt:\n\t\treturn b.buildSelect(ctx, x)\n\tcase *ast.UnionStmt:\n\t\treturn b.buildUnion(ctx, x)\n\tdefault:\n\t\treturn nil, ErrUnsupportedType.GenWithStack(\"Unsupported ast.ResultSetNode(%T) for buildResultSetNode()\", x)\n\t}\n}\n\nfunc resetNotNullFlag(schema *expression.Schema, start, end int) {\n\tfor i := start; i < end; i++ {\n\t\tcol := *schema.Columns[i]\n\t\tnewFieldType := *col.RetType\n\t\tnewFieldType.Flag &= ^mysql.NotNullFlag\n\t\tcol.RetType = &newFieldType\n\t\tschema.Columns[i] = &col\n\t}\n}\n\nfunc (b *PlanBuilder) buildJoin(ctx context.Context, joinNode *ast.Join) (LogicalPlan, error) {\n\t// We will construct a \"Join\" node for some statements like \"INSERT\",\n\t// \"DELETE\", \"UPDATE\", \"REPLACE\". For this scenario \"joinNode.Right\" is nil\n\t// and we only build the left \"ResultSetNode\".\n\tif joinNode.Right == nil {\n\t\treturn b.buildResultSetNode(ctx, joinNode.Left)\n\t}\n\n\tb.optFlag = b.optFlag | flagPredicatePushDown\n\n\tleftPlan, err := b.buildResultSetNode(ctx, joinNode.Left)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trightPlan, err := b.buildResultSetNode(ctx, joinNode.Right)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tjoinPlan := LogicalJoin{}.Init(b.ctx, b.getSelectOffset())\n\tjoinPlan.SetChildren(leftPlan, rightPlan)\n\tjoinPlan.SetSchema(expression.MergeSchema(leftPlan.Schema(), rightPlan.Schema()))\n\tjoinPlan.names = make([]*types.FieldName, leftPlan.Schema().Len()+rightPlan.Schema().Len())\n\tcopy(joinPlan.names, leftPlan.OutputNames())\n\tcopy(joinPlan.names[leftPlan.Schema().Len():], rightPlan.OutputNames())\n\n\t// Set join type.\n\tswitch joinNode.Tp {\n\tcase ast.LeftJoin:\n\t\t// left outer join need to be checked elimination\n\t\tb.optFlag = b.optFlag | flagEliminateOuterJoin\n\t\tjoinPlan.JoinType = LeftOuterJoin\n\t\tresetNotNullFlag(joinPlan.schema, leftPlan.Schema().Len(), joinPlan.schema.Len())\n\tcase ast.RightJoin:\n\t\t// right outer join need to be checked elimination\n\t\tjoinPlan.JoinType = RightOuterJoin\n\t\tb.optFlag = b.optFlag | flagEliminateOuterJoin\n\t\tresetNotNullFlag(joinPlan.schema, 0, leftPlan.Schema().Len())\n\tdefault:\n\t\tb.optFlag = b.optFlag | flagJoinReOrder\n\t\tjoinPlan.JoinType = InnerJoin\n\t}\n\n\t// Merge sub join's redundantSchema into this join plan. When handle query like\n\t// select t2.a from (t1 join t2 using (a)) join t3 using (a);\n\t// we can simply search in the top level join plan to find redundant column.\n\tvar (\n\t\tlRedundantSchema, rRedundantSchema *expression.Schema\n\t\tlRedundantNames, rRedundantNames   types.NameSlice\n\t)\n\tif left, ok := leftPlan.(*LogicalJoin); ok && left.redundantSchema != nil {\n\t\tlRedundantSchema = left.redundantSchema\n\t\tlRedundantNames = left.redundantNames\n\t}\n\tif right, ok := rightPlan.(*LogicalJoin); ok && right.redundantSchema != nil {\n\t\trRedundantSchema = right.redundantSchema\n\t\trRedundantNames = right.redundantNames\n\t}\n\tjoinPlan.redundantSchema = expression.MergeSchema(lRedundantSchema, rRedundantSchema)\n\tjoinPlan.redundantNames = make([]*types.FieldName, len(lRedundantNames)+len(rRedundantNames))\n\tcopy(joinPlan.redundantNames, lRedundantNames)\n\tcopy(joinPlan.redundantNames[len(lRedundantNames):], rRedundantNames)\n\n\tif joinNode.NaturalJoin {\n\t\treturn nil, ErrUnsupportedType.GenWithStackByArgs(joinNode.NaturalJoin)\n\t\t//err = b.buildNaturalJoin(joinPlan, leftPlan, rightPlan, joinNode)\n\t\t//if err != nil {\n\t\t//\treturn nil, err\n\t\t//}\n\t} else if joinNode.Using != nil {\n\t\treturn nil, ErrUnsupportedType.GenWithStackByArgs(joinNode.Using)\n\t\t//err = b.buildUsingClause(joinPlan, leftPlan, rightPlan, joinNode)\n\t\t//if err != nil {\n\t\t//\treturn nil, err\n\t\t//}\n\t} else if joinNode.On != nil {\n\t\tb.curClause = onClause\n\t\tonExpr, newPlan, err := b.rewrite(ctx, joinNode.On.Expr, joinPlan, nil, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif newPlan != joinPlan {\n\t\t\treturn nil, errors.New(\"ON condition doesn't support subqueries yet\")\n\t\t}\n\t\tonCondition := expression.SplitCNFItems(onExpr)\n\t\tjoinPlan.AttachOnConds(onCondition)\n\t} else if joinPlan.JoinType == InnerJoin {\n\t\t// If a inner join without \"ON\" or \"USING\" clause, it's a cartesian\n\t\t// product over the join tables.\n\t\tjoinPlan.cartesianJoin = true\n\t} else {\n\t\tpanic(\"unexpected branch\")\n\t}\n\n\treturn joinPlan, nil\n}\n\nfunc (b *PlanBuilder) resolveGbyExprs(\n\tctx context.Context,\n\tp LogicalPlan,\n\tgby *ast.GroupByClause,\n\tfields []*ast.SelectField) (LogicalPlan, []expression.Expression, error) {\n\tb.curClause = groupByClause\n\texprs := make([]expression.Expression, 0, len(gby.Items))\n\tresolver := &gbyResolver{\n\t\tctx:    b.ctx,\n\t\tfields: fields,\n\t\tschema: p.Schema(),\n\t\tnames:  p.OutputNames(),\n\t}\n\tfor _, item := range gby.Items {\n\t\tresolver.inExpr = false\n\t\tretExpr, _ := item.Expr.Accept(resolver)\n\t\tif resolver.err != nil {\n\t\t\treturn nil, nil, errors.Trace(resolver.err)\n\t\t}\n\t\tif !resolver.isParam {\n\t\t\titem.Expr = retExpr.(ast.ExprNode)\n\t\t}\n\n\t\titemExpr := retExpr.(ast.ExprNode)\n\t\texpr, np, err := b.rewrite(ctx, itemExpr, p, nil, true)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\texprs = append(exprs, expr)\n\t\tp = np\n\t}\n\treturn p, exprs, nil\n}\n\nfunc (b *PlanBuilder) unfoldWildStar(\n\tp LogicalPlan, selectFields []*ast.SelectField) (\n\tresultList []*ast.SelectField, err error) {\n\tfor i, field := range selectFields {\n\t\tif field.WildCard == nil {\n\t\t\tresultList = append(resultList, field)\n\t\t\tcontinue\n\t\t}\n\t\tif field.WildCard.Table.L == \"\" && i > 0 {\n\t\t\treturn nil, ErrInvalidWildCard\n\t\t}\n\t\tdbName := field.WildCard.Schema\n\t\ttblName := field.WildCard.Table\n\t\tfindTblNameInSchema := false\n\t\tfor i, name := range p.OutputNames() {\n\t\t\tcol := p.Schema().Columns[i]\n\t\t\tif (dbName.L == \"\" || dbName.L == name.DBName.L) &&\n\t\t\t\t(tblName.L == \"\" || tblName.L == name.TblName.L) &&\n\t\t\t\tcol.ID != model.ExtraHandleID {\n\t\t\t\tfindTblNameInSchema = true\n\t\t\t\tcolName := &ast.ColumnNameExpr{\n\t\t\t\t\tName: &ast.ColumnName{\n\t\t\t\t\t\tSchema: name.DBName,\n\t\t\t\t\t\tTable:  name.TblName,\n\t\t\t\t\t\tName:   name.ColName,\n\t\t\t\t\t}}\n\t\t\t\tcolName.SetType(col.GetType())\n\t\t\t\tfield := &ast.SelectField{Expr: colName}\n\t\t\t\tfield.SetText(name.ColName.O)\n\t\t\t\tresultList = append(resultList, field)\n\t\t\t}\n\t\t}\n\t\tif !findTblNameInSchema {\n\t\t\treturn nil, ErrBadTable.GenWithStackByArgs(tblName)\n\t\t}\n\t}\n\treturn resultList, nil\n}\n\nfunc (p *LogicalJoin) extractOnCondition(conditions []expression.Expression, deriveLeft bool,\n\tderiveRight bool) (eqCond []*expression.ScalarFunction, leftCond []expression.Expression,\n\trightCond []expression.Expression, otherCond []expression.Expression) {\n\treturn p.ExtractOnCondition(conditions, p.Children()[0].Schema(), p.Children()[1].Schema(), deriveLeft, deriveRight)\n}\n\n// ExtractOnCondition divide conditions in CNF of join node into 4 groups.\n// These conditions can be where conditions, join conditions, or collection of both.\n// If deriveLeft/deriveRight is set, we would try to derive more conditions for left/right plan.\nfunc (p *LogicalJoin) ExtractOnCondition(\n\tconditions []expression.Expression,\n\tleftSchema *expression.Schema,\n\trightSchema *expression.Schema,\n\tderiveLeft bool,\n\tderiveRight bool) (eqCond []*expression.ScalarFunction, leftCond []expression.Expression,\n\trightCond []expression.Expression, otherCond []expression.Expression) {\n\tfor _, expr := range conditions {\n\t\tbinop, ok := expr.(*expression.ScalarFunction)\n\t\tif ok && len(binop.GetArgs()) == 2 {\n\t\t\tctx := binop.GetCtx()\n\t\t\targ0, lOK := binop.GetArgs()[0].(*expression.Column)\n\t\t\targ1, rOK := binop.GetArgs()[1].(*expression.Column)\n\t\t\tif lOK && rOK {\n\t\t\t\tleftCol := leftSchema.RetrieveColumn(arg0)\n\t\t\t\trightCol := rightSchema.RetrieveColumn(arg1)\n\t\t\t\tif leftCol == nil || rightCol == nil {\n\t\t\t\t\tleftCol = leftSchema.RetrieveColumn(arg1)\n\t\t\t\t\trightCol = rightSchema.RetrieveColumn(arg0)\n\t\t\t\t\targ0, arg1 = arg1, arg0\n\t\t\t\t}\n\t\t\t\tif leftCol != nil && rightCol != nil {\n\t\t\t\t\t/* TODO(yang.y): the following Null check logic is not needed\n\t\t\t\t\tif deriveLeft {\n\t\t\t\t\t\tif isNullRejected(ctx, leftSchema, expr) && !mysql.HasNotNullFlag(leftCol.RetType.Flag) {\n\t\t\t\t\t\t\tnotNullExpr := expression.BuildNotNullExpr(ctx, leftCol)\n\t\t\t\t\t\t\tleftCond = append(leftCond, notNullExpr)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif deriveRight {\n\t\t\t\t\t\tif isNullRejected(ctx, rightSchema, expr) && !mysql.HasNotNullFlag(rightCol.RetType.Flag) {\n\t\t\t\t\t\t\tnotNullExpr := expression.BuildNotNullExpr(ctx, rightCol)\n\t\t\t\t\t\t\trightCond = append(rightCond, notNullExpr)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t*/\n\t\t\t\t\t// For queries like `select a in (select a from s where s.b = t.b) from t`,\n\t\t\t\t\t// if subquery is empty caused by `s.b = t.b`, the result should always be\n\t\t\t\t\t// false even if t.a is null or s.a is null. To make this join \"empty aware\",\n\t\t\t\t\t// we should differentiate `t.a = s.a` from other column equal conditions, so\n\t\t\t\t\t// we put it into OtherConditions instead of EqualConditions of join.\n\t\t\t\t\tif binop.FuncName.L == ast.EQ && !arg0.InOperand && !arg1.InOperand {\n\t\t\t\t\t\tcond := expression.NewFunctionInternal(ctx, ast.EQ, types.NewFieldType(mysql.TypeTiny), arg0, arg1)\n\t\t\t\t\t\teqCond = append(eqCond, cond.(*expression.ScalarFunction))\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcolumns := expression.ExtractColumns(expr)\n\t\t// `columns` may be empty, if the condition is like `correlated_column op constant`, or `constant`,\n\t\t// push this kind of constant condition down according to join type.\n\t\tif len(columns) == 0 {\n\t\t\tleftCond, rightCond = p.pushDownConstExpr(expr, leftCond, rightCond, deriveLeft || deriveRight)\n\t\t\tcontinue\n\t\t}\n\t\tallFromLeft, allFromRight := true, true\n\t\tfor _, col := range columns {\n\t\t\tif !leftSchema.Contains(col) {\n\t\t\t\tallFromLeft = false\n\t\t\t}\n\t\t\tif !rightSchema.Contains(col) {\n\t\t\t\tallFromRight = false\n\t\t\t}\n\t\t}\n\t\tif allFromRight {\n\t\t\trightCond = append(rightCond, expr)\n\t\t} else if allFromLeft {\n\t\t\tleftCond = append(leftCond, expr)\n\t\t} else {\n\t\t\t/* TODO(yang.y): we skip further optimization on rewriting the expression\n\t\t\t// Relax expr to two supersets: leftRelaxedCond and rightRelaxedCond, the expression now is\n\t\t\t// `expr AND leftRelaxedCond AND rightRelaxedCond`. Motivation is to push filters down to\n\t\t\t// children as much as possible.\n\t\t\tif deriveLeft {\n\t\t\t\tleftRelaxedCond := expression.DeriveRelaxedFiltersFromDNF(expr, leftSchema)\n\t\t\t\tif leftRelaxedCond != nil {\n\t\t\t\t\tleftCond = append(leftCond, leftRelaxedCond)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif deriveRight {\n\t\t\t\trightRelaxedCond := expression.DeriveRelaxedFiltersFromDNF(expr, rightSchema)\n\t\t\t\tif rightRelaxedCond != nil {\n\t\t\t\t\trightCond = append(rightCond, rightRelaxedCond)\n\t\t\t\t}\n\t\t\t}\n\t\t\t*/\n\t\t\totherCond = append(otherCond, expr)\n\t\t}\n\t}\n\treturn\n}\n\nfunc (b *PlanBuilder) buildSelect(\n\tctx context.Context, sel *ast.SelectStmt) (p LogicalPlan, err error) {\n\tb.pushSelectOffset(sel.QueryBlockOffset)\n\tdefer func() {\n\t\tb.popSelectOffset()\n\t\tif err == nil && sel.SelectIntoOpt != nil && p != nil {\n\t\t\tpartyColumns := make(map[string][]*expression.Column)\n\t\t\tfor _, partyFile := range sel.SelectIntoOpt.PartyFiles {\n\t\t\t\tif len(partyFile.FieldList) == 0 {\n\t\t\t\t\tcontinue // default empty list means select all columns in select field\n\t\t\t\t}\n\n\t\t\t\tcolumns, deferErr := b.resolveSelectIntoColumns(ctx, p, partyFile.FieldList)\n\t\t\t\tif deferErr != nil {\n\t\t\t\t\terr = deferErr // NOTE: set err with deferErr\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tpartyColumns[partyFile.PartyCode] = columns\n\t\t\t}\n\n\t\t\tp.SetIntoOpt(sel.SelectIntoOpt, partyColumns)\n\t\t}\n\t}()\n\tvar (\n\t\taggFuncs                      []*ast.AggregateFuncExpr\n\t\thavingMap, orderMap, totalMap map[*ast.AggregateFuncExpr]int\n\t\tgbyCols                       []expression.Expression\n\t\twindowAggMap                  map[*ast.AggregateFuncExpr]int\n\t)\n\n\tif sel.From == nil {\n\t\treturn nil, fmt.Errorf(\"buildSelect: empty from clause\")\n\t}\n\tp, err = b.buildResultSetNode(ctx, sel.From.TableRefs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\toriginalFields := sel.Fields.Fields\n\tsel.Fields.Fields, err = b.unfoldWildStar(p, sel.Fields.Fields)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif sel.SelectIntoOpt != nil {\n\t\tfor _, partyFile := range sel.SelectIntoOpt.PartyFiles {\n\t\t\tif len(partyFile.FieldList) == 0 {\n\t\t\t\tcontinue // default empty list means select all columns in select field\n\t\t\t}\n\t\t\tpartyFile.FieldList, err = b.unfoldWildStar(p, partyFile.FieldList)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"buildSelect: %v\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif sel.GroupBy != nil {\n\t\tp, gbyCols, err = b.resolveGbyExprs(ctx, p, sel.GroupBy, sel.Fields.Fields)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\thasWindowFuncField := b.detectSelectWindow(sel)\n\tif hasWindowFuncField {\n\t\twindowAggMap, err = b.resolveWindowFunction(sel, p)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// We must resolve order by clause before build projection,\n\t// because when the query is \"select a+1 as b from t order by b\", we must replace b to a+1,\n\t// which only can be done before building projection and extracting Agg functions.\n\thavingMap, orderMap, err = b.resolveHavingAndOrderBy(sel, p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif sel.Where != nil {\n\t\tp, err = b.buildSelection(ctx, p, sel.Where, nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\thasAgg := b.detectSelectAgg(sel)\n\tif hasAgg {\n\t\taggFuncs, totalMap = b.extractAggFuncs(sel.Fields.Fields)\n\t\tvar aggIndexMap map[int]int\n\t\tp, aggIndexMap, err = b.buildAggregation(ctx, p, aggFuncs, gbyCols)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor k, v := range totalMap {\n\t\t\ttotalMap[k] = aggIndexMap[v]\n\t\t}\n\t}\n\tvar oldLen int\n\tp, oldLen, err = b.buildProjection(ctx, p, sel.Fields.Fields, totalMap, nil, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif sel.Having != nil {\n\t\tb.curClause = havingClause\n\t\tp, err = b.buildSelection(ctx, p, sel.Having.Expr, havingMap)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tvar windowMapper map[*ast.WindowFuncExpr]int\n\tif hasWindowFuncField {\n\t\twindowFuncs := extractWindowFuncs(sel.Fields.Fields)\n\t\t// we need to check the func args first before we check the window spec\n\t\terr := b.checkWindowFuncArgs(ctx, p, windowFuncs, windowAggMap)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tgroupedFuncs, err := b.groupWindowFuncs(windowFuncs)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tp, windowMapper, err = b.buildWindowFunctions(ctx, p, groupedFuncs, windowAggMap)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// Now we build the window function fields.\n\t\tp, oldLen, err = b.buildProjection(ctx, p, sel.Fields.Fields, windowAggMap, windowMapper, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif sel.Distinct {\n\t\tp, err = b.buildDistinct(p, oldLen)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif sel.OrderBy != nil {\n\t\tp, err = b.buildSort(ctx, p, sel.OrderBy.Items, orderMap, windowMapper)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif sel.Limit != nil {\n\t\tp, err = b.buildLimit(p, sel.Limit)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tsel.Fields.Fields = originalFields\n\tif oldLen != p.Schema().Len() {\n\t\tproj := LogicalProjection{\n\t\t\tExprs: expression.Column2Exprs(p.Schema().Columns[:oldLen]),\n\t\t}.Init(b.ctx, b.getSelectOffset())\n\t\tproj.SetChildren(p)\n\t\tschema := expression.NewSchema(p.Schema().Clone().Columns[:oldLen]...)\n\t\tfor _, col := range schema.Columns {\n\t\t\tcol.UniqueID = b.ctx.GetSessionVars().AllocPlanColumnID()\n\t\t}\n\t\tproj.names = p.OutputNames()[:oldLen]\n\t\tproj.SetSchema(schema)\n\t\treturn proj, nil\n\t}\n\n\treturn p, nil\n}\n\ntype windowFuncs struct {\n\tspec  *ast.WindowSpec\n\tfuncs []*ast.WindowFuncExpr\n}\n\n// sortWindowSpecs sorts the window specifications by reversed alphabetical order, then we could add less `Sort` operator\n// in physical plan because the window functions with the same partition by and order by clause will be at near places.\nfunc sortWindowSpecs(groupedFuncs map[*ast.WindowSpec][]*ast.WindowFuncExpr) []windowFuncs {\n\twindows := make([]windowFuncs, 0, len(groupedFuncs))\n\tfor spec, funcs := range groupedFuncs {\n\t\twindows = append(windows, windowFuncs{spec, funcs})\n\t}\n\tlItemsBuf := make([]*ast.ByItem, 0, 4)\n\trItemsBuf := make([]*ast.ByItem, 0, 4)\n\tsort.SliceStable(windows, func(i, j int) bool {\n\t\t// here is to make the order of window functions with the same partition by and order by clause consistent.\n\t\tl := windows[i].funcs[0].F\n\t\tr := windows[j].funcs[0].F\n\t\tif l != r {\n\t\t\treturn cmp.Compare(l, r) > 0\n\t\t}\n\t\tlItemsBuf = getAllByItems(lItemsBuf, windows[i].spec)\n\t\trItemsBuf = getAllByItems(rItemsBuf, windows[j].spec)\n\t\treturn !compareItems(lItemsBuf, rItemsBuf)\n\t})\n\treturn windows\n}\n\nfunc compareItems(lItems []*ast.ByItem, rItems []*ast.ByItem) bool {\n\tminLen := mathutil.Min(len(lItems), len(rItems))\n\tfor i := 0; i < minLen; i++ {\n\t\tres := strings.Compare(restoreByItemText(lItems[i]), restoreByItemText(rItems[i]))\n\t\tif res != 0 {\n\t\t\treturn res < 0\n\t\t}\n\t\tres = compareBool(lItems[i].Desc, rItems[i].Desc)\n\t\tif res != 0 {\n\t\t\treturn res < 0\n\t\t}\n\t}\n\treturn len(lItems) < len(rItems)\n}\n\nfunc compareBool(l, r bool) int {\n\tif l == r {\n\t\treturn 0\n\t}\n\tif !l {\n\t\treturn -1\n\t}\n\treturn 1\n}\n\nfunc restoreByItemText(item *ast.ByItem) string {\n\tvar sb strings.Builder\n\tctx := format.NewRestoreCtx(0, &sb)\n\terr := item.Expr.Restore(ctx)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn sb.String()\n}\n\nfunc getAllByItems(itemsBuf []*ast.ByItem, spec *ast.WindowSpec) []*ast.ByItem {\n\titemsBuf = itemsBuf[:0]\n\tif spec.PartitionBy != nil {\n\t\titemsBuf = append(itemsBuf, spec.PartitionBy.Items...)\n\t}\n\tif spec.OrderBy != nil {\n\t\titemsBuf = append(itemsBuf, spec.OrderBy.Items...)\n\t}\n\treturn itemsBuf\n}\n\nfunc (b *PlanBuilder) buildByItemsForWindow(\n\tctx context.Context,\n\tp LogicalPlan,\n\tproj *LogicalProjection,\n\titems []*ast.ByItem,\n\tretItems []property.Item,\n\taggMap map[*ast.AggregateFuncExpr]int,\n) (LogicalPlan, []property.Item, error) {\n\ttransformer := &itemTransformer{}\n\tfor _, item := range items {\n\t\tnewExpr, _ := item.Expr.Accept(transformer)\n\t\titem.Expr = newExpr.(ast.ExprNode)\n\t\tit, np, err := b.rewrite(ctx, item.Expr, p, aggMap, true)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tp = np\n\t\tif it.GetType().Tp == mysql.TypeNull {\n\t\t\tcontinue\n\t\t}\n\t\tif col, ok := it.(*expression.Column); ok {\n\t\t\tretItems = append(retItems, property.Item{Col: col, Desc: item.Desc})\n\t\t\tcontinue\n\t\t}\n\t\tproj.Exprs = append(proj.Exprs, it)\n\t\tproj.names = append(proj.names, types.EmptyName)\n\t\tcol := &expression.Column{\n\t\t\tUniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t\tRetType:  it.GetType(),\n\t\t}\n\t\tproj.schema.Append(col)\n\t\tretItems = append(retItems, property.Item{Col: col, Desc: item.Desc})\n\t}\n\treturn p, retItems, nil\n}\n\n// itemTransformer transforms ParamMarkerExpr to PositionExpr in the context of ByItem\ntype itemTransformer struct {\n}\n\nfunc (t *itemTransformer) Enter(inNode ast.Node) (ast.Node, bool) {\n\tswitch n := inNode.(type) {\n\tcase *driver.ParamMarkerExpr:\n\t\tnewNode := expression.ConstructPositionExpr(n)\n\t\treturn newNode, true\n\t}\n\treturn inNode, false\n}\n\nfunc (t *itemTransformer) Leave(inNode ast.Node) (ast.Node, bool) {\n\treturn inNode, false\n}\n\n// buildProjectionForWindow builds the projection for expressions in the window specification that is not an column,\n// so after the projection, window functions only needs to deal with columns.\nfunc (b *PlanBuilder) buildProjectionForWindow(ctx context.Context, p LogicalPlan, spec *ast.WindowSpec, args []ast.ExprNode, aggMap map[*ast.AggregateFuncExpr]int) (LogicalPlan, []property.Item, []property.Item, []expression.Expression, error) {\n\tb.optFlag |= flagEliminateProjection\n\n\tvar partitionItems, orderItems []*ast.ByItem\n\tif spec.PartitionBy != nil {\n\t\tpartitionItems = spec.PartitionBy.Items\n\t}\n\tif spec.OrderBy != nil {\n\t\torderItems = spec.OrderBy.Items\n\t}\n\n\tprojLen := len(p.Schema().Columns) + len(partitionItems) + len(orderItems) + len(args)\n\tproj := LogicalProjection{Exprs: make([]expression.Expression, 0, projLen)}.Init(b.ctx, b.getSelectOffset())\n\tproj.SetSchema(expression.NewSchema(make([]*expression.Column, 0, projLen)...))\n\tproj.names = make([]*types.FieldName, p.Schema().Len(), projLen)\n\tfor _, col := range p.Schema().Columns {\n\t\tproj.Exprs = append(proj.Exprs, col)\n\t\tproj.schema.Append(col)\n\t}\n\tcopy(proj.names, p.OutputNames())\n\n\tpropertyItems := make([]property.Item, 0, len(partitionItems)+len(orderItems))\n\tvar err error\n\tp, propertyItems, err = b.buildByItemsForWindow(ctx, p, proj, partitionItems, propertyItems, aggMap)\n\tif err != nil {\n\t\treturn nil, nil, nil, nil, err\n\t}\n\tlenPartition := len(propertyItems)\n\tp, propertyItems, err = b.buildByItemsForWindow(ctx, p, proj, orderItems, propertyItems, aggMap)\n\tif err != nil {\n\t\treturn nil, nil, nil, nil, err\n\t}\n\n\tnewArgList := make([]expression.Expression, 0, len(args))\n\tfor _, arg := range args {\n\t\tnewArg, np, err := b.rewrite(ctx, arg, p, aggMap, true)\n\t\tif err != nil {\n\t\t\treturn nil, nil, nil, nil, err\n\t\t}\n\t\tp = np\n\t\tswitch newArg.(type) {\n\t\tcase *expression.Column, *expression.Constant:\n\t\t\tnewArgList = append(newArgList, newArg)\n\t\t\tcontinue\n\t\t}\n\t\tproj.Exprs = append(proj.Exprs, newArg)\n\t\tproj.names = append(proj.names, types.EmptyName)\n\t\tcol := &expression.Column{\n\t\t\tUniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t\tRetType:  newArg.GetType(),\n\t\t}\n\t\tproj.schema.Append(col)\n\t\tnewArgList = append(newArgList, col)\n\t}\n\n\tproj.SetChildren(p)\n\treturn proj, propertyItems[:lenPartition], propertyItems[lenPartition:], newArgList, nil\n}\n\n// checkOriginWindowSpecs checks the validation for origin window specifications for a group of functions.\n// Because of the grouped specification is different from it, we should especially check them before build window frame.\nfunc (b *PlanBuilder) checkOriginWindowSpecs(funcs []*ast.WindowFuncExpr, orderByItems []property.Item) error {\n\tfor _, f := range funcs {\n\t\tif f.IgnoreNull {\n\t\t\treturn ErrNotSupportedYet.GenWithStackByArgs(\"IGNORE NULLS\")\n\t\t}\n\t\tif f.Distinct {\n\t\t\treturn ErrNotSupportedYet.GenWithStackByArgs(\"<window function>(DISTINCT ..)\")\n\t\t}\n\t\tif f.FromLast {\n\t\t\treturn ErrNotSupportedYet.GenWithStackByArgs(\"FROM LAST\")\n\t\t}\n\t\tspec := &f.Spec\n\t\tif f.Spec.Name.L != \"\" {\n\t\t\tspec = b.windowSpecs[f.Spec.Name.L]\n\t\t}\n\t\tif spec.Frame == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif spec.Frame.Type == ast.Groups {\n\t\t\treturn ErrNotSupportedYet.GenWithStackByArgs(\"GROUPS\")\n\t\t}\n\t\tstart, end := spec.Frame.Extent.Start, spec.Frame.Extent.End\n\t\tif start.Type == ast.Following && start.UnBounded {\n\t\t\treturn ErrWindowFrameStartIllegal.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t\t}\n\t\tif end.Type == ast.Preceding && end.UnBounded {\n\t\t\treturn ErrWindowFrameEndIllegal.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t\t}\n\t\tif start.Type == ast.Following && (end.Type == ast.Preceding || end.Type == ast.CurrentRow) {\n\t\t\treturn ErrWindowFrameIllegal.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t\t}\n\t\tif (start.Type == ast.Following || start.Type == ast.CurrentRow) && end.Type == ast.Preceding {\n\t\t\treturn ErrWindowFrameIllegal.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t\t}\n\n\t\terr := b.checkOriginWindowFrameBound(&start, spec, orderByItems)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = b.checkOriginWindowFrameBound(&end, spec, orderByItems)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (b *PlanBuilder) checkOriginWindowFrameBound(bound *ast.FrameBound, spec *ast.WindowSpec, orderByItems []property.Item) error {\n\tif bound.Type == ast.CurrentRow || bound.UnBounded {\n\t\treturn nil\n\t}\n\n\tframeType := spec.Frame.Type\n\tif frameType == ast.Rows {\n\t\tif bound.Unit != ast.TimeUnitInvalid {\n\t\t\treturn ErrWindowRowsIntervalUse.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t\t}\n\t\t_, isNull, isExpectedType := getUintFromNode(b.ctx, bound.Expr)\n\t\tif isNull || !isExpectedType {\n\t\t\treturn ErrWindowFrameIllegal.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t\t}\n\t\treturn nil\n\t}\n\n\tif len(orderByItems) != 1 {\n\t\treturn ErrWindowRangeFrameOrderType.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t}\n\torderItemType := orderByItems[0].Col.RetType.Tp\n\tisNumeric, isTemporal := types.IsTypeNumeric(orderItemType), types.IsTypeTemporal(orderItemType)\n\tif !isNumeric && !isTemporal {\n\t\treturn ErrWindowRangeFrameOrderType.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t}\n\tif bound.Unit != ast.TimeUnitInvalid && !isTemporal {\n\t\treturn ErrWindowRangeFrameNumericType.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t}\n\tif bound.Unit == ast.TimeUnitInvalid && !isNumeric {\n\t\treturn ErrWindowRangeFrameTemporalType.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t}\n\treturn nil\n}\n\n// paramMarkerInPrepareChecker checks whether the given ast tree has paramMarker and is in prepare statement.\ntype paramMarkerInPrepareChecker struct {\n\tinPrepareStmt bool\n}\n\n// Enter implements Visitor Interface.\nfunc (pc *paramMarkerInPrepareChecker) Enter(in ast.Node) (out ast.Node, skipChildren bool) {\n\tswitch v := in.(type) {\n\tcase *driver.ParamMarkerExpr:\n\t\tpc.inPrepareStmt = !v.InExecute\n\t\treturn v, true\n\t}\n\treturn in, false\n}\n\n// Leave implements Visitor Interface.\nfunc (pc *paramMarkerInPrepareChecker) Leave(in ast.Node) (out ast.Node, ok bool) {\n\treturn in, true\n}\n\n// buildWindowFunctionFrameBound builds the bounds of window function frames.\n// For type `Rows`, the bound expr must be an unsigned integer.\n// For type `Range`, the bound expr must be temporal or numeric types.\nfunc (b *PlanBuilder) buildWindowFunctionFrameBound(ctx context.Context, spec *ast.WindowSpec, orderByItems []property.Item, boundClause *ast.FrameBound) (*FrameBound, error) {\n\tframeType := spec.Frame.Type\n\tbound := &FrameBound{Type: boundClause.Type, UnBounded: boundClause.UnBounded}\n\tif bound.UnBounded {\n\t\treturn bound, nil\n\t}\n\n\tif frameType == ast.Rows {\n\t\tif bound.Type == ast.CurrentRow {\n\t\t\treturn bound, nil\n\t\t}\n\t\tnumRows, _, _ := getUintFromNode(b.ctx, boundClause.Expr)\n\t\tbound.Num = numRows\n\t\treturn bound, nil\n\t}\n\n\tbound.CalcFuncs = make([]expression.Expression, len(orderByItems))\n\tbound.CmpFuncs = make([]expression.CompareFunc, len(orderByItems))\n\tif bound.Type == ast.CurrentRow {\n\t\tfor i, item := range orderByItems {\n\t\t\tcol := item.Col\n\t\t\tbound.CalcFuncs[i] = col\n\t\t\tbound.CmpFuncs[i] = expression.GetCmpFunction(col, col)\n\t\t}\n\t\treturn bound, nil\n\t}\n\n\tcol := orderByItems[0].Col\n\t// TODO: We also need to raise error for non-deterministic expressions, like rand().\n\tval, err := evalAstExpr(b.ctx, boundClause.Expr)\n\tif err != nil {\n\t\treturn nil, ErrWindowRangeBoundNotConstant.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t}\n\texpr := expression.Constant{Value: val, RetType: boundClause.Expr.GetType()}\n\n\tchecker := &paramMarkerInPrepareChecker{}\n\tboundClause.Expr.Accept(checker)\n\n\t// If it has paramMarker and is in prepare stmt. We don't need to eval it since its value is not decided yet.\n\tif !checker.inPrepareStmt {\n\t\t// Do not raise warnings for truncate.\n\t\toriIgnoreTruncate := b.ctx.GetSessionVars().StmtCtx.IgnoreTruncate\n\t\tb.ctx.GetSessionVars().StmtCtx.IgnoreTruncate = true\n\t\tuVal, isNull, err := expr.EvalInt(b.ctx, chunk.Row{})\n\t\tb.ctx.GetSessionVars().StmtCtx.IgnoreTruncate = oriIgnoreTruncate\n\t\tif uVal < 0 || isNull || err != nil {\n\t\t\treturn nil, ErrWindowFrameIllegal.GenWithStackByArgs(getWindowName(spec.Name.O))\n\t\t}\n\t}\n\n\tdesc := orderByItems[0].Desc\n\tif boundClause.Unit != ast.TimeUnitInvalid {\n\t\t// TODO: Perhaps we don't need to transcode this back to generic string\n\t\tunitVal := boundClause.Unit.String()\n\t\tunit := expression.Constant{\n\t\t\tValue:   types.NewStringDatum(unitVal),\n\t\t\tRetType: types.NewFieldType(mysql.TypeVarchar),\n\t\t}\n\n\t\t// When the order is asc:\n\t\t//   `+` for following, and `-` for the preceding\n\t\t// When the order is desc, `+` becomes `-` and vice-versa.\n\t\tfuncName := ast.DateAdd\n\t\tif (!desc && bound.Type == ast.Preceding) || (desc && bound.Type == ast.Following) {\n\t\t\tfuncName = ast.DateSub\n\t\t}\n\t\tbound.CalcFuncs[0], err = expression.NewFunctionBase(b.ctx, funcName, col.RetType, col, &expr, &unit)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tbound.CmpFuncs[0] = expression.GetCmpFunction(orderByItems[0].Col, bound.CalcFuncs[0])\n\t\treturn bound, nil\n\t}\n\t// When the order is asc:\n\t//   `+` for following, and `-` for the preceding\n\t// When the order is desc, `+` becomes `-` and vice-versa.\n\tfuncName := ast.Plus\n\tif (!desc && bound.Type == ast.Preceding) || (desc && bound.Type == ast.Following) {\n\t\tfuncName = ast.Minus\n\t}\n\tbound.CalcFuncs[0], err = expression.NewFunctionBase(b.ctx, funcName, col.RetType, col, &expr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbound.CmpFuncs[0] = expression.GetCmpFunction(orderByItems[0].Col, bound.CalcFuncs[0])\n\treturn bound, nil\n}\n\n// buildWindowFunctionFrame builds the window function frames.\n// See https://dev.mysql.com/doc/refman/8.0/en/window-functions-frames.html\nfunc (b *PlanBuilder) buildWindowFunctionFrame(ctx context.Context, spec *ast.WindowSpec, orderByItems []property.Item) (*WindowFrame, error) {\n\tframeClause := spec.Frame\n\tif frameClause == nil {\n\t\treturn nil, nil\n\t}\n\tframe := &WindowFrame{Type: frameClause.Type}\n\tvar err error\n\tframe.Start, err = b.buildWindowFunctionFrameBound(ctx, spec, orderByItems, &frameClause.Extent.Start)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tframe.End, err = b.buildWindowFunctionFrameBound(ctx, spec, orderByItems, &frameClause.Extent.End)\n\treturn frame, err\n}\n\nfunc (b *PlanBuilder) buildWindowFunctions(ctx context.Context, p LogicalPlan, groupedFuncs map[*ast.WindowSpec][]*ast.WindowFuncExpr, aggMap map[*ast.AggregateFuncExpr]int) (LogicalPlan, map[*ast.WindowFuncExpr]int, error) {\n\targs := make([]ast.ExprNode, 0, 4)\n\twindowMap := make(map[*ast.WindowFuncExpr]int)\n\tfor _, window := range sortWindowSpecs(groupedFuncs) {\n\t\targs = args[:0]\n\t\tspec, funcs := window.spec, window.funcs\n\t\tfor _, windowFunc := range funcs {\n\t\t\targs = append(args, windowFunc.Args...)\n\t\t}\n\t\tnp, partitionBy, orderBy, args, err := b.buildProjectionForWindow(ctx, p, spec, args, aggMap)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\terr = b.checkOriginWindowSpecs(funcs, orderBy)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tframe, err := b.buildWindowFunctionFrame(ctx, spec, orderBy)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\twindow := LogicalWindow{\n\t\t\tPartitionBy: partitionBy,\n\t\t\tOrderBy:     orderBy,\n\t\t\tFrame:       frame,\n\t\t}.Init(b.ctx, b.getSelectOffset())\n\t\twindow.names = make([]*types.FieldName, np.Schema().Len())\n\t\tcopy(window.names, np.OutputNames())\n\t\tschema := np.Schema().Clone()\n\t\tdescs := make([]*aggregation.WindowFuncDesc, 0, len(funcs))\n\t\tpreArgs := 0\n\t\tfor _, windowFunc := range funcs {\n\t\t\tdesc, err := aggregation.NewWindowFuncDesc(b.ctx, windowFunc.F, args[preArgs:preArgs+len(windowFunc.Args)])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\t\t\tif desc == nil {\n\t\t\t\treturn nil, nil, ErrWrongArguments.GenWithStackByArgs(strings.ToLower(windowFunc.F))\n\t\t\t}\n\t\t\tpreArgs += len(windowFunc.Args)\n\t\t\tdesc.WrapCastForAggArgs(b.ctx)\n\t\t\tdescs = append(descs, desc)\n\t\t\twindowMap[windowFunc] = schema.Len()\n\t\t\tschema.Append(&expression.Column{\n\t\t\t\tUniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t\t\tRetType:  desc.RetTp,\n\t\t\t})\n\t\t\twindow.names = append(window.names, types.EmptyName)\n\t\t}\n\t\twindow.WindowFuncDescs = descs\n\t\twindow.SetChildren(np)\n\t\twindow.SetSchema(schema)\n\t\tp = window\n\t}\n\treturn p, windowMap, nil\n}\n\nfunc (b *PlanBuilder) buildSelection(\n\tctx context.Context,\n\tp LogicalPlan,\n\twhere ast.ExprNode,\n\tAggMapper map[*ast.AggregateFuncExpr]int) (LogicalPlan, error) {\n\tb.optFlag = b.optFlag | flagPredicatePushDown\n\tif b.curClause != havingClause {\n\t\tb.curClause = whereClause\n\t}\n\n\tconditions := splitWhere(where)\n\texpressions := make([]expression.Expression, 0, len(conditions))\n\tselection := LogicalSelection{}.Init(b.ctx, b.getSelectOffset())\n\tfor _, cond := range conditions {\n\t\texpr, np, err := b.rewrite(ctx, cond, p, AggMapper, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tp = np\n\t\tif expr == nil {\n\t\t\tcontinue\n\t\t}\n\t\tcnfItems := expression.SplitCNFItems(expr)\n\t\tfor _, item := range cnfItems {\n\t\t\texpressions = append(expressions, item)\n\t\t}\n\t}\n\tif len(expressions) == 0 {\n\t\treturn p, nil\n\t}\n\tselection.Conditions = expressions\n\tselection.SetChildren(p)\n\tselection.SetSchema(p.Schema().Clone())\n\tselection.SetOutputNames(p.OutputNames())\n\treturn selection, nil\n}\n\n// splitWhere split a where expression to a list of AND conditions.\nfunc splitWhere(where ast.ExprNode) []ast.ExprNode {\n\tvar conditions []ast.ExprNode\n\tswitch x := where.(type) {\n\tcase nil:\n\tcase *ast.BinaryOperationExpr:\n\t\tif x.Op == opcode.LogicAnd {\n\t\t\tconditions = append(conditions, splitWhere(x.L)...)\n\t\t\tconditions = append(conditions, splitWhere(x.R)...)\n\t\t} else {\n\t\t\tconditions = append(conditions, x)\n\t\t}\n\tcase *ast.ParenthesesExpr:\n\t\tconditions = append(conditions, splitWhere(x.Expr)...)\n\tdefault:\n\t\tconditions = append(conditions, where)\n\t}\n\treturn conditions\n}\n\n// buildSemiApply builds apply plan with outerPlan and innerPlan, which apply semi-join for every row from outerPlan and the whole innerPlan.\nfunc (b *PlanBuilder) buildSemiApply(outerPlan, innerPlan LogicalPlan, condition []expression.Expression, asScalar, not bool) (LogicalPlan, error) {\n\tb.optFlag = b.optFlag | flagPredicatePushDown | flagBuildKeyInfo | flagDecorrelate\n\n\tjoin, err := b.buildSemiJoin(outerPlan, innerPlan, condition, asScalar, not)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tap := &LogicalApply{LogicalJoin: *join}\n\tap.tp = plancodec.TypeApply\n\tap.self = ap\n\treturn ap, nil\n}\n\nfunc (b *PlanBuilder) buildSemiJoin(outerPlan, innerPlan LogicalPlan, onCondition []expression.Expression, asScalar bool, not bool) (*LogicalJoin, error) {\n\tjoinPlan := LogicalJoin{}.Init(b.ctx, b.getSelectOffset())\n\tfor i, expr := range onCondition {\n\t\tonCondition[i] = expr.Decorrelate(outerPlan.Schema())\n\t}\n\tjoinPlan.SetChildren(outerPlan, innerPlan)\n\tjoinPlan.AttachOnConds(onCondition)\n\tjoinPlan.names = make([]*types.FieldName, outerPlan.Schema().Len(), outerPlan.Schema().Len()+innerPlan.Schema().Len()+1)\n\tcopy(joinPlan.names, outerPlan.OutputNames())\n\tif asScalar {\n\t\tnewSchema := outerPlan.Schema().Clone()\n\t\tnewSchema.Append(&expression.Column{\n\t\t\tRetType:  types.NewFieldType(mysql.TypeTiny),\n\t\t\tUniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t})\n\t\tjoinPlan.names = append(joinPlan.names, types.EmptyName)\n\t\tjoinPlan.SetSchema(newSchema)\n\t\tif not {\n\t\t\tjoinPlan.JoinType = AntiLeftOuterSemiJoin\n\t\t} else {\n\t\t\tjoinPlan.JoinType = LeftOuterSemiJoin\n\t\t}\n\t} else {\n\t\tjoinPlan.SetSchema(outerPlan.Schema().Clone())\n\t\tif not {\n\t\t\tjoinPlan.JoinType = AntiSemiJoin\n\t\t} else {\n\t\t\tjoinPlan.JoinType = SemiJoin\n\t\t}\n\t}\n\treturn joinPlan, nil\n}\n\nfunc (la *LogicalAggregation) collectGroupByColumns() {\n\tla.groupByCols = la.groupByCols[:0]\n\tfor _, item := range la.GroupByItems {\n\t\tif col, ok := item.(*expression.Column); ok {\n\t\t\tla.groupByCols = append(la.groupByCols, col)\n\t\t}\n\t}\n}\n\nfunc (b *PlanBuilder) buildAggregation(\n\tctx context.Context, p LogicalPlan, aggFuncList []*ast.AggregateFuncExpr, gbyItems []expression.Expression) (\n\tLogicalPlan, map[int]int, error) {\n\tb.optFlag = b.optFlag | flagBuildKeyInfo\n\tb.optFlag = b.optFlag | flagPushDownAgg\n\t// We may apply aggregation eliminate optimization.\n\t// So we add the flagMaxMinEliminate to try to convert max/min to topn and flagPushDownTopN to handle the newly added topn operator.\n\tb.optFlag = b.optFlag | flagMaxMinEliminate\n\tb.optFlag = b.optFlag | flagPushDownTopN\n\t// when we eliminate the max and min we may add `is not null` filter.\n\tb.optFlag = b.optFlag | flagPredicatePushDown\n\tb.optFlag = b.optFlag | flagEliminateAgg\n\tb.optFlag = b.optFlag | flagEliminateProjection\n\n\tplan4Agg := LogicalAggregation{\n\t\tAggFuncs: make([]*aggregation.AggFuncDesc, 0, len(aggFuncList)),\n\t}.Init(b.ctx, b.getSelectOffset())\n\tschema4Agg := expression.NewSchema(make([]*expression.Column, 0, len(aggFuncList)+p.Schema().Len())...)\n\tnames := make(types.NameSlice, 0, len(aggFuncList)+p.Schema().Len())\n\t// aggIdxMap maps the old index to new index after applying common aggregation functions elimination.\n\taggIndexMap := make(map[int]int)\n\n\tfor i, aggFunc := range aggFuncList {\n\t\tnewArgList := make([]expression.Expression, 0, len(aggFunc.Args))\n\t\tfor _, arg := range aggFunc.Args {\n\t\t\tnewArg, np, err := b.rewrite(ctx, arg, p, nil, true)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\t\t\tp = np\n\t\t\tnewArgList = append(newArgList, newArg)\n\t\t}\n\t\tnewFunc, err := aggregation.NewAggFuncDesc(b.ctx, aggFunc.F, newArgList, aggFunc.Distinct)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tcombined := false\n\t\tfor j, oldFunc := range plan4Agg.AggFuncs {\n\t\t\tif oldFunc.Equal(b.ctx, newFunc) {\n\t\t\t\taggIndexMap[i] = j\n\t\t\t\tcombined = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !combined {\n\t\t\tposition := len(plan4Agg.AggFuncs)\n\t\t\taggIndexMap[i] = position\n\t\t\tplan4Agg.AggFuncs = append(plan4Agg.AggFuncs, newFunc)\n\t\t\tschema4Agg.Append(&expression.Column{\n\t\t\t\tUniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t\t\tRetType:  newFunc.RetTp,\n\t\t\t})\n\t\t\tnames = append(names, types.EmptyName)\n\t\t}\n\t}\n\n\tfor i, col := range p.Schema().Columns {\n\t\tnewFunc, err := aggregation.NewAggFuncDesc(\n\t\t\tb.ctx, ast.AggFuncFirstRow, []expression.Expression{col}, false)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tplan4Agg.AggFuncs = append(plan4Agg.AggFuncs, newFunc)\n\t\tnewCol, ok := col.Clone().(*expression.Column)\n\t\tif !ok {\n\t\t\treturn nil, nil, fmt.Errorf(\"clone column failed\")\n\t\t}\n\t\tnewCol.RetType = newFunc.RetTp\n\t\tschema4Agg.Append(newCol)\n\t\tnames = append(names, p.OutputNames()[i])\n\t}\n\tplan4Agg.names = names\n\tplan4Agg.SetChildren(p)\n\tplan4Agg.GroupByItems = gbyItems\n\tplan4Agg.SetSchema(schema4Agg)\n\tplan4Agg.collectGroupByColumns()\n\treturn plan4Agg, aggIndexMap, nil\n}\n\nfunc (b *PlanBuilder) extractAggFuncs(fields []*ast.SelectField) ([]*ast.AggregateFuncExpr, map[*ast.AggregateFuncExpr]int) {\n\textractor := &AggregateFuncExtractor{}\n\tfor _, f := range fields {\n\t\tn, _ := f.Expr.Accept(extractor)\n\t\tf.Expr = n.(ast.ExprNode)\n\t}\n\taggList := extractor.AggFuncs\n\ttotalAggMapper := make(map[*ast.AggregateFuncExpr]int)\n\n\tfor i, agg := range aggList {\n\t\ttotalAggMapper[agg] = i\n\t}\n\treturn aggList, totalAggMapper\n}\n\n// gbyResolver resolves group by items from select fields.\ntype gbyResolver struct {\n\tctx     sessionctx.Context\n\tfields  []*ast.SelectField\n\tschema  *expression.Schema\n\tnames   []*types.FieldName\n\terr     error\n\tinExpr  bool\n\tisParam bool\n\n\texprDepth int // exprDepth is the depth of current expression in expression tree.\n}\n\nfunc (g *gbyResolver) Enter(inNode ast.Node) (ast.Node, bool) {\n\tg.exprDepth++\n\tswitch inNode.(type) {\n\tcase *ast.SubqueryExpr, *ast.CompareSubqueryExpr, *ast.ExistsSubqueryExpr:\n\t\treturn inNode, true\n\tcase *ast.ColumnNameExpr, *ast.ParenthesesExpr, *ast.ColumnName:\n\tdefault:\n\t\tg.inExpr = true\n\t}\n\treturn inNode, false\n}\n\nfunc (g *gbyResolver) Leave(inNode ast.Node) (ast.Node, bool) {\n\textractor := &AggregateFuncExtractor{}\n\tswitch v := inNode.(type) {\n\tcase *ast.ColumnNameExpr:\n\t\tidx, err := expression.FindFieldName(g.names, v.Name)\n\t\tif idx < 0 || !g.inExpr {\n\t\t\tvar index int\n\t\t\tindex, g.err = resolveFromSelectFields(v, g.fields, false)\n\t\t\tif g.err != nil {\n\t\t\t\treturn inNode, false\n\t\t\t}\n\t\t\tif idx >= 0 {\n\t\t\t\treturn inNode, true\n\t\t\t}\n\t\t\tif index != -1 {\n\t\t\t\tret := g.fields[index].Expr\n\t\t\t\tret.Accept(extractor)\n\t\t\t\tif len(extractor.AggFuncs) != 0 {\n\t\t\t\t\terr = ErrIllegalReference.GenWithStackByArgs(v.Name.OrigColName(), \"reference to group function\")\n\t\t\t\t} else if ast.HasWindowFlag(ret) {\n\t\t\t\t\terr = ErrIllegalReference.GenWithStackByArgs(v.Name.OrigColName(), \"reference to window function\")\n\t\t\t\t} else {\n\t\t\t\t\treturn ret, true\n\t\t\t\t}\n\t\t\t}\n\t\t\tg.err = err\n\t\t\treturn inNode, false\n\t\t}\n\tcase *ast.PositionExpr:\n\t\tg.err = ErrUnknownColumn.GenWithStackByArgs(\"\", \"We don't support GROUP BY positions for now\")\n\tcase *ast.ValuesExpr:\n\t\tif v.Column == nil {\n\t\t\tg.err = ErrUnknownColumn.GenWithStackByArgs(\"\", \"VALUES() function\")\n\t\t}\n\t}\n\treturn inNode, true\n}\n\n// colMatch means that if a match b, e.g. t.a can match test.t.a but test.t.a can't match t.a.\n// Because column a want column from database test exactly.\nfunc colMatch(a *ast.ColumnName, b *ast.ColumnName) bool {\n\tif a.Schema.L == \"\" || a.Schema.L == b.Schema.L {\n\t\tif a.Table.L == \"\" || a.Table.L == b.Table.L {\n\t\t\treturn a.Name.L == b.Name.L\n\t\t}\n\t}\n\treturn false\n}\n\nfunc matchField(f *ast.SelectField, col *ast.ColumnNameExpr, ignoreAsName bool) bool {\n\t// if col specify a table name, resolve from table source directly.\n\tif col.Name.Table.L == \"\" {\n\t\tif f.AsName.L == \"\" || ignoreAsName {\n\t\t\tif curCol, isCol := f.Expr.(*ast.ColumnNameExpr); isCol {\n\t\t\t\treturn curCol.Name.Name.L == col.Name.Name.L\n\t\t\t} else if _, isFunc := f.Expr.(*ast.FuncCallExpr); isFunc {\n\t\t\t\t// Fix issue 7331\n\t\t\t\t// If there are some function calls in SelectField, we check if\n\t\t\t\t// ColumnNameExpr in GroupByClause matches one of these function calls.\n\t\t\t\t// Example: select concat(k1,k2) from t group by `concat(k1,k2)`,\n\t\t\t\t// `concat(k1,k2)` matches with function call concat(k1, k2).\n\t\t\t\treturn strings.ToLower(f.Text()) == col.Name.Name.L\n\t\t\t}\n\t\t\t// a expression without as name can't be matched.\n\t\t\treturn false\n\t\t}\n\t\treturn f.AsName.L == col.Name.Name.L\n\t}\n\treturn false\n}\n\nfunc resolveFromSelectFields(v *ast.ColumnNameExpr, fields []*ast.SelectField, ignoreAsName bool) (index int, err error) {\n\tvar matchedExpr ast.ExprNode\n\tindex = -1\n\tfor i, field := range fields {\n\t\tif field.Auxiliary {\n\t\t\tcontinue\n\t\t}\n\t\tif matchField(field, v, ignoreAsName) {\n\t\t\tcurCol, isCol := field.Expr.(*ast.ColumnNameExpr)\n\t\t\tif !isCol {\n\t\t\t\treturn i, nil\n\t\t\t}\n\t\t\tif matchedExpr == nil {\n\t\t\t\tmatchedExpr = curCol\n\t\t\t\tindex = i\n\t\t\t} else if !colMatch(matchedExpr.(*ast.ColumnNameExpr).Name, curCol.Name) &&\n\t\t\t\t!colMatch(curCol.Name, matchedExpr.(*ast.ColumnNameExpr).Name) {\n\t\t\t\treturn -1, ErrAmbiguous.GenWithStackByArgs(curCol.Name.Name.L, clauseMsg[fieldList])\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// orderbyExprResolver visits Expr tree.\n// It converts ColunmNameExpr to AggregateFuncExpr and collects AggregateFuncExpr.\ntype orderbyExprResolver struct {\n\tinAggFunc    bool\n\tinExpr       bool\n\torderBy      bool\n\terr          error\n\tp            LogicalPlan\n\tselectFields []*ast.SelectField\n\taggMapper    map[*ast.AggregateFuncExpr]int\n\tcolMapper    map[*ast.ColumnNameExpr]int\n\tgbyItems     []*ast.ByItem\n\touterSchemas []*expression.Schema\n\touterNames   [][]*types.FieldName\n\tcurClause    clauseCode\n}\n\n// Enter implements Visitor interface.\nfunc (a *orderbyExprResolver) Enter(n ast.Node) (node ast.Node, skipChildren bool) {\n\tswitch n.(type) {\n\tcase *ast.AggregateFuncExpr:\n\t\ta.inAggFunc = true\n\tcase *ast.WindowFuncExpr, *ast.WindowSpec, *ast.ExistsSubqueryExpr:\n\t\ta.err = fmt.Errorf(\"orderbyExprResolver.Enter encounter unsupported expr: %v\", n)\n\t\treturn n, false\n\tcase *ast.ColumnNameExpr, *ast.ColumnName:\n\tcase *ast.SubqueryExpr:\n\t\t// Enter a new context, skip it.\n\t\treturn n, true\n\tdefault:\n\t\ta.inExpr = true\n\t}\n\treturn n, false\n}\n\nfunc (a *orderbyExprResolver) resolveFromPlan(v *ast.ColumnNameExpr, p LogicalPlan) (int, error) {\n\tidx, err := expression.FindFieldName(p.OutputNames(), v.Name)\n\tif err != nil {\n\t\treturn -1, err\n\t}\n\tif idx < 0 {\n\t\treturn -1, nil\n\t}\n\tcol := p.Schema().Columns[idx]\n\tname := p.OutputNames()[idx]\n\tnewColName := &ast.ColumnName{\n\t\tSchema: name.DBName,\n\t\tTable:  name.TblName,\n\t\tName:   name.ColName,\n\t}\n\tfor i, field := range a.selectFields {\n\t\tif c, ok := field.Expr.(*ast.ColumnNameExpr); ok && colMatch(c.Name, newColName) {\n\t\t\treturn i, nil\n\t\t}\n\t}\n\tsf := &ast.SelectField{\n\t\tExpr:      &ast.ColumnNameExpr{Name: newColName},\n\t\tAuxiliary: true,\n\t}\n\tsf.Expr.SetType(col.GetType())\n\ta.selectFields = append(a.selectFields, sf)\n\treturn len(a.selectFields) - 1, nil\n}\n\n// Leave implements Visitor interface.\nfunc (a *orderbyExprResolver) Leave(n ast.Node) (node ast.Node, ok bool) {\n\tswitch v := n.(type) {\n\tcase *ast.AggregateFuncExpr:\n\t\ta.inAggFunc = false\n\t\ta.aggMapper[v] = len(a.selectFields)\n\t\ta.selectFields = append(a.selectFields, &ast.SelectField{\n\t\t\tAuxiliary: true,\n\t\t\tExpr:      v,\n\t\t\tAsName:    model.NewCIStr(fmt.Sprintf(\"sel_agg_%d\", len(a.selectFields))),\n\t\t})\n\tcase *ast.WindowFuncExpr, *ast.WindowSpec:\n\t\ta.err = fmt.Errorf(\"orderbyExprResolver.Leave encounter unsupported expr: %v\", n)\n\t\treturn node, false\n\tcase *ast.ColumnNameExpr:\n\t\tresolveFieldsFirst := true\n\t\tif a.inAggFunc || (a.orderBy && a.inExpr) || a.curClause == fieldList {\n\t\t\tresolveFieldsFirst = false\n\t\t}\n\t\tif !a.inAggFunc && !a.orderBy {\n\t\t\tfor _, item := range a.gbyItems {\n\t\t\t\tif col, ok := item.Expr.(*ast.ColumnNameExpr); ok &&\n\t\t\t\t\t(colMatch(v.Name, col.Name) || colMatch(col.Name, v.Name)) {\n\t\t\t\t\tresolveFieldsFirst = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvar index int\n\t\tif resolveFieldsFirst {\n\t\t\tindex, a.err = resolveFromSelectFields(v, a.selectFields, false)\n\t\t\tif a.err != nil {\n\t\t\t\treturn node, false\n\t\t\t}\n\t\t\tif index != -1 && a.curClause == havingClause && ast.HasWindowFlag(a.selectFields[index].Expr) {\n\t\t\t\ta.err = ErrWindowInvalidWindowFuncAliasUse.GenWithStackByArgs(v.Name.Name.O)\n\t\t\t\treturn node, false\n\t\t\t}\n\t\t\tif index == -1 {\n\t\t\t\tif a.orderBy {\n\t\t\t\t\tindex, a.err = a.resolveFromPlan(v, a.p)\n\t\t\t\t} else {\n\t\t\t\t\tindex, a.err = resolveFromSelectFields(v, a.selectFields, true)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// We should ignore the err when resolving from schema. Because we could resolve successfully\n\t\t\t// when considering select fields.\n\t\t\tvar err error\n\t\t\tindex, err = a.resolveFromPlan(v, a.p)\n\t\t\t_ = err\n\t\t\tif index == -1 && a.curClause != fieldList {\n\t\t\t\tindex, a.err = resolveFromSelectFields(v, a.selectFields, false)\n\t\t\t\tif index != -1 && a.curClause == havingClause && ast.HasWindowFlag(a.selectFields[index].Expr) {\n\t\t\t\t\ta.err = ErrWindowInvalidWindowFuncAliasUse.GenWithStackByArgs(v.Name.Name.O)\n\t\t\t\t\treturn node, false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif a.err != nil {\n\t\t\treturn node, false\n\t\t}\n\t\tif index == -1 {\n\t\t\t// If we can't find it any where, it may be a correlated columns.\n\t\t\tfor _, names := range a.outerNames {\n\t\t\t\tidx, err1 := expression.FindFieldName(names, v.Name)\n\t\t\t\tif err1 != nil {\n\t\t\t\t\ta.err = err1\n\t\t\t\t\treturn node, false\n\t\t\t\t}\n\t\t\t\tif idx >= 0 {\n\t\t\t\t\treturn n, true\n\t\t\t\t}\n\t\t\t}\n\t\t\ta.err = ErrUnknownColumn.GenWithStackByArgs(v.Name.OrigColName(), clauseMsg[a.curClause])\n\t\t\treturn node, false\n\t\t}\n\t\tif a.inAggFunc {\n\t\t\treturn a.selectFields[index].Expr, true\n\t\t}\n\t\ta.colMapper[v] = index\n\t}\n\treturn n, true\n}\n\n// resolveHavingAndOrderBy will process aggregate functions and resolve the columns that don't exist in select fields.\n// If we found some columns that are not in select fields, we will append it to select fields and update the colMapper.\n// When we rewrite the order by / having expression, we will find column in map at first.\nfunc (b *PlanBuilder) resolveHavingAndOrderBy(sel *ast.SelectStmt, p LogicalPlan) (\n\tmap[*ast.AggregateFuncExpr]int, map[*ast.AggregateFuncExpr]int, error) {\n\textractor := &havingWindowAndOrderbyExprResolver{\n\t\tp:            p,\n\t\tselectFields: sel.Fields.Fields,\n\t\taggMapper:    make(map[*ast.AggregateFuncExpr]int),\n\t\tcolMapper:    b.colMapper,\n\t\touterSchemas: b.outerSchemas,\n\t\touterNames:   b.outerNames,\n\t}\n\tif sel.GroupBy != nil {\n\t\textractor.gbyItems = sel.GroupBy.Items\n\t}\n\t// Extract agg funcs from having clause.\n\tif sel.Having != nil {\n\t\textractor.curClause = havingClause\n\t\tn, ok := sel.Having.Expr.Accept(extractor)\n\t\tif !ok {\n\t\t\treturn nil, nil, errors.Trace(extractor.err)\n\t\t}\n\t\tsel.Having.Expr = n.(ast.ExprNode)\n\t}\n\thavingAggMapper := extractor.aggMapper\n\textractor.aggMapper = make(map[*ast.AggregateFuncExpr]int)\n\textractor.orderBy = true\n\textractor.inExpr = false\n\t// Extract agg funcs from order by clause.\n\tif sel.OrderBy != nil {\n\t\textractor.curClause = orderByClause\n\t\tfor _, item := range sel.OrderBy.Items {\n\t\t\tif ast.HasWindowFlag(item.Expr) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tn, ok := item.Expr.Accept(extractor)\n\t\t\tif !ok {\n\t\t\t\treturn nil, nil, errors.Trace(extractor.err)\n\t\t\t}\n\t\t\titem.Expr = n.(ast.ExprNode)\n\t\t}\n\t}\n\tsel.Fields.Fields = extractor.selectFields\n\treturn havingAggMapper, extractor.aggMapper, nil\n}\n\n// ByItems wraps a \"by\" item.\ntype ByItems struct {\n\tExpr expression.Expression\n\tDesc bool\n}\n\n// String implements fmt.Stringer interface.\nfunc (by *ByItems) String() string {\n\tif by.Desc {\n\t\treturn fmt.Sprintf(\"%s desc\", by.Expr)\n\t}\n\treturn by.Expr.String()\n}\n\n// Clone makes a copy of ByItems.\nfunc (by *ByItems) Clone() *ByItems {\n\treturn &ByItems{Expr: by.Expr.Clone(), Desc: by.Desc}\n}\n\nfunc (b *PlanBuilder) buildSort(\n\tctx context.Context,\n\tp LogicalPlan,\n\tbyItems []*ast.ByItem,\n\taggMapper map[*ast.AggregateFuncExpr]int,\n\twindowMapper map[*ast.WindowFuncExpr]int) (*LogicalSort, error) {\n\tb.curClause = orderByClause\n\tsort := LogicalSort{}.Init(b.ctx, b.getSelectOffset())\n\texprs := make([]*ByItems, 0, len(byItems))\n\tfor _, item := range byItems {\n\t\tit, np, err := b.rewriteWithPreprocess(ctx, item.Expr, p, aggMapper, windowMapper, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tp = np\n\t\texprs = append(exprs, &ByItems{Expr: it, Desc: item.Desc})\n\t}\n\tsort.ByItems = exprs\n\tsort.SetChildren(p)\n\treturn sort, nil\n}\n\n// getUintFromNode gets uint64 value from ast.Node.\n// For ordinary statement, node should be uint64 constant value.\n// For prepared statement, node is string. We should convert it to uint64.\nfunc getUintFromNode(ctx sessionctx.Context, n ast.Node) (uVal uint64, isNull bool, isExpectedType bool) {\n\tvar val interface{}\n\tswitch v := n.(type) {\n\tcase *driver.ValueExpr:\n\t\tval = v.GetValue()\n\tcase *driver.ParamMarkerExpr:\n\t\tval = v.GetValue()\n\tdefault:\n\t\treturn 0, false, false\n\t}\n\tswitch v := val.(type) {\n\tcase uint64:\n\t\treturn v, false, true\n\tcase int64:\n\t\tif v >= 0 {\n\t\t\treturn uint64(v), false, true\n\t\t}\n\tcase string:\n\t\tsc := ctx.GetSessionVars().StmtCtx\n\t\tuVal, err := types.StrToUint(sc, v)\n\t\tif err != nil {\n\t\t\treturn 0, false, false\n\t\t}\n\t\treturn uVal, false, true\n\t}\n\treturn 0, false, false\n}\n\nfunc extractLimitCountOffset(ctx sessionctx.Context, limit *ast.Limit) (count uint64,\n\toffset uint64, err error) {\n\tvar isExpectedType bool\n\tif limit.Count != nil {\n\t\tcount, _, isExpectedType = getUintFromNode(ctx, limit.Count)\n\t\tif !isExpectedType {\n\t\t\treturn 0, 0, ErrWrongArguments.GenWithStackByArgs(\"LIMIT\")\n\t\t}\n\t}\n\tif limit.Offset != nil {\n\t\toffset, _, isExpectedType = getUintFromNode(ctx, limit.Offset)\n\t\tif !isExpectedType {\n\t\t\treturn 0, 0, ErrWrongArguments.GenWithStackByArgs(\"LIMIT\")\n\t\t}\n\t}\n\treturn count, offset, nil\n}\n\nfunc (b *PlanBuilder) buildLimit(src LogicalPlan, limit *ast.Limit) (LogicalPlan, error) {\n\tb.optFlag = b.optFlag | flagPushDownTopN\n\tvar (\n\t\toffset, count uint64\n\t\terr           error\n\t)\n\tif count, offset, err = extractLimitCountOffset(b.ctx, limit); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif count > math.MaxUint64-offset {\n\t\tcount = math.MaxUint64 - offset\n\t}\n\tif offset+count == 0 {\n\t\treturn nil, fmt.Errorf(\"buildLimit offset + count should not be 0\")\n\t}\n\tli := LogicalLimit{\n\t\tOffset: offset,\n\t\tCount:  count,\n\t}.Init(b.ctx, b.getSelectOffset())\n\tli.SetChildren(src)\n\treturn li, nil\n}\n\nfunc (b *PlanBuilder) buildDistinct(child LogicalPlan, length int) (*LogicalAggregation, error) {\n\tb.optFlag = b.optFlag | flagBuildKeyInfo\n\tb.optFlag = b.optFlag | flagPushDownAgg\n\tplan4Agg := LogicalAggregation{\n\t\tAggFuncs:           make([]*aggregation.AggFuncDesc, 0, child.Schema().Len()),\n\t\tGroupByItems:       expression.Column2Exprs(child.Schema().Columns[:length]),\n\t\tProducedByDistinct: true,\n\t}.Init(b.ctx, child.SelectBlockOffset())\n\tplan4Agg.collectGroupByColumns()\n\tfor _, col := range child.Schema().Columns {\n\t\taggDesc, err := aggregation.NewAggFuncDesc(b.ctx, ast.AggFuncFirstRow, []expression.Expression{col}, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tplan4Agg.AggFuncs = append(plan4Agg.AggFuncs, aggDesc)\n\t}\n\tplan4Agg.SetChildren(child)\n\tplan4Agg.SetSchema(child.Schema().Clone())\n\tplan4Agg.names = child.OutputNames()\n\t// Distinct will be rewritten as first_row, we reset the type here since the return type\n\t// of first_row is not always the same as the column arg of first_row.\n\tfor i, col := range plan4Agg.schema.Columns {\n\t\tcol.RetType = plan4Agg.AggFuncs[i].RetTp\n\t}\n\treturn plan4Agg, nil\n}\n\n// unionJoinFieldType finds the type which can carry the given types in Union.\nfunc unionJoinFieldType(a, b *types.FieldType) *types.FieldType {\n\tresultTp := types.NewFieldType(types.MergeFieldType(a.Tp, b.Tp))\n\t// This logic will be intelligible when it is associated with the buildProjection4Union logic.\n\tif resultTp.Tp == mysql.TypeNewDecimal {\n\t\t// The decimal result type will be unsigned only when all the decimals to be united are unsigned.\n\t\tresultTp.Flag &= b.Flag & mysql.UnsignedFlag\n\t} else {\n\t\t// Non-decimal results will be unsigned when the first SQL statement result in the union is unsigned.\n\t\tresultTp.Flag |= a.Flag & mysql.UnsignedFlag\n\t}\n\tresultTp.Decimal = mathutil.Max(a.Decimal, b.Decimal)\n\t// `Flen - Decimal` is the fraction before '.'\n\tresultTp.Flen = mathutil.Max(a.Flen-a.Decimal, b.Flen-b.Decimal) + resultTp.Decimal\n\tif resultTp.EvalType() != types.ETInt && (a.EvalType() == types.ETInt || b.EvalType() == types.ETInt) && resultTp.Flen < mysql.MaxIntWidth {\n\t\tresultTp.Flen = mysql.MaxIntWidth\n\t}\n\tresultTp.Charset = a.Charset\n\tresultTp.Collate = a.Collate\n\texpression.SetBinFlagOrBinStr(b, resultTp)\n\treturn resultTp\n}\n\nfunc (b *PlanBuilder) buildProjection4Union(ctx context.Context, u *LogicalUnionAll) {\n\tunionCols := make([]*expression.Column, 0, u.Children()[0].Schema().Len())\n\tnames := make([]*types.FieldName, 0, u.Children()[0].Schema().Len())\n\n\t// Infer union result types by its children's schema.\n\tfor i, col := range u.Children()[0].Schema().Columns {\n\t\tresultTp := col.RetType\n\t\tfor j := 1; j < len(u.children); j++ {\n\t\t\tchildTp := u.children[j].Schema().Columns[i].RetType\n\t\t\tresultTp = unionJoinFieldType(resultTp, childTp)\n\t\t}\n\t\tnames = append(names, &types.FieldName{ColName: u.Children()[0].OutputNames()[i].ColName})\n\t\tunionCols = append(unionCols, &expression.Column{\n\t\t\tRetType:  resultTp,\n\t\t\tUniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t})\n\t}\n\tu.schema = expression.NewSchema(unionCols...)\n\tu.names = names\n\t// Process each child and add a projection above original child.\n\t// So the schema of `UnionAll` can be the same with its children's.\n\tfor childID, child := range u.children {\n\t\texprs := make([]expression.Expression, len(child.Schema().Columns))\n\t\tfor i, srcCol := range child.Schema().Columns {\n\t\t\tdstType := unionCols[i].RetType\n\t\t\tsrcType := srcCol.RetType\n\t\t\tif !srcType.Equal(dstType) {\n\t\t\t\texprs[i] = expression.BuildCastFunction4Union(b.ctx, srcCol, dstType)\n\t\t\t} else {\n\t\t\t\texprs[i] = srcCol\n\t\t\t}\n\t\t}\n\t\tb.optFlag |= flagEliminateProjection\n\t\tproj := LogicalProjection{Exprs: exprs, AvoidColumnEvaluator: true}.Init(b.ctx, b.getSelectOffset())\n\t\tproj.SetSchema(u.schema.Clone())\n\t\tproj.SetChildren(child)\n\t\tu.children[childID] = proj\n\t}\n}\n\nfunc (b *PlanBuilder) buildUnion(ctx context.Context, union *ast.UnionStmt) (LogicalPlan, error) {\n\tdistinctSelectPlans, allSelectPlans, err := b.divideUnionSelectPlans(ctx, union.SelectList.Selects)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tunionDistinctPlan := b.buildUnionAll(ctx, distinctSelectPlans)\n\tif unionDistinctPlan != nil {\n\t\tunionDistinctPlan, err = b.buildDistinct(unionDistinctPlan, unionDistinctPlan.Schema().Len())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif len(allSelectPlans) > 0 {\n\t\t\t// Can't change the statements order in order to get the correct column info.\n\t\t\tallSelectPlans = append([]LogicalPlan{unionDistinctPlan}, allSelectPlans...)\n\t\t}\n\t}\n\n\tunionAllPlan := b.buildUnionAll(ctx, allSelectPlans)\n\tunionPlan := unionDistinctPlan\n\tif unionAllPlan != nil {\n\t\tunionPlan = unionAllPlan\n\t}\n\n\toldLen := unionPlan.Schema().Len()\n\n\tif union.OrderBy != nil {\n\t\tunionPlan, err = b.buildSort(ctx, unionPlan, union.OrderBy.Items, nil, nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif union.Limit != nil {\n\t\tunionPlan, err = b.buildLimit(unionPlan, union.Limit)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Fix issue #8189 (https://github.com/pingcap/tidb/issues/8189).\n\t// If there are extra expressions generated from `ORDER BY` clause, generate a `Projection` to remove them.\n\tif oldLen != unionPlan.Schema().Len() {\n\t\tproj := LogicalProjection{\n\t\t\tExprs: expression.Column2Exprs(unionPlan.Schema().Columns[:oldLen]),\n\t\t}.Init(b.ctx, b.getSelectOffset())\n\t\tproj.SetChildren(unionPlan)\n\t\tschema := expression.NewSchema(unionPlan.Schema().Clone().Columns[:oldLen]...)\n\t\tfor _, col := range schema.Columns {\n\t\t\tcol.UniqueID = b.ctx.GetSessionVars().AllocPlanColumnID()\n\t\t}\n\t\tproj.names = unionPlan.OutputNames()[:oldLen]\n\t\tproj.SetSchema(schema)\n\t\treturn proj, nil\n\t}\n\n\treturn unionPlan, nil\n}\n\n// divideUnionSelectPlans resolves union's select stmts to logical plans.\n// and divide result plans into \"union-distinct\" and \"union-all\" parts.\n// divide rule ref: https://dev.mysql.com/doc/refman/5.7/en/union.html\n// \"Mixed UNION types are treated such that a DISTINCT union overrides any ALL union to its left.\"\nfunc (b *PlanBuilder) divideUnionSelectPlans(ctx context.Context, selects []*ast.SelectStmt) (\n\tdistinctSelects []LogicalPlan, allSelects []LogicalPlan, err error) {\n\tfirstUnionAllIdx, columnNums := 0, -1\n\t// The last slot is reserved for appending distinct union outside this function.\n\tchildren := make([]LogicalPlan, len(selects), len(selects)+1)\n\tfor i := len(selects) - 1; i >= 0; i-- {\n\t\tstmt := selects[i]\n\t\tif firstUnionAllIdx == 0 && stmt.IsAfterUnionDistinct {\n\t\t\tfirstUnionAllIdx = i + 1\n\t\t}\n\n\t\tselectPlan, err := b.buildSelect(ctx, stmt)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tif columnNums == -1 {\n\t\t\tcolumnNums = selectPlan.Schema().Len()\n\t\t}\n\t\tif selectPlan.Schema().Len() != columnNums {\n\t\t\treturn nil, nil, ErrWrongNumberOfColumnsInSelect.GenWithStackByArgs()\n\t\t}\n\t\tchildren[i] = selectPlan\n\t}\n\treturn children[:firstUnionAllIdx], children[firstUnionAllIdx:], nil\n}\n\nfunc (b *PlanBuilder) buildUnionAll(ctx context.Context, subPlan []LogicalPlan) LogicalPlan {\n\tif len(subPlan) == 0 {\n\t\treturn nil\n\t}\n\tu := LogicalUnionAll{}.Init(b.ctx, b.getSelectOffset())\n\tu.children = subPlan\n\tb.buildProjection4Union(ctx, u)\n\treturn u\n}\n\nfunc appendVisitInfo(vi []visitInfo, priv mysql.PrivilegeType, db, tbl, col string, err error) []visitInfo {\n\treturn append(vi, visitInfo{\n\t\tprivilege: priv,\n\t\tdb:        db,\n\t\ttable:     tbl,\n\t\tcolumn:    col,\n\t\terr:       err,\n\t})\n}\n\nfunc extractWindowFuncs(fields []*ast.SelectField) []*ast.WindowFuncExpr {\n\textractor := &WindowFuncExtractor{}\n\tfor _, f := range fields {\n\t\tn, _ := f.Expr.Accept(extractor)\n\t\tf.Expr = n.(ast.ExprNode)\n\t}\n\treturn extractor.windowFuncs\n}\n\n// LogicalMaxOneRow checks if a query returns no more than one row.\ntype LogicalMaxOneRow struct {\n\tbaseLogicalPlan\n}\n\nfunc (b *PlanBuilder) buildMaxOneRow(p LogicalPlan) LogicalPlan {\n\tmaxOneRow := LogicalMaxOneRow{}.Init(b.ctx, b.getSelectOffset())\n\tmaxOneRow.SetChildren(p)\n\treturn maxOneRow\n}\n\n// buildApplyWithJoinType builds apply plan with outerPlan and innerPlan, which apply join with particular join type for\n// every row from outerPlan and the whole innerPlan.\nfunc (b *PlanBuilder) buildApplyWithJoinType(outerPlan, innerPlan LogicalPlan, tp JoinType) LogicalPlan {\n\tb.optFlag = b.optFlag | flagPredicatePushDown | flagBuildKeyInfo | flagDecorrelate\n\tap := LogicalApply{LogicalJoin: LogicalJoin{JoinType: tp}}.Init(b.ctx, b.getSelectOffset())\n\tap.SetChildren(outerPlan, innerPlan)\n\tap.names = make([]*types.FieldName, outerPlan.Schema().Len()+innerPlan.Schema().Len())\n\tcopy(ap.names, outerPlan.OutputNames())\n\tap.SetSchema(expression.MergeSchema(outerPlan.Schema(), innerPlan.Schema()))\n\t// Note that, tp can only be LeftOuterJoin or InnerJoin, so we don't consider other outer joins.\n\tif tp == LeftOuterJoin {\n\t\tb.optFlag = b.optFlag | flagEliminateOuterJoin\n\t\tresetNotNullFlag(ap.schema, outerPlan.Schema().Len(), ap.schema.Len())\n\t}\n\tfor i := outerPlan.Schema().Len(); i < ap.Schema().Len(); i++ {\n\t\tap.names[i] = types.EmptyName\n\t}\n\treturn ap\n}\n\n// TableHints returns the *tableHintInfo of PlanBuilder.\nfunc (b *PlanBuilder) TableHints() *tableHintInfo {\n\tif len(b.tableHintInfo) == 0 {\n\t\treturn nil\n\t}\n\treturn &(b.tableHintInfo[len(b.tableHintInfo)-1])\n}\n\nfunc (b *PlanBuilder) resolveSelectIntoColumns(ctx context.Context, p LogicalPlan, customFields []*ast.SelectField) ([]*expression.Column, error) {\n\tvar columns []*expression.Column\n\tfor _, field := range customFields {\n\t\texpr, _, err := b.rewrite(ctx, field.Expr, p, nil, true)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"resolveSelectIntoColumns: rewrite expr{%v} err: %v\", field.Expr, err)\n\t\t}\n\t\tcolumn, ok := expr.(*expression.Column)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"resolveSelectIntoColumns: custom field {%v} must be a column\", expr)\n\t\t}\n\t\tcolumns = append(columns, column)\n\t}\n\treturn columns, nil\n}\n"
  },
  {
    "path": "pkg/planner/core/logical_plan_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/util/mock\"\n\t\"github.com/secretflow/scql/pkg/util/testleak\"\n\t\"github.com/secretflow/scql/pkg/util/testutil\"\n\n\t// NOTE(yang.y): import parser_driver so that ast.NewValueExpr\n\t// https://github.com/pingcap/parser/blob/a9496438d77d525d8759e0103f6eca40ce1d2788/ast/expressions.go#L66\n\t// is initialized.\n\t_ \"github.com/secretflow/scql/pkg/types/parser_driver\"\n)\n\nvar _ = Suite(&testPlanSuite{})\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\ntype testPlanSuite struct {\n\t*parser.Parser\n\n\tis  infoschema.InfoSchema\n\tctx sessionctx.Context\n\n\ttestData testutil.TestData\n}\n\nfunc (s *testPlanSuite) SetUpSuite(c *C) {\n\tmockTables, err := mock.MockAllTables()\n\tc.Assert(err, IsNil)\n\ts.is = infoschema.MockInfoSchema(mockTables)\n\ts.ctx = mock.MockContext()\n\ts.Parser = parser.New()\n\n\ts.testData, err = testutil.LoadTestSuiteData(\"testdata\", \"typical_query\")\n\tc.Assert(err, IsNil)\n}\n\nfunc (s *testPlanSuite) TearDownSuite(c *C) {\n\tc.Assert(s.testData.GenerateOutputIfNeeded(), IsNil)\n}\n\nfunc (s *testPlanSuite) testPlanBuilder(c *C, ca string, output string) string {\n\tcomment := Commentf(\"for %s\", ca)\n\tstmt, err := s.ParseOneStmt(ca, \"\", \"\")\n\tc.Assert(err, IsNil, comment)\n\terr = Preprocess(s.ctx, stmt, s.is)\n\tc.Assert(err, IsNil)\n\n\tp, _, err := BuildLogicalPlan(context.Background(), s.ctx, stmt, s.is)\n\tc.Assert(err, IsNil)\n\n\tresult := ToString(p)\n\tif !testutil.IsRecording() {\n\t\tc.Assert(result, Equals, output, Commentf(\"for %s\", ca))\n\t}\n\treturn result\n}\n\nfunc (s *testPlanSuite) testPlanBuilderWithOptimization(c *C, ca string, output string) string {\n\tcomment := Commentf(\"for %s\", ca)\n\tstmt, err := s.ParseOneStmt(ca, \"\", \"\")\n\tc.Assert(err, IsNil, comment)\n\terr = Preprocess(s.ctx, stmt, s.is)\n\tc.Assert(err, IsNil)\n\n\tp, _, err := BuildLogicalPlanWithOptimization(context.Background(), s.ctx, stmt, s.is)\n\tc.Assert(err, IsNil)\n\n\tresult := ToString(p)\n\tif !testutil.IsRecording() {\n\t\tc.Assert(result, Equals, output, Commentf(\"for %s\", ca))\n\t}\n\treturn result\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderSimple(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderSelection(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderWindow(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderSubQuery(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderInOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderLowerUpperOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderCoalesceOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderLengthOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderReplaceOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuildeLikeRlikeOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderSubstringOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderTrimOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuildeLimitOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderInstrOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderGreatestLeastOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderLogicalOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderMathOp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderCast(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilder(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderWithMissingDataSource(c *C) {\n\tca := `select alice.tbl_0.long_0 < bob.tbl_0.long_0 from alice.tbl_0`\n\tcomment := Commentf(\"for %s\", ca)\n\tstmt, err := s.ParseOneStmt(ca, \"\", \"\")\n\tc.Assert(err, IsNil, comment)\n\n\terr = Preprocess(s.ctx, stmt, s.is)\n\tc.Assert(err, IsNil)\n\n\t_, _, err = BuildLogicalPlanWithOptimization(context.Background(), s.ctx, stmt, s.is)\n\tc.Assert(err != nil, IsTrue)\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderWithMissingWhereClause(c *C) {\n\tca := `select 1`\n\tcomment := Commentf(\"for %s\", ca)\n\tstmt, err := s.ParseOneStmt(ca, \"\", \"\")\n\tc.Assert(err, IsNil, comment)\n\n\terr = Preprocess(s.ctx, stmt, s.is)\n\tc.Assert(err, IsNil)\n\n\t_, _, err = BuildLogicalPlanWithOptimization(context.Background(), s.ctx, stmt, s.is)\n\tc.Assert(err != nil, IsTrue)\n}\n\n// name test after optimizing with TestxxxxWithOptimization\nfunc (s *testPlanSuite) TestPlanBuilderSimpleWithOptimization(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilderWithOptimization(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderSelectionWithOptimization(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilderWithOptimization(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderWindowWithOptimization(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilderWithOptimization(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderSubQueryWithOptimization(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilderWithOptimization(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n\nfunc (s *testPlanSuite) TestPlanBuilderDateTimeWithOptimization(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input, output []string\n\ts.testData.GetTestCases(c, &input, &output)\n\tfor i, ca := range input {\n\t\tresult := s.testPlanBuilderWithOptimization(c, ca, output[i])\n\t\ts.testData.OnRecord(func() {\n\t\t\toutput[i] = result\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/planner/core/logical_plans.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/auth\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/planner/property\"\n\t\"github.com/secretflow/scql/pkg/table\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/ranger\"\n)\n\nvar (\n\t_ LogicalPlan = &LogicalJoin{}\n\t_ LogicalPlan = &LogicalAggregation{}\n\t_ LogicalPlan = &LogicalProjection{}\n\t_ LogicalPlan = &LogicalSelection{}\n\t_ LogicalPlan = &LogicalApply{}\n\t_ LogicalPlan = &DataSource{}\n\t_ LogicalPlan = &LogicalTableScan{}\n\t_ LogicalPlan = &LogicalSort{}\n\t_ LogicalPlan = &LogicalLimit{}\n\t_ LogicalPlan = &LogicalUnionAll{}\n\t_ LogicalPlan = &LogicalMaxOneRow{}\n)\n\ntype JoinType int\n\nconst (\n\t// InnerJoin means inner join.\n\tInnerJoin JoinType = iota\n\t// LeftOuterJoin means left join.\n\tLeftOuterJoin\n\t// RightOuterJoin means right join.\n\tRightOuterJoin\n\t// SemiJoin means if row a in table A matches some rows in B, just output a.\n\tSemiJoin\n\t// AntiSemiJoin means if row a in table A does not match any row in B, then output a.\n\tAntiSemiJoin\n\t// LeftOuterSemiJoin means if row a in table A matches some rows in B, output (a, true), otherwise, output (a, false).\n\tLeftOuterSemiJoin\n\t// AntiLeftOuterSemiJoin means if row a in table A matches some rows in B, output (a, false), otherwise, output (a, true).\n\tAntiLeftOuterSemiJoin\n)\n\n// IsOuterJoin returns if this joiner is a outer joiner\nfunc (tp JoinType) IsOuterJoin() bool {\n\treturn tp == LeftOuterJoin || tp == RightOuterJoin\n}\n\nfunc (tp JoinType) String() string {\n\tswitch tp {\n\tcase InnerJoin:\n\t\treturn \"inner join\"\n\tcase LeftOuterJoin:\n\t\treturn \"left outer join\"\n\tcase RightOuterJoin:\n\t\treturn \"right outer join\"\n\tcase LeftOuterSemiJoin:\n\t\treturn \"left outer semi join\"\n\tcase AntiLeftOuterSemiJoin:\n\t\treturn \"anti left outer semi join\"\n\tcase SemiJoin:\n\t\treturn \"semi join\"\n\t}\n\treturn \"unsupported join type\"\n}\n\nconst (\n\tpreferLeftAsINLJInner uint = 1 << iota\n\tpreferRightAsINLJInner\n\tpreferLeftAsINLHJInner\n\tpreferRightAsINLHJInner\n\tpreferLeftAsINLMJInner\n\tpreferRightAsINLMJInner\n\tpreferHashJoin\n\tpreferMergeJoin\n\tpreferHashAgg\n\tpreferStreamAgg\n)\n\ntype LogicalJoin struct {\n\tlogicalSchemaProducer\n\n\tJoinType      JoinType\n\treordered     bool\n\tcartesianJoin bool\n\n\tEqualConditions []*expression.ScalarFunction\n\tLeftConditions  expression.CNFExprs\n\tRightConditions expression.CNFExprs\n\tOtherConditions expression.CNFExprs\n\n\tLeftJoinKeys    []*expression.Column\n\tRightJoinKeys   []*expression.Column\n\tleftProperties  [][]*expression.Column\n\trightProperties [][]*expression.Column\n\n\t// DefaultValues is only used for left/right outer join, which is values the inner row's should be when the outer table\n\t// doesn't match any inner table's row.\n\t// That it's nil just means the default values is a slice of NULL.\n\t// Currently, only `aggregation push down` phase will set this.\n\tDefaultValues []types.Datum\n\n\t// redundantSchema contains columns which are eliminated in join.\n\t// For select * from a join b using (c); a.c will in output schema, and b.c will in redundantSchema.\n\tredundantSchema *expression.Schema\n\tredundantNames  types.NameSlice\n}\n\nfunc (p *LogicalJoin) columnSubstitute(schema *expression.Schema, exprs []expression.Expression) {\n\tfor i, cond := range p.LeftConditions {\n\t\tp.LeftConditions[i] = expression.ColumnSubstitute(cond, schema, exprs)\n\t}\n\n\tfor i, cond := range p.RightConditions {\n\t\tp.RightConditions[i] = expression.ColumnSubstitute(cond, schema, exprs)\n\t}\n\n\tfor i, cond := range p.OtherConditions {\n\t\tp.OtherConditions[i] = expression.ColumnSubstitute(cond, schema, exprs)\n\t}\n\n\tfor i := len(p.EqualConditions) - 1; i >= 0; i-- {\n\t\tnewCond := expression.ColumnSubstitute(p.EqualConditions[i], schema, exprs).(*expression.ScalarFunction)\n\n\t\t// If the columns used in the new filter all come from the left child,\n\t\t// we can push this filter to it.\n\t\tif expression.ExprFromSchema(newCond, p.children[0].Schema()) {\n\t\t\tp.LeftConditions = append(p.LeftConditions, newCond)\n\t\t\tp.EqualConditions = append(p.EqualConditions[:i], p.EqualConditions[i+1:]...)\n\t\t\tcontinue\n\t\t}\n\n\t\t// If the columns used in the new filter all come from the right\n\t\t// child, we can push this filter to it.\n\t\tif expression.ExprFromSchema(newCond, p.children[1].Schema()) {\n\t\t\tp.RightConditions = append(p.RightConditions, newCond)\n\t\t\tp.EqualConditions = append(p.EqualConditions[:i], p.EqualConditions[i+1:]...)\n\t\t\tcontinue\n\t\t}\n\n\t\t_, lhsIsCol := newCond.GetArgs()[0].(*expression.Column)\n\t\t_, rhsIsCol := newCond.GetArgs()[1].(*expression.Column)\n\n\t\t// If the columns used in the new filter are not all expression.Column,\n\t\t// we can not use it as join's equal condition.\n\t\tif !(lhsIsCol && rhsIsCol) {\n\t\t\tp.OtherConditions = append(p.OtherConditions, newCond)\n\t\t\tp.EqualConditions = append(p.EqualConditions[:i], p.EqualConditions[i+1:]...)\n\t\t\tcontinue\n\t\t}\n\n\t\tp.EqualConditions[i] = newCond\n\t}\n}\n\nfunc (p *LogicalJoin) extractCorrelatedCols() []*expression.CorrelatedColumn {\n\tcorCols := p.baseLogicalPlan.extractCorrelatedCols()\n\tfor _, fun := range p.EqualConditions {\n\t\tcorCols = append(corCols, expression.ExtractCorColumns(fun)...)\n\t}\n\tfor _, fun := range p.LeftConditions {\n\t\tcorCols = append(corCols, expression.ExtractCorColumns(fun)...)\n\t}\n\tfor _, fun := range p.RightConditions {\n\t\tcorCols = append(corCols, expression.ExtractCorColumns(fun)...)\n\t}\n\tfor _, fun := range p.OtherConditions {\n\t\tcorCols = append(corCols, expression.ExtractCorColumns(fun)...)\n\t}\n\treturn corCols\n}\n\n// AttachOnConds extracts on conditions for join and set the `EqualConditions`, `LeftConditions`, `RightConditions` and\n// `OtherConditions` by the result of extract.\nfunc (p *LogicalJoin) AttachOnConds(onConds []expression.Expression) {\n\teq, left, right, other := p.extractOnCondition(onConds, false, false)\n\tp.AppendJoinConds(eq, left, right, other)\n}\n\n// AppendJoinConds appends new join conditions.\nfunc (p *LogicalJoin) AppendJoinConds(eq []*expression.ScalarFunction, left, right, other []expression.Expression) {\n\tp.EqualConditions = append(eq, p.EqualConditions...)\n\tp.LeftConditions = append(left, p.LeftConditions...)\n\tp.RightConditions = append(right, p.RightConditions...)\n\tp.OtherConditions = append(other, p.OtherConditions...)\n}\n\n// pushDownConstExpr checks if the condition is from filter condition, if true, push it down to both\n// children of join, whatever the join type is; if false, push it down to inner child of outer join,\n// and both children of non-outer-join.\nfunc (p *LogicalJoin) pushDownConstExpr(expr expression.Expression, leftCond []expression.Expression,\n\trightCond []expression.Expression, filterCond bool) ([]expression.Expression, []expression.Expression) {\n\tswitch p.JoinType {\n\tcase LeftOuterJoin, LeftOuterSemiJoin, AntiLeftOuterSemiJoin:\n\t\tif filterCond {\n\t\t\tleftCond = append(leftCond, expr)\n\t\t\t// Append the expr to right join condition instead of `rightCond`, to make it able to be\n\t\t\t// pushed down to children of join.\n\t\t\tp.RightConditions = append(p.RightConditions, expr)\n\t\t} else {\n\t\t\trightCond = append(rightCond, expr)\n\t\t}\n\tcase RightOuterJoin:\n\t\tif filterCond {\n\t\t\trightCond = append(rightCond, expr)\n\t\t\tp.LeftConditions = append(p.LeftConditions, expr)\n\t\t} else {\n\t\t\tleftCond = append(leftCond, expr)\n\t\t}\n\tcase SemiJoin, InnerJoin:\n\t\tleftCond = append(leftCond, expr)\n\t\trightCond = append(rightCond, expr)\n\tcase AntiSemiJoin:\n\t\tif filterCond {\n\t\t\tleftCond = append(leftCond, expr)\n\t\t}\n\t\trightCond = append(rightCond, expr)\n\t}\n\treturn leftCond, rightCond\n}\n\ntype LogicalProjection struct {\n\tlogicalSchemaProducer\n\n\tExprs []expression.Expression\n\n\t// calculateGenCols indicates the projection is for calculating generated columns.\n\t// In *UPDATE*, we should know this to tell different projections.\n\tcalculateGenCols bool\n\n\t// CalculateNoDelay indicates this Projection is the root Plan and should be\n\t// calculated without delay and will not return any result to client.\n\t// Currently it is \"true\" only when the current sql query is a \"DO\" statement.\n\t// See \"https://dev.mysql.com/doc/refman/5.7/en/do.html\" for more detail.\n\tCalculateNoDelay bool\n\n\t// AvoidColumnEvaluator is a temporary variable which is ONLY used to avoid\n\t// building columnEvaluator for the expressions of Projection which is\n\t// built by buildProjection4Union.\n\t// This can be removed after column pool being supported.\n\t// Related issue: TiDB#8141(https://github.com/pingcap/tidb/issues/8141)\n\tAvoidColumnEvaluator bool\n}\n\nfunc (p *LogicalProjection) extractCorrelatedCols() []*expression.CorrelatedColumn {\n\tcorCols := p.baseLogicalPlan.extractCorrelatedCols()\n\tfor _, expr := range p.Exprs {\n\t\tcorCols = append(corCols, expression.ExtractCorColumns(expr)...)\n\t}\n\treturn corCols\n}\n\n// DataSource represents a tableScan without condition push down.\ntype DataSource struct {\n\tlogicalSchemaProducer\n\n\ttable     table.Table\n\ttableInfo *model.TableInfo\n\tColumns   []*model.ColumnInfo\n\tDBName    model.CIStr\n\tPartyName model.CIStr\n\n\tTableAsName *model.CIStr\n\t// allConds contains all the filters on this table. For now it's maintained\n\t// in predicate push down and used only in partition pruning.\n\t// allConds []expression.Expression\n\n\t// statisticTable *statistics.Table\n\t// tableStats     *property.StatsInfo\n\n\t// possibleAccessPaths stores all the possible access path for physical plan, including table scan.\n\t// possibleAccessPaths []*util.AccessPath\n\n\t// handleCol represents the handle column for the datasource, either the\n\t// int primary key column or extra handle column.\n\t// handleCol *expression.Column\n\n\t// TblCols contains the original columns of table before being pruned, and it\n\t// is used for estimating table scan cost.\n\tTblCols []*expression.Column\n\n\t// preferStoreType means the DataSource is enforced to which storage.\n\t// preferStoreType int\n}\n\n// TableInfo returns the *TableInfo of data source.\nfunc (ds *DataSource) TableInfo() *model.TableInfo {\n\treturn ds.tableInfo\n}\n\nfunc (ds *DataSource) buildTableGather() LogicalPlan {\n\tts := LogicalTableScan{Source: ds}.Init(ds.ctx, ds.blockOffset)\n\tts.SetSchema(ds.Schema())\n\treturn ts\n}\n\n// LogicalTableScan is the logical table scan operator.\ntype LogicalTableScan struct {\n\tlogicalSchemaProducer\n\tSource *DataSource\n\tRanges []*ranger.Range\n}\n\n// LogicalSelection represents a where or having predicate.\ntype LogicalSelection struct {\n\tlogicalSchemaProducer\n\n\t// Originally the WHERE or ON condition is parsed into a single expression,\n\t// but after we converted to CNF(Conjunctive normal form), it can be\n\t// split into a list of AND conditions.\n\tConditions []expression.Expression\n}\n\nfunc (p *LogicalSelection) extractCorrelatedCols() []*expression.CorrelatedColumn {\n\tcorCols := p.baseLogicalPlan.extractCorrelatedCols()\n\tfor _, cond := range p.Conditions {\n\t\tcorCols = append(corCols, expression.ExtractCorColumns(cond)...)\n\t}\n\treturn corCols\n}\n\n// extractCorColumnsBySchema only extracts the correlated columns that match the specified schema.\n// e.g. If the correlated columns from plan are [t1.a, t2.a, t3.a] and specified schema is [t2.a, t2.b, t2.c],\n// only [t2.a] is returned.\nfunc extractCorColumnsBySchema(p LogicalPlan, schema *expression.Schema) []*expression.CorrelatedColumn {\n\tcorCols := p.extractCorrelatedCols()\n\tresultCorCols := make([]*expression.CorrelatedColumn, schema.Len())\n\tfor _, corCol := range corCols {\n\t\tidx := schema.ColumnIndex(&corCol.Column)\n\t\tif idx != -1 {\n\t\t\tif resultCorCols[idx] == nil {\n\t\t\t\tresultCorCols[idx] = &expression.CorrelatedColumn{\n\t\t\t\t\tColumn: *schema.Columns[idx],\n\t\t\t\t\tData:   new(types.Datum),\n\t\t\t\t}\n\t\t\t}\n\t\t\tcorCol.Data = resultCorCols[idx].Data\n\t\t}\n\t}\n\t// Shrink slice. e.g. [col1, nil, col2, nil] will be changed to [col1, col2].\n\tlength := 0\n\tfor _, col := range resultCorCols {\n\t\tif col != nil {\n\t\t\tresultCorCols[length] = col\n\t\t\tlength++\n\t\t}\n\t}\n\treturn resultCorCols[:length]\n}\n\n// LogicalApply gets one row from outer executor and gets one row from inner executor according to outer row.\ntype LogicalApply struct {\n\tLogicalJoin\n\n\tCorCols []*expression.CorrelatedColumn\n}\n\nfunc (la *LogicalApply) extractCorrelatedCols() []*expression.CorrelatedColumn {\n\tcorCols := la.LogicalJoin.extractCorrelatedCols()\n\tfor i := len(corCols) - 1; i >= 0; i-- {\n\t\tif la.children[0].Schema().Contains(&corCols[i].Column) {\n\t\t\tcorCols = append(corCols[:i], corCols[i+1:]...)\n\t\t}\n\t}\n\treturn corCols\n}\n\n// LogicalAggregation represents an aggregate plan.\ntype LogicalAggregation struct {\n\tlogicalSchemaProducer\n\n\tAggFuncs     []*aggregation.AggFuncDesc\n\tGroupByItems []expression.Expression\n\t// groupByCols stores the columns that are group-by items.\n\tgroupByCols []*expression.Column\n\n\t// aggHints stores aggregation hint information.\n\taggHints aggHintInfo\n\n\tpossibleProperties [][]*expression.Column\n\tinputCount         float64 // inputCount is the input count of this plan.\n\n\t// LogicalAggregation is produced by `select distinct`\n\tProducedByDistinct bool\n}\n\n// GetGroupByCols returns the groupByCols. If the groupByCols haven't be collected,\n// this method would collect them at first. If the GroupByItems have been changed,\n// we should explicitly collect GroupByColumns before this method.\nfunc (la *LogicalAggregation) GetGroupByCols() []*expression.Column {\n\tif la.groupByCols == nil {\n\t\tla.collectGroupByColumns()\n\t}\n\treturn la.groupByCols\n}\n\nfunc (la *LogicalAggregation) extractCorrelatedCols() []*expression.CorrelatedColumn {\n\tcorCols := la.baseLogicalPlan.extractCorrelatedCols()\n\tfor _, expr := range la.GroupByItems {\n\t\tcorCols = append(corCols, expression.ExtractCorColumns(expr)...)\n\t}\n\tfor _, fun := range la.AggFuncs {\n\t\tfor _, arg := range fun.Args {\n\t\t\tcorCols = append(corCols, expression.ExtractCorColumns(arg)...)\n\t\t}\n\t}\n\treturn corCols\n}\n\n// LogicalSort stands for the order by plan.\ntype LogicalSort struct {\n\tbaseLogicalPlan\n\n\tByItems []*ByItems\n}\n\nfunc (ls *LogicalSort) extractCorrelatedCols() []*expression.CorrelatedColumn {\n\tcorCols := ls.baseLogicalPlan.extractCorrelatedCols()\n\tfor _, item := range ls.ByItems {\n\t\tcorCols = append(corCols, expression.ExtractCorColumns(item.Expr)...)\n\t}\n\treturn corCols\n}\n\n// LogicalLimit represents offset and limit plan.\ntype LogicalLimit struct {\n\tbaseLogicalPlan\n\n\tOffset uint64\n\tCount  uint64\n}\n\n// LogicalUnionAll represents LogicalUnionAll plan.\ntype LogicalUnionAll struct {\n\tlogicalSchemaProducer\n}\n\n// ShowContents stores the contents for the `SHOW` statement.\ntype ShowContents struct {\n\tTp        ast.ShowStmtType // Databases/Tables/Columns/....\n\tDBName    string\n\tTable     *ast.TableName  // Used for showing columns.\n\tColumn    *ast.ColumnName // Used for `desc table column`.\n\tIndexName model.CIStr\n\tFlag      int                  // Some flag parsed from sql, such as FULL.\n\tUser      *auth.UserIdentity   // Used for show grants.\n\tRoles     []*auth.RoleIdentity // Used for show grants.\n\n\tFull        bool\n\tIfNotExists bool // Used for `show create database if not exists`.\n\tGlobalScope bool // Used by show variables.\n\tExtended    bool // Used for `show extended columns from ...`\n}\n\n// LogicalShow represents a show plan.\ntype LogicalShow struct {\n\tlogicalSchemaProducer\n\tShowContents\n}\n\n// WindowFrame represents a window function frame.\ntype WindowFrame struct {\n\tType  ast.FrameType\n\tStart *FrameBound\n\tEnd   *FrameBound\n}\n\n// FrameBound is the boundary of a frame.\ntype FrameBound struct {\n\tType      ast.BoundType\n\tUnBounded bool\n\tNum       uint64\n\t// CalcFuncs is used for range framed windows.\n\t// We will build the date_add or date_sub functions for frames like `INTERVAL '2:30' MINUTE_SECOND FOLLOWING`,\n\t// and plus or minus for frames like `1 preceding`.\n\tCalcFuncs []expression.Expression\n\t// CmpFuncs is used to decide whether one row is included in the current frame.\n\tCmpFuncs []expression.CompareFunc\n}\n\n// LogicalTableDual represents a dual table plan.\ntype LogicalTableDual struct {\n\tlogicalSchemaProducer\n\n\tRowCount int\n}\n\n// LogicalWindow represents a logical window function plan.\ntype LogicalWindow struct {\n\tlogicalSchemaProducer\n\n\tWindowFuncDescs []*aggregation.WindowFuncDesc\n\tPartitionBy     []property.Item\n\tOrderBy         []property.Item\n\tFrame           *WindowFrame\n}\n\n// GetWindowResultColumns returns the columns storing the result of the window function.\nfunc (p *LogicalWindow) GetWindowResultColumns() []*expression.Column {\n\treturn p.schema.Columns[p.schema.Len()-len(p.WindowFuncDescs):]\n}\n"
  },
  {
    "path": "pkg/planner/core/logicalplan_to_stmt.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"fmt\"\n\n\t\"slices\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n)\n\nfunc (p *DataSource) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\tc := NewRunSqlCtx()\n\ttableName := ast.TableName{Schema: p.DBName, Name: p.tableInfo.Name}\n\tfrom := &ast.TableRefsClause{TableRefs: &ast.Join{Left: &ast.TableSource{Source: &tableName, AsName: *p.TableAsName}}}\n\ttableAsName := *p.TableAsName\n\terr := c.updateExprNodeFromColumns(d, p.logicalSchemaProducer.Schema().Columns)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.updateTableRefs([]string{fmt.Sprintf(\"%s.%s\", p.DBName, p.tableInfo.Name)})\n\tc.updateTableAsName(tableAsName)\n\tc.setFrom(from)\n\treturn c, err\n}\n\nfunc (p *LogicalProjection) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\tc, err := BuildChildCtx(d, p.Children()[0])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewCtx, err := c.addClause(ClauseProjection)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t_, err = newCtx.updateExprNodeFromExpressions(d, p.Exprs, p.logicalSchemaProducer.Schema().Columns)\n\treturn newCtx, err\n}\n\nfunc (p *LogicalSelection) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\tc, err := BuildChildCtx(d, p.Children()[0])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// empty selection, due to group by threshold is 1\n\tif len(p.Conditions) == 0 {\n\t\treturn c, nil\n\t}\n\tif slices.Contains(c.clauses, ClauseAggregate) {\n\t\tc, err = c.addClause(ClauseHaving)\n\t} else {\n\t\tc, err = c.addClause(ClauseWhere)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcondExprs, err := c.updateExprNodeFromExpressions(d, p.Conditions, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tCNFExpr := composeCNFCondition(condExprs)\n\tif slices.Contains(c.clauses, ClauseAggregate) {\n\t\tc.setHaving(CNFExpr)\n\t} else {\n\t\tc.setWhere(CNFExpr)\n\t}\n\treturn c, nil\n}\n\nfunc (p *LogicalJoin) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\tswitch p.JoinType {\n\tcase SemiJoin, AntiSemiJoin, AntiLeftOuterSemiJoin, LeftOuterSemiJoin:\n\t\treturn SemiJoinToSqlStmt(p, d)\n\tcase LeftOuterJoin, RightOuterJoin, InnerJoin:\n\t\treturn JoinSqlStmt(p, d)\n\t}\n\treturn nil, fmt.Errorf(\"unsupported join type %d\", p.JoinType)\n}\n\n// SemiJoinToSqlStmt converts a LogicalJoin of type\n// SemiJoin/AntiSemiJoin/AntiLeftOuterSemiJoin/LeftOuterSemiJoin to a SQL statement.\nfunc SemiJoinToSqlStmt(p *LogicalJoin, d Dialect) (*runSqlCtx, error) {\n\tvar result []*runSqlCtx\n\tfor _, child := range p.Children() {\n\t\tc, err := BuildChildCtx(d, child)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult = append(result, c)\n\t}\n\tctx := result[0]\n\tctx.updateTableRefs(result[1].GetTableRefs())\n\tcolumns := p.logicalSchemaProducer.Schema().Columns\n\terr := ctx.updateExprNodeFromColumns(d, columns[:len(columns)-1])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// If it's generated from an in operator, translate to in expression\n\t// In other cases, translate to ExistsSubqueryExpr\n\tinScalarFunc := []*expression.ScalarFunction{}\n\totherExprs := []expression.Expression{}\n\n\tsplitExpr := func(cond expression.Expression) {\n\t\tif sfunc, ok := cond.(*expression.ScalarFunction); ok {\n\t\t\t// If it's an eq function and both arguments are in operand columns, translate to in expression\n\t\t\tif sfunc.FuncName.L == ast.EQ {\n\t\t\t\tc1, ok1 := sfunc.GetArgs()[0].(*expression.Column)\n\t\t\t\tc2, ok2 := sfunc.GetArgs()[1].(*expression.Column)\n\t\t\t\tif ok1 && ok2 && (c1.InOperand || c2.InOperand) {\n\t\t\t\t\tinScalarFunc = append(inScalarFunc, sfunc)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\totherExprs = append(otherExprs, cond)\n\t}\n\n\tfor _, condition := range p.EqualConditions {\n\t\tsplitExpr(condition)\n\t}\n\tfor _, condition := range p.OtherConditions {\n\t\tsplitExpr(condition)\n\t}\n\tinExprNodes := []ast.ExprNode{}\n\tfor _, sfunc := range inScalarFunc {\n\t\targs, err := ctx.updateExprNodeFromExpressions(d, []expression.Expression{sfunc.GetArgs()[0]}, nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tss, err := result[1].GetSQLStmt()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tinExpr := &ast.PatternInExpr{Expr: args[0], Sel: &ast.SubqueryExpr{Query: ss}, Not: p.JoinType == AntiSemiJoin || p.JoinType == AntiLeftOuterSemiJoin}\n\t\tinExprNodes = append(inExprNodes, inExpr)\n\t}\n\tif len(otherExprs) > 0 {\n\t\tresult[1].mergeFieldsName(result[0])\n\t\totherExprNodes, err := result[1].updateExprNodeFromExpressions(d, otherExprs, nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcondExpr := composeCNFCondition(otherExprNodes)\n\t\tif slices.Contains(result[1].clauses, ClauseWhere) {\n\t\t\tresult[1].setWhere(composeCNFCondition([]ast.ExprNode{result[1].selectStmt.Where, condExpr}))\n\t\t} else {\n\t\t\tresult[1].setWhere(condExpr)\n\t\t}\n\t\tss, err := result[1].GetSQLStmt()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcondExpr = &ast.ExistsSubqueryExpr{Sel: &ast.SubqueryExpr{Query: ss}, Not: p.JoinType == AntiSemiJoin || p.JoinType == AntiLeftOuterSemiJoin}\n\t\tinExprNodes = append(inExprNodes, condExpr)\n\t}\n\tcondExpr := composeCNFCondition(inExprNodes)\n\tswitch p.JoinType {\n\tcase SemiJoin, AntiSemiJoin:\n\t\tif slices.Contains(ctx.clauses, ClauseWhere) {\n\t\t\tctx.selectStmt.Where = composeCNFCondition([]ast.ExprNode{ctx.selectStmt.Where, condExpr})\n\t\t} else {\n\t\t\tctx.setWhere(condExpr)\n\t\t}\n\tcase AntiLeftOuterSemiJoin, LeftOuterSemiJoin:\n\t\tctx.colIdToExprNode[columns[len(columns)-1].UniqueID] = condExpr\n\t}\n\treturn ctx, nil\n}\n\nfunc JoinSqlStmt(p *LogicalJoin, d Dialect) (*runSqlCtx, error) {\n\tjoinStmt := &ast.Join{}\n\tswitch p.JoinType {\n\tcase InnerJoin:\n\t\tjoinStmt.Tp = ast.CrossJoin\n\tcase LeftOuterJoin:\n\t\tjoinStmt.Tp = ast.LeftJoin\n\tcase RightOuterJoin:\n\t\tjoinStmt.Tp = ast.RightJoin\n\tdefault:\n\t\t// for now only support join/left join/right join\n\t\treturn nil, fmt.Errorf(\"unsupported join type %d\", p.JoinType)\n\t}\n\n\tnewCtx := NewRunSqlCtx()\n\tvar results []ast.ResultSetNode\n\tfor i, child := range p.Children() {\n\t\tc, err := BuildChildCtx(d, child)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnewCtx.updateTableRefs(c.tableRefs)\n\t\tif t, ok := stripAsTbl(c); ok {\n\t\t\tresults = append(results, t)\n\t\t\tfor id, expr := range c.colIdToExprNode {\n\t\t\t\tnewCtx.colIdToExprNode[id] = expr\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tss, err := c.GetSQLStmt()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsubTable := ast.TableSource{Source: ss, AsName: createAsTable(&p.logicalSchemaProducer, i)}\n\t\tc.tableAsName = subTable.AsName\n\t\tnewCtx.UpdateFieldsName(c)\n\t\tresults = append(results, &subTable)\n\t}\n\tjoinStmt.Left, joinStmt.Right = results[0], results[1]\n\t// update on conditions\n\tvar conditions []expression.Expression\n\tfor _, condition := range p.EqualConditions {\n\t\tconditions = append(conditions, condition)\n\t}\n\tconds, err := newCtx.updateExprNodeFromExpressions(d, conditions, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// size of conds is zero means it's cross join\n\tif len(conds) > 0 {\n\t\tjoinStmt.On = &ast.OnCondition{Expr: composeCNFCondition(conds)}\n\t}\n\tnewCtx.setFrom(&ast.TableRefsClause{TableRefs: joinStmt})\n\treturn newCtx, nil\n}\n\nfunc (p *LogicalUnionAll) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\tunionStmt := ast.UnionStmt{SelectList: &ast.UnionSelectList{Selects: make([]*ast.SelectStmt, len(p.Children()))}}\n\tnewCtx := NewRunSqlCtx()\n\tfor i, child := range p.Children() {\n\t\tc, err := BuildChildCtx(d, child)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnewCtx.updateTableRefs(c.tableRefs)\n\t\tss, err := c.GetSQLStmt()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tss.IsInBraces = true\n\t\tunionStmt.SelectList.Selects[i] = ss\n\t\tif i == 0 {\n\t\t\tnewCtx.UpdateFieldsName(c)\n\t\t}\n\t}\n\ttableAsName := createAsTable(&p.logicalSchemaProducer, 0)\n\tnewCtx.updateTableAsName(tableAsName)\n\tnewCtx.setFrom(&ast.TableRefsClause{TableRefs: &ast.Join{Left: &ast.TableSource{Source: &unionStmt, AsName: tableAsName}}})\n\treturn newCtx, nil\n}\n\nfunc (p *LogicalLimit) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\tc, err := BuildChildCtx(d, p.Children()[0])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc, err = c.addClause(ClauseLimit)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.setLimit(p.Count, p.Offset)\n\treturn c, nil\n}\n\nfunc (p *LogicalSort) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\tc, err := BuildChildCtx(d, p.Children()[0])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc, err = c.addClause(ClauseOrderby)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar expressions []expression.Expression\n\tfor _, byItem := range p.ByItems {\n\t\texpressions = append(expressions, byItem.Expr)\n\t}\n\titems, err := c.updateExprNodeFromExpressions(d, expressions, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar byItems []*ast.ByItem\n\tfor i, item := range items {\n\t\tbyItems = append(byItems, &ast.ByItem{Expr: item, Desc: p.ByItems[i].Desc})\n\t}\n\tc.setOrderBy(byItems)\n\treturn c, nil\n}\nfunc (p *LogicalWindow) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\tc, err := BuildChildCtx(d, p.Children()[0])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc, err = c.addClause(ClauseWindow)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar partitionByCols []expression.Expression\n\tfor _, item := range p.PartitionBy {\n\t\tpartitionByCols = append(partitionByCols, item.Col)\n\t}\n\tupdatedPartitionItems, err := c.updateExprNodeFromExpressions(d, partitionByCols, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar partitionByItems []*ast.ByItem\n\tfor _, item := range updatedPartitionItems {\n\t\tpartitionByItems = append(partitionByItems, &ast.ByItem{Expr: item})\n\t}\n\tvar orderByCols []expression.Expression\n\tvar desc []bool\n\tfor _, item := range p.OrderBy {\n\t\torderByCols = append(orderByCols, item.Col)\n\t\tdesc = append(desc, item.Desc)\n\t}\n\tupdatedOrderByItems, err := c.updateExprNodeFromExpressions(d, orderByCols, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar orderByItems []*ast.ByItem\n\tfor i, item := range updatedOrderByItems {\n\t\torderByItems = append(orderByItems, &ast.ByItem{Expr: item, Desc: desc[i]})\n\t}\n\tif len(p.WindowFuncDescs) != 1 {\n\t\treturn nil, fmt.Errorf(\"expect 1 window spec but get %v\", len(p.WindowFuncDescs))\n\t}\n\tvar spec ast.WindowSpec\n\tspec.OrderBy = &ast.OrderByClause{\n\t\tItems: orderByItems,\n\t}\n\tspec.PartitionBy = &ast.PartitionByClause{\n\t\tItems: partitionByItems,\n\t}\n\tc.convertWindowFunc(p, spec)\n\treturn c, nil\n}\n\nfunc (p *LogicalAggregation) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\tc, err := BuildChildCtx(d, p.Children()[0])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc, err = c.addClause(ClauseAggregate)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\titems, err := c.updateExprNodeFromExpressions(d, p.GroupByItems, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar byItems []*ast.ByItem\n\tfor _, item := range items {\n\t\tbyItems = append(byItems, &ast.ByItem{Expr: item})\n\t}\n\tc.setGroupBY(byItems)\n\terr = c.convertAggregateFunc(d, p)\n\treturn c, err\n}\n\nfunc (p *LogicalMaxOneRow) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\tc, err := BuildChildCtx(d, p.Children()[0])\n\treturn c, err\n}\n"
  },
  {
    "path": "pkg/planner/core/logicalplan_to_stmt_helper.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n)\n\ntype ClauseType int\n\nconst (\n\t// table source includes join, union, table\n\tClauseTableSource ClauseType = iota\n\tClauseWhere\n\tClauseAggregate\n\tClauseHaving\n\tClauseWindow\n\tClauseProjection\n\tClauseOrderby\n\tClauseLimit\n)\n\ntype runSqlCtx struct {\n\texprConverter   *expression.ExprConverter\n\tcolIdToExprNode map[int64]ast.ExprNode\n\tselectStmt      *ast.SelectStmt\n\tschemaProducer  *logicalSchemaProducer\n\tstoredClause    map[ClauseType]LogicalPlan\n\tclauses         []ClauseType\n\ttableAsName     model.CIStr\n\ttableRefs       []string\n}\n\nfunc NewRunSqlCtx() *runSqlCtx {\n\treturn &runSqlCtx{\n\t\texprConverter:   &expression.ExprConverter{},\n\t\tcolIdToExprNode: make(map[int64]ast.ExprNode),\n\t\tselectStmt:      &ast.SelectStmt{},\n\t\tstoredClause:    make(map[ClauseType]LogicalPlan),\n\t}\n}\n\nfunc BuildChildCtx(d Dialect, in LogicalPlan) (*runSqlCtx, error) {\n\texpectChildNumber := 1\n\tswitch in.(type) {\n\tcase *LogicalJoin, *LogicalApply:\n\t\texpectChildNumber = 2\n\tcase *DataSource:\n\t\texpectChildNumber = 0\n\tcase *LogicalUnionAll:\n\t\texpectChildNumber = -1\n\t}\n\tif expectChildNumber != -1 && len(in.Children()) != expectChildNumber {\n\t\treturn nil, fmt.Errorf(\"%T: invalid children number %d != %d\", in, len(in.Children()), expectChildNumber)\n\t}\n\tctx, err := in.SqlStmt(d)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif producer := getSchemaProducer(in); producer != nil {\n\t\tctx.schemaProducer = producer\n\t}\n\treturn ctx, nil\n}\n\nfunc getSchemaProducer(in LogicalPlan) *logicalSchemaProducer {\n\tswitch x := in.(type) {\n\tcase *LogicalJoin:\n\t\treturn &x.logicalSchemaProducer\n\tcase *LogicalUnionAll:\n\t\treturn &x.logicalSchemaProducer\n\tcase *DataSource:\n\t\treturn &x.logicalSchemaProducer\n\tcase *LogicalAggregation:\n\t\treturn &x.logicalSchemaProducer\n\tcase *LogicalWindow:\n\t\treturn &x.logicalSchemaProducer\n\tcase *LogicalProjection:\n\t\treturn &x.logicalSchemaProducer\n\tcase *LogicalSelection:\n\t\treturn &x.logicalSchemaProducer\n\t}\n\treturn nil\n}\n\nfunc (ctx *runSqlCtx) updateTableAsNameIfNeed(p *logicalSchemaProducer) {\n\tif ctx.tableAsName.String() == \"\" {\n\t\tctx.tableAsName = createAsTable(p, 0)\n\t\tctx.updateTableAsName(ctx.tableAsName)\n\t}\n}\n\nfunc (c *runSqlCtx) GetSQLStmt() (*ast.SelectStmt, error) {\n\tif c.schemaProducer == nil {\n\t\treturn nil, fmt.Errorf(\"failed to find schema producer\")\n\t}\n\tp := c.schemaProducer\n\tnamesLen := len(p.names)\n\tfields := &ast.FieldList{Fields: make([]*ast.SelectField, len(p.Schema().Columns))}\n\tfor i, col := range p.Schema().Columns {\n\t\tif col.IsHidden {\n\t\t\treturn nil, fmt.Errorf(\"col(%+v) is hidden\", col)\n\t\t}\n\t\tf := &ast.SelectField{}\n\t\tif expr, ok := c.colIdToExprNode[col.UniqueID]; !ok {\n\t\t\treturn nil, fmt.Errorf(\"failed to find expr for column unique id %d\", col.UniqueID)\n\t\t} else {\n\t\t\tf.Expr = expr\n\t\t}\n\t\tfields.Fields[i] = f\n\t\tif i >= namesLen {\n\t\t\taddAsNameForNonColumnName(f, col.UniqueID)\n\t\t\tcontinue\n\t\t}\n\t\tname := p.names[i]\n\t\t// For logical union all, name.OrigColName may be nil, we should catch this case\n\t\tif colName, ok := f.Expr.(*ast.ColumnNameExpr); ok {\n\t\t\t// skip to avoid 'a' as 'a'\n\t\t\tif name.OrigColName.String() == \"\" && colName.Name.Name.String() == name.ColName.String() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tif name.ColName.String() != \"\" &&\n\t\t\tname.OrigColName.String() != name.ColName.String() {\n\t\t\tf.AsName = name.ColName\n\t\t\tcontinue\n\t\t}\n\t\taddAsNameForNonColumnName(f, col.UniqueID)\n\t}\n\tc.selectStmt.Fields = fields\n\treturn c.selectStmt, nil\n}\n\nfunc (c *runSqlCtx) GetTableRefs() []string {\n\treturn c.tableRefs\n}\n\nfunc (c *runSqlCtx) setFrom(from *ast.TableRefsClause) {\n\tc.clauses = append(c.clauses, ClauseTableSource)\n\tc.selectStmt.From = from\n}\n\nfunc (c *runSqlCtx) setWhere(where ast.ExprNode) {\n\tc.selectStmt.Where = where\n}\n\nfunc (c *runSqlCtx) setGroupBY(byItems []*ast.ByItem) {\n\tif len(byItems) > 0 {\n\t\tc.selectStmt.GroupBy = &ast.GroupByClause{Items: byItems}\n\t}\n}\n\nfunc (c *runSqlCtx) setHaving(having ast.ExprNode) {\n\tc.selectStmt.Having = &ast.HavingClause{Expr: having}\n}\n\nfunc (c *runSqlCtx) setLimit(count uint64, offset uint64) {\n\tif offset == 0 {\n\t\tc.selectStmt.Limit = &ast.Limit{Count: ast.NewValueExpr(count)}\n\t} else {\n\t\tc.selectStmt.Limit = &ast.Limit{Count: ast.NewValueExpr(count), Offset: ast.NewValueExpr(offset)}\n\t}\n}\n\nfunc (c *runSqlCtx) setOrderBy(byItems []*ast.ByItem) {\n\tc.selectStmt.OrderBy = &ast.OrderByClause{Items: byItems}\n}\n\nfunc (c *runSqlCtx) updateExprNodeFromColumns(d Dialect, columns []*expression.Column) error {\n\tfor _, col := range columns {\n\t\tif col.IsHidden {\n\t\t\tcontinue\n\t\t}\n\t\texpr, err := c.exprConverter.ConvertExpressionToExprNode(d.GetFormatDialect(), col, 0, c.colIdToExprNode)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tc.colIdToExprNode[col.UniqueID] = expr\n\t}\n\treturn nil\n}\n\n// cases for sub query\n// 1. replicated clauses\n// 2. when current clause type < any clause type in stored clauses\nfunc (ctx *runSqlCtx) needAsSub(c ClauseType) bool {\n\tfor _, t := range ctx.clauses {\n\t\tif c == ClauseTableSource && len(ctx.clauses) == 1 && ctx.clauses[0] == ClauseTableSource {\n\t\t\treturn true\n\t\t}\n\t\tif c <= t {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (ctx *runSqlCtx) addClause(c ClauseType) (newCtx *runSqlCtx, err error) {\n\tnewCtx = ctx\n\tif ctx.needAsSub(c) {\n\t\tnewCtx, err = ctx.WorkAsSub()\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tnewCtx.clauses = append(newCtx.clauses, ClauseTableSource)\n\t\tnewCtx.updateTableRefs(ctx.tableRefs)\n\t}\n\tnewCtx.clauses = append(newCtx.clauses, c)\n\tnewCtx.clauses = sliceutil.SliceDeDup(newCtx.clauses)\n\treturn\n}\n\nfunc (c *runSqlCtx) updateTableRefs(refs []string) {\n\tc.tableRefs = append(c.tableRefs, refs...)\n\tc.tableRefs = sliceutil.SliceDeDup(c.tableRefs)\n}\n\nfunc (c *runSqlCtx) UpdateFieldsName(oldCtx *runSqlCtx) {\n\tfor i, col := range oldCtx.schemaProducer.Schema().Columns {\n\t\tfield := oldCtx.selectStmt.Fields.Fields[i]\n\t\tif field.AsName.String() != \"\" {\n\t\t\tc.colIdToExprNode[col.UniqueID] = &ast.ColumnNameExpr{Name: &ast.ColumnName{Table: oldCtx.tableAsName, Name: field.AsName}}\n\t\t\tcontinue\n\t\t}\n\t\tif colName, ok := field.Expr.(*ast.ColumnNameExpr); ok {\n\t\t\tc.colIdToExprNode[col.UniqueID] = &ast.ColumnNameExpr{Name: &ast.ColumnName{Table: oldCtx.tableAsName, Name: colName.Name.Name}}\n\t\t}\n\t}\n}\n\nfunc (c *runSqlCtx) mergeFieldsName(ctx *runSqlCtx) {\n\tfor _, col := range ctx.schemaProducer.Schema().Columns {\n\t\tc.colIdToExprNode[col.UniqueID] = ctx.colIdToExprNode[col.UniqueID]\n\t}\n}\n\nfunc (c *runSqlCtx) WorkAsSub() (*runSqlCtx, error) {\n\tss, err := c.GetSQLStmt()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// create table as name after creating sub query\n\tc.updateTableAsNameIfNeed(nil)\n\tnewCtx := NewRunSqlCtx()\n\tnewCtx.selectStmt.From = &ast.TableRefsClause{TableRefs: &ast.Join{Left: &ast.TableSource{Source: ss, AsName: c.tableAsName}}}\n\tnewCtx.addClause(ClauseTableSource)\n\tnewCtx.UpdateFieldsName(c)\n\treturn newCtx, nil\n}\n\nfunc (c *runSqlCtx) updateExprNodeFromExpressions(d Dialect, exprs []expression.Expression, columns []*expression.Column) ([]ast.ExprNode, error) {\n\tvar exprStmts []ast.ExprNode\n\tfor i, expr := range exprs {\n\t\texprStmt, err := c.exprConverter.ConvertExpressionToExprNode(d.GetFormatDialect(), expr, 0, c.colIdToExprNode)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif columns != nil {\n\t\t\tc.colIdToExprNode[columns[i].UniqueID] = exprStmt\n\t\t}\n\t\texprStmts = append(exprStmts, exprStmt)\n\t}\n\treturn exprStmts, nil\n}\n\nfunc (c *runSqlCtx) convertWindowFunc(window *LogicalWindow, spec ast.WindowSpec) {\n\tcolumns := window.Schema().Columns\n\tlastCol := columns[len(columns)-1]\n\twindowDesc := window.WindowFuncDescs[0]\n\tc.colIdToExprNode[lastCol.UniqueID] = &ast.WindowFuncExpr{\n\t\tF:    windowDesc.Name,\n\t\tSpec: spec,\n\t}\n}\n\nfunc (c *runSqlCtx) convertAggregateFunc(d Dialect, agg *LogicalAggregation) error {\n\tfor i, col := range agg.Schema().Columns {\n\t\tf := agg.AggFuncs[i]\n\t\targExpr, err := c.updateExprNodeFromExpressions(d, f.Args, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif f.Name == ast.AggFuncFirstRow {\n\t\t\tif d.SupportAnyValue() {\n\t\t\t\tc.colIdToExprNode[col.UniqueID] = &ast.AggregateFuncExpr{Args: argExpr, F: \"any_value\", Distinct: f.HasDistinct}\n\t\t\t} else {\n\t\t\t\tc.colIdToExprNode[col.UniqueID] = argExpr[0]\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tc.colIdToExprNode[col.UniqueID] = &ast.AggregateFuncExpr{Args: argExpr, F: f.Name, Distinct: f.HasDistinct}\n\t}\n\treturn nil\n}\n\nfunc (c *runSqlCtx) updateTableAsName(tableAsName model.CIStr) {\n\tif tableAsName.String() == \"\" {\n\t\treturn\n\t}\n\tfor id, expr := range c.colIdToExprNode {\n\t\tif col, ok := expr.(*ast.ColumnNameExpr); ok {\n\t\t\tc.colIdToExprNode[id] = &ast.ColumnNameExpr{Name: &ast.ColumnName{Table: tableAsName, Name: col.Name.Name}}\n\t\t}\n\t}\n}\n\nfunc stripAsTbl(ctx *runSqlCtx) (*ast.TableSource, bool) {\n\tif len(ctx.clauses) != 1 || ctx.clauses[0] != ClauseTableSource {\n\t\treturn nil, false\n\t}\n\tfrom := ctx.selectStmt.From\n\tif from == nil || from.TableRefs == nil {\n\t\treturn nil, false\n\t}\n\tif from.TableRefs.Right != nil {\n\t\treturn nil, false\n\t}\n\tif source, ok := from.TableRefs.Left.(*ast.TableSource); !ok {\n\t\treturn nil, false\n\t} else {\n\t\tif _, ok := source.Source.(*ast.TableName); !ok {\n\t\t\treturn nil, false\n\t\t} else {\n\t\t\treturn source, true\n\t\t}\n\t}\n}\n\nfunc composeCNFCondition(conds []ast.ExprNode) ast.ExprNode {\n\tvar result ast.ExprNode\n\tfor i, expr := range conds {\n\t\tif i == 0 {\n\t\t\tresult = conds[0]\n\t\t\tcontinue\n\t\t}\n\t\tresult = &ast.BinaryOperationExpr{Op: opcode.LogicAnd, L: &ast.ParenthesesExpr{Expr: result}, R: &ast.ParenthesesExpr{Expr: expr}}\n\t}\n\treturn result\n}\n\n// get table as name\nfunc getOriginAsName(p *logicalSchemaProducer, colIndex int) (model.CIStr, bool) {\n\tif p == nil {\n\t\treturn model.CIStr{}, false\n\t}\n\tif colIndex >= len(p.names) || colIndex < 0 {\n\t\treturn model.CIStr{}, false\n\t}\n\tif p.names[colIndex].TblName.O != \"\" &&\n\t\tp.names[colIndex].TblName.O != p.names[colIndex].OrigTblName.O {\n\t\treturn p.names[colIndex].TblName, true\n\t}\n\n\treturn model.CIStr{}, false\n}\n\n// common case for subquery\n// sometimes table need as name, if the table don't rename in logical plan, use this function creating table as name\n// special case for join\n// join plan has two children, columns from left children locate in left half of p.names, columns from right children locate in right half of p.names\n// Note: length of p.names may not equal to length of p.schema.columns due to column pruning\nfunc createAsTable(p *logicalSchemaProducer, childIndex int) model.CIStr {\n\t// if childIndex != 0, means right child of logical join\n\tleft := childIndex == 0\n\n\tif p != nil {\n\t\tcolIndex := 0\n\t\tif !left {\n\t\t\tcolIndex = len(p.names) - 1\n\t\t}\n\t\ttableAsName, found := getOriginAsName(p, colIndex)\n\t\tif found {\n\t\t\treturn tableAsName\n\t\t}\n\t}\n\treturn model.CIStr{L: fmt.Sprintf(\"t_%d\", childIndex), O: fmt.Sprintf(\"t_%d\", childIndex)}\n}\n\nfunc addAsNameForNonColumnName(f *ast.SelectField, uniqueID int64) {\n\tif _, ok := f.Expr.(*ast.ColumnNameExpr); !ok {\n\t\tf.AsName = model.NewCIStr(fmt.Sprintf(\"expr_%d\", uniqueID))\n\t}\n}\n"
  },
  {
    "path": "pkg/planner/core/logicalplan_to_stmt_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\n\t. \"github.com/pingcap/check\"\n\t\"github.com/pingcap/log\"\n\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/util/mock\"\n\t\"github.com/secretflow/scql/pkg/util/testleak\"\n\t\"github.com/secretflow/scql/pkg/util/testutil\"\n\n\t// NOTE(yang.y): import parser_driver so that ast.NewValueExpr\n\t// https://github.com/pingcap/parser/blob/a9496438d77d525d8759e0103f6eca40ce1d2788/ast/expressions.go#L66\n\t// is initialized.\n\n\t_ \"github.com/secretflow/scql/pkg/types/parser_driver\"\n)\n\nvar _ = Suite(&testRunSQLSuite{})\nvar testBackEnds = []string{MySQL, Postgres, ODPS, CSV}\n\nconst (\n\tMySQL    = \"MYSQL\"\n\tPostgres = \"POSTGRESQL\"\n\tODPS     = \"ODPS\"\n\tCSV      = \"CSVDB\"\n)\n\ntype testRunSQLSuite struct {\n\t*parser.Parser\n\n\tis  infoschema.InfoSchema\n\tctx sessionctx.Context\n\n\ttestData testutil.TestData\n}\n\ntype TestCaseSqlString struct {\n\tSql               string `json:\"sql\"`\n\tSkipProjection    bool   `json:\"skip_projection\"`\n\tRewrittenSqlODPS  string `json:\"rewritten_sql_odps,omitempty\"`\n\tRewrittenSqlMysql string `json:\"rewritten_sql_mysql,omitempty\"`\n\tRewrittenSqlPg    string `json:\"rewritten_sql_pg,omitempty\"`\n\tRewrittenSqlCSV   string `json:\"rewritten_sql_csv,omitempty\"`\n\tSkipOdpsTest      bool   `json:\"skip_odps_test,omitempty\"`\n\tSkipPgTest        bool   `json:\"skip_pg_test,omitempty\"`\n\tSkipCSVTest       bool   `json:\"skip_csv_test,omitempty\"`\n\t// default; if RewrittenSql set, all back ends use this sql as default\n\tRewrittenSql string `json:\"rewritten_sql\"`\n}\n\nfunc (s *testRunSQLSuite) SetUpSuite(c *C) {\n\tmockTables, err := mock.MockAllTables()\n\tc.Assert(err, IsNil)\n\ts.is = infoschema.MockInfoSchema(mockTables)\n\ts.ctx = mock.MockContext()\n\ts.Parser = parser.New()\n\tc.Assert(err, IsNil)\n\n\t// SkipOutJson is no longer needed - the system automatically detects based on file existence\n\n\ts.testData, err = testutil.LoadTestSuiteData(\"testdata\", \"runsql\")\n\tc.Assert(err, IsNil)\n}\n\nfunc (s *testRunSQLSuite) TearDownSuite(c *C) {\n\tc.Assert(s.testData.GenerateOutputIfNeeded(), IsNil)\n}\n\nfunc (s *testRunSQLSuite) TestRunSQL(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tvar input []TestCaseSqlString\n\ts.testData.GetTestCasesWithoutOut(c, &input)\n\tfor i := range input {\n\t\ts.testRunSQL(c, &input[i])\n\t}\n}\n\ntype rewriteCase struct {\n\toriginSql  string\n\trewriteSql string\n}\n\nfunc (s *testRunSQLSuite) TestRewriteSQLWithDomainDataId(c *C) {\n\tdefer testleak.AfterTest(c)()\n\n\tcases := []rewriteCase{\n\t\t{\n\t\t\toriginSql:  \"select plain_int_0 from bob.tbl_0\",\n\t\t\trewriteSql: `select \"usercredit-0afb3b4c-d160-4050-b71a-c6674a11d2f9\".\"plain_int_0\" from \"usercredit-0afb3b4c-d160-4050-b71a-c6674a11d2f9\";`,\n\t\t},\n\t\t{\n\t\t\toriginSql:  \"select distinct t0.plain_int_0, t0.groupby_float_0 from bob.tbl_0 as t0 join bob.tbl_1 as t1 where t0.join_string_0=t1.join_string_0\",\n\t\t\trewriteSql: `select \"t0\".\"plain_int_0\",\"t0\".\"groupby_float_0\" from \"usercredit-0afb3b4c-d160-4050-b71a-c6674a11d2f9\" as \"t0\" join \"domain-data-id-as-table-name\" as \"t1\" on \"t0\".\"join_string_0\"=\"t1\".\"join_string_0\" group by \"t0\".\"plain_int_0\",\"t0\".\"groupby_float_0\";`,\n\t\t},\n\t}\n\n\tfor _, ca := range cases {\n\t\tstmt, err := s.ParseOneStmt(ca.originSql, \"\", \"\")\n\t\tcomment := Commentf(\"for test: %s\\n\", ca.originSql)\n\t\tc.Assert(err, IsNil, comment)\n\n\t\terr = Preprocess(s.ctx, stmt, s.is)\n\t\tc.Assert(err, IsNil, comment)\n\n\t\tlp, _, err := BuildLogicalPlanWithOptimization(context.Background(), s.ctx, stmt, s.is)\n\t\tc.Assert(err, IsNil, comment)\n\n\t\tm := make(map[DbTable]DbTable)\n\t\tref0 := NewDbTable(\"\", \"usercredit-0afb3b4c-d160-4050-b71a-c6674a11d2f9\")\n\t\tref0.SetDBType(DBTypeCSVDB)\n\t\tm[NewDbTable(\"bob\", \"tbl_0\")] = ref0\n\t\tref1 := NewDbTable(\"\", \"domain-data-id-as-table-name\")\n\t\tref1.SetDBType(DBTypeCSVDB)\n\t\tm[NewDbTable(\"bob\", \"tbl_1\")] = ref1\n\t\tactual, _, err := RewriteSQLFromLP(lp, m, true)\n\t\tc.Assert(err, IsNil, comment)\n\t\tcomment = Commentf(\"for test: %s\\n expect: %s\\n actual: %s\", ca.originSql, ca.rewriteSql, actual)\n\t\tc.Assert(actual == ca.rewriteSql, IsTrue, comment)\n\t}\n}\n\nfunc GetExpectSQL(backEnd string, testCase TestCaseSqlString) string {\n\tif backEnd == MySQL {\n\t\tif testCase.RewrittenSqlMysql != \"\" {\n\t\t\treturn testCase.RewrittenSqlMysql\n\t\t}\n\t}\n\tif backEnd == Postgres {\n\t\tif testCase.RewrittenSqlPg != \"\" {\n\t\t\treturn testCase.RewrittenSqlPg\n\t\t}\n\t}\n\tif backEnd == ODPS {\n\t\tif testCase.RewrittenSqlODPS != \"\" {\n\t\t\treturn testCase.RewrittenSqlODPS\n\t\t}\n\t}\n\tif backEnd == CSV {\n\t\tif testCase.RewrittenSqlCSV != \"\" {\n\t\t\treturn testCase.RewrittenSqlCSV\n\t\t}\n\t}\n\treturn testCase.RewrittenSql\n}\n\nfunc SkipTestFor(backEnd string, testCase TestCaseSqlString) bool {\n\tswitch backEnd {\n\tcase MySQL:\n\t\treturn false\n\tcase Postgres:\n\t\treturn testCase.SkipPgTest\n\tcase ODPS:\n\t\treturn testCase.SkipOdpsTest\n\tcase CSV:\n\t\treturn testCase.SkipCSVTest\n\t}\n\treturn false\n}\n\nfunc (s *testRunSQLSuite) testRunSQL(c *C, testCase *TestCaseSqlString) {\n\tfor _, backEnd := range testBackEnds {\n\t\tif SkipTestFor(backEnd, *testCase) {\n\t\t\tcontinue\n\t\t}\n\t\texpect := GetExpectSQL(backEnd, *testCase)\n\t\tdbType, err := ParseDBType(backEnd)\n\t\tc.Assert(err, IsNil)\n\t\t// test mysql\n\t\tsql, err := regenerateSql(*testCase, s, DBDialectMap[dbType])\n\t\tcomment := Commentf(\"%s tests: for %+v\", backEnd, *testCase)\n\t\tlog.Info(sql)\n\t\tc.Assert(err, IsNil, comment)\n\n\t\t// When in record mode, update the expected SQL in the test case\n\t\tif testutil.IsRecording() {\n\t\t\tswitch backEnd {\n\t\t\tcase MySQL:\n\t\t\t\tif testCase.RewrittenSqlMysql != \"\" || testCase.RewrittenSql == \"\" {\n\t\t\t\t\ttestCase.RewrittenSqlMysql = sql\n\t\t\t\t} else {\n\t\t\t\t\ttestCase.RewrittenSql = sql\n\t\t\t\t}\n\t\t\tcase Postgres:\n\t\t\t\tif testCase.RewrittenSqlPg != \"\" || (testCase.RewrittenSql != \"\" && testCase.RewrittenSqlMysql != \"\") {\n\t\t\t\t\ttestCase.RewrittenSqlPg = sql\n\t\t\t\t}\n\t\t\tcase ODPS:\n\t\t\t\tif testCase.RewrittenSqlODPS != \"\" || (testCase.RewrittenSql != \"\" && testCase.RewrittenSqlMysql != \"\") {\n\t\t\t\t\ttestCase.RewrittenSqlODPS = sql\n\t\t\t\t}\n\t\t\tcase CSV:\n\t\t\t\tif testCase.RewrittenSqlCSV != \"\" || (testCase.RewrittenSql != \"\" && testCase.RewrittenSqlMysql != \"\") {\n\t\t\t\t\ttestCase.RewrittenSqlCSV = sql\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tc.Assert(expect == sql, IsTrue, comment)\n\t\t}\n\t}\n}\n\nfunc regenerateSql(testCase TestCaseSqlString, s *testRunSQLSuite, dialect Dialect) (string, error) {\n\tstmt, err := s.ParseOneStmt(testCase.Sql, \"\", \"\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\terr = Preprocess(s.ctx, stmt, s.is)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tlp, _, err := BuildLogicalPlanWithOptimization(context.Background(), s.ctx, stmt, s.is)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t// log.Info(ToString(lp))\n\tvar sqlCtx *runSqlCtx\n\tif testCase.SkipProjection {\n\t\tswitch p := lp.(type) {\n\t\tcase *LogicalProjection:\n\t\t\tsqlCtx, err = BuildChildCtx(dialect, p.Children()[0])\n\t\tdefault:\n\t\t\tsqlCtx, err = BuildChildCtx(dialect, p)\n\t\t}\n\t} else {\n\t\tsqlCtx, err = BuildChildCtx(dialect, lp)\n\t}\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tnewStmt, err := sqlCtx.GetSQLStmt()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t// StripFieldAsName(newStmt)\n\tb := new(bytes.Buffer)\n\tif err := newStmt.Restore(format.NewRestoreCtxWithDialect(format.RestoreStringSingleQuotes|format.RestoreKeyWordLowercase, b, dialect.GetFormatDialect())); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn b.String(), err\n}\n"
  },
  {
    "path": "pkg/planner/core/optimizer.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Modified by Ant Group in 2023\n\npackage core\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\nconst (\n\tflagPrunColumns uint64 = 1 << iota\n\tflagBuildKeyInfo\n\tflagDecorrelate\n\tflagEliminateAgg\n\tflagEliminateProjection\n\tflagMaxMinEliminate\n\tflagPredicatePushDown\n\tflagJoinReOrder\n\tflagPrunColumnsDouble // eliminate unused columns added by predicate push down\n\tflagEliminateOuterJoin\n\tflagPartitionProcessor\n\tflagApplyGroupbyThreshold\n\tflagMergeSelection\n\tflagPushDownAgg\n\tflagPushDownTopN\n\tflagDoubleCheckEliminateProjection\n\tflagPatchTimeZone\n)\n\n// Warning: rules in this list should be consistent with the order of flags\nvar optRuleList = []logicalOptRule{\n\t&columnPruner{},\n\t&optPlaceHolder{},\n\t&decorrelateSolver{},\n\t&optPlaceHolder{},\n\t&projectionEliminator{},\n\t&optPlaceHolder{},\n\t&ppdSolver{},\n\t&joinReOrderSolver{},\n\t&columnPruner{},\n\t&optPlaceHolder{},\n\t&optPlaceHolder{},\n\t&groupbyThresholdApplier{},\n\t&selectionMerger{},\n\t&aggregationPushDownSolver{},\n\t&optPlaceHolder{},\n\t&projectionEliminator{},\n\t&timeZonePatcher{},\n}\n\n// logicalOptRule means a logical optimizing rule, which contains decorrelate, ppd, column pruning, etc.\ntype logicalOptRule interface {\n\toptimize(context.Context, LogicalPlan) (LogicalPlan, error)\n\tname() string\n}\n\nvar customizedCheckRules = []customizedCheckRule{\n\t&maxOneRowCheck{},\n}\n\ntype customizedCheckRule interface {\n\tcheck(lp LogicalPlan) error\n}\n\n// NOTE(yang.y): the order of applying the optimization rule matters, so\n// we should create temporary place holders for optimizers that yet to be\n// implemented.\ntype optPlaceHolder struct{}\n\nfunc (optPlaceHolder) optimize(_ context.Context, lp LogicalPlan) (LogicalPlan, error) {\n\treturn lp, nil\n}\n\nfunc (optPlaceHolder) name() string { return \"opt_place_holder\" }\n\n// TODO: move BuildLogicalPlan out of this file.\n// BuildLogicalPlan used to build logical plan from ast.Node.\nfunc BuildLogicalPlan(ctx context.Context, sctx sessionctx.Context, node ast.Node, is infoschema.InfoSchema) (Plan, types.NameSlice, error) {\n\tsctx.GetSessionVars().PlanID = 0\n\tsctx.GetSessionVars().PlanColumnID = 0\n\tbuilder := NewPlanBuilder(sctx, is)\n\tp, err := builder.Build(ctx, node)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn p, p.OutputNames(), err\n}\n\n// BuildLogicalPlanWithOptimization used to build logical plan from ast.Node and optimize it on logical level.\nfunc BuildLogicalPlanWithOptimization(ctx context.Context, sctx sessionctx.Context, node ast.Node, is infoschema.InfoSchema) (LogicalPlan, types.NameSlice, error) {\n\tsctx.GetSessionVars().PlanID = 0\n\tsctx.GetSessionVars().PlanColumnID = 0\n\tbuilder := NewPlanBuilder(sctx, is)\n\tp, err := builder.Build(ctx, node)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tlp, err := logicalOptimize(ctx, builder.optFlag|flagDoubleCheckEliminateProjection|flagPrunColumnsDouble|flagApplyGroupbyThreshold|flagMergeSelection|flagPatchTimeZone|flagDecorrelate, p.(LogicalPlan))\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn lp, lp.OutputNames(), err\n}\n\nfunc BuildLogicalPlanWithBasicRules(ctx context.Context, sctx sessionctx.Context, node ast.Node, is infoschema.InfoSchema) (LogicalPlan, types.NameSlice, error) {\n\tsctx.GetSessionVars().PlanID = 0\n\tsctx.GetSessionVars().PlanColumnID = 0\n\tbuilder := NewPlanBuilder(sctx, is)\n\tp, err := builder.Build(ctx, node)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tlogic := p.(LogicalPlan)\n\trules := []logicalOptRule{\n\t\t&columnPruner{},\n\t\t&decorrelateSolver{},\n\t\t&ppdSolver{},\n\t}\n\tfor _, rule := range rules {\n\t\tlogic, err = rule.optimize(ctx, logic)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t}\n\n\treturn logic, logic.OutputNames(), err\n}\n\nfunc logicalOptimize(ctx context.Context, flag uint64, logic LogicalPlan) (LogicalPlan, error) {\n\tvar err error\n\tfor i, rule := range optRuleList {\n\t\t// The order of flags is same as the order of optRule in the list.\n\t\t// We use a bitmask to record which opt rules should be used. If the i-th bit is 1, it means we should\n\t\t// apply i-th optimizing rule.\n\t\tif flag&(1<<uint(i)) == 0 || isLogicalRuleDisabled(rule) {\n\t\t\tcontinue\n\t\t}\n\t\tlogic, err = rule.optimize(ctx, logic)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tfor _, c := range customizedCheckRules {\n\t\terr = c.check(logic)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn logic, err\n}\n\nfunc isLogicalRuleDisabled(_ logicalOptRule) bool {\n\t// TODO(yang.y): make this configurable\n\treturn false\n}\n\ntype maxOneRowCheck struct{}\n\nfunc (m maxOneRowCheck) check(lp LogicalPlan) error {\n\tmaxOneRow, ok := lp.(*LogicalMaxOneRow)\n\tif !ok {\n\t\tfor _, child := range lp.Children() {\n\t\t\terr := m.check(child)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\tchildren := maxOneRow.Children()\n\tfor _, child := range children {\n\t\tagg, ok := child.(*LogicalAggregation)\n\n\t\t// SELECT ... WHERE col > (SELECT AVG(a) ...)\n\t\tif ok {\n\t\t\tif len(agg.GetGroupByCols()) > 0 {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tfor _, child := range agg.Children() {\n\t\t\t\terr := m.check(child)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tprojection, ok := child.(*LogicalProjection)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"child node of MaxOneRow must be Aggregation or Projection, but got %s\", child.TP())\n\t\t\t}\n\n\t\t\tprojChildren := projection.Children()\n\t\t\t// SELECT ... WHERE col > (SELECT SUM(a) + AVG(b) ...)\n\t\t\tfor _, projChild := range projChildren {\n\t\t\t\t_, ok := projChild.(*LogicalAggregation)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"child node of Projection must be Aggregation, but got %s\", projChild.TP())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/planner/core/plan.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/stringutil\"\n)\n\ntype Plan interface {\n\t// Get the schema.\n\tSchema() *expression.Schema\n\n\t// Get the ID.\n\tID() int\n\n\t// TP get the plan type.\n\tTP() string\n\n\t// Get the ID in explain statement\n\tExplainID() fmt.Stringer\n\n\t// ExplainInfo returns operator information to be explained.\n\tExplainInfo() string\n\n\t// replaceExprColumns replace all the column reference in the plan's expression node.\n\treplaceExprColumns(replace map[string]*expression.Column)\n\n\tSCtx() sessionctx.Context\n\n\t// OutputNames returns the outputting names of each column.\n\tOutputNames() types.NameSlice\n\n\t// SetOutputNames sets the outputting name by the given slice.\n\tSetOutputNames(names types.NameSlice)\n\n\tSelectBlockOffset() int\n\n\tOwnerPartyCodes() []string\n\n\tSetOwnerPartyCodes(partyCodes []string)\n}\n\ntype IntoOpt struct {\n\tPartyColumns map[string][]*expression.Column\n\tOpt          *ast.SelectIntoOption\n}\n\ntype InsertTableOption struct {\n\tTableName string\n\tColumns   []string\n}\n\ntype LogicalPlan interface {\n\tPlan\n\n\t// HashCode encodes a LogicalPlan to fast compare whether a LogicalPlan equals to another.\n\t// We use a strict encode method here which ensures there is no conflict.\n\tHashCode() []byte\n\n\t// PredicatePushDown pushes down the predicates in the where/on/having clauses as deeply as possible.\n\t// It will accept a predicate that is an expression slice, and return the expressions that can't be pushed.\n\t// Because it might change the root if the having clause exists, we need to return a plan that represents a new root.\n\tPredicatePushDown([]expression.Expression) ([]expression.Expression, LogicalPlan)\n\n\t// PruneColumns prunes the unused columns.\n\tPruneColumns([]*expression.Column) error\n\n\t// BuildKeyInfo will collect the information of unique keys into schema.\n\tBuildKeyInfo(selfSchema *expression.Schema, childSchema []*expression.Schema)\n\n\textractCorrelatedCols() []*expression.CorrelatedColumn\n\n\t// Get all the children.\n\tChildren() []LogicalPlan\n\n\t// SetChildren sets the children for the plan.\n\tSetChildren(...LogicalPlan)\n\n\t// SetChild sets the ith child for the plan.\n\tSetChild(i int, child LogicalPlan)\n\n\tSqlStmt(Dialect) (*runSqlCtx, error)\n\n\t// Added for SCQL\n\tSetIntoOpt(option *ast.SelectIntoOption, partyColumns map[string][]*expression.Column)\n\tIntoOpt() *IntoOpt\n\tSetInsertTableOpt(option *InsertTableOption)\n\tInsertTableOpt() *InsertTableOption\n}\n\ntype basePlan struct {\n\ttp              string\n\tid              int\n\tctx             sessionctx.Context\n\tblockOffset     int\n\tintoOpt         *IntoOpt\n\tinsertTableOpt  *InsertTableOption\n\townerPartyCodes []string\n}\n\nfunc (p *basePlan) TP() string {\n\treturn p.tp\n}\n\nfunc (p *basePlan) ID() int {\n\treturn p.id\n}\n\nfunc (p *basePlan) ExplainID() fmt.Stringer {\n\treturn stringutil.MemoizeStr(func() string {\n\t\treturn p.tp + \"_\" + strconv.Itoa(p.id)\n\t})\n}\n\n// ExplainInfo implements Plan interface.\nfunc (p *basePlan) ExplainInfo() string {\n\treturn \"N/A\"\n}\n\nfunc (p *basePlan) SCtx() sessionctx.Context {\n\treturn p.ctx\n}\n\nfunc (p *basePlan) SelectBlockOffset() int {\n\treturn p.blockOffset\n}\n\nfunc (p *basePlan) OwnerPartyCodes() []string {\n\treturn p.ownerPartyCodes\n}\n\nfunc (p *basePlan) SetOwnerPartyCodes(partyCodes []string) {\n\tp.ownerPartyCodes = partyCodes\n}\n\nfunc (p *baseLogicalPlan) extractCorrelatedCols() []*expression.CorrelatedColumn {\n\tcorCols := make([]*expression.CorrelatedColumn, 0, len(p.children))\n\tfor _, child := range p.children {\n\t\tcorCols = append(corCols, child.extractCorrelatedCols()...)\n\t}\n\treturn corCols\n}\n\nfunc newBasePlan(ctx sessionctx.Context, tp string, offset int) basePlan {\n\tctx.GetSessionVars().PlanID++\n\tid := ctx.GetSessionVars().PlanID\n\treturn basePlan{\n\t\ttp:          tp,\n\t\tid:          id,\n\t\tctx:         ctx,\n\t\tblockOffset: offset,\n\t}\n}\n\nfunc newBaseLogicalPlan(ctx sessionctx.Context, tp string, self LogicalPlan, offset int) baseLogicalPlan {\n\treturn baseLogicalPlan{\n\t\tbasePlan: newBasePlan(ctx, tp, offset),\n\t\tself:     self,\n\t}\n}\n\ntype baseLogicalPlan struct {\n\tbasePlan\n\n\tself     LogicalPlan\n\tchildren []LogicalPlan\n}\n\nfunc (p *baseLogicalPlan) ExplainInfo() string {\n\treturn \"\"\n}\n\nfunc (p *baseLogicalPlan) Children() []LogicalPlan {\n\treturn p.children\n}\n\nfunc (p *baseLogicalPlan) SetChildren(children ...LogicalPlan) {\n\tp.children = children\n}\n\nfunc (p *baseLogicalPlan) SetChild(i int, child LogicalPlan) {\n\tp.children[i] = child\n}\n\n// Schema implements Plan Schema interface.\nfunc (p *baseLogicalPlan) Schema() *expression.Schema {\n\treturn p.children[0].Schema()\n}\n\nfunc (p *baseLogicalPlan) OutputNames() types.NameSlice {\n\treturn p.children[0].OutputNames()\n}\n\nfunc (p *baseLogicalPlan) SetOutputNames(names types.NameSlice) {\n\tp.children[0].SetOutputNames(names)\n}\n\nfunc (p *basePlan) replaceExprColumns(replace map[string]*expression.Column) {\n}\n\n// BuildKeyInfo implements LogicalPlan BuildKeyInfo interface.\nfunc (p *baseLogicalPlan) BuildKeyInfo(selfSchema *expression.Schema, childSchema []*expression.Schema) {\n\t// TODO(teng.t): Decide whether we need MaxOneRow function here.\n\t// childMaxOneRow := make([]bool, len(p.children))\n\t// for i := range p.children {\n\t// \tchildMaxOneRow[i] = p.children[i].MaxOneRow()\n\t// }\n\t// p.maxOneRow = HasMaxOneRow(p.self, childMaxOneRow)\n}\n\n// PruneColumns implements LogicalPlan interface.\nfunc (p *baseLogicalPlan) PruneColumns(parentUsedCols []*expression.Column) error {\n\tif len(p.children) == 0 {\n\t\treturn nil\n\t}\n\treturn p.children[0].PruneColumns(parentUsedCols)\n}\n\n// BuildKeyInfo implements LogicalPlan BuildKeyInfo interface.\nfunc (p *logicalSchemaProducer) BuildKeyInfo(selfSchema *expression.Schema, childSchema []*expression.Schema) {\n\tselfSchema.Keys = nil\n\tp.baseLogicalPlan.BuildKeyInfo(selfSchema, childSchema)\n}\n\nfunc (p *basePlan) SetIntoOpt(option *ast.SelectIntoOption, partyColumns map[string][]*expression.Column) {\n\tp.intoOpt = &IntoOpt{\n\t\tOpt:          option,\n\t\tPartyColumns: partyColumns,\n\t}\n}\n\nfunc (p *basePlan) IntoOpt() *IntoOpt {\n\treturn p.intoOpt\n}\n\nfunc (p *basePlan) SetInsertTableOpt(option *InsertTableOption) {\n\tp.insertTableOpt = option\n}\n\nfunc (p *basePlan) InsertTableOpt() *InsertTableOption {\n\treturn p.insertTableOpt\n}\n\nfunc (p *baseLogicalPlan) SqlStmt(d Dialect) (*runSqlCtx, error) {\n\treturn nil, fmt.Errorf(\"unsupported logical plan baseLogicalPlan: %s\", p.TP())\n}\n"
  },
  {
    "path": "pkg/planner/core/planbuilder.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\tdriver \"github.com/secretflow/scql/pkg/types/parser_driver\"\n\n\tglog \"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/table\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\ntype indexNestedLoopJoinTables struct {\n\tinljTables  []hintTableInfo\n\tinlhjTables []hintTableInfo\n\tinlmjTables []hintTableInfo\n}\n\ntype tableHintInfo struct {\n\tindexNestedLoopJoinTables\n\tsortMergeJoinTables []hintTableInfo\n\thashJoinTables      []hintTableInfo\n\tindexHintList       []indexHintInfo\n\ttiflashTables       []hintTableInfo\n\ttikvTables          []hintTableInfo\n\taggHints            aggHintInfo\n\tindexMergeHintList  []indexHintInfo\n}\n\ntype hintTableInfo struct {\n\tdbName       model.CIStr\n\ttblName      model.CIStr\n\tselectOffset int\n\tmatched      bool\n}\n\ntype indexHintInfo struct {\n\tdbName    model.CIStr\n\ttblName   model.CIStr\n\tindexHint *ast.IndexHint\n}\n\ntype visitInfo struct {\n\tprivilege mysql.PrivilegeType\n\tdb        string\n\ttable     string\n\tcolumn    string\n\terr       error\n}\n\ntype aggHintInfo struct {\n\tpreferAggType  uint\n\tpreferAggToCop bool\n}\n\n// clauseCode indicates in which clause the column is currently.\ntype clauseCode int\n\nconst (\n\tunknowClause clauseCode = iota + 1\n\tfieldList\n\thavingClause\n\tonClause\n\torderByClause\n\twhereClause\n\tgroupByClause\n\tshowStatement\n\tglobalOrderByClause\n)\n\nvar clauseMsg = map[clauseCode]string{\n\tunknowClause:        \"\",\n\tfieldList:           \"field list\",\n\thavingClause:        \"having clause\",\n\tonClause:            \"on clause\",\n\torderByClause:       \"order clause\",\n\twhereClause:         \"where clause\",\n\tgroupByClause:       \"group statement\",\n\tshowStatement:       \"show statement\",\n\tglobalOrderByClause: \"global ORDER clause\",\n}\n\n// PlanBuilder builds Plan from an ast.Node.\n// It just builds the ast node straightforwardly.\ntype PlanBuilder struct {\n\tctx          sessionctx.Context\n\tis           infoschema.InfoSchema\n\touterSchemas []*expression.Schema\n\touterNames   [][]*types.FieldName\n\t// colMapper stores the column that must be pre-resolved.\n\tcolMapper map[*ast.ColumnNameExpr]int\n\t// visitInfo is used for privilege check.\n\tvisitInfo     []visitInfo\n\ttableHintInfo []tableHintInfo\n\t// optFlag indicates the flags of the optimizer rules.\n\toptFlag uint64\n\n\tcurClause clauseCode\n\n\t// rewriterPool stores the expressionRewriter we have created to reuse it if it has been released.\n\t// rewriterCounter counts how many rewriter is being used.\n\trewriterPool    []*expressionRewriter\n\trewriterCounter int\n\n\t// selectOffset is the offsets of current processing select stmts.\n\tselectOffset []int\n\n\twindowSpecs map[string]*ast.WindowSpec\n}\n\n// GetVisitInfo gets the visitInfo of the PlanBuilder.\nfunc (b *PlanBuilder) GetVisitInfo() []visitInfo {\n\treturn b.visitInfo\n}\n\n// GetOptFlag gets the optFlag of the PlanBuilder.\nfunc (b *PlanBuilder) GetOptFlag() uint64 {\n\treturn b.optFlag\n}\n\nfunc (b *PlanBuilder) getSelectOffset() int {\n\tif len(b.selectOffset) > 0 {\n\t\treturn b.selectOffset[len(b.selectOffset)-1]\n\t}\n\treturn -1\n}\n\nfunc (b *PlanBuilder) pushSelectOffset(offset int) {\n\tb.selectOffset = append(b.selectOffset, offset)\n}\n\nfunc (b *PlanBuilder) popSelectOffset() {\n\tb.selectOffset = b.selectOffset[:len(b.selectOffset)-1]\n}\n\n// NewPlanBuilder creates a new PlanBuilder.\nfunc NewPlanBuilder(sctx sessionctx.Context, is infoschema.InfoSchema) *PlanBuilder {\n\treturn &PlanBuilder{\n\t\tctx:       sctx,\n\t\tis:        is,\n\t\tcolMapper: make(map[*ast.ColumnNameExpr]int),\n\t}\n}\n\n// Build builds the ast node to a Plan.\nfunc (b *PlanBuilder) Build(ctx context.Context, node ast.Node) (Plan, error) {\n\tb.optFlag = flagPrunColumns\n\tswitch x := node.(type) {\n\tcase *ast.SelectStmt:\n\t\treturn b.buildSelect(ctx, x)\n\tcase *ast.UnionStmt:\n\t\treturn b.buildUnion(ctx, x)\n\tcase *ast.CreateUserStmt, *ast.DropUserStmt, *ast.GrantStmt, *ast.RevokeStmt, *ast.AlterUserStmt:\n\t\treturn b.buildSimple(node.(ast.StmtNode))\n\tcase ast.DDLNode:\n\t\treturn b.buildDDL(ctx, x)\n\tcase *ast.ShowStmt:\n\t\treturn b.buildShow(ctx, x)\n\tcase *ast.ExplainStmt:\n\t\treturn b.buildExplain(ctx, x)\n\tcase *ast.SetStmt:\n\t\treturn b.buildSet(ctx, x)\n\tcase *ast.InsertStmt:\n\t\treturn b.buildInsert(ctx, x)\n\t}\n\treturn nil, ErrUnsupportedType.GenWithStack(\"Unsupported type %T\", node)\n}\n\n// detectSelectAgg detects an aggregate function or GROUP BY clause.\nfunc (b *PlanBuilder) detectSelectAgg(sel *ast.SelectStmt) bool {\n\tif sel.GroupBy != nil {\n\t\treturn true\n\t}\n\tfor _, f := range sel.Fields.Fields {\n\t\tif ast.HasAggFlag(f.Expr) {\n\t\t\treturn true\n\t\t}\n\t}\n\tif sel.Having != nil {\n\t\tif ast.HasAggFlag(sel.Having.Expr) {\n\t\t\treturn true\n\t\t}\n\t}\n\tif sel.OrderBy != nil {\n\t\tfor _, item := range sel.OrderBy.Items {\n\t\t\tif ast.HasAggFlag(item.Expr) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (b *PlanBuilder) buildSimple(node ast.StmtNode) (Plan, error) {\n\tp := &Simple{Statement: node}\n\n\tswitch raw := node.(type) {\n\tcase *ast.FlushStmt, *ast.GrantRoleStmt, *ast.RevokeRoleStmt,\n\t\t*ast.KillStmt, *ast.UseStmt, *ast.ShutdownStmt:\n\t\treturn nil, fmt.Errorf(\"buildSimple: un-ported node %v\", raw)\n\tcase *ast.CreateUserStmt, *ast.DropUserStmt, *ast.GrantStmt, *ast.RevokeStmt:\n\t\treturn nil, fmt.Errorf(\"CreateUserStmt/DropUserStmt/GrantStmt/RevokeStmt only valid in SCDB mode(removed)\")\n\t}\n\n\treturn p, nil\n}\n\nfunc (b *PlanBuilder) buildSet(ctx context.Context, v *ast.SetStmt) (Plan, error) {\n\tp := &Set{}\n\tfor _, vars := range v.Variables {\n\t\tif vars.IsGlobal {\n\t\t\terr := ErrSpecificAccessDenied.GenWithStackByArgs(\"SUPER\")\n\t\t\tb.visitInfo = appendVisitInfo(b.visitInfo, mysql.SuperPriv, \"\", \"\", \"\", err)\n\t\t}\n\t\tassign := &expression.VarAssignment{\n\t\t\tName:     vars.Name,\n\t\t\tIsGlobal: vars.IsGlobal,\n\t\t\tIsSystem: vars.IsSystem,\n\t\t}\n\t\tif _, ok := vars.Value.(*ast.DefaultExpr); !ok {\n\t\t\tif cn, ok2 := vars.Value.(*ast.ColumnNameExpr); ok2 && cn.Name.Table.L == \"\" {\n\t\t\t\t// Set use to set timezone, not support other value\n\t\t\t\t// Convert column name expression to string value expression.\n\t\t\t\t// char, col := b.ctx.GetSessionVars().GetCharsetInfo()\n\t\t\t\t// vars.Value = ast.NewValueExpr(cn.Name.Name.O, char, col)\n\t\t\t\treturn nil, ErrUnsupportedType.GenWithStack(\"Unsupported set type\")\n\t\t\t}\n\t\t\tmockTablePlan := LogicalTableDual{}.Init(b.ctx, b.getSelectOffset())\n\t\t\tvar err error\n\t\t\tassign.Expr, _, err = b.rewrite(ctx, vars.Value, mockTablePlan, nil, true)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t} else {\n\t\t\tassign.IsDefault = true\n\t\t}\n\t\tif vars.ExtendValue != nil {\n\t\t\treturn nil, ErrUnsupportedType.GenWithStack(\"Unsupported set type\")\n\t\t\t//assign.ExtendValue = &expression.Constant{\n\t\t\t//\tValue:   vars.ExtendValue.(*driver.ValueExpr).Datum,\n\t\t\t//\tRetType: &vars.ExtendValue.(*driver.ValueExpr).Type,\n\t\t\t// }\n\t\t}\n\t\tp.VarAssigns = append(p.VarAssigns, assign)\n\t}\n\treturn p, nil\n}\n\nfunc (b *PlanBuilder) detectSelectWindow(sel *ast.SelectStmt) bool {\n\tfor _, f := range sel.Fields.Fields {\n\t\tif ast.HasWindowFlag(f.Expr) {\n\t\t\treturn true\n\t\t}\n\t}\n\tif sel.OrderBy != nil {\n\t\tfor _, item := range sel.OrderBy.Items {\n\t\t\tif ast.HasWindowFlag(item.Expr) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// havingWindowAndOrderbyExprResolver visits Expr tree.\n// It converts ColunmNameExpr to AggregateFuncExpr and collects AggregateFuncExpr.\ntype havingWindowAndOrderbyExprResolver struct {\n\tinAggFunc    bool\n\tinWindowFunc bool\n\tinWindowSpec bool\n\tinExpr       bool\n\torderBy      bool\n\terr          error\n\tp            LogicalPlan\n\tselectFields []*ast.SelectField\n\taggMapper    map[*ast.AggregateFuncExpr]int\n\tcolMapper    map[*ast.ColumnNameExpr]int\n\tgbyItems     []*ast.ByItem\n\touterSchemas []*expression.Schema\n\touterNames   [][]*types.FieldName\n\tcurClause    clauseCode\n}\n\n// Enter implements Visitor interface.\nfunc (a *havingWindowAndOrderbyExprResolver) Enter(n ast.Node) (node ast.Node, skipChildren bool) {\n\tswitch n.(type) {\n\tcase *ast.AggregateFuncExpr:\n\t\ta.inAggFunc = true\n\tcase *ast.WindowFuncExpr:\n\t\ta.inWindowFunc = true\n\tcase *ast.WindowSpec:\n\t\ta.inWindowSpec = true\n\tcase *driver.ParamMarkerExpr, *ast.ColumnNameExpr, *ast.ColumnName:\n\tcase *ast.SubqueryExpr, *ast.ExistsSubqueryExpr:\n\t\t// Enter a new context, skip it.\n\t\t// For example: select sum(c) + c + exists(select c from t) from t;\n\t\treturn n, true\n\tdefault:\n\t\ta.inExpr = true\n\t}\n\treturn n, false\n}\n\nfunc (a *havingWindowAndOrderbyExprResolver) resolveFromPlan(v *ast.ColumnNameExpr, p LogicalPlan) (int, error) {\n\tidx, err := expression.FindFieldName(p.OutputNames(), v.Name)\n\tif err != nil {\n\t\treturn -1, err\n\t}\n\tif idx < 0 {\n\t\treturn -1, nil\n\t}\n\tcol := p.Schema().Columns[idx]\n\tname := p.OutputNames()[idx]\n\tnewColName := &ast.ColumnName{\n\t\tSchema: name.DBName,\n\t\tTable:  name.TblName,\n\t\tName:   name.ColName,\n\t}\n\tfor i, field := range a.selectFields {\n\t\tif c, ok := field.Expr.(*ast.ColumnNameExpr); ok && colMatch(c.Name, newColName) {\n\t\t\treturn i, nil\n\t\t}\n\t}\n\tsf := &ast.SelectField{\n\t\tExpr:      &ast.ColumnNameExpr{Name: newColName},\n\t\tAuxiliary: true,\n\t}\n\tsf.Expr.SetType(col.GetType())\n\ta.selectFields = append(a.selectFields, sf)\n\treturn len(a.selectFields) - 1, nil\n}\n\n// Leave implements Visitor interface.\nfunc (a *havingWindowAndOrderbyExprResolver) Leave(n ast.Node) (node ast.Node, ok bool) {\n\tswitch v := n.(type) {\n\tcase *ast.AggregateFuncExpr:\n\t\ta.inAggFunc = false\n\t\ta.aggMapper[v] = len(a.selectFields)\n\t\ta.selectFields = append(a.selectFields, &ast.SelectField{\n\t\t\tAuxiliary: true,\n\t\t\tExpr:      v,\n\t\t\tAsName:    model.NewCIStr(fmt.Sprintf(\"sel_agg_%d\", len(a.selectFields))),\n\t\t})\n\tcase *ast.WindowFuncExpr:\n\t\ta.inWindowFunc = false\n\t\tif a.curClause == havingClause {\n\t\t\ta.err = ErrWindowInvalidWindowFuncUse.GenWithStackByArgs(strings.ToLower(v.F))\n\t\t\tglog.Infof(\"havingWindowAndOrderbyExprResolver error: %s\", a.err)\n\t\t\treturn node, false\n\t\t}\n\t\tif a.curClause == orderByClause {\n\t\t\ta.selectFields = append(a.selectFields, &ast.SelectField{\n\t\t\t\tAuxiliary: true,\n\t\t\t\tExpr:      v,\n\t\t\t\tAsName:    model.NewCIStr(fmt.Sprintf(\"sel_window_%d\", len(a.selectFields))),\n\t\t\t})\n\t\t}\n\tcase *ast.WindowSpec:\n\t\ta.inWindowSpec = false\n\tcase *ast.ColumnNameExpr:\n\t\tresolveFieldsFirst := true\n\t\tif a.inAggFunc || a.inWindowFunc || a.inWindowSpec || (a.orderBy && a.inExpr) || a.curClause == fieldList {\n\t\t\tresolveFieldsFirst = false\n\t\t}\n\t\tif !a.inAggFunc && !a.orderBy {\n\t\t\tfor _, item := range a.gbyItems {\n\t\t\t\tif col, ok := item.Expr.(*ast.ColumnNameExpr); ok &&\n\t\t\t\t\t(colMatch(v.Name, col.Name) || colMatch(col.Name, v.Name)) {\n\t\t\t\t\tresolveFieldsFirst = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvar index int\n\t\tif resolveFieldsFirst {\n\t\t\tindex, a.err = resolveFromSelectFields(v, a.selectFields, false)\n\t\t\tif a.err != nil {\n\t\t\t\treturn node, false\n\t\t\t}\n\t\t\tif index != -1 && a.curClause == havingClause && ast.HasWindowFlag(a.selectFields[index].Expr) {\n\t\t\t\ta.err = ErrWindowInvalidWindowFuncAliasUse.GenWithStackByArgs(v.Name.Name.O)\n\t\t\t\treturn node, false\n\t\t\t}\n\t\t\tif index == -1 {\n\t\t\t\tif a.orderBy {\n\t\t\t\t\tindex, a.err = a.resolveFromPlan(v, a.p)\n\t\t\t\t} else {\n\t\t\t\t\tindex, a.err = resolveFromSelectFields(v, a.selectFields, true)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// We should ignore the err when resolving from schema. Because we could resolve successfully\n\t\t\t// when considering select fields.\n\t\t\tvar err error\n\t\t\tindex, err = a.resolveFromPlan(v, a.p)\n\t\t\t_ = err\n\t\t\tif index == -1 && a.curClause != fieldList {\n\t\t\t\tindex, a.err = resolveFromSelectFields(v, a.selectFields, false)\n\t\t\t\tif index != -1 && a.curClause == havingClause && ast.HasWindowFlag(a.selectFields[index].Expr) {\n\t\t\t\t\ta.err = ErrWindowInvalidWindowFuncAliasUse.GenWithStackByArgs(v.Name.Name.O)\n\t\t\t\t\treturn node, false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif a.err != nil {\n\t\t\treturn node, false\n\t\t}\n\t\tif index == -1 {\n\t\t\t// If we can't find it any where, it may be a correlated columns.\n\t\t\tfor _, names := range a.outerNames {\n\t\t\t\tidx, err1 := expression.FindFieldName(names, v.Name)\n\t\t\t\tif err1 != nil {\n\t\t\t\t\ta.err = err1\n\t\t\t\t\treturn node, false\n\t\t\t\t}\n\t\t\t\tif idx >= 0 {\n\t\t\t\t\treturn n, true\n\t\t\t\t}\n\t\t\t}\n\t\t\ta.err = ErrUnknownColumn.GenWithStackByArgs(v.Name.OrigColName(), clauseMsg[a.curClause])\n\t\t\treturn node, false\n\t\t}\n\t\tif a.inAggFunc {\n\t\t\treturn a.selectFields[index].Expr, true\n\t\t}\n\t\ta.colMapper[v] = index\n\t}\n\treturn n, true\n}\n\n// resolveWindowFunction will process window functions and resolve the columns that don't exist in select fields.\nfunc (b *PlanBuilder) resolveWindowFunction(sel *ast.SelectStmt, p LogicalPlan) (\n\tmap[*ast.AggregateFuncExpr]int, error) {\n\textractor := &havingWindowAndOrderbyExprResolver{\n\t\tp:            p,\n\t\tselectFields: sel.Fields.Fields,\n\t\taggMapper:    make(map[*ast.AggregateFuncExpr]int),\n\t\tcolMapper:    b.colMapper,\n\t\touterSchemas: b.outerSchemas,\n\t\touterNames:   b.outerNames,\n\t}\n\textractor.curClause = fieldList\n\tfor _, field := range sel.Fields.Fields {\n\t\tif !ast.HasWindowFlag(field.Expr) {\n\t\t\tcontinue\n\t\t}\n\t\tn, ok := field.Expr.Accept(extractor)\n\t\tif !ok {\n\t\t\treturn nil, extractor.err\n\t\t}\n\t\tfield.Expr = n.(ast.ExprNode)\n\t}\n\tfor _, spec := range sel.WindowSpecs {\n\t\t_, ok := spec.Accept(extractor)\n\t\tif !ok {\n\t\t\treturn nil, extractor.err\n\t\t}\n\t}\n\tif sel.OrderBy != nil {\n\t\textractor.curClause = orderByClause\n\t\tfor _, item := range sel.OrderBy.Items {\n\t\t\tif !ast.HasWindowFlag(item.Expr) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tn, ok := item.Expr.Accept(extractor)\n\t\t\tif !ok {\n\t\t\t\treturn nil, extractor.err\n\t\t\t}\n\t\t\titem.Expr = n.(ast.ExprNode)\n\t\t}\n\t}\n\tsel.Fields.Fields = extractor.selectFields\n\treturn extractor.aggMapper, nil\n}\n\nfunc (b *PlanBuilder) checkWindowFuncArgs(ctx context.Context, p LogicalPlan, windowFuncExprs []*ast.WindowFuncExpr, windowAggMap map[*ast.AggregateFuncExpr]int) error {\n\tfor _, windowFuncExpr := range windowFuncExprs {\n\t\targs, err := b.buildArgs4WindowFunc(ctx, p, windowFuncExpr.Args, windowAggMap)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdesc, err := aggregation.NewWindowFuncDesc(b.ctx, windowFuncExpr.F, args)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif desc == nil {\n\t\t\treturn ErrWrongArguments.GenWithStackByArgs(strings.ToLower(windowFuncExpr.F))\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (b *PlanBuilder) buildArgs4WindowFunc(ctx context.Context, p LogicalPlan, args []ast.ExprNode, aggMap map[*ast.AggregateFuncExpr]int) ([]expression.Expression, error) {\n\tb.optFlag |= flagEliminateProjection\n\n\tnewArgList := make([]expression.Expression, 0, len(args))\n\t// use below index for created a new col definition\n\t// it's okay here because we only want to return the args used in window function\n\tnewColIndex := 0\n\tfor _, arg := range args {\n\t\tnewArg, np, err := b.rewrite(ctx, arg, p, aggMap, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tp = np\n\t\tswitch newArg.(type) {\n\t\tcase *expression.Column, *expression.Constant:\n\t\t\tnewArgList = append(newArgList, newArg)\n\t\t\tcontinue\n\t\t}\n\t\tcol := &expression.Column{\n\t\t\tUniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t\tRetType:  newArg.GetType(),\n\t\t}\n\t\tnewColIndex += 1\n\t\tnewArgList = append(newArgList, col)\n\t}\n\treturn newArgList, nil\n}\n\nfunc (b *PlanBuilder) buildDDL(ctx context.Context, node ast.DDLNode) (Plan, error) {\n\tvar authErr error\n\tswitch v := node.(type) {\n\tcase *ast.AlterDatabaseStmt, *ast.AlterTableStmt, *ast.CreateIndexStmt,\n\t\t*ast.CreateSequenceStmt, *ast.DropIndexStmt,\n\t\t*ast.TruncateTableStmt, *ast.RenameTableStmt, *ast.RecoverTableStmt,\n\t\t*ast.FlashBackTableStmt, *ast.LockTablesStmt, *ast.UnlockTablesStmt,\n\t\t*ast.CleanupTableLockStmt, *ast.RepairTableStmt:\n\t\t// TODO(yang.y): port the above cases when needed\n\t\treturn nil, fmt.Errorf(\"planbuilder.buildDDL: unsupported ast %v\", node)\n\tcase *ast.CreateViewStmt:\n\t\tplan, err := b.Build(ctx, v.Select)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschema := plan.Schema()\n\t\tnames := plan.OutputNames()\n\t\tif v.Cols == nil {\n\t\t\tv.Cols = make([]model.CIStr, len(schema.Columns))\n\t\t\tfor i, name := range names {\n\t\t\t\tv.Cols[i] = name.ColName\n\t\t\t}\n\t\t}\n\t\tif len(v.Cols) != schema.Len() {\n\t\t\treturn nil, fmt.Errorf(\"create view must include all columns in the select clause\")\n\t\t}\n\t\tif _, ok := plan.(LogicalPlan); ok {\n\t\t\tif b.ctx.GetSessionVars().User != nil {\n\t\t\t\tauthErr = ErrTableaccessDenied.GenWithStackByArgs(\"CREATE VIEW\", b.ctx.GetSessionVars().User.Hostname,\n\t\t\t\t\tb.ctx.GetSessionVars().User.Username, v.ViewName.Name.L)\n\t\t\t}\n\t\t\tb.visitInfo = appendVisitInfo(b.visitInfo, mysql.CreateViewPriv, v.ViewName.Schema.L,\n\t\t\t\tv.ViewName.Name.L, \"\", authErr)\n\t\t}\n\t\tif v.Definer.CurrentUser && b.ctx.GetSessionVars().User != nil {\n\t\t\tv.Definer = b.ctx.GetSessionVars().User\n\t\t}\n\t\tif b.ctx.GetSessionVars().User != nil && v.Definer.String() != b.ctx.GetSessionVars().User.String() {\n\t\t\terr = ErrSpecificAccessDenied.GenWithStackByArgs(\"SUPER\")\n\t\t\tb.visitInfo = appendVisitInfo(b.visitInfo, mysql.SuperPriv, \"\",\n\t\t\t\t\"\", \"\", err)\n\t\t}\n\tcase *ast.CreateTableStmt:\n\t\tif b.ctx.GetSessionVars().User != nil {\n\t\t\tauthErr = ErrTableaccessDenied.GenWithStackByArgs(\"CREATE\", b.ctx.GetSessionVars().User.Username,\n\t\t\t\tb.ctx.GetSessionVars().User.Hostname, v.Table.Name.L)\n\t\t}\n\t\tb.visitInfo = appendVisitInfo(b.visitInfo, mysql.CreatePriv, v.Table.Schema.L,\n\t\t\tv.Table.Name.L, \"\", authErr)\n\t\tif v.ReferTable != nil {\n\t\t\tif b.ctx.GetSessionVars().User != nil {\n\t\t\t\tauthErr = ErrTableaccessDenied.GenWithStackByArgs(\"CREATE\", b.ctx.GetSessionVars().User.Username,\n\t\t\t\t\tb.ctx.GetSessionVars().User.Hostname, v.ReferTable.Name.L)\n\t\t\t}\n\t\t\tb.visitInfo = appendVisitInfo(b.visitInfo, mysql.SelectPriv, v.ReferTable.Schema.L,\n\t\t\t\tv.ReferTable.Name.L, \"\", authErr)\n\t\t}\n\tcase *ast.CreateDatabaseStmt:\n\t\tif b.ctx.GetSessionVars().User != nil {\n\t\t\tauthErr = ErrDBaccessDenied.GenWithStackByArgs(b.ctx.GetSessionVars().User.Username,\n\t\t\t\tb.ctx.GetSessionVars().User.Hostname, v.Name)\n\t\t}\n\t\tb.visitInfo = appendVisitInfo(b.visitInfo, mysql.CreatePriv, v.Name,\n\t\t\t\"\", \"\", authErr)\n\tcase *ast.DropDatabaseStmt:\n\t\tif b.ctx.GetSessionVars().User != nil {\n\t\t\tauthErr = ErrDBaccessDenied.GenWithStackByArgs(b.ctx.GetSessionVars().User.Username,\n\t\t\t\tb.ctx.GetSessionVars().User.Hostname, v.Name)\n\t\t}\n\t\tb.visitInfo = appendVisitInfo(b.visitInfo, mysql.DropPriv, v.Name,\n\t\t\t\"\", \"\", authErr)\n\tcase *ast.DropTableStmt:\n\t\tfor _, tableVal := range v.Tables {\n\t\t\tif b.ctx.GetSessionVars().User != nil {\n\t\t\t\tauthErr = ErrTableaccessDenied.GenWithStackByArgs(\"DROP\", b.ctx.GetSessionVars().User.Username,\n\t\t\t\t\tb.ctx.GetSessionVars().User.Hostname, tableVal.Name.L)\n\t\t\t}\n\t\t\tb.visitInfo = appendVisitInfo(b.visitInfo, mysql.DropPriv, tableVal.Schema.L,\n\t\t\t\ttableVal.Name.L, \"\", authErr)\n\t\t}\n\n\t}\n\tp := &DDL{Statement: node}\n\treturn p, nil\n}\n\nfunc (b *PlanBuilder) buildShow(ctx context.Context, show *ast.ShowStmt) (Plan, error) {\n\tp := LogicalShow{\n\t\tShowContents: ShowContents{\n\t\t\tTp:          show.Tp,\n\t\t\tDBName:      show.DBName,\n\t\t\tTable:       show.Table,\n\t\t\tColumn:      show.Column,\n\t\t\tIndexName:   show.IndexName,\n\t\t\tFlag:        show.Flag,\n\t\t\tUser:        show.User,\n\t\t\tRoles:       show.Roles,\n\t\t\tFull:        show.Full,\n\t\t\tIfNotExists: show.IfNotExists,\n\t\t\tGlobalScope: show.GlobalScope,\n\t\t\tExtended:    show.Extended,\n\t\t},\n\t}.Init(b.ctx)\n\tisView := false\n\tswitch show.Tp {\n\tcase ast.ShowTables, ast.ShowTableStatus:\n\t\tif p.DBName == \"\" {\n\t\t\treturn nil, ErrNoDB\n\t\t}\n\tcase ast.ShowCreateTable, ast.ShowCreateView:\n\t\treturn nil, fmt.Errorf(\"buildShow unsupported\")\n\t}\n\tschema, names := buildShowSchema(show, isView)\n\tp.SetSchema(schema)\n\tp.names = names\n\tfor _, col := range p.schema.Columns {\n\t\tcol.UniqueID = b.ctx.GetSessionVars().AllocPlanColumnID()\n\t}\n\tvar err error\n\tvar np LogicalPlan\n\tnp = p\n\tif show.Pattern != nil {\n\t\tshow.Pattern.Expr = &ast.ColumnNameExpr{\n\t\t\tName: &ast.ColumnName{Name: p.OutputNames()[0].ColName},\n\t\t}\n\t\tnp, err = b.buildSelection(ctx, np, show.Pattern, nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif show.Where != nil {\n\t\tnp, err = b.buildSelection(ctx, np, show.Where, nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif np != p {\n\t\tb.optFlag |= flagEliminateProjection\n\t\tfieldsLen := len(p.schema.Columns)\n\t\tproj := LogicalProjection{Exprs: make([]expression.Expression, 0, fieldsLen)}.Init(b.ctx, 0)\n\t\tschema := expression.NewSchema(make([]*expression.Column, 0, fieldsLen)...)\n\t\tfor _, col := range p.schema.Columns {\n\t\t\tproj.Exprs = append(proj.Exprs, col)\n\t\t\tnewCol := col.Clone().(*expression.Column)\n\t\t\tnewCol.UniqueID = b.ctx.GetSessionVars().AllocPlanColumnID()\n\t\t\tschema.Append(newCol)\n\t\t}\n\t\tproj.SetSchema(schema)\n\t\tproj.SetChildren(np)\n\t\tproj.SetOutputNames(np.OutputNames())\n\t\treturn proj, nil\n\t}\n\treturn p, nil\n}\n\n// buildShowSchema builds column info for ShowStmt including column name and type.\nfunc buildShowSchema(s *ast.ShowStmt, isView bool) (schema *expression.Schema, outputNames []*types.FieldName) {\n\tvar names []string\n\tvar ftypes []byte\n\tswitch s.Tp {\n\tcase ast.ShowProcedureStatus, ast.ShowTriggers, ast.ShowEvents, ast.ShowWarnings, ast.ShowErrors,\n\t\tast.ShowRegions, ast.ShowEngines, ast.ShowOpenTables, ast.ShowTableStatus,\n\t\tast.ShowCharset, ast.ShowVariables, ast.ShowStatus, ast.ShowCollation, ast.ShowCreateTable,\n\t\tast.ShowCreateUser, ast.ShowCreateView, ast.ShowCreateDatabase, ast.ShowDrainerStatus,\n\t\tast.ShowIndex, ast.ShowPlugins, ast.ShowProcessList, ast.ShowPumpStatus, ast.ShowStatsMeta,\n\t\tast.ShowStatsHistograms, ast.ShowStatsBuckets, ast.ShowStatsHealthy, ast.ShowProfiles,\n\t\tast.ShowMasterStatus, ast.ShowPrivileges, ast.ShowBindings, ast.ShowAnalyzeStatus, ast.ShowBuiltins:\n\t\treturn\n\tcase ast.ShowDatabases:\n\t\tnames = []string{\"Database\"}\n\tcase ast.ShowTables:\n\t\tnames = []string{fmt.Sprintf(\"Tables_in_%s\", s.DBName)}\n\t\tif s.Full {\n\t\t\tnames = append(names, \"Table_type\")\n\t\t}\n\tcase ast.ShowColumns:\n\t\tnames = table.ColDescFieldNames(s.Full)\n\tcase ast.ShowGrants:\n\t\tif s.User != nil {\n\t\t\tnames = []string{fmt.Sprintf(\"Grants on %s for %s\", s.DBName, s.User)}\n\t\t} else {\n\t\t\t// Don't know the name yet, so just say \"user\"\n\t\t\tnames = []string{fmt.Sprintf(\"Grants on %s for User\", s.DBName)}\n\t\t}\n\t}\n\n\tschema = expression.NewSchema(make([]*expression.Column, 0, len(names))...)\n\toutputNames = make([]*types.FieldName, 0, len(names))\n\tfor i := range names {\n\t\tcol := &expression.Column{}\n\t\toutputNames = append(outputNames, &types.FieldName{ColName: model.NewCIStr(names[i])})\n\t\t// User varchar as the default return column type.\n\t\ttp := mysql.TypeVarchar\n\t\tif len(ftypes) != 0 && ftypes[i] != mysql.TypeUnspecified {\n\t\t\ttp = ftypes[i]\n\t\t}\n\t\tfieldType := types.NewFieldType(tp)\n\t\tfieldType.Flen, fieldType.Decimal = mysql.GetDefaultFieldLengthAndDecimal(tp)\n\t\tfieldType.Charset, fieldType.Collate = types.DefaultCharsetForType(tp)\n\t\tcol.RetType = fieldType\n\t\tschema.Append(col)\n\t}\n\treturn\n}\n\nfunc (b *PlanBuilder) buildExplain(ctx context.Context, explain *ast.ExplainStmt) (Plan, error) {\n\tshow, ok := explain.Stmt.(*ast.ShowStmt)\n\tif !ok {\n\t\treturn nil, ErrUnsupportedType.GenWithStack(\"Unsupported explain stmt %T\", explain.Stmt)\n\t}\n\treturn b.buildShow(ctx, show)\n}\n\nfunc (b *PlanBuilder) buildInsert(ctx context.Context, insert *ast.InsertStmt) (Plan, error) {\n\tts, ok := insert.Table.TableRefs.Left.(*ast.TableSource)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"buildInsert: get table source failed\")\n\t}\n\ttn, ok := ts.Source.(*ast.TableName)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"buildInsert: get table name failed\")\n\t}\n\tfullTableName := tn.Name.String()\n\tif fullTableName == \"\" {\n\t\treturn nil, fmt.Errorf(\"buildInsert: table name is empty\")\n\t}\n\tif tn.Schema.String() != \"\" {\n\t\tfullTableName = tn.Schema.String() + \".\" + fullTableName\n\t}\n\n\tvar plainColumnNames []string\n\tif len(insert.Columns) <= 0 {\n\t\treturn nil, fmt.Errorf(\"buildInsert: get column failed\")\n\t}\n\tfor _, col := range insert.Columns {\n\t\tif col.Schema.String() != \"\" {\n\t\t\treturn nil, fmt.Errorf(\"buildInsert: column name should not contain schema\")\n\t\t}\n\t\tif col.Table.String() != \"\" && col.Table.String() != fullTableName {\n\t\t\treturn nil, fmt.Errorf(\"buildInsert: table '%s' in column not equal to table '%s'\", col.Table.String(), fullTableName)\n\t\t}\n\t\tplainColumnNames = append(plainColumnNames, col.Name.String())\n\t}\n\n\tif insert.Select == nil {\n\t\treturn nil, fmt.Errorf(\"buildInsert: get select failed, only support 'INSERT INTO ... SELECT ... '\")\n\t}\n\n\tss, ok := insert.Select.(*ast.SelectStmt)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"buildInsert: get select stmt failed\")\n\t}\n\tp, err := b.buildSelect(ctx, ss)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"buildInsert: buildSelect failed: %v\", err)\n\t}\n\n\tp.SetInsertTableOpt(&InsertTableOption{\n\t\tTableName: fullTableName,\n\t\tColumns:   plainColumnNames,\n\t})\n\treturn p, nil\n}\n\nfunc getWindowName(name string) string {\n\tif name == \"\" {\n\t\treturn \"<unnamed window>\"\n\t}\n\treturn name\n}\n\nfunc mergeWindowSpec(spec, ref *ast.WindowSpec) error {\n\tif ref.Frame != nil {\n\t\treturn ErrWindowNoInherentFrame.GenWithStackByArgs(ref.Name.O)\n\t}\n\tif spec.PartitionBy != nil {\n\t\treturn errors.Trace(ErrWindowNoChildPartitioning)\n\t}\n\tif ref.OrderBy != nil {\n\t\tif spec.OrderBy != nil {\n\t\t\treturn ErrWindowNoRedefineOrderBy.GenWithStackByArgs(getWindowName(spec.Name.O), ref.Name.O)\n\t\t}\n\t\tspec.OrderBy = ref.OrderBy\n\t}\n\tspec.PartitionBy = ref.PartitionBy\n\tspec.Ref = model.NewCIStr(\"\")\n\treturn nil\n}\n\nfunc (b *PlanBuilder) handleDefaultFrame(spec *ast.WindowSpec, windowFuncName string) (*ast.WindowSpec, bool) {\n\tneedFrame := aggregation.NeedFrame(windowFuncName)\n\t// According to MySQL, In the absence of a frame clause, the default frame depends on whether an ORDER BY clause is present:\n\t//   (1) With order by, the default frame is equivalent to \"RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\";\n\t//   (2) Without order by, the default frame is equivalent to \"RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING\",\n\t//       which is the same as an empty frame.\n\tif needFrame && spec.Frame == nil && spec.OrderBy != nil {\n\t\tnewSpec := *spec\n\t\tnewSpec.Frame = &ast.FrameClause{\n\t\t\tType: ast.Ranges,\n\t\t\tExtent: ast.FrameExtent{\n\t\t\t\tStart: ast.FrameBound{Type: ast.Preceding, UnBounded: true},\n\t\t\t\tEnd:   ast.FrameBound{Type: ast.CurrentRow},\n\t\t\t},\n\t\t}\n\t\treturn &newSpec, true\n\t}\n\t// For functions that operate on the entire partition, the frame clause will be ignored.\n\tif !needFrame && spec.Frame != nil {\n\t\t// specName := spec.Name.O\n\t\t// b.ctx.GetSessionVars().StmtCtx.AppendNote(ErrWindowFunctionIgnoresFrame.GenWithStackByArgs(windowFuncName, getWindowName(specName)))\n\t\tnewSpec := *spec\n\t\tnewSpec.Frame = nil\n\t\treturn &newSpec, true\n\t}\n\treturn spec, false\n}\n\n// groupWindowFuncs groups the window functions according to the window specification name.\n// TODO: We can group the window function by the definition of window specification.\nfunc (b *PlanBuilder) groupWindowFuncs(windowFuncs []*ast.WindowFuncExpr) (map[*ast.WindowSpec][]*ast.WindowFuncExpr, error) {\n\t// updatedSpecMap is used to handle the specifications that have frame clause changed.\n\tupdatedSpecMap := make(map[string]*ast.WindowSpec)\n\tgroupedWindow := make(map[*ast.WindowSpec][]*ast.WindowFuncExpr)\n\tfor _, windowFunc := range windowFuncs {\n\t\tif windowFunc.Spec.Name.L == \"\" {\n\t\t\tspec := &windowFunc.Spec\n\t\t\tif spec.Ref.L != \"\" {\n\t\t\t\tref, ok := b.windowSpecs[spec.Ref.L]\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, ErrWindowNoSuchWindow.GenWithStackByArgs(getWindowName(spec.Ref.O))\n\t\t\t\t}\n\t\t\t\terr := mergeWindowSpec(spec, ref)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\tspec, _ = b.handleDefaultFrame(spec, windowFunc.F)\n\t\t\tgroupedWindow[spec] = append(groupedWindow[spec], windowFunc)\n\t\t\tcontinue\n\t\t}\n\n\t\tname := windowFunc.Spec.Name.L\n\t\tspec, ok := b.windowSpecs[name]\n\t\tif !ok {\n\t\t\treturn nil, ErrWindowNoSuchWindow.GenWithStackByArgs(windowFunc.Spec.Name.O)\n\t\t}\n\t\tnewSpec, updated := b.handleDefaultFrame(spec, windowFunc.F)\n\t\tif !updated {\n\t\t\tgroupedWindow[spec] = append(groupedWindow[spec], windowFunc)\n\t\t} else {\n\t\t\tif _, ok := updatedSpecMap[name]; !ok {\n\t\t\t\tupdatedSpecMap[name] = newSpec\n\t\t\t}\n\t\t\tupdatedSpec := updatedSpecMap[name]\n\t\t\tgroupedWindow[updatedSpec] = append(groupedWindow[updatedSpec], windowFunc)\n\t\t}\n\t}\n\treturn groupedWindow, nil\n}\n"
  },
  {
    "path": "pkg/planner/core/preprocess.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n)\n\n// PreprocessOpt presents optional parameters to `Preprocess` method.\ntype PreprocessOpt func(*preprocessor)\n\n// InPrepare is a PreprocessOpt that indicates preprocess is executing under prepare statement.\nfunc InPrepare(p *preprocessor) {\n\tp.flag |= inPrepare\n}\n\n// InTxnRetry is a PreprocessOpt that indicates preprocess is executing under transaction retry.\nfunc InTxnRetry(p *preprocessor) {\n\tp.flag |= inTxnRetry\n}\n\n// Preprocess resolves table names of the node, and checks some statements validation.\nfunc Preprocess(ctx sessionctx.Context, node ast.Node, is infoschema.InfoSchema, preprocessOpt ...PreprocessOpt) error {\n\tv := preprocessor{is: is, ctx: ctx, tableAliasInJoin: make([]map[string]interface{}, 0)}\n\tfor _, optFn := range preprocessOpt {\n\t\toptFn(&v)\n\t}\n\tnode.Accept(&v)\n\treturn errors.Trace(v.err)\n}\n\ntype preprocessorFlag uint8\n\nconst (\n\t// inPrepare is set when visiting in prepare statement.\n\tinPrepare preprocessorFlag = 1 << iota\n\t// inTxnRetry is set when visiting in transaction retry.\n\tinTxnRetry\n\t// inCreateOrDropTable is set when visiting create/drop table statement.\n\tinCreateOrDropTable\n\t// parentIsJoin is set when visiting node's parent is join.\n\tparentIsJoin\n\t// inRepairTable is set when visiting a repair table statement.\n\tinRepairTable\n)\n\n// preprocessor is an ast.Visitor that preprocess\n// ast Nodes parsed from parser.\ntype preprocessor struct {\n\tis   infoschema.InfoSchema\n\tctx  sessionctx.Context\n\terr  error\n\tflag preprocessorFlag\n\n\t// tableAliasInJoin is a stack that keeps the table alias names for joins.\n\t// len(tableAliasInJoin) may bigger than 1 because the left/right child of join may be subquery that contains `JOIN`\n\ttableAliasInJoin []map[string]interface{}\n}\n\nfunc (p *preprocessor) Enter(in ast.Node) (out ast.Node, skipChildren bool) {\n\tswitch node := in.(type) {\n\tcase *ast.CreateTableStmt:\n\t\tp.flag |= inCreateOrDropTable\n\t\tp.resolveCreateTableStmt(node)\n\t\t//p.checkCreateTableGrammar(node)\n\tcase *ast.CreateViewStmt:\n\t\tp.flag |= inCreateOrDropTable\n\t\t// p.checkCreateViewGrammar(node)\n\tcase *ast.DropTableStmt:\n\t\tp.flag |= inCreateOrDropTable\n\t\t//p.checkDropTableGrammar(node)\n\tcase *ast.ShowStmt:\n\t\tp.resolveShowStmt(node)\n\tcase *ast.UnionSelectList:\n\t\tp.checkUnionSelectList(node)\n\tcase *ast.Join:\n\t\tp.checkNonUniqTableAlias(node)\n\tdefault:\n\t\tp.flag &= ^parentIsJoin\n\t}\n\treturn in, p.err != nil\n}\n\nfunc (p *preprocessor) Leave(in ast.Node) (out ast.Node, ok bool) {\n\tswitch x := in.(type) {\n\tcase *ast.CreateTableStmt:\n\t\tp.flag &= ^inCreateOrDropTable\n\t\t//p.checkAutoIncrement(x)\n\t\t//p.checkContainDotColumn(x)\n\tcase *ast.DropTableStmt, *ast.AlterTableStmt, *ast.RenameTableStmt:\n\t\tp.flag &= ^inCreateOrDropTable\n\tcase *ast.TableName:\n\t\tp.handleTableName(x)\n\tcase *ast.Join:\n\t\tif len(p.tableAliasInJoin) > 0 {\n\t\t\tp.tableAliasInJoin = p.tableAliasInJoin[:len(p.tableAliasInJoin)-1]\n\t\t}\n\t}\n\n\treturn in, p.err == nil\n}\n\n// checkUnionSelectList checks union's selectList.\n// refer: https://dev.mysql.com/doc/refman/5.7/en/union.html\n// \"To apply ORDER BY or LIMIT to an individual SELECT, place the clause inside the parentheses that enclose the SELECT.\"\nfunc (p *preprocessor) checkUnionSelectList(stmt *ast.UnionSelectList) {\n\tfor _, sel := range stmt.Selects[:len(stmt.Selects)-1] {\n\t\tif sel.IsInBraces {\n\t\t\tcontinue\n\t\t}\n\t\tif sel.Limit != nil {\n\t\t\tp.err = ErrWrongUsage.GenWithStackByArgs(\"UNION\", \"LIMIT\")\n\t\t\treturn\n\t\t}\n\t\tif sel.OrderBy != nil {\n\t\t\tp.err = ErrWrongUsage.GenWithStackByArgs(\"UNION\", \"ORDER BY\")\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (p *preprocessor) handleTableName(tn *ast.TableName) {\n\tif tn.Schema.L == \"\" {\n\t\tcurrentDB := p.ctx.GetSessionVars().CurrentDB\n\t\tif currentDB == \"\" {\n\t\t\tp.err = errors.Trace(ErrNoDB)\n\t\t\treturn\n\t\t}\n\t\ttn.Schema = model.NewCIStr(currentDB)\n\t}\n\tif p.flag&inCreateOrDropTable > 0 {\n\t\t// The table may not exist in create table or drop table statement.\n\t\treturn\n\t}\n\n\ttable, err := p.is.TableByName(tn.Schema, tn.Name)\n\tif err != nil {\n\t\tp.err = err\n\t\treturn\n\t}\n\ttn.TableInfo = table.Meta()\n\tdbInfo, _ := p.is.SchemaByName(tn.Schema)\n\ttn.DBInfo = dbInfo\n}\n\nfunc (p *preprocessor) checkNonUniqTableAlias(stmt *ast.Join) {\n\tif p.flag&parentIsJoin == 0 {\n\t\tp.tableAliasInJoin = append(p.tableAliasInJoin, make(map[string]interface{}))\n\t}\n\ttableAliases := p.tableAliasInJoin[len(p.tableAliasInJoin)-1]\n\tif err := isTableAliasDuplicate(stmt.Left, tableAliases); err != nil {\n\t\tp.err = err\n\t\treturn\n\t}\n\tif err := isTableAliasDuplicate(stmt.Right, tableAliases); err != nil {\n\t\tp.err = err\n\t\treturn\n\t}\n\tp.flag |= parentIsJoin\n}\n\nfunc isTableAliasDuplicate(node ast.ResultSetNode, tableAliases map[string]interface{}) error {\n\tif ts, ok := node.(*ast.TableSource); ok {\n\t\ttabName := ts.AsName\n\t\tif tabName.L == \"\" {\n\t\t\tif tableNode, ok := ts.Source.(*ast.TableName); ok {\n\t\t\t\tif tableNode.Schema.L != \"\" {\n\t\t\t\t\ttabName = model.NewCIStr(fmt.Sprintf(\"%s.%s\", tableNode.Schema.L, tableNode.Name.L))\n\t\t\t\t} else {\n\t\t\t\t\ttabName = tableNode.Name\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t_, exists := tableAliases[tabName.L]\n\t\tif len(tabName.L) != 0 && exists {\n\t\t\treturn ErrNonUniqTable.GenWithStackByArgs(tabName)\n\t\t}\n\t\ttableAliases[tabName.L] = nil\n\t}\n\treturn nil\n}\n\nfunc (p *preprocessor) resolveShowStmt(node *ast.ShowStmt) {\n\tif node.DBName == \"\" {\n\t\tif node.Table != nil && node.Table.Schema.L != \"\" {\n\t\t\tnode.DBName = node.Table.Schema.O\n\t\t} else {\n\t\t\tnode.DBName = p.ctx.GetSessionVars().CurrentDB\n\t\t}\n\t} else if node.Table != nil && node.Table.Schema.L == \"\" {\n\t\tnode.Table.Schema = model.NewCIStr(node.DBName)\n\t}\n\tif node.User != nil && node.User.CurrentUser {\n\t\t// Fill the Username and Hostname with the current user.\n\t\tcurrentUser := p.ctx.GetSessionVars().User\n\t\tif currentUser != nil {\n\t\t\tnode.User.Username = currentUser.Username\n\t\t\tnode.User.Hostname = currentUser.Hostname\n\t\t\tnode.User.AuthUsername = currentUser.AuthUsername\n\t\t\tnode.User.AuthHostname = currentUser.AuthHostname\n\t\t}\n\t}\n}\n\nfunc (p *preprocessor) resolveCreateTableStmt(node *ast.CreateTableStmt) {\n\tfor _, val := range node.Constraints {\n\t\tif val.Refer != nil && val.Refer.Table.Schema.String() == \"\" {\n\t\t\tval.Refer.Table.Schema = node.Table.Schema\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/planner/core/rewrite.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/variable\"\n\tdriver \"github.com/secretflow/scql/pkg/types/parser_driver\"\n)\n\ntype DbTable struct {\n\tdbName    string\n\ttableName string\n\tdbType    DBType // db type of table stored\n}\n\nfunc (dt *DbTable) SetDBTypeFromString(dbStr, tableName string) error {\n\tif dbStr != \"\" {\n\t\tdbType, err := ParseDBType(dbStr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to set db type of %s: %v\", tableName, err)\n\t\t}\n\t\tdt.SetDBType(dbType)\n\t} else {\n\t\tlogrus.Infof(\"DB type of %s is empty\", tableName)\n\t}\n\treturn nil\n}\n\nfunc (dt *DbTable) String() string {\n\tif dt.dbName == \"\" {\n\t\treturn dt.tableName\n\t}\n\treturn fmt.Sprintf(\"%s.%s\", dt.dbName, dt.tableName)\n}\n\nfunc NewDbTable(db, table string) DbTable {\n\treturn DbTable{dbName: db, tableName: table}\n}\n\nfunc NewDbTableFromString(dbTableName string) (DbTable, error) {\n\tss := strings.Split(dbTableName, \".\")\n\tif len(ss) > 2 || len(ss) < 1 {\n\t\treturn DbTable{}, fmt.Errorf(\"NewDbTableFromString: invalid dbTableName %v\", dbTableName)\n\t}\n\tif len(ss) == 1 {\n\t\treturn DbTable{tableName: ss[0]}, nil\n\t}\n\treturn DbTable{dbName: ss[0], tableName: ss[1]}, nil\n}\n\nfunc (dt *DbTable) SetDBType(dbType DBType) {\n\tdt.dbType = dbType\n}\n\nfunc (dt *DbTable) GetTableName() string {\n\treturn dt.tableName\n}\n\nfunc (dt *DbTable) GetDbName() string {\n\treturn dt.dbName\n}\n\n// RewriteTableRefsAndGetDBType rewrites the tableRefs with local db_dbname.table_name and get db type of table\nfunc RewriteTableRefsAndGetDBType(m map[DbTable]DbTable, tableRefs []string) ([]string, DBType, error) {\n\tdbType := DBTypeUnknown\n\tnewTableRefs := make([]string, 0, len(tableRefs))\n\tfor _, dbTableName := range tableRefs {\n\t\tDbTable, err := NewDbTableFromString(dbTableName)\n\t\tif err != nil {\n\t\t\treturn nil, DBTypeUnknown, err\n\t\t}\n\t\tdbTable, ok := m[DbTable]\n\t\tif !ok {\n\t\t\treturn nil, DBTypeUnknown, fmt.Errorf(\"table %s not found\", DbTable.String())\n\t\t}\n\t\tnewTableRefs = append(newTableRefs, dbTable.String())\n\t\tif dbTable.dbType == DBTypeUnknown {\n\t\t\tcontinue\n\t\t}\n\t\tif dbType != DBTypeUnknown && dbTable.dbType != dbType {\n\t\t\treturn nil, DBTypeUnknown, fmt.Errorf(\"table %s has wrong db type %+v\", DbTable.String(), dbTable.dbType)\n\t\t}\n\t\tdbType = dbTable.dbType\n\t}\n\tif dbType == DBTypeUnknown {\n\t\tdbType = DBTypeMySQL\n\t}\n\treturn newTableRefs, dbType, nil\n}\n\n// replace ref table name by local table name\ntype DbTableRewriter struct {\n\terr error\n\tm   map[DbTable]DbTable\n}\n\nfunc NewDbTableRewriter(m map[DbTable]DbTable) *DbTableRewriter {\n\treturn &DbTableRewriter{m: m}\n}\n\nfunc (r *DbTableRewriter) Enter(in ast.Node) (ast.Node, bool) {\n\treturn in, r.err != nil\n}\n\nfunc (r *DbTableRewriter) Leave(in ast.Node) (ast.Node, bool) {\n\tswitch x := in.(type) {\n\tcase *ast.TableSource:\n\t\tif t, ok := x.Source.(*ast.TableName); ok {\n\t\t\tr.rewriteDbTableName(t)\n\t\t}\n\tcase *ast.ColumnNameExpr:\n\t\tr.rewriteDbTableName4Column(in.(*ast.ColumnNameExpr).Name)\n\tcase *ast.ColumnName:\n\t\tr.rewriteDbTableName4Column(in.(*ast.ColumnName))\n\t}\n\n\treturn in, r.err == nil\n}\n\nfunc (r *DbTableRewriter) rewriteDbTableName(t *ast.TableName) {\n\tfor from, to := range r.m {\n\t\tif from.dbName == t.Schema.String() && from.tableName == t.Name.String() {\n\t\t\tt.Schema = model.NewCIStr(to.dbName)\n\t\t\tt.Name = model.NewCIStr(to.tableName)\n\t\t}\n\t}\n}\n\nfunc (r *DbTableRewriter) rewriteDbTableName4Column(t *ast.ColumnName) {\n\tfor from, to := range r.m {\n\t\tif from.dbName == t.Schema.String() && from.tableName == t.Table.String() {\n\t\t\tt.Schema = model.NewCIStr(to.dbName)\n\t\t\tt.Table = model.NewCIStr(to.tableName)\n\t\t}\n\t}\n}\n\nfunc (r *DbTableRewriter) Error() error {\n\treturn r.err\n}\n\n// retrieval all table used by logical plan\ntype DbTableVisitor struct {\n\terr    error\n\ttables []DbTable\n}\n\nfunc NewDbTableVisitor() *DbTableVisitor {\n\treturn &DbTableVisitor{tables: make([]DbTable, 0)}\n}\n\nfunc (r *DbTableVisitor) Enter(in ast.Node) (ast.Node, bool) {\n\treturn in, r.err != nil\n}\n\nfunc (r *DbTableVisitor) Leave(in ast.Node) (ast.Node, bool) {\n\tswitch x := in.(type) {\n\tcase *ast.TableSource:\n\t\tif t, ok := x.Source.(*ast.TableName); ok {\n\t\t\tr.tables = append(r.tables, NewDbTable(t.Schema.String(), t.Name.String()))\n\t\t}\n\t}\n\treturn in, r.err == nil\n}\n\nfunc (r *DbTableVisitor) Error() error {\n\treturn r.err\n}\n\nfunc (r *DbTableVisitor) Tables() []DbTable {\n\treturn r.tables\n}\n\n// RewriteSQLFromLP create sql string from lp with dialect\nfunc RewriteSQLFromLP(lp LogicalPlan, m map[DbTable]DbTable, needRewrite bool) (sql string, newTableRefs []string, err error) {\n\tvar dialect Dialect\n\tdialect = NewMySQLDialect()\n\t// use MySQL as default dialect to get ref tables\n\tctx, err := BuildChildCtx(dialect, lp)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\tstmt, err := ctx.GetSQLStmt()\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\ttableRefs := ctx.GetTableRefs()\n\tdbType := DBTypeMySQL\n\n\tif needRewrite {\n\t\tnewTableRefs, dbType, err = RewriteTableRefsAndGetDBType(m, tableRefs)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tif dbType != DBTypeMySQL {\n\t\t\tok := true\n\t\t\tdialect, ok = DBDialectMap[dbType]\n\t\t\tif !ok {\n\t\t\t\treturn \"\", nil, fmt.Errorf(\"failed to find dialect for db type %v\", dbType)\n\t\t\t}\n\t\t\tctx, err := BuildChildCtx(dialect, lp)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", nil, err\n\t\t\t}\n\t\t\tstmt, err = ctx.GetSQLStmt()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", nil, err\n\t\t\t}\n\t\t}\n\n\t\tr := NewDbTableRewriter(m)\n\t\tstmt.Accept(r)\n\t\tif r.Error() != nil {\n\t\t\terr = r.Error()\n\t\t\treturn\n\t\t}\n\t} else {\n\t\tnewTableRefs = tableRefs\n\t}\n\n\tb := new(bytes.Buffer)\n\tif err := stmt.Restore(format.NewRestoreCtxWithDialect(dialect.GetRestoreFlags(), b, dialect.GetFormatDialect())); err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\treturn b.String() + \";\", newTableRefs, nil\n}\n\nfunc ReplaceTableNameInSQL(sql string, dialect format.Dialect, restoreFlags format.RestoreFlags, m map[DbTable]DbTable) (newSql string, err error) {\n\tp := parser.New()\n\tstmts, _, err := p.Parse(sql, \"\", \"\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tstmt := stmts[0]\n\tr := NewDbTableRewriter(m)\n\tstmt.Accept(r)\n\tif r.Error() != nil {\n\t\terr = r.Error()\n\t\treturn\n\t}\n\tb := new(bytes.Buffer)\n\tif err := stmt.Restore(format.NewRestoreCtxWithDialect(restoreFlags, b, dialect)); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn b.String(), nil\n}\n\nfunc GetSourceTables(sql string) ([]DbTable, error) {\n\tp := parser.New()\n\tstmts, _, err := p.Parse(sql, \"\", \"\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tstmt := stmts[0]\n\tr := NewDbTableVisitor()\n\tstmt.Accept(r)\n\tif r.Error() != nil {\n\t\terr = r.Error()\n\t\treturn nil, err\n\t}\n\treturn r.tables, nil\n}\n\ntype PreparedParamsVisitor struct {\n\terr            error\n\tpreparedParams *variable.PreparedParams\n\t// used params\n\tusedParams map[string]struct{}\n}\n\nfunc NewPreparedParamsVisitor(params *variable.PreparedParams) *PreparedParamsVisitor {\n\treturn &PreparedParamsVisitor{preparedParams: params, usedParams: make(map[string]struct{})}\n}\n\nfunc (v *PreparedParamsVisitor) Enter(in ast.Node) (ast.Node, bool) {\n\tif len(*v.preparedParams) == 0 {\n\t\treturn in, false\n\t}\n\treturn in, v.err != nil\n}\n\nfunc (v *PreparedParamsVisitor) Leave(in ast.Node) (ast.Node, bool) {\n\tswitch x := in.(type) {\n\tcase *driver.ParamMarkerExpr:\n\t\tif d, ok := v.preparedParams.GetPreparedParam(x.ParamName); ok {\n\t\t\tx.Datum = *d\n\t\t} else {\n\t\t\tv.err = fmt.Errorf(\"param %s not found\", x.ParamName)\n\t\t}\n\t\tv.usedParams[x.ParamName] = struct{}{}\n\t}\n\treturn in, v.err == nil\n}\n\nfunc (v *PreparedParamsVisitor) Error() error {\n\tif v.err != nil {\n\t\treturn v.err\n\t}\n\tfor paramName := range *v.preparedParams {\n\t\tif _, ok := v.usedParams[paramName]; !ok {\n\t\t\treturn fmt.Errorf(\"param %s not used\", paramName)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/planner/core/rewrite_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n)\n\nfunc TestRestoreSQL(t *testing.T) {\n\tr := require.New(t)\n\tsql := \"select * from dt1.test\"\n\ttables, err := GetSourceTables(sql)\n\tr.NoError(err)\n\tr.Equal(1, len(tables))\n\n\tsql = \"select * from dt1.test join dt2.test\"\n\ttables, err = GetSourceTables(sql)\n\tr.NoError(err)\n\tr.Equal(2, len(tables))\n\tr.Equal(\"dt1.test\", tables[0].String())\n\tr.Equal(\"dt2.test\", tables[1].String())\n\n\tsql = \"select * from dt1.test where id in (select id from dt2.test)\"\n\ttables, err = GetSourceTables(sql)\n\tr.NoError(err)\n\tr.Equal(2, len(tables))\n\tr.Equal(\"dt1.test\", tables[0].String())\n\tr.Equal(\"dt2.test\", tables[1].String())\n\n\tm := map[DbTable]DbTable{\n\t\tNewDbTable(\"dt1\", \"test\"): NewDbTable(\"newdb1\", \"newtable1\"),\n\t\tNewDbTable(\"dt2\", \"test\"): NewDbTable(\"newdb2\", \"newtable2\"),\n\t}\n\n\tnewSql, err := ReplaceTableNameInSQL(sql, format.NewMySQLDialect(), format.DefaultRestoreFlags, m)\n\tr.NoError(err)\n\tr.Equal(\"SELECT * FROM `newdb1`.`newtable1` WHERE `id` IN (SELECT `id` FROM `newdb2`.`newtable2`)\", newSql)\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_aggregation_elimination.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"math\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\ntype aggregationEliminateChecker struct {\n}\n\n// tryToEliminateAggregation will eliminate aggregation grouped by unique key.\n// e.g. select min(b) from t group by a. If a is a unique key, then this sql is equal to `select b from t group by a`.\n// For count(expr), sum(expr), avg(expr), count(distinct expr, [expr...]) we may need to rewrite the expr. Details are shown below.\n// If we can eliminate agg successful, we return a projection. Else we return a nil pointer.\nfunc (a *aggregationEliminateChecker) tryToEliminateAggregation(agg *LogicalAggregation) *LogicalProjection {\n\tfor _, af := range agg.AggFuncs {\n\t\t// TODO(issue #9968): Actually, we can rewrite GROUP_CONCAT when all the\n\t\t// arguments it accepts are promised to be NOT-NULL.\n\t\t// When it accepts only 1 argument, we can extract this argument into a\n\t\t// projection.\n\t\t// When it accepts multiple arguments, we can wrap the arguments with a\n\t\t// function CONCAT_WS and extract this function into a projection.\n\t\t// BUT, GROUP_CONCAT should truncate the final result according to the\n\t\t// system variable `group_concat_max_len`. To ensure the correctness of\n\t\t// the result, we close the elimination of GROUP_CONCAT here.\n\t\tif af.Name == ast.AggFuncGroupConcat {\n\t\t\treturn nil\n\t\t}\n\t}\n\tschemaByGroupby := expression.NewSchema(agg.groupByCols...)\n\tcoveredByUniqueKey := false\n\tfor _, key := range agg.children[0].Schema().Keys {\n\t\tif schemaByGroupby.ColumnsIndices(key) != nil {\n\t\t\tcoveredByUniqueKey = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif coveredByUniqueKey {\n\t\t// GroupByCols has unique key, so this aggregation can be removed.\n\t\tproj := a.convertAggToProj(agg)\n\t\tproj.SetChildren(agg.children[0])\n\t\treturn proj\n\t}\n\treturn nil\n}\n\nfunc (a *aggregationEliminateChecker) convertAggToProj(agg *LogicalAggregation) *LogicalProjection {\n\tproj := LogicalProjection{\n\t\tExprs: make([]expression.Expression, 0, len(agg.AggFuncs)),\n\t}.Init(agg.ctx, agg.blockOffset)\n\tfor _, fun := range agg.AggFuncs {\n\t\texpr := a.rewriteExpr(agg.ctx, fun)\n\t\tproj.Exprs = append(proj.Exprs, expr)\n\t}\n\tproj.SetSchema(agg.schema.Clone())\n\treturn proj\n}\n\n// rewriteExpr will rewrite the aggregate function to expression doesn't contain aggregate function.\nfunc (a *aggregationEliminateChecker) rewriteExpr(ctx sessionctx.Context, aggFunc *aggregation.AggFuncDesc) expression.Expression {\n\tswitch aggFunc.Name {\n\tcase ast.AggFuncCount:\n\t\tif aggFunc.Mode == aggregation.FinalMode {\n\t\t\treturn a.wrapCastFunction(ctx, aggFunc.Args[0], aggFunc.RetTp)\n\t\t}\n\t\treturn a.rewriteCount(ctx, aggFunc.Args, aggFunc.RetTp)\n\tcase ast.AggFuncSum, ast.AggFuncAvg, ast.AggFuncFirstRow, ast.AggFuncMax, ast.AggFuncMin, ast.AggFuncGroupConcat:\n\t\treturn a.wrapCastFunction(ctx, aggFunc.Args[0], aggFunc.RetTp)\n\tcase ast.AggFuncBitAnd, ast.AggFuncBitOr, ast.AggFuncBitXor:\n\t\treturn a.rewriteBitFunc(ctx, aggFunc.Name, aggFunc.Args[0], aggFunc.RetTp)\n\tdefault:\n\t\tpanic(\"Unsupported function\")\n\t}\n}\n\nfunc (a *aggregationEliminateChecker) rewriteCount(ctx sessionctx.Context, exprs []expression.Expression, targetTp *types.FieldType) expression.Expression {\n\t// If is count(expr), we will change it to if(isnull(expr), 0, 1).\n\t// If is count(distinct x, y, z) we will change it to if(isnull(x) or isnull(y) or isnull(z), 0, 1).\n\t// If is count(expr not null), we will change it to constant 1.\n\tisNullExprs := make([]expression.Expression, 0, len(exprs))\n\tfor _, expr := range exprs {\n\t\tif mysql.HasNotNullFlag(expr.GetType().Flag) {\n\t\t\tisNullExprs = append(isNullExprs, expression.Zero)\n\t\t} else {\n\t\t\tisNullExpr := expression.NewFunctionInternal(ctx, ast.IsNull, types.NewFieldType(mysql.TypeTiny), expr)\n\t\t\tisNullExprs = append(isNullExprs, isNullExpr)\n\t\t}\n\t}\n\n\tinnerExpr := expression.ComposeDNFCondition(ctx, isNullExprs...)\n\tnewExpr := expression.NewFunctionInternal(ctx, ast.If, targetTp, innerExpr, expression.Zero, expression.One)\n\treturn newExpr\n}\n\nfunc (a *aggregationEliminateChecker) rewriteBitFunc(ctx sessionctx.Context, funcType string, arg expression.Expression, targetTp *types.FieldType) expression.Expression {\n\t// For not integer type. We need to cast(cast(arg as signed) as unsigned) to make the bit function work.\n\tinnerCast := expression.WrapWithCastAsInt(ctx, arg)\n\touterCast := a.wrapCastFunction(ctx, innerCast, targetTp)\n\tvar finalExpr expression.Expression\n\tif funcType != ast.AggFuncBitAnd {\n\t\tfinalExpr = expression.NewFunctionInternal(ctx, ast.Ifnull, targetTp, outerCast, expression.Zero.Clone())\n\t} else {\n\t\tfinalExpr = expression.NewFunctionInternal(ctx, ast.Ifnull, outerCast.GetType(), outerCast, &expression.Constant{Value: types.NewUintDatum(math.MaxUint64), RetType: targetTp})\n\t}\n\treturn finalExpr\n}\n\n// wrapCastFunction will wrap a cast if the targetTp is not equal to the arg's.\nfunc (a *aggregationEliminateChecker) wrapCastFunction(ctx sessionctx.Context, arg expression.Expression, targetTp *types.FieldType) expression.Expression {\n\tif arg.GetType() == targetTp {\n\t\treturn arg\n\t}\n\treturn expression.BuildCastFunction(ctx, arg, targetTp)\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_aggregation_push_down.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n// // Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Modified by Ant Group in 2023\n\npackage core\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\ntype aggregationPushDownSolver struct {\n\taggregationEliminateChecker\n}\n\n// isDecomposable checks if an aggregate function is decomposable. An aggregation function $F$ is decomposable\n// if there exist aggregation functions F_1 and F_2 such that F(S_1 union all S_2) = F_2(F_1(S_1),F_1(S_2)),\n// where S_1 and S_2 are two sets of values. We call S_1 and S_2 partial groups.\n// It's easy to see that max, min, first row is decomposable, no matter whether it's distinct, but sum(distinct) and\n// count(distinct) is not.\n// Currently we don't support avg and concat.\nfunc (a *aggregationPushDownSolver) isDecomposable(fun *aggregation.AggFuncDesc) bool {\n\tswitch fun.Name {\n\tcase ast.AggFuncAvg, ast.AggFuncGroupConcat, ast.AggFuncVarPop:\n\t\t// TODO: Support avg push down.\n\t\treturn false\n\tcase ast.AggFuncMax, ast.AggFuncMin, ast.AggFuncFirstRow:\n\t\treturn true\n\tcase ast.AggFuncSum, ast.AggFuncCount:\n\t\treturn !fun.HasDistinct\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// getAggFuncChildIdx gets which children it belongs to, 0 stands for left, 1 stands for right, -1 stands for both.\nfunc (a *aggregationPushDownSolver) getAggFuncChildIdx(aggFunc *aggregation.AggFuncDesc, schema *expression.Schema) int {\n\tfromLeft, fromRight := false, false\n\tvar cols []*expression.Column\n\tcols = expression.ExtractColumnsFromExpressions(cols, aggFunc.Args, nil)\n\tfor _, col := range cols {\n\t\tif schema.Contains(col) {\n\t\t\tfromLeft = true\n\t\t} else {\n\t\t\tfromRight = true\n\t\t}\n\t}\n\tif fromLeft && fromRight {\n\t\treturn -1\n\t} else if fromLeft {\n\t\treturn 0\n\t}\n\treturn 1\n}\n\n// collectAggFuncs collects all aggregate functions and splits them into two parts: \"leftAggFuncs\" and \"rightAggFuncs\" whose\n// arguments are all from left child or right child separately. If some aggregate functions have the arguments that have\n// columns both from left and right children, the whole aggregation is forbidden to push down.\nfunc (a *aggregationPushDownSolver) collectAggFuncs(agg *LogicalAggregation, join *LogicalJoin) (valid bool, leftAggFuncs, rightAggFuncs []*aggregation.AggFuncDesc) {\n\tvalid = true\n\tleftChild := join.children[0]\n\tfor _, aggFunc := range agg.AggFuncs {\n\t\tif !a.isDecomposable(aggFunc) {\n\t\t\treturn false, nil, nil\n\t\t}\n\t\tindex := a.getAggFuncChildIdx(aggFunc, leftChild.Schema())\n\t\tswitch index {\n\t\tcase 0:\n\t\t\tleftAggFuncs = append(leftAggFuncs, aggFunc)\n\t\tcase 1:\n\t\t\trightAggFuncs = append(rightAggFuncs, aggFunc)\n\t\tdefault:\n\t\t\treturn false, nil, nil\n\t\t}\n\t}\n\treturn\n}\n\n// collectGbyCols collects all columns from gby-items and join-conditions and splits them into two parts: \"leftGbyCols\" and\n// \"rightGbyCols\". e.g. For query \"SELECT SUM(B.id) FROM A, B WHERE A.c1 = B.c1 AND A.c2 != B.c2 GROUP BY B.c3\" , the optimized\n// query should be \"SELECT SUM(B.agg) FROM A, (SELECT SUM(id) as agg, c1, c2, c3 FROM B GROUP BY id, c1, c2, c3) as B\n// WHERE A.c1 = B.c1 AND A.c2 != B.c2 GROUP BY B.c3\". As you see, all the columns appearing in join-conditions should be\n// treated as group by columns in join subquery.\nfunc (a *aggregationPushDownSolver) collectGbyCols(agg *LogicalAggregation, join *LogicalJoin) (leftGbyCols, rightGbyCols []*expression.Column) {\n\tleftChild := join.children[0]\n\tctx := agg.ctx\n\tfor _, gbyExpr := range agg.GroupByItems {\n\t\tcols := expression.ExtractColumns(gbyExpr)\n\t\tfor _, col := range cols {\n\t\t\tif leftChild.Schema().Contains(col) {\n\t\t\t\tleftGbyCols = append(leftGbyCols, col)\n\t\t\t} else {\n\t\t\t\trightGbyCols = append(rightGbyCols, col)\n\t\t\t}\n\t\t}\n\t}\n\t// extract equal conditions\n\tfor _, eqFunc := range join.EqualConditions {\n\t\tleftGbyCols = a.addGbyCol(ctx, leftGbyCols, eqFunc.GetArgs()[0].(*expression.Column))\n\t\trightGbyCols = a.addGbyCol(ctx, rightGbyCols, eqFunc.GetArgs()[1].(*expression.Column))\n\t}\n\tfor _, leftCond := range join.LeftConditions {\n\t\tcols := expression.ExtractColumns(leftCond)\n\t\tleftGbyCols = a.addGbyCol(ctx, leftGbyCols, cols...)\n\t}\n\tfor _, rightCond := range join.RightConditions {\n\t\tcols := expression.ExtractColumns(rightCond)\n\t\trightGbyCols = a.addGbyCol(ctx, rightGbyCols, cols...)\n\t}\n\tfor _, otherCond := range join.OtherConditions {\n\t\tcols := expression.ExtractColumns(otherCond)\n\t\tfor _, col := range cols {\n\t\t\tif leftChild.Schema().Contains(col) {\n\t\t\t\tleftGbyCols = a.addGbyCol(ctx, leftGbyCols, col)\n\t\t\t} else {\n\t\t\t\trightGbyCols = a.addGbyCol(ctx, rightGbyCols, col)\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\nfunc (a *aggregationPushDownSolver) splitAggFuncsAndGbyCols(agg *LogicalAggregation, join *LogicalJoin) (valid bool,\n\tleftAggFuncs, rightAggFuncs []*aggregation.AggFuncDesc,\n\tleftGbyCols, rightGbyCols []*expression.Column) {\n\tvalid, leftAggFuncs, rightAggFuncs = a.collectAggFuncs(agg, join)\n\tif !valid {\n\t\treturn\n\t}\n\tleftGbyCols, rightGbyCols = a.collectGbyCols(agg, join)\n\treturn\n}\n\n// addGbyCol adds a column to gbyCols. If a group by column has existed, it will not be added repeatedly.\nfunc (a *aggregationPushDownSolver) addGbyCol(ctx sessionctx.Context, gbyCols []*expression.Column, cols ...*expression.Column) []*expression.Column {\n\tfor _, c := range cols {\n\t\tduplicate := false\n\t\tfor _, gbyCol := range gbyCols {\n\t\t\tif c.Equal(ctx, gbyCol) {\n\t\t\t\tduplicate = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !duplicate {\n\t\t\tgbyCols = append(gbyCols, c)\n\t\t}\n\t}\n\treturn gbyCols\n}\n\n// checkValidJoin checks if this join should be pushed across.\nfunc (a *aggregationPushDownSolver) checkValidJoin(join *LogicalJoin) bool {\n\treturn join.JoinType == InnerJoin || join.JoinType == LeftOuterJoin || join.JoinType == RightOuterJoin\n}\n\n// decompose splits an aggregate function to two parts: a final mode function and a partial mode function. Currently\n// there are no differences between partial mode and complete mode, so we can confuse them.\nfunc (a *aggregationPushDownSolver) decompose(ctx sessionctx.Context, aggFunc *aggregation.AggFuncDesc, schema *expression.Schema) ([]*aggregation.AggFuncDesc, *expression.Schema) {\n\t// Result is a slice because avg should be decomposed to sum and count. Currently we don't process this case.\n\tresult := []*aggregation.AggFuncDesc{aggFunc.Clone()}\n\tfor _, aggFunc := range result {\n\t\tschema.Append(&expression.Column{\n\t\t\tUniqueID: ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t\tRetType:  aggFunc.RetTp,\n\t\t})\n\t}\n\taggFunc.Args = expression.Column2Exprs(schema.Columns[schema.Len()-len(result):])\n\taggFunc.Mode = aggregation.FinalMode\n\treturn result, schema\n}\n\n// tryToPushDownAgg tries to push down an aggregate function into a join path. If all aggFuncs are first row, we won't\n// process it temporarily. If not, We will add additional group by columns and first row functions. We make a new aggregation operator.\n// If the pushed aggregation is grouped by unique key, it's no need to push it down.\nfunc (a *aggregationPushDownSolver) tryToPushDownAgg(aggFuncs []*aggregation.AggFuncDesc, gbyCols []*expression.Column, join *LogicalJoin, childIdx int, aggHints aggHintInfo, blockOffset int) (_ LogicalPlan, err error) {\n\tchild := join.children[childIdx]\n\tif aggregation.IsAllFirstRow(aggFuncs) {\n\t\treturn child, nil\n\t}\n\t// If the join is multiway-join, we forbid pushing down.\n\tif _, ok := join.children[childIdx].(*LogicalJoin); ok {\n\t\treturn child, nil\n\t}\n\ttmpSchema := expression.NewSchema(gbyCols...)\n\tfor _, key := range child.Schema().Keys {\n\t\tif tmpSchema.ColumnsIndices(key) != nil {\n\t\t\treturn child, nil\n\t\t}\n\t}\n\tagg, err := a.makeNewAgg(join.ctx, aggFuncs, gbyCols, aggHints, blockOffset)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tagg.SetChildren(child)\n\t// If agg has no group-by item, it will return a default value, which may cause some bugs.\n\t// So here we add a group-by item forcely.\n\tif len(agg.GroupByItems) == 0 {\n\t\tagg.GroupByItems = []expression.Expression{&expression.Constant{\n\t\t\tValue:   types.NewDatum(0),\n\t\t\tRetType: types.NewFieldType(mysql.TypeLong)}}\n\t}\n\tif (childIdx == 0 && join.JoinType == RightOuterJoin) || (childIdx == 1 && join.JoinType == LeftOuterJoin) {\n\t\tvar existsDefaultValues bool\n\t\tjoin.DefaultValues, existsDefaultValues = a.getDefaultValues(agg)\n\t\t_, existsDefaultValues = a.getDefaultValues(agg)\n\t\tif !existsDefaultValues {\n\t\t\treturn child, nil\n\t\t}\n\t}\n\treturn agg, nil\n}\n\nfunc (a *aggregationPushDownSolver) getDefaultValues(agg *LogicalAggregation) ([]types.Datum, bool) {\n\tdefaultValues := make([]types.Datum, 0, agg.Schema().Len())\n\tfor _, aggFunc := range agg.AggFuncs {\n\t\tvalue, existsDefaultValue := aggFunc.EvalNullValueInOuterJoin(agg.ctx, agg.children[0].Schema())\n\t\tif !existsDefaultValue {\n\t\t\treturn nil, false\n\t\t}\n\t\tdefaultValues = append(defaultValues, value)\n\t}\n\treturn defaultValues, true\n}\n\nfunc (a *aggregationPushDownSolver) checkAnyCountAndSum(aggFuncs []*aggregation.AggFuncDesc) bool {\n\tfor _, fun := range aggFuncs {\n\t\tif fun.Name == ast.AggFuncSum || fun.Name == ast.AggFuncCount {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (a *aggregationPushDownSolver) makeNewAgg(ctx sessionctx.Context, aggFuncs []*aggregation.AggFuncDesc, gbyCols []*expression.Column, aggHints aggHintInfo, blockOffset int) (*LogicalAggregation, error) {\n\tnewAgg := LogicalAggregation{\n\t\tGroupByItems: expression.Column2Exprs(gbyCols),\n\t\tgroupByCols:  gbyCols,\n\t\taggHints:     aggHints,\n\t}.Init(ctx, blockOffset)\n\taggLen := len(aggFuncs) + len(gbyCols)\n\tnewAggFuncDescs := make([]*aggregation.AggFuncDesc, 0, aggLen)\n\tnewSchema := expression.NewSchema(make([]*expression.Column, 0, aggLen)...)\n\tfor _, aggFunc := range aggFuncs {\n\t\tvar newFuncs []*aggregation.AggFuncDesc\n\t\tnewFuncs, newSchema = a.decompose(ctx, aggFunc, newSchema)\n\t\tnewAggFuncDescs = append(newAggFuncDescs, newFuncs...)\n\t}\n\tfor i, gbyCol := range gbyCols {\n\t\tfirstRow, err := aggregation.NewAggFuncDesc(newAgg.ctx, ast.AggFuncFirstRow, []expression.Expression{gbyCol}, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnewCol, ok := gbyCol.Clone().(*expression.Column)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"makeNewAgg: clone column err\")\n\t\t}\n\t\tnewCol.RetType = firstRow.RetTp\n\n\t\tduplicateFirstRow := false\n\t\tfor j, aggFunc := range newAggFuncDescs {\n\t\t\tif firstRow.Equal(ctx, aggFunc) {\n\t\t\t\tduplicateFirstRow = true\n\t\t\t\tgbyCols[i].UniqueID = newSchema.Columns[j].UniqueID\n\t\t\t}\n\t\t}\n\t\tif !duplicateFirstRow {\n\t\t\tnewAggFuncDescs = append(newAggFuncDescs, firstRow)\n\t\t\tnewSchema.Append(newCol)\n\t\t}\n\t}\n\tnewAgg.AggFuncs = newAggFuncDescs\n\tnewAgg.SetSchema(newSchema)\n\t// TODO: Add a Projection if any argument of aggregate funcs or group by items are scalar functions.\n\t// agg.buildProjectionIfNecessary()\n\treturn newAgg, nil\n}\n\n// pushAggCrossUnion will try to push the agg down to the union. If the new aggregation's group-by columns doesn't contain unique key.\n// We will return the new aggregation. Otherwise we will transform the aggregation to projection.\n// TODO(yang.y): merge duplicated first_row\nfunc (a *aggregationPushDownSolver) pushAggCrossUnion(agg *LogicalAggregation, unionSchema *expression.Schema, unionChild LogicalPlan) LogicalPlan {\n\tctx := agg.ctx\n\tnewAgg := LogicalAggregation{\n\t\tAggFuncs:           make([]*aggregation.AggFuncDesc, 0, len(agg.AggFuncs)),\n\t\tGroupByItems:       make([]expression.Expression, 0, len(agg.GroupByItems)),\n\t\taggHints:           agg.aggHints,\n\t\tProducedByDistinct: agg.ProducedByDistinct,\n\t}.Init(ctx, agg.blockOffset)\n\tnewAgg.SetSchema(agg.schema.Clone())\n\tfor _, aggFunc := range agg.AggFuncs {\n\t\tnewAggFunc := aggFunc.Clone()\n\t\tnewArgs := make([]expression.Expression, 0, len(newAggFunc.Args))\n\t\tfor _, arg := range newAggFunc.Args {\n\t\t\tnewArgs = append(newArgs, expression.ColumnSubstitute(arg, unionSchema, expression.Column2Exprs(unionChild.Schema().Columns)))\n\t\t}\n\t\tnewAggFunc.Args = newArgs\n\t\tnewAgg.AggFuncs = append(newAgg.AggFuncs, newAggFunc)\n\t}\n\tfor _, gbyExpr := range agg.GroupByItems {\n\t\tnewExpr := expression.ColumnSubstitute(gbyExpr, unionSchema, expression.Column2Exprs(unionChild.Schema().Columns))\n\t\tnewAgg.GroupByItems = append(newAgg.GroupByItems, newExpr)\n\t}\n\tnewAgg.collectGroupByColumns()\n\ttmpSchema := expression.NewSchema(newAgg.groupByCols...)\n\t// e.g. Union distinct will add a aggregation like `select join_agg_0, join_agg_1, join_agg_2 from t group by a, b, c` above UnionAll.\n\t// And the pushed agg will be something like `select a, b, c, a, b, c from t group by a, b, c`. So if we just return child as join does,\n\t// this will cause error during executor phase.\n\tfor _, key := range unionChild.Schema().Keys {\n\t\tif tmpSchema.ColumnsIndices(key) != nil {\n\t\t\tproj := a.convertAggToProj(newAgg)\n\t\t\tproj.SetChildren(unionChild)\n\t\t\treturn proj\n\t\t}\n\t}\n\tnewAgg.SetChildren(unionChild)\n\treturn newAgg\n}\n\nfunc (a *aggregationPushDownSolver) optimize(ctx context.Context, p LogicalPlan) (LogicalPlan, error) {\n\tif err := CheckAggFuncArgInGroupByItems(p); err != nil {\n\t\treturn nil, err\n\t}\n\treturn a.aggPushDown(p)\n}\n\nfunc (a *aggregationPushDownSolver) tryAggPushDownForUnion(union *LogicalUnionAll, agg *LogicalAggregation) error {\n\tfor _, aggFunc := range agg.AggFuncs {\n\t\tif !a.isDecomposable(aggFunc) {\n\t\t\treturn nil\n\t\t}\n\t}\n\tvar gbyCols []*expression.Column\n\tgbyCols = expression.ExtractColumnsFromExpressions(gbyCols, agg.GroupByItems, nil)\n\tpushedAgg, err := a.makeNewAgg(agg.ctx, agg.AggFuncs, gbyCols, agg.aggHints, agg.blockOffset)\n\tif err != nil {\n\t\treturn err\n\t}\n\tpushedAgg.ProducedByDistinct = agg.ProducedByDistinct\n\tnewChildren := make([]LogicalPlan, 0, len(union.children))\n\tfor _, child := range union.children {\n\t\tnewChild := a.pushAggCrossUnion(pushedAgg, union.Schema(), child)\n\t\tnewChildren = append(newChildren, newChild)\n\t}\n\tunion.SetSchema(expression.NewSchema(newChildren[0].Schema().Columns...))\n\tunion.SetChildren(newChildren...)\n\treturn nil\n}\n\nfunc CheckAggFuncArgInGroupByItems(p LogicalPlan) error {\n\tfor _, child := range p.Children() {\n\t\terr := CheckAggFuncArgInGroupByItems(child)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tagg, ok := p.(*LogicalAggregation)\n\tif !ok {\n\t\treturn nil\n\t}\n\tfor _, aggFunc := range agg.AggFuncs {\n\t\tif aggFunc.Name == ast.AggFuncFirstRow {\n\t\t\tIsArgInGroupKeys := false\n\t\t\tif _, ok := aggFunc.Args[0].(*expression.Constant); ok {\n\t\t\t\tIsArgInGroupKeys = true\n\t\t\t}\n\t\t\tif !IsArgInGroupKeys {\n\t\t\t\tfor _, item := range agg.GroupByItems {\n\t\t\t\t\tif ok := aggFunc.Args[0].Equal(agg.ctx, item); ok {\n\t\t\t\t\t\tIsArgInGroupKeys = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !IsArgInGroupKeys {\n\t\t\t\treturn fmt.Errorf(\"failed to check aggregate function: select column (%+v) is not in group by items %+v\", aggFunc.Args[0], agg.GroupByItems)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// aggPushDown tries to push down aggregate functions to join paths.\nfunc (a *aggregationPushDownSolver) aggPushDown(p LogicalPlan) (_ LogicalPlan, err error) {\n\tif agg, ok := p.(*LogicalAggregation); ok {\n\t\tproj := a.tryToEliminateAggregation(agg)\n\t\tif proj != nil {\n\t\t\tp = proj\n\t\t} else {\n\t\t\tchild := agg.children[0]\n\t\t\tif join, ok1 := child.(*LogicalJoin); ok1 && a.checkValidJoin(join) {\n\t\t\t\t// NOTE(yang.y): disable push down for join for now. Join node's child usually contains one data source,\n\t\t\t\t// so it is likely translated to RunSQL nodes. The translation from sub logical plan to SQL string hasn't\n\t\t\t\t// support agg node yet.\n\t\t\t\t//\n\t\t\t\t//if valid, leftAggFuncs, rightAggFuncs, leftGbyCols, rightGbyCols := a.splitAggFuncsAndGbyCols(agg, join); valid {\n\t\t\t\t//\tvar lChild, rChild LogicalPlan\n\t\t\t\t//\t// If there exist count or sum functions in left join path, we can't push any\n\t\t\t\t//\t// aggregate function into right join path.\n\t\t\t\t//\trightInvalid := a.checkAnyCountAndSum(leftAggFuncs)\n\t\t\t\t//\tleftInvalid := a.checkAnyCountAndSum(rightAggFuncs)\n\t\t\t\t//\tif rightInvalid {\n\t\t\t\t//\t\trChild = join.children[1]\n\t\t\t\t//\t} else {\n\t\t\t\t//\t\trChild, err = a.tryToPushDownAgg(rightAggFuncs, rightGbyCols, join, 1, agg.aggHints, agg.blockOffset)\n\t\t\t\t//\t\tif err != nil {\n\t\t\t\t//\t\t\treturn nil, err\n\t\t\t\t//\t\t}\n\t\t\t\t//\t}\n\t\t\t\t//\tif leftInvalid {\n\t\t\t\t//\t\tlChild = join.children[0]\n\t\t\t\t//\t} else {\n\t\t\t\t//\t\tlChild, err = a.tryToPushDownAgg(leftAggFuncs, leftGbyCols, join, 0, agg.aggHints, agg.blockOffset)\n\t\t\t\t//\t\tif err != nil {\n\t\t\t\t//\t\t\treturn nil, err\n\t\t\t\t//\t\t}\n\t\t\t\t//\t}\n\t\t\t\t//\tjoin.SetChildren(lChild, rChild)\n\t\t\t\t//\tjoin.SetSchema(expression.MergeSchema(lChild.Schema(), rChild.Schema()))\n\t\t\t\t//\tbuildKeyInfo(join)\n\t\t\t\t//\tproj := a.tryToEliminateAggregation(agg)\n\t\t\t\t//\tif proj != nil {\n\t\t\t\t//\t\tp = proj\n\t\t\t\t//\t}\n\t\t\t\t//}\n\t\t\t} else if proj, ok1 := child.(*LogicalProjection); ok1 {\n\t\t\t\t/// WARNING: this optimization is disable when projection exprs contains scalar function. Because it does not make the execution graph more efficient.\n\t\t\t\t/// On the contrary, it will bring more computation cost. e.g.: compute the same expression more than once.\n\t\t\t\t// TODO: This optimization is not always reasonable. We have not supported pushing projection to kv layer yet,\n\t\t\t\t// so we must do this optimization.\n\t\t\t\tif canProjectionBeEliminatedLoose(proj) {\n\t\t\t\t\tfor i, gbyItem := range agg.GroupByItems {\n\t\t\t\t\t\tagg.GroupByItems[i] = expression.ColumnSubstitute(gbyItem, proj.schema, proj.Exprs)\n\t\t\t\t\t}\n\t\t\t\t\tagg.collectGroupByColumns()\n\t\t\t\t\tfor _, aggFunc := range agg.AggFuncs {\n\t\t\t\t\t\tnewArgs := make([]expression.Expression, 0, len(aggFunc.Args))\n\t\t\t\t\t\tfor _, arg := range aggFunc.Args {\n\t\t\t\t\t\t\tnewArgs = append(newArgs, expression.ColumnSubstitute(arg, proj.schema, proj.Exprs))\n\t\t\t\t\t\t}\n\t\t\t\t\t\taggFunc.Args = newArgs\n\t\t\t\t\t}\n\t\t\t\t\tprojChild := proj.children[0]\n\t\t\t\t\tagg.SetChildren(projChild)\n\t\t\t\t}\n\t\t\t} else if union, ok1 := child.(*LogicalUnionAll); ok1 {\n\t\t\t\tif err := a.tryAggPushDownForUnion(union, agg); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tnewChildren := make([]LogicalPlan, 0, len(p.Children()))\n\tfor _, child := range p.Children() {\n\t\tnewChild, err := a.aggPushDown(child)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnewChildren = append(newChildren, newChild)\n\t}\n\tp.SetChildren(newChildren...)\n\treturn p, nil\n}\n\nfunc (*aggregationPushDownSolver) name() string {\n\treturn \"aggregation_push_down\"\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_build_key_info.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"github.com/secretflow/scql/pkg/expression\"\n)\n\n// buildKeyInfo recursively calls LogicalPlan's BuildKeyInfo method.\nfunc buildKeyInfo(lp LogicalPlan) {\n\tfor _, child := range lp.Children() {\n\t\tbuildKeyInfo(child)\n\t}\n\tchildSchema := make([]*expression.Schema, len(lp.Children()))\n\tfor i, child := range lp.Children() {\n\t\tchildSchema[i] = child.Schema()\n\t}\n\tlp.BuildKeyInfo(lp.Schema(), childSchema)\n}\n\nfunc (p *LogicalJoin) BuildKeyInfo(selfSchema *expression.Schema, childSchema []*expression.Schema) {\n\tp.logicalSchemaProducer.BuildKeyInfo(selfSchema, childSchema)\n\tswitch p.JoinType {\n\tcase SemiJoin, LeftOuterSemiJoin, AntiSemiJoin, AntiLeftOuterSemiJoin:\n\t\tselfSchema.Keys = childSchema[0].Clone().Keys\n\tcase InnerJoin, LeftOuterJoin, RightOuterJoin:\n\t\t// If there is no equal conditions, then cartesian product can't be prevented and unique key information will destroy.\n\t\tif len(p.EqualConditions) == 0 {\n\t\t\treturn\n\t\t}\n\t\tlOk := false\n\t\trOk := false\n\t\t// Such as 'select * from t1 join t2 where t1.a = t2.a and t1.b = t2.b'.\n\t\t// If one sides (a, b) is a unique key, then the unique key information is remained.\n\t\t// But we don't consider this situation currently.\n\t\t// Only key made by one column is considered now.\n\t\tfor _, expr := range p.EqualConditions {\n\t\t\tln := expr.GetArgs()[0].(*expression.Column)\n\t\t\trn := expr.GetArgs()[1].(*expression.Column)\n\t\t\tfor _, key := range childSchema[0].Keys {\n\t\t\t\tif len(key) == 1 && key[0].Equal(p.ctx, ln) {\n\t\t\t\t\tlOk = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, key := range childSchema[1].Keys {\n\t\t\t\tif len(key) == 1 && key[0].Equal(p.ctx, rn) {\n\t\t\t\t\trOk = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// For inner join, if one side of one equal condition is unique key,\n\t\t// another side's unique key information will all be reserved.\n\t\t// If it's an outer join, NULL value will fill some position, which will destroy the unique key information.\n\t\tif lOk && p.JoinType != LeftOuterJoin {\n\t\t\tselfSchema.Keys = append(selfSchema.Keys, childSchema[1].Keys...)\n\t\t}\n\t\tif rOk && p.JoinType != RightOuterJoin {\n\t\t\tselfSchema.Keys = append(selfSchema.Keys, childSchema[0].Keys...)\n\t\t}\n\t}\n}\n\nfunc (p *LogicalProjection) buildSchemaByExprs(selfSchema *expression.Schema) *expression.Schema {\n\tschema := expression.NewSchema(make([]*expression.Column, 0, selfSchema.Len())...)\n\tfor _, expr := range p.Exprs {\n\t\tif col, isCol := expr.(*expression.Column); isCol {\n\t\t\tschema.Append(col)\n\t\t} else {\n\t\t\t// If the expression is not a column, we add a column to occupy the position.\n\t\t\tschema.Append(&expression.Column{\n\t\t\t\t// TODO(tengt): Implement UniqueID logic.\n\t\t\t\t// UniqueID: p.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t\t\tUniqueID: 0,\n\t\t\t\tRetType:  expr.GetType(),\n\t\t\t})\n\t\t}\n\t}\n\treturn schema\n}\n\n// BuildKeyInfo implements LogicalPlan BuildKeyInfo interface.\nfunc (p *LogicalProjection) BuildKeyInfo(selfSchema *expression.Schema, childSchema []*expression.Schema) {\n\tp.logicalSchemaProducer.BuildKeyInfo(selfSchema, childSchema)\n\tschema := p.buildSchemaByExprs(selfSchema)\n\tfor _, key := range childSchema[0].Keys {\n\t\tindices := schema.ColumnsIndices(key)\n\t\tif indices == nil {\n\t\t\tcontinue\n\t\t}\n\t\tnewKey := make([]*expression.Column, 0, len(key))\n\t\tfor _, i := range indices {\n\t\t\tnewKey = append(newKey, selfSchema.Columns[i])\n\t\t}\n\t\tselfSchema.Keys = append(selfSchema.Keys, newKey)\n\t}\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_column_pruning.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n)\n\ntype columnPruner struct {\n}\n\nfunc (s *columnPruner) optimize(ctx context.Context, lp LogicalPlan) (LogicalPlan, error) {\n\terr := lp.PruneColumns(lp.Schema().Columns)\n\treturn lp, err\n}\n\nfunc (*columnPruner) name() string {\n\treturn \"column_prune\"\n}\n\n// ExprsHasSideEffects checks if any of the expressions has side effects.\nfunc ExprsHasSideEffects(exprs []expression.Expression) bool {\n\tfor _, expr := range exprs {\n\t\tif exprHasSetVarOrSleep(expr) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// exprHasSetVarOrSleep checks if the expression has SetVar function or Sleep function.\nfunc exprHasSetVarOrSleep(expr expression.Expression) bool {\n\tscalaFunc, isScalaFunc := expr.(*expression.ScalarFunction)\n\tif !isScalaFunc {\n\t\treturn false\n\t}\n\tif scalaFunc.FuncName.L == ast.SetVar || scalaFunc.FuncName.L == ast.Sleep {\n\t\treturn true\n\t}\n\tfor _, arg := range scalaFunc.GetArgs() {\n\t\tif exprHasSetVarOrSleep(arg) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// PruneColumns implements LogicalPlan interface.\nfunc (p *LogicalSelection) PruneColumns(parentUsedCols []*expression.Column) error {\n\tchild := p.children[0]\n\tused := GetUsedList(parentUsedCols, p.schema)\n\tp.schema.Columns = sliceutil.Take(p.schema.Columns, used)\n\tparentUsedCols = expression.ExtractColumnsFromExpressions(parentUsedCols, p.Conditions, nil)\n\terr := child.PruneColumns(parentUsedCols)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(p.schema.Columns) == 0 {\n\t\tp.schema.Columns = []*expression.Column{child.Schema().Columns[0]}\n\t}\n\treturn nil\n}\n\nfunc (p *LogicalJoin) extractUsedCols(parentUsedCols []*expression.Column) (leftCols []*expression.Column, rightCols []*expression.Column) {\n\tfor _, eqCond := range p.EqualConditions {\n\t\tparentUsedCols = append(parentUsedCols, expression.ExtractColumns(eqCond)...)\n\t}\n\tfor _, leftCond := range p.LeftConditions {\n\t\tparentUsedCols = append(parentUsedCols, expression.ExtractColumns(leftCond)...)\n\t}\n\tfor _, rightCond := range p.RightConditions {\n\t\tparentUsedCols = append(parentUsedCols, expression.ExtractColumns(rightCond)...)\n\t}\n\tfor _, otherCond := range p.OtherConditions {\n\t\tparentUsedCols = append(parentUsedCols, expression.ExtractColumns(otherCond)...)\n\t}\n\tlChild := p.children[0]\n\trChild := p.children[1]\n\tfor _, col := range parentUsedCols {\n\t\tif lChild.Schema().Contains(col) {\n\t\t\tleftCols = append(leftCols, col)\n\t\t} else if rChild.Schema().Contains(col) {\n\t\t\trightCols = append(rightCols, col)\n\t\t}\n\t}\n\treturn leftCols, rightCols\n}\n\nfunc (p *LogicalJoin) mergeSchema(parentUsedCols []*expression.Column) {\n\tp.schema = buildLogicalJoinSchema(p.JoinType, p, parentUsedCols)\n}\n\nfunc (p *LogicalJoin) PruneColumns(parentUsedCols []*expression.Column) error {\n\tleftCols, rightCols := p.extractUsedCols(parentUsedCols)\n\n\terr := p.children[0].PruneColumns(leftCols)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = p.children[1].PruneColumns(rightCols)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tp.mergeSchema(parentUsedCols)\n\treturn nil\n}\n\n// PruneColumns implements LogicalPlan interface.\nfunc (p *LogicalProjection) PruneColumns(parentUsedCols []*expression.Column) error {\n\tchild := p.children[0]\n\tused := GetUsedList(parentUsedCols, p.schema)\n\n\tp.schema.Columns = sliceutil.Take(p.schema.Columns, used)\n\tp.Exprs = sliceutil.Take(p.Exprs, used)\n\n\tselfUsedCols := make([]*expression.Column, 0, len(p.Exprs))\n\tselfUsedCols = expression.ExtractColumnsFromExpressions(selfUsedCols, p.Exprs, nil)\n\terr := child.PruneColumns(selfUsedCols)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(p.schema.Columns) == 0 {\n\t\tp.schema.Columns = []*expression.Column{child.Schema().Columns[0]}\n\t\tp.Exprs = []expression.Expression{child.Schema().Columns[0]}\n\t}\n\treturn nil\n}\n\n// PruneColumns implements LogicalPlan interface.\nfunc (p *LogicalWindow) PruneColumns(parentUsedCols []*expression.Column) error {\n\tvar selfUsedCols []*expression.Column\n\twindowColumns := p.GetWindowResultColumns()\n\n\tfor _, col := range parentUsedCols {\n\t\tused := false\n\t\tfor _, windowColumn := range windowColumns {\n\t\t\tif windowColumn.Equal(nil, col) {\n\t\t\t\tused = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !used {\n\t\t\tselfUsedCols = append(selfUsedCols, col)\n\t\t}\n\t}\n\n\tselfUsedCols = p.extractUsedCols(selfUsedCols)\n\terr := p.children[0].PruneColumns(selfUsedCols)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tused := GetUsedList(parentUsedCols, p.schema)\n\tp.schema.Columns = sliceutil.Take(p.schema.Columns, used)\n\n\treturn nil\n}\n\nfunc (p *LogicalWindow) extractUsedCols(usedCols []*expression.Column) []*expression.Column {\n\tfor _, desc := range p.WindowFuncDescs {\n\t\tfor _, arg := range desc.Args {\n\t\t\tusedCols = append(usedCols, expression.ExtractColumns(arg)...)\n\t\t}\n\t}\n\tfor _, by := range p.PartitionBy {\n\t\tusedCols = append(usedCols, by.Col)\n\t}\n\tfor _, by := range p.OrderBy {\n\t\tusedCols = append(usedCols, by.Col)\n\t}\n\treturn usedCols\n}\n\n// PruneColumns implements LogicalPlan interface.\nfunc (la *LogicalApply) PruneColumns(parentUsedCols []*expression.Column) error {\n\tleftCols, rightCols := la.extractUsedCols(parentUsedCols)\n\n\terr := la.children[1].PruneColumns(rightCols)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tla.CorCols = extractCorColumnsBySchema(la.children[1], la.children[0].Schema())\n\tfor _, col := range la.CorCols {\n\t\tleftCols = append(leftCols, &col.Column)\n\t}\n\n\terr = la.children[0].PruneColumns(leftCols)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tla.mergeSchema(parentUsedCols)\n\treturn nil\n}\n\n// PruneColumns implements LogicalPlan interface.\nfunc (ds *DataSource) PruneColumns(parentUsedCols []*expression.Column) error {\n\tused := GetUsedList(parentUsedCols, ds.schema)\n\n\tvar (\n\t\thandleCol     *expression.Column\n\t\thandleColInfo *model.ColumnInfo\n\t)\n\toriginSchemaColumns := ds.schema.Columns\n\toriginColumns := ds.Columns\n\tds.schema.Columns = sliceutil.Take(ds.schema.Columns, used)\n\tds.Columns = sliceutil.Take(ds.Columns, used)\n\n\t// For SQL like `select 1 from t`, we'll force to push one if schema doesn't have any column.\n\tif ds.schema.Len() == 0 {\n\t\tif len(originColumns) > 0 {\n\t\t\t// use the first line.\n\t\t\thandleCol = originSchemaColumns[0]\n\t\t\thandleColInfo = originColumns[0]\n\t\t} else {\n\t\t\thandleCol = ds.newExtraHandleSchemaCol()\n\t\t\thandleColInfo = model.NewExtraHandleColInfo()\n\t\t}\n\t\tds.Columns = append(ds.Columns, handleColInfo)\n\t\tds.schema.Append(handleCol)\n\t}\n\treturn nil\n}\n\n// PruneColumns implements LogicalPlan interface.\nfunc (la *LogicalAggregation) PruneColumns(parentUsedCols []*expression.Column) error {\n\tchild := la.children[0]\n\tused := GetUsedList(parentUsedCols, la.Schema())\n\n\tla.schema.Columns = sliceutil.Take(la.schema.Columns, used)\n\tla.AggFuncs = sliceutil.Take(la.AggFuncs, used)\n\tvar selfUsedCols []*expression.Column\n\tfor _, aggrFunc := range la.AggFuncs {\n\t\tselfUsedCols = expression.ExtractColumnsFromExpressions(selfUsedCols, aggrFunc.Args, nil)\n\t}\n\tif len(la.AggFuncs) == 0 {\n\t\t// If all the aggregate functions are pruned, we should add an aggregate function to keep the correctness.\n\t\tone, err := aggregation.NewAggFuncDesc(la.ctx, ast.AggFuncFirstRow, []expression.Expression{expression.One}, false)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tla.AggFuncs = []*aggregation.AggFuncDesc{one}\n\t\tcol := &expression.Column{\n\t\t\tUniqueID: la.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t\tRetType:  types.NewFieldType(mysql.TypeTiny),\n\t\t}\n\t\tla.schema.Columns = []*expression.Column{col}\n\t}\n\n\tif len(la.GroupByItems) > 0 {\n\t\tfor i := len(la.GroupByItems) - 1; i >= 0; i-- {\n\t\t\tcols := expression.ExtractColumns(la.GroupByItems[i])\n\t\t\tif len(cols) == 0 {\n\t\t\t\tla.GroupByItems = append(la.GroupByItems[:i], la.GroupByItems[i+1:]...)\n\t\t\t} else {\n\t\t\t\tselfUsedCols = append(selfUsedCols, cols...)\n\t\t\t}\n\t\t}\n\t\t// If all the group by items are pruned, we should add a constant 1 to keep the correctness.\n\t\t// Because `select count(*) from t` is different from `select count(*) from t group by 1`.\n\t\tif len(la.GroupByItems) == 0 {\n\t\t\tla.GroupByItems = []expression.Expression{expression.One}\n\t\t}\n\t}\n\treturn child.PruneColumns(selfUsedCols)\n}\n\n// PruneColumns implements LogicalPlan interface.\n// If any expression can view as a constant in execution stage, such as correlated column, constant,\n// we do prune them. Note that we can't prune the expressions contain non-deterministic functions, such as rand().\nfunc (ls *LogicalSort) PruneColumns(parentUsedCols []*expression.Column) error {\n\tchild := ls.children[0]\n\tfor i := len(ls.ByItems) - 1; i >= 0; i-- {\n\t\tcols := expression.ExtractColumns(ls.ByItems[i].Expr)\n\t\tif len(cols) == 0 {\n\t\t\tif expression.IsMutableEffectsExpr(ls.ByItems[i].Expr) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tls.ByItems = append(ls.ByItems[:i], ls.ByItems[i+1:]...)\n\t\t} else if ls.ByItems[i].Expr.GetType().Tp == mysql.TypeNull {\n\t\t\tls.ByItems = append(ls.ByItems[:i], ls.ByItems[i+1:]...)\n\t\t} else {\n\t\t\tparentUsedCols = append(parentUsedCols, cols...)\n\t\t}\n\t}\n\treturn child.PruneColumns(parentUsedCols)\n}\n\n// PruneColumns implements LogicalPlan interface.\nfunc (p *LogicalUnionAll) PruneColumns(parentUsedCols []*expression.Column) error {\n\tused := GetUsedList(parentUsedCols, p.schema)\n\n\thasBeenUsed := false\n\tfor i := range used {\n\t\thasBeenUsed = hasBeenUsed || used[i]\n\t\tif hasBeenUsed {\n\t\t\tbreak\n\t\t}\n\t}\n\tif !hasBeenUsed {\n\t\tparentUsedCols = make([]*expression.Column, len(p.schema.Columns))\n\t\tcopy(parentUsedCols, p.schema.Columns)\n\t} else {\n\t\t// Issue 10341: p.schema.Columns might contain table name (AsName), but p.Children()0].Schema().Columns does not.\n\t\tp.schema.Columns = sliceutil.Take(p.schema.Columns, used)\n\t}\n\tfor _, child := range p.Children() {\n\t\terr := child.PruneColumns(parentUsedCols)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_decorrelate.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\t\"math\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// canPullUpAgg checks if an apply can pull an aggregation up.\nfunc (la *LogicalApply) canPullUpAgg() bool {\n\tif la.JoinType != InnerJoin && la.JoinType != LeftOuterJoin {\n\t\treturn false\n\t}\n\tif len(la.EqualConditions)+len(la.LeftConditions)+len(la.RightConditions)+len(la.OtherConditions) > 0 {\n\t\treturn false\n\t}\n\treturn len(la.children[0].Schema().Keys) > 0\n}\n\n// canPullUp checks if an aggregation can be pulled up. An aggregate function like count(*) cannot be pulled up.\nfunc (la *LogicalAggregation) canPullUp() bool {\n\tif len(la.GroupByItems) > 0 {\n\t\treturn false\n\t}\n\tfor _, f := range la.AggFuncs {\n\t\tfor _, arg := range f.Args {\n\t\t\texpr := expression.EvaluateExprWithNull(la.ctx, la.children[0].Schema(), arg)\n\t\t\tif con, ok := expr.(*expression.Constant); !ok || !con.Value.IsNull() {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\n// deCorColFromEqExpr checks whether it's an equal condition of form `col = correlated col`. If so we will change the decorrelated\n// column to normal column to make a new equal condition.\nfunc (la *LogicalApply) deCorColFromEqExpr(expr expression.Expression) expression.Expression {\n\tsf, ok := expr.(*expression.ScalarFunction)\n\tif !ok || sf.FuncName.L != ast.EQ {\n\t\treturn nil\n\t}\n\tif col, lOk := sf.GetArgs()[0].(*expression.Column); lOk {\n\t\tif corCol, rOk := sf.GetArgs()[1].(*expression.CorrelatedColumn); rOk {\n\t\t\tret := corCol.Decorrelate(la.Schema())\n\t\t\tif _, ok := ret.(*expression.CorrelatedColumn); ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\t// We should make sure that the equal condition's left side is the join's left join key, right is the right key.\n\t\t\treturn expression.NewFunctionInternal(la.ctx, ast.EQ, types.NewFieldType(mysql.TypeTiny), ret, col)\n\t\t}\n\t}\n\tif corCol, lOk := sf.GetArgs()[0].(*expression.CorrelatedColumn); lOk {\n\t\tif col, rOk := sf.GetArgs()[1].(*expression.Column); rOk {\n\t\t\tret := corCol.Decorrelate(la.Schema())\n\t\t\tif _, ok := ret.(*expression.CorrelatedColumn); ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\t// We should make sure that the equal condition's left side is the join's left join key, right is the right key.\n\t\t\treturn expression.NewFunctionInternal(la.ctx, ast.EQ, types.NewFieldType(mysql.TypeTiny), ret, col)\n\t\t}\n\t}\n\treturn nil\n}\n\n// decorrelateSolver tries to convert apply plan to join plan.\ntype decorrelateSolver struct{}\n\nfunc (s *decorrelateSolver) aggDefaultValueMap(agg *LogicalAggregation) map[int]*expression.Constant {\n\tdefaultValueMap := make(map[int]*expression.Constant)\n\tfor i, f := range agg.AggFuncs {\n\t\tswitch f.Name {\n\t\tcase ast.AggFuncBitOr, ast.AggFuncBitXor, ast.AggFuncCount:\n\t\t\tdefaultValueMap[i] = expression.Zero.Clone().(*expression.Constant)\n\t\tcase ast.AggFuncBitAnd:\n\t\t\tdefaultValueMap[i] = &expression.Constant{Value: types.NewUintDatum(math.MaxUint64), RetType: types.NewFieldType(mysql.TypeLonglong)}\n\t\t}\n\t}\n\treturn defaultValueMap\n}\n\n// optimize implements logicalOptRule interface.\nfunc (s *decorrelateSolver) optimize(ctx context.Context, p LogicalPlan) (LogicalPlan, error) {\n\tif apply, ok := p.(*LogicalApply); ok {\n\t\touterPlan := apply.children[0]\n\t\tinnerPlan := apply.children[1]\n\t\tapply.CorCols = extractCorColumnsBySchema(apply.children[1], apply.children[0].Schema())\n\t\tif len(apply.CorCols) == 0 {\n\t\t\t// If the inner plan is non-correlated, the apply will be simplified to join.\n\t\t\tjoin := &apply.LogicalJoin\n\t\t\tjoin.self = join\n\t\t\tp = join\n\t\t} else if sel, ok := innerPlan.(*LogicalSelection); ok {\n\t\t\t// If the inner plan is a selection, we add this condition to join predicates.\n\t\t\t// Notice that no matter what kind of join is, it's always right.\n\t\t\tnewConds := make([]expression.Expression, 0, len(sel.Conditions))\n\t\t\tfor _, cond := range sel.Conditions {\n\t\t\t\tnewConds = append(newConds, cond.Decorrelate(outerPlan.Schema()))\n\t\t\t}\n\t\t\tapply.AttachOnConds(newConds)\n\t\t\tinnerPlan = sel.children[0]\n\t\t\tapply.SetChildren(outerPlan, innerPlan)\n\t\t\treturn s.optimize(ctx, p)\n\t\t} else if m, ok := innerPlan.(*LogicalMaxOneRow); ok {\n\t\t\t// if m.children[0].MaxOneRow() {\n\t\t\tinnerPlan = m.children[0]\n\t\t\tapply.SetChildren(outerPlan, innerPlan)\n\t\t\treturn s.optimize(ctx, p)\n\t\t} else if proj, ok := innerPlan.(*LogicalProjection); ok {\n\t\t\tfor i, expr := range proj.Exprs {\n\t\t\t\tproj.Exprs[i] = expr.Decorrelate(outerPlan.Schema())\n\t\t\t}\n\t\t\tapply.columnSubstitute(proj.Schema(), proj.Exprs)\n\t\t\tinnerPlan = proj.children[0]\n\t\t\tapply.SetChildren(outerPlan, innerPlan)\n\t\t\tif apply.JoinType != SemiJoin && apply.JoinType != LeftOuterSemiJoin && apply.JoinType != AntiSemiJoin && apply.JoinType != AntiLeftOuterSemiJoin {\n\t\t\t\t// NOTE: schema and exprs need to correspond one-to-one, so when modifying exprs,\n\t\t\t\t// the schema columns must also be modified accordingly\n\t\t\t\tproj.SetSchema(expression.MergeSchema(outerPlan.Schema(), proj.Schema()))\n\t\t\t\tproj.Exprs = append(expression.Column2Exprs(outerPlan.Schema().Clone().Columns), proj.Exprs...)\n\t\t\t\tapply.SetSchema(expression.MergeSchema(outerPlan.Schema(), innerPlan.Schema()))\n\t\t\t\tnp, err := s.optimize(ctx, p)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tproj.SetChildren(np)\n\t\t\t\treturn proj, nil\n\t\t\t}\n\t\t\treturn s.optimize(ctx, p)\n\t\t} else if agg, ok := innerPlan.(*LogicalAggregation); ok {\n\t\t\tif apply.canPullUpAgg() && agg.canPullUp() {\n\t\t\t\tinnerPlan = agg.children[0]\n\t\t\t\tapply.JoinType = LeftOuterJoin\n\t\t\t\tapply.SetChildren(outerPlan, innerPlan)\n\t\t\t\tagg.SetSchema(apply.Schema())\n\t\t\t\tagg.GroupByItems = expression.Column2Exprs(outerPlan.Schema().Keys[0])\n\t\t\t\tnewAggFuncs := make([]*aggregation.AggFuncDesc, 0, apply.Schema().Len())\n\n\t\t\t\touterColsInSchema := make([]*expression.Column, 0, outerPlan.Schema().Len())\n\t\t\t\tfor i, col := range outerPlan.Schema().Columns {\n\t\t\t\t\tfirst, err := aggregation.NewAggFuncDesc(agg.ctx, ast.AggFuncFirstRow, []expression.Expression{col}, false)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tnewAggFuncs = append(newAggFuncs, first)\n\n\t\t\t\t\touterCol, _ := outerPlan.Schema().Columns[i].Clone().(*expression.Column)\n\t\t\t\t\touterCol.RetType = first.RetTp\n\t\t\t\t\touterColsInSchema = append(outerColsInSchema, outerCol)\n\t\t\t\t}\n\t\t\t\tnewAggFuncs = append(newAggFuncs, agg.AggFuncs...)\n\t\t\t\tagg.AggFuncs = newAggFuncs\n\t\t\t\tapply.SetSchema(expression.MergeSchema(expression.NewSchema(outerColsInSchema...), innerPlan.Schema()))\n\t\t\t\tnp, err := s.optimize(ctx, p)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tagg.SetChildren(np)\n\t\t\t\t// TODO: Add a Projection if any argument of aggregate funcs or group by items are scalar functions.\n\t\t\t\t// agg.buildProjectionIfNecessary()\n\t\t\t\tagg.collectGroupByColumns()\n\t\t\t\treturn agg, nil\n\t\t\t}\n\t\t\t// We can pull up the equal conditions below the aggregation as the join key of the apply, if only\n\t\t\t// the equal conditions contain the correlated column of this apply.\n\t\t\tif sel, ok := agg.children[0].(*LogicalSelection); ok && apply.JoinType == LeftOuterJoin {\n\t\t\t\tvar (\n\t\t\t\t\teqCondWithCorCol []*expression.ScalarFunction\n\t\t\t\t\tremainedExpr     []expression.Expression\n\t\t\t\t)\n\t\t\t\t// Extract the equal condition.\n\t\t\t\tfor _, cond := range sel.Conditions {\n\t\t\t\t\tif expr := apply.deCorColFromEqExpr(cond); expr != nil {\n\t\t\t\t\t\teqCondWithCorCol = append(eqCondWithCorCol, expr.(*expression.ScalarFunction))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tremainedExpr = append(remainedExpr, cond)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif len(eqCondWithCorCol) > 0 {\n\t\t\t\t\toriginalExpr := sel.Conditions\n\t\t\t\t\tsel.Conditions = remainedExpr\n\t\t\t\t\t// NOTE(xiaoyuan): agg use sel's child schema, so we need to ensure\n\t\t\t\t\t// sel and child schema are consistent\n\t\t\t\t\tsel.SetOutputNames(sel.Children()[0].OutputNames())\n\t\t\t\t\tsel.SetSchema(sel.Children()[0].Schema().Clone())\n\t\t\t\t\tapply.CorCols = extractCorColumnsBySchema(apply.children[1], apply.children[0].Schema())\n\t\t\t\t\t// There's no other correlated column.\n\t\t\t\t\tgroupByCols := expression.NewSchema(agg.groupByCols...)\n\t\t\t\t\tif len(apply.CorCols) == 0 {\n\t\t\t\t\t\tjoin := &apply.LogicalJoin\n\t\t\t\t\t\tjoin.EqualConditions = append(join.EqualConditions, eqCondWithCorCol...)\n\t\t\t\t\t\tfor _, eqCond := range eqCondWithCorCol {\n\t\t\t\t\t\t\tclonedCol := eqCond.GetArgs()[1].(*expression.Column)\n\t\t\t\t\t\t\t// If the join key is not in the aggregation's schema, add first row function.\n\t\t\t\t\t\t\tif agg.schema.ColumnIndex(eqCond.GetArgs()[1].(*expression.Column)) == -1 {\n\t\t\t\t\t\t\t\tnewFunc, err := aggregation.NewAggFuncDesc(apply.ctx, ast.AggFuncFirstRow, []expression.Expression{clonedCol}, false)\n\t\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tagg.AggFuncs = append(agg.AggFuncs, newFunc)\n\t\t\t\t\t\t\t\tagg.schema.Append(clonedCol)\n\t\t\t\t\t\t\t\tagg.schema.Columns[agg.schema.Len()-1].RetType = newFunc.RetTp\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// If group by cols don't contain the join key, add it into this.\n\t\t\t\t\t\t\tif !groupByCols.Contains(clonedCol) {\n\t\t\t\t\t\t\t\tagg.GroupByItems = append(agg.GroupByItems, clonedCol)\n\t\t\t\t\t\t\t\tgroupByCols.Append(clonedCol)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tagg.collectGroupByColumns()\n\t\t\t\t\t\t// The selection may be useless, check and remove it.\n\t\t\t\t\t\tif len(sel.Conditions) == 0 {\n\t\t\t\t\t\t\tagg.SetChildren(sel.children[0])\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefaultValueMap := s.aggDefaultValueMap(agg)\n\t\t\t\t\t\t// We should use it directly, rather than building a projection.\n\t\t\t\t\t\tif len(defaultValueMap) > 0 {\n\t\t\t\t\t\t\tproj := LogicalProjection{}.Init(agg.ctx, agg.blockOffset)\n\t\t\t\t\t\t\tproj.SetSchema(apply.schema)\n\t\t\t\t\t\t\tproj.Exprs = expression.Column2Exprs(apply.schema.Columns)\n\t\t\t\t\t\t\tfor i, val := range defaultValueMap {\n\t\t\t\t\t\t\t\tpos := proj.schema.ColumnIndex(agg.schema.Columns[i])\n\t\t\t\t\t\t\t\tifNullFunc := expression.NewFunctionInternal(agg.ctx, ast.Ifnull, types.NewFieldType(mysql.TypeLonglong), agg.schema.Columns[i], val)\n\t\t\t\t\t\t\t\tproj.Exprs[pos] = ifNullFunc\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tproj.SetChildren(apply)\n\t\t\t\t\t\t\tp = proj\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn s.optimize(ctx, p)\n\t\t\t\t\t}\n\t\t\t\t\tsel.Conditions = originalExpr\n\t\t\t\t\tapply.CorCols = extractCorColumnsBySchema(apply.children[1], apply.children[0].Schema())\n\t\t\t\t}\n\t\t\t}\n\t\t} else if sort, ok := innerPlan.(*LogicalSort); ok {\n\t\t\t// Since we only pull up Selection, Projection, Aggregation, MaxOneRow,\n\t\t\t// the top level Sort has no effect on the subquery's result.\n\t\t\tinnerPlan = sort.children[0]\n\t\t\tapply.SetChildren(outerPlan, innerPlan)\n\t\t\treturn s.optimize(ctx, p)\n\t\t}\n\t}\n\tnewChildren := make([]LogicalPlan, 0, len(p.Children()))\n\tfor _, child := range p.Children() {\n\t\tnp, err := s.optimize(ctx, child)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnewChildren = append(newChildren, np)\n\t}\n\tp.SetChildren(newChildren...)\n\treturn p, nil\n}\n\nfunc (*decorrelateSolver) name() string {\n\treturn \"decorrelate\"\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_eliminate_projection.go",
    "content": "//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// canProjectionBeEliminatedLoose checks whether a projection can be eliminated,\n// returns true if\n//\n//\tevery expression is a single column\n//\tand\n//\tprojection has the same number of columns as its children.\nfunc canProjectionBeEliminatedLoose(p *LogicalProjection) bool {\n\tfor _, expr := range p.Exprs {\n\t\t_, ok := expr.(*expression.Column)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\tif p.Schema().Len() != p.Children()[0].Schema().Len() {\n\t\treturn false\n\t}\n\treturn true\n}\n\n//// canProjectionBeEliminatedStrict checks whether a projection can be\n//// eliminated, returns true if the projection just copy its child's output.\n//func canProjectionBeEliminatedStrict(p *PhysicalProjection) bool {\n//\t// If this projection is specially added for `DO`, we keep it.\n//\tif p.CalculateNoDelay {\n//\t\treturn false\n//\t}\n//\tif p.Schema().Len() == 0 {\n//\t\treturn true\n//\t}\n//\tchild := p.Children()[0]\n//\tif p.Schema().Len() != child.Schema().Len() {\n//\t\treturn false\n//\t}\n//\tfor i, expr := range p.Exprs {\n//\t\tcol, ok := expr.(*expression.Column)\n//\t\tif !ok || !col.Equal(nil, child.Schema().Columns[i]) {\n//\t\t\treturn false\n//\t\t}\n//\t}\n//\treturn true\n//}\n\nfunc resolveColumnAndReplace(origin *expression.Column, replace map[string]*expression.Column) {\n\tdst := replace[string(origin.HashCode(nil))]\n\t// different from original code\n\t// use for to loop until dst is nil rather than a if statement\n\t// TODO: refine this\n\tfor dst != nil {\n\t\tretType, inOperand := origin.RetType, origin.InOperand\n\t\t*origin = *dst\n\t\torigin.RetType, origin.InOperand = retType, inOperand\n\n\t\tdst = replace[string(origin.HashCode(nil))]\n\t\tif dst != nil && dst.UniqueID == origin.UniqueID {\n\t\t\t// avoid infinite loop\n\t\t\tdst = nil\n\t\t}\n\t}\n}\n\n// ResolveExprAndReplace replaces columns fields of expressions by children logical plans.\nfunc ResolveExprAndReplace(origin expression.Expression, replace map[string]*expression.Column) {\n\tswitch expr := origin.(type) {\n\tcase *expression.Column:\n\t\tresolveColumnAndReplace(expr, replace)\n\tcase *expression.CorrelatedColumn:\n\t\tresolveColumnAndReplace(&expr.Column, replace)\n\tcase *expression.ScalarFunction:\n\t\tfor _, arg := range expr.GetArgs() {\n\t\t\tResolveExprAndReplace(arg, replace)\n\t\t}\n\t}\n}\n\n//func doPhysicalProjectionElimination(p PhysicalPlan) PhysicalPlan {\n//\tfor i, child := range p.Children() {\n//\t\tp.Children()[i] = doPhysicalProjectionElimination(child)\n//\t}\n//\n//\tproj, isProj := p.(*PhysicalProjection)\n//\tif !isProj || !canProjectionBeEliminatedStrict(proj) {\n//\t\treturn p\n//\t}\n//\tchild := p.Children()[0]\n//\treturn child\n//}\n\n//// eliminatePhysicalProjection should be called after physical optimization to\n//// eliminate the redundant projection left after logical projection elimination.\n//func eliminatePhysicalProjection(p PhysicalPlan) PhysicalPlan {\n//\toldSchema := p.Schema()\n//\tnewRoot := doPhysicalProjectionElimination(p)\n//\tnewCols := newRoot.Schema().Columns\n//\tfor i, oldCol := range oldSchema.Columns {\n//\t\toldCol.Index = newCols[i].Index\n//\t\toldCol.ID = newCols[i].ID\n//\t\toldCol.UniqueID = newCols[i].UniqueID\n//\t\toldCol.VirtualExpr = newCols[i].VirtualExpr\n//\t\tnewRoot.Schema().Columns[i] = oldCol\n//\t}\n//\treturn newRoot\n//}\n\ntype projectionEliminator struct {\n}\n\n// optimize implements the logicalOptRule interface.\nfunc (pe *projectionEliminator) optimize(ctx context.Context, lp LogicalPlan) (LogicalPlan, error) {\n\troot := pe.eliminate(lp, make(map[string]*expression.Column), false)\n\treturn root, nil\n}\n\n// eliminate eliminates the redundant projection in a logical plan.\nfunc (pe *projectionEliminator) eliminate(p LogicalPlan, replace map[string]*expression.Column, canEliminate bool) LogicalPlan {\n\tproj, isProj := p.(*LogicalProjection)\n\tchildFlag := canEliminate\n\tif _, isUnion := p.(*LogicalUnionAll); isUnion {\n\t\tchildFlag = false\n\t} else if _, isAgg := p.(*LogicalAggregation); isAgg || isProj {\n\t\tchildFlag = true\n\t}\n\tfor i, child := range p.Children() {\n\t\tp.Children()[i] = pe.eliminate(child, replace, childFlag)\n\t}\n\n\tswitch x := p.(type) {\n\tcase *LogicalJoin:\n\t\tx.schema = buildLogicalJoinSchema(x.JoinType, x, x.Schema().Columns)\n\tcase *LogicalApply:\n\t\tx.schema = buildLogicalJoinSchema(x.JoinType, x, x.Schema().Columns)\n\tdefault:\n\t\tfor _, dst := range p.Schema().Columns {\n\t\t\tresolveColumnAndReplace(dst, replace)\n\t\t}\n\t}\n\tp.replaceExprColumns(replace)\n\tif isProj {\n\t\tif child, ok := p.Children()[0].(*LogicalProjection); ok && !ExprsHasSideEffects(child.Exprs) {\n\t\t\tfor i := range proj.Exprs {\n\t\t\t\tproj.Exprs[i] = ReplaceColumnOfExpr(proj.Exprs[i], child, child.Schema())\n\t\t\t}\n\t\t\tp.Children()[0] = child.Children()[0]\n\t\t}\n\t}\n\n\tif !(isProj && canEliminate && canProjectionBeEliminatedLoose(proj)) {\n\t\treturn p\n\t}\n\texprs := proj.Exprs\n\tfor i, col := range proj.Schema().Columns {\n\t\treplace[string(col.HashCode(nil))] = exprs[i].(*expression.Column)\n\t}\n\treturn p.Children()[0]\n}\n\n// ReplaceColumnOfExpr replaces column of expression by another LogicalProjection.\nfunc ReplaceColumnOfExpr(expr expression.Expression, proj *LogicalProjection, schema *expression.Schema) expression.Expression {\n\tswitch v := expr.(type) {\n\tcase *expression.Column:\n\t\tidx := schema.ColumnIndex(v)\n\t\tif idx != -1 && idx < len(proj.Exprs) {\n\t\t\treturn proj.Exprs[idx]\n\t\t}\n\tcase *expression.ScalarFunction:\n\t\tfor i := range v.GetArgs() {\n\t\t\tv.GetArgs()[i] = ReplaceColumnOfExpr(v.GetArgs()[i], proj, schema)\n\t\t}\n\t}\n\treturn expr\n}\n\nfunc (p *LogicalJoin) replaceExprColumns(replace map[string]*expression.Column) {\n\tfor _, equalExpr := range p.EqualConditions {\n\t\tResolveExprAndReplace(equalExpr, replace)\n\t}\n\tfor _, leftExpr := range p.LeftConditions {\n\t\tResolveExprAndReplace(leftExpr, replace)\n\t}\n\tfor _, rightExpr := range p.RightConditions {\n\t\tResolveExprAndReplace(rightExpr, replace)\n\t}\n\tfor _, otherExpr := range p.OtherConditions {\n\t\tResolveExprAndReplace(otherExpr, replace)\n\t}\n}\n\nfunc (p *LogicalProjection) replaceExprColumns(replace map[string]*expression.Column) {\n\tfor _, expr := range p.Exprs {\n\t\tResolveExprAndReplace(expr, replace)\n\t}\n}\n\nfunc (la *LogicalAggregation) replaceExprColumns(replace map[string]*expression.Column) {\n\tfor _, agg := range la.AggFuncs {\n\t\tfor _, aggExpr := range agg.Args {\n\t\t\tResolveExprAndReplace(aggExpr, replace)\n\t\t}\n\t}\n\tfor _, gbyItem := range la.GroupByItems {\n\t\tResolveExprAndReplace(gbyItem, replace)\n\t}\n\tla.collectGroupByColumns()\n}\n\nfunc (p *LogicalSelection) replaceExprColumns(replace map[string]*expression.Column) {\n\tfor _, expr := range p.Conditions {\n\t\tResolveExprAndReplace(expr, replace)\n\t}\n}\n\nfunc (la *LogicalApply) replaceExprColumns(replace map[string]*expression.Column) {\n\tla.LogicalJoin.replaceExprColumns(replace)\n\tfor _, coCol := range la.CorCols {\n\t\tdst := replace[string(coCol.Column.HashCode(nil))]\n\t\tif dst != nil {\n\t\t\tcoCol.Column = *dst\n\t\t}\n\t}\n}\n\nfunc (ls *LogicalSort) replaceExprColumns(replace map[string]*expression.Column) {\n\tfor _, byItem := range ls.ByItems {\n\t\tResolveExprAndReplace(byItem.Expr, replace)\n\t}\n}\n\nfunc (*projectionEliminator) name() string {\n\treturn \"projection_eliminate\"\n}\n\n// buildQuantifierPlan adds extra condition for any / all subquery.\nfunc (er *expressionRewriter) buildQuantifierPlan(plan4Agg *LogicalAggregation, cond, lexpr, rexpr expression.Expression, all bool) {\n\t// innerIsNull := expression.NewFunctionInternal(er.sctx, ast.IsNull, types.NewFieldType(mysql.TypeTiny), rexpr)\n\t//outerIsNull := expression.NewFunctionInternal(er.sctx, ast.IsNull, types.NewFieldType(mysql.TypeTiny), lexpr)\n\n\t// funcSum, err := aggregation.NewAggFuncDesc(er.sctx, ast.AggFuncSum, []expression.Expression{innerIsNull}, false)\n\t// if err != nil {\n\t// \ter.err = err\n\t// \treturn\n\t// }\n\t// colSum := &expression.Column{\n\t// \tUniqueID: er.sctx.GetSessionVars().AllocPlanColumnID(),\n\t// \tRetType:  funcSum.RetTp,\n\t// }\n\t// plan4Agg.AggFuncs = append(plan4Agg.AggFuncs, funcSum)\n\t// plan4Agg.schema.Append(colSum)\n\t// innerHasNull := expression.NewFunctionInternal(er.sctx, ast.NE, types.NewFieldType(mysql.TypeTiny), colSum, expression.Zero)\n\n\t// Build `count(1)` aggregation to check if subquery is empty.\n\t// funcCount, err := aggregation.NewAggFuncDesc(er.sctx, ast.AggFuncCount, []expression.Expression{expression.One}, false)\n\t// if err != nil {\n\t// \ter.err = err\n\t// \treturn\n\t// }\n\t// colCount := &expression.Column{\n\t// \tUniqueID: er.sctx.GetSessionVars().AllocPlanColumnID(),\n\t// \tRetType:  funcCount.RetTp,\n\t// }\n\t// plan4Agg.AggFuncs = append(plan4Agg.AggFuncs, funcCount)\n\t// plan4Agg.schema.Append(colCount)\n\n\t// if all {\n\t// \t// All of the inner record set should not contain null value. So for t.id < all(select s.id from s), it\n\t// \t// should be rewrote to t.id < min(s.id) and if(sum(s.id is null) != 0, null, true).\n\t// \tinnerNullChecker := expression.NewFunctionInternal(er.sctx, ast.If, types.NewFieldType(mysql.TypeTiny), innerHasNull, expression.Null, expression.One)\n\t// \tcond = expression.ComposeCNFCondition(er.sctx, cond, innerNullChecker)\n\t// \t// If the subquery is empty, it should always return true.\n\t// \temptyChecker := expression.NewFunctionInternal(er.sctx, ast.EQ, types.NewFieldType(mysql.TypeTiny), colCount, expression.Zero)\n\t// \t// If outer key is null, and subquery is not empty, it should always return null, even when it is `null = all (1, 2)`.\n\t// \touterNullChecker := expression.NewFunctionInternal(er.sctx, ast.If, types.NewFieldType(mysql.TypeTiny), outerIsNull, expression.Null, expression.Zero)\n\t// \tcond = expression.ComposeDNFCondition(er.sctx, cond, emptyChecker, outerNullChecker)\n\t// } else {\n\t// \t// For \"any\" expression, if the subquery has null and the cond returns false, the result should be NULL.\n\t// \t// Specifically, `t.id < any (select s.id from s)` would be rewrote to `t.id < max(s.id) or if(sum(s.id is null) != 0, null, false)`\n\t// \tinnerNullChecker := expression.NewFunctionInternal(er.sctx, ast.If, types.NewFieldType(mysql.TypeTiny), innerHasNull, expression.Null, expression.Zero)\n\t// \tcond = expression.ComposeDNFCondition(er.sctx, cond, innerNullChecker)\n\t// \t// If the subquery is empty, it should always return false.\n\t// \temptyChecker := expression.NewFunctionInternal(er.sctx, ast.NE, types.NewFieldType(mysql.TypeTiny), colCount, expression.Zero)\n\t// \t// If outer key is null, and subquery is not empty, it should return null.\n\t// \touterNullChecker := expression.NewFunctionInternal(er.sctx, ast.If, types.NewFieldType(mysql.TypeTiny), outerIsNull, expression.Null, expression.One)\n\t// \tcond = expression.ComposeCNFCondition(er.sctx, cond, emptyChecker, outerNullChecker)\n\t// }\n\n\t// TODO: Add a Projection if any argument of aggregate funcs or group by items are scalar functions.\n\t// plan4Agg.buildProjectionIfNecessary()\n\t// if !er.asScalar {\n\t// \t// For Semi LogicalApply without aux column, the result is no matter false or null. So we can add it to join predicate.\n\t// \ter.p, er.err = er.b.buildSemiApply(er.p, plan4Agg, []expression.Expression{cond}, false, false)\n\t// \treturn\n\t// }\n\t// If we treat the result as a scalar value, we will add a projection with a extra column to output true, false or null.\n\touterSchemaLen := er.p.Schema().Len()\n\ter.p = er.b.buildApplyWithJoinType(er.p, plan4Agg, InnerJoin)\n\tjoinSchema := er.p.Schema()\n\tproj := LogicalProjection{\n\t\tExprs: expression.Column2Exprs(joinSchema.Clone().Columns[:outerSchemaLen]),\n\t}.Init(er.sctx, er.b.getSelectOffset())\n\tproj.names = make([]*types.FieldName, outerSchemaLen, outerSchemaLen+1)\n\tcopy(proj.names, er.p.OutputNames())\n\tproj.SetSchema(expression.NewSchema(joinSchema.Clone().Columns[:outerSchemaLen]...))\n\tproj.Exprs = append(proj.Exprs, cond)\n\tproj.schema.Append(&expression.Column{\n\t\tUniqueID: er.sctx.GetSessionVars().AllocPlanColumnID(),\n\t\tRetType:  cond.GetType(),\n\t})\n\tproj.names = append(proj.names, types.EmptyName)\n\tproj.SetChildren(er.p)\n\ter.p = proj\n\n\t//scql change\n\ter.asScalar = true\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_groupby_threshold.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/expression/aggregation\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\ntype groupbyThresholdApplier struct {\n}\n\nfunc (g *groupbyThresholdApplier) name() string {\n\treturn \"add_groupby_threshold\"\n}\n\nfunc getThreshold(p LogicalPlan) int {\n\tsctx := p.SCtx()\n\tthreshold := sctx.GetSessionVars().GroupByThreshold\n\tif threshold == 0 {\n\t\tlogrus.Warn(\"group by threshold is 0, use default value 4\")\n\t\treturn 4\n\t}\n\treturn int(threshold)\n}\n\nfunc (g *groupbyThresholdApplier) optimize(ctx context.Context, p LogicalPlan) (LogicalPlan, error) {\n\tthreshold := getThreshold(p)\n\n\tif threshold == 1 {\n\t\treturn p, nil\n\t}\n\n\tif err := g.markAggCountFunc(p); err != nil {\n\t\treturn p, err\n\t}\n\n\tif err := g.addThreshold(nil, p, 0); err != nil {\n\t\treturn p, err\n\t}\n\treturn p, nil\n}\n\n// markAggCountFunc mark aggregation function which can be used as threshold.\n// If no count aggregation function found, add a count aggregation function.\nfunc (g *groupbyThresholdApplier) markAggCountFunc(lp LogicalPlan) error {\n\tfor _, child := range lp.Children() {\n\t\terr := g.markAggCountFunc(child)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tagg, ok := lp.(*LogicalAggregation)\n\tif !ok {\n\t\treturn nil\n\t}\n\t// By pass \"reduce aggregation\" and \"group aggregation produced by distinct\".\n\tif len(agg.GroupByItems) == 0 || agg.ProducedByDistinct {\n\t\treturn nil\n\t}\n\n\thasCount := false\n\tfor _, aggFunc := range agg.AggFuncs {\n\t\tif aggFunc.Name == ast.AggFuncCount && !aggFunc.HasDistinct {\n\t\t\taggFunc.UseAsThreshold = true\n\t\t\thasCount = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !hasCount {\n\t\tcountFunc, err := aggregation.NewAggFuncDesc(agg.ctx, ast.AggFuncCount, []expression.Expression{expression.One}, false)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcountFunc.UseAsThreshold = true\n\t\tagg.AggFuncs = append(agg.AggFuncs, countFunc)\n\t\tagg.schema.Append(&expression.Column{\n\t\t\tUniqueID: agg.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\t\tRetType:  countFunc.RetTp,\n\t\t})\n\t}\n\treturn nil\n}\n\n// addThreshold add selection between lp and flp(father of lp)\n// index indicate the index of lp in flp's children\nfunc (g *groupbyThresholdApplier) addThreshold(flp LogicalPlan, lp LogicalPlan, index int) error {\n\tfor i, childLp := range lp.Children() {\n\t\tif err := g.addThreshold(lp, childLp, i); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif flp == nil {\n\t\treturn nil\n\t}\n\n\tif agg, ok := lp.(*LogicalAggregation); ok {\n\t\tfor i, f := range agg.AggFuncs {\n\t\t\tif f.UseAsThreshold {\n\t\t\t\tcountCol := agg.Schema().Columns[i]\n\t\t\t\tcountCol.UseAsThreshold = true\n\n\t\t\t\tthresholdConstant := &expression.Constant{\n\t\t\t\t\tValue:   types.NewDatum(getThreshold(lp)),\n\t\t\t\t\tRetType: types.NewFieldType(mysql.TypeTiny),\n\t\t\t\t}\n\t\t\t\targs := []expression.Expression{countCol, thresholdConstant}\n\t\t\t\tcondExpr, err := expression.NewFunction(sessionctx.NewContext(), ast.GE, types.NewFieldType(mysql.TypeTiny), args...)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tAddSelection(flp, lp, []expression.Expression{condExpr}, index)\n\n\t\t\t\t_, ok := flp.Children()[index].(*LogicalSelection)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"flp's child must be LogicalSelection after AddSelection\")\n\t\t\t\t}\n\t\t\t\tlp.SCtx().GetSessionVars().AffectedByGroupThreshold = true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_join_reorder.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n)\n\nconst (\n\tLocalJoin    = 0\n\tNonLocalJoin = 1000\n)\n\n// extractJoinGroup extracts all the join nodes connected with continuous\n// InnerJoins to construct a join group. This join group is further used to\n// construct a new join order based on a reorder algorithm.\n//\n// For example: \"InnerJoin(InnerJoin(a, b), LeftJoin(c, d))\"\n// results in a join group {a, b, LeftJoin(c, d)}.\nfunc extractJoinGroup(p LogicalPlan) (group []LogicalPlan, eqEdges []*expression.ScalarFunction, otherConds []expression.Expression) {\n\tjoin, isJoin := p.(*LogicalJoin)\n\tif !isJoin || join.JoinType != InnerJoin {\n\t\treturn []LogicalPlan{p}, nil, nil\n\t}\n\n\tlhsGroup, lhsEqualConds, lhsOtherConds := extractJoinGroup(join.children[0])\n\trhsGroup, rhsEqualConds, rhsOtherConds := extractJoinGroup(join.children[1])\n\n\tgroup = append(group, lhsGroup...)\n\tgroup = append(group, rhsGroup...)\n\teqEdges = append(eqEdges, join.EqualConditions...)\n\teqEdges = append(eqEdges, lhsEqualConds...)\n\teqEdges = append(eqEdges, rhsEqualConds...)\n\totherConds = append(otherConds, join.OtherConditions...)\n\totherConds = append(otherConds, lhsOtherConds...)\n\totherConds = append(otherConds, rhsOtherConds...)\n\treturn group, eqEdges, otherConds\n}\n\ntype joinReOrderSolver struct {\n}\n\ntype jrNode struct {\n\tp       LogicalPlan\n\tcumCost float64\n}\n\nfunc (s *joinReOrderSolver) optimize(ctx context.Context, p LogicalPlan) (LogicalPlan, error) {\n\tfillPartyCode(p)\n\treturn s.optimizeRecursive(p.SCtx(), p)\n}\n\nfunc fillPartyCode(p LogicalPlan) {\n\tif len(p.Children()) == 0 {\n\t\treturn\n\t}\n\t// fill party code recursively\n\tfor _, child := range p.Children() {\n\t\tfillPartyCode(child)\n\t}\n\tpartyCodes := p.Children()[0].OwnerPartyCodes()\n\tfor _, child := range p.Children() {\n\t\tpartyCodes = sliceutil.SliceDeDup(append(partyCodes, child.OwnerPartyCodes()...))\n\t}\n\tp.SetOwnerPartyCodes(partyCodes)\n}\n\n// optimizeRecursive recursively collects join groups and applies join reorder algorithm for each group.\nfunc (s *joinReOrderSolver) optimizeRecursive(ctx sessionctx.Context, p LogicalPlan) (LogicalPlan, error) {\n\tvar err error\n\tcurJoinGroup, eqEdges, otherConds := extractJoinGroup(p)\n\t// Note: for scql, SCQL only optimizes scenarios involving joins of more than two tables.\n\tif len(curJoinGroup) > 2 {\n\t\tfor i := range curJoinGroup {\n\t\t\tcurJoinGroup[i], err = s.optimizeRecursive(ctx, curJoinGroup[i])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tbaseGroupSolver := &baseSingleGroupJoinOrderSolver{\n\t\t\tctx:        ctx,\n\t\t\totherConds: otherConds,\n\t\t}\n\t\tgroupSolver := &joinReorderGreedySolver{\n\t\t\tbaseSingleGroupJoinOrderSolver: baseGroupSolver,\n\t\t\teqEdges:                        eqEdges,\n\t\t}\n\t\tp, err = groupSolver.solve(curJoinGroup)\n\t\t// TODO: @xiaoyuan support Dp solver\n\t\t// else {\n\t\t// \tdpSolver := &joinReorderDPSolver{\n\t\t// \t\tbaseSingleGroupJoinOrderSolver: baseGroupSolver,\n\t\t// \t}\n\t\t// \tdpSolver.newJoin = dpSolver.newJoinWithEdges\n\t\t// \tp, err = dpSolver.solve(curJoinGroup, expression.ScalarFuncs2Exprs(eqEdges))\n\t\t// }\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn p, nil\n\t}\n\tnewChildren := make([]LogicalPlan, 0, len(p.Children()))\n\tfor _, child := range p.Children() {\n\t\tnewChild, err := s.optimizeRecursive(ctx, child)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnewChildren = append(newChildren, newChild)\n\t}\n\tp.SetChildren(newChildren...)\n\treturn p, nil\n}\n\ntype baseSingleGroupJoinOrderSolver struct {\n\tctx          sessionctx.Context\n\tcurJoinGroup []*jrNode\n\totherConds   []expression.Expression\n}\n\n// baseNodeCumCost calculate the cumulative cost of the node in the join group.\nfunc (s *baseSingleGroupJoinOrderSolver) baseNodeCumCost(groupNode LogicalPlan) float64 {\n\treturn 0.0\n}\n\n// makeBushyJoin build bushy tree for the nodes which have no equal condition to connect them.\nfunc (s *baseSingleGroupJoinOrderSolver) makeBushyJoin(cartesianJoinGroup []LogicalPlan) LogicalPlan {\n\tresultJoinGroup := make([]LogicalPlan, 0, (len(cartesianJoinGroup)+1)/2)\n\tfor len(cartesianJoinGroup) > 1 {\n\t\tresultJoinGroup = resultJoinGroup[:0]\n\t\tfor i := 0; i < len(cartesianJoinGroup); i += 2 {\n\t\t\tif i+1 == len(cartesianJoinGroup) {\n\t\t\t\tresultJoinGroup = append(resultJoinGroup, cartesianJoinGroup[i])\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tnewJoin := s.newCartesianJoin(cartesianJoinGroup[i], cartesianJoinGroup[i+1])\n\t\t\tfor i := len(s.otherConds) - 1; i >= 0; i-- {\n\t\t\t\tcols := expression.ExtractColumns(s.otherConds[i])\n\t\t\t\tif newJoin.schema.ColumnsIndices(cols) != nil {\n\t\t\t\t\tnewJoin.OtherConditions = append(newJoin.OtherConditions, s.otherConds[i])\n\t\t\t\t\ts.otherConds = append(s.otherConds[:i], s.otherConds[i+1:]...)\n\t\t\t\t}\n\t\t\t}\n\t\t\tresultJoinGroup = append(resultJoinGroup, newJoin)\n\t\t}\n\t\tcartesianJoinGroup, resultJoinGroup = resultJoinGroup, cartesianJoinGroup\n\t}\n\treturn cartesianJoinGroup[0]\n}\n\nfunc (s *baseSingleGroupJoinOrderSolver) newCartesianJoin(lChild, rChild LogicalPlan) *LogicalJoin {\n\toffset := lChild.SelectBlockOffset()\n\tif offset != rChild.SelectBlockOffset() {\n\t\toffset = -1\n\t}\n\tjoin := LogicalJoin{\n\t\tJoinType:  InnerJoin,\n\t\treordered: true,\n\t}.Init(s.ctx, offset)\n\tjoin.SetSchema(expression.MergeSchema(lChild.Schema(), rChild.Schema()))\n\tjoin.SetChildren(lChild, rChild)\n\t// rebuild logicalSchemaProducer.names\n\tjoin.names = make([]*types.FieldName, lChild.Schema().Len()+rChild.Schema().Len())\n\tcopy(join.names, lChild.OutputNames())\n\tcopy(join.names[lChild.Schema().Len():], rChild.OutputNames())\n\treturn join\n}\n\nfunc (s *baseSingleGroupJoinOrderSolver) newJoinWithEdges(lChild, rChild LogicalPlan, eqEdges []*expression.ScalarFunction, otherConds []expression.Expression) LogicalPlan {\n\tnewJoin := s.newCartesianJoin(lChild, rChild)\n\tnewJoin.EqualConditions = eqEdges\n\tnewJoin.OtherConditions = otherConds\n\tfor _, eqCond := range newJoin.EqualConditions {\n\t\tnewJoin.LeftJoinKeys = append(newJoin.LeftJoinKeys, eqCond.GetArgs()[0].(*expression.Column))\n\t\tnewJoin.RightJoinKeys = append(newJoin.RightJoinKeys, eqCond.GetArgs()[1].(*expression.Column))\n\t}\n\tnewJoin.SetOwnerPartyCodes(sliceutil.SliceDeDup(append(lChild.OwnerPartyCodes(), rChild.OwnerPartyCodes()...)))\n\treturn newJoin\n}\n\n// calcJoinCumCost calculates the cumulative cost of the join node.\nfunc (s *baseSingleGroupJoinOrderSolver) calcJoinCumCost(join LogicalPlan, lNode, rNode *jrNode) float64 {\n\tif len(rNode.p.OwnerPartyCodes()) == 1 && sliceutil.UnOrderedSliceEqual(lNode.p.OwnerPartyCodes(), rNode.p.OwnerPartyCodes()) {\n\t\treturn LocalJoin + lNode.cumCost + rNode.cumCost\n\t}\n\treturn NonLocalJoin + lNode.cumCost + rNode.cumCost\n}\n\nfunc (*joinReOrderSolver) name() string {\n\treturn \"join_reorder\"\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_join_reorder_greedy.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"math\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n)\n\ntype joinReorderGreedySolver struct {\n\t*baseSingleGroupJoinOrderSolver\n\teqEdges []*expression.ScalarFunction\n}\n\n// solve reorders the join nodes in the group based on a greedy algorithm.\n//\n// For each node having a join equal condition with the current join tree in\n// the group, calculate the cumulative join cost of that node and the join\n// tree, choose the node with the smallest cumulative cost to join with the\n// current join tree.\n//\n// cumulative join cost = CumCount(lhs) + CumCount(rhs) + RowCount(join)\n//\n//\tFor base node, its CumCount equals to the sum of the count of its subtree.\n//\tSee baseNodeCumCost for more details.\n//\n// TODO: this formula can be changed to real physical cost in future.\n//\n// For the nodes and join trees which don't have a join equal condition to\n// connect them, we make a bushy join tree to do the cartesian joins finally.\nfunc (s *joinReorderGreedySolver) solve(joinNodePlans []LogicalPlan) (LogicalPlan, error) {\n\tfor _, node := range joinNodePlans {\n\t\ts.curJoinGroup = append(s.curJoinGroup, &jrNode{\n\t\t\tp:       node,\n\t\t\tcumCost: s.baseNodeCumCost(node),\n\t\t})\n\t}\n\tvar optimizedCurJoinGroup []*jrNode\n\tfor {\n\t\tif len(s.curJoinGroup) == 0 {\n\t\t\tbreak\n\t\t}\n\t\tnewNode := s.popIfFirstNodeCantBeMerged()\n\t\tif newNode != nil {\n\t\t\toptimizedCurJoinGroup = append(optimizedCurJoinGroup, newNode)\n\t\t}\n\t}\n\ts.curJoinGroup = optimizedCurJoinGroup\n\n\tvar cartesianGroup []LogicalPlan\n\tfor len(s.curJoinGroup) > 0 {\n\t\tnewNode, err := s.constructConnectedJoinTree()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcartesianGroup = append(cartesianGroup, newNode.p)\n\t}\n\n\treturn s.makeBushyJoin(cartesianGroup), nil\n}\n\nfunc (s *joinReorderGreedySolver) popIfFirstNodeCantBeMerged() *jrNode {\n\tcurJoinTree := s.curJoinGroup[0]\n\t// only merging plans with same party code\n\tfor i, node := range s.curJoinGroup[1:] {\n\t\t// skip join node which can't merge with curJoinTree\n\t\tif len(node.p.OwnerPartyCodes()) != 1 || !sliceutil.UnOrderedSliceEqual(curJoinTree.p.OwnerPartyCodes(), node.p.OwnerPartyCodes()) {\n\t\t\tcontinue\n\t\t}\n\t\tnewJoin, remainOthers := s.checkConnectionAndMakeJoin(curJoinTree.p, node.p)\n\t\tif newJoin == nil {\n\t\t\tcontinue\n\t\t}\n\t\tcurCost := s.calcJoinCumCost(newJoin, curJoinTree, node)\n\t\tmergedIdx := i + 1\n\t\t// remove merged node\n\t\ts.curJoinGroup = append(s.curJoinGroup[:mergedIdx], s.curJoinGroup[mergedIdx+1:]...)\n\t\ts.otherConds = remainOthers\n\t\tcurJoinTree = &jrNode{\n\t\t\tp:       newJoin,\n\t\t\tcumCost: curCost,\n\t\t}\n\t\ts.curJoinGroup[0] = curJoinTree\n\t\treturn nil\n\t}\n\t// If we could find more join node, meaning that the sub connected graph have been totally explored.\n\ts.curJoinGroup = s.curJoinGroup[1:]\n\treturn curJoinTree\n}\n\nfunc (s *joinReorderGreedySolver) constructConnectedJoinTree() (*jrNode, error) {\n\tcurJoinTree := s.curJoinGroup[0]\n\ts.curJoinGroup = s.curJoinGroup[1:]\n\n\tfor {\n\t\tbestCost := math.MaxFloat64\n\t\tbestIdx := -1\n\t\tvar finalRemainOthers []expression.Expression\n\t\tvar bestJoin LogicalPlan\n\t\tfor i, node := range s.curJoinGroup {\n\t\t\tnewJoin, remainOthers := s.checkConnectionAndMakeJoin(curJoinTree.p, node.p)\n\t\t\tif newJoin == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// NOTE: didn't work for scql\n\t\t\t// _, err := newJoin.recursiveDeriveStats()\n\t\t\t// if err != nil {\n\t\t\t// \treturn nil, err\n\t\t\t// }\n\t\t\tcurCost := s.calcJoinCumCost(newJoin, curJoinTree, node)\n\t\t\tif bestCost > curCost {\n\t\t\t\tbestCost = curCost\n\t\t\t\tbestJoin = newJoin\n\t\t\t\tbestIdx = i\n\t\t\t\tfinalRemainOthers = remainOthers\n\t\t\t}\n\t\t}\n\t\t// If we could find more join node, meaning that the sub connected graph have been totally explored.\n\t\tif bestJoin == nil {\n\t\t\tbreak\n\t\t}\n\t\tcurJoinTree = &jrNode{\n\t\t\tp:       bestJoin,\n\t\t\tcumCost: bestCost,\n\t\t}\n\t\ts.curJoinGroup = append(s.curJoinGroup[:bestIdx], s.curJoinGroup[bestIdx+1:]...)\n\t\ts.otherConds = finalRemainOthers\n\t}\n\treturn curJoinTree, nil\n}\n\nfunc (s *joinReorderGreedySolver) checkConnectionAndMakeJoin(leftNode, rightNode LogicalPlan) (LogicalPlan, []expression.Expression) {\n\tvar usedEdges []*expression.ScalarFunction\n\tremainOtherConds := make([]expression.Expression, len(s.otherConds))\n\tcopy(remainOtherConds, s.otherConds)\n\tfor _, edge := range s.eqEdges {\n\t\tlCol := edge.GetArgs()[0].(*expression.Column)\n\t\trCol := edge.GetArgs()[1].(*expression.Column)\n\t\tif leftNode.Schema().Contains(lCol) && rightNode.Schema().Contains(rCol) {\n\t\t\tusedEdges = append(usedEdges, edge)\n\t\t} else if rightNode.Schema().Contains(lCol) && leftNode.Schema().Contains(rCol) {\n\t\t\tnewSf := expression.NewFunctionInternal(s.ctx, ast.EQ, edge.GetType(), rCol, lCol).(*expression.ScalarFunction)\n\t\t\tusedEdges = append(usedEdges, newSf)\n\t\t}\n\t}\n\tif len(usedEdges) == 0 {\n\t\treturn nil, nil\n\t}\n\tvar otherConds []expression.Expression\n\tmergedSchema := expression.MergeSchema(leftNode.Schema(), rightNode.Schema())\n\tremainOtherConds, otherConds = expression.FilterOutInPlace(remainOtherConds, func(expr expression.Expression) bool {\n\t\treturn expression.ExprFromSchema(expr, mergedSchema)\n\t})\n\treturn s.newJoinWithEdges(leftNode, rightNode, usedEdges, otherConds), remainOtherConds\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_merge_selection.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n)\n\ntype selectionMerger struct{}\n\nfunc (s *selectionMerger) name() string {\n\treturn \"merge_selection\"\n}\n\nfunc (s *selectionMerger) optimize(ctx context.Context, lp LogicalPlan) (LogicalPlan, error) {\n\tif err := s.mergeSelection(lp); err != nil {\n\t\treturn nil, err\n\t}\n\treturn lp, nil\n}\n\n// mergeSelection merges lp and it's father when they both are selection\nfunc (s *selectionMerger) mergeSelection(lp LogicalPlan) error {\n\tif selection, ok := lp.(*LogicalSelection); ok && len(selection.Children()) == 1 {\n\t\tif childSelection, ok := lp.Children()[0].(*LogicalSelection); ok {\n\t\t\tselection.Conditions = append(selection.Conditions, childSelection.Conditions...)\n\t\t\tselection.Children()[0] = childSelection.Children()[0]\n\t\t}\n\t}\n\tfor _, childLp := range lp.Children() {\n\t\tif err := s.mergeSelection(childLp); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_patch_timezone.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\t\"regexp\"\n\t\"time\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// timeZonePatcher is an optimization rule that adds timezone information\n// to timestamp literals when they are being compared to timestamp columns\ntype timeZonePatcher struct{}\n\nfunc (t *timeZonePatcher) optimize(ctx context.Context, lp LogicalPlan) (LogicalPlan, error) {\n\t// Get the session context from the logical plan\n\tsctx := lp.SCtx()\n\tif sctx == nil {\n\t\treturn lp, nil\n\t}\n\n\t// Get the createdAt time from the session context\n\tcreatedAt := sctx.GetSessionVars().CreatedAt\n\tif createdAt.IsZero() {\n\t\treturn lp, nil\n\t}\n\n\t// Create and apply the logical plan timestamp visitor\n\tvisitor := newLogicalPlanTimestampVisitor(createdAt)\n\tvisitor.visit(lp)\n\n\treturn lp, nil\n}\n\nfunc (t *timeZonePatcher) name() string {\n\treturn \"time_zone_patch\"\n}\n\n// logicalPlanTimestampVisitor is a visitor that adds timezone information to timestamp literals\n// in the logical plan directly, using the type information available in the logical plan\ntype logicalPlanTimestampVisitor struct {\n\tcreatedAt time.Time\n}\n\n// newLogicalPlanTimestampVisitor creates a new logicalPlanTimestampVisitor\nfunc newLogicalPlanTimestampVisitor(createdAt time.Time) *logicalPlanTimestampVisitor {\n\treturn &logicalPlanTimestampVisitor{\n\t\tcreatedAt: createdAt,\n\t}\n}\n\n// visit implements a recursive traversal of the logical plan to modify timestamp literals\nfunc (lptv *logicalPlanTimestampVisitor) visit(lp LogicalPlan) {\n\tfor _, child := range lp.Children() {\n\t\tlptv.visit(child)\n\t}\n\n\tlptv.processNode(lp)\n}\n\n// processNode processes a single logical plan node to modify timestamp literals\nfunc (lptv *logicalPlanTimestampVisitor) processNode(lp LogicalPlan) {\n\tswitch node := lp.(type) {\n\tcase *LogicalSelection:\n\t\tfor _, expr := range node.Conditions {\n\t\t\tlptv.processExpression(expr, logicalPlanContextInfo{})\n\t\t}\n\n\tcase *LogicalProjection:\n\t\tfor _, expr := range node.Exprs {\n\t\t\tlptv.processExpression(expr, logicalPlanContextInfo{})\n\t\t}\n\n\tcase *LogicalAggregation:\n\t\t// Process aggregation function arguments and group by items\n\t\tfor _, aggFunc := range node.AggFuncs {\n\t\t\tfor _, arg := range aggFunc.Args {\n\t\t\t\tlptv.processExpression(arg, logicalPlanContextInfo{})\n\t\t\t}\n\t\t}\n\t\tfor _, item := range node.GroupByItems {\n\t\t\tlptv.processExpression(item, logicalPlanContextInfo{})\n\t\t}\n\tcase *LogicalWindow:\n\t\t// Process window function arguments, partition by, order by, and frame bounds\n\t\tfor _, windowFunc := range node.WindowFuncDescs {\n\t\t\tfor _, arg := range windowFunc.Args {\n\t\t\t\tlptv.processExpression(arg, logicalPlanContextInfo{})\n\t\t\t}\n\t\t}\n\t\tfor _, item := range node.PartitionBy {\n\t\t\tlptv.processExpression(item.Col, logicalPlanContextInfo{})\n\t\t}\n\t\tfor _, item := range node.OrderBy {\n\t\t\tlptv.processExpression(item.Col, logicalPlanContextInfo{})\n\t\t}\n\t\t// Process frame bounds if present\n\t\tif node.Frame != nil {\n\t\t\tif node.Frame.Start != nil {\n\t\t\t\tfor _, calcFunc := range node.Frame.Start.CalcFuncs {\n\t\t\t\t\tlptv.processExpression(calcFunc, logicalPlanContextInfo{})\n\t\t\t\t}\n\t\t\t}\n\t\t\tif node.Frame.End != nil {\n\t\t\t\tfor _, calcFunc := range node.Frame.End.CalcFuncs {\n\t\t\t\t\tlptv.processExpression(calcFunc, logicalPlanContextInfo{})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tcase *LogicalSort:\n\t\t// Process sort expressions\n\t\tfor _, item := range node.ByItems {\n\t\t\tlptv.processExpression(item.Expr, logicalPlanContextInfo{})\n\t\t}\n\n\tcase *LogicalApply:\n\t\t// Process correlated columns\n\t\tfor _, col := range node.CorCols {\n\t\t\tlptv.processExpression(&col.Column, logicalPlanContextInfo{})\n\t\t}\n\n\t\tif join, ok := lp.(*LogicalJoin); ok {\n\t\t\tfor _, eqCond := range join.EqualConditions {\n\t\t\t\tlptv.processExpression(eqCond, logicalPlanContextInfo{})\n\t\t\t}\n\t\t\tfor _, leftCond := range join.LeftConditions {\n\t\t\t\tlptv.processExpression(leftCond, logicalPlanContextInfo{})\n\t\t\t}\n\t\t\tfor _, rightCond := range join.RightConditions {\n\t\t\t\tlptv.processExpression(rightCond, logicalPlanContextInfo{})\n\t\t\t}\n\t\t\tfor _, otherCond := range join.OtherConditions {\n\t\t\t\tlptv.processExpression(otherCond, logicalPlanContextInfo{})\n\t\t\t}\n\t\t}\n\n\t\t// In SCQL, join operations typically only involve column-to-column equality comparisons\n\t\t// case *LogicalJoin:\n\t\t// \t// Process all join conditions\n\t\t// \tfor _, eqCond := range node.EqualConditions {\n\t\t// \t\tlptv.processExpression(eqCond, logicalPlanContextInfo{})\n\t\t// \t}\n\t\t// \tfor _, leftCond := range node.LeftConditions {\n\t\t// \t\tlptv.processExpression(leftCond, logicalPlanContextInfo{})\n\t\t// \t}\n\t\t// \tfor _, rightCond := range node.RightConditions {\n\t\t// \t\tlptv.processExpression(rightCond, logicalPlanContextInfo{})\n\t\t// \t}\n\t\t// \tfor _, otherCond := range node.OtherConditions {\n\t\t// \t\tlptv.processExpression(otherCond, logicalPlanContextInfo{})\n\t\t// \t}\n\t}\n}\n\n// processExpression processes a single expression to modify timestamp literals\nfunc (lptv *logicalPlanTimestampVisitor) processExpression(expr expression.Expression, ctx logicalPlanContextInfo) {\n\t// If this is a scalar function, we need to check if it's a timestamp comparison\n\t// and process its arguments with the appropriate context\n\tif scalarFunc, ok := expr.(*expression.ScalarFunction); ok {\n\t\tisTimestampComparison := lptv.isTimestampComparison(expr)\n\n\t\tnewCtx := logicalPlanContextInfo{\n\t\t\tinTimestampComparison: isTimestampComparison,\n\t\t}\n\n\t\tlptv.processExpressions(scalarFunc.GetArgs(), newCtx)\n\t\treturn\n\t}\n\n\t// If this is a constant value expression, check if it's a timestamp literal we need to modify\n\tif constant, ok := expr.(*expression.Constant); ok {\n\t\tlptv.processConstant(constant, ctx)\n\t\treturn\n\t}\n}\n\n// processExpressions processes a slice of expressions to modify timestamp literals\nfunc (lptv *logicalPlanTimestampVisitor) processExpressions(exprs []expression.Expression, ctx logicalPlanContextInfo) {\n\tfor _, expr := range exprs {\n\t\tlptv.processExpression(expr, ctx)\n\t}\n}\n\n// logicalPlanContextInfo tracks information about the current context during logical plan traversal\ntype logicalPlanContextInfo struct {\n\t// Whether we're in a comparison operation with a timestamp column\n\tinTimestampComparison bool\n}\n\n// isTimestampComparison checks if an expression is a comparison with a timestamp column\nfunc (lptv *logicalPlanTimestampVisitor) isTimestampComparison(expr expression.Expression) bool {\n\tif scalarFunc, ok := expr.(*expression.ScalarFunction); ok {\n\t\tswitch scalarFunc.FuncName.L {\n\t\tcase ast.EQ, ast.NE, ast.LT, ast.LE, ast.GT, ast.GE:\n\t\t\tfor _, arg := range scalarFunc.GetArgs() {\n\t\t\t\tif lptv.isTimestampColumn(arg) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\tcase ast.In:\n\t\t\targs := scalarFunc.GetArgs()\n\t\t\tif len(args) > 0 && lptv.isTimestampColumn(args[0]) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// isTimestampColumn checks if an expression represents a timestamp column\nfunc (lptv *logicalPlanTimestampVisitor) isTimestampColumn(expr expression.Expression) bool {\n\tif col, ok := expr.(*expression.Column); ok {\n\t\treturn col.RetType.Tp == mysql.TypeTimestamp\n\t}\n\treturn false\n}\n\n// isTimestampWithoutTimezone checks if a string is a timestamp format without timezone\nfunc (lptv *logicalPlanTimestampVisitor) isTimestampWithoutTimezone(s string) bool {\n\t// Check if it matches timestamp pattern like \"2023-10-01 08:30:00\" or \"2023-10-01T08:30:00\"\n\ttimestampPattern := regexp.MustCompile(`^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}$`)\n\n\t// Check if it already has timezone information\n\thasTimezonePattern := regexp.MustCompile(`^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}([+-]\\d{2}:\\d{2}|Z)$`)\n\n\treturn timestampPattern.MatchString(s) && !hasTimezonePattern.MatchString(s)\n}\n\n// processConstant processes a constant value to modify timestamp literals\nfunc (lptv *logicalPlanTimestampVisitor) processConstant(constant *expression.Constant, ctx logicalPlanContextInfo) {\n\tif constant.Value.Kind() == types.KindString {\n\t\tstrValue := constant.Value.GetString()\n\n\t\tif ctx.inTimestampComparison {\n\t\t\tif lptv.isTimestampWithoutTimezone(strValue) {\n\t\t\t\t// Add timezone from createdAt\n\t\t\t\ttimezoneStr := lptv.createdAt.Format(\"-07:00\")\n\t\t\t\tif timezoneStr[0] != '-' && timezoneStr[0] != '+' {\n\t\t\t\t\ttimezoneStr = \"+\" + timezoneStr\n\t\t\t\t}\n\t\t\t\tnewValue := strValue + timezoneStr\n\n\t\t\t\t// Update the constant with the new value\n\t\t\t\tconstant.Value.SetString(newValue)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_patch_timezone_test.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\t\"regexp\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/infoschema\"\n\t\"github.com/secretflow/scql/pkg/parser\"\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// TestLogicalPlanTimestampVisitor tests the logical plan timestamp visitor\nfunc TestLogicalPlanTimestampVisitor(t *testing.T) {\n\tcreatedAt := time.Date(2023, 10, 1, 8, 30, 0, 0, time.FixedZone(\"UTC+8\", 8*3600))\n\tvisitor := newLogicalPlanTimestampVisitor(createdAt)\n\n\t// Test case 1: isTimestampWithoutTimezone should correctly identify timestamp strings\n\tt.Run(\"IsTimestampWithoutTimezone\", func(t *testing.T) {\n\t\t// Should match timestamps without timezone\n\t\tassert.True(t, visitor.isTimestampWithoutTimezone(\"2023-10-01 08:30:00\"))\n\t\tassert.True(t, visitor.isTimestampWithoutTimezone(\"2023-10-01T08:30:00\"))\n\n\t\t// Should not match timestamps with timezone\n\t\tassert.False(t, visitor.isTimestampWithoutTimezone(\"2023-10-01 08:30:00+08:00\"))\n\t\tassert.False(t, visitor.isTimestampWithoutTimezone(\"2023-10-01T08:30:00Z\"))\n\n\t\t// Should not match other strings\n\t\tassert.False(t, visitor.isTimestampWithoutTimezone(\"not a timestamp\"))\n\t\tassert.False(t, visitor.isTimestampWithoutTimezone(\"2023-10-01\"))\n\t})\n\n\t// Test case 2: processConstant should add timezone when in timestamp comparison context\n\tt.Run(\"ProcessConstantInTimestampComparison\", func(t *testing.T) {\n\t\t// Create a constant with timestamp value\n\t\ttimestampConst := &expression.Constant{\n\t\t\tValue: types.NewStringDatum(\"2023-10-01 08:30:00\"),\n\t\t}\n\n\t\t// Process with timestamp comparison context\n\t\tctx := logicalPlanContextInfo{inTimestampComparison: true}\n\t\tvisitor.processConstant(timestampConst, ctx)\n\n\t\t// Check that the timezone was appended\n\t\texpected := \"2023-10-01 08:30:00+08:00\"\n\t\tassert.Equal(t, expected, timestampConst.Value.GetString())\n\t})\n\n\t// Test case 3: processConstant should not add timezone when not in timestamp comparison context\n\tt.Run(\"ProcessConstantNotInTimestampComparison\", func(t *testing.T) {\n\t\t// Create a constant with timestamp value\n\t\ttimestampConst := &expression.Constant{\n\t\t\tValue: types.NewStringDatum(\"2023-10-01 08:30:00\"),\n\t\t}\n\n\t\t// Process with non-timestamp comparison context\n\t\tctx := logicalPlanContextInfo{inTimestampComparison: false}\n\t\tvisitor.processConstant(timestampConst, ctx)\n\n\t\t// Check that the timezone was NOT appended\n\t\texpected := \"2023-10-01 08:30:00\"\n\t\tassert.Equal(t, expected, timestampConst.Value.GetString())\n\t})\n\n\t// Test case 4: processConstant should not modify non-string constants\n\tt.Run(\"ProcessNonStringConstant\", func(t *testing.T) {\n\t\t// Create a constant with integer value\n\t\tintConst := &expression.Constant{\n\t\t\tValue: types.NewIntDatum(123),\n\t\t}\n\n\t\t// Process with timestamp comparison context\n\t\tctx := logicalPlanContextInfo{inTimestampComparison: true}\n\t\tvisitor.processConstant(intConst, ctx)\n\n\t\t// Check that the value was not modified\n\t\texpected := int64(123)\n\t\tassert.Equal(t, expected, intConst.Value.GetInt64())\n\t})\n\n\t// Test case 5: isTimestampColumn should correctly identify timestamp columns\n\tt.Run(\"IsTimestampColumn\", func(t *testing.T) {\n\t\t// Create a column with timestamp type\n\t\ttimestampCol := &expression.Column{\n\t\t\tRetType: types.NewFieldType(mysql.TypeTimestamp),\n\t\t}\n\n\t\t// Create a column with varchar type\n\t\tvarcharCol := &expression.Column{\n\t\t\tRetType: types.NewFieldType(mysql.TypeVarchar),\n\t\t}\n\n\t\t// Check that timestamp column is identified correctly\n\t\tassert.True(t, visitor.isTimestampColumn(timestampCol))\n\n\t\t// Check that non-timestamp column is identified correctly\n\t\tassert.False(t, visitor.isTimestampColumn(varcharCol))\n\t})\n}\n\n// TestTimestampLiteralOptimizer tests the complete timestamp literal optimization functionality\nfunc TestTimestampLiteralOptimizer(t *testing.T) {\n\t// Create a session context with createdAt time\n\tsctx := sessionctx.NewContext()\n\tcreatedAt := time.Date(2023, 10, 1, 8, 30, 0, 0, time.FixedZone(\"UTC+8\", 8*3600))\n\tsctx.GetSessionVars().CreatedAt = createdAt\n\tsctx.GetSessionVars().StmtCtx = &stmtctx.StatementContext{}\n\tsctx.GetSessionVars().PlanID = 0\n\tsctx.GetSessionVars().PlanColumnID = 0\n\n\t// Create a simple infoschema for testing\n\ttableInfos := map[string][]*model.TableInfo{\n\t\t\"test\": {\n\t\t\t{\n\t\t\t\tName: model.NewCIStr(\"orders\"),\n\t\t\t\tColumns: []*model.ColumnInfo{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:      model.NewCIStr(\"created_at\"),\n\t\t\t\t\t\tFieldType: *types.NewFieldType(mysql.TypeTimestamp),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:      model.NewCIStr(\"status\"),\n\t\t\t\t\t\tFieldType: *types.NewFieldType(mysql.TypeVarchar),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tis := infoschema.MockInfoSchema(tableInfos)\n\n\t// Test case 1: Simple equality comparison with timestamp column\n\tt.Run(\"SimpleEqualityComparison\", func(t *testing.T) {\n\t\tp := parser.New()\n\t\tstmts, _, err := p.Parse(\"SELECT * FROM test.orders WHERE created_at = '2023-10-01 08:30:00'\", \"\", \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, stmts, 1)\n\n\t\t// Build logical plan without optimization\n\t\tplan1, _, err := BuildLogicalPlan(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan1)\n\n\t\tlp1, ok := plan1.(LogicalPlan)\n\t\tassert.True(t, ok)\n\n\t\t// Find constants in the non-optimized plan\n\t\tconstants1 := findConstantsInPlan(lp1)\n\t\tassert.GreaterOrEqual(t, len(constants1), 1)\n\t\tif len(constants1) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00\", constants1[0].Value.GetString())\n\t\t}\n\n\t\t// Build logical plan with optimization\n\t\tplan2, _, err := BuildLogicalPlanWithOptimization(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan2)\n\n\t\t// Find constants in the optimized plan\n\t\tconstants2 := findConstantsInPlan(plan2)\n\t\tassert.GreaterOrEqual(t, len(constants2), 1)\n\t\tif len(constants2) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00+08:00\", constants2[0].Value.GetString())\n\t\t}\n\t})\n\n\t// Test case 2: IN clause with timestamp column\n\tt.Run(\"InClauseComparison\", func(t *testing.T) {\n\t\tp := parser.New()\n\t\tstmts, _, err := p.Parse(\"SELECT * FROM test.orders WHERE created_at IN ('2023-10-01 08:30:00', '2023-10-02 09:00:00')\", \"\", \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, stmts, 1)\n\n\t\t// Build logical plan without optimization\n\t\tplan1, _, err := BuildLogicalPlan(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan1)\n\n\t\tlp1, ok := plan1.(LogicalPlan)\n\t\tassert.True(t, ok)\n\n\t\t// Find constants in the non-optimized plan\n\t\tconstants1 := findConstantsInPlan(lp1)\n\t\tassert.GreaterOrEqual(t, len(constants1), 2)\n\t\tif len(constants1) >= 2 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00\", constants1[0].Value.GetString())\n\t\t\tassert.Equal(t, \"2023-10-02 09:00:00\", constants1[1].Value.GetString())\n\t\t}\n\n\t\t// Build logical plan with optimization\n\t\tplan2, _, err := BuildLogicalPlanWithOptimization(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan2)\n\n\t\t// Find constants in the optimized plan\n\t\tconstants2 := findConstantsInPlan(plan2)\n\t\tassert.GreaterOrEqual(t, len(constants2), 2)\n\t\tif len(constants2) >= 2 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00+08:00\", constants2[0].Value.GetString())\n\t\t\tassert.Equal(t, \"2023-10-02 09:00:00+08:00\", constants2[1].Value.GetString())\n\t\t}\n\t})\n\n\t// Test case 3: Timestamp with existing timezone should not be modified\n\tt.Run(\"TimestampWithExistingTimezone\", func(t *testing.T) {\n\t\tp := parser.New()\n\t\tstmts, _, err := p.Parse(\"SELECT * FROM test.orders WHERE created_at = '2023-10-01 08:30:00+08:00'\", \"\", \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, stmts, 1)\n\n\t\t// Build logical plan without optimization\n\t\tplan1, _, err := BuildLogicalPlan(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan1)\n\n\t\tlp1, ok := plan1.(LogicalPlan)\n\t\tassert.True(t, ok)\n\n\t\t// Find constants in the non-optimized plan\n\t\tconstants1 := findConstantsInPlan(lp1)\n\t\tassert.GreaterOrEqual(t, len(constants1), 1)\n\t\tif len(constants1) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00+08:00\", constants1[0].Value.GetString())\n\t\t}\n\n\t\t// Build logical plan with optimization\n\t\tplan2, _, err := BuildLogicalPlanWithOptimization(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan2)\n\n\t\t// Find constants in the optimized plan\n\t\tconstants2 := findConstantsInPlan(plan2)\n\t\tassert.GreaterOrEqual(t, len(constants2), 1)\n\t\tif len(constants2) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00+08:00\", constants2[0].Value.GetString())\n\t\t}\n\t})\n\n\t// Test case 4: Non-timestamp column should not be modified\n\tt.Run(\"NonTimestampColumn\", func(t *testing.T) {\n\t\tp := parser.New()\n\t\tstmts, _, err := p.Parse(\"SELECT * FROM test.orders WHERE status = '2023-10-01 08:30:00'\", \"\", \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, stmts, 1)\n\n\t\t// Build logical plan without optimization\n\t\tplan1, _, err := BuildLogicalPlan(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan1)\n\n\t\tlp1, ok := plan1.(LogicalPlan)\n\t\tassert.True(t, ok)\n\n\t\t// Find constants in the non-optimized plan\n\t\tconstants1 := findConstantsInPlan(lp1)\n\t\tassert.GreaterOrEqual(t, len(constants1), 1)\n\t\tif len(constants1) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00\", constants1[0].Value.GetString())\n\t\t}\n\n\t\t// Build logical plan with optimization\n\t\tplan2, _, err := BuildLogicalPlanWithOptimization(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan2)\n\n\t\t// Find constants in the optimized plan\n\t\tconstants2 := findConstantsInPlan(plan2)\n\t\tassert.GreaterOrEqual(t, len(constants2), 1)\n\t\tif len(constants2) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00\", constants2[0].Value.GetString())\n\t\t}\n\t})\n\n\t// Test case 5: Timestamp comparison in projection\n\tt.Run(\"TimestampComparisonInProjection\", func(t *testing.T) {\n\t\tp := parser.New()\n\t\tstmts, _, err := p.Parse(\"SELECT created_at > '2023-10-01 08:30:00' FROM test.orders\", \"\", \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, stmts, 1)\n\n\t\t// Build logical plan without optimization\n\t\tplan1, _, err := BuildLogicalPlan(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan1)\n\n\t\tlp1, ok := plan1.(LogicalPlan)\n\t\tassert.True(t, ok)\n\n\t\t// Find constants in the non-optimized plan\n\t\tconstants1 := findConstantsInPlan(lp1)\n\t\tassert.GreaterOrEqual(t, len(constants1), 1)\n\t\tif len(constants1) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00\", constants1[0].Value.GetString())\n\t\t}\n\n\t\t// Build logical plan with optimization\n\t\tplan2, _, err := BuildLogicalPlanWithOptimization(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan2)\n\n\t\t// Find constants in the optimized plan\n\t\tconstants2 := findConstantsInPlan(plan2)\n\t\tassert.GreaterOrEqual(t, len(constants2), 1)\n\t\tif len(constants2) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00+08:00\", constants2[0].Value.GetString())\n\t\t}\n\t})\n\n\t// Test case 6: Timestamp literals in aggregation expressions\n\tt.Run(\"TimestampLiteralsInAggregation\", func(t *testing.T) {\n\t\tp := parser.New()\n\t\tstmts, _, err := p.Parse(\"SELECT SUM(IF(created_at > '2023-10-01 08:30:00', 1, 0.5)) FROM test.orders\", \"\", \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, stmts, 1)\n\n\t\t// Build logical plan without optimization\n\t\tplan1, _, err := BuildLogicalPlan(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan1)\n\n\t\tlp1, ok := plan1.(LogicalPlan)\n\t\tassert.True(t, ok)\n\n\t\t// Find constants in the non-optimized plan\n\t\tconstants1 := findConstantsInPlan(lp1)\n\t\tassert.GreaterOrEqual(t, len(constants1), 1)\n\t\tif len(constants1) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00\", constants1[0].Value.GetString())\n\t\t}\n\n\t\t// Build logical plan with optimization\n\t\tplan2, _, err := BuildLogicalPlanWithOptimization(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan2)\n\n\t\t// Find constants in the optimized plan\n\t\tconstants2 := findConstantsInPlan(plan2)\n\t\tassert.GreaterOrEqual(t, len(constants2), 1)\n\t\tif len(constants2) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00+08:00\", constants2[0].Value.GetString())\n\t\t}\n\t})\n\n\t// Test case 7: Timestamp literals in GROUP BY with time comparisons\n\tt.Run(\"TimestampLiteralsInGroupByWithComparisons\", func(t *testing.T) {\n\t\tp := parser.New()\n\t\tstmts, _, err := p.Parse(\"SELECT COUNT(*) FROM test.orders GROUP BY created_at > '2023-10-01 08:30:00'\", \"\", \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, stmts, 1)\n\n\t\t// Build logical plan without optimization\n\t\tplan1, _, err := BuildLogicalPlan(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan1)\n\n\t\tlp1, ok := plan1.(LogicalPlan)\n\t\tassert.True(t, ok)\n\n\t\t// Find constants in the non-optimized plan\n\t\tconstants1 := findConstantsInPlan(lp1)\n\t\tassert.GreaterOrEqual(t, len(constants1), 1)\n\t\tif len(constants1) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00\", constants1[0].Value.GetString())\n\t\t}\n\n\t\t// Build logical plan with optimization\n\t\tplan2, _, err := BuildLogicalPlanWithOptimization(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan2)\n\n\t\t// Find constants in the optimized plan\n\t\tconstants2 := findConstantsInPlan(plan2)\n\t\tassert.GreaterOrEqual(t, len(constants2), 1)\n\t\tif len(constants2) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00+08:00\", constants2[0].Value.GetString())\n\t\t}\n\t})\n\n\t// Test case 8: Timestamp literals in window functions\n\tt.Run(\"TimestampLiteralsInWindowFunctions\", func(t *testing.T) {\n\t\tp := parser.New()\n\t\tstmts, _, err := p.Parse(\"SELECT created_at, ROW_NUMBER() OVER (PARTITION BY created_at > '2023-10-01 08:30:00' ORDER BY created_at) as rn FROM test.orders\", \"\", \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, stmts, 1)\n\n\t\t// Build logical plan without optimization\n\t\tplan1, _, err := BuildLogicalPlan(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan1)\n\n\t\tlp1, ok := plan1.(LogicalPlan)\n\t\tassert.True(t, ok)\n\n\t\t// Find constants in the non-optimized plan\n\t\tconstants1 := findConstantsInPlan(lp1)\n\t\tassert.GreaterOrEqual(t, len(constants1), 1)\n\t\tif len(constants1) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00\", constants1[0].Value.GetString())\n\t\t}\n\n\t\t// Build logical plan with optimization\n\t\tplan2, _, err := BuildLogicalPlanWithOptimization(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan2)\n\n\t\t// Find constants in the optimized plan\n\t\tconstants2 := findConstantsInPlan(plan2)\n\t\tassert.GreaterOrEqual(t, len(constants2), 1)\n\t\tif len(constants2) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00+08:00\", constants2[0].Value.GetString())\n\t\t}\n\t})\n\n\t// Test case 9: Timestamp literals in ORDER BY clauses\n\tt.Run(\"TimestampLiteralsInOrderBy\", func(t *testing.T) {\n\t\tp := parser.New()\n\t\tstmts, _, err := p.Parse(\"SELECT created_at FROM test.orders ORDER BY (created_at > '2023-10-01 08:30:00') DESC\", \"\", \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, stmts, 1)\n\n\t\t// Build logical plan without optimization\n\t\tplan1, _, err := BuildLogicalPlan(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan1)\n\n\t\tlp1, ok := plan1.(LogicalPlan)\n\t\tassert.True(t, ok)\n\n\t\t// Find constants in the non-optimized plan\n\t\tconstants1 := findConstantsInPlan(lp1)\n\t\tassert.GreaterOrEqual(t, len(constants1), 1)\n\t\tif len(constants1) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00\", constants1[0].Value.GetString())\n\t\t}\n\n\t\t// Build logical plan with optimization\n\t\tplan2, _, err := BuildLogicalPlanWithOptimization(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan2)\n\n\t\t// Find constants in the optimized plan\n\t\tconstants2 := findConstantsInPlan(plan2)\n\t\tassert.GreaterOrEqual(t, len(constants2), 1)\n\t\tif len(constants2) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00+08:00\", constants2[0].Value.GetString())\n\t\t}\n\t})\n\n\t// Test case 10: Timestamp literals in subquery with APPLY\n\tt.Run(\"TimestampLiteralsInApply\", func(t *testing.T) {\n\t\tp := parser.New()\n\t\tstmts, _, err := p.Parse(\"SELECT (SELECT COUNT(*) FROM test.orders o2 WHERE o2.created_at > '2023-10-01 08:30:00' AND o2.status = o1.status) FROM test.orders o1\", \"\", \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, stmts, 1)\n\n\t\t// Build logical plan without optimization\n\t\tplan1, _, err := BuildLogicalPlan(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan1)\n\n\t\tlp1, ok := plan1.(LogicalPlan)\n\t\tassert.True(t, ok)\n\n\t\t// Find constants in the non-optimized plan\n\t\tconstants1 := findConstantsInPlan(lp1)\n\t\tassert.GreaterOrEqual(t, len(constants1), 1)\n\t\tif len(constants1) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00\", constants1[0].Value.GetString())\n\t\t}\n\n\t\t// Build logical plan with optimization\n\t\tplan2, _, err := BuildLogicalPlanWithOptimization(context.Background(), sctx, stmts[0], is)\n\t\tassert.NoError(t, err)\n\t\tassert.NotNil(t, plan2)\n\n\t\t// Find constants in the optimized plan\n\t\tconstants2 := findConstantsInPlan(plan2)\n\t\tassert.GreaterOrEqual(t, len(constants2), 1)\n\t\tif len(constants2) > 0 {\n\t\t\tassert.Equal(t, \"2023-10-01 08:30:00+08:00\", constants2[0].Value.GetString())\n\t\t}\n\t})\n}\n\n// findConstantsInPlan recursively traverses a logical plan and collects all constant expressions\nfunc findConstantsInPlan(lp LogicalPlan) []*expression.Constant {\n\tvar constants []*expression.Constant\n\n\tswitch node := lp.(type) {\n\tcase *LogicalSelection:\n\t\tfor _, expr := range node.Conditions {\n\t\t\tconstants = append(constants, findConstantsInExpression(expr)...)\n\t\t}\n\n\tcase *LogicalProjection:\n\t\tfor _, expr := range node.Exprs {\n\t\t\tconstants = append(constants, findConstantsInExpression(expr)...)\n\t\t}\n\n\tcase *LogicalAggregation:\n\t\t// Process aggregation function arguments and group by items\n\t\tfor _, aggFunc := range node.AggFuncs {\n\t\t\tfor _, arg := range aggFunc.Args {\n\t\t\t\tconstants = append(constants, findConstantsInExpression(arg)...)\n\t\t\t}\n\t\t}\n\t\tfor _, item := range node.GroupByItems {\n\t\t\tconstants = append(constants, findConstantsInExpression(item)...)\n\t\t}\n\n\tcase *LogicalWindow:\n\t\t// Process window function arguments, partition by, order by, and frame bounds\n\t\tfor _, windowFunc := range node.WindowFuncDescs {\n\t\t\tfor _, arg := range windowFunc.Args {\n\t\t\t\tconstants = append(constants, findConstantsInExpression(arg)...)\n\t\t\t}\n\t\t}\n\t\tfor _, item := range node.PartitionBy {\n\t\t\tconstants = append(constants, findConstantsInExpression(item.Col)...)\n\t\t}\n\t\tfor _, item := range node.OrderBy {\n\t\t\tconstants = append(constants, findConstantsInExpression(item.Col)...)\n\t\t}\n\t\t// Process frame bound expressions if they exist\n\t\tif node.Frame != nil {\n\t\t\tif node.Frame.Start != nil {\n\t\t\t\tfor _, calcFunc := range node.Frame.Start.CalcFuncs {\n\t\t\t\t\tconstants = append(constants, findConstantsInExpression(calcFunc)...)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif node.Frame.End != nil {\n\t\t\t\tfor _, calcFunc := range node.Frame.End.CalcFuncs {\n\t\t\t\t\tconstants = append(constants, findConstantsInExpression(calcFunc)...)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tcase *LogicalSort:\n\t\t// Process sort expressions\n\t\tfor _, item := range node.ByItems {\n\t\t\tconstants = append(constants, findConstantsInExpression(item.Expr)...)\n\t\t}\n\n\tcase *LogicalApply:\n\t\t// Process correlated columns\n\t\tfor _, col := range node.CorCols {\n\t\t\tconstants = append(constants, findConstantsInExpression(&col.Column)...)\n\t\t}\n\t\t// Process all join conditions\n\t\tfor _, eqCond := range node.EqualConditions {\n\t\t\tconstants = append(constants, findConstantsInExpression(eqCond)...)\n\t\t}\n\t\tfor _, leftCond := range node.LeftConditions {\n\t\t\tconstants = append(constants, findConstantsInExpression(leftCond)...)\n\t\t}\n\t\tfor _, rightCond := range node.RightConditions {\n\t\t\tconstants = append(constants, findConstantsInExpression(rightCond)...)\n\t\t}\n\t\tfor _, otherCond := range node.OtherConditions {\n\t\t\tconstants = append(constants, findConstantsInExpression(otherCond)...)\n\t\t}\n\t}\n\n\t// Recursively process children\n\tfor _, child := range lp.Children() {\n\t\tconstants = append(constants, findConstantsInPlan(child)...)\n\t}\n\n\treturn constants\n}\n\n// findConstantsInExpression recursively traverses an expression and collects all constant expressions\nfunc findConstantsInExpression(expr expression.Expression) []*expression.Constant {\n\tvar constants []*expression.Constant\n\n\tif constant, ok := expr.(*expression.Constant); ok {\n\t\t// Only include constants that match timestamp formats\n\t\tif constant.Value.Kind() == types.KindString {\n\t\t\tstrValue := constant.Value.GetString()\n\t\t\t// Check if it matches timestamp pattern like \"2023-10-01 08:30:00\" or \"2023-10-01T08:30:00\"\n\t\t\ttimestampPattern := regexp.MustCompile(`^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}`)\n\t\t\tif timestampPattern.MatchString(strValue) {\n\t\t\t\tconstants = append(constants, constant)\n\t\t\t}\n\t\t}\n\t}\n\n\tif scalarFunc, ok := expr.(*expression.ScalarFunction); ok {\n\t\tfor _, arg := range scalarFunc.GetArgs() {\n\t\t\tconstants = append(constants, findConstantsInExpression(arg)...)\n\t\t}\n\t}\n\n\treturn constants\n}\n"
  },
  {
    "path": "pkg/planner/core/rule_predicate_push_down.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n// // Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"context\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\n\t\"github.com/secretflow/scql/pkg/expression\"\n)\n\ntype ppdSolver struct{}\n\nfunc (s *ppdSolver) optimize(ctx context.Context, lp LogicalPlan) (LogicalPlan, error) {\n\t_, p := lp.PredicatePushDown(nil)\n\treturn p, nil\n}\n\nfunc (*ppdSolver) name() string {\n\treturn \"predicate_push_down\"\n}\n\nfunc addSelection(p LogicalPlan, child LogicalPlan, conditions []expression.Expression, chIdx int) {\n\tif len(conditions) == 0 {\n\t\tp.Children()[chIdx] = child\n\t\treturn\n\t}\n\tselection := LogicalSelection{Conditions: conditions}.Init(p.SCtx(), p.SelectBlockOffset())\n\tselection.SetChildren(child)\n\tselection.SetSchema(child.Schema().Clone())\n\tselection.SetOutputNames(child.OutputNames())\n\tp.Children()[chIdx] = selection\n}\n\nfunc AddSelection(p LogicalPlan, child LogicalPlan, conditions []expression.Expression, chIdx int) {\n\taddSelection(p, child, conditions, chIdx)\n}\n\n// PredicatePushDown implements LogicalPlan PredicatePushDown interface.\nfunc (la *LogicalAggregation) PredicatePushDown(predicates []expression.Expression) (ret []expression.Expression, retPlan LogicalPlan) {\n\tvar condsToPush []expression.Expression\n\texprsOriginal := make([]expression.Expression, 0, len(la.AggFuncs))\n\tfor _, fun := range la.AggFuncs {\n\t\texprsOriginal = append(exprsOriginal, fun.Args[0])\n\t}\n\tgroupByColumns := expression.NewSchema(la.groupByCols...)\n\tfor _, cond := range predicates {\n\t\tswitch cond.(type) {\n\t\tcase *expression.Constant:\n\t\t\tcondsToPush = append(condsToPush, cond)\n\t\t\t// Consider SQL list \"select sum(b) from t group by a having 1=0\". \"1=0\" is a constant predicate which should be\n\t\t\t// retained and pushed down at the same time. Because we will get a wrong query result that contains one column\n\t\t\t// with value 0 rather than an empty query result.\n\t\t\tret = append(ret, cond)\n\t\tcase *expression.ScalarFunction:\n\t\t\textractedCols := expression.ExtractColumns(cond)\n\t\t\tok := true\n\t\t\tfor _, col := range extractedCols {\n\t\t\t\tif !groupByColumns.Contains(col) {\n\t\t\t\t\tok = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ok {\n\t\t\t\tnewFunc := expression.ColumnSubstitute(cond, la.Schema(), exprsOriginal)\n\t\t\t\tcondsToPush = append(condsToPush, newFunc)\n\t\t\t} else {\n\t\t\t\tret = append(ret, cond)\n\t\t\t}\n\t\tdefault:\n\t\t\tret = append(ret, cond)\n\t\t}\n\t}\n\tla.baseLogicalPlan.PredicatePushDown(condsToPush)\n\treturn ret, la\n}\n\n// PredicatePushDown implements LogicalPlan interface.\nfunc (p *baseLogicalPlan) PredicatePushDown(predicates []expression.Expression) ([]expression.Expression, LogicalPlan) {\n\tif len(p.children) == 0 {\n\t\treturn predicates, p.self\n\t}\n\tchild := p.children[0]\n\trest, newChild := child.PredicatePushDown(predicates)\n\taddSelection(p.self, newChild, rest, 0)\n\treturn nil, p.self\n}\n\n// PredicatePushDown implements LogicalPlan PredicatePushDown interface.\nfunc (p *LogicalSelection) PredicatePushDown(predicates []expression.Expression) ([]expression.Expression, LogicalPlan) {\n\tretConditions, child := p.children[0].PredicatePushDown(append(p.Conditions, predicates...))\n\tif len(retConditions) > 0 {\n\t\tp.Conditions = retConditions\n\t\treturn nil, p\n\t}\n\treturn nil, child\n}\n\n// PredicatePushDown implements LogicalPlan PredicatePushDown interface.\nfunc (ds *DataSource) PredicatePushDown(predicates []expression.Expression) ([]expression.Expression, LogicalPlan) {\n\treturn predicates, ds\n}\n\n// PredicatePushDown implements LogicalPlan PredicatePushDown interface.\nfunc (p *LogicalJoin) PredicatePushDown(predicates []expression.Expression) (ret []expression.Expression, retPlan LogicalPlan) {\n\tvar equalCond []*expression.ScalarFunction\n\tvar leftPushCond, rightPushCond, otherCond, leftCond, rightCond []expression.Expression\n\tswitch p.JoinType {\n\tcase LeftOuterJoin, LeftOuterSemiJoin, AntiLeftOuterSemiJoin:\n\t\t// Handle where conditions\n\t\tpredicates = expression.ExtractFiltersFromDNFs(p.ctx, predicates)\n\t\t// Only derive left where condition, because right where condition cannot be pushed down\n\t\tequalCond, leftPushCond, rightPushCond, otherCond = p.extractOnCondition(predicates, true, false)\n\t\tleftCond = leftPushCond\n\t\t// Handle join conditions, only derive right join condition, because left join condition cannot be pushed down\n\t\t_, derivedRightJoinCond := DeriveOtherConditions(p, false, true)\n\t\trightCond = append(p.RightConditions, derivedRightJoinCond...)\n\t\tp.RightConditions = nil\n\t\tret = append(expression.ScalarFuncs2Exprs(equalCond), otherCond...)\n\t\tret = append(ret, rightPushCond...)\n\tcase RightOuterJoin:\n\t\t// Handle where conditions\n\t\tpredicates = expression.ExtractFiltersFromDNFs(p.ctx, predicates)\n\t\t// Only derive right where condition, because left where condition cannot be pushed down\n\t\tequalCond, leftPushCond, rightPushCond, otherCond = p.extractOnCondition(predicates, false, true)\n\t\trightCond = rightPushCond\n\t\t// Handle join conditions, only derive left join condition, because right join condition cannot be pushed down\n\t\tderivedLeftJoinCond, _ := DeriveOtherConditions(p, true, false)\n\t\tleftCond = append(p.LeftConditions, derivedLeftJoinCond...)\n\t\tp.LeftConditions = nil\n\t\tret = append(expression.ScalarFuncs2Exprs(equalCond), otherCond...)\n\t\tret = append(ret, leftPushCond...)\n\tcase SemiJoin, InnerJoin:\n\t\ttempCond := make([]expression.Expression, 0, len(p.LeftConditions)+len(p.RightConditions)+len(p.EqualConditions)+len(p.OtherConditions)+len(predicates))\n\t\ttempCond = append(tempCond, p.LeftConditions...)\n\t\ttempCond = append(tempCond, p.RightConditions...)\n\t\ttempCond = append(tempCond, expression.ScalarFuncs2Exprs(p.EqualConditions)...)\n\t\ttempCond = append(tempCond, p.OtherConditions...)\n\t\ttempCond = append(tempCond, predicates...)\n\t\ttempCond = expression.ExtractFiltersFromDNFs(p.ctx, tempCond)\n\t\tequalCond, leftPushCond, rightPushCond, otherCond = p.extractOnCondition(tempCond, true, true)\n\t\tp.LeftConditions = nil\n\t\tp.RightConditions = nil\n\t\tp.EqualConditions = equalCond\n\t\tp.OtherConditions = otherCond\n\t\tleftCond = leftPushCond\n\t\trightCond = rightPushCond\n\tcase AntiSemiJoin:\n\t\t// `predicates` should only contain left conditions or constant filters.\n\t\t_, leftPushCond, rightPushCond, _ = p.extractOnCondition(predicates, true, true)\n\t\t// Do not derive `is not null` for anti join, since it may cause wrong results.\n\t\t// For example:\n\t\t// `select * from t t1 where t1.a not in (select b from t t2)` does not imply `t2.b is not null`,\n\t\t// `select * from t t1 where t1.a not in (select a from t t2 where t1.b = t2.b` does not imply `t1.b is not null`,\n\t\t// `select * from t t1 where not exists (select * from t t2 where t2.a = t1.a)` does not imply `t1.a is not null`,\n\t\tleftCond = leftPushCond\n\t\trightCond = append(p.RightConditions, rightPushCond...)\n\t\tp.RightConditions = nil\n\t}\n\tleftCond = expression.RemoveDupExprs(p.ctx, leftCond)\n\trightCond = expression.RemoveDupExprs(p.ctx, rightCond)\n\tleftRet, lCh := p.children[0].PredicatePushDown(leftCond)\n\trightRet, rCh := p.children[1].PredicatePushDown(rightCond)\n\taddSelection(p, lCh, leftRet, 0)\n\taddSelection(p, rCh, rightRet, 1)\n\tp.updateEQCond()\n\tfor _, eqCond := range p.EqualConditions {\n\t\tp.LeftJoinKeys = append(p.LeftJoinKeys, eqCond.GetArgs()[0].(*expression.Column))\n\t\tp.RightJoinKeys = append(p.RightJoinKeys, eqCond.GetArgs()[1].(*expression.Column))\n\t}\n\tp.mergeSchema(p.Schema().Columns)\n\tbuildKeyInfo(p)\n\t// except semi\n\tswitch p.JoinType {\n\tcase InnerJoin, LeftOuterJoin, RightOuterJoin:\n\t\tnilOtherCond := p.OtherConditions == nil || len(p.OtherConditions) == 0\n\t\tnilLeftCond := p.LeftConditions == nil || len(p.LeftConditions) == 0\n\t\tnilRightCond := p.RightConditions == nil || len(p.RightConditions) == 0\n\t\tconditonsNeedPushToSelection := expression.CNFExprs{}\n\t\tif !nilOtherCond {\n\t\t\tconditonsNeedPushToSelection = append(conditonsNeedPushToSelection, p.OtherConditions...)\n\t\t\tp.OtherConditions = nil\n\t\t}\n\t\tif !nilLeftCond {\n\t\t\tconditonsNeedPushToSelection = append(conditonsNeedPushToSelection, p.LeftConditions...)\n\t\t\tp.LeftConditions = nil\n\t\t}\n\t\tif !nilRightCond {\n\t\t\tconditonsNeedPushToSelection = append(conditonsNeedPushToSelection, p.RightConditions...)\n\t\t\tp.RightConditions = nil\n\t\t}\n\n\t\tif !nilLeftCond || !nilOtherCond || !nilRightCond {\n\t\t\tselection := LogicalSelection{Conditions: conditonsNeedPushToSelection}.Init(p.SCtx(), 0)\n\t\t\tselection.SetSchema(p.Schema().Clone())\n\t\t\tselection.SetOutputNames(p.OutputNames())\n\t\t\tselection.SetChildren(p)\n\t\t\treturn ret, selection.self\n\t\t}\n\t}\n\n\treturn ret, p.self\n}\n\n// updateEQCond will extract the arguments of a equal condition that connect two expressions.\nfunc (p *LogicalJoin) updateEQCond() {\n\tlChild, rChild := p.children[0], p.children[1]\n\tvar lKeys, rKeys []expression.Expression\n\tfor i := len(p.OtherConditions) - 1; i >= 0; i-- {\n\t\tneed2Remove := false\n\t\tif eqCond, ok := p.OtherConditions[i].(*expression.ScalarFunction); ok && eqCond.FuncName.L == ast.EQ {\n\t\t\t// If it is a column equal condition converted from `[not] in (subq)`, do not move it\n\t\t\t// to EqualConditions, and keep it in OtherConditions. Reference comments in `extractOnCondition`\n\t\t\t// for detailed reasons.\n\t\t\tif expression.IsEQCondFromIn(eqCond) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlExpr, rExpr := eqCond.GetArgs()[0], eqCond.GetArgs()[1]\n\t\t\tif expression.ExprFromSchema(lExpr, lChild.Schema()) && expression.ExprFromSchema(rExpr, rChild.Schema()) {\n\t\t\t\tlKeys = append(lKeys, lExpr)\n\t\t\t\trKeys = append(rKeys, rExpr)\n\t\t\t\tneed2Remove = true\n\t\t\t} else if expression.ExprFromSchema(lExpr, rChild.Schema()) && expression.ExprFromSchema(rExpr, lChild.Schema()) {\n\t\t\t\tlKeys = append(lKeys, rExpr)\n\t\t\t\trKeys = append(rKeys, lExpr)\n\t\t\t\tneed2Remove = true\n\t\t\t}\n\t\t}\n\t\tif need2Remove {\n\t\t\tp.OtherConditions = append(p.OtherConditions[:i], p.OtherConditions[i+1:]...)\n\t\t}\n\t}\n\tif len(lKeys) > 0 {\n\t\tneedLProj, needRProj := false, false\n\t\tfor i := range lKeys {\n\t\t\t_, lOk := lKeys[i].(*expression.Column)\n\t\t\t_, rOk := rKeys[i].(*expression.Column)\n\t\t\tneedLProj = needLProj || !lOk\n\t\t\tneedRProj = needRProj || !rOk\n\t\t}\n\n\t\tvar lProj, rProj *LogicalProjection\n\t\tif needLProj {\n\t\t\tlProj = p.getProj(0)\n\t\t}\n\t\tif needRProj {\n\t\t\trProj = p.getProj(1)\n\t\t}\n\t\tfor i := range lKeys {\n\t\t\tlKey, rKey := lKeys[i], rKeys[i]\n\t\t\tif lProj != nil {\n\t\t\t\tlKey = lProj.appendExpr(lKey)\n\t\t\t}\n\t\t\tif rProj != nil {\n\t\t\t\trKey = rProj.appendExpr(rKey)\n\t\t\t}\n\t\t\teqCond := expression.NewFunctionInternal(p.ctx, ast.EQ, types.NewFieldType(mysql.TypeTiny), lKey, rKey)\n\t\t\tp.EqualConditions = append(p.EqualConditions, eqCond.(*expression.ScalarFunction))\n\t\t}\n\t}\n}\n\nfunc (p *LogicalProjection) appendExpr(expr expression.Expression) *expression.Column {\n\tif col, ok := expr.(*expression.Column); ok {\n\t\treturn col\n\t}\n\texpr = expression.ColumnSubstitute(expr, p.schema, p.Exprs)\n\tp.Exprs = append(p.Exprs, expr)\n\n\tcol := &expression.Column{\n\t\tUniqueID: p.ctx.GetSessionVars().AllocPlanColumnID(),\n\t\tRetType:  expr.GetType(),\n\t}\n\tp.schema.Append(col)\n\treturn col\n}\n\nfunc (p *LogicalJoin) getProj(idx int) *LogicalProjection {\n\tchild := p.children[idx]\n\tproj, ok := child.(*LogicalProjection)\n\tif ok {\n\t\treturn proj\n\t}\n\tproj = LogicalProjection{Exprs: make([]expression.Expression, 0, child.Schema().Len())}.Init(p.ctx, child.SelectBlockOffset())\n\tfor _, col := range child.Schema().Columns {\n\t\tproj.Exprs = append(proj.Exprs, col)\n\t}\n\tproj.SetSchema(child.Schema().Clone())\n\tproj.SetChildren(child)\n\tp.children[idx] = proj\n\treturn proj\n}\n\n// PredicatePushDown implements LogicalPlan PredicatePushDown interface.\nfunc (p *LogicalProjection) PredicatePushDown(predicates []expression.Expression) (ret []expression.Expression, retPlan LogicalPlan) {\n\tcanBePushed := make([]expression.Expression, 0, len(predicates))\n\tfor _, cond := range predicates {\n\t\tcanBePushed = append(canBePushed, expression.ColumnSubstitute(cond, p.Schema(), p.Exprs))\n\t}\n\treturn p.baseLogicalPlan.PredicatePushDown(canBePushed)\n}\n\n// DeriveOtherConditions given a LogicalJoin, check the OtherConditions to see if we can derive more\n// conditions for left/right child pushdown.\nfunc DeriveOtherConditions(p *LogicalJoin, deriveLeft bool, deriveRight bool) (leftCond []expression.Expression,\n\trightCond []expression.Expression) {\n\t// NOTE(yang.y): further simplification on DNF is skipped\n\treturn\n}\n\n// PredicatePushDown implements LogicalPlan PredicatePushDown interface.\nfunc (p *LogicalUnionAll) PredicatePushDown(predicates []expression.Expression) (ret []expression.Expression, retPlan LogicalPlan) {\n\tfor i, proj := range p.children {\n\t\tnewExprs := make([]expression.Expression, 0, len(predicates))\n\t\tnewExprs = append(newExprs, predicates...)\n\t\tretCond, newChild := proj.PredicatePushDown(newExprs)\n\t\taddSelection(p, newChild, retCond, i)\n\t}\n\treturn nil, p\n}\n\nfunc (p *LogicalWindow) GetPartitionByCols() []*expression.Column {\n\tpartitionCols := make([]*expression.Column, 0, len(p.PartitionBy))\n\tfor _, partitionItem := range p.PartitionBy {\n\t\tpartitionCols = append(partitionCols, partitionItem.Col)\n\t}\n\treturn partitionCols\n}\n\n// PredicatePushDown implements LogicalPlan PredicatePushDown interface.\nfunc (p *LogicalWindow) PredicatePushDown(predicates []expression.Expression) ([]expression.Expression, LogicalPlan) {\n\tcanBePushed := make([]expression.Expression, 0, len(predicates))\n\tcanNotBePushed := make([]expression.Expression, 0, len(predicates))\n\tpartitionCols := expression.NewSchema(p.GetPartitionByCols()...)\n\tfor _, cond := range predicates {\n\t\t// We can push predicate beneath Window, only if all of the\n\t\t// extractedCols are part of partitionBy columns.\n\t\tif expression.ExprFromSchema(cond, partitionCols) {\n\t\t\tcanBePushed = append(canBePushed, cond)\n\t\t} else {\n\t\t\tcanNotBePushed = append(canNotBePushed, cond)\n\t\t}\n\t}\n\tp.baseLogicalPlan.PredicatePushDown(canBePushed)\n\treturn canNotBePushed, p\n}\n"
  },
  {
    "path": "pkg/planner/core/stringer.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n// ToString explains a Plan, returns description string.\nfunc ToString(p Plan) string {\n\tstrs, _ := toString(p, []string{}, []int{})\n\treturn strings.Join(strs, \"->\")\n}\n\nfunc toString(in Plan, strs []string, idxs []int) ([]string, []int) {\n\tswitch x := in.(type) {\n\tcase LogicalPlan:\n\t\tif len(x.Children()) > 1 {\n\t\t\tidxs = append(idxs, len(strs))\n\t\t}\n\n\t\tfor _, c := range x.Children() {\n\t\t\tstrs, idxs = toString(c, strs, idxs)\n\t\t}\n\t}\n\n\tvar str string\n\tswitch x := in.(type) {\n\tcase *LogicalJoin:\n\t\tlast := len(idxs) - 1\n\t\tidx := idxs[last]\n\t\tchildren := strs[idx:]\n\t\tstrs = strs[:idx]\n\t\tstr = \"Join{\" + strings.Join(children, \"->\") + \"}\"\n\t\tidxs = idxs[:last]\n\n\t\tvar conds []string\n\t\tif len(x.EqualConditions) > 0 {\n\t\t\tconds = append(conds, fmt.Sprintf(\"%s,\", x.EqualConditions))\n\t\t}\n\t\tif len(x.LeftConditions) > 0 {\n\t\t\tconds = append(conds, fmt.Sprintf(\"l%s,\", x.LeftConditions))\n\t\t}\n\t\tif len(x.RightConditions) > 0 {\n\t\t\tconds = append(conds, fmt.Sprintf(\"r%s,\", x.RightConditions))\n\t\t}\n\t\tif len(x.OtherConditions) > 0 {\n\t\t\tconds = append(conds, fmt.Sprintf(\"o%s,\", x.OtherConditions))\n\t\t}\n\t\tif len(conds) > 0 {\n\t\t\tstr += \"(\" + strings.Join(conds, \",\") + \")\"\n\t\t}\n\tcase *LogicalUnionAll:\n\t\tlast := len(idxs) - 1\n\t\tidx := idxs[last]\n\t\tchildren := strs[idx:]\n\t\tstrs = strs[:idx]\n\t\tstr = \"UnionAll{\" + strings.Join(children, \"->\") + \"}\"\n\t\tidxs = idxs[:last]\n\tcase *DataSource:\n\t\tif x.TableAsName != nil && x.TableAsName.L != \"\" {\n\t\t\tstr = fmt.Sprintf(\"DataScan(%s)\", x.TableAsName)\n\t\t} else {\n\t\t\tstr = fmt.Sprintf(\"DataScan(%s)\", x.tableInfo.Name)\n\t\t}\n\tcase *LogicalProjection:\n\t\tstr = fmt.Sprintf(\"Projection(%s)\", x.Exprs)\n\tcase *LogicalSelection:\n\t\tstr = fmt.Sprintf(\"Sel(%s)\", x.Conditions)\n\tcase *LogicalSort:\n\t\tstr = \"Sort(\"\n\t\tfor i, byItem := range x.ByItems {\n\t\t\tstr += byItem.String()\n\t\t\tif i != len(x.ByItems)-1 {\n\t\t\t\tstr += \",\"\n\t\t\t}\n\t\t}\n\t\tstr += \")\"\n\tcase *LogicalLimit:\n\t\tstr = \"Limit\"\n\tcase *LogicalAggregation:\n\t\tstr = \"Aggr(\"\n\t\tfor i, aggFunc := range x.AggFuncs {\n\t\t\tstr += aggFunc.String()\n\t\t\tif i != len(x.AggFuncs)-1 {\n\t\t\t\tstr += \",\"\n\t\t\t}\n\t\t}\n\t\tstr += \")\"\n\tcase *LogicalApply:\n\t\tlast := len(idxs) - 1\n\t\tidx := idxs[last]\n\t\tchildren := strs[idx:]\n\t\tstrs = strs[:idx]\n\t\tidxs = idxs[:last]\n\t\tstr = \"Apply{\" + strings.Join(children, \"->\") + \"}\"\n\n\t\tvar conds []string\n\t\tif len(x.EqualConditions) > 0 {\n\t\t\tconds = append(conds, fmt.Sprintf(\"%s\", x.EqualConditions))\n\t\t}\n\t\tif len(x.LeftConditions) > 0 {\n\t\t\tconds = append(conds, fmt.Sprintf(\"l%s\", x.LeftConditions))\n\t\t}\n\t\tif len(x.RightConditions) > 0 {\n\t\t\tconds = append(conds, fmt.Sprintf(\"r%s\", x.RightConditions))\n\t\t}\n\t\tif len(x.OtherConditions) > 0 {\n\t\t\tconds = append(conds, fmt.Sprintf(\"o%s\", x.OtherConditions))\n\t\t}\n\t\tif len(conds) > 0 {\n\t\t\tstr += \"(\" + strings.Join(conds, \",\") + \")\"\n\t\t}\n\tcase *LogicalWindow:\n\t\tbuffer := bytes.NewBufferString(\"\")\n\t\tformatWindowFuncDescs(buffer, x.WindowFuncDescs, x.schema)\n\t\tstr = fmt.Sprintf(\"Window(%s)\", buffer.String())\n\tdefault:\n\t\tstr = fmt.Sprintf(\"%T\", in)\n\t}\n\tstrs = append(strs, str)\n\treturn strs, idxs\n}\n"
  },
  {
    "path": "pkg/planner/core/testdata/runsql_in.json",
    "content": "[\n  {\n    \"name\": \"TestRunSQL\",\n    \"cases\": [\n      {\n        \"sql\": \"SELECT  count(*) AS numwait FROM alice.tbl_0 l1, alice.tbl_1 as l2 WHERE l1.plain_int_0 = l2.plain_int_0 AND NOT EXISTS ( SELECT * FROM alice.tbl_2 l3 WHERE l3.plain_int_0 = l1.plain_int_0 AND l3.plain_int_0 != l1.plain_int_0 AND l3.plain_int_0 > l1.plain_int_0 ) GROUP BY l1.plain_string_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql\": \"select count(1) as numwait from alice.tbl_0 as l1 join alice.tbl_1 as l2 on l1.plain_int_0=l2.plain_int_0 where not exists (select l3.plain_int_0 from alice.tbl_2 as l3 where ((l1.plain_int_0=l3.plain_int_0) and (l3.plain_int_0!=l1.plain_int_0)) and (l3.plain_int_0>l1.plain_int_0)) group by l1.plain_string_0 having count(1)>=4\"\n      },\n      {\n        \"sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 cross join alice.tbl_2\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2\"\n      },\n      {\n        \"sql\": \"SELECT tbl_1.plain_int_0, tbl_1.plain_float_0, ROW_NUMBER() OVER(PARTITION BY tbl_1.plain_int_0 ORDER BY tbl_1.plain_float_0) AS number from alice.tbl_1 as tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_int_0,tbl_1.plain_float_0,row_number() over (partition by tbl_1.plain_int_0 order by tbl_1.plain_float_0) as number from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_int_0,tbl_1.plain_float_0,row_number() over (partition by tbl_1.plain_int_0 order by tbl_1.plain_float_0) as number from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_int_0,tbl_1.plain_float_0,row_number() over (partition by tbl_1.plain_int_0 order by tbl_1.plain_float_0) as number from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_int_0,tbl_1.plain_float_0,row_number() over (partition by tbl_1.plain_int_0 order by tbl_1.plain_float_0) as number from alice.tbl_1 as tbl_1\"\n      },\n      {\n        \"sql\": \"SELECT geodist(plain_int_0, plain_float_0, plain_int_0, plain_float_0, 6300) from alice.tbl_1 as tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select 6300*acos(sin(radians(tbl_1.plain_float_0))*sin(radians(tbl_1.plain_float_0))+cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_int_0)-radians(tbl_1.plain_int_0))) as expr_121 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_pg\": \"select 6300*acos(sin(radians(tbl_1.plain_float_0))*sin(radians(tbl_1.plain_float_0))+cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_int_0)-radians(tbl_1.plain_int_0))) as expr_121 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_csv\": \"select 6300*acos(sin(radians(tbl_1.plain_float_0))*sin(radians(tbl_1.plain_float_0))+cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_int_0)-radians(tbl_1.plain_int_0))) as expr_121 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql\": \"select 6300*acos(sin(radians(tbl_1.plain_float_0))*sin(radians(tbl_1.plain_float_0))+cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_int_0)-radians(tbl_1.plain_int_0))) as expr_121 from alice.tbl_1 as tbl_1\"\n      },\n      {\n        \"sql\": \"SELECT geodist(plain_int_0, plain_float_0, plain_int_0, plain_float_0) from alice.tbl_1 as tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select 6371*acos(sin(radians(tbl_1.plain_float_0))*sin(radians(tbl_1.plain_float_0))+cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_int_0)-radians(tbl_1.plain_int_0))) as expr_121 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_pg\": \"select 6371*acos(sin(radians(tbl_1.plain_float_0))*sin(radians(tbl_1.plain_float_0))+cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_int_0)-radians(tbl_1.plain_int_0))) as expr_121 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_csv\": \"select 6371*acos(sin(radians(tbl_1.plain_float_0))*sin(radians(tbl_1.plain_float_0))+cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_int_0)-radians(tbl_1.plain_int_0))) as expr_121 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql\": \"select 6371*acos(sin(radians(tbl_1.plain_float_0))*sin(radians(tbl_1.plain_float_0))+cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_float_0))*cos(radians(tbl_1.plain_int_0)-radians(tbl_1.plain_int_0))) as expr_121 from alice.tbl_1 as tbl_1\"\n      },\n      {\n        \"sql\": \"select * from alice.tbl_1;\",\n        \"skip_projection\": true,\n        \"rewritten_sql_odps\": \"select tbl_1.aggregate_datetime_0,tbl_1.aggregate_datetime_1,tbl_1.aggregate_datetime_2,tbl_1.aggregate_float_0,tbl_1.aggregate_float_1,tbl_1.aggregate_float_2,tbl_1.aggregate_int_0,tbl_1.aggregate_int_1,tbl_1.aggregate_int_2,tbl_1.aggregate_string_0,tbl_1.aggregate_string_1,tbl_1.aggregate_string_2,tbl_1.aggregate_timestamp_0,tbl_1.aggregate_timestamp_1,tbl_1.aggregate_timestamp_2,tbl_1.compare_datetime_0,tbl_1.compare_datetime_1,tbl_1.compare_datetime_2,tbl_1.compare_float_0,tbl_1.compare_float_1,tbl_1.compare_float_2,tbl_1.compare_int_0,tbl_1.compare_int_1,tbl_1.compare_int_2,tbl_1.compare_string_0,tbl_1.compare_string_1,tbl_1.compare_string_2,tbl_1.compare_timestamp_0,tbl_1.compare_timestamp_1,tbl_1.compare_timestamp_2,tbl_1.encrypt_datetime_0,tbl_1.encrypt_datetime_1,tbl_1.encrypt_datetime_2,tbl_1.encrypt_float_0,tbl_1.encrypt_float_1,tbl_1.encrypt_float_2,tbl_1.encrypt_int_0,tbl_1.encrypt_int_1,tbl_1.encrypt_int_2,tbl_1.encrypt_string_0,tbl_1.encrypt_string_1,tbl_1.encrypt_string_2,tbl_1.encrypt_timestamp_0,tbl_1.encrypt_timestamp_1,tbl_1.encrypt_timestamp_2,tbl_1.groupby_datetime_0,tbl_1.groupby_datetime_1,tbl_1.groupby_datetime_2,tbl_1.groupby_float_0,tbl_1.groupby_float_1,tbl_1.groupby_float_2,tbl_1.groupby_int_0,tbl_1.groupby_int_1,tbl_1.groupby_int_2,tbl_1.groupby_string_0,tbl_1.groupby_string_1,tbl_1.groupby_string_2,tbl_1.groupby_timestamp_0,tbl_1.groupby_timestamp_1,tbl_1.groupby_timestamp_2,tbl_1.join_datetime_0,tbl_1.join_datetime_1,tbl_1.join_datetime_2,tbl_1.join_float_0,tbl_1.join_float_1,tbl_1.join_float_2,tbl_1.join_int_0,tbl_1.join_int_1,tbl_1.join_int_2,tbl_1.join_string_0,tbl_1.join_string_1,tbl_1.join_string_2,tbl_1.join_timestamp_0,tbl_1.join_timestamp_1,tbl_1.join_timestamp_2,tbl_1.joinpayload_datetime_0,tbl_1.joinpayload_datetime_1,tbl_1.joinpayload_datetime_2,tbl_1.joinpayload_float_0,tbl_1.joinpayload_float_1,tbl_1.joinpayload_float_2,tbl_1.joinpayload_int_0,tbl_1.joinpayload_int_1,tbl_1.joinpayload_int_2,tbl_1.joinpayload_string_0,tbl_1.joinpayload_string_1,tbl_1.joinpayload_string_2,tbl_1.joinpayload_timestamp_0,tbl_1.joinpayload_timestamp_1,tbl_1.joinpayload_timestamp_2,tbl_1.plain_datetime_0,tbl_1.plain_datetime_1,tbl_1.plain_datetime_2,tbl_1.plain_float_0,tbl_1.plain_float_1,tbl_1.plain_float_2,tbl_1.plain_int_0,tbl_1.plain_int_1,tbl_1.plain_int_2,tbl_1.plain_string_0,tbl_1.plain_string_1,tbl_1.plain_string_2,tbl_1.plain_timestamp_0,tbl_1.plain_timestamp_1,tbl_1.plain_timestamp_2,tbl_1.rank_datetime_0,tbl_1.rank_datetime_1,tbl_1.rank_datetime_2,tbl_1.rank_float_0,tbl_1.rank_float_1,tbl_1.rank_float_2,tbl_1.rank_int_0,tbl_1.rank_int_1,tbl_1.rank_int_2,tbl_1.rank_string_0,tbl_1.rank_string_1,tbl_1.rank_string_2,tbl_1.rank_timestamp_0,tbl_1.rank_timestamp_1,tbl_1.rank_timestamp_2 from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.aggregate_datetime_0,tbl_1.aggregate_datetime_1,tbl_1.aggregate_datetime_2,tbl_1.aggregate_float_0,tbl_1.aggregate_float_1,tbl_1.aggregate_float_2,tbl_1.aggregate_int_0,tbl_1.aggregate_int_1,tbl_1.aggregate_int_2,tbl_1.aggregate_string_0,tbl_1.aggregate_string_1,tbl_1.aggregate_string_2,tbl_1.aggregate_timestamp_0,tbl_1.aggregate_timestamp_1,tbl_1.aggregate_timestamp_2,tbl_1.compare_datetime_0,tbl_1.compare_datetime_1,tbl_1.compare_datetime_2,tbl_1.compare_float_0,tbl_1.compare_float_1,tbl_1.compare_float_2,tbl_1.compare_int_0,tbl_1.compare_int_1,tbl_1.compare_int_2,tbl_1.compare_string_0,tbl_1.compare_string_1,tbl_1.compare_string_2,tbl_1.compare_timestamp_0,tbl_1.compare_timestamp_1,tbl_1.compare_timestamp_2,tbl_1.encrypt_datetime_0,tbl_1.encrypt_datetime_1,tbl_1.encrypt_datetime_2,tbl_1.encrypt_float_0,tbl_1.encrypt_float_1,tbl_1.encrypt_float_2,tbl_1.encrypt_int_0,tbl_1.encrypt_int_1,tbl_1.encrypt_int_2,tbl_1.encrypt_string_0,tbl_1.encrypt_string_1,tbl_1.encrypt_string_2,tbl_1.encrypt_timestamp_0,tbl_1.encrypt_timestamp_1,tbl_1.encrypt_timestamp_2,tbl_1.groupby_datetime_0,tbl_1.groupby_datetime_1,tbl_1.groupby_datetime_2,tbl_1.groupby_float_0,tbl_1.groupby_float_1,tbl_1.groupby_float_2,tbl_1.groupby_int_0,tbl_1.groupby_int_1,tbl_1.groupby_int_2,tbl_1.groupby_string_0,tbl_1.groupby_string_1,tbl_1.groupby_string_2,tbl_1.groupby_timestamp_0,tbl_1.groupby_timestamp_1,tbl_1.groupby_timestamp_2,tbl_1.join_datetime_0,tbl_1.join_datetime_1,tbl_1.join_datetime_2,tbl_1.join_float_0,tbl_1.join_float_1,tbl_1.join_float_2,tbl_1.join_int_0,tbl_1.join_int_1,tbl_1.join_int_2,tbl_1.join_string_0,tbl_1.join_string_1,tbl_1.join_string_2,tbl_1.join_timestamp_0,tbl_1.join_timestamp_1,tbl_1.join_timestamp_2,tbl_1.joinpayload_datetime_0,tbl_1.joinpayload_datetime_1,tbl_1.joinpayload_datetime_2,tbl_1.joinpayload_float_0,tbl_1.joinpayload_float_1,tbl_1.joinpayload_float_2,tbl_1.joinpayload_int_0,tbl_1.joinpayload_int_1,tbl_1.joinpayload_int_2,tbl_1.joinpayload_string_0,tbl_1.joinpayload_string_1,tbl_1.joinpayload_string_2,tbl_1.joinpayload_timestamp_0,tbl_1.joinpayload_timestamp_1,tbl_1.joinpayload_timestamp_2,tbl_1.plain_datetime_0,tbl_1.plain_datetime_1,tbl_1.plain_datetime_2,tbl_1.plain_float_0,tbl_1.plain_float_1,tbl_1.plain_float_2,tbl_1.plain_int_0,tbl_1.plain_int_1,tbl_1.plain_int_2,tbl_1.plain_string_0,tbl_1.plain_string_1,tbl_1.plain_string_2,tbl_1.plain_timestamp_0,tbl_1.plain_timestamp_1,tbl_1.plain_timestamp_2,tbl_1.rank_datetime_0,tbl_1.rank_datetime_1,tbl_1.rank_datetime_2,tbl_1.rank_float_0,tbl_1.rank_float_1,tbl_1.rank_float_2,tbl_1.rank_int_0,tbl_1.rank_int_1,tbl_1.rank_int_2,tbl_1.rank_string_0,tbl_1.rank_string_1,tbl_1.rank_string_2,tbl_1.rank_timestamp_0,tbl_1.rank_timestamp_1,tbl_1.rank_timestamp_2 from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.aggregate_datetime_0,tbl_1.aggregate_datetime_1,tbl_1.aggregate_datetime_2,tbl_1.aggregate_float_0,tbl_1.aggregate_float_1,tbl_1.aggregate_float_2,tbl_1.aggregate_int_0,tbl_1.aggregate_int_1,tbl_1.aggregate_int_2,tbl_1.aggregate_string_0,tbl_1.aggregate_string_1,tbl_1.aggregate_string_2,tbl_1.aggregate_timestamp_0,tbl_1.aggregate_timestamp_1,tbl_1.aggregate_timestamp_2,tbl_1.compare_datetime_0,tbl_1.compare_datetime_1,tbl_1.compare_datetime_2,tbl_1.compare_float_0,tbl_1.compare_float_1,tbl_1.compare_float_2,tbl_1.compare_int_0,tbl_1.compare_int_1,tbl_1.compare_int_2,tbl_1.compare_string_0,tbl_1.compare_string_1,tbl_1.compare_string_2,tbl_1.compare_timestamp_0,tbl_1.compare_timestamp_1,tbl_1.compare_timestamp_2,tbl_1.encrypt_datetime_0,tbl_1.encrypt_datetime_1,tbl_1.encrypt_datetime_2,tbl_1.encrypt_float_0,tbl_1.encrypt_float_1,tbl_1.encrypt_float_2,tbl_1.encrypt_int_0,tbl_1.encrypt_int_1,tbl_1.encrypt_int_2,tbl_1.encrypt_string_0,tbl_1.encrypt_string_1,tbl_1.encrypt_string_2,tbl_1.encrypt_timestamp_0,tbl_1.encrypt_timestamp_1,tbl_1.encrypt_timestamp_2,tbl_1.groupby_datetime_0,tbl_1.groupby_datetime_1,tbl_1.groupby_datetime_2,tbl_1.groupby_float_0,tbl_1.groupby_float_1,tbl_1.groupby_float_2,tbl_1.groupby_int_0,tbl_1.groupby_int_1,tbl_1.groupby_int_2,tbl_1.groupby_string_0,tbl_1.groupby_string_1,tbl_1.groupby_string_2,tbl_1.groupby_timestamp_0,tbl_1.groupby_timestamp_1,tbl_1.groupby_timestamp_2,tbl_1.join_datetime_0,tbl_1.join_datetime_1,tbl_1.join_datetime_2,tbl_1.join_float_0,tbl_1.join_float_1,tbl_1.join_float_2,tbl_1.join_int_0,tbl_1.join_int_1,tbl_1.join_int_2,tbl_1.join_string_0,tbl_1.join_string_1,tbl_1.join_string_2,tbl_1.join_timestamp_0,tbl_1.join_timestamp_1,tbl_1.join_timestamp_2,tbl_1.joinpayload_datetime_0,tbl_1.joinpayload_datetime_1,tbl_1.joinpayload_datetime_2,tbl_1.joinpayload_float_0,tbl_1.joinpayload_float_1,tbl_1.joinpayload_float_2,tbl_1.joinpayload_int_0,tbl_1.joinpayload_int_1,tbl_1.joinpayload_int_2,tbl_1.joinpayload_string_0,tbl_1.joinpayload_string_1,tbl_1.joinpayload_string_2,tbl_1.joinpayload_timestamp_0,tbl_1.joinpayload_timestamp_1,tbl_1.joinpayload_timestamp_2,tbl_1.plain_datetime_0,tbl_1.plain_datetime_1,tbl_1.plain_datetime_2,tbl_1.plain_float_0,tbl_1.plain_float_1,tbl_1.plain_float_2,tbl_1.plain_int_0,tbl_1.plain_int_1,tbl_1.plain_int_2,tbl_1.plain_string_0,tbl_1.plain_string_1,tbl_1.plain_string_2,tbl_1.plain_timestamp_0,tbl_1.plain_timestamp_1,tbl_1.plain_timestamp_2,tbl_1.rank_datetime_0,tbl_1.rank_datetime_1,tbl_1.rank_datetime_2,tbl_1.rank_float_0,tbl_1.rank_float_1,tbl_1.rank_float_2,tbl_1.rank_int_0,tbl_1.rank_int_1,tbl_1.rank_int_2,tbl_1.rank_string_0,tbl_1.rank_string_1,tbl_1.rank_string_2,tbl_1.rank_timestamp_0,tbl_1.rank_timestamp_1,tbl_1.rank_timestamp_2 from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.aggregate_datetime_0,tbl_1.aggregate_datetime_1,tbl_1.aggregate_datetime_2,tbl_1.aggregate_float_0,tbl_1.aggregate_float_1,tbl_1.aggregate_float_2,tbl_1.aggregate_int_0,tbl_1.aggregate_int_1,tbl_1.aggregate_int_2,tbl_1.aggregate_string_0,tbl_1.aggregate_string_1,tbl_1.aggregate_string_2,tbl_1.aggregate_timestamp_0,tbl_1.aggregate_timestamp_1,tbl_1.aggregate_timestamp_2,tbl_1.compare_datetime_0,tbl_1.compare_datetime_1,tbl_1.compare_datetime_2,tbl_1.compare_float_0,tbl_1.compare_float_1,tbl_1.compare_float_2,tbl_1.compare_int_0,tbl_1.compare_int_1,tbl_1.compare_int_2,tbl_1.compare_string_0,tbl_1.compare_string_1,tbl_1.compare_string_2,tbl_1.compare_timestamp_0,tbl_1.compare_timestamp_1,tbl_1.compare_timestamp_2,tbl_1.encrypt_datetime_0,tbl_1.encrypt_datetime_1,tbl_1.encrypt_datetime_2,tbl_1.encrypt_float_0,tbl_1.encrypt_float_1,tbl_1.encrypt_float_2,tbl_1.encrypt_int_0,tbl_1.encrypt_int_1,tbl_1.encrypt_int_2,tbl_1.encrypt_string_0,tbl_1.encrypt_string_1,tbl_1.encrypt_string_2,tbl_1.encrypt_timestamp_0,tbl_1.encrypt_timestamp_1,tbl_1.encrypt_timestamp_2,tbl_1.groupby_datetime_0,tbl_1.groupby_datetime_1,tbl_1.groupby_datetime_2,tbl_1.groupby_float_0,tbl_1.groupby_float_1,tbl_1.groupby_float_2,tbl_1.groupby_int_0,tbl_1.groupby_int_1,tbl_1.groupby_int_2,tbl_1.groupby_string_0,tbl_1.groupby_string_1,tbl_1.groupby_string_2,tbl_1.groupby_timestamp_0,tbl_1.groupby_timestamp_1,tbl_1.groupby_timestamp_2,tbl_1.join_datetime_0,tbl_1.join_datetime_1,tbl_1.join_datetime_2,tbl_1.join_float_0,tbl_1.join_float_1,tbl_1.join_float_2,tbl_1.join_int_0,tbl_1.join_int_1,tbl_1.join_int_2,tbl_1.join_string_0,tbl_1.join_string_1,tbl_1.join_string_2,tbl_1.join_timestamp_0,tbl_1.join_timestamp_1,tbl_1.join_timestamp_2,tbl_1.joinpayload_datetime_0,tbl_1.joinpayload_datetime_1,tbl_1.joinpayload_datetime_2,tbl_1.joinpayload_float_0,tbl_1.joinpayload_float_1,tbl_1.joinpayload_float_2,tbl_1.joinpayload_int_0,tbl_1.joinpayload_int_1,tbl_1.joinpayload_int_2,tbl_1.joinpayload_string_0,tbl_1.joinpayload_string_1,tbl_1.joinpayload_string_2,tbl_1.joinpayload_timestamp_0,tbl_1.joinpayload_timestamp_1,tbl_1.joinpayload_timestamp_2,tbl_1.plain_datetime_0,tbl_1.plain_datetime_1,tbl_1.plain_datetime_2,tbl_1.plain_float_0,tbl_1.plain_float_1,tbl_1.plain_float_2,tbl_1.plain_int_0,tbl_1.plain_int_1,tbl_1.plain_int_2,tbl_1.plain_string_0,tbl_1.plain_string_1,tbl_1.plain_string_2,tbl_1.plain_timestamp_0,tbl_1.plain_timestamp_1,tbl_1.plain_timestamp_2,tbl_1.rank_datetime_0,tbl_1.rank_datetime_1,tbl_1.rank_datetime_2,tbl_1.rank_float_0,tbl_1.rank_float_1,tbl_1.rank_float_2,tbl_1.rank_int_0,tbl_1.rank_int_1,tbl_1.rank_int_2,tbl_1.rank_string_0,tbl_1.rank_string_1,tbl_1.rank_string_2,tbl_1.rank_timestamp_0,tbl_1.rank_timestamp_1,tbl_1.rank_timestamp_2 from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select * from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.aggregate_datetime_0,tbl_1.aggregate_datetime_1,tbl_1.aggregate_datetime_2,tbl_1.aggregate_float_0,tbl_1.aggregate_float_1,tbl_1.aggregate_float_2,tbl_1.aggregate_int_0,tbl_1.aggregate_int_1,tbl_1.aggregate_int_2,tbl_1.aggregate_string_0,tbl_1.aggregate_string_1,tbl_1.aggregate_string_2,tbl_1.aggregate_timestamp_0,tbl_1.aggregate_timestamp_1,tbl_1.aggregate_timestamp_2,tbl_1.compare_datetime_0,tbl_1.compare_datetime_1,tbl_1.compare_datetime_2,tbl_1.compare_float_0,tbl_1.compare_float_1,tbl_1.compare_float_2,tbl_1.compare_int_0,tbl_1.compare_int_1,tbl_1.compare_int_2,tbl_1.compare_string_0,tbl_1.compare_string_1,tbl_1.compare_string_2,tbl_1.compare_timestamp_0,tbl_1.compare_timestamp_1,tbl_1.compare_timestamp_2,tbl_1.encrypt_datetime_0,tbl_1.encrypt_datetime_1,tbl_1.encrypt_datetime_2,tbl_1.encrypt_float_0,tbl_1.encrypt_float_1,tbl_1.encrypt_float_2,tbl_1.encrypt_int_0,tbl_1.encrypt_int_1,tbl_1.encrypt_int_2,tbl_1.encrypt_string_0,tbl_1.encrypt_string_1,tbl_1.encrypt_string_2,tbl_1.encrypt_timestamp_0,tbl_1.encrypt_timestamp_1,tbl_1.encrypt_timestamp_2,tbl_1.groupby_datetime_0,tbl_1.groupby_datetime_1,tbl_1.groupby_datetime_2,tbl_1.groupby_float_0,tbl_1.groupby_float_1,tbl_1.groupby_float_2,tbl_1.groupby_int_0,tbl_1.groupby_int_1,tbl_1.groupby_int_2,tbl_1.groupby_string_0,tbl_1.groupby_string_1,tbl_1.groupby_string_2,tbl_1.groupby_timestamp_0,tbl_1.groupby_timestamp_1,tbl_1.groupby_timestamp_2,tbl_1.join_datetime_0,tbl_1.join_datetime_1,tbl_1.join_datetime_2,tbl_1.join_float_0,tbl_1.join_float_1,tbl_1.join_float_2,tbl_1.join_int_0,tbl_1.join_int_1,tbl_1.join_int_2,tbl_1.join_string_0,tbl_1.join_string_1,tbl_1.join_string_2,tbl_1.join_timestamp_0,tbl_1.join_timestamp_1,tbl_1.join_timestamp_2,tbl_1.joinpayload_datetime_0,tbl_1.joinpayload_datetime_1,tbl_1.joinpayload_datetime_2,tbl_1.joinpayload_float_0,tbl_1.joinpayload_float_1,tbl_1.joinpayload_float_2,tbl_1.joinpayload_int_0,tbl_1.joinpayload_int_1,tbl_1.joinpayload_int_2,tbl_1.joinpayload_string_0,tbl_1.joinpayload_string_1,tbl_1.joinpayload_string_2,tbl_1.joinpayload_timestamp_0,tbl_1.joinpayload_timestamp_1,tbl_1.joinpayload_timestamp_2,tbl_1.plain_datetime_0,tbl_1.plain_datetime_1,tbl_1.plain_datetime_2,tbl_1.plain_float_0,tbl_1.plain_float_1,tbl_1.plain_float_2,tbl_1.plain_int_0,tbl_1.plain_int_1,tbl_1.plain_int_2,tbl_1.plain_string_0,tbl_1.plain_string_1,tbl_1.plain_string_2,tbl_1.plain_timestamp_0,tbl_1.plain_timestamp_1,tbl_1.plain_timestamp_2,tbl_1.rank_datetime_0,tbl_1.rank_datetime_1,tbl_1.rank_datetime_2,tbl_1.rank_float_0,tbl_1.rank_float_1,tbl_1.rank_float_2,tbl_1.rank_int_0,tbl_1.rank_int_1,tbl_1.rank_int_2,tbl_1.rank_string_0,tbl_1.rank_string_1,tbl_1.rank_string_2,tbl_1.rank_timestamp_0,tbl_1.rank_timestamp_1,tbl_1.rank_timestamp_2 from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.aggregate_datetime_0,tbl_1.aggregate_datetime_1,tbl_1.aggregate_datetime_2,tbl_1.aggregate_float_0,tbl_1.aggregate_float_1,tbl_1.aggregate_float_2,tbl_1.aggregate_int_0,tbl_1.aggregate_int_1,tbl_1.aggregate_int_2,tbl_1.aggregate_string_0,tbl_1.aggregate_string_1,tbl_1.aggregate_string_2,tbl_1.aggregate_timestamp_0,tbl_1.aggregate_timestamp_1,tbl_1.aggregate_timestamp_2,tbl_1.compare_datetime_0,tbl_1.compare_datetime_1,tbl_1.compare_datetime_2,tbl_1.compare_float_0,tbl_1.compare_float_1,tbl_1.compare_float_2,tbl_1.compare_int_0,tbl_1.compare_int_1,tbl_1.compare_int_2,tbl_1.compare_string_0,tbl_1.compare_string_1,tbl_1.compare_string_2,tbl_1.compare_timestamp_0,tbl_1.compare_timestamp_1,tbl_1.compare_timestamp_2,tbl_1.encrypt_datetime_0,tbl_1.encrypt_datetime_1,tbl_1.encrypt_datetime_2,tbl_1.encrypt_float_0,tbl_1.encrypt_float_1,tbl_1.encrypt_float_2,tbl_1.encrypt_int_0,tbl_1.encrypt_int_1,tbl_1.encrypt_int_2,tbl_1.encrypt_string_0,tbl_1.encrypt_string_1,tbl_1.encrypt_string_2,tbl_1.encrypt_timestamp_0,tbl_1.encrypt_timestamp_1,tbl_1.encrypt_timestamp_2,tbl_1.groupby_datetime_0,tbl_1.groupby_datetime_1,tbl_1.groupby_datetime_2,tbl_1.groupby_float_0,tbl_1.groupby_float_1,tbl_1.groupby_float_2,tbl_1.groupby_int_0,tbl_1.groupby_int_1,tbl_1.groupby_int_2,tbl_1.groupby_string_0,tbl_1.groupby_string_1,tbl_1.groupby_string_2,tbl_1.groupby_timestamp_0,tbl_1.groupby_timestamp_1,tbl_1.groupby_timestamp_2,tbl_1.join_datetime_0,tbl_1.join_datetime_1,tbl_1.join_datetime_2,tbl_1.join_float_0,tbl_1.join_float_1,tbl_1.join_float_2,tbl_1.join_int_0,tbl_1.join_int_1,tbl_1.join_int_2,tbl_1.join_string_0,tbl_1.join_string_1,tbl_1.join_string_2,tbl_1.join_timestamp_0,tbl_1.join_timestamp_1,tbl_1.join_timestamp_2,tbl_1.joinpayload_datetime_0,tbl_1.joinpayload_datetime_1,tbl_1.joinpayload_datetime_2,tbl_1.joinpayload_float_0,tbl_1.joinpayload_float_1,tbl_1.joinpayload_float_2,tbl_1.joinpayload_int_0,tbl_1.joinpayload_int_1,tbl_1.joinpayload_int_2,tbl_1.joinpayload_string_0,tbl_1.joinpayload_string_1,tbl_1.joinpayload_string_2,tbl_1.joinpayload_timestamp_0,tbl_1.joinpayload_timestamp_1,tbl_1.joinpayload_timestamp_2,tbl_1.plain_datetime_0,tbl_1.plain_datetime_1,tbl_1.plain_datetime_2,tbl_1.plain_float_0,tbl_1.plain_float_1,tbl_1.plain_float_2,tbl_1.plain_int_0,tbl_1.plain_int_1,tbl_1.plain_int_2,tbl_1.plain_string_0,tbl_1.plain_string_1,tbl_1.plain_string_2,tbl_1.plain_timestamp_0,tbl_1.plain_timestamp_1,tbl_1.plain_timestamp_2,tbl_1.rank_datetime_0,tbl_1.rank_datetime_1,tbl_1.rank_datetime_2,tbl_1.rank_float_0,tbl_1.rank_float_1,tbl_1.rank_float_2,tbl_1.rank_int_0,tbl_1.rank_int_1,tbl_1.rank_int_2,tbl_1.rank_string_0,tbl_1.rank_string_1,tbl_1.rank_string_2,tbl_1.rank_timestamp_0,tbl_1.rank_timestamp_1,tbl_1.rank_timestamp_2 from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.aggregate_datetime_0,tbl_1.aggregate_datetime_1,tbl_1.aggregate_datetime_2,tbl_1.aggregate_float_0,tbl_1.aggregate_float_1,tbl_1.aggregate_float_2,tbl_1.aggregate_int_0,tbl_1.aggregate_int_1,tbl_1.aggregate_int_2,tbl_1.aggregate_string_0,tbl_1.aggregate_string_1,tbl_1.aggregate_string_2,tbl_1.aggregate_timestamp_0,tbl_1.aggregate_timestamp_1,tbl_1.aggregate_timestamp_2,tbl_1.compare_datetime_0,tbl_1.compare_datetime_1,tbl_1.compare_datetime_2,tbl_1.compare_float_0,tbl_1.compare_float_1,tbl_1.compare_float_2,tbl_1.compare_int_0,tbl_1.compare_int_1,tbl_1.compare_int_2,tbl_1.compare_string_0,tbl_1.compare_string_1,tbl_1.compare_string_2,tbl_1.compare_timestamp_0,tbl_1.compare_timestamp_1,tbl_1.compare_timestamp_2,tbl_1.encrypt_datetime_0,tbl_1.encrypt_datetime_1,tbl_1.encrypt_datetime_2,tbl_1.encrypt_float_0,tbl_1.encrypt_float_1,tbl_1.encrypt_float_2,tbl_1.encrypt_int_0,tbl_1.encrypt_int_1,tbl_1.encrypt_int_2,tbl_1.encrypt_string_0,tbl_1.encrypt_string_1,tbl_1.encrypt_string_2,tbl_1.encrypt_timestamp_0,tbl_1.encrypt_timestamp_1,tbl_1.encrypt_timestamp_2,tbl_1.groupby_datetime_0,tbl_1.groupby_datetime_1,tbl_1.groupby_datetime_2,tbl_1.groupby_float_0,tbl_1.groupby_float_1,tbl_1.groupby_float_2,tbl_1.groupby_int_0,tbl_1.groupby_int_1,tbl_1.groupby_int_2,tbl_1.groupby_string_0,tbl_1.groupby_string_1,tbl_1.groupby_string_2,tbl_1.groupby_timestamp_0,tbl_1.groupby_timestamp_1,tbl_1.groupby_timestamp_2,tbl_1.join_datetime_0,tbl_1.join_datetime_1,tbl_1.join_datetime_2,tbl_1.join_float_0,tbl_1.join_float_1,tbl_1.join_float_2,tbl_1.join_int_0,tbl_1.join_int_1,tbl_1.join_int_2,tbl_1.join_string_0,tbl_1.join_string_1,tbl_1.join_string_2,tbl_1.join_timestamp_0,tbl_1.join_timestamp_1,tbl_1.join_timestamp_2,tbl_1.joinpayload_datetime_0,tbl_1.joinpayload_datetime_1,tbl_1.joinpayload_datetime_2,tbl_1.joinpayload_float_0,tbl_1.joinpayload_float_1,tbl_1.joinpayload_float_2,tbl_1.joinpayload_int_0,tbl_1.joinpayload_int_1,tbl_1.joinpayload_int_2,tbl_1.joinpayload_string_0,tbl_1.joinpayload_string_1,tbl_1.joinpayload_string_2,tbl_1.joinpayload_timestamp_0,tbl_1.joinpayload_timestamp_1,tbl_1.joinpayload_timestamp_2,tbl_1.plain_datetime_0,tbl_1.plain_datetime_1,tbl_1.plain_datetime_2,tbl_1.plain_float_0,tbl_1.plain_float_1,tbl_1.plain_float_2,tbl_1.plain_int_0,tbl_1.plain_int_1,tbl_1.plain_int_2,tbl_1.plain_string_0,tbl_1.plain_string_1,tbl_1.plain_string_2,tbl_1.plain_timestamp_0,tbl_1.plain_timestamp_1,tbl_1.plain_timestamp_2,tbl_1.rank_datetime_0,tbl_1.rank_datetime_1,tbl_1.rank_datetime_2,tbl_1.rank_float_0,tbl_1.rank_float_1,tbl_1.rank_float_2,tbl_1.rank_int_0,tbl_1.rank_int_1,tbl_1.rank_int_2,tbl_1.rank_string_0,tbl_1.rank_string_1,tbl_1.rank_string_2,tbl_1.rank_timestamp_0,tbl_1.rank_timestamp_1,tbl_1.rank_timestamp_2 from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.aggregate_datetime_0,tbl_1.aggregate_datetime_1,tbl_1.aggregate_datetime_2,tbl_1.aggregate_float_0,tbl_1.aggregate_float_1,tbl_1.aggregate_float_2,tbl_1.aggregate_int_0,tbl_1.aggregate_int_1,tbl_1.aggregate_int_2,tbl_1.aggregate_string_0,tbl_1.aggregate_string_1,tbl_1.aggregate_string_2,tbl_1.aggregate_timestamp_0,tbl_1.aggregate_timestamp_1,tbl_1.aggregate_timestamp_2,tbl_1.compare_datetime_0,tbl_1.compare_datetime_1,tbl_1.compare_datetime_2,tbl_1.compare_float_0,tbl_1.compare_float_1,tbl_1.compare_float_2,tbl_1.compare_int_0,tbl_1.compare_int_1,tbl_1.compare_int_2,tbl_1.compare_string_0,tbl_1.compare_string_1,tbl_1.compare_string_2,tbl_1.compare_timestamp_0,tbl_1.compare_timestamp_1,tbl_1.compare_timestamp_2,tbl_1.encrypt_datetime_0,tbl_1.encrypt_datetime_1,tbl_1.encrypt_datetime_2,tbl_1.encrypt_float_0,tbl_1.encrypt_float_1,tbl_1.encrypt_float_2,tbl_1.encrypt_int_0,tbl_1.encrypt_int_1,tbl_1.encrypt_int_2,tbl_1.encrypt_string_0,tbl_1.encrypt_string_1,tbl_1.encrypt_string_2,tbl_1.encrypt_timestamp_0,tbl_1.encrypt_timestamp_1,tbl_1.encrypt_timestamp_2,tbl_1.groupby_datetime_0,tbl_1.groupby_datetime_1,tbl_1.groupby_datetime_2,tbl_1.groupby_float_0,tbl_1.groupby_float_1,tbl_1.groupby_float_2,tbl_1.groupby_int_0,tbl_1.groupby_int_1,tbl_1.groupby_int_2,tbl_1.groupby_string_0,tbl_1.groupby_string_1,tbl_1.groupby_string_2,tbl_1.groupby_timestamp_0,tbl_1.groupby_timestamp_1,tbl_1.groupby_timestamp_2,tbl_1.join_datetime_0,tbl_1.join_datetime_1,tbl_1.join_datetime_2,tbl_1.join_float_0,tbl_1.join_float_1,tbl_1.join_float_2,tbl_1.join_int_0,tbl_1.join_int_1,tbl_1.join_int_2,tbl_1.join_string_0,tbl_1.join_string_1,tbl_1.join_string_2,tbl_1.join_timestamp_0,tbl_1.join_timestamp_1,tbl_1.join_timestamp_2,tbl_1.joinpayload_datetime_0,tbl_1.joinpayload_datetime_1,tbl_1.joinpayload_datetime_2,tbl_1.joinpayload_float_0,tbl_1.joinpayload_float_1,tbl_1.joinpayload_float_2,tbl_1.joinpayload_int_0,tbl_1.joinpayload_int_1,tbl_1.joinpayload_int_2,tbl_1.joinpayload_string_0,tbl_1.joinpayload_string_1,tbl_1.joinpayload_string_2,tbl_1.joinpayload_timestamp_0,tbl_1.joinpayload_timestamp_1,tbl_1.joinpayload_timestamp_2,tbl_1.plain_datetime_0,tbl_1.plain_datetime_1,tbl_1.plain_datetime_2,tbl_1.plain_float_0,tbl_1.plain_float_1,tbl_1.plain_float_2,tbl_1.plain_int_0,tbl_1.plain_int_1,tbl_1.plain_int_2,tbl_1.plain_string_0,tbl_1.plain_string_1,tbl_1.plain_string_2,tbl_1.plain_timestamp_0,tbl_1.plain_timestamp_1,tbl_1.plain_timestamp_2,tbl_1.rank_datetime_0,tbl_1.rank_datetime_1,tbl_1.rank_datetime_2,tbl_1.rank_float_0,tbl_1.rank_float_1,tbl_1.rank_float_2,tbl_1.rank_int_0,tbl_1.rank_int_1,tbl_1.rank_int_2,tbl_1.rank_string_0,tbl_1.rank_string_1,tbl_1.rank_string_2,tbl_1.rank_timestamp_0,tbl_1.rank_timestamp_1,tbl_1.rank_timestamp_2 from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select count(*) from alice.tbl_1 as t1 join alice.tbl_2 as t2 join bob.tbl_1 as t3 join bob.tbl_2 as t4 where t1.plain_int_0 = t2.plain_int_0 and t2.plain_int_0 = t3.plain_int_0 and t3.plain_int_0 = t4.plain_int_0\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select count(1) as expr_481 from (select t2.plain_int_0 from (alice.tbl_1 as t1 join alice.tbl_2 as t2 on t1.plain_int_0=t2.plain_int_0)) as t1 join (select t3.plain_int_0 from (bob.tbl_1 as t3 join bob.tbl_2 as t4 on t3.plain_int_0=t4.plain_int_0)) as t4 on t1.plain_int_0=t4.plain_int_0\",\n        \"rewritten_sql_pg\": \"select count(1) as expr_481 from (select t2.plain_int_0 from (alice.tbl_1 as t1 join alice.tbl_2 as t2 on t1.plain_int_0=t2.plain_int_0)) as t1 join (select t3.plain_int_0 from (bob.tbl_1 as t3 join bob.tbl_2 as t4 on t3.plain_int_0=t4.plain_int_0)) as t4 on t1.plain_int_0=t4.plain_int_0\",\n        \"rewritten_sql_csv\": \"select count(1) as expr_481 from (select t2.plain_int_0 from (alice.tbl_1 as t1 join alice.tbl_2 as t2 on t1.plain_int_0=t2.plain_int_0)) as t1 join (select t3.plain_int_0 from (bob.tbl_1 as t3 join bob.tbl_2 as t4 on t3.plain_int_0=t4.plain_int_0)) as t4 on t1.plain_int_0=t4.plain_int_0\",\n        \"rewritten_sql\": \"select count(1) as expr_481 from (select t2.plain_int_0 from (alice.tbl_1 as t1 join alice.tbl_2 as t2 on t1.plain_int_0=t2.plain_int_0)) as t1 join (select t3.plain_int_0 from (bob.tbl_1 as t3 join bob.tbl_2 as t4 on t3.plain_int_0=t4.plain_int_0)) as t4 on t1.plain_int_0=t4.plain_int_0\"\n      },\n      {\n        \"sql\": \"select plain_float_0 from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0 from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_float_0 from alice.tbl_1 as tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0 from alice.tbl_1 as tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_float_0, Plain_float_1 from alice.tbl_1 as tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0,tbl_1.plain_float_1 as Plain_float_1 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0,tbl_1.plain_float_1 as Plain_float_1 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0,tbl_1.plain_float_1 as Plain_float_1 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0,tbl_1.plain_float_1 as Plain_float_1 from alice.tbl_1 as tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_float_0, Plain_float_1 + plain_float_0 from alice.tbl_1 as tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0,tbl_1.plain_float_1+tbl_1.plain_float_0 as expr_121 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0,tbl_1.plain_float_1+tbl_1.plain_float_0 as expr_121 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0,tbl_1.plain_float_1+tbl_1.plain_float_0 as expr_121 from alice.tbl_1 as tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0,tbl_1.plain_float_1+tbl_1.plain_float_0 as expr_121 from alice.tbl_1 as tbl_1\"\n      },\n      {\n        \"sql\": \"select count(*) from (select plain_float_0, Plain_float_1 from alice.tbl_1) as tbl_1 join alice.tbl_2 on tbl_1.Plain_float_1 = tbl_2.plain_float_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select count(1) as expr_241 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_float_1=tbl_2.plain_float_1\",\n        \"rewritten_sql_pg\": \"select count(1) as expr_241 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_float_1=tbl_2.plain_float_1\",\n        \"rewritten_sql_csv\": \"select count(1) as expr_241 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_float_1=tbl_2.plain_float_1\",\n        \"rewritten_sql\": \"select count(1) as expr_241 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_float_1=tbl_2.plain_float_1\"\n      },\n      {\n        \"sql\": \"select plain_float_0, plain_float_0 from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0,tbl_1.plain_float_0 from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0,tbl_1.plain_float_0 from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0,tbl_1.plain_float_0 from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0,tbl_1.plain_float_0 from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select fl, fl from (select plain_float_0 as fl, plain_float_0 as fl2 from alice.tbl_1 as alice1) as alice2;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select alice1.plain_float_0 as fl,alice1.plain_float_0 as fl from alice.tbl_1 as alice1\",\n        \"rewritten_sql_pg\": \"select alice1.plain_float_0 as fl,alice1.plain_float_0 as fl from alice.tbl_1 as alice1\",\n        \"rewritten_sql_csv\": \"select alice1.plain_float_0 as fl,alice1.plain_float_0 as fl from alice.tbl_1 as alice1\",\n        \"rewritten_sql\": \"select alice1.plain_float_0 as fl,alice1.plain_float_0 as fl from alice.tbl_1 as alice1\"\n      },\n      {\n        \"sql\": \"select plain_float_0 as fl from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_float_0 / plain_float_1, plain_float_0 div plain_float_1 from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0/tbl_1.plain_float_1 as expr_121,tbl_1.plain_float_0 div tbl_1.plain_float_1 as expr_122 from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0/tbl_1.plain_float_1 as expr_121,div(tbl_1.plain_float_0, tbl_1.plain_float_1) as expr_122 from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0/tbl_1.plain_float_1 as expr_121,tbl_1.plain_float_0 // tbl_1.plain_float_1 as expr_122 from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0/tbl_1.plain_float_1 as expr_121,tbl_1.plain_float_0 div tbl_1.plain_float_1 as expr_122 from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_float_0 as fl from alice.tbl_1 as alice;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select alice.plain_float_0 as fl from alice.tbl_1 as alice\",\n        \"rewritten_sql_pg\": \"select alice.plain_float_0 as fl from alice.tbl_1 as alice\",\n        \"rewritten_sql_csv\": \"select alice.plain_float_0 as fl from alice.tbl_1 as alice\",\n        \"rewritten_sql\": \"select alice.plain_float_0 as fl from alice.tbl_1 as alice\"\n      },\n      {\n        \"sql\": \"select ifnull(plain_float_0, plain_float_1) as fl from alice.tbl_1 as alice;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select nvl(alice.plain_float_0, alice.plain_float_1) as fl from alice.tbl_1 as alice\",\n        \"rewritten_sql_pg\": \"select coalesce(alice.plain_float_0, alice.plain_float_1) as fl from alice.tbl_1 as alice\",\n        \"rewritten_sql_csv\": \"select coalesce(alice.plain_float_0, alice.plain_float_1) as fl from alice.tbl_1 as alice\",\n        \"rewritten_sql\": \"select ifnull(alice.plain_float_0, alice.plain_float_1) as fl from alice.tbl_1 as alice\"\n      },\n      {\n        \"sql\": \"select plain_float_0 is null as fl from alice.tbl_1 where plain_float_1 is not null;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 is null as fl from alice.tbl_1 where not(tbl_1.plain_float_1 is null)\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 is null as fl from alice.tbl_1 where not(tbl_1.plain_float_1 is null)\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 is null as fl from alice.tbl_1 where not(tbl_1.plain_float_1 is null)\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0 is null as fl from alice.tbl_1 where not(tbl_1.plain_float_1 is null)\"\n      },\n      {\n        \"sql\": \"select coalesce(plain_float_0, plain_float_1, plain_float_2) as fl from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select coalesce(tbl_1.plain_float_0, tbl_1.plain_float_1, tbl_1.plain_float_2) as fl from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select coalesce(tbl_1.plain_float_0, tbl_1.plain_float_1, tbl_1.plain_float_2) as fl from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select coalesce(tbl_1.plain_float_0, tbl_1.plain_float_1, tbl_1.plain_float_2) as fl from alice.tbl_1\",\n        \"rewritten_sql\": \"select coalesce(tbl_1.plain_float_0, tbl_1.plain_float_1, tbl_1.plain_float_2) as fl from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select if(plain_float_0 > 0, plain_float_0, plain_float_1) as fl from alice.tbl_1 as alice;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select if(alice.plain_float_0>0, alice.plain_float_0, alice.plain_float_1) as fl from alice.tbl_1 as alice\",\n        \"rewritten_sql_csv\": \"select if(alice.plain_float_0>0, alice.plain_float_0, alice.plain_float_1) as fl from alice.tbl_1 as alice\",\n        \"skip_pg_test\": true,\n        \"rewritten_sql\": \"select if(alice.plain_float_0>0, alice.plain_float_0, alice.plain_float_1) as fl from alice.tbl_1 as alice\"\n      },\n      {\n        \"sql\": \"select if(plain_float_0 > 0, -plain_float_0, -1) as fl from alice.tbl_1 as alice;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select if(alice.plain_float_0>0, -alice.plain_float_0, -1) as fl from alice.tbl_1 as alice\",\n        \"rewritten_sql_csv\": \"select if(alice.plain_float_0>0, -alice.plain_float_0, -1) as fl from alice.tbl_1 as alice\",\n        \"skip_pg_test\": true,\n        \"rewritten_sql\": \"select if(alice.plain_float_0>0, -alice.plain_float_0, -1) as fl from alice.tbl_1 as alice\"\n      },\n      {\n        \"sql\": \"select plain_float_0 + plain_float_1 as fl from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0+tbl_1.plain_float_1 as fl from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0+tbl_1.plain_float_1 as fl from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0+tbl_1.plain_float_1 as fl from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0+tbl_1.plain_float_1 as fl from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select (plain_float_0 = plain_float_1) = 1 as fl from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select (tbl_1.plain_float_0=tbl_1.plain_float_1)=1 as fl from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select (tbl_1.plain_float_0=tbl_1.plain_float_1)=1 as fl from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select (tbl_1.plain_float_0=tbl_1.plain_float_1)=1 as fl from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0=tbl_1.plain_float_1=1 as fl from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_int_0 % plain_int_0 as fl from alice.tbl_1 where tbl_1.plain_int_0 != 0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_int_0%tbl_1.plain_int_0 as fl from alice.tbl_1 where tbl_1.plain_int_0!=0\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_int_0%tbl_1.plain_int_0 as fl from alice.tbl_1 where tbl_1.plain_int_0!=0\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_int_0%tbl_1.plain_int_0 as fl from alice.tbl_1 where tbl_1.plain_int_0!=0\",\n        \"rewritten_sql\": \"select tbl_1.plain_int_0%tbl_1.plain_int_0 as fl from alice.tbl_1 where tbl_1.plain_int_0!=0\"\n      },\n      {\n        \"sql\": \"select plain_float_0 + plain_float_1 as fl from alice.tbl_1 where plain_float_0 + plain_float_1 > 0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0+tbl_1.plain_float_1 as fl from alice.tbl_1 where tbl_1.plain_float_0+tbl_1.plain_float_1>0\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0+tbl_1.plain_float_1 as fl from alice.tbl_1 where tbl_1.plain_float_0+tbl_1.plain_float_1>0\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0+tbl_1.plain_float_1 as fl from alice.tbl_1 where tbl_1.plain_float_0+tbl_1.plain_float_1>0\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0+tbl_1.plain_float_1 as fl from alice.tbl_1 where tbl_1.plain_float_0+tbl_1.plain_float_1>0\"\n      },\n      {\n        \"sql\": \"select plain_float_0 as fl from alice.tbl_1 where plain_string_0 = '{\\\"a\\\":\\\"b\\\"}';\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 where tbl_1.plain_string_0='{\\\"a\\\":\\\"b\\\"}'\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 where tbl_1.plain_string_0='{\\\"a\\\":\\\"b\\\"}'\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 where tbl_1.plain_string_0='{\\\"a\\\":\\\"b\\\"}'\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 where tbl_1.plain_string_0='{\\\"a\\\":\\\"b\\\"}'\"\n      },\n      {\n        \"sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0\"\n      },\n      {\n        \"sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0;\",\n        \"skip_projection\": true,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0\"\n      },\n      {\n        \"sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 limit 1,2;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 limit 2 offset 1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 limit 2 offset 1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 limit 2 offset 1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 limit 2 offset 1\"\n      },\n      {\n        \"sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 order by fl limit 1,2;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 order by tbl_1.plain_float_0 limit 2 offset 1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 order by tbl_1.plain_float_0 limit 2 offset 1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 order by tbl_1.plain_float_0 limit 2 offset 1\",\n        \"rewritten_sql\": \"select tbl_1.plain_float_0 as fl from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 order by tbl_1.plain_float_0 limit 2 offset 1\"\n      },\n      {\n        \"sql\": \"select count(*) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(*) > 3;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>3) and (count(1)>=4)\",\n        \"rewritten_sql_pg\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>3) and (count(1)>=4)\",\n        \"rewritten_sql_csv\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>3) and (count(1)>=4)\",\n        \"rewritten_sql\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>3) and (count(1)>=4)\"\n      },\n      {\n        \"sql\": \"select sum(tbl_1.plain_float_0) as ss, sum(tbl_1.plain_float_0 > 0) as bs from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(*) > 3;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_pg\": \"select sum(tbl_1.plain_float_0) as ss,sum(tbl_1.plain_float_0>0) as bs from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>3) and (count(1)>=4)\",\n        \"rewritten_sql_csv\": \"select sum(tbl_1.plain_float_0) as ss,sum(tbl_1.plain_float_0>0) as bs from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>3) and (count(1)>=4)\",\n        \"skip_odps_test\": true,\n        \"rewritten_sql\": \"select sum(tbl_1.plain_float_0) as ss,sum(tbl_1.plain_float_0>0) as bs from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>3) and (count(1)>=4)\"\n      },\n      {\n        \"sql\": \"select sum(distinct(tbl_1.compare_float_0)) as ss, count(distinct(tbl_1.compare_float_0)) as ss from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 group by tbl_1.plain_float_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select sum(distinct tbl_1.compare_float_0) as ss,count(distinct tbl_1.compare_float_0) as ss from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(1)>=4\",\n        \"rewritten_sql_pg\": \"select sum(distinct tbl_1.compare_float_0) as ss,count(distinct tbl_1.compare_float_0) as ss from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(1)>=4\",\n        \"rewritten_sql_csv\": \"select sum(distinct tbl_1.compare_float_0) as ss,count(distinct tbl_1.compare_float_0) as ss from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(1)>=4\",\n        \"rewritten_sql\": \"select sum(distinct tbl_1.compare_float_0) as ss,count(distinct tbl_1.compare_float_0) as ss from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(1)>=4\"\n      },\n      {\n        \"sql\": \"select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(*) > 0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>0) and (count(1)>=4)\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>0) and (count(1)>=4)\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>0) and (count(1)>=4)\",\n        \"rewritten_sql\": \"select any_value(tbl_1.plain_float_0) as expr_242 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>0) and (count(1)>=4)\"\n      },\n      {\n        \"sql\": \"select tbl_1.plain_float_0 from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(*) > 0 and sum(tbl_1.plain_float_0) > 100 and tbl_1.plain_float_0 > 3;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t_0.plain_float_0 from (select tbl_1.plain_float_0,tbl_1.plain_int_0 from alice.tbl_1 where tbl_1.plain_float_0>3) as t_0 join alice.tbl_2 on t_0.plain_int_0=tbl_2.plain_int_0 group by t_0.plain_float_0 having ((count(1)>0) and (sum(t_0.plain_float_0)>100)) and (count(1)>=4)\",\n        \"rewritten_sql_pg\": \"select t_0.plain_float_0 from (select tbl_1.plain_float_0,tbl_1.plain_int_0 from alice.tbl_1 where tbl_1.plain_float_0>3) as t_0 join alice.tbl_2 on t_0.plain_int_0=tbl_2.plain_int_0 group by t_0.plain_float_0 having ((count(1)>0) and (sum(t_0.plain_float_0)>100)) and (count(1)>=4)\",\n        \"rewritten_sql_csv\": \"select t_0.plain_float_0 from (select tbl_1.plain_float_0,tbl_1.plain_int_0 from alice.tbl_1 where tbl_1.plain_float_0>3) as t_0 join alice.tbl_2 on t_0.plain_int_0=tbl_2.plain_int_0 group by t_0.plain_float_0 having ((count(1)>0) and (sum(t_0.plain_float_0)>100)) and (count(1)>=4)\",\n        \"rewritten_sql\": \"select any_value(t_0.plain_float_0) as expr_243 from (select tbl_1.plain_float_0,tbl_1.plain_int_0 from alice.tbl_1 where tbl_1.plain_float_0>3) as t_0 join alice.tbl_2 on t_0.plain_int_0=tbl_2.plain_int_0 group by t_0.plain_float_0 having ((count(1)>0) and (sum(t_0.plain_float_0)>100)) and (count(1)>=4)\"\n      },\n      {\n        \"sql\": \"select count(*) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 group by tbl_1.plain_float_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(1)>=4\",\n        \"rewritten_sql_pg\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(1)>=4\",\n        \"rewritten_sql_csv\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(1)>=4\",\n        \"rewritten_sql\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having count(1)>=4\"\n      },\n      {\n        \"sql\": \"select count(*) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0 = tbl_2.plain_int_0 group by tbl_1.plain_float_0 having c > 1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>1) and (count(1)>=4)\",\n        \"rewritten_sql_pg\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>1) and (count(1)>=4)\",\n        \"rewritten_sql_csv\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>1) and (count(1)>=4)\",\n        \"rewritten_sql\": \"select count(1) as c from alice.tbl_1 join alice.tbl_2 on tbl_1.plain_int_0=tbl_2.plain_int_0 group by tbl_1.plain_float_0 having (count(1)>1) and (count(1)>=4)\"\n      },\n      {\n        \"sql\": \"select count(distinct (alice.tbl_1.plain_float_0)) as co,sum(distinct (alice.tbl_1.plain_int_0)) as su from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select count(distinct tbl_1.plain_float_0) as co,sum(distinct tbl_1.plain_int_0) as su from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select count(distinct tbl_1.plain_float_0) as co,sum(distinct tbl_1.plain_int_0) as su from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select count(distinct tbl_1.plain_float_0) as co,sum(distinct tbl_1.plain_int_0) as su from alice.tbl_1\",\n        \"rewritten_sql\": \"select count(distinct tbl_1.plain_float_0) as co,sum(distinct tbl_1.plain_int_0) as su from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_int_0 from alice.tbl_1 union all select plain_int_0 from alice.tbl_2;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t_0.plain_int_0 from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_2.plain_int_0 from alice.tbl_2)) as t_0\",\n        \"rewritten_sql_pg\": \"select t_0.plain_int_0 from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_2.plain_int_0 from alice.tbl_2)) as t_0\",\n        \"rewritten_sql_csv\": \"select t_0.plain_int_0 from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_2.plain_int_0 from alice.tbl_2)) as t_0\",\n        \"rewritten_sql\": \"select t_0.plain_int_0 from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_2.plain_int_0 from alice.tbl_2)) as t_0\"\n      },\n      {\n        \"sql\": \"select mm from (select plain_int_0 + plain_int_1 as mm from alice.tbl_1 union all select plain_int_0 + plain_int_1 as mm from alice.tbl_2) as tt;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tt.expr_243 as mm from ((select tbl_1.plain_int_0+tbl_1.plain_int_1 as expr_243 from alice.tbl_1) union all (select tbl_2.plain_int_0+tbl_2.plain_int_1 as expr_243 from alice.tbl_2)) as tt\",\n        \"rewritten_sql_pg\": \"select tt.expr_243 as mm from ((select tbl_1.plain_int_0+tbl_1.plain_int_1 as expr_243 from alice.tbl_1) union all (select tbl_2.plain_int_0+tbl_2.plain_int_1 as expr_243 from alice.tbl_2)) as tt\",\n        \"rewritten_sql_csv\": \"select tt.expr_243 as mm from ((select tbl_1.plain_int_0+tbl_1.plain_int_1 as expr_243 from alice.tbl_1) union all (select tbl_2.plain_int_0+tbl_2.plain_int_1 as expr_243 from alice.tbl_2)) as tt\",\n        \"rewritten_sql\": \"select tt.expr_243 as mm from ((select tbl_1.plain_int_0+tbl_1.plain_int_1 as expr_243 from alice.tbl_1) union all (select tbl_2.plain_int_0+tbl_2.plain_int_1 as expr_243 from alice.tbl_2)) as tt\"\n      },\n      {\n        \"sql\": \"select plain_int_0 as p from alice.tbl_1 union all select plain_int_0 from alice.tbl_2;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t_0.plain_int_0 as p from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_2.plain_int_0 from alice.tbl_2)) as t_0\",\n        \"rewritten_sql_pg\": \"select t_0.plain_int_0 as p from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_2.plain_int_0 from alice.tbl_2)) as t_0\",\n        \"rewritten_sql_csv\": \"select t_0.plain_int_0 as p from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_2.plain_int_0 from alice.tbl_2)) as t_0\",\n        \"rewritten_sql\": \"select t_0.plain_int_0 as p from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_2.plain_int_0 from alice.tbl_2)) as t_0\"\n      },\n      {\n        \"sql\": \"select plain_int_0 as l from alice.tbl_1 union all select plain_int_1 as l from alice.tbl_1 union all select plain_int_2 as l from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t_0.plain_int_0 as l from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_1.plain_int_1 from alice.tbl_1) union all (select tbl_1.plain_int_2 from alice.tbl_1)) as t_0\",\n        \"rewritten_sql_pg\": \"select t_0.plain_int_0 as l from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_1.plain_int_1 from alice.tbl_1) union all (select tbl_1.plain_int_2 from alice.tbl_1)) as t_0\",\n        \"rewritten_sql_csv\": \"select t_0.plain_int_0 as l from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_1.plain_int_1 from alice.tbl_1) union all (select tbl_1.plain_int_2 from alice.tbl_1)) as t_0\",\n        \"rewritten_sql\": \"select t_0.plain_int_0 as l from ((select tbl_1.plain_int_0 from alice.tbl_1) union all (select tbl_1.plain_int_1 from alice.tbl_1) union all (select tbl_1.plain_int_2 from alice.tbl_1)) as t_0\"\n      },\n      {\n        \"sql\": \"select cnt from (select count(*) as cnt from alice.tbl_1 union all select count(*) as cnt from alice.tbl_2 union all select count(*) as cnt from alice.tbl_0) as a;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select a.expr_364 as cnt from ((select count(1) as expr_364 from alice.tbl_1) union all (select count(1) as expr_364 from alice.tbl_2) union all (select count(1) as expr_364 from alice.tbl_0)) as a\",\n        \"rewritten_sql_pg\": \"select a.expr_364 as cnt from ((select count(1) as expr_364 from alice.tbl_1) union all (select count(1) as expr_364 from alice.tbl_2) union all (select count(1) as expr_364 from alice.tbl_0)) as a\",\n        \"rewritten_sql_csv\": \"select a.expr_364 as cnt from ((select count(1) as expr_364 from alice.tbl_1) union all (select count(1) as expr_364 from alice.tbl_2) union all (select count(1) as expr_364 from alice.tbl_0)) as a\",\n        \"rewritten_sql\": \"select a.expr_364 as cnt from ((select count(1) as expr_364 from alice.tbl_1) union all (select count(1) as expr_364 from alice.tbl_2) union all (select count(1) as expr_364 from alice.tbl_0)) as a\"\n      },\n      {\n        \"sql\": \"select tbl_1.plain_int_0, '123' as constStr, 123 as constInt from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_int_0,'123' as constStr,123 as constInt from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_int_0,'123' as constStr,123 as constInt from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_int_0,'123' as constStr,123 as constInt from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_int_0,'123' as constStr,123 as constInt from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_int_0 in (select plain_int_0 from alice.tbl_1) from alice.tbl_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_0.plain_int_0 in (select tbl_1.plain_int_0 from alice.tbl_1) as expr_241 from alice.tbl_0\",\n        \"rewritten_sql_pg\": \"select tbl_0.plain_int_0 in (select tbl_1.plain_int_0 from alice.tbl_1) as expr_241 from alice.tbl_0\",\n        \"rewritten_sql_csv\": \"select tbl_0.plain_int_0 in (select tbl_1.plain_int_0 from alice.tbl_1) as expr_241 from alice.tbl_0\",\n        \"rewritten_sql\": \"select tbl_0.plain_int_0 in (select tbl_1.plain_int_0 from alice.tbl_1) as expr_241 from alice.tbl_0\"\n      },\n      {\n        \"sql\": \"select plain_int_1, plain_int_0 not in (select plain_int_0 from alice.tbl_1) as tt from alice.tbl_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_0.plain_int_1,tbl_0.plain_int_0 not in (select tbl_1.plain_int_0 from alice.tbl_1) as tt from alice.tbl_0\",\n        \"rewritten_sql_pg\": \"select tbl_0.plain_int_1,tbl_0.plain_int_0 not in (select tbl_1.plain_int_0 from alice.tbl_1) as tt from alice.tbl_0\",\n        \"rewritten_sql_csv\": \"select tbl_0.plain_int_1,tbl_0.plain_int_0 not in (select tbl_1.plain_int_0 from alice.tbl_1) as tt from alice.tbl_0\",\n        \"rewritten_sql\": \"select tbl_0.plain_int_1,tbl_0.plain_int_0 not in (select tbl_1.plain_int_0 from alice.tbl_1) as tt from alice.tbl_0\"\n      },\n      {\n        \"sql\": \"select plain_int_0 from alice.tbl_0 where plain_int_0 in (select plain_int_0 from alice.tbl_1);\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_0.plain_int_0 from alice.tbl_0 where exists (select tbl_1.plain_int_0 from alice.tbl_1 where tbl_0.plain_int_0=tbl_1.plain_int_0)\",\n        \"rewritten_sql_pg\": \"select tbl_0.plain_int_0 from alice.tbl_0 where exists (select tbl_1.plain_int_0 from alice.tbl_1 where tbl_0.plain_int_0=tbl_1.plain_int_0)\",\n        \"rewritten_sql_csv\": \"select tbl_0.plain_int_0 from alice.tbl_0 where exists (select tbl_1.plain_int_0 from alice.tbl_1 where tbl_0.plain_int_0=tbl_1.plain_int_0)\",\n        \"rewritten_sql\": \"select tbl_0.plain_int_0 from alice.tbl_0 where exists (select tbl_1.plain_int_0 from alice.tbl_1 where tbl_0.plain_int_0=tbl_1.plain_int_0)\"\n      },\n      {\n        \"sql\": \"select plain_int_0 from alice.tbl_0 where (plain_int_0 in (select plain_int_0 from alice.tbl_1)) and plain_int_0 > 0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_0.plain_int_0 from alice.tbl_0 where (tbl_0.plain_int_0>0) and (exists (select tbl_1.plain_int_0 from alice.tbl_1 where tbl_0.plain_int_0=tbl_1.plain_int_0))\",\n        \"rewritten_sql_pg\": \"select tbl_0.plain_int_0 from alice.tbl_0 where (tbl_0.plain_int_0>0) and (exists (select tbl_1.plain_int_0 from alice.tbl_1 where tbl_0.plain_int_0=tbl_1.plain_int_0))\",\n        \"rewritten_sql_csv\": \"select tbl_0.plain_int_0 from alice.tbl_0 where (tbl_0.plain_int_0>0) and (exists (select tbl_1.plain_int_0 from alice.tbl_1 where tbl_0.plain_int_0=tbl_1.plain_int_0))\",\n        \"rewritten_sql\": \"select tbl_0.plain_int_0 from alice.tbl_0 where (tbl_0.plain_int_0>0) and (exists (select tbl_1.plain_int_0 from alice.tbl_1 where tbl_0.plain_int_0=tbl_1.plain_int_0))\"\n      },\n      {\n        \"sql\": \"select plain_int_0 from alice.tbl_0 where plain_int_0 not in (select plain_int_0 from alice.tbl_1);\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_0.plain_int_0 from alice.tbl_0 where tbl_0.plain_int_0 not in (select tbl_1.plain_int_0 from alice.tbl_1)\",\n        \"rewritten_sql_pg\": \"select tbl_0.plain_int_0 from alice.tbl_0 where tbl_0.plain_int_0 not in (select tbl_1.plain_int_0 from alice.tbl_1)\",\n        \"rewritten_sql_csv\": \"select tbl_0.plain_int_0 from alice.tbl_0 where tbl_0.plain_int_0 not in (select tbl_1.plain_int_0 from alice.tbl_1)\",\n        \"rewritten_sql\": \"select tbl_0.plain_int_0 from alice.tbl_0 where tbl_0.plain_int_0 not in (select tbl_1.plain_int_0 from alice.tbl_1)\"\n      },\n      {\n        \"sql\": \"select t1.plain_int_0 from alice.tbl_0 as t1 join alice.tbl_1 as t2 on t1.plain_int_0 = t2.plain_int_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t1.plain_int_0 from alice.tbl_0 as t1 join alice.tbl_1 as t2 on t1.plain_int_0=t2.plain_int_0\",\n        \"rewritten_sql_pg\": \"select t1.plain_int_0 from alice.tbl_0 as t1 join alice.tbl_1 as t2 on t1.plain_int_0=t2.plain_int_0\",\n        \"rewritten_sql_csv\": \"select t1.plain_int_0 from alice.tbl_0 as t1 join alice.tbl_1 as t2 on t1.plain_int_0=t2.plain_int_0\",\n        \"rewritten_sql\": \"select t1.plain_int_0 from alice.tbl_0 as t1 join alice.tbl_1 as t2 on t1.plain_int_0=t2.plain_int_0\"\n      },\n      {\n        \"sql\": \"select alice.tbl_0.plain_int_0 from alice.tbl_0 join alice.tbl_1 on alice.tbl_0.plain_int_0 = alice.tbl_1.plain_int_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_0.plain_int_0 from alice.tbl_0 join alice.tbl_1 on tbl_0.plain_int_0=tbl_1.plain_int_0\",\n        \"rewritten_sql_pg\": \"select tbl_0.plain_int_0 from alice.tbl_0 join alice.tbl_1 on tbl_0.plain_int_0=tbl_1.plain_int_0\",\n        \"rewritten_sql_csv\": \"select tbl_0.plain_int_0 from alice.tbl_0 join alice.tbl_1 on tbl_0.plain_int_0=tbl_1.plain_int_0\",\n        \"rewritten_sql\": \"select tbl_0.plain_int_0 from alice.tbl_0 join alice.tbl_1 on tbl_0.plain_int_0=tbl_1.plain_int_0\"\n      },\n      {\n        \"sql\": \"select concat(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1) as tg, (alice.tbl_0.plain_int_0 + alice.tbl_1.plain_int_0) as tt from alice.tbl_0 join alice.tbl_1 on alice.tbl_0.plain_int_0 = alice.tbl_1.plain_int_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select concat(tbl_0.plain_string_0, tbl_0.plain_string_1) as tg,tbl_0.plain_int_0+tbl_1.plain_int_0 as tt from alice.tbl_0 join alice.tbl_1 on tbl_0.plain_int_0=tbl_1.plain_int_0\",\n        \"rewritten_sql_pg\": \"select concat(tbl_0.plain_string_0, tbl_0.plain_string_1) as tg,tbl_0.plain_int_0+tbl_1.plain_int_0 as tt from alice.tbl_0 join alice.tbl_1 on tbl_0.plain_int_0=tbl_1.plain_int_0\",\n        \"rewritten_sql_csv\": \"select concat(tbl_0.plain_string_0, tbl_0.plain_string_1) as tg,tbl_0.plain_int_0+tbl_1.plain_int_0 as tt from alice.tbl_0 join alice.tbl_1 on tbl_0.plain_int_0=tbl_1.plain_int_0\",\n        \"rewritten_sql\": \"select concat(tbl_0.plain_string_0, tbl_0.plain_string_1) as tg,tbl_0.plain_int_0+tbl_1.plain_int_0 as tt from alice.tbl_0 join alice.tbl_1 on tbl_0.plain_int_0=tbl_1.plain_int_0\"\n      },\n      {\n        \"sql\": \"select concat(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1) as tt from alice.tbl_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select concat(tbl_0.plain_string_0, tbl_0.plain_string_1) as tt from alice.tbl_0\",\n        \"rewritten_sql_pg\": \"select concat(tbl_0.plain_string_0, tbl_0.plain_string_1) as tt from alice.tbl_0\",\n        \"rewritten_sql_csv\": \"select concat(tbl_0.plain_string_0, tbl_0.plain_string_1) as tt from alice.tbl_0\",\n        \"rewritten_sql\": \"select concat(tbl_0.plain_string_0, tbl_0.plain_string_1) as tt from alice.tbl_0\"\n      },\n      {\n        \"sql\": \"select concat(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1) as tt from alice.tbl_0;\",\n        \"skip_projection\": true,\n        \"rewritten_sql_odps\": \"select tbl_0.plain_string_0,tbl_0.plain_string_1 from alice.tbl_0\",\n        \"rewritten_sql_pg\": \"select tbl_0.plain_string_0,tbl_0.plain_string_1 from alice.tbl_0\",\n        \"rewritten_sql_csv\": \"select tbl_0.plain_string_0,tbl_0.plain_string_1 from alice.tbl_0\",\n        \"rewritten_sql\": \"select tbl_0.plain_string_0,tbl_0.plain_string_1 from alice.tbl_0\"\n      },\n      {\n        \"sql\": \"select lower(alice.tbl_0.plain_string_0) as tt from alice.tbl_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select lower(tbl_0.plain_string_0) as tt from alice.tbl_0\",\n        \"rewritten_sql_pg\": \"select lower(tbl_0.plain_string_0) as tt from alice.tbl_0\",\n        \"rewritten_sql_csv\": \"select lower(tbl_0.plain_string_0) as tt from alice.tbl_0\",\n        \"rewritten_sql\": \"select lower(tbl_0.plain_string_0) as tt from alice.tbl_0\"\n      },\n      {\n        \"sql\": \"select count(*), sum(sumId), max(minId), min(maxId) from (select t.plain_int_0, sum(t.plain_int_1) as sumId, max(t.plain_int_1) as maxId, min(t.plain_int_2) as minId from alice.tbl_0 as t group by t.plain_int_0) as hp;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select count(1) as expr_124,sum(t_0.expr_121) as expr_125,max(t_0.expr_123) as expr_126,min(t_0.expr_122) as expr_127 from (select sum(t.plain_int_1) as expr_121,max(t.plain_int_1) as expr_122,min(t.plain_int_2) as expr_123,count(1) as expr_128 from alice.tbl_0 as t group by t.plain_int_0 having count(1)>=4) as t_0\",\n        \"rewritten_sql_pg\": \"select count(1) as expr_124,sum(t_0.expr_121) as expr_125,max(t_0.expr_123) as expr_126,min(t_0.expr_122) as expr_127 from (select sum(t.plain_int_1) as expr_121,max(t.plain_int_1) as expr_122,min(t.plain_int_2) as expr_123,count(1) as expr_128 from alice.tbl_0 as t group by t.plain_int_0 having count(1)>=4) as t_0\",\n        \"rewritten_sql_csv\": \"select count(1) as expr_124,sum(t_0.expr_121) as expr_125,max(t_0.expr_123) as expr_126,min(t_0.expr_122) as expr_127 from (select sum(t.plain_int_1) as expr_121,max(t.plain_int_1) as expr_122,min(t.plain_int_2) as expr_123,count(1) as expr_128 from alice.tbl_0 as t group by t.plain_int_0 having count(1)>=4) as t_0\",\n        \"rewritten_sql\": \"select count(1) as expr_124,sum(t_0.expr_121) as expr_125,max(t_0.expr_123) as expr_126,min(t_0.expr_122) as expr_127 from (select sum(t.plain_int_1) as expr_121,max(t.plain_int_1) as expr_122,min(t.plain_int_2) as expr_123,count(1) as expr_128 from alice.tbl_0 as t group by t.plain_int_0 having count(1)>=4) as t_0\"\n      },\n      {\n        \"sql\": \"select count(*) from (select encrypt_float_0, encrypt_float_1 from alice.tbl_1 as t union all select encrypt_float_0, encrypt_float_1 from alice.tbl_1 as t1) as tt group by tt.encrypt_float_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select count(tt.expr_244) as expr_243 from ((select count(1) as expr_244,t.encrypt_float_0 from alice.tbl_1 as t group by t.encrypt_float_0) union all (select count(1) as expr_244,t1.encrypt_float_0 from alice.tbl_1 as t1 group by t1.encrypt_float_0)) as tt group by tt.encrypt_float_0 having count(tt.expr_244)>=4\",\n        \"rewritten_sql_pg\": \"select count(tt.expr_244) as expr_243 from ((select count(1) as expr_244,t.encrypt_float_0 from alice.tbl_1 as t group by t.encrypt_float_0) union all (select count(1) as expr_244,t1.encrypt_float_0 from alice.tbl_1 as t1 group by t1.encrypt_float_0)) as tt group by tt.encrypt_float_0 having count(tt.expr_244)>=4\",\n        \"rewritten_sql_csv\": \"select count(tt.expr_244) as expr_243 from ((select count(1) as expr_244,t.encrypt_float_0 from alice.tbl_1 as t group by t.encrypt_float_0) union all (select count(1) as expr_244,t1.encrypt_float_0 from alice.tbl_1 as t1 group by t1.encrypt_float_0)) as tt group by tt.encrypt_float_0 having count(tt.expr_244)>=4\",\n        \"rewritten_sql\": \"select count(tt.expr_244) as expr_243 from ((select count(1) as expr_244,any_value(t.encrypt_float_0) as expr_241 from alice.tbl_1 as t group by t.encrypt_float_0) union all (select count(1) as expr_244,any_value(t1.encrypt_float_0) as expr_241 from alice.tbl_1 as t1 group by t1.encrypt_float_0)) as tt group by tt.expr_241 having count(tt.expr_244)>=4\"\n      },\n      {\n        \"sql\": \"select min(alice.compare_float_0*alice.compare_float_1) as m from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select min(alice.compare_float_0*alice.compare_float_1) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select min(alice.compare_float_0*alice.compare_float_1) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select min(alice.compare_float_0*alice.compare_float_1) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select min(alice.compare_float_0*alice.compare_float_1) as m from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"select cast(alice.compare_float_0 as decimal(11,2)) as m from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select cast(alice.compare_float_0 as decimal) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select cast(alice.compare_float_0 as numeric(11, 2)) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select cast(alice.compare_float_0 as numeric(11, 2)) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select cast(alice.compare_float_0 as decimal(11, 2)) as m from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"select cast(alice.compare_string_0 as datetime) as m from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select cast(alice.compare_string_0 as datetime) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select cast(alice.compare_string_0 as timestamp) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select cast(alice.compare_string_0 as timestamp) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select cast(alice.compare_string_0 as datetime) as m from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"select cast(alice.compare_string_0 as CHAR(100)) as m from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select cast(alice.compare_string_0 as string) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select cast(alice.compare_string_0 as varchar) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select cast(alice.compare_string_0 as varchar) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select cast(alice.compare_string_0 as char(100)) as m from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"select cast(alice.compare_float_0 as double) as m from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select cast(alice.compare_float_0 as double) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select cast(alice.compare_float_0 as double precision) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select cast(alice.compare_float_0 as double precision) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select cast(alice.compare_float_0 as decimal(64,30)) as m from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"select cast(alice.compare_float_0 as decimal(11)) as m from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select cast(alice.compare_float_0 as bigint) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select cast(alice.compare_float_0 as numeric(11)) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select cast(alice.compare_float_0 as numeric(11)) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select cast(alice.compare_float_0 as decimal(11)) as m from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"select cast(alice.compare_float_0 as signed) as m from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select cast(alice.compare_float_0 as bigint) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select cast(alice.compare_float_0 as integer) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select cast(alice.compare_float_0 as integer) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select cast(alice.compare_float_0 as signed) as m from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"select cast(alice.compare_float_0 as unsigned) as m from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"skip_odps_test\": true,\n        \"skip_pg_test\": true,\n        \"skip_csv_test\": true,\n        \"rewritten_sql\": \"select cast(alice.compare_float_0 as unsigned) as m from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"select cast(alice.compare_datetime_0 as date) as m from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_pg\": \"select cast(alice.compare_datetime_0 as date) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select cast(alice.compare_datetime_0 as date) as m from alice.tbl_0 as alice\",\n        \"skip_odps_test\": true,\n        \"rewritten_sql\": \"select cast(alice.compare_datetime_0 as date) as m from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"select cast(alice.compare_datetime_0 as datetime) as m from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_pg\": \"select cast(alice.compare_datetime_0 as timestamp) as m from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select cast(alice.compare_datetime_0 as timestamp) as m from alice.tbl_0 as alice\",\n        \"skip_odps_test\": true,\n        \"rewritten_sql\": \"select cast(alice.compare_datetime_0 as datetime) as m from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"SELECT 'David!' LIKE 'David\\\\_' as tt from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select 'David!'='David_' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select 'David!'='David_' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select 'David!'='David_' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select 'David!'='David_' as tt from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"SELECT 'David_' LIKE 'David|_' ESCAPE '|' as  tt from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select 'David_'='David_' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select 'David_'='David_' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select 'David_'='David_' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select 'David_'='David_' as tt from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"SELECT alice.plain_string_0 LIKE '%str%' as tt from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select alice.plain_string_0 like '%str%' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select alice.plain_string_0 like '%str%' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select alice.plain_string_0 like '%str%' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select alice.plain_string_0 like '%str%' as tt from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"SELECT alice.plain_string_0 LIKE '%str#%' ESCAPE '#' as tt from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select alice.plain_string_0 like '%str#%' escape '#' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql_pg\": \"select alice.plain_string_0 like '%str#%' escape '#' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select alice.plain_string_0 like '%str#%' escape '#' as tt from alice.tbl_0 as alice\",\n        \"rewritten_sql\": \"select alice.plain_string_0 like '%str#%' escape '#' as tt from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"SELECT (alice.plain_string_0 LIKE '%str%') * 10 as tt1, (alice.plain_string_0 LIKE '%str%') + 10 as tt2, alice.plain_string_0 LIKE '%str%' and alice.plain_string_1 LIKE '%str%' as tt3 from alice.tbl_0 as alice;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_pg\": \"select (alice.plain_string_0 like '%str%')*10 as tt1,(alice.plain_string_0 like '%str%')+10 as tt2,alice.plain_string_0 like '%str%' and alice.plain_string_1 like '%str%' as tt3 from alice.tbl_0 as alice\",\n        \"rewritten_sql_csv\": \"select (alice.plain_string_0 like '%str%')*10 as tt1,(alice.plain_string_0 like '%str%')+10 as tt2,alice.plain_string_0 like '%str%' and alice.plain_string_1 like '%str%' as tt3 from alice.tbl_0 as alice\",\n        \"skip_odps_test\": true,\n        \"rewritten_sql\": \"select (alice.plain_string_0 like '%str%')*10 as tt1,(alice.plain_string_0 like '%str%')+10 as tt2,alice.plain_string_0 like '%str%' and alice.plain_string_1 like '%str%' as tt3 from alice.tbl_0 as alice\"\n      },\n      {\n        \"sql\": \"select plain_int_0, 3 + plain_int_1 in (2, 5, 15) as ee from alice.tbl_1 where plain_int_0 in (2, 5, 15) and plain_int_1 not in (2, 5, 15);;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_int_0,(3+tbl_1.plain_int_1=2) or (3+tbl_1.plain_int_1=5) or (3+tbl_1.plain_int_1=15) as ee from alice.tbl_1 where ((tbl_1.plain_int_0=2) or (tbl_1.plain_int_0=5) or (tbl_1.plain_int_0=15)) and (not((tbl_1.plain_int_1=2) or (tbl_1.plain_int_1=5) or (tbl_1.plain_int_1=15)))\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_int_0,(3+tbl_1.plain_int_1=2) or (3+tbl_1.plain_int_1=5) or (3+tbl_1.plain_int_1=15) as ee from alice.tbl_1 where ((tbl_1.plain_int_0=2) or (tbl_1.plain_int_0=5) or (tbl_1.plain_int_0=15)) and (not((tbl_1.plain_int_1=2) or (tbl_1.plain_int_1=5) or (tbl_1.plain_int_1=15)))\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_int_0,(3+tbl_1.plain_int_1=2) or (3+tbl_1.plain_int_1=5) or (3+tbl_1.plain_int_1=15) as ee from alice.tbl_1 where ((tbl_1.plain_int_0=2) or (tbl_1.plain_int_0=5) or (tbl_1.plain_int_0=15)) and (not((tbl_1.plain_int_1=2) or (tbl_1.plain_int_1=5) or (tbl_1.plain_int_1=15)))\",\n        \"rewritten_sql\": \"select tbl_1.plain_int_0,3+tbl_1.plain_int_1=2 or 3+tbl_1.plain_int_1=5 or 3+tbl_1.plain_int_1=15 as ee from alice.tbl_1 where (tbl_1.plain_int_0=2 or tbl_1.plain_int_0=5 or tbl_1.plain_int_0=15) and (not(tbl_1.plain_int_1=2 or tbl_1.plain_int_1=5 or tbl_1.plain_int_1=15))\"\n      },\n      {\n        \"sql\": \"select plain_int_0 + plain_int_0 + 5, (plain_int_1 + plain_int_2 + plain_int_0) > plain_int_1 and plain_int_1 > plain_int_0 and plain_int_1 < plain_int_0 from alice.tbl_1;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_int_0+tbl_1.plain_int_0+5 as expr_121,(tbl_1.plain_int_1+tbl_1.plain_int_2+tbl_1.plain_int_0>tbl_1.plain_int_1) and (tbl_1.plain_int_1>tbl_1.plain_int_0) and (tbl_1.plain_int_1<tbl_1.plain_int_0) as expr_122 from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_int_0+tbl_1.plain_int_0+5 as expr_121,(tbl_1.plain_int_1+tbl_1.plain_int_2+tbl_1.plain_int_0>tbl_1.plain_int_1) and (tbl_1.plain_int_1>tbl_1.plain_int_0) and (tbl_1.plain_int_1<tbl_1.plain_int_0) as expr_122 from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_int_0+tbl_1.plain_int_0+5 as expr_121,(tbl_1.plain_int_1+tbl_1.plain_int_2+tbl_1.plain_int_0>tbl_1.plain_int_1) and (tbl_1.plain_int_1>tbl_1.plain_int_0) and (tbl_1.plain_int_1<tbl_1.plain_int_0) as expr_122 from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_int_0+tbl_1.plain_int_0+5 as expr_121,tbl_1.plain_int_1+tbl_1.plain_int_2+tbl_1.plain_int_0>tbl_1.plain_int_1 and tbl_1.plain_int_1>tbl_1.plain_int_0 and tbl_1.plain_int_1<tbl_1.plain_int_0 as expr_122 from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_int_0 > if(plain_int_0, plain_int_1, plain_int_2) as res from alice.tbl_1;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_pg\": \"select tbl_1.plain_int_0>if(tbl_1.plain_int_0, tbl_1.plain_int_1, tbl_1.plain_int_2) as res from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_int_0>if(tbl_1.plain_int_0, tbl_1.plain_int_1, tbl_1.plain_int_2) as res from alice.tbl_1\",\n        \"skip_odps_test\": true,\n        \"rewritten_sql\": \"select tbl_1.plain_int_0>if(tbl_1.plain_int_0, tbl_1.plain_int_1, tbl_1.plain_int_2) as res from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_int_0, plain_int_0 > 1 and plain_int_0 >= 1 as and_log, not (plain_int_0 < 5) as not_log, (plain_int_0 <= 5) or (plain_int_0 <> 8) as or_log from carol.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_int_0,(tbl_1.plain_int_0>1) and (tbl_1.plain_int_0>=1) as and_log,not(tbl_1.plain_int_0<5) as not_log,(tbl_1.plain_int_0<=5) or (tbl_1.plain_int_0!=8) as or_log from carol.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_int_0,(tbl_1.plain_int_0>1) and (tbl_1.plain_int_0>=1) as and_log,not(tbl_1.plain_int_0<5) as not_log,(tbl_1.plain_int_0<=5) or (tbl_1.plain_int_0!=8) as or_log from carol.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_int_0,(tbl_1.plain_int_0>1) and (tbl_1.plain_int_0>=1) as and_log,not(tbl_1.plain_int_0<5) as not_log,(tbl_1.plain_int_0<=5) or (tbl_1.plain_int_0!=8) as or_log from carol.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_int_0,tbl_1.plain_int_0>1 and tbl_1.plain_int_0>=1 as and_log,not(tbl_1.plain_int_0<5) as not_log,tbl_1.plain_int_0<=5 or tbl_1.plain_int_0!=8 as or_log from carol.tbl_1\"\n      },\n      {\n        \"sql\": \"select -(plain_int_0 + plain_int_2) * plain_int_1 as res from carol.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select -(tbl_1.plain_int_0+tbl_1.plain_int_2)*tbl_1.plain_int_1 as res from carol.tbl_1\",\n        \"rewritten_sql_pg\": \"select -(tbl_1.plain_int_0+tbl_1.plain_int_2)*tbl_1.plain_int_1 as res from carol.tbl_1\",\n        \"rewritten_sql_csv\": \"select -(tbl_1.plain_int_0+tbl_1.plain_int_2)*tbl_1.plain_int_1 as res from carol.tbl_1\",\n        \"rewritten_sql\": \"select -(tbl_1.plain_int_0+tbl_1.plain_int_2)*tbl_1.plain_int_1 as res from carol.tbl_1\"\n      },\n      {\n        \"sql\": \"select cos(aggregate_float_0) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select cos(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select cos(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select cos(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select cos(tbl_1.aggregate_float_0) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select truncate(plain_float_0, 2) as a, truncate(plain_float_0, 0) as b, truncate(3.1415926, 3) as c from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select trunc(tbl_1.plain_float_0, 2) as a,trunc(tbl_1.plain_float_0, 0) as b,trunc(3.1415926, 3) as c from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select trunc(tbl_1.plain_float_0, 2) as a,trunc(tbl_1.plain_float_0, 0) as b,trunc(3.1415926, 3) as c from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select trunc(tbl_1.plain_float_0, 2) as a,trunc(tbl_1.plain_float_0, 0) as b,trunc(3.1415926, 3) as c from alice.tbl_1\",\n        \"rewritten_sql\": \"select truncate(tbl_1.plain_float_0, 2) as a,truncate(tbl_1.plain_float_0, 0) as b,truncate(3.1415926, 3) as c from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select abs(aggregate_float_0) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select abs(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select abs(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select abs(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select abs(tbl_1.aggregate_float_0) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select round(aggregate_float_0) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select round(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select round(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select round(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select round(tbl_1.aggregate_float_0) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select log10(aggregate_float_0) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select log10(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select log10(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select log10(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select log10(tbl_1.aggregate_float_0) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select ceil(aggregate_float_0) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select ceil(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select ceil(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select ceil(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select ceil(tbl_1.aggregate_float_0) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select floor(aggregate_float_0) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select floor(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select floor(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select floor(tbl_1.aggregate_float_0) as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select floor(tbl_1.aggregate_float_0) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select length(plain_string_0) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select length(tbl_1.plain_string_0) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select length(tbl_1.plain_string_0) as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select length(tbl_1.plain_string_0) as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select length(tbl_1.plain_string_0) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select trim(plain_string_0) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select trim(tbl_1.plain_string_0) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select trim(tbl_1.plain_string_0) as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select trim(tbl_1.plain_string_0) as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select trim(tbl_1.plain_string_0) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select instr(plain_string_0, 'teststr') as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select instr(tbl_1.plain_string_0, 'teststr') as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select instr(tbl_1.plain_string_0, 'teststr') as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select instr(tbl_1.plain_string_0, 'teststr') as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select instr(tbl_1.plain_string_0, 'teststr') as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_datetime_0 < now() as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_datetime_0<now() as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_datetime_0<now() as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_datetime_0<now() as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_datetime_0<now() as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select plain_datetime_0 < curdate() as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_datetime_0<curdate() as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_datetime_0<current_date as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_datetime_0<current_date as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select tbl_1.plain_datetime_0<curdate() as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select date_add(plain_datetime_0, INTERVAL 30 DAY) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select date_add(tbl_1.plain_datetime_0, interval 30 DAY) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_datetime_0+ interval '30 DAY' as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_datetime_0+interval 30 DAY as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select date_add(tbl_1.plain_datetime_0, interval 30 DAY) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select adddate(plain_datetime_0, INTERVAL 30 DAY) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select adddate(tbl_1.plain_datetime_0, interval 30 DAY) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_datetime_0+ interval '30 DAY' as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_datetime_0+interval 30 DAY as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select adddate(tbl_1.plain_datetime_0, interval 30 DAY) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select subdate(plain_datetime_0, INTERVAL 30 DAY) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select subdate(tbl_1.plain_datetime_0, interval 30 DAY) as a from alice.tbl_1\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_datetime_0- interval '30 DAY' as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_datetime_0-interval 30 DAY as a from alice.tbl_1\",\n        \"rewritten_sql\": \"select subdate(tbl_1.plain_datetime_0, interval 30 DAY) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select datediff(plain_datetime_0, plain_datetime_1) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select datediff(tbl_1.plain_datetime_0, tbl_1.plain_datetime_1) as a from alice.tbl_1\",\n        \"skip_pg_test\": true,\n        \"skip_csv_test\": true,\n        \"rewritten_sql\": \"select datediff(tbl_1.plain_datetime_0, tbl_1.plain_datetime_1) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select last_day(plain_datetime_0) as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select last_day(tbl_1.plain_datetime_0) as a from alice.tbl_1\",\n        \"rewritten_sql_csv\": \"select last_day(tbl_1.plain_datetime_0) as a from alice.tbl_1\",\n        \"skip_pg_test\": true,\n        \"rewritten_sql\": \"select last_day(tbl_1.plain_datetime_0) as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select str_to_date('August 10 2017', '%M %d %Y') as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select str_to_date('August 10 2017', '%M %d %Y') as a from alice.tbl_1\",\n        \"skip_pg_test\": true,\n        \"skip_csv_test\": true,\n        \"rewritten_sql\": \"select str_to_date('August 10 2017', '%M %d %Y') as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"select date_format(plain_datetime_0, '%Y-%m-%d %H:%i:%S') as a from alice.tbl_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select date_format(tbl_1.plain_datetime_0, '%Y-%m-%d %H:%i:%S') as a from alice.tbl_1\",\n        \"skip_pg_test\": true,\n        \"skip_csv_test\": true,\n        \"rewritten_sql\": \"select date_format(tbl_1.plain_datetime_0, '%Y-%m-%d %H:%i:%S') as a from alice.tbl_1\"\n      },\n      {\n        \"sql\": \"SELECT t_0.b4 FROM  (SELECT tbl_1.plain_string_0 as b4 FROM alice.tbl_1 WHERE tbl_1.plain_string_0 = '123') AS t_0 GROUP BY t_0.b4 HAVING count(1)>=4;;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select tbl_1.plain_string_0 as b4 from alice.tbl_1 where tbl_1.plain_string_0='123' group by tbl_1.plain_string_0 having (count(1)>=4) and (count(1)>=4)\",\n        \"rewritten_sql_pg\": \"select tbl_1.plain_string_0 as b4 from alice.tbl_1 where tbl_1.plain_string_0='123' group by tbl_1.plain_string_0 having (count(1)>=4) and (count(1)>=4)\",\n        \"rewritten_sql_csv\": \"select tbl_1.plain_string_0 as b4 from alice.tbl_1 where tbl_1.plain_string_0='123' group by tbl_1.plain_string_0 having (count(1)>=4) and (count(1)>=4)\",\n        \"rewritten_sql\": \"select any_value(tbl_1.plain_string_0) as b4 from alice.tbl_1 where tbl_1.plain_string_0='123' group by tbl_1.plain_string_0 having (count(1)>=4) and (count(1)>=4)\"\n      },\n      {\n        \"sql\": \"SELECT CASE WHEN (t_0.b4='1' OR t_0.b4='1' OR t_0.b4='2') THEN '3' ELSE '4' END AS bank_type, count(1) AS expr_24 FROM (SELECT str_to_date(plain_string_0, '%Y-%m-%d') AS p0, plain_string_1 as b4, plain_string_2 as b5 FROM alice.tbl_1 WHERE (str_to_date(plain_string_0, '%Y-%m-%d')=str_to_date('2023-01-10', '%Y-%m-%d'))) AS t_0 GROUP BY t_0.b4 HAVING count(1)>=4;;\",\n        \"skip_projection\": false,\n        \"skip_odps_test\": true,\n        \"skip_pg_test\": true,\n        \"skip_csv_test\": true,\n        \"rewritten_sql\": \"select case when (any_value(tbl_1.plain_string_1)='1' or any_value(tbl_1.plain_string_1)='1' or any_value(tbl_1.plain_string_1)='2') then '3' else '4' end as bank_type,count(1) as expr_24 from alice.tbl_1 where str_to_date(tbl_1.plain_string_0, '%Y-%m-%d')=str_to_date('2023-01-10', '%Y-%m-%d') group by tbl_1.plain_string_1 having (count(1)>=4) and (count(1)>=4)\"\n      },\n      {\n        \"sql\": \"select count(*) from (select plain_float_0 + plain_float_1 as f1 from alice.tbl_1) as ta join alice.tbl_2 on ta.f1 = tbl_2.plain_float_1;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select count(1) as expr_242 from (select tbl_1.plain_float_0+tbl_1.plain_float_1 as f1 from alice.tbl_1) as ta join alice.tbl_2 on ta.f1=tbl_2.plain_float_1\",\n        \"rewritten_sql_pg\": \"select count(1) as expr_242 from (select tbl_1.plain_float_0+tbl_1.plain_float_1 as f1 from alice.tbl_1) as ta join alice.tbl_2 on ta.f1=tbl_2.plain_float_1\",\n        \"rewritten_sql_csv\": \"select count(1) as expr_242 from (select tbl_1.plain_float_0+tbl_1.plain_float_1 as f1 from alice.tbl_1) as ta join alice.tbl_2 on ta.f1=tbl_2.plain_float_1\",\n        \"rewritten_sql\": \"select count(1) as expr_242 from (select tbl_1.plain_float_0+tbl_1.plain_float_1 as f1 from alice.tbl_1) as ta join alice.tbl_2 on ta.f1=tbl_2.plain_float_1\"\n      },\n      {\n        \"sql\": \"select bank_type, count(1) from (select case when t1.b4 in ('1', '2', '3') then '1' else '2' end as bank_type from (select str_to_date(plain_string_0, '%Y-%m-%d') as partition_date, plain_string_1 as b4, plain_string_2 as b5 from alice.tbl_1) t1 where t1.partition_date = '2022-02-02') tt group by bank_type;\",\n        \"skip_projection\": false,\n        \"skip_odps_test\": true,\n        \"skip_pg_test\": true,\n        \"skip_csv_test\": true,\n        \"rewritten_sql\": \"select any_value(t_0.bank_type) as bank_type,count(1) as expr_123 from (select case when (tbl_1.plain_string_1='1' or tbl_1.plain_string_1='2' or tbl_1.plain_string_1='3') then '1' else '2' end as bank_type from alice.tbl_1 where str_to_date(tbl_1.plain_string_0, '%Y-%m-%d')='2022-02-02') as t_0 group by t_0.bank_type having count(1)>=4\"\n      },\n      {\n        \"sql\": \"select a.plain_int_0, b.plain_int_0 from alice.tbl_0 a left join (select distinct plain_int_0, plain_int_1 from alice.tbl_1) b on a.plain_int_0 = b.plain_int_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select a.plain_int_0,b.plain_int_0 from alice.tbl_0 as a left join (select tbl_1.plain_int_0 from alice.tbl_1 group by tbl_1.plain_int_0,tbl_1.plain_int_1) as b on a.plain_int_0=b.plain_int_0\",\n        \"rewritten_sql_pg\": \"select a.plain_int_0,b.plain_int_0 from alice.tbl_0 as a left join (select tbl_1.plain_int_0 from alice.tbl_1 group by tbl_1.plain_int_0,tbl_1.plain_int_1) as b on a.plain_int_0=b.plain_int_0\",\n        \"rewritten_sql_csv\": \"select a.plain_int_0,b.plain_int_0 from alice.tbl_0 as a left join (select tbl_1.plain_int_0 from alice.tbl_1 group by tbl_1.plain_int_0,tbl_1.plain_int_1) as b on a.plain_int_0=b.plain_int_0\",\n        \"rewritten_sql\": \"select a.plain_int_0,b.expr_217 from alice.tbl_0 as a left join (select any_value(tbl_1.plain_int_0) as expr_217 from alice.tbl_1 group by tbl_1.plain_int_0,tbl_1.plain_int_1) as b on a.plain_int_0=b.expr_217\"\n      },\n      {\n        \"sql\": \"select a.plain_int_0 from alice.tbl_0 a left join (select distinct plain_int_0, plain_int_1 from alice.tbl_1) b on a.plain_int_0 = b.plain_int_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select a.plain_int_0 from alice.tbl_0 as a left join (select tbl_1.plain_int_0 from alice.tbl_1 group by tbl_1.plain_int_0,tbl_1.plain_int_1) as b on a.plain_int_0=b.plain_int_0\",\n        \"rewritten_sql_pg\": \"select a.plain_int_0 from alice.tbl_0 as a left join (select tbl_1.plain_int_0 from alice.tbl_1 group by tbl_1.plain_int_0,tbl_1.plain_int_1) as b on a.plain_int_0=b.plain_int_0\",\n        \"rewritten_sql_csv\": \"select a.plain_int_0 from alice.tbl_0 as a left join (select tbl_1.plain_int_0 from alice.tbl_1 group by tbl_1.plain_int_0,tbl_1.plain_int_1) as b on a.plain_int_0=b.plain_int_0\",\n        \"rewritten_sql\": \"select a.plain_int_0 from alice.tbl_0 as a left join (select any_value(tbl_1.plain_int_0) as expr_217 from alice.tbl_1 group by tbl_1.plain_int_0,tbl_1.plain_int_1) as b on a.plain_int_0=b.expr_217\"\n      },\n      {\n        \"sql\": \"select plain_int_0, 'a' from alice.tbl_0 UNION ALL select plain_int_0, 'a' from alice.tbl_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t_0.plain_int_0,t_0.expr_244 from ((select tbl_0.plain_int_0,'a' as expr_244 from alice.tbl_0) union all (select tbl_0.plain_int_0,'a' as expr_244 from alice.tbl_0)) as t_0\",\n        \"rewritten_sql_pg\": \"select t_0.plain_int_0,t_0.expr_244 from ((select tbl_0.plain_int_0,'a' as expr_244 from alice.tbl_0) union all (select tbl_0.plain_int_0,'a' as expr_244 from alice.tbl_0)) as t_0\",\n        \"rewritten_sql_csv\": \"select t_0.plain_int_0,t_0.expr_244 from ((select tbl_0.plain_int_0,'a' as expr_244 from alice.tbl_0) union all (select tbl_0.plain_int_0,'a' as expr_244 from alice.tbl_0)) as t_0\",\n        \"rewritten_sql\": \"select t_0.plain_int_0,t_0.expr_244 from ((select tbl_0.plain_int_0,'a' as expr_244 from alice.tbl_0) union all (select tbl_0.plain_int_0,'a' as expr_244 from alice.tbl_0)) as t_0\"\n      },\n      {\n        \"sql\": \"select avg(plain_int_0) from alice.tbl_0 union all select sum(plain_int_0) from alice.tbl_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t_0.expr_243 from ((select avg(tbl_0.plain_int_0) as expr_243 from alice.tbl_0) union all (select cast(sum(tbl_0.plain_int_0) as decimal) as expr_243 from alice.tbl_0)) as t_0\",\n        \"rewritten_sql_pg\": \"select t_0.expr_243 from ((select avg(tbl_0.plain_int_0) as expr_243 from alice.tbl_0) union all (select cast(sum(tbl_0.plain_int_0) as numeric(65, 30)) as expr_243 from alice.tbl_0)) as t_0\",\n        \"rewritten_sql_csv\": \"select t_0.expr_243 from ((select avg(tbl_0.plain_int_0) as expr_243 from alice.tbl_0) union all (select cast(sum(tbl_0.plain_int_0) as numeric) as expr_243 from alice.tbl_0)) as t_0\",\n        \"rewritten_sql\": \"select t_0.expr_243 from ((select avg(tbl_0.plain_int_0) as expr_243 from alice.tbl_0) union all (select cast(sum(tbl_0.plain_int_0) as decimal(65, 30)) as expr_243 from alice.tbl_0)) as t_0\"\n      },\n      {\n        \"sql\": \"select replace(plain_string_0, 'a', 'b') as res1 from alice.tbl_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select replace(tbl_0.plain_string_0, 'a', 'b') as res1 from alice.tbl_0\",\n        \"rewritten_sql_pg\": \"select replace(tbl_0.plain_string_0, 'a', 'b') as res1 from alice.tbl_0\",\n        \"rewritten_sql_csv\": \"select replace(tbl_0.plain_string_0, 'a', 'b') as res1 from alice.tbl_0\",\n        \"rewritten_sql\": \"select replace(tbl_0.plain_string_0, 'a', 'b') as res1 from alice.tbl_0\"\n      },\n      {\n        \"sql\": \"SELECT a.SVC_NUM AS SVC_NUM, a.plain_string_2, IF((d.plain_int_1 <= 30) OR d.plain_int_1 IS NULL, '1', IF(d.plain_int_1 <= 100, '2', '3')) AS plain_int_1, IF(a.compare_string_0 = '1', '是', '否') AS compare_string_0, IF((a.compare_int_1 <= 21) OR a.compare_int_1 IS NULL, '1', '2') AS compare_int_1 FROM (SELECT a.plain_int_2 AS SVC_NUM, a.plain_string_2, c.compare_string_0, c.compare_int_1 FROM alice.tbl_2 AS a LEFT JOIN (SELECT plain_int_0, compare_string_0, compare_int_1 FROM alice.tbl_0 WHERE plain_string_1 = '202505') AS c ON a.plain_int_2 = c.plain_int_0) AS a LEFT JOIN (SELECT plain_int_0, plain_int_1 FROM alice.tbl_1 WHERE plain_string_1 = '202505') AS d ON a.SVC_NUM = d.plain_int_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select a.plain_int_2 as SVC_NUM,a.plain_string_2,if((d.plain_int_1<=30) or d.plain_int_1 is null, '1', if(d.plain_int_1<=100, '2', '3')) as plain_int_1,if(a.compare_string_0='1', '是', '否') as compare_string_0,if((a.compare_int_1<=21) or a.compare_int_1 is null, '1', '2') as compare_int_1 from (select a.plain_int_2,a.plain_string_2,c.compare_int_1,c.compare_string_0 from (alice.tbl_2 as a left join (select tbl_0.compare_int_1,tbl_0.compare_string_0,tbl_0.plain_int_0 from alice.tbl_0 where tbl_0.plain_string_1='202505') as c on a.plain_int_2=c.plain_int_0)) as a left join (select tbl_1.plain_int_0,tbl_1.plain_int_1 from alice.tbl_1 where tbl_1.plain_string_1='202505') as d on a.plain_int_2=d.plain_int_0\",\n        \"rewritten_sql_pg\": \"select a.plain_int_2 as SVC_NUM,a.plain_string_2,if((d.plain_int_1<=30) or d.plain_int_1 is null, '1', if(d.plain_int_1<=100, '2', '3')) as plain_int_1,if(a.compare_string_0='1', '是', '否') as compare_string_0,if((a.compare_int_1<=21) or a.compare_int_1 is null, '1', '2') as compare_int_1 from (select a.plain_int_2,a.plain_string_2,c.compare_int_1,c.compare_string_0 from (alice.tbl_2 as a left join (select tbl_0.compare_int_1,tbl_0.compare_string_0,tbl_0.plain_int_0 from alice.tbl_0 where tbl_0.plain_string_1='202505') as c on a.plain_int_2=c.plain_int_0)) as a left join (select tbl_1.plain_int_0,tbl_1.plain_int_1 from alice.tbl_1 where tbl_1.plain_string_1='202505') as d on a.plain_int_2=d.plain_int_0\",\n        \"rewritten_sql_csv\": \"select a.plain_int_2 as SVC_NUM,a.plain_string_2,if((d.plain_int_1<=30) or d.plain_int_1 is null, '1', if(d.plain_int_1<=100, '2', '3')) as plain_int_1,if(a.compare_string_0='1', '是', '否') as compare_string_0,if((a.compare_int_1<=21) or a.compare_int_1 is null, '1', '2') as compare_int_1 from (select a.plain_int_2,a.plain_string_2,c.compare_int_1,c.compare_string_0 from (alice.tbl_2 as a left join (select tbl_0.compare_int_1,tbl_0.compare_string_0,tbl_0.plain_int_0 from alice.tbl_0 where tbl_0.plain_string_1='202505') as c on a.plain_int_2=c.plain_int_0)) as a left join (select tbl_1.plain_int_0,tbl_1.plain_int_1 from alice.tbl_1 where tbl_1.plain_string_1='202505') as d on a.plain_int_2=d.plain_int_0\",\n        \"rewritten_sql\": \"select a.plain_int_2 as SVC_NUM,a.plain_string_2,if(d.plain_int_1<=30 or d.plain_int_1 is null, '1', if(d.plain_int_1<=100, '2', '3')) as plain_int_1,if(a.compare_string_0='1', '是', '否') as compare_string_0,if(a.compare_int_1<=21 or a.compare_int_1 is null, '1', '2') as compare_int_1 from (select a.plain_int_2,a.plain_string_2,c.compare_int_1,c.compare_string_0 from (alice.tbl_2 as a left join (select tbl_0.compare_int_1,tbl_0.compare_string_0,tbl_0.plain_int_0 from alice.tbl_0 where tbl_0.plain_string_1='202505') as c on a.plain_int_2=c.plain_int_0)) as a left join (select tbl_1.plain_int_0,tbl_1.plain_int_1 from alice.tbl_1 where tbl_1.plain_string_1='202505') as d on a.plain_int_2=d.plain_int_0\"\n      },\n      {\n        \"sql\": \"SELECT t0.plain_int_0 AS partkey, SUM(t0.plain_int_1 * t0.plain_int_0) AS value FROM alice.tbl_0 t0, alice.tbl_1 t1, alice.tbl_2 t2 WHERE t0.plain_int_1 = t1.plain_int_0 AND t1.plain_int_1 = t2.plain_int_0 AND t2.plain_string_0 = 'GERMANY' GROUP BY t0.plain_int_0 HAVING SUM(t0.plain_int_1 * t0.plain_int_0) > (SELECT SUM(t0_sub.plain_int_1 * t0_sub.plain_int_0) * 0.0000001000 FROM alice.tbl_0 t0_sub, alice.tbl_1 t1_sub, alice.tbl_2 t2_sub WHERE t0_sub.plain_int_1 = t1_sub.plain_int_0 AND t1_sub.plain_int_1 = t2_sub.plain_int_0 AND t2_sub.plain_string_0 = 'GERMANY') ORDER BY value DESC;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t_0.partkey as partkey,t_0.expr_361 as value from (select t0.plain_int_0 as partkey,t0.expr_361 as value,t0.expr_361 from (select sum(t0.plain_int_1*t0.plain_int_0) as expr_361,t0.plain_int_0,count(1) as expr_726 from ((select t0.plain_int_0,t0.plain_int_1,t1.plain_int_1 from (alice.tbl_0 as t0 join alice.tbl_1 as t1 on t0.plain_int_1=t1.plain_int_0)) as t0 join (select t2.plain_int_0 from alice.tbl_2 as t2 where t2.plain_string_0='GERMANY') as t2 on t0.plain_int_1=t2.plain_int_0) group by t0.plain_int_0 having count(1)>=4) as t0 join (select sum(t0_sub.plain_int_1*t0_sub.plain_int_0)*0.0000001000 as expr_723 from ((select t0_sub.plain_int_0,t0_sub.plain_int_1,t1_sub.plain_int_1 from (alice.tbl_0 as t0_sub join alice.tbl_1 as t1_sub on t0_sub.plain_int_1=t1_sub.plain_int_0)) as t0_sub join (select t2_sub.plain_int_0 from alice.tbl_2 as t2_sub where t2_sub.plain_string_0='GERMANY') as t2_sub on t0_sub.plain_int_1=t2_sub.plain_int_0)) as t_1 where t0.expr_361>t_1.expr_723 order by t0.expr_361 desc) as t_0\",\n        \"rewritten_sql_pg\": \"select t_0.partkey as partkey,t_0.expr_361 as value from (select t0.plain_int_0 as partkey,t0.expr_361 as value,t0.expr_361 from (select sum(t0.plain_int_1*t0.plain_int_0) as expr_361,t0.plain_int_0,count(1) as expr_726 from ((select t0.plain_int_0,t0.plain_int_1,t1.plain_int_1 from (alice.tbl_0 as t0 join alice.tbl_1 as t1 on t0.plain_int_1=t1.plain_int_0)) as t0 join (select t2.plain_int_0 from alice.tbl_2 as t2 where t2.plain_string_0='GERMANY') as t2 on t0.plain_int_1=t2.plain_int_0) group by t0.plain_int_0 having count(1)>=4) as t0 join (select sum(t0_sub.plain_int_1*t0_sub.plain_int_0)*0.0000001000 as expr_723 from ((select t0_sub.plain_int_0,t0_sub.plain_int_1,t1_sub.plain_int_1 from (alice.tbl_0 as t0_sub join alice.tbl_1 as t1_sub on t0_sub.plain_int_1=t1_sub.plain_int_0)) as t0_sub join (select t2_sub.plain_int_0 from alice.tbl_2 as t2_sub where t2_sub.plain_string_0='GERMANY') as t2_sub on t0_sub.plain_int_1=t2_sub.plain_int_0)) as t_1 where t0.expr_361>t_1.expr_723 order by t0.expr_361 desc) as t_0\",\n        \"rewritten_sql_csv\": \"select t_0.partkey as partkey,t_0.expr_361 as value from (select t0.plain_int_0 as partkey,t0.expr_361 as value,t0.expr_361 from (select sum(t0.plain_int_1*t0.plain_int_0) as expr_361,t0.plain_int_0,count(1) as expr_726 from ((select t0.plain_int_0,t0.plain_int_1,t1.plain_int_1 from (alice.tbl_0 as t0 join alice.tbl_1 as t1 on t0.plain_int_1=t1.plain_int_0)) as t0 join (select t2.plain_int_0 from alice.tbl_2 as t2 where t2.plain_string_0='GERMANY') as t2 on t0.plain_int_1=t2.plain_int_0) group by t0.plain_int_0 having count(1)>=4) as t0 cross join (select sum(t0_sub.plain_int_1*t0_sub.plain_int_0)*0.0000001000 as expr_723 from ((select t0_sub.plain_int_0,t0_sub.plain_int_1,t1_sub.plain_int_1 from (alice.tbl_0 as t0_sub join alice.tbl_1 as t1_sub on t0_sub.plain_int_1=t1_sub.plain_int_0)) as t0_sub join (select t2_sub.plain_int_0 from alice.tbl_2 as t2_sub where t2_sub.plain_string_0='GERMANY') as t2_sub on t0_sub.plain_int_1=t2_sub.plain_int_0)) as t_1 where t0.expr_361>t_1.expr_723 order by t0.expr_361 desc) as t_0\",\n        \"rewritten_sql\": \"select t_0.partkey as partkey,t_0.expr_361 as value from (select t0.expr_97 as partkey,t0.expr_361 as value,t0.expr_361 from (select sum(t0.plain_int_1*t0.plain_int_0) as expr_361,any_value(t0.plain_int_0) as expr_97,count(1) as expr_726 from ((select t0.plain_int_0,t0.plain_int_1,t1.plain_int_1 from (alice.tbl_0 as t0 join alice.tbl_1 as t1 on t0.plain_int_1=t1.plain_int_0)) as t0 join (select t2.plain_int_0 from alice.tbl_2 as t2 where t2.plain_string_0='GERMANY') as t2 on t0.plain_int_1=t2.plain_int_0) group by t0.plain_int_0 having count(1)>=4) as t0 join (select sum(t0_sub.plain_int_1*t0_sub.plain_int_0)*0.0000001000 as expr_723 from ((select t0_sub.plain_int_0,t0_sub.plain_int_1,t1_sub.plain_int_1 from (alice.tbl_0 as t0_sub join alice.tbl_1 as t1_sub on t0_sub.plain_int_1=t1_sub.plain_int_0)) as t0_sub join (select t2_sub.plain_int_0 from alice.tbl_2 as t2_sub where t2_sub.plain_string_0='GERMANY') as t2_sub on t0_sub.plain_int_1=t2_sub.plain_int_0)) as t_1 where t0.expr_361>t_1.expr_723 order by t0.expr_361 desc) as t_0\"\n      },\n      {\n        \"sql\": \"select t0.plain_int_0, plain_int_1, plain_int_2 from alice.tbl_0 t0 where plain_int_1 = (select max(plain_int_1) from alice.tbl_0 t00 where t0.plain_int_2 = t00.plain_int_2);\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t0.plain_int_0,t0.plain_int_1,t0.plain_int_2 from alice.tbl_0 as t0 left join (select max(t00.plain_int_1) as expr_241,t00.plain_int_2,count(1) as expr_242 from alice.tbl_0 as t00 group by t00.plain_int_2 having count(1)>=4) as t_1 on t0.plain_int_2=t_1.plain_int_2 where t0.plain_int_1=t_1.expr_241\",\n        \"rewritten_sql_pg\": \"select t0.plain_int_0,t0.plain_int_1,t0.plain_int_2 from alice.tbl_0 as t0 left join (select max(t00.plain_int_1) as expr_241,t00.plain_int_2,count(1) as expr_242 from alice.tbl_0 as t00 group by t00.plain_int_2 having count(1)>=4) as t_1 on t0.plain_int_2=t_1.plain_int_2 where t0.plain_int_1=t_1.expr_241\",\n        \"rewritten_sql_csv\": \"select t0.plain_int_0,t0.plain_int_1,t0.plain_int_2 from alice.tbl_0 as t0 left join (select max(t00.plain_int_1) as expr_241,t00.plain_int_2,count(1) as expr_242 from alice.tbl_0 as t00 group by t00.plain_int_2 having count(1)>=4) as t_1 on t0.plain_int_2=t_1.plain_int_2 where t0.plain_int_1=t_1.expr_241\",\n        \"rewritten_sql\": \"select t0.plain_int_0,t0.plain_int_1,t0.plain_int_2 from alice.tbl_0 as t0 left join (select max(t00.plain_int_1) as expr_241,any_value(t00.plain_int_2) as expr_219,count(1) as expr_242 from alice.tbl_0 as t00 group by t00.plain_int_2 having count(1)>=4) as t_1 on t0.plain_int_2=t_1.expr_219 where t0.plain_int_1=t_1.expr_241\"\n      },\n      {\n        \"sql\": \"SELECT t1.plain_int_0,t1.plain_string_0,t3.gb_gb_gb_int_0,t2.plain_string_0,t2.plain_string_1,t1.plain_string_1,t1.plain_string_2,t1.join_string_0 FROM alice.tbl_2 t2,alice.tbl_1 t1,alice.tbl_0 t0,alice.tbl_3 t3,alice.UPPER_table t4 WHERE t2.groupby_int_0=t3.jn_jn_jn_int_0 AND t1.groupby_int_1=t3.cp_cp_cp_int_0 AND t2.plain_int_1=15 AND t2.groupby_string_0 LIKE '%BRASS' AND t1.groupby_int_2=t3.pl_jn_cp_int_0 AND t3.jn_jn_jn_int_0=t4.groupby_int_1 AND t4.JOIN_string_0='EUROPE' AND t3.pl_jn_cp_int_0=(SELECT MIN(t3.pl_jn_cp_int_0) FROM alice.tbl_0 t0,alice.tbl_1 t1,alice.tbl_3 t3,alice.UPPER_table t4 WHERE t2.groupby_int_0=t3.jn_jn_jn_int_0 AND t1.groupby_int_1=t3.cp_cp_cp_int_0 AND t1.groupby_int_2=t3.pl_jn_cp_int_0 AND t3.jn_jn_jn_int_0=t4.groupby_int_1 AND t4.JOIN_string_0='EUROPE') ORDER BY t1.plain_int_0 DESC,t3.gb_gb_gb_int_0,t1.plain_string_0,t2.plain_string_0;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t2.plain_int_0,t2.plain_string_0,t2.gb_gb_gb_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_1,t2.plain_string_2,t2.join_string_0 from (select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.pl_jn_cp_int_0,t2.join_string_0,t2.plain_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.pl_jn_cp_int_0,t2.join_string_0,t2.plain_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.jn_jn_jn_int_0,t2.pl_jn_cp_int_0,t1.join_string_0,t1.plain_int_0,t1.plain_string_0,t1.plain_string_1,t1.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t3.cp_cp_cp_int_0,t3.gb_gb_gb_int_0,t3.jn_jn_jn_int_0,t3.pl_jn_cp_int_0 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1 from alice.tbl_2 as t2 where (t2.plain_int_1=15) and (t2.groupby_string_0 like '%BRASS')) as t2 join alice.tbl_3 as t3 on t2.groupby_int_0=t3.jn_jn_jn_int_0)) as t2 join alice.tbl_1 as t1 on (t2.cp_cp_cp_int_0=t1.groupby_int_1) and (t2.pl_jn_cp_int_0=t1.groupby_int_2))) as t2 join (select t4.groupby_int_1 from alice.UPPER_table as t4 where t4.JOIN_string_0='EUROPE') as t4 on t2.jn_jn_jn_int_0=t4.groupby_int_1)) as t2 join alice.tbl_0 as t0)) as t2 left join (select min(t4.pl_jn_cp_int_0) as expr_621,t4.jn_jn_jn_int_0,count(1) as expr_622 from (alice.tbl_0 as t0 join (select t1.jn_jn_jn_int_0,t1.pl_jn_cp_int_0 from ((select t3.jn_jn_jn_int_0,t3.pl_jn_cp_int_0 from (alice.tbl_1 as t1 join alice.tbl_3 as t3 on (t1.groupby_int_1=t3.cp_cp_cp_int_0) and (t1.groupby_int_2=t3.pl_jn_cp_int_0))) as t1 join (select t4.groupby_int_1 from alice.UPPER_table as t4 where t4.JOIN_string_0='EUROPE') as t4 on t1.jn_jn_jn_int_0=t4.groupby_int_1)) as t4) group by t4.jn_jn_jn_int_0 having count(1)>=4) as t_1 on t2.groupby_int_0=t_1.jn_jn_jn_int_0 where t2.pl_jn_cp_int_0=t_1.expr_621 order by t2.plain_int_0 desc,t2.gb_gb_gb_int_0,t2.plain_string_0,t2.plain_string_0\",\n        \"rewritten_sql_pg\": \"select t2.plain_int_0,t2.plain_string_0,t2.gb_gb_gb_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_1,t2.plain_string_2,t2.join_string_0 from (select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.pl_jn_cp_int_0,t2.join_string_0,t2.plain_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.pl_jn_cp_int_0,t2.join_string_0,t2.plain_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.jn_jn_jn_int_0,t2.pl_jn_cp_int_0,t1.join_string_0,t1.plain_int_0,t1.plain_string_0,t1.plain_string_1,t1.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t3.cp_cp_cp_int_0,t3.gb_gb_gb_int_0,t3.jn_jn_jn_int_0,t3.pl_jn_cp_int_0 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1 from alice.tbl_2 as t2 where (t2.plain_int_1=15) and (t2.groupby_string_0 like '%BRASS')) as t2 join alice.tbl_3 as t3 on t2.groupby_int_0=t3.jn_jn_jn_int_0)) as t2 join alice.tbl_1 as t1 on (t2.cp_cp_cp_int_0=t1.groupby_int_1) and (t2.pl_jn_cp_int_0=t1.groupby_int_2))) as t2 join (select t4.groupby_int_1 from alice.UPPER_table as t4 where t4.JOIN_string_0='EUROPE') as t4 on t2.jn_jn_jn_int_0=t4.groupby_int_1)) as t2 join alice.tbl_0 as t0)) as t2 left join (select min(t4.pl_jn_cp_int_0) as expr_621,t4.jn_jn_jn_int_0,count(1) as expr_622 from (alice.tbl_0 as t0 join (select t1.jn_jn_jn_int_0,t1.pl_jn_cp_int_0 from ((select t3.jn_jn_jn_int_0,t3.pl_jn_cp_int_0 from (alice.tbl_1 as t1 join alice.tbl_3 as t3 on (t1.groupby_int_1=t3.cp_cp_cp_int_0) and (t1.groupby_int_2=t3.pl_jn_cp_int_0))) as t1 join (select t4.groupby_int_1 from alice.UPPER_table as t4 where t4.JOIN_string_0='EUROPE') as t4 on t1.jn_jn_jn_int_0=t4.groupby_int_1)) as t4) group by t4.jn_jn_jn_int_0 having count(1)>=4) as t_1 on t2.groupby_int_0=t_1.jn_jn_jn_int_0 where t2.pl_jn_cp_int_0=t_1.expr_621 order by t2.plain_int_0 desc,t2.gb_gb_gb_int_0,t2.plain_string_0,t2.plain_string_0\",\n        \"rewritten_sql_csv\": \"select t2.plain_int_0,t2.plain_string_0,t2.gb_gb_gb_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_1,t2.plain_string_2,t2.join_string_0 from (select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.pl_jn_cp_int_0,t2.join_string_0,t2.plain_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.pl_jn_cp_int_0,t2.join_string_0,t2.plain_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.jn_jn_jn_int_0,t2.pl_jn_cp_int_0,t1.join_string_0,t1.plain_int_0,t1.plain_string_0,t1.plain_string_1,t1.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t3.cp_cp_cp_int_0,t3.gb_gb_gb_int_0,t3.jn_jn_jn_int_0,t3.pl_jn_cp_int_0 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1 from alice.tbl_2 as t2 where (t2.plain_int_1=15) and (t2.groupby_string_0 like '%BRASS')) as t2 join alice.tbl_3 as t3 on t2.groupby_int_0=t3.jn_jn_jn_int_0)) as t2 join alice.tbl_1 as t1 on (t2.cp_cp_cp_int_0=t1.groupby_int_1) and (t2.pl_jn_cp_int_0=t1.groupby_int_2))) as t2 join (select t4.groupby_int_1 from alice.UPPER_table as t4 where t4.JOIN_string_0='EUROPE') as t4 on t2.jn_jn_jn_int_0=t4.groupby_int_1)) as t2 cross join alice.tbl_0 as t0)) as t2 left join (select min(t4.pl_jn_cp_int_0) as expr_621,t4.jn_jn_jn_int_0,count(1) as expr_622 from (alice.tbl_0 as t0 cross join (select t1.jn_jn_jn_int_0,t1.pl_jn_cp_int_0 from ((select t3.jn_jn_jn_int_0,t3.pl_jn_cp_int_0 from (alice.tbl_1 as t1 join alice.tbl_3 as t3 on (t1.groupby_int_1=t3.cp_cp_cp_int_0) and (t1.groupby_int_2=t3.pl_jn_cp_int_0))) as t1 join (select t4.groupby_int_1 from alice.UPPER_table as t4 where t4.JOIN_string_0='EUROPE') as t4 on t1.jn_jn_jn_int_0=t4.groupby_int_1)) as t4) group by t4.jn_jn_jn_int_0 having count(1)>=4) as t_1 on t2.groupby_int_0=t_1.jn_jn_jn_int_0 where t2.pl_jn_cp_int_0=t_1.expr_621 order by t2.plain_int_0 desc,t2.gb_gb_gb_int_0,t2.plain_string_0,t2.plain_string_0\",\n        \"rewritten_sql\": \"select t2.plain_int_0,t2.plain_string_0,t2.gb_gb_gb_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_1,t2.plain_string_2,t2.join_string_0 from (select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.pl_jn_cp_int_0,t2.join_string_0,t2.plain_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.pl_jn_cp_int_0,t2.join_string_0,t2.plain_int_0,t2.plain_string_0,t2.plain_string_1,t2.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t2.gb_gb_gb_int_0,t2.jn_jn_jn_int_0,t2.pl_jn_cp_int_0,t1.join_string_0,t1.plain_int_0,t1.plain_string_0,t1.plain_string_1,t1.plain_string_2 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1,t3.cp_cp_cp_int_0,t3.gb_gb_gb_int_0,t3.jn_jn_jn_int_0,t3.pl_jn_cp_int_0 from ((select t2.groupby_int_0,t2.plain_string_0,t2.plain_string_1 from alice.tbl_2 as t2 where (t2.plain_int_1=15) and (t2.groupby_string_0 like '%BRASS')) as t2 join alice.tbl_3 as t3 on t2.groupby_int_0=t3.jn_jn_jn_int_0)) as t2 join alice.tbl_1 as t1 on (t2.cp_cp_cp_int_0=t1.groupby_int_1) and (t2.pl_jn_cp_int_0=t1.groupby_int_2))) as t2 join (select t4.groupby_int_1 from alice.UPPER_table as t4 where t4.JOIN_string_0='EUROPE') as t4 on t2.jn_jn_jn_int_0=t4.groupby_int_1)) as t2 join alice.tbl_0 as t0)) as t2 left join (select min(t4.pl_jn_cp_int_0) as expr_621,any_value(t4.jn_jn_jn_int_0) as expr_613,count(1) as expr_622 from (alice.tbl_0 as t0 join (select t1.jn_jn_jn_int_0,t1.pl_jn_cp_int_0 from ((select t3.jn_jn_jn_int_0,t3.pl_jn_cp_int_0 from (alice.tbl_1 as t1 join alice.tbl_3 as t3 on (t1.groupby_int_1=t3.cp_cp_cp_int_0) and (t1.groupby_int_2=t3.pl_jn_cp_int_0))) as t1 join (select t4.groupby_int_1 from alice.UPPER_table as t4 where t4.JOIN_string_0='EUROPE') as t4 on t1.jn_jn_jn_int_0=t4.groupby_int_1)) as t4) group by t4.jn_jn_jn_int_0 having count(1)>=4) as t_1 on t2.groupby_int_0=t_1.expr_613 where t2.pl_jn_cp_int_0=t_1.expr_621 order by t2.plain_int_0 desc,t2.gb_gb_gb_int_0,t2.plain_string_0,t2.plain_string_0\"\n      },\n      {\n        \"sql\": \"SELECT t1.plain_int_1 AS o_orderpriority,count(*) AS order_count FROM alice.tbl_0 t1 WHERE t1.plain_int_0>=3 AND t1.plain_int_0<7 AND EXISTS(SELECT * FROM alice.tbl_1 t0 WHERE t0.plain_string_0=t1.plain_string_0 AND t0.plain_int_0<t0.plain_int_1) GROUP BY o_orderpriority ORDER BY o_orderpriority;\",\n        \"skip_projection\": false,\n        \"rewritten_sql_odps\": \"select t1.plain_int_1 as o_orderpriority,count(1) as order_count from alice.tbl_0 as t1 where ((t1.plain_int_0>=3) and (t1.plain_int_0<7)) and (exists (select t0.plain_string_0 from alice.tbl_1 as t0 where (t0.plain_int_0<t0.plain_int_1) and (t1.plain_string_0=t0.plain_string_0))) group by t1.plain_int_1 having count(1)>=4 order by t1.plain_int_1\",\n        \"rewritten_sql_pg\": \"select t1.plain_int_1 as o_orderpriority,count(1) as order_count from alice.tbl_0 as t1 where ((t1.plain_int_0>=3) and (t1.plain_int_0<7)) and (exists (select t0.plain_string_0 from alice.tbl_1 as t0 where (t0.plain_int_0<t0.plain_int_1) and (t1.plain_string_0=t0.plain_string_0))) group by t1.plain_int_1 having count(1)>=4 order by t1.plain_int_1\",\n        \"rewritten_sql_csv\": \"select t1.plain_int_1 as o_orderpriority,count(1) as order_count from alice.tbl_0 as t1 where ((t1.plain_int_0>=3) and (t1.plain_int_0<7)) and (exists (select t0.plain_string_0 from alice.tbl_1 as t0 where (t0.plain_int_0<t0.plain_int_1) and (t1.plain_string_0=t0.plain_string_0))) group by t1.plain_int_1 having count(1)>=4 order by t1.plain_int_1\",\n        \"rewritten_sql\": \"select any_value(t1.plain_int_1) as o_orderpriority,count(1) as order_count from alice.tbl_0 as t1 where ((t1.plain_int_0>=3) and (t1.plain_int_0<7)) and (exists (select t0.plain_string_0 from alice.tbl_1 as t0 where (t0.plain_int_0<t0.plain_int_1) and (t1.plain_string_0=t0.plain_string_0))) group by t1.plain_int_1 having count(1)>=4 order by any_value(t1.plain_int_1)\"\n      }\n    ]\n  }\n]\n"
  },
  {
    "path": "pkg/planner/core/testdata/typical_query_in.json",
    "content": "[\n  {\n    \"name\": \"TestPlanBuilderSimple\",\n    \"cases\": [\n      \"select alice.plain_int_0 from alice.tbl_0 alice join bob.tbl_0 bob on alice.plain_int_1 = bob.plain_int_1\",\n      \"select alice.plain_int_0, bob.plain_string_0 from alice.tbl_0 alice join bob.tbl_0 bob on alice.plain_int_1 = bob.plain_int_1 and alice.plain_string_1 = bob.plain_string_1\",\n      \"select plain_int_0 from alice.tbl_0\",\n      \"select (plain_int_0 = plain_int_1) as f from alice.tbl_0\",\n      \"select plain_int_0 < plain_int_1 from alice.tbl_0\",\n      \"select plain_int_0 <= plain_int_1 from alice.tbl_0\",\n      \"select plain_int_0 > plain_int_1 from alice.tbl_0\",\n      \"select plain_int_0 >= plain_int_1 from alice.tbl_0\",\n      \"select plain_int_0 != plain_int_1 from alice.tbl_0\",\n      \"select plain_int_0 <> plain_int_1 from alice.tbl_0\",\n      \"select plain_string_0 = plain_string_1 from alice.tbl_0\",\n      \"select plain_string_0 > plain_string_1 from alice.tbl_0\",\n      \"select plain_string_0 >= plain_string_1 from alice.tbl_0\",\n      \"select plain_string_0 < plain_string_1 from alice.tbl_0\",\n      \"select plain_string_0 <= plain_string_1 from alice.tbl_0\",\n      \"select plain_string_0 != plain_string_1 from alice.tbl_0\",\n      \"select plain_string_0 <> plain_string_1 from alice.tbl_0\",\n      \"select plain_int_0 + 1 from alice.tbl_0\",\n      \"select plain_int_0 - 1 from alice.tbl_0\",\n      \"select plain_int_0 % 3 from alice.tbl_0\",\n      \"select plain_int_0 + plain_int_1 - 1 from alice.tbl_0\",\n      \"select plain_int_0 - plain_int_1 + 1 from alice.tbl_0\",\n      \"select plain_int_0 % plain_int_1 % 3 from alice.tbl_0\",\n      \"select plain_int_0 - (plain_int_1 - 1) from alice.tbl_0\",\n      \"select plain_int_0 * plain_int_0 from alice.tbl_0\",\n      \"select plain_int_0 * 10 from alice.tbl_0\",\n      \"select plain_int_0 / plain_int_1 from alice.tbl_0\",\n      \"select plain_int_0 / 10 from alice.tbl_0\",\n      \"select plain_int_0, sum(plain_int_1) as new_long from alice.tbl_0 group by plain_int_0 having new_long > 0\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSelection\",\n    \"cases\": [\n      \"select plain_int_0 from (select plain_int_0, sum(plain_int_1) as new_long1 from alice.tbl_0 group by plain_int_0) new_tbl where new_long1 > 0;\",\n      \"select plain_int_0 from (select plain_int_0, sum(plain_int_1) as new_long1 from alice.tbl_0 group by plain_int_0) new_tbl order by new_long1;\",\n      \"select plain_int_0, sum(plain_int_1) as new_long1 from (select plain_int_0, plain_int_1 from alice.tbl_0 where alice.tbl_0.plain_int_0 > 10) new_tbl group by new_tbl.plain_int_0;\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderWindow\",\n    \"cases\": [\n      \"select plain_int_0, rank() over (order by plain_int_1) from alice.tbl_0\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSubQuery\",\n    \"cases\": [\n      \"select plain_int_0 in (select plain_int_1 from alice.tbl_0) from alice.tbl_0;\",\n      \"select t0.plain_int_0 in (select plain_int_1 from alice.tbl_0) as f1 from alice.tbl_0 t0 join alice.tbl_1 t1 where t0.plain_int_0=1234 and t1.plain_int_1=3456\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderInOp\",\n    \"cases\": [\n      \"select plain_int_0 in (1,2,3) from alice.tbl_0\",\n      \"select plain_int_0 in (select plain_int_0 from alice.tbl_1) from alice.tbl_0\",\n      \"select plain_int_0 from alice.tbl_0 where plain_int_0 in (select plain_int_0 from alice.tbl_1)\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderLowerUpperOp\",\n    \"cases\": [\n      \"select lower(plain_string_0) from alice.tbl_0\",\n      \"select upper(plain_string_0) from alice.tbl_0\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderCoalesceOp\",\n    \"cases\": [\"select coalesce(plain_int_0, plain_int_1) from alice.tbl_0\"]\n  },\n  {\n    \"name\": \"TestPlanBuilderLengthOp\",\n    \"cases\": [\"select length(plain_int_0) from alice.tbl_0\"]\n  },\n  {\n    \"name\": \"TestPlanBuilderReplaceOp\",\n    \"cases\": [\"select replace(plain_string_0, 'old', 'new') from alice.tbl_0\"]\n  },\n  {\n    \"name\": \"TestPlanBuildeLikeRlikeOp\",\n    \"cases\": [\n      \"select plain_string_0 from alice.tbl_0 where plain_string_0 like '%xxx';\",\n      \"select plain_string_0 from alice.tbl_0 where plain_string_0 rlike 'f[a-d].*';\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSubstringOp\",\n    \"cases\": [\n      \"select substring(plain_string_0, 2, 3) from alice.tbl_0 where substring(plain_string_0, 2, 3) = 'xxx';\",\n      \"select substring(plain_string_0, 2) from alice.tbl_0 where substring(plain_string_0, 2) = 'xxx';\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderTrimOp\",\n    \"cases\": [\n      \"select trim(plain_string_0) from alice.tbl_0 where trim(plain_string_0) != '';\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuildeLimitOp\",\n    \"cases\": [\"select plain_int_0 from alice.tbl_0 limit 5;\"]\n  },\n  {\n    \"name\": \"TestPlanBuilderInstrOp\",\n    \"cases\": [\"select instr(plain_string_0, plain_string_1) from alice.tbl_0\"]\n  },\n  {\n    \"name\": \"TestPlanBuilderGreatestLeastOp\",\n    \"cases\": [\n      \"select greatest(plain_int_0, plain_int_1, plain_int_2) from alice.tbl_0\",\n      \"select least(plain_int_0, plain_int_1, plain_int_2) from alice.tbl_0\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderLogicalOp\",\n    \"cases\": [\n      \"select (plain_int_0 in (1,2) and plain_int_1 in (2,3)) as f1 from alice.tbl_0\",\n      \"select (plain_int_0 in (1,2) or plain_int_1 in (2,3)) as f1 from alice.tbl_0\",\n      \"select (plain_int_0 in (1,2) xor plain_int_1 in (2,3)) as f1 from alice.tbl_0\",\n      \"select not(plain_int_0 in (1,2)) as f1 from alice.tbl_0\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderMathOp\",\n    \"cases\": [\n      \"select sin(plain_int_0) as f1 from alice.tbl_0\",\n      \"select cos(plain_int_0) as f1 from alice.tbl_0\",\n      \"select tan(plain_int_0) as f1 from alice.tbl_0\",\n      \"select abs(plain_int_0) as f1 from alice.tbl_0\",\n      \"select acos(plain_int_0) as f1 from alice.tbl_0\",\n      \"select atan(plain_int_0) as f1 from alice.tbl_0\",\n      \"select atan(plain_int_0, 3) as f1 from alice.tbl_0\",\n      \"select ceil(plain_int_0) as f1 from alice.tbl_0\",\n      \"select ceiling(plain_int_0) as f1 from alice.tbl_0\",\n      \"select conv(plain_int_0, 2, 10) as f1 from alice.tbl_0\",\n      \"select cos(plain_int_0) as f1 from alice.tbl_0\",\n      \"select cot(plain_int_0) as f1 from alice.tbl_0\",\n      \"select crc32(plain_int_0) as f1 from alice.tbl_0\",\n      \"select degrees(plain_int_0) as f1 from alice.tbl_0\",\n      \"select exp(plain_int_0) as f1 from alice.tbl_0\",\n      \"select floor(plain_int_0) as f1 from alice.tbl_0\",\n      \"select ln(plain_int_0) as f1 from alice.tbl_0\",\n      \"select log(2,plain_int_0) as f1 from alice.tbl_0\",\n      \"select log2(plain_int_0), pi() as f1 from alice.tbl_0\",\n      \"select log10(plain_int_0) as f1 from alice.tbl_0\",\n      \"select pow(2, plain_int_0) as f1 from alice.tbl_0\",\n      \"select power(2, plain_int_0) as f1 from alice.tbl_0\",\n      \"select radians(plain_int_0) as f1 from alice.tbl_0\",\n      \"select rand() as f1 from alice.tbl_0\",\n      \"select sign(plain_int_0) as f1 from alice.tbl_0\",\n      \"select sqrt(plain_int_0) as f1 from alice.tbl_0\",\n      \"select truncate(plain_int_0, 1) as f1 from alice.tbl_0\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderCast\",\n    \"cases\": [\"select cast(plain_int_0 as float) from alice.tbl_0;\"]\n  },\n  {\n    \"name\": \"TestPlanBuilderSimpleWithOptimization\",\n    \"cases\": [\n      \"select plain_int_0 from alice.tbl_0 into outfile '/tmp/result.txt'\",\n      \"select plain_float_0 < plain_float_1 from alice.tbl_0\",\n      \"select plain_int_0 from alice.tbl_0 where plain_int_0 not in (select plain_int_1 from alice.tbl_0)\",\n      \"select case when plain_int_0 < 1 then 0 else 1 end from alice.tbl_0\",\n      \"select case when plain_int_0 in (select plain_int_1 from alice.tbl_0) then 0 else 1 end from alice.tbl_0\",\n      \"select case when plain_int_0 < 0 then -1 when plain_int_0 = 0 then 0 else 1 end from alice.tbl_0\",\n      \"select plain_int_0 in (select plain_int_1 from alice.tbl_0 where plain_int_2 = 3) from alice.tbl_0\",\n      \"select 1 from alice.tbl_0\",\n      \"select alice.plain_int_0 from alice.tbl_0 alice join bob.tbl_0 bob on alice.plain_int_1 = bob.plain_int_1 where bob.plain_int_2\",\n      \"select distinct plain_int_0, plain_int_1 from alice.tbl_0\",\n      \"select count(plain_int_1) from alice.tbl_0 group by plain_int_1\",\n      \"select sum(plain_int_1) from alice.tbl_0 group by plain_int_1\",\n      \"select count(plain_int_0) div count(plain_int_0) from alice.tbl_0 group by plain_int_0\",\n      \"select max(plain_int_0), min(plain_int_0), median(plain_int_0), percentile_disc(plain_int_0, 0.8) from alice.tbl_0 group by plain_int_1\",\n      \"select t from (select (plain_int_0 + plain_int_1) as t from alice.tbl_0) as alice group by t\",\n      \"select plain_int_0 from alice.tbl_0 order by plain_int_0\",\n      \"select plain_int_0 from alice.tbl_0 order by plain_int_0 desc\",\n      \"select plain_int_0 from alice.tbl_0 order by plain_int_0 desc, plain_int_1 asc\",\n      \"select plain_int_0 from alice.tbl_0 limit 1\",\n      \"select plain_int_0 from alice.tbl_0 union select plain_int_1 from alice.tbl_1\",\n      \"select plain_int_0 from alice.tbl_0 union all select plain_int_1 from alice.tbl_1\",\n      \"select plain_int_0 from alice.tbl_0 union select plain_int_1 from alice.tbl_1 union all select plain_int_2 from alice.tbl_2\",\n      \"(select plain_int_0 from alice.tbl_0 where plain_int_0=10 and plain_int_1=1) union (select plain_int_0 from alice.tbl_1 where plain_int_0=11 and plain_int_1=2) order by plain_int_0 limit 10\",\n      \"(select plain_int_0 from alice.tbl_0 where plain_int_1=2 limit 9) union (select plain_int_0 from alice.tbl_1 where plain_int_1=1 limit 10) limit 15\",\n      \"select alice.plain_string_0 as str0, alice.plain_string_1 as str1, count(*) as cnt, sum(bob.plain_string_0) as sum from alice.tbl_0 as alice, bob.tbl_0 as bob where alice.plain_int_0=bob.plain_int_0 group by alice.plain_string_0, alice.plain_string_1\",\n      \"select count(*), sum(plain_int_1), min(plain_int_1), max(plain_int_1), avg(plain_int_1) from alice.tbl_0\",\n      \"select sum(plain_int_0) from (select plain_int_0 from alice.tbl_0 union all select plain_int_1 from alice.tbl_1) alice\",\n      \"select plain_int_1, sum(plain_int_0) from (select plain_int_0, plain_int_1 from alice.tbl_1 union all select plain_int_0, plain_int_1 from alice.tbl_2) J group by plain_int_1\",\n      \"select plain_int_1, max(plain_int_0) from (select plain_int_0, plain_int_1 from alice.tbl_1 union all select plain_int_0, plain_int_1 from alice.tbl_2) J group by plain_int_1\",\n      \"select plain_int_1, min(plain_int_0) from (select plain_int_0, plain_int_1 from alice.tbl_1 union all select plain_int_0, plain_int_1 from alice.tbl_2) J group by plain_int_1\",\n      \"select plain_int_1, avg(plain_int_0) from (select plain_int_0, plain_int_1 from alice.tbl_1 union all select plain_int_0, plain_int_1 from alice.tbl_2) J group by plain_int_1\",\n      \"select plain_int_1, median(plain_int_0) from (select plain_int_0, plain_int_1 from alice.tbl_1 union all select plain_int_0, plain_int_1 from alice.tbl_2) J group by plain_int_1\",\n      \"select plain_int_1, count(*) from (select plain_int_0, plain_int_1 from alice.tbl_0 union all select plain_int_0, plain_int_1 from alice.tbl_0) J group by plain_int_1\",\n      \"select plain_int_0 from (select plain_int_0, sum(plain_int_1) as new_long from alice.tbl_1 group by plain_int_0) new_tbl order by new_long;\",\n      \"select count(*) from (select ta.groupby_string_0 from alice.tbl_0 as ta union select tb.groupby_string_0 from bob.tbl_0 as tb union select tc.groupby_string_0 from carol.tbl_0 as tc) as uu\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSelectionWithOptimization\",\n    \"cases\": [\n      \"select plain_int_0 from (select plain_int_0, sum(plain_int_1) as new_long1 from alice.tbl_0 group by plain_int_0) new_tbl where new_long1 > 0;\",\n      \"select plain_int_0 from (select plain_int_0, sum(plain_int_1) as new_long1 from alice.tbl_0 group by plain_int_0) new_tbl order by new_long1;\",\n      \"select plain_int_0, sum(plain_int_1) as new_long1 from (select plain_int_0, plain_int_1 from alice.tbl_0 where alice.tbl_0.plain_int_0 > 10) new_tbl group by new_tbl.plain_int_0;\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderWindowWithOptimization\",\n    \"cases\": [\n      \"select plain_int_0, rank() over (order by plain_int_1) from alice.tbl_0\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSubQueryWithOptimization\",\n    \"cases\": [\n      \"select plain_int_0 in (select plain_int_1 from alice.tbl_0) from alice.tbl_0;\",\n      \"select t0.plain_int_0 in (select plain_int_1 from alice.tbl_0) as f1 from alice.tbl_0 t0 join alice.tbl_1 t1 where t0.plain_int_0=1234 and t1.plain_int_1=3456\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderDateTimeWithOptimization\",\n    \"cases\": [\n      \"select plain_datetime_0 < now() from alice.tbl_0;\",\n      \"select plain_timestamp_0 < curdate() from alice.tbl_0;\",\n      \"select plain_datetime_0 < curtime() from alice.tbl_0;\",\n      \"select adddate(plain_datetime_0, interval 10 day) from alice.tbl_0;\",\n      \"select subdate(plain_timestamp_0, interval 10 day) from alice.tbl_0;\",\n      \"select addtime(plain_datetime_0, '1 1:1:1') from alice.tbl_0;\",\n      \"select subtime(plain_timestamp_0, '1 1:1:1') from alice.tbl_0;\",\n      \"select datediff(plain_datetime_0, plain_datetime_1) from alice.tbl_0;\",\n      \"select datediff(plain_datetime_0, plain_timestamp_0) from alice.tbl_0;\",\n      \"select datediff(plain_timestamp_0, plain_timestamp_1) from alice.tbl_0;\",\n      \"select timediff(plain_datetime_0, plain_datetime_1) from alice.tbl_0;\",\n      \"select timediff(plain_datetime_0, plain_timestamp_0) from alice.tbl_0;\",\n      \"select timediff(plain_timestamp_0, plain_timestamp_1) from alice.tbl_0;\",\n      \"select last_day(plain_timestamp_0) from alice.tbl_0;\",\n      \"select str_to_date('August 10 2017', '%M %d %Y') from alice.tbl_0;\",\n      \"select date_format(plain_datetime_0, '%Y-%m-%d %H:%i:%S') from alice.tbl_0;\",\n      \"select plain_datetime_0, plain_timestamp_0 from alice.tbl_0;\",\n      \"select plain_datetime_0 < plain_datetime_1 from alice.tbl_0\",\n      \"select plain_timestamp_0 < plain_timestamp_1 from alice.tbl_0\",\n      \"select plain_datetime_0 < plain_timestamp_0 from alice.tbl_0\",\n      \"select plain_datetime_0 from alice.tbl_0 where plain_datetime_0 not in (select plain_timestamp_0 from alice.tbl_0)\",\n      \"select case when plain_datetime_0 < '2020-10-10' then 0 else 1 end from alice.tbl_0\",\n      \"select case when plain_datetime_0 in (select plain_timestamp_1 from alice.tbl_1) then 0 else 1 end from alice.tbl_0\",\n      \"select plain_datetime_0 in (select plain_datetime_1 from alice.tbl_0 where plain_datetime_1 = '2020-10-10 10:10:10') from alice.tbl_0\",\n      \"select distinct plain_datetime_0, plain_timestamp_0 from alice.tbl_0\",\n      \"select count(plain_int_1) from alice.tbl_0 group by plain_datetime_0\",\n      \"select max(plain_timestamp_0), min(plain_timestamp_0), median(plain_timestamp_0) from alice.tbl_0 group by plain_datetime_0\",\n      \"select plain_datetime_0 from alice.tbl_0 order by plain_datetime_0\",\n      \"select plain_datetime_0 from alice.tbl_0 order by plain_datetime_0 desc\",\n      \"select plain_datetime_0 from alice.tbl_0 order by plain_datetime_0 desc, plain_timestamp_0 asc\",\n      \"select plain_datetime_0 from alice.tbl_0 limit 1\"\n    ]\n  }\n]\n"
  },
  {
    "path": "pkg/planner/core/testdata/typical_query_out.json",
    "content": "[\n  {\n    \"name\": \"TestPlanBuilderSimple\",\n    \"cases\": [\n      \"Join{DataScan(alice)->DataScan(bob)}([eq(alice.tbl_0.plain_int_1, bob.tbl_0.plain_int_1)],)->Projection([alice.tbl_0.plain_int_0])\",\n      \"Join{DataScan(alice)->DataScan(bob)}([eq(alice.tbl_0.plain_int_1, bob.tbl_0.plain_int_1) eq(alice.tbl_0.plain_string_1, bob.tbl_0.plain_string_1)],)->Projection([alice.tbl_0.plain_int_0 bob.tbl_0.plain_string_0])\",\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_int_0])\",\n      \"DataScan(tbl_0)->Projection([eq(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])\",\n      \"DataScan(tbl_0)->Projection([lt(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])\",\n      \"DataScan(tbl_0)->Projection([le(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])\",\n      \"DataScan(tbl_0)->Projection([gt(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])\",\n      \"DataScan(tbl_0)->Projection([ge(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])\",\n      \"DataScan(tbl_0)->Projection([ne(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])\",\n      \"DataScan(tbl_0)->Projection([ne(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])\",\n      \"DataScan(tbl_0)->Projection([eq(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1)])\",\n      \"DataScan(tbl_0)->Projection([gt(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1)])\",\n      \"DataScan(tbl_0)->Projection([ge(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1)])\",\n      \"DataScan(tbl_0)->Projection([lt(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1)])\",\n      \"DataScan(tbl_0)->Projection([le(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1)])\",\n      \"DataScan(tbl_0)->Projection([ne(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1)])\",\n      \"DataScan(tbl_0)->Projection([ne(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1)])\",\n      \"DataScan(tbl_0)->Projection([plus(alice.tbl_0.plain_int_0, 1)])\",\n      \"DataScan(tbl_0)->Projection([minus(alice.tbl_0.plain_int_0, 1)])\",\n      \"DataScan(tbl_0)->Projection([mod(alice.tbl_0.plain_int_0, 3)])\",\n      \"DataScan(tbl_0)->Projection([minus(plus(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1), 1)])\",\n      \"DataScan(tbl_0)->Projection([plus(minus(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1), 1)])\",\n      \"DataScan(tbl_0)->Projection([mod(mod(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1), 3)])\",\n      \"DataScan(tbl_0)->Projection([minus(alice.tbl_0.plain_int_0, minus(alice.tbl_0.plain_int_1, 1))])\",\n      \"DataScan(tbl_0)->Projection([mul(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([mul(alice.tbl_0.plain_int_0, 10)])\",\n      \"DataScan(tbl_0)->Projection([div(cast(alice.tbl_0.plain_int_0), alice.tbl_0.plain_int_1)])\",\n      \"DataScan(tbl_0)->Projection([div(cast(alice.tbl_0.plain_int_0), 10)])\",\n      \"DataScan(tbl_0)->Aggr(sum(alice.tbl_0.plain_int_1),firstrow(alice.tbl_0.aggregate_datetime_0),firstrow(alice.tbl_0.aggregate_datetime_1),firstrow(alice.tbl_0.aggregate_datetime_2),firstrow(alice.tbl_0.aggregate_float_0),firstrow(alice.tbl_0.aggregate_float_1),firstrow(alice.tbl_0.aggregate_float_2),firstrow(alice.tbl_0.aggregate_int_0),firstrow(alice.tbl_0.aggregate_int_1),firstrow(alice.tbl_0.aggregate_int_2),firstrow(alice.tbl_0.aggregate_string_0),firstrow(alice.tbl_0.aggregate_string_1),firstrow(alice.tbl_0.aggregate_string_2),firstrow(alice.tbl_0.aggregate_timestamp_0),firstrow(alice.tbl_0.aggregate_timestamp_1),firstrow(alice.tbl_0.aggregate_timestamp_2),firstrow(alice.tbl_0.compare_datetime_0),firstrow(alice.tbl_0.compare_datetime_1),firstrow(alice.tbl_0.compare_datetime_2),firstrow(alice.tbl_0.compare_float_0),firstrow(alice.tbl_0.compare_float_1),firstrow(alice.tbl_0.compare_float_2),firstrow(alice.tbl_0.compare_int_0),firstrow(alice.tbl_0.compare_int_1),firstrow(alice.tbl_0.compare_int_2),firstrow(alice.tbl_0.compare_string_0),firstrow(alice.tbl_0.compare_string_1),firstrow(alice.tbl_0.compare_string_2),firstrow(alice.tbl_0.compare_timestamp_0),firstrow(alice.tbl_0.compare_timestamp_1),firstrow(alice.tbl_0.compare_timestamp_2),firstrow(alice.tbl_0.encrypt_datetime_0),firstrow(alice.tbl_0.encrypt_datetime_1),firstrow(alice.tbl_0.encrypt_datetime_2),firstrow(alice.tbl_0.encrypt_float_0),firstrow(alice.tbl_0.encrypt_float_1),firstrow(alice.tbl_0.encrypt_float_2),firstrow(alice.tbl_0.encrypt_int_0),firstrow(alice.tbl_0.encrypt_int_1),firstrow(alice.tbl_0.encrypt_int_2),firstrow(alice.tbl_0.encrypt_string_0),firstrow(alice.tbl_0.encrypt_string_1),firstrow(alice.tbl_0.encrypt_string_2),firstrow(alice.tbl_0.encrypt_timestamp_0),firstrow(alice.tbl_0.encrypt_timestamp_1),firstrow(alice.tbl_0.encrypt_timestamp_2),firstrow(alice.tbl_0.groupby_datetime_0),firstrow(alice.tbl_0.groupby_datetime_1),firstrow(alice.tbl_0.groupby_datetime_2),firstrow(alice.tbl_0.groupby_float_0),firstrow(alice.tbl_0.groupby_float_1),firstrow(alice.tbl_0.groupby_float_2),firstrow(alice.tbl_0.groupby_int_0),firstrow(alice.tbl_0.groupby_int_1),firstrow(alice.tbl_0.groupby_int_2),firstrow(alice.tbl_0.groupby_string_0),firstrow(alice.tbl_0.groupby_string_1),firstrow(alice.tbl_0.groupby_string_2),firstrow(alice.tbl_0.groupby_timestamp_0),firstrow(alice.tbl_0.groupby_timestamp_1),firstrow(alice.tbl_0.groupby_timestamp_2),firstrow(alice.tbl_0.join_datetime_0),firstrow(alice.tbl_0.join_datetime_1),firstrow(alice.tbl_0.join_datetime_2),firstrow(alice.tbl_0.join_float_0),firstrow(alice.tbl_0.join_float_1),firstrow(alice.tbl_0.join_float_2),firstrow(alice.tbl_0.join_int_0),firstrow(alice.tbl_0.join_int_1),firstrow(alice.tbl_0.join_int_2),firstrow(alice.tbl_0.join_string_0),firstrow(alice.tbl_0.join_string_1),firstrow(alice.tbl_0.join_string_2),firstrow(alice.tbl_0.join_timestamp_0),firstrow(alice.tbl_0.join_timestamp_1),firstrow(alice.tbl_0.join_timestamp_2),firstrow(alice.tbl_0.joinpayload_datetime_0),firstrow(alice.tbl_0.joinpayload_datetime_1),firstrow(alice.tbl_0.joinpayload_datetime_2),firstrow(alice.tbl_0.joinpayload_float_0),firstrow(alice.tbl_0.joinpayload_float_1),firstrow(alice.tbl_0.joinpayload_float_2),firstrow(alice.tbl_0.joinpayload_int_0),firstrow(alice.tbl_0.joinpayload_int_1),firstrow(alice.tbl_0.joinpayload_int_2),firstrow(alice.tbl_0.joinpayload_string_0),firstrow(alice.tbl_0.joinpayload_string_1),firstrow(alice.tbl_0.joinpayload_string_2),firstrow(alice.tbl_0.joinpayload_timestamp_0),firstrow(alice.tbl_0.joinpayload_timestamp_1),firstrow(alice.tbl_0.joinpayload_timestamp_2),firstrow(alice.tbl_0.plain_datetime_0),firstrow(alice.tbl_0.plain_datetime_1),firstrow(alice.tbl_0.plain_datetime_2),firstrow(alice.tbl_0.plain_float_0),firstrow(alice.tbl_0.plain_float_1),firstrow(alice.tbl_0.plain_float_2),firstrow(alice.tbl_0.plain_int_0),firstrow(alice.tbl_0.plain_int_1),firstrow(alice.tbl_0.plain_int_2),firstrow(alice.tbl_0.plain_string_0),firstrow(alice.tbl_0.plain_string_1),firstrow(alice.tbl_0.plain_string_2),firstrow(alice.tbl_0.plain_timestamp_0),firstrow(alice.tbl_0.plain_timestamp_1),firstrow(alice.tbl_0.plain_timestamp_2),firstrow(alice.tbl_0.rank_datetime_0),firstrow(alice.tbl_0.rank_datetime_1),firstrow(alice.tbl_0.rank_datetime_2),firstrow(alice.tbl_0.rank_float_0),firstrow(alice.tbl_0.rank_float_1),firstrow(alice.tbl_0.rank_float_2),firstrow(alice.tbl_0.rank_int_0),firstrow(alice.tbl_0.rank_int_1),firstrow(alice.tbl_0.rank_int_2),firstrow(alice.tbl_0.rank_string_0),firstrow(alice.tbl_0.rank_string_1),firstrow(alice.tbl_0.rank_string_2),firstrow(alice.tbl_0.rank_timestamp_0),firstrow(alice.tbl_0.rank_timestamp_1),firstrow(alice.tbl_0.rank_timestamp_2))->Projection([alice.tbl_0.plain_int_0 Column#121])->Sel([gt(Column#121, 0)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSelection\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Aggr(sum(alice.tbl_0.plain_int_1),firstrow(alice.tbl_0.aggregate_datetime_0),firstrow(alice.tbl_0.aggregate_datetime_1),firstrow(alice.tbl_0.aggregate_datetime_2),firstrow(alice.tbl_0.aggregate_float_0),firstrow(alice.tbl_0.aggregate_float_1),firstrow(alice.tbl_0.aggregate_float_2),firstrow(alice.tbl_0.aggregate_int_0),firstrow(alice.tbl_0.aggregate_int_1),firstrow(alice.tbl_0.aggregate_int_2),firstrow(alice.tbl_0.aggregate_string_0),firstrow(alice.tbl_0.aggregate_string_1),firstrow(alice.tbl_0.aggregate_string_2),firstrow(alice.tbl_0.aggregate_timestamp_0),firstrow(alice.tbl_0.aggregate_timestamp_1),firstrow(alice.tbl_0.aggregate_timestamp_2),firstrow(alice.tbl_0.compare_datetime_0),firstrow(alice.tbl_0.compare_datetime_1),firstrow(alice.tbl_0.compare_datetime_2),firstrow(alice.tbl_0.compare_float_0),firstrow(alice.tbl_0.compare_float_1),firstrow(alice.tbl_0.compare_float_2),firstrow(alice.tbl_0.compare_int_0),firstrow(alice.tbl_0.compare_int_1),firstrow(alice.tbl_0.compare_int_2),firstrow(alice.tbl_0.compare_string_0),firstrow(alice.tbl_0.compare_string_1),firstrow(alice.tbl_0.compare_string_2),firstrow(alice.tbl_0.compare_timestamp_0),firstrow(alice.tbl_0.compare_timestamp_1),firstrow(alice.tbl_0.compare_timestamp_2),firstrow(alice.tbl_0.encrypt_datetime_0),firstrow(alice.tbl_0.encrypt_datetime_1),firstrow(alice.tbl_0.encrypt_datetime_2),firstrow(alice.tbl_0.encrypt_float_0),firstrow(alice.tbl_0.encrypt_float_1),firstrow(alice.tbl_0.encrypt_float_2),firstrow(alice.tbl_0.encrypt_int_0),firstrow(alice.tbl_0.encrypt_int_1),firstrow(alice.tbl_0.encrypt_int_2),firstrow(alice.tbl_0.encrypt_string_0),firstrow(alice.tbl_0.encrypt_string_1),firstrow(alice.tbl_0.encrypt_string_2),firstrow(alice.tbl_0.encrypt_timestamp_0),firstrow(alice.tbl_0.encrypt_timestamp_1),firstrow(alice.tbl_0.encrypt_timestamp_2),firstrow(alice.tbl_0.groupby_datetime_0),firstrow(alice.tbl_0.groupby_datetime_1),firstrow(alice.tbl_0.groupby_datetime_2),firstrow(alice.tbl_0.groupby_float_0),firstrow(alice.tbl_0.groupby_float_1),firstrow(alice.tbl_0.groupby_float_2),firstrow(alice.tbl_0.groupby_int_0),firstrow(alice.tbl_0.groupby_int_1),firstrow(alice.tbl_0.groupby_int_2),firstrow(alice.tbl_0.groupby_string_0),firstrow(alice.tbl_0.groupby_string_1),firstrow(alice.tbl_0.groupby_string_2),firstrow(alice.tbl_0.groupby_timestamp_0),firstrow(alice.tbl_0.groupby_timestamp_1),firstrow(alice.tbl_0.groupby_timestamp_2),firstrow(alice.tbl_0.join_datetime_0),firstrow(alice.tbl_0.join_datetime_1),firstrow(alice.tbl_0.join_datetime_2),firstrow(alice.tbl_0.join_float_0),firstrow(alice.tbl_0.join_float_1),firstrow(alice.tbl_0.join_float_2),firstrow(alice.tbl_0.join_int_0),firstrow(alice.tbl_0.join_int_1),firstrow(alice.tbl_0.join_int_2),firstrow(alice.tbl_0.join_string_0),firstrow(alice.tbl_0.join_string_1),firstrow(alice.tbl_0.join_string_2),firstrow(alice.tbl_0.join_timestamp_0),firstrow(alice.tbl_0.join_timestamp_1),firstrow(alice.tbl_0.join_timestamp_2),firstrow(alice.tbl_0.joinpayload_datetime_0),firstrow(alice.tbl_0.joinpayload_datetime_1),firstrow(alice.tbl_0.joinpayload_datetime_2),firstrow(alice.tbl_0.joinpayload_float_0),firstrow(alice.tbl_0.joinpayload_float_1),firstrow(alice.tbl_0.joinpayload_float_2),firstrow(alice.tbl_0.joinpayload_int_0),firstrow(alice.tbl_0.joinpayload_int_1),firstrow(alice.tbl_0.joinpayload_int_2),firstrow(alice.tbl_0.joinpayload_string_0),firstrow(alice.tbl_0.joinpayload_string_1),firstrow(alice.tbl_0.joinpayload_string_2),firstrow(alice.tbl_0.joinpayload_timestamp_0),firstrow(alice.tbl_0.joinpayload_timestamp_1),firstrow(alice.tbl_0.joinpayload_timestamp_2),firstrow(alice.tbl_0.plain_datetime_0),firstrow(alice.tbl_0.plain_datetime_1),firstrow(alice.tbl_0.plain_datetime_2),firstrow(alice.tbl_0.plain_float_0),firstrow(alice.tbl_0.plain_float_1),firstrow(alice.tbl_0.plain_float_2),firstrow(alice.tbl_0.plain_int_0),firstrow(alice.tbl_0.plain_int_1),firstrow(alice.tbl_0.plain_int_2),firstrow(alice.tbl_0.plain_string_0),firstrow(alice.tbl_0.plain_string_1),firstrow(alice.tbl_0.plain_string_2),firstrow(alice.tbl_0.plain_timestamp_0),firstrow(alice.tbl_0.plain_timestamp_1),firstrow(alice.tbl_0.plain_timestamp_2),firstrow(alice.tbl_0.rank_datetime_0),firstrow(alice.tbl_0.rank_datetime_1),firstrow(alice.tbl_0.rank_datetime_2),firstrow(alice.tbl_0.rank_float_0),firstrow(alice.tbl_0.rank_float_1),firstrow(alice.tbl_0.rank_float_2),firstrow(alice.tbl_0.rank_int_0),firstrow(alice.tbl_0.rank_int_1),firstrow(alice.tbl_0.rank_int_2),firstrow(alice.tbl_0.rank_string_0),firstrow(alice.tbl_0.rank_string_1),firstrow(alice.tbl_0.rank_string_2),firstrow(alice.tbl_0.rank_timestamp_0),firstrow(alice.tbl_0.rank_timestamp_1),firstrow(alice.tbl_0.rank_timestamp_2))->Projection([alice.tbl_0.plain_int_0 Column#121])->Sel([gt(Column#121, 0)])->Projection([alice.tbl_0.plain_int_0])\",\n      \"DataScan(tbl_0)->Aggr(sum(alice.tbl_0.plain_int_1),firstrow(alice.tbl_0.aggregate_datetime_0),firstrow(alice.tbl_0.aggregate_datetime_1),firstrow(alice.tbl_0.aggregate_datetime_2),firstrow(alice.tbl_0.aggregate_float_0),firstrow(alice.tbl_0.aggregate_float_1),firstrow(alice.tbl_0.aggregate_float_2),firstrow(alice.tbl_0.aggregate_int_0),firstrow(alice.tbl_0.aggregate_int_1),firstrow(alice.tbl_0.aggregate_int_2),firstrow(alice.tbl_0.aggregate_string_0),firstrow(alice.tbl_0.aggregate_string_1),firstrow(alice.tbl_0.aggregate_string_2),firstrow(alice.tbl_0.aggregate_timestamp_0),firstrow(alice.tbl_0.aggregate_timestamp_1),firstrow(alice.tbl_0.aggregate_timestamp_2),firstrow(alice.tbl_0.compare_datetime_0),firstrow(alice.tbl_0.compare_datetime_1),firstrow(alice.tbl_0.compare_datetime_2),firstrow(alice.tbl_0.compare_float_0),firstrow(alice.tbl_0.compare_float_1),firstrow(alice.tbl_0.compare_float_2),firstrow(alice.tbl_0.compare_int_0),firstrow(alice.tbl_0.compare_int_1),firstrow(alice.tbl_0.compare_int_2),firstrow(alice.tbl_0.compare_string_0),firstrow(alice.tbl_0.compare_string_1),firstrow(alice.tbl_0.compare_string_2),firstrow(alice.tbl_0.compare_timestamp_0),firstrow(alice.tbl_0.compare_timestamp_1),firstrow(alice.tbl_0.compare_timestamp_2),firstrow(alice.tbl_0.encrypt_datetime_0),firstrow(alice.tbl_0.encrypt_datetime_1),firstrow(alice.tbl_0.encrypt_datetime_2),firstrow(alice.tbl_0.encrypt_float_0),firstrow(alice.tbl_0.encrypt_float_1),firstrow(alice.tbl_0.encrypt_float_2),firstrow(alice.tbl_0.encrypt_int_0),firstrow(alice.tbl_0.encrypt_int_1),firstrow(alice.tbl_0.encrypt_int_2),firstrow(alice.tbl_0.encrypt_string_0),firstrow(alice.tbl_0.encrypt_string_1),firstrow(alice.tbl_0.encrypt_string_2),firstrow(alice.tbl_0.encrypt_timestamp_0),firstrow(alice.tbl_0.encrypt_timestamp_1),firstrow(alice.tbl_0.encrypt_timestamp_2),firstrow(alice.tbl_0.groupby_datetime_0),firstrow(alice.tbl_0.groupby_datetime_1),firstrow(alice.tbl_0.groupby_datetime_2),firstrow(alice.tbl_0.groupby_float_0),firstrow(alice.tbl_0.groupby_float_1),firstrow(alice.tbl_0.groupby_float_2),firstrow(alice.tbl_0.groupby_int_0),firstrow(alice.tbl_0.groupby_int_1),firstrow(alice.tbl_0.groupby_int_2),firstrow(alice.tbl_0.groupby_string_0),firstrow(alice.tbl_0.groupby_string_1),firstrow(alice.tbl_0.groupby_string_2),firstrow(alice.tbl_0.groupby_timestamp_0),firstrow(alice.tbl_0.groupby_timestamp_1),firstrow(alice.tbl_0.groupby_timestamp_2),firstrow(alice.tbl_0.join_datetime_0),firstrow(alice.tbl_0.join_datetime_1),firstrow(alice.tbl_0.join_datetime_2),firstrow(alice.tbl_0.join_float_0),firstrow(alice.tbl_0.join_float_1),firstrow(alice.tbl_0.join_float_2),firstrow(alice.tbl_0.join_int_0),firstrow(alice.tbl_0.join_int_1),firstrow(alice.tbl_0.join_int_2),firstrow(alice.tbl_0.join_string_0),firstrow(alice.tbl_0.join_string_1),firstrow(alice.tbl_0.join_string_2),firstrow(alice.tbl_0.join_timestamp_0),firstrow(alice.tbl_0.join_timestamp_1),firstrow(alice.tbl_0.join_timestamp_2),firstrow(alice.tbl_0.joinpayload_datetime_0),firstrow(alice.tbl_0.joinpayload_datetime_1),firstrow(alice.tbl_0.joinpayload_datetime_2),firstrow(alice.tbl_0.joinpayload_float_0),firstrow(alice.tbl_0.joinpayload_float_1),firstrow(alice.tbl_0.joinpayload_float_2),firstrow(alice.tbl_0.joinpayload_int_0),firstrow(alice.tbl_0.joinpayload_int_1),firstrow(alice.tbl_0.joinpayload_int_2),firstrow(alice.tbl_0.joinpayload_string_0),firstrow(alice.tbl_0.joinpayload_string_1),firstrow(alice.tbl_0.joinpayload_string_2),firstrow(alice.tbl_0.joinpayload_timestamp_0),firstrow(alice.tbl_0.joinpayload_timestamp_1),firstrow(alice.tbl_0.joinpayload_timestamp_2),firstrow(alice.tbl_0.plain_datetime_0),firstrow(alice.tbl_0.plain_datetime_1),firstrow(alice.tbl_0.plain_datetime_2),firstrow(alice.tbl_0.plain_float_0),firstrow(alice.tbl_0.plain_float_1),firstrow(alice.tbl_0.plain_float_2),firstrow(alice.tbl_0.plain_int_0),firstrow(alice.tbl_0.plain_int_1),firstrow(alice.tbl_0.plain_int_2),firstrow(alice.tbl_0.plain_string_0),firstrow(alice.tbl_0.plain_string_1),firstrow(alice.tbl_0.plain_string_2),firstrow(alice.tbl_0.plain_timestamp_0),firstrow(alice.tbl_0.plain_timestamp_1),firstrow(alice.tbl_0.plain_timestamp_2),firstrow(alice.tbl_0.rank_datetime_0),firstrow(alice.tbl_0.rank_datetime_1),firstrow(alice.tbl_0.rank_datetime_2),firstrow(alice.tbl_0.rank_float_0),firstrow(alice.tbl_0.rank_float_1),firstrow(alice.tbl_0.rank_float_2),firstrow(alice.tbl_0.rank_int_0),firstrow(alice.tbl_0.rank_int_1),firstrow(alice.tbl_0.rank_int_2),firstrow(alice.tbl_0.rank_string_0),firstrow(alice.tbl_0.rank_string_1),firstrow(alice.tbl_0.rank_string_2),firstrow(alice.tbl_0.rank_timestamp_0),firstrow(alice.tbl_0.rank_timestamp_1),firstrow(alice.tbl_0.rank_timestamp_2))->Projection([alice.tbl_0.plain_int_0 Column#121])->Projection([alice.tbl_0.plain_int_0 Column#121])->Sort(Column#121)->Projection([alice.tbl_0.plain_int_0])\",\n      \"DataScan(tbl_0)->Sel([gt(alice.tbl_0.plain_int_0, 10)])->Projection([alice.tbl_0.plain_int_0 alice.tbl_0.plain_int_1])->Aggr(sum(alice.tbl_0.plain_int_1),firstrow(alice.tbl_0.plain_int_0),firstrow(alice.tbl_0.plain_int_1))->Projection([alice.tbl_0.plain_int_0 Column#121])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderWindow\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_int_0 0 alice.tbl_0.plain_int_1])->Projection([alice.tbl_0.plain_int_0 Column#121 alice.tbl_0.plain_int_1])->Window(rank()->Column#122)->Projection([alice.tbl_0.plain_int_0 Column#122 alice.tbl_0.plain_int_1])->Projection([alice.tbl_0.plain_int_0 Column#122])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSubQuery\",\n    \"cases\": [\n      \"Apply{DataScan(tbl_0)->DataScan(tbl_0)->Projection([alice.tbl_0.plain_int_1])}(o[eq(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])->Projection([Column#241])\",\n      \"Apply{Join{DataScan(t0)->DataScan(t1)}->Sel([eq(alice.tbl_0.plain_int_0, 1234) eq(alice.tbl_1.plain_int_1, 3456)])->DataScan(tbl_0)->Projection([alice.tbl_0.plain_int_1])}(o[eq(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])->Projection([Column#361])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderInOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([or(eq(alice.tbl_0.plain_int_0, 1), or(eq(alice.tbl_0.plain_int_0, 2), eq(alice.tbl_0.plain_int_0, 3)))])\",\n      \"Apply{DataScan(tbl_0)->DataScan(tbl_1)->Projection([alice.tbl_1.plain_int_0])}(o[eq(alice.tbl_0.plain_int_0, alice.tbl_1.plain_int_0)])->Projection([Column#241])\",\n      \"Apply{DataScan(tbl_0)->DataScan(tbl_1)->Projection([alice.tbl_1.plain_int_0])}([eq(alice.tbl_0.plain_int_0, alice.tbl_1.plain_int_0)])->Projection([alice.tbl_0.plain_int_0])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderLowerUpperOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([lower(alice.tbl_0.plain_string_0)])\",\n      \"DataScan(tbl_0)->Projection([upper(alice.tbl_0.plain_string_0)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderCoalesceOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([coalesce(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderLengthOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([length(alice.tbl_0.plain_int_0)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderReplaceOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([replace(alice.tbl_0.plain_string_0, old, new)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuildeLikeRlikeOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Sel([like(alice.tbl_0.plain_string_0, %xxx, 92)])->Projection([alice.tbl_0.plain_string_0])\",\n      \"DataScan(tbl_0)->Sel([regexp(alice.tbl_0.plain_string_0, f[a-d].*)])->Projection([alice.tbl_0.plain_string_0])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSubstringOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Sel([eq(substring(alice.tbl_0.plain_string_0, 2, 3), xxx)])->Projection([substring(alice.tbl_0.plain_string_0, 2, 3)])\",\n      \"DataScan(tbl_0)->Sel([eq(substring(alice.tbl_0.plain_string_0, 2), xxx)])->Projection([substring(alice.tbl_0.plain_string_0, 2)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderTrimOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Sel([ne(trim(alice.tbl_0.plain_string_0), )])->Projection([trim(alice.tbl_0.plain_string_0)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuildeLimitOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_int_0])->Limit\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderInstrOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([instr(alice.tbl_0.plain_string_0, alice.tbl_0.plain_string_1)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderGreatestLeastOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([greatest(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1, alice.tbl_0.plain_int_2)])\",\n      \"DataScan(tbl_0)->Projection([least(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1, alice.tbl_0.plain_int_2)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderLogicalOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([and(or(eq(alice.tbl_0.plain_int_0, 1), eq(alice.tbl_0.plain_int_0, 2)), or(eq(alice.tbl_0.plain_int_1, 2), eq(alice.tbl_0.plain_int_1, 3)))])\",\n      \"DataScan(tbl_0)->Projection([or(or(eq(alice.tbl_0.plain_int_0, 1), eq(alice.tbl_0.plain_int_0, 2)), or(eq(alice.tbl_0.plain_int_1, 2), eq(alice.tbl_0.plain_int_1, 3)))])\",\n      \"DataScan(tbl_0)->Projection([xor(or(eq(alice.tbl_0.plain_int_0, 1), eq(alice.tbl_0.plain_int_0, 2)), or(eq(alice.tbl_0.plain_int_1, 2), eq(alice.tbl_0.plain_int_1, 3)))])\",\n      \"DataScan(tbl_0)->Projection([not(or(eq(alice.tbl_0.plain_int_0, 1), eq(alice.tbl_0.plain_int_0, 2)))])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderMathOp\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([sin(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([cos(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([tan(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([abs(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([acos(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([atan(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([atan(alice.tbl_0.plain_int_0, 3)])\",\n      \"DataScan(tbl_0)->Projection([ceil(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([ceiling(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([conv(alice.tbl_0.plain_int_0, 2, 10)])\",\n      \"DataScan(tbl_0)->Projection([cos(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([cot(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([crc32(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([degrees(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([exp(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([floor(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([ln(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([log(2, alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([log2(alice.tbl_0.plain_int_0) pi()])\",\n      \"DataScan(tbl_0)->Projection([log10(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([pow(2, alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([power(2, alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([radians(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([rand()])\",\n      \"DataScan(tbl_0)->Projection([sign(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([sqrt(alice.tbl_0.plain_int_0)])\",\n      \"DataScan(tbl_0)->Projection([truncate(alice.tbl_0.plain_int_0, 1)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderCast\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([cast(alice.tbl_0.plain_int_0)])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSimpleWithOptimization\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_int_0])\",\n      \"DataScan(tbl_0)->Projection([lt(alice.tbl_0.plain_float_0, alice.tbl_0.plain_float_1)])\",\n      \"Join{DataScan(tbl_0)->DataScan(tbl_0)}(o[eq(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)],)->Projection([alice.tbl_0.plain_int_0])\",\n      \"DataScan(tbl_0)->Projection([case(lt(alice.tbl_0.plain_int_0, 1), 0, 1)])\",\n      \"Join{DataScan(tbl_0)->DataScan(tbl_0)}(o[eq(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)],)->Projection([case(Column#241, 0, 1)])\",\n      \"DataScan(tbl_0)->Projection([case(lt(alice.tbl_0.plain_int_0, 0), -1, eq(alice.tbl_0.plain_int_0, 0), 0, 1)])\",\n      \"Join{DataScan(tbl_0)->DataScan(tbl_0)->Sel([eq(alice.tbl_0.plain_int_2, 3)])}(o[eq(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)],)->Projection([Column#241])\",\n      \"DataScan(tbl_0)->Projection([1])\",\n      \"Join{DataScan(alice)->DataScan(bob)->Sel([bob.tbl_0.plain_int_2])}([eq(alice.tbl_0.plain_int_1, bob.tbl_0.plain_int_1)],)->Projection([alice.tbl_0.plain_int_0])\",\n      \"DataScan(tbl_0)->Aggr(firstrow(alice.tbl_0.plain_int_0),firstrow(alice.tbl_0.plain_int_1))\",\n      \"DataScan(tbl_0)->Aggr(count(alice.tbl_0.plain_int_1))->Sel([ge(Column#121, 4)])->Projection([Column#121])\",\n      \"DataScan(tbl_0)->Aggr(sum(alice.tbl_0.plain_int_1),count(1))->Sel([ge(Column#122, 4)])->Projection([Column#121])\",\n      \"DataScan(tbl_0)->Aggr(count(alice.tbl_0.plain_int_0))->Sel([ge(Column#121, 4)])->Projection([intdiv(Column#121, Column#121)])\",\n      \"DataScan(tbl_0)->Aggr(max(alice.tbl_0.plain_int_0),min(alice.tbl_0.plain_int_0),median(alice.tbl_0.plain_int_0),percentile_disc(alice.tbl_0.plain_int_0, 0.8),count(1))->Sel([ge(Column#125, 4)])->Projection([Column#121 Column#122 Column#123 Column#124])\",\n      \"DataScan(tbl_0)->Projection([plus(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)])->Aggr(firstrow(Column#121),count(1))->Sel([ge(Column#122, 4)])->Projection([Column#121])\",\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_int_0])->Sort(alice.tbl_0.plain_int_0)\",\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_int_0])->Sort(alice.tbl_0.plain_int_0 desc)\",\n      \"DataScan(tbl_0)->Sort(alice.tbl_0.plain_int_0 desc,alice.tbl_0.plain_int_1)->Projection([alice.tbl_0.plain_int_0])\",\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_int_0])->Limit\",\n      \"UnionAll{DataScan(tbl_0)->Aggr(firstrow(alice.tbl_0.plain_int_0))->DataScan(tbl_1)->Aggr(firstrow(alice.tbl_1.plain_int_1))}->Aggr(firstrow(Column#242))\",\n      \"UnionAll{DataScan(tbl_0)->Projection([alice.tbl_0.plain_int_0])->DataScan(tbl_1)->Projection([alice.tbl_1.plain_int_1])}\",\n      \"UnionAll{UnionAll{DataScan(tbl_0)->Aggr(firstrow(alice.tbl_0.plain_int_0))->DataScan(tbl_1)->Aggr(firstrow(alice.tbl_1.plain_int_1))}->Aggr(firstrow(Column#363))->Projection([Column#361])->DataScan(tbl_2)->Projection([alice.tbl_2.plain_int_2])}\",\n      \"UnionAll{DataScan(tbl_0)->Sel([eq(alice.tbl_0.plain_int_0, 10) eq(alice.tbl_0.plain_int_1, 1)])->Aggr(firstrow(alice.tbl_0.plain_int_0))->DataScan(tbl_1)->Sel([eq(alice.tbl_1.plain_int_0, 11) eq(alice.tbl_1.plain_int_1, 2)])->Aggr(firstrow(alice.tbl_1.plain_int_0))}->Aggr(firstrow(Column#242))->Sort(Column#241)->Limit\",\n      \"UnionAll{DataScan(tbl_0)->Sel([eq(alice.tbl_0.plain_int_1, 2)])->Limit->Aggr(firstrow(alice.tbl_0.plain_int_0))->DataScan(tbl_1)->Sel([eq(alice.tbl_1.plain_int_1, 1)])->Limit->Aggr(firstrow(alice.tbl_1.plain_int_0))}->Aggr(firstrow(Column#242))->Limit\",\n      \"Join{DataScan(alice)->DataScan(bob)}([eq(alice.tbl_0.plain_int_0, bob.tbl_0.plain_int_0)],)->Aggr(count(1),sum(bob.tbl_0.plain_string_0),firstrow(alice.tbl_0.plain_string_0),firstrow(alice.tbl_0.plain_string_1))->Sel([ge(Column#241, 4)])->Projection([alice.tbl_0.plain_string_0 alice.tbl_0.plain_string_1 Column#241 Column#242])\",\n      \"DataScan(tbl_0)->Aggr(count(1),sum(alice.tbl_0.plain_int_1),min(alice.tbl_0.plain_int_1),max(alice.tbl_0.plain_int_1),avg(alice.tbl_0.plain_int_1))->Projection([Column#121 Column#122 Column#123 Column#124 Column#125])\",\n      \"UnionAll{DataScan(tbl_0)->Aggr(sum(alice.tbl_0.plain_int_0))->DataScan(tbl_1)->Aggr(sum(alice.tbl_1.plain_int_1))}->Aggr(sum(Column#243))->Projection([Column#242])\",\n      \"UnionAll{DataScan(tbl_1)->Aggr(sum(alice.tbl_1.plain_int_0),firstrow(alice.tbl_1.plain_int_1),count(1))->DataScan(tbl_2)->Aggr(sum(alice.tbl_2.plain_int_0),firstrow(alice.tbl_2.plain_int_1),count(1))}->Aggr(sum(Column#245),firstrow(Column#246),count(Column#247))->Sel([ge(Column#244, 4)])->Projection([Column#242 Column#243])\",\n      \"UnionAll{DataScan(tbl_1)->Aggr(max(alice.tbl_1.plain_int_0),firstrow(alice.tbl_1.plain_int_1),count(1))->DataScan(tbl_2)->Aggr(max(alice.tbl_2.plain_int_0),firstrow(alice.tbl_2.plain_int_1),count(1))}->Aggr(max(Column#245),firstrow(Column#246),count(Column#247))->Sel([ge(Column#244, 4)])->Projection([Column#242 Column#243])\",\n      \"UnionAll{DataScan(tbl_1)->Aggr(min(alice.tbl_1.plain_int_0),firstrow(alice.tbl_1.plain_int_1),count(1))->DataScan(tbl_2)->Aggr(min(alice.tbl_2.plain_int_0),firstrow(alice.tbl_2.plain_int_1),count(1))}->Aggr(min(Column#245),firstrow(Column#246),count(Column#247))->Sel([ge(Column#244, 4)])->Projection([Column#242 Column#243])\",\n      \"UnionAll{DataScan(tbl_1)->Projection([alice.tbl_1.plain_int_0 alice.tbl_1.plain_int_1])->DataScan(tbl_2)->Projection([alice.tbl_2.plain_int_0 alice.tbl_2.plain_int_1])}->Aggr(avg(Column#241),firstrow(Column#242),count(1))->Sel([ge(Column#244, 4)])->Projection([Column#242 Column#243])\",\n      \"UnionAll{DataScan(tbl_1)->Projection([alice.tbl_1.plain_int_0 alice.tbl_1.plain_int_1])->DataScan(tbl_2)->Projection([alice.tbl_2.plain_int_0 alice.tbl_2.plain_int_1])}->Aggr(median(Column#241),firstrow(Column#242),count(1))->Sel([ge(Column#244, 4)])->Projection([Column#242 Column#243])\",\n      \"UnionAll{DataScan(tbl_0)->Aggr(count(1),firstrow(alice.tbl_0.plain_int_1))->DataScan(tbl_0)->Aggr(count(1),firstrow(alice.tbl_0.plain_int_1))}->Aggr(count(Column#244),firstrow(Column#245))->Sel([ge(Column#243, 4)])->Projection([Column#242 Column#243])\",\n      \"DataScan(tbl_1)->Aggr(sum(alice.tbl_1.plain_int_1),firstrow(alice.tbl_1.plain_int_0),count(1))->Sel([ge(Column#123, 4)])->Sort(Column#121)->Projection([alice.tbl_1.plain_int_0])\",\n      \"UnionAll{DataScan(ta)->Aggr(firstrow(1),firstrow(alice.tbl_0.groupby_string_0))->DataScan(tb)->Aggr(firstrow(1),firstrow(bob.tbl_0.groupby_string_0))->DataScan(tc)->Aggr(firstrow(1),firstrow(carol.tbl_0.groupby_string_0))}->Aggr(firstrow(Column#365))->Aggr(count(1))->Projection([Column#362])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSelectionWithOptimization\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Aggr(sum(alice.tbl_0.plain_int_1),firstrow(alice.tbl_0.plain_int_0),count(1))->Sel([gt(Column#121, 0) ge(Column#122, 4)])->Projection([alice.tbl_0.plain_int_0])\",\n      \"DataScan(tbl_0)->Aggr(sum(alice.tbl_0.plain_int_1),firstrow(alice.tbl_0.plain_int_0),count(1))->Sel([ge(Column#123, 4)])->Sort(Column#121)->Projection([alice.tbl_0.plain_int_0])\",\n      \"DataScan(tbl_0)->Sel([gt(alice.tbl_0.plain_int_0, 10)])->Aggr(sum(alice.tbl_0.plain_int_1),firstrow(alice.tbl_0.plain_int_0),count(1))->Sel([ge(Column#122, 4)])->Projection([alice.tbl_0.plain_int_0 Column#121])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderWindowWithOptimization\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Window(rank()->Column#122)->Projection([alice.tbl_0.plain_int_0 Column#122])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderSubQueryWithOptimization\",\n    \"cases\": [\n      \"Join{DataScan(tbl_0)->DataScan(tbl_0)}(o[eq(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)],)->Projection([Column#241])\",\n      \"Join{Join{DataScan(t0)->Sel([eq(alice.tbl_0.plain_int_0, 1234)])->DataScan(t1)->Sel([eq(alice.tbl_1.plain_int_1, 3456)])}->DataScan(tbl_0)}(o[eq(alice.tbl_0.plain_int_0, alice.tbl_0.plain_int_1)],)->Projection([Column#361])\"\n    ]\n  },\n  {\n    \"name\": \"TestPlanBuilderDateTimeWithOptimization\",\n    \"cases\": [\n      \"DataScan(tbl_0)->Projection([lt(alice.tbl_0.plain_datetime_0, now())])\",\n      \"DataScan(tbl_0)->Projection([lt(alice.tbl_0.plain_timestamp_0, curdate())])\",\n      \"DataScan(tbl_0)->Projection([lt(alice.tbl_0.plain_datetime_0, curtime())])\",\n      \"DataScan(tbl_0)->Projection([adddate(alice.tbl_0.plain_datetime_0, 10, DAY)])\",\n      \"DataScan(tbl_0)->Projection([subdate(alice.tbl_0.plain_timestamp_0, 10, DAY)])\",\n      \"DataScan(tbl_0)->Projection([addtime(alice.tbl_0.plain_datetime_0, 1 1:1:1)])\",\n      \"DataScan(tbl_0)->Projection([subtime(alice.tbl_0.plain_timestamp_0, 1 1:1:1)])\",\n      \"DataScan(tbl_0)->Projection([datediff(alice.tbl_0.plain_datetime_0, alice.tbl_0.plain_datetime_1)])\",\n      \"DataScan(tbl_0)->Projection([datediff(alice.tbl_0.plain_datetime_0, alice.tbl_0.plain_timestamp_0)])\",\n      \"DataScan(tbl_0)->Projection([datediff(alice.tbl_0.plain_timestamp_0, alice.tbl_0.plain_timestamp_1)])\",\n      \"DataScan(tbl_0)->Projection([timediff(alice.tbl_0.plain_datetime_0, alice.tbl_0.plain_datetime_1)])\",\n      \"DataScan(tbl_0)->Projection([timediff(alice.tbl_0.plain_datetime_0, alice.tbl_0.plain_timestamp_0)])\",\n      \"DataScan(tbl_0)->Projection([timediff(alice.tbl_0.plain_timestamp_0, alice.tbl_0.plain_timestamp_1)])\",\n      \"DataScan(tbl_0)->Projection([last_day(alice.tbl_0.plain_timestamp_0)])\",\n      \"DataScan(tbl_0)->Projection([str_to_date(August 10 2017, %M %d %Y)])\",\n      \"DataScan(tbl_0)->Projection([date_format(alice.tbl_0.plain_datetime_0, %Y-%m-%d %H:%i:%S)])\",\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_datetime_0 alice.tbl_0.plain_timestamp_0])\",\n      \"DataScan(tbl_0)->Projection([lt(alice.tbl_0.plain_datetime_0, alice.tbl_0.plain_datetime_1)])\",\n      \"DataScan(tbl_0)->Projection([lt(alice.tbl_0.plain_timestamp_0, alice.tbl_0.plain_timestamp_1)])\",\n      \"DataScan(tbl_0)->Projection([lt(alice.tbl_0.plain_datetime_0, alice.tbl_0.plain_timestamp_0)])\",\n      \"Join{DataScan(tbl_0)->DataScan(tbl_0)}(o[eq(alice.tbl_0.plain_datetime_0, alice.tbl_0.plain_timestamp_0)],)->Projection([alice.tbl_0.plain_datetime_0])\",\n      \"DataScan(tbl_0)->Projection([case(lt(alice.tbl_0.plain_datetime_0, 2020-10-10), 0, 1)])\",\n      \"Join{DataScan(tbl_0)->DataScan(tbl_1)}(o[eq(alice.tbl_0.plain_datetime_0, alice.tbl_1.plain_timestamp_1)],)->Projection([case(Column#241, 0, 1)])\",\n      \"Join{DataScan(tbl_0)->DataScan(tbl_0)->Sel([eq(alice.tbl_0.plain_datetime_1, 2020-10-10 10:10:10)])}(o[eq(alice.tbl_0.plain_datetime_0, alice.tbl_0.plain_datetime_1)],)->Projection([Column#241])\",\n      \"DataScan(tbl_0)->Aggr(firstrow(alice.tbl_0.plain_datetime_0),firstrow(alice.tbl_0.plain_timestamp_0))\",\n      \"DataScan(tbl_0)->Aggr(count(alice.tbl_0.plain_int_1))->Sel([ge(Column#121, 4)])->Projection([Column#121])\",\n      \"DataScan(tbl_0)->Aggr(max(alice.tbl_0.plain_timestamp_0),min(alice.tbl_0.plain_timestamp_0),median(alice.tbl_0.plain_timestamp_0),count(1))->Sel([ge(Column#124, 4)])->Projection([Column#121 Column#122 Column#123])\",\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_datetime_0])->Sort(alice.tbl_0.plain_datetime_0)\",\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_datetime_0])->Sort(alice.tbl_0.plain_datetime_0 desc)\",\n      \"DataScan(tbl_0)->Sort(alice.tbl_0.plain_datetime_0 desc,alice.tbl_0.plain_timestamp_0)->Projection([alice.tbl_0.plain_datetime_0])\",\n      \"DataScan(tbl_0)->Projection([alice.tbl_0.plain_datetime_0])->Limit\"\n    ]\n  }\n]\n"
  },
  {
    "path": "pkg/planner/core/util.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage core\n\nimport (\n\t\"github.com/secretflow/scql/pkg/expression\"\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n)\n\n// AggregateFuncExtractor visits Expr tree.\n// It converts ColunmNameExpr to AggregateFuncExpr and collects AggregateFuncExpr.\ntype AggregateFuncExtractor struct {\n\tinAggregateFuncExpr bool\n\t// AggFuncs is the collected AggregateFuncExprs.\n\tAggFuncs []*ast.AggregateFuncExpr\n}\n\n// Enter implements Visitor interface.\nfunc (a *AggregateFuncExtractor) Enter(n ast.Node) (ast.Node, bool) {\n\tswitch n.(type) {\n\tcase *ast.AggregateFuncExpr:\n\t\ta.inAggregateFuncExpr = true\n\tcase *ast.SelectStmt, *ast.UnionStmt:\n\t\treturn n, true\n\t}\n\treturn n, false\n}\n\n// Leave implements Visitor interface.\nfunc (a *AggregateFuncExtractor) Leave(n ast.Node) (ast.Node, bool) {\n\tswitch v := n.(type) {\n\tcase *ast.AggregateFuncExpr:\n\t\ta.inAggregateFuncExpr = false\n\t\ta.AggFuncs = append(a.AggFuncs, v)\n\t}\n\treturn n, true\n}\n\n// WindowFuncExtractor visits Expr tree.\n// It converts ColunmNameExpr to WindowFuncExpr and collects WindowFuncExpr.\ntype WindowFuncExtractor struct {\n\t// WindowFuncs is the collected WindowFuncExprs.\n\twindowFuncs []*ast.WindowFuncExpr\n}\n\n// Enter implements Visitor interface.\nfunc (a *WindowFuncExtractor) Enter(n ast.Node) (ast.Node, bool) {\n\tswitch n.(type) {\n\tcase *ast.SelectStmt, *ast.UnionStmt:\n\t\treturn n, true\n\t}\n\treturn n, false\n}\n\n// Leave implements Visitor interface.\nfunc (a *WindowFuncExtractor) Leave(n ast.Node) (ast.Node, bool) {\n\tswitch v := n.(type) {\n\tcase *ast.WindowFuncExpr:\n\t\ta.windowFuncs = append(a.windowFuncs, v)\n\t}\n\treturn n, true\n}\n\n// logicalSchemaProducer stores the schema for the logical plans who can produce schema directly.\ntype logicalSchemaProducer struct {\n\tschema *expression.Schema\n\tnames  types.NameSlice\n\tbaseLogicalPlan\n}\n\n// Schema implements the Plan.Schema interface.\nfunc (s *logicalSchemaProducer) Schema() *expression.Schema {\n\tif s.schema == nil {\n\t\ts.schema = expression.NewSchema()\n\t}\n\treturn s.schema\n}\n\nfunc (s *logicalSchemaProducer) OutputNames() types.NameSlice {\n\treturn s.names\n}\n\nfunc (s *logicalSchemaProducer) SetOutputNames(names types.NameSlice) {\n\ts.names = names\n}\n\nfunc (s *logicalSchemaProducer) SetSchema(schema *expression.Schema) {\n\ts.schema = schema\n}\n\nfunc buildLogicalJoinSchema(joinType JoinType, join LogicalPlan, parentUsedCols []*expression.Column) *expression.Schema {\n\tleftSchema := join.Children()[0].Schema()\n\tswitch joinType {\n\tcase SemiJoin, AntiSemiJoin:\n\t\treturn leftSchema.Clone()\n\tcase LeftOuterSemiJoin, AntiLeftOuterSemiJoin:\n\t\tnewSchema := leftSchema.Clone()\n\t\tnewSchema.Append(join.Schema().Columns[join.Schema().Len()-1])\n\t\treturn newSchema\n\t}\n\tnewSchema := expression.MergeSchema(leftSchema, join.Children()[1].Schema())\n\tif joinType == LeftOuterJoin {\n\t\tresetNotNullFlag(newSchema, leftSchema.Len(), newSchema.Len())\n\t} else if joinType == RightOuterJoin {\n\t\tresetNotNullFlag(newSchema, 0, leftSchema.Len())\n\t}\n\tif len(parentUsedCols) != 0 {\n\t\tused := GetUsedList(parentUsedCols, newSchema)\n\t\tnewSchema.Columns = sliceutil.Take(newSchema.Columns, used)\n\t} else {\n\t\t// if parent node don't use any column, we only keep the first column\n\t\tnewSchema.Columns = []*expression.Column{newSchema.Columns[0]}\n\t}\n\treturn newSchema\n}\n\n// baseSchemaProducer stores the schema for the base plans who can produce schema directly.\ntype baseSchemaProducer struct {\n\tschema *expression.Schema\n\tnames  types.NameSlice\n\tbasePlan\n}\n\n// OutputNames returns the outputting names of each column.\nfunc (s *baseSchemaProducer) OutputNames() types.NameSlice {\n\treturn s.names\n}\n\nfunc (s *baseSchemaProducer) SetOutputNames(names types.NameSlice) {\n\ts.names = names\n}\n\n// Schema implements the Plan.Schema interface.\nfunc (s *baseSchemaProducer) Schema() *expression.Schema {\n\tif s.schema == nil {\n\t\ts.schema = expression.NewSchema()\n\t}\n\treturn s.schema\n}\n\n// SetSchema implements the Plan.SetSchema interface.\nfunc (s *baseSchemaProducer) SetSchema(schema *expression.Schema) {\n\ts.schema = schema\n}\n\nfunc (s *baseSchemaProducer) setSchemaAndNames(schema *expression.Schema, names types.NameSlice) {\n\ts.schema = schema\n\ts.names = names\n}\n\nfunc GetUsedList(usedCols []*expression.Column, schema *expression.Schema) []bool {\n\ttmpSchema := expression.NewSchema(usedCols...)\n\tused := make([]bool, schema.Len())\n\tfor i, col := range schema.Columns {\n\t\tused[i] = tmpSchema.Contains(col)\n\t}\n\treturn used\n}\n"
  },
  {
    "path": "pkg/planner/property/property.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage property\n\nimport \"github.com/secretflow/scql/pkg/expression\"\n\ntype Item struct {\n\tCol  *expression.Column\n\tDesc bool\n}\n"
  },
  {
    "path": "pkg/planner/util/custom_vistor.go",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage util\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\n\t\"github.com/secretflow/scql/pkg/parser\"\n)\n\n// selectIntoPartyCollector collects into parties from SelectStmt which has INTO clause.\ntype selectIntoPartyCollector struct {\n\tparties []string\n}\n\n// Enter implements Visitor interface.\nfunc (collector *selectIntoPartyCollector) Enter(in ast.Node) (out ast.Node, skipChildren bool) {\n\tswitch node := in.(type) {\n\tcase *ast.SelectStmt:\n\t\tif node.SelectIntoOpt != nil {\n\t\t\tfor _, partyFile := range node.SelectIntoOpt.PartyFiles {\n\t\t\t\tif partyFile.PartyCode != \"\" {\n\t\t\t\t\tcollector.parties = append(collector.parties, partyFile.PartyCode)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn in, true\n\t}\n\treturn in, false\n}\n\n// Leave implements Visitor interface.\nfunc (collector *selectIntoPartyCollector) Leave(in ast.Node) (out ast.Node, ok bool) {\n\treturn in, true\n}\n\n// NOTE: collect parties in SELECT INTO clause, but the empty party will be ignored.\n//\n//\te.g: no party will be collected from \"select xxx into outfile '/path/to/file';\"\nfunc CollectIntoParties(sql string) ([]string, error) {\n\tp := parser.New()\n\tstmts, _, err := p.Parse(sql, \"\", \"\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tstmt := stmts[0]\n\tc := &selectIntoPartyCollector{}\n\tstmt.Accept(c)\n\n\treturn c.parties, nil\n\n}\n"
  },
  {
    "path": "pkg/planner/util/custom_vistor_test.go",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage util_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/planner/util\"\n)\n\nfunc TestCollectIntoParties(t *testing.T) {\n\tr := require.New(t)\n\t{\n\t\tsql := \"select * from dt1.test\"\n\t\tparties, err := util.CollectIntoParties(sql)\n\t\tr.NoError(err)\n\t\tr.Equal(0, len(parties))\n\t}\n\n\t{\n\t\tsql := \"select test.id from dt1.test into outfile party_code 'bob' '/tmp/file.csv' party_code 'carol' '/tmp/file.csv'\"\n\t\tparties, err := util.CollectIntoParties(sql)\n\t\tr.NoError(err)\n\t\tr.Equal(2, len(parties))\n\t}\n\n\t{\n\t\tsql := \"select test.id from dt1.test into outfile '/tmp/file.csv'\"\n\t\tparties, err := util.CollectIntoParties(sql)\n\t\tr.NoError(err)\n\t\tr.Equal(0, len(parties))\n\t}\n\n}\n"
  },
  {
    "path": "pkg/planner/util/debug_util.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//\thttp://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\npackage util\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/planner/core\"\n)\n\n// Helper function to print the details of a LogicalPlan\nfunc printPlanDetails(plan core.LogicalPlan, level int) {\n\tindent := \"    \"\n\tfor i := 0; i < level; i++ {\n\t\tindent += \"    \"\n\t}\n\n\tfmt.Printf(\"%sPlan ID: %d\\n\", indent, plan.ID())\n\tfmt.Printf(\"%sPlan Type: %s\\n\", indent, plan.TP())\n\tfor _, col := range plan.Schema().Columns {\n\t\tfmt.Printf(\"%s Column: %d, %s\\n\", indent, col.UniqueID, col.OrigName)\n\t}\n\tfmt.Println()\n\tfmt.Println(indent + \"Children:\")\n\tfor _, child := range plan.Children() {\n\t\tprintPlanDetails(child, level+1)\n\t}\n}\n\n// Debug function to print the logical plan\nfunc PrintLogicalPlan(plan core.LogicalPlan) {\n\tfmt.Println(\"Logical Plan:\")\n\tprintPlanDetails(plan, 0)\n}\n"
  },
  {
    "path": "pkg/planner/util/path.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage util\n\n// AccessPath indicates the way we access a table: using table scan.\ntype AccessPath struct {\n\tIsTablePath bool\n}\n"
  },
  {
    "path": "pkg/proto-gen/scql/common.pb.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.3\n// \tprotoc        v5.27.3\n// source: api/common.proto\n\npackage scql\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tanypb \"google.golang.org/protobuf/types/known/anypb\"\n\ttimestamppb \"google.golang.org/protobuf/types/known/timestamppb\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype JobState int32\n\nconst (\n\tJobState_JOB_STATE_UNSPECIFIED JobState = 0\n\tJobState_JOB_INITIALIZED       JobState = 1\n\tJobState_JOB_RUNNING           JobState = 2\n\tJobState_JOB_SUCCEEDED         JobState = 3\n\tJobState_JOB_FAILED            JobState = 4\n\tJobState_JOB_CANCELED          JobState = 5\n)\n\n// Enum value maps for JobState.\nvar (\n\tJobState_name = map[int32]string{\n\t\t0: \"JOB_STATE_UNSPECIFIED\",\n\t\t1: \"JOB_INITIALIZED\",\n\t\t2: \"JOB_RUNNING\",\n\t\t3: \"JOB_SUCCEEDED\",\n\t\t4: \"JOB_FAILED\",\n\t\t5: \"JOB_CANCELED\",\n\t}\n\tJobState_value = map[string]int32{\n\t\t\"JOB_STATE_UNSPECIFIED\": 0,\n\t\t\"JOB_INITIALIZED\":       1,\n\t\t\"JOB_RUNNING\":           2,\n\t\t\"JOB_SUCCEEDED\":         3,\n\t\t\"JOB_FAILED\":            4,\n\t\t\"JOB_CANCELED\":          5,\n\t}\n)\n\nfunc (x JobState) Enum() *JobState {\n\tp := new(JobState)\n\t*p = x\n\treturn p\n}\n\nfunc (x JobState) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (JobState) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_api_common_proto_enumTypes[0].Descriptor()\n}\n\nfunc (JobState) Type() protoreflect.EnumType {\n\treturn &file_api_common_proto_enumTypes[0]\n}\n\nfunc (x JobState) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use JobState.Descriptor instead.\nfunc (JobState) EnumDescriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{0}\n}\n\ntype PsiAlgorithmType int32\n\nconst (\n\t// auto means choosing psi type by engine\n\tPsiAlgorithmType_AUTO PsiAlgorithmType = 0\n\tPsiAlgorithmType_ECDH PsiAlgorithmType = 1\n\tPsiAlgorithmType_OPRF PsiAlgorithmType = 2\n\tPsiAlgorithmType_RR22 PsiAlgorithmType = 3\n)\n\n// Enum value maps for PsiAlgorithmType.\nvar (\n\tPsiAlgorithmType_name = map[int32]string{\n\t\t0: \"AUTO\",\n\t\t1: \"ECDH\",\n\t\t2: \"OPRF\",\n\t\t3: \"RR22\",\n\t}\n\tPsiAlgorithmType_value = map[string]int32{\n\t\t\"AUTO\": 0,\n\t\t\"ECDH\": 1,\n\t\t\"OPRF\": 2,\n\t\t\"RR22\": 3,\n\t}\n)\n\nfunc (x PsiAlgorithmType) Enum() *PsiAlgorithmType {\n\tp := new(PsiAlgorithmType)\n\t*p = x\n\treturn p\n}\n\nfunc (x PsiAlgorithmType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (PsiAlgorithmType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_api_common_proto_enumTypes[1].Descriptor()\n}\n\nfunc (PsiAlgorithmType) Type() protoreflect.EnumType {\n\treturn &file_api_common_proto_enumTypes[1]\n}\n\nfunc (x PsiAlgorithmType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use PsiAlgorithmType.Descriptor instead.\nfunc (PsiAlgorithmType) EnumDescriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{1}\n}\n\ntype Rr22Mode int32\n\nconst (\n\tRr22Mode_UNDEFINED Rr22Mode = 0\n\tRr22Mode_LOW_MODE  Rr22Mode = 1\n\tRr22Mode_FAST_MODE Rr22Mode = 2\n)\n\n// Enum value maps for Rr22Mode.\nvar (\n\tRr22Mode_name = map[int32]string{\n\t\t0: \"UNDEFINED\",\n\t\t1: \"LOW_MODE\",\n\t\t2: \"FAST_MODE\",\n\t}\n\tRr22Mode_value = map[string]int32{\n\t\t\"UNDEFINED\": 0,\n\t\t\"LOW_MODE\":  1,\n\t\t\"FAST_MODE\": 2,\n\t}\n)\n\nfunc (x Rr22Mode) Enum() *Rr22Mode {\n\tp := new(Rr22Mode)\n\t*p = x\n\treturn p\n}\n\nfunc (x Rr22Mode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Rr22Mode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_api_common_proto_enumTypes[2].Descriptor()\n}\n\nfunc (Rr22Mode) Type() protoreflect.EnumType {\n\treturn &file_api_common_proto_enumTypes[2]\n}\n\nfunc (x Rr22Mode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Rr22Mode.Descriptor instead.\nfunc (Rr22Mode) EnumDescriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{2}\n}\n\n// RequestHeader carries the user custom headers.\ntype RequestHeader struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Custom headers used to record custom information.\n\tCustomHeaders map[string]string `protobuf:\"bytes,1,rep,name=custom_headers,json=customHeaders,proto3\" json:\"custom_headers,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RequestHeader) Reset() {\n\t*x = RequestHeader{}\n\tmi := &file_api_common_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RequestHeader) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RequestHeader) ProtoMessage() {}\n\nfunc (x *RequestHeader) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RequestHeader.ProtoReflect.Descriptor instead.\nfunc (*RequestHeader) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *RequestHeader) GetCustomHeaders() map[string]string {\n\tif x != nil {\n\t\treturn x.CustomHeaders\n\t}\n\treturn nil\n}\n\ntype DebugOptions struct {\n\tstate              protoimpl.MessageState `protogen:\"open.v1\"`\n\tEnablePsiDetailLog bool                   `protobuf:\"varint,1,opt,name=enable_psi_detail_log,json=enablePsiDetailLog,proto3\" json:\"enable_psi_detail_log,omitempty\"`\n\tunknownFields      protoimpl.UnknownFields\n\tsizeCache          protoimpl.SizeCache\n}\n\nfunc (x *DebugOptions) Reset() {\n\t*x = DebugOptions{}\n\tmi := &file_api_common_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DebugOptions) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DebugOptions) ProtoMessage() {}\n\nfunc (x *DebugOptions) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DebugOptions.ProtoReflect.Descriptor instead.\nfunc (*DebugOptions) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *DebugOptions) GetEnablePsiDetailLog() bool {\n\tif x != nil {\n\t\treturn x.EnablePsiDetailLog\n\t}\n\treturn false\n}\n\n// (-- TODO: move SQLWarning to a proper place --)\ntype SQLWarning struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Description of the warning\n\tReason        string `protobuf:\"bytes,1,opt,name=reason,proto3\" json:\"reason,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SQLWarning) Reset() {\n\t*x = SQLWarning{}\n\tmi := &file_api_common_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SQLWarning) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SQLWarning) ProtoMessage() {}\n\nfunc (x *SQLWarning) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SQLWarning.ProtoReflect.Descriptor instead.\nfunc (*SQLWarning) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *SQLWarning) GetReason() string {\n\tif x != nil {\n\t\treturn x.Reason\n\t}\n\treturn \"\"\n}\n\n// IOStats contains input/output statistics for a job, including bytes sent and\n// received, as well as the number of send and receive actions performed.\ntype IOStats struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tSendBytes     uint64                 `protobuf:\"varint,1,opt,name=send_bytes,json=sendBytes,proto3\" json:\"send_bytes,omitempty\"`\n\tRecvBytes     uint64                 `protobuf:\"varint,2,opt,name=recv_bytes,json=recvBytes,proto3\" json:\"recv_bytes,omitempty\"`\n\tSendActions   uint64                 `protobuf:\"varint,3,opt,name=send_actions,json=sendActions,proto3\" json:\"send_actions,omitempty\"`\n\tRecvActions   uint64                 `protobuf:\"varint,4,opt,name=recv_actions,json=recvActions,proto3\" json:\"recv_actions,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *IOStats) Reset() {\n\t*x = IOStats{}\n\tmi := &file_api_common_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *IOStats) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*IOStats) ProtoMessage() {}\n\nfunc (x *IOStats) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use IOStats.ProtoReflect.Descriptor instead.\nfunc (*IOStats) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *IOStats) GetSendBytes() uint64 {\n\tif x != nil {\n\t\treturn x.SendBytes\n\t}\n\treturn 0\n}\n\nfunc (x *IOStats) GetRecvBytes() uint64 {\n\tif x != nil {\n\t\treturn x.RecvBytes\n\t}\n\treturn 0\n}\n\nfunc (x *IOStats) GetSendActions() uint64 {\n\tif x != nil {\n\t\treturn x.SendActions\n\t}\n\treturn 0\n}\n\nfunc (x *IOStats) GetRecvActions() uint64 {\n\tif x != nil {\n\t\treturn x.RecvActions\n\t}\n\treturn 0\n}\n\n// StageInfo provides information about an individual stage within a running\n// job.\ntype StageInfo struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The name of the stage.\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// A brief summary describing the stage\n\tSummary string `protobuf:\"bytes,2,opt,name=summary,proto3\" json:\"summary,omitempty\"`\n\t// Stage start time\n\tStartTime *timestamppb.Timestamp `protobuf:\"bytes,3,opt,name=start_time,json=startTime,proto3\" json:\"start_time,omitempty\"`\n\t// Personalized details that may have different structures depending on the\n\t// stage type.\n\tDetails       *anypb.Any `protobuf:\"bytes,4,opt,name=details,proto3\" json:\"details,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *StageInfo) Reset() {\n\t*x = StageInfo{}\n\tmi := &file_api_common_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StageInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StageInfo) ProtoMessage() {}\n\nfunc (x *StageInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StageInfo.ProtoReflect.Descriptor instead.\nfunc (*StageInfo) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *StageInfo) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *StageInfo) GetSummary() string {\n\tif x != nil {\n\t\treturn x.Summary\n\t}\n\treturn \"\"\n}\n\nfunc (x *StageInfo) GetStartTime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.StartTime\n\t}\n\treturn nil\n}\n\nfunc (x *StageInfo) GetDetails() *anypb.Any {\n\tif x != nil {\n\t\treturn x.Details\n\t}\n\treturn nil\n}\n\n// JobProgress provides detailed information about the progress of a running\n// job.\ntype JobProgress struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Job start time\n\tStartTime *timestamppb.Timestamp `protobuf:\"bytes,1,opt,name=start_time,json=startTime,proto3\" json:\"start_time,omitempty\"`\n\t// The total number of stages planned for the job.\n\tStagesCount int32 `protobuf:\"varint,2,opt,name=stages_count,json=stagesCount,proto3\" json:\"stages_count,omitempty\"`\n\t// The number of stages that have been executed so far.\n\tExecutedStages int32    `protobuf:\"varint,3,opt,name=executed_stages,json=executedStages,proto3\" json:\"executed_stages,omitempty\"`\n\tIoStats        *IOStats `protobuf:\"bytes,4,opt,name=io_stats,json=ioStats,proto3\" json:\"io_stats,omitempty\"`\n\t// A list of currently running stages, providing insight into which parts of\n\t// the job are active.\n\tRunningStages []*StageInfo `protobuf:\"bytes,5,rep,name=running_stages,json=runningStages,proto3\" json:\"running_stages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *JobProgress) Reset() {\n\t*x = JobProgress{}\n\tmi := &file_api_common_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *JobProgress) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*JobProgress) ProtoMessage() {}\n\nfunc (x *JobProgress) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use JobProgress.ProtoReflect.Descriptor instead.\nfunc (*JobProgress) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *JobProgress) GetStartTime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.StartTime\n\t}\n\treturn nil\n}\n\nfunc (x *JobProgress) GetStagesCount() int32 {\n\tif x != nil {\n\t\treturn x.StagesCount\n\t}\n\treturn 0\n}\n\nfunc (x *JobProgress) GetExecutedStages() int32 {\n\tif x != nil {\n\t\treturn x.ExecutedStages\n\t}\n\treturn 0\n}\n\nfunc (x *JobProgress) GetIoStats() *IOStats {\n\tif x != nil {\n\t\treturn x.IoStats\n\t}\n\treturn nil\n}\n\nfunc (x *JobProgress) GetRunningStages() []*StageInfo {\n\tif x != nil {\n\t\treturn x.RunningStages\n\t}\n\treturn nil\n}\n\ntype LinkConfig struct {\n\tstate                       protoimpl.MessageState `protogen:\"open.v1\"`\n\tLinkRecvTimeoutSec          int64                  `protobuf:\"varint,1,opt,name=link_recv_timeout_sec,json=linkRecvTimeoutSec,proto3\" json:\"link_recv_timeout_sec,omitempty\"`\n\tLinkThrottleWindowSize      int64                  `protobuf:\"varint,2,opt,name=link_throttle_window_size,json=linkThrottleWindowSize,proto3\" json:\"link_throttle_window_size,omitempty\"`\n\tLinkChunkedSendParallelSize int64                  `protobuf:\"varint,3,opt,name=link_chunked_send_parallel_size,json=linkChunkedSendParallelSize,proto3\" json:\"link_chunked_send_parallel_size,omitempty\"`\n\tHttpMaxPayloadSize          int64                  `protobuf:\"varint,4,opt,name=http_max_payload_size,json=httpMaxPayloadSize,proto3\" json:\"http_max_payload_size,omitempty\"`\n\tunknownFields               protoimpl.UnknownFields\n\tsizeCache                   protoimpl.SizeCache\n}\n\nfunc (x *LinkConfig) Reset() {\n\t*x = LinkConfig{}\n\tmi := &file_api_common_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LinkConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LinkConfig) ProtoMessage() {}\n\nfunc (x *LinkConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LinkConfig.ProtoReflect.Descriptor instead.\nfunc (*LinkConfig) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *LinkConfig) GetLinkRecvTimeoutSec() int64 {\n\tif x != nil {\n\t\treturn x.LinkRecvTimeoutSec\n\t}\n\treturn 0\n}\n\nfunc (x *LinkConfig) GetLinkThrottleWindowSize() int64 {\n\tif x != nil {\n\t\treturn x.LinkThrottleWindowSize\n\t}\n\treturn 0\n}\n\nfunc (x *LinkConfig) GetLinkChunkedSendParallelSize() int64 {\n\tif x != nil {\n\t\treturn x.LinkChunkedSendParallelSize\n\t}\n\treturn 0\n}\n\nfunc (x *LinkConfig) GetHttpMaxPayloadSize() int64 {\n\tif x != nil {\n\t\treturn x.HttpMaxPayloadSize\n\t}\n\treturn 0\n}\n\ntype PsiConfig struct {\n\tstate        protoimpl.MessageState `protogen:\"open.v1\"`\n\tPsiCurveType int32                  `protobuf:\"varint,1,opt,name=psi_curve_type,json=psiCurveType,proto3\" json:\"psi_curve_type,omitempty\"`\n\tPsiType      PsiAlgorithmType       `protobuf:\"varint,2,opt,name=psi_type,json=psiType,proto3,enum=scql.pb.PsiAlgorithmType\" json:\"psi_type,omitempty\"`\n\t// activated when psi_type is rr22\n\tRr22Mode      Rr22Mode `protobuf:\"varint,3,opt,name=rr22_mode,json=rr22Mode,proto3,enum=scql.pb.Rr22Mode\" json:\"rr22_mode,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PsiConfig) Reset() {\n\t*x = PsiConfig{}\n\tmi := &file_api_common_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PsiConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PsiConfig) ProtoMessage() {}\n\nfunc (x *PsiConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PsiConfig.ProtoReflect.Descriptor instead.\nfunc (*PsiConfig) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *PsiConfig) GetPsiCurveType() int32 {\n\tif x != nil {\n\t\treturn x.PsiCurveType\n\t}\n\treturn 0\n}\n\nfunc (x *PsiConfig) GetPsiType() PsiAlgorithmType {\n\tif x != nil {\n\t\treturn x.PsiType\n\t}\n\treturn PsiAlgorithmType_AUTO\n}\n\nfunc (x *PsiConfig) GetRr22Mode() Rr22Mode {\n\tif x != nil {\n\t\treturn x.Rr22Mode\n\t}\n\treturn Rr22Mode_UNDEFINED\n}\n\ntype LogConfig struct {\n\tstate                         protoimpl.MessageState `protogen:\"open.v1\"`\n\tEnableSessionLoggerSeparation bool                   `protobuf:\"varint,1,opt,name=enable_session_logger_separation,json=enableSessionLoggerSeparation,proto3\" json:\"enable_session_logger_separation,omitempty\"`\n\tunknownFields                 protoimpl.UnknownFields\n\tsizeCache                     protoimpl.SizeCache\n}\n\nfunc (x *LogConfig) Reset() {\n\t*x = LogConfig{}\n\tmi := &file_api_common_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LogConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LogConfig) ProtoMessage() {}\n\nfunc (x *LogConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LogConfig.ProtoReflect.Descriptor instead.\nfunc (*LogConfig) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *LogConfig) GetEnableSessionLoggerSeparation() bool {\n\tif x != nil {\n\t\treturn x.EnableSessionLoggerSeparation\n\t}\n\treturn false\n}\n\ntype Placeholder struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// placeholder name\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// placeholder name, e.g. string, int64, float\n\tDataType      string `protobuf:\"bytes,2,opt,name=data_type,json=dataType,proto3\" json:\"data_type,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Placeholder) Reset() {\n\t*x = Placeholder{}\n\tmi := &file_api_common_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Placeholder) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Placeholder) ProtoMessage() {}\n\nfunc (x *Placeholder) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Placeholder.ProtoReflect.Descriptor instead.\nfunc (*Placeholder) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *Placeholder) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Placeholder) GetDataType() string {\n\tif x != nil {\n\t\treturn x.DataType\n\t}\n\treturn \"\"\n}\n\ntype Placeholders struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPlaceholders  []*Placeholder         `protobuf:\"bytes,1,rep,name=placeholders,proto3\" json:\"placeholders,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Placeholders) Reset() {\n\t*x = Placeholders{}\n\tmi := &file_api_common_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Placeholders) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Placeholders) ProtoMessage() {}\n\nfunc (x *Placeholders) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Placeholders.ProtoReflect.Descriptor instead.\nfunc (*Placeholders) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *Placeholders) GetPlaceholders() []*Placeholder {\n\tif x != nil {\n\t\treturn x.Placeholders\n\t}\n\treturn nil\n}\n\ntype Variable struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tStringData    string                 `protobuf:\"bytes,2,opt,name=string_data,json=stringData,proto3\" json:\"string_data,omitempty\"`\n\tInt64Data     int64                  `protobuf:\"varint,3,opt,name=int64_data,json=int64Data,proto3\" json:\"int64_data,omitempty\"`\n\tFloatData     float32                `protobuf:\"fixed32,4,opt,name=float_data,json=floatData,proto3\" json:\"float_data,omitempty\"`\n\tBoolData      bool                   `protobuf:\"varint,5,opt,name=bool_data,json=boolData,proto3\" json:\"bool_data,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Variable) Reset() {\n\t*x = Variable{}\n\tmi := &file_api_common_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Variable) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Variable) ProtoMessage() {}\n\nfunc (x *Variable) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_common_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Variable.ProtoReflect.Descriptor instead.\nfunc (*Variable) Descriptor() ([]byte, []int) {\n\treturn file_api_common_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *Variable) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Variable) GetStringData() string {\n\tif x != nil {\n\t\treturn x.StringData\n\t}\n\treturn \"\"\n}\n\nfunc (x *Variable) GetInt64Data() int64 {\n\tif x != nil {\n\t\treturn x.Int64Data\n\t}\n\treturn 0\n}\n\nfunc (x *Variable) GetFloatData() float32 {\n\tif x != nil {\n\t\treturn x.FloatData\n\t}\n\treturn 0\n}\n\nfunc (x *Variable) GetBoolData() bool {\n\tif x != nil {\n\t\treturn x.BoolData\n\t}\n\treturn false\n}\n\nvar File_api_common_proto protoreflect.FileDescriptor\n\nvar file_api_common_proto_rawDesc = []byte{\n\t0x0a, 0x10, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x12, 0x07, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x1a, 0x1f, 0x67, 0x6f, 0x6f,\n\t0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d,\n\t0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f,\n\t0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e,\n\t0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa3, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x50, 0x0a, 0x0e, 0x63, 0x75, 0x73,\n\t0x74, 0x6f, 0x6d, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x29, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d,\n\t0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x63, 0x75,\n\t0x73, 0x74, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x43,\n\t0x75, 0x73, 0x74, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72,\n\t0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,\n\t0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x41, 0x0a,\n\t0x0c, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x31, 0x0a,\n\t0x15, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x73, 0x69, 0x5f, 0x64, 0x65, 0x74, 0x61,\n\t0x69, 0x6c, 0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x65, 0x6e,\n\t0x61, 0x62, 0x6c, 0x65, 0x50, 0x73, 0x69, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x4c, 0x6f, 0x67,\n\t0x22, 0x24, 0x0a, 0x0a, 0x53, 0x51, 0x4c, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x16,\n\t0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,\n\t0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x8d, 0x01, 0x0a, 0x07, 0x49, 0x4f, 0x53, 0x74, 0x61,\n\t0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x42, 0x79, 0x74, 0x65,\n\t0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x63, 0x76, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18,\n\t0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x63, 0x76, 0x42, 0x79, 0x74, 0x65, 0x73,\n\t0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x65, 0x6e, 0x64, 0x41, 0x63, 0x74, 0x69,\n\t0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x63, 0x76, 0x5f, 0x61, 0x63, 0x74, 0x69,\n\t0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x72, 0x65, 0x63, 0x76, 0x41,\n\t0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa4, 0x01, 0x0a, 0x09, 0x53, 0x74, 0x61, 0x67, 0x65,\n\t0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d,\n\t0x61, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61,\n\t0x72, 0x79, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,\n\t0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2e, 0x0a,\n\t0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14,\n\t0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,\n\t0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0xfc, 0x01,\n\t0x0a, 0x0b, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x39, 0x0a,\n\t0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73,\n\t0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x67,\n\t0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b,\n\t0x73, 0x74, 0x61, 0x67, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x65,\n\t0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x65, 0x73, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x53, 0x74,\n\t0x61, 0x67, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x08, 0x69, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73,\n\t0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62,\n\t0x2e, 0x49, 0x4f, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x07, 0x69, 0x6f, 0x53, 0x74, 0x61, 0x74,\n\t0x73, 0x12, 0x39, 0x0a, 0x0e, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61,\n\t0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x63, 0x71, 0x6c,\n\t0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x72,\n\t0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x67, 0x65, 0x73, 0x22, 0xf3, 0x01, 0x0a,\n\t0x0a, 0x4c, 0x69, 0x6e, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x31, 0x0a, 0x15, 0x6c,\n\t0x69, 0x6e, 0x6b, 0x5f, 0x72, 0x65, 0x63, 0x76, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,\n\t0x5f, 0x73, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x6c, 0x69, 0x6e, 0x6b,\n\t0x52, 0x65, 0x63, 0x76, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x12, 0x39,\n\t0x0a, 0x19, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x5f,\n\t0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x03, 0x52, 0x16, 0x6c, 0x69, 0x6e, 0x6b, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x57,\n\t0x69, 0x6e, 0x64, 0x6f, 0x77, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x44, 0x0a, 0x1f, 0x6c, 0x69, 0x6e,\n\t0x6b, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x70,\n\t0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01,\n\t0x28, 0x03, 0x52, 0x1b, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x65, 0x64, 0x53,\n\t0x65, 0x6e, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x12,\n\t0x31, 0x0a, 0x15, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x61, 0x79, 0x6c,\n\t0x6f, 0x61, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12,\n\t0x68, 0x74, 0x74, 0x70, 0x4d, 0x61, 0x78, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x69,\n\t0x7a, 0x65, 0x22, 0x97, 0x01, 0x0a, 0x09, 0x50, 0x73, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x12, 0x24, 0x0a, 0x0e, 0x70, 0x73, 0x69, 0x5f, 0x63, 0x75, 0x72, 0x76, 0x65, 0x5f, 0x74, 0x79,\n\t0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x73, 0x69, 0x43, 0x75, 0x72,\n\t0x76, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x70, 0x73, 0x69, 0x5f, 0x74, 0x79,\n\t0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e,\n\t0x70, 0x62, 0x2e, 0x50, 0x73, 0x69, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x54,\n\t0x79, 0x70, 0x65, 0x52, 0x07, 0x70, 0x73, 0x69, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x09,\n\t0x72, 0x72, 0x32, 0x32, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,\n\t0x11, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x72, 0x32, 0x32, 0x4d, 0x6f,\n\t0x64, 0x65, 0x52, 0x08, 0x72, 0x72, 0x32, 0x32, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0x54, 0x0a, 0x09,\n\t0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x47, 0x0a, 0x20, 0x65, 0x6e, 0x61,\n\t0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x6f, 0x67, 0x67,\n\t0x65, 0x72, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x08, 0x52, 0x1d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69,\n\t0x6f, 0x6e, 0x4c, 0x6f, 0x67, 0x67, 0x65, 0x72, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x22, 0x3e, 0x0a, 0x0b, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65,\n\t0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x74, 0x79,\n\t0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x54, 0x79,\n\t0x70, 0x65, 0x22, 0x48, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65,\n\t0x72, 0x73, 0x12, 0x38, 0x0a, 0x0c, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65,\n\t0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e,\n\t0x70, 0x62, 0x2e, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x52, 0x0c,\n\t0x70, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x22, 0x9a, 0x01, 0x0a,\n\t0x08, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,\n\t0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a,\n\t0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d,\n\t0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01,\n\t0x28, 0x03, 0x52, 0x09, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a,\n\t0x0a, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28,\n\t0x02, 0x52, 0x09, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09,\n\t0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,\n\t0x08, 0x62, 0x6f, 0x6f, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x2a, 0x80, 0x01, 0x0a, 0x08, 0x4a, 0x6f,\n\t0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4a, 0x4f, 0x42, 0x5f, 0x53, 0x54,\n\t0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,\n\t0x00, 0x12, 0x13, 0x0a, 0x0f, 0x4a, 0x4f, 0x42, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c,\n\t0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4a, 0x4f, 0x42, 0x5f, 0x52, 0x55,\n\t0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4a, 0x4f, 0x42, 0x5f, 0x53,\n\t0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x4a, 0x4f,\n\t0x42, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x4a, 0x4f,\n\t0x42, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x2a, 0x3a, 0x0a, 0x10,\n\t0x50, 0x73, 0x69, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x54, 0x79, 0x70, 0x65,\n\t0x12, 0x08, 0x0a, 0x04, 0x41, 0x55, 0x54, 0x4f, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x45, 0x43,\n\t0x44, 0x48, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4f, 0x50, 0x52, 0x46, 0x10, 0x02, 0x12, 0x08,\n\t0x0a, 0x04, 0x52, 0x52, 0x32, 0x32, 0x10, 0x03, 0x2a, 0x36, 0x0a, 0x08, 0x52, 0x72, 0x32, 0x32,\n\t0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45,\n\t0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x4f, 0x57, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x10,\n\t0x01, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x41, 0x53, 0x54, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x10, 0x02,\n\t0x42, 0x25, 0x0a, 0x13, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x66, 0x6c,\n\t0x6f, 0x77, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x5a, 0x0e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x67,\n\t0x65, 0x6e, 0x2f, 0x73, 0x63, 0x71, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_api_common_proto_rawDescOnce sync.Once\n\tfile_api_common_proto_rawDescData = file_api_common_proto_rawDesc\n)\n\nfunc file_api_common_proto_rawDescGZIP() []byte {\n\tfile_api_common_proto_rawDescOnce.Do(func() {\n\t\tfile_api_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_common_proto_rawDescData)\n\t})\n\treturn file_api_common_proto_rawDescData\n}\n\nvar file_api_common_proto_enumTypes = make([]protoimpl.EnumInfo, 3)\nvar file_api_common_proto_msgTypes = make([]protoimpl.MessageInfo, 13)\nvar file_api_common_proto_goTypes = []any{\n\t(JobState)(0),                 // 0: scql.pb.JobState\n\t(PsiAlgorithmType)(0),         // 1: scql.pb.PsiAlgorithmType\n\t(Rr22Mode)(0),                 // 2: scql.pb.Rr22Mode\n\t(*RequestHeader)(nil),         // 3: scql.pb.RequestHeader\n\t(*DebugOptions)(nil),          // 4: scql.pb.DebugOptions\n\t(*SQLWarning)(nil),            // 5: scql.pb.SQLWarning\n\t(*IOStats)(nil),               // 6: scql.pb.IOStats\n\t(*StageInfo)(nil),             // 7: scql.pb.StageInfo\n\t(*JobProgress)(nil),           // 8: scql.pb.JobProgress\n\t(*LinkConfig)(nil),            // 9: scql.pb.LinkConfig\n\t(*PsiConfig)(nil),             // 10: scql.pb.PsiConfig\n\t(*LogConfig)(nil),             // 11: scql.pb.LogConfig\n\t(*Placeholder)(nil),           // 12: scql.pb.Placeholder\n\t(*Placeholders)(nil),          // 13: scql.pb.Placeholders\n\t(*Variable)(nil),              // 14: scql.pb.Variable\n\tnil,                           // 15: scql.pb.RequestHeader.CustomHeadersEntry\n\t(*timestamppb.Timestamp)(nil), // 16: google.protobuf.Timestamp\n\t(*anypb.Any)(nil),             // 17: google.protobuf.Any\n}\nvar file_api_common_proto_depIdxs = []int32{\n\t15, // 0: scql.pb.RequestHeader.custom_headers:type_name -> scql.pb.RequestHeader.CustomHeadersEntry\n\t16, // 1: scql.pb.StageInfo.start_time:type_name -> google.protobuf.Timestamp\n\t17, // 2: scql.pb.StageInfo.details:type_name -> google.protobuf.Any\n\t16, // 3: scql.pb.JobProgress.start_time:type_name -> google.protobuf.Timestamp\n\t6,  // 4: scql.pb.JobProgress.io_stats:type_name -> scql.pb.IOStats\n\t7,  // 5: scql.pb.JobProgress.running_stages:type_name -> scql.pb.StageInfo\n\t1,  // 6: scql.pb.PsiConfig.psi_type:type_name -> scql.pb.PsiAlgorithmType\n\t2,  // 7: scql.pb.PsiConfig.rr22_mode:type_name -> scql.pb.Rr22Mode\n\t12, // 8: scql.pb.Placeholders.placeholders:type_name -> scql.pb.Placeholder\n\t9,  // [9:9] is the sub-list for method output_type\n\t9,  // [9:9] is the sub-list for method input_type\n\t9,  // [9:9] is the sub-list for extension type_name\n\t9,  // [9:9] is the sub-list for extension extendee\n\t0,  // [0:9] is the sub-list for field type_name\n}\n\nfunc init() { file_api_common_proto_init() }\nfunc file_api_common_proto_init() {\n\tif File_api_common_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_api_common_proto_rawDesc,\n\t\t\tNumEnums:      3,\n\t\t\tNumMessages:   13,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_api_common_proto_goTypes,\n\t\tDependencyIndexes: file_api_common_proto_depIdxs,\n\t\tEnumInfos:         file_api_common_proto_enumTypes,\n\t\tMessageInfos:      file_api_common_proto_msgTypes,\n\t}.Build()\n\tFile_api_common_proto = out.File\n\tfile_api_common_proto_rawDesc = nil\n\tfile_api_common_proto_goTypes = nil\n\tfile_api_common_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/proto-gen/scql/core.pb.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.3\n// \tprotoc        v5.27.3\n// source: api/core.proto\n\npackage scql\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype PrimitiveDataType int32\n\nconst (\n\tPrimitiveDataType_PrimitiveDataType_UNDEFINED PrimitiveDataType = 0\n\t// Numeric types\n\tPrimitiveDataType_INT8    PrimitiveDataType = 1 // the 8-bit signed integer type\n\tPrimitiveDataType_INT16   PrimitiveDataType = 2 // the 16-bit signed integer type\n\tPrimitiveDataType_INT32   PrimitiveDataType = 3 // the 32-bit signed integer type\n\tPrimitiveDataType_INT64   PrimitiveDataType = 4 // the 64-bit signed integer type\n\tPrimitiveDataType_FLOAT32 PrimitiveDataType = 5 // the 32-bit binary floating point type\n\tPrimitiveDataType_FLOAT64 PrimitiveDataType = 6 // the 64-bit binary floating point type\n\t// Other types\n\tPrimitiveDataType_BOOL   PrimitiveDataType = 7\n\tPrimitiveDataType_STRING PrimitiveDataType = 8\n\t// DATETIME and TIMESTAMP\n\tPrimitiveDataType_DATETIME  PrimitiveDataType = 9  // https://dev.mysql.com/doc/refman/8.0/en/datetime.html\n\tPrimitiveDataType_TIMESTAMP PrimitiveDataType = 10 // seconds since '1970-01-01 00:00:00' UTC\n\tPrimitiveDataType_DECIMAL   PrimitiveDataType = 11\n)\n\n// Enum value maps for PrimitiveDataType.\nvar (\n\tPrimitiveDataType_name = map[int32]string{\n\t\t0:  \"PrimitiveDataType_UNDEFINED\",\n\t\t1:  \"INT8\",\n\t\t2:  \"INT16\",\n\t\t3:  \"INT32\",\n\t\t4:  \"INT64\",\n\t\t5:  \"FLOAT32\",\n\t\t6:  \"FLOAT64\",\n\t\t7:  \"BOOL\",\n\t\t8:  \"STRING\",\n\t\t9:  \"DATETIME\",\n\t\t10: \"TIMESTAMP\",\n\t\t11: \"DECIMAL\",\n\t}\n\tPrimitiveDataType_value = map[string]int32{\n\t\t\"PrimitiveDataType_UNDEFINED\": 0,\n\t\t\"INT8\":                        1,\n\t\t\"INT16\":                       2,\n\t\t\"INT32\":                       3,\n\t\t\"INT64\":                       4,\n\t\t\"FLOAT32\":                     5,\n\t\t\"FLOAT64\":                     6,\n\t\t\"BOOL\":                        7,\n\t\t\"STRING\":                      8,\n\t\t\"DATETIME\":                    9,\n\t\t\"TIMESTAMP\":                   10,\n\t\t\"DECIMAL\":                     11,\n\t}\n)\n\nfunc (x PrimitiveDataType) Enum() *PrimitiveDataType {\n\tp := new(PrimitiveDataType)\n\t*p = x\n\treturn p\n}\n\nfunc (x PrimitiveDataType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (PrimitiveDataType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_api_core_proto_enumTypes[0].Descriptor()\n}\n\nfunc (PrimitiveDataType) Type() protoreflect.EnumType {\n\treturn &file_api_core_proto_enumTypes[0]\n}\n\nfunc (x PrimitiveDataType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use PrimitiveDataType.Descriptor instead.\nfunc (PrimitiveDataType) EnumDescriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{0}\n}\n\n// Tensor options.\ntype TensorOptions int32\n\nconst (\n\t// A tensor with data.\n\tTensorOptions_VALUE TensorOptions = 0\n\t// A tensor with reference (URI).\n\tTensorOptions_REFERENCE TensorOptions = 1\n\t// A tensor variable (declaration).\n\tTensorOptions_VARIABLE TensorOptions = 2\n)\n\n// Enum value maps for TensorOptions.\nvar (\n\tTensorOptions_name = map[int32]string{\n\t\t0: \"VALUE\",\n\t\t1: \"REFERENCE\",\n\t\t2: \"VARIABLE\",\n\t}\n\tTensorOptions_value = map[string]int32{\n\t\t\"VALUE\":     0,\n\t\t\"REFERENCE\": 1,\n\t\t\"VARIABLE\":  2,\n\t}\n)\n\nfunc (x TensorOptions) Enum() *TensorOptions {\n\tp := new(TensorOptions)\n\t*p = x\n\treturn p\n}\n\nfunc (x TensorOptions) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (TensorOptions) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_api_core_proto_enumTypes[1].Descriptor()\n}\n\nfunc (TensorOptions) Type() protoreflect.EnumType {\n\treturn &file_api_core_proto_enumTypes[1]\n}\n\nfunc (x TensorOptions) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use TensorOptions.Descriptor instead.\nfunc (TensorOptions) EnumDescriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{1}\n}\n\ntype TensorStatus int32\n\nconst (\n\t// Unknown.\n\tTensorStatus_TENSORSTATUS_UNKNOWN TensorStatus = 0\n\t// Private.\n\tTensorStatus_TENSORSTATUS_PRIVATE TensorStatus = 1\n\t// Secret, usually in the form of secret sharing.\n\tTensorStatus_TENSORSTATUS_SECRET TensorStatus = 2\n\t// Ciphertext, usually in the form of homomorphic encryption ciphertext.\n\tTensorStatus_TENSORSTATUS_CIPHER TensorStatus = 3\n\t// Public.\n\tTensorStatus_TENSORSTATUS_PUBLIC TensorStatus = 4\n)\n\n// Enum value maps for TensorStatus.\nvar (\n\tTensorStatus_name = map[int32]string{\n\t\t0: \"TENSORSTATUS_UNKNOWN\",\n\t\t1: \"TENSORSTATUS_PRIVATE\",\n\t\t2: \"TENSORSTATUS_SECRET\",\n\t\t3: \"TENSORSTATUS_CIPHER\",\n\t\t4: \"TENSORSTATUS_PUBLIC\",\n\t}\n\tTensorStatus_value = map[string]int32{\n\t\t\"TENSORSTATUS_UNKNOWN\": 0,\n\t\t\"TENSORSTATUS_PRIVATE\": 1,\n\t\t\"TENSORSTATUS_SECRET\":  2,\n\t\t\"TENSORSTATUS_CIPHER\":  3,\n\t\t\"TENSORSTATUS_PUBLIC\":  4,\n\t}\n)\n\nfunc (x TensorStatus) Enum() *TensorStatus {\n\tp := new(TensorStatus)\n\t*p = x\n\treturn p\n}\n\nfunc (x TensorStatus) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (TensorStatus) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_api_core_proto_enumTypes[2].Descriptor()\n}\n\nfunc (TensorStatus) Type() protoreflect.EnumType {\n\treturn &file_api_core_proto_enumTypes[2]\n}\n\nfunc (x TensorStatus) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use TensorStatus.Descriptor instead.\nfunc (TensorStatus) EnumDescriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{2}\n}\n\n// Formal parameter options.\ntype FormalParameterOptions int32\n\nconst (\n\t// Undefined.\n\tFormalParameterOptions_FORMALPARAMETEROPTIONS_UNDEFINED FormalParameterOptions = 0\n\t// This is a single formal parameter.\n\tFormalParameterOptions_FORMALPARAMETEROPTIONS_SINGLE FormalParameterOptions = 1\n\t// This is an optional formal parameter.\n\tFormalParameterOptions_FORMALPARAMETEROPTIONS_OPTIONAL FormalParameterOptions = 2\n\t// This is a variadic formal parameter.\n\tFormalParameterOptions_FORMALPARAMETEROPTIONS_VARIADIC FormalParameterOptions = 3\n)\n\n// Enum value maps for FormalParameterOptions.\nvar (\n\tFormalParameterOptions_name = map[int32]string{\n\t\t0: \"FORMALPARAMETEROPTIONS_UNDEFINED\",\n\t\t1: \"FORMALPARAMETEROPTIONS_SINGLE\",\n\t\t2: \"FORMALPARAMETEROPTIONS_OPTIONAL\",\n\t\t3: \"FORMALPARAMETEROPTIONS_VARIADIC\",\n\t}\n\tFormalParameterOptions_value = map[string]int32{\n\t\t\"FORMALPARAMETEROPTIONS_UNDEFINED\": 0,\n\t\t\"FORMALPARAMETEROPTIONS_SINGLE\":    1,\n\t\t\"FORMALPARAMETEROPTIONS_OPTIONAL\":  2,\n\t\t\"FORMALPARAMETEROPTIONS_VARIADIC\":  3,\n\t}\n)\n\nfunc (x FormalParameterOptions) Enum() *FormalParameterOptions {\n\tp := new(FormalParameterOptions)\n\t*p = x\n\treturn p\n}\n\nfunc (x FormalParameterOptions) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (FormalParameterOptions) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_api_core_proto_enumTypes[3].Descriptor()\n}\n\nfunc (FormalParameterOptions) Type() protoreflect.EnumType {\n\treturn &file_api_core_proto_enumTypes[3]\n}\n\nfunc (x FormalParameterOptions) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use FormalParameterOptions.Descriptor instead.\nfunc (FormalParameterOptions) EnumDescriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{3}\n}\n\n// Defines a tensor shape. A dimension can be either an integer value\n// or a symbolic variable. A symbolic variable represents an unknown\n// dimension.\ntype TensorShape struct {\n\tstate         protoimpl.MessageState   `protogen:\"open.v1\"`\n\tDim           []*TensorShape_Dimension `protobuf:\"bytes,1,rep,name=dim,proto3\" json:\"dim,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TensorShape) Reset() {\n\t*x = TensorShape{}\n\tmi := &file_api_core_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TensorShape) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TensorShape) ProtoMessage() {}\n\nfunc (x *TensorShape) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TensorShape.ProtoReflect.Descriptor instead.\nfunc (*TensorShape) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *TensorShape) GetDim() []*TensorShape_Dimension {\n\tif x != nil {\n\t\treturn x.Dim\n\t}\n\treturn nil\n}\n\ntype TensorAnnotation struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tStatus        TensorStatus           `protobuf:\"varint,1,opt,name=status,proto3,enum=scql.pb.TensorStatus\" json:\"status,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TensorAnnotation) Reset() {\n\t*x = TensorAnnotation{}\n\tmi := &file_api_core_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TensorAnnotation) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TensorAnnotation) ProtoMessage() {}\n\nfunc (x *TensorAnnotation) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TensorAnnotation.ProtoReflect.Descriptor instead.\nfunc (*TensorAnnotation) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *TensorAnnotation) GetStatus() TensorStatus {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn TensorStatus_TENSORSTATUS_UNKNOWN\n}\n\n// A tensor data representation.\ntype Tensor struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Tensor name.\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// Tensor shape.\n\t// In SCQL cases, it's normally [M] (a vector with M elements).\n\tShape *TensorShape `protobuf:\"bytes,2,opt,name=shape,proto3\" json:\"shape,omitempty\"`\n\t// Tensor element type.\n\tElemType PrimitiveDataType `protobuf:\"varint,3,opt,name=elem_type,json=elemType,proto3,enum=scql.pb.PrimitiveDataType\" json:\"elem_type,omitempty\"`\n\t// used by decimal type\n\tScale int32 `protobuf:\"varint,14,opt,name=scale,proto3\" json:\"scale,omitempty\"`\n\tWidth int32 `protobuf:\"varint,15,opt,name=width,proto3\" json:\"width,omitempty\"`\n\t// Tensor options.\n\tOption TensorOptions `protobuf:\"varint,4,opt,name=option,proto3,enum=scql.pb.TensorOptions\" json:\"option,omitempty\"`\n\t// Tensor annotation carries physical status information.\n\t// It MUST be there if the <option> is \"Reference\"\n\tAnnotation *TensorAnnotation `protobuf:\"bytes,5,opt,name=annotation,proto3\" json:\"annotation,omitempty\"`\n\t// For int8, int16, int32 data types\n\tInt32Data []int32 `protobuf:\"varint,6,rep,packed,name=int32_data,json=int32Data,proto3\" json:\"int32_data,omitempty\"`\n\t// For int64 and timestamp data types\n\tInt64Data []int64 `protobuf:\"varint,7,rep,packed,name=int64_data,json=int64Data,proto3\" json:\"int64_data,omitempty\"`\n\t// For float32 data type\n\tFloatData []float32 `protobuf:\"fixed32,8,rep,packed,name=float_data,json=floatData,proto3\" json:\"float_data,omitempty\"`\n\t// For float64 data type\n\tDoubleData []float64 `protobuf:\"fixed64,9,rep,packed,name=double_data,json=doubleData,proto3\" json:\"double_data,omitempty\"`\n\t// For bool data type\n\tBoolData []bool `protobuf:\"varint,10,rep,packed,name=bool_data,json=boolData,proto3\" json:\"bool_data,omitempty\"`\n\t// For string and datetime and decimal data types\n\tStringData []string `protobuf:\"bytes,11,rep,name=string_data,json=stringData,proto3\" json:\"string_data,omitempty\"`\n\t// validity mask for data(int32_data/int64_data/...), size can be zero(all\n\t// data valid) or the same as data, where item false means NULL, true means\n\t// valid value\n\tDataValidity []bool `protobuf:\"varint,13,rep,packed,name=data_validity,json=dataValidity,proto3\" json:\"data_validity,omitempty\"`\n\t// Tensor reference nums, internally used to delete tensor immediately\n\tRefNum        int32 `protobuf:\"varint,12,opt,name=ref_num,json=refNum,proto3\" json:\"ref_num,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Tensor) Reset() {\n\t*x = Tensor{}\n\tmi := &file_api_core_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Tensor) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Tensor) ProtoMessage() {}\n\nfunc (x *Tensor) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Tensor.ProtoReflect.Descriptor instead.\nfunc (*Tensor) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *Tensor) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Tensor) GetShape() *TensorShape {\n\tif x != nil {\n\t\treturn x.Shape\n\t}\n\treturn nil\n}\n\nfunc (x *Tensor) GetElemType() PrimitiveDataType {\n\tif x != nil {\n\t\treturn x.ElemType\n\t}\n\treturn PrimitiveDataType_PrimitiveDataType_UNDEFINED\n}\n\nfunc (x *Tensor) GetScale() int32 {\n\tif x != nil {\n\t\treturn x.Scale\n\t}\n\treturn 0\n}\n\nfunc (x *Tensor) GetWidth() int32 {\n\tif x != nil {\n\t\treturn x.Width\n\t}\n\treturn 0\n}\n\nfunc (x *Tensor) GetOption() TensorOptions {\n\tif x != nil {\n\t\treturn x.Option\n\t}\n\treturn TensorOptions_VALUE\n}\n\nfunc (x *Tensor) GetAnnotation() *TensorAnnotation {\n\tif x != nil {\n\t\treturn x.Annotation\n\t}\n\treturn nil\n}\n\nfunc (x *Tensor) GetInt32Data() []int32 {\n\tif x != nil {\n\t\treturn x.Int32Data\n\t}\n\treturn nil\n}\n\nfunc (x *Tensor) GetInt64Data() []int64 {\n\tif x != nil {\n\t\treturn x.Int64Data\n\t}\n\treturn nil\n}\n\nfunc (x *Tensor) GetFloatData() []float32 {\n\tif x != nil {\n\t\treturn x.FloatData\n\t}\n\treturn nil\n}\n\nfunc (x *Tensor) GetDoubleData() []float64 {\n\tif x != nil {\n\t\treturn x.DoubleData\n\t}\n\treturn nil\n}\n\nfunc (x *Tensor) GetBoolData() []bool {\n\tif x != nil {\n\t\treturn x.BoolData\n\t}\n\treturn nil\n}\n\nfunc (x *Tensor) GetStringData() []string {\n\tif x != nil {\n\t\treturn x.StringData\n\t}\n\treturn nil\n}\n\nfunc (x *Tensor) GetDataValidity() []bool {\n\tif x != nil {\n\t\treturn x.DataValidity\n\t}\n\treturn nil\n}\n\nfunc (x *Tensor) GetRefNum() int32 {\n\tif x != nil {\n\t\treturn x.RefNum\n\t}\n\treturn 0\n}\n\n// Attribute value, it may be a tensor.\ntype AttributeValue struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Types that are valid to be assigned to Value:\n\t//\n\t//\t*AttributeValue_T\n\tValue         isAttributeValue_Value `protobuf_oneof:\"value\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *AttributeValue) Reset() {\n\t*x = AttributeValue{}\n\tmi := &file_api_core_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AttributeValue) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AttributeValue) ProtoMessage() {}\n\nfunc (x *AttributeValue) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AttributeValue.ProtoReflect.Descriptor instead.\nfunc (*AttributeValue) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *AttributeValue) GetValue() isAttributeValue_Value {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn nil\n}\n\nfunc (x *AttributeValue) GetT() *Tensor {\n\tif x != nil {\n\t\tif x, ok := x.Value.(*AttributeValue_T); ok {\n\t\t\treturn x.T\n\t\t}\n\t}\n\treturn nil\n}\n\ntype isAttributeValue_Value interface {\n\tisAttributeValue_Value()\n}\n\ntype AttributeValue_T struct {\n\tT *Tensor `protobuf:\"bytes,1,opt,name=t,proto3,oneof\"`\n}\n\nfunc (*AttributeValue_T) isAttributeValue_Value() {}\n\ntype TensorList struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tTensors       []*Tensor              `protobuf:\"bytes,1,rep,name=tensors,proto3\" json:\"tensors,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TensorList) Reset() {\n\t*x = TensorList{}\n\tmi := &file_api_core_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TensorList) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TensorList) ProtoMessage() {}\n\nfunc (x *TensorList) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TensorList.ProtoReflect.Descriptor instead.\nfunc (*TensorList) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *TensorList) GetTensors() []*Tensor {\n\tif x != nil {\n\t\treturn x.Tensors\n\t}\n\treturn nil\n}\n\n// An execution node\ntype ExecNode struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Node name, should be unique in an execution plan,\n\t// its format may be like \"${name}.${id}\"\n\tNodeName string `protobuf:\"bytes,1,opt,name=node_name,json=nodeName,proto3\" json:\"node_name,omitempty\"`\n\t// Operator type that this node refers to.\n\tOpType string `protobuf:\"bytes,2,opt,name=op_type,json=opType,proto3\" json:\"op_type,omitempty\"`\n\t// Input arguments.\n\tInputs map[string]*TensorList `protobuf:\"bytes,3,rep,name=inputs,proto3\" json:\"inputs,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\t// Output arguments.\n\tOutputs map[string]*TensorList `protobuf:\"bytes,4,rep,name=outputs,proto3\" json:\"outputs,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\t// Static attributes may be used in this node.\n\t// It's used to replace the default value defined\n\t// in the operator definition if needed.\n\tAttributes    map[string]*AttributeValue `protobuf:\"bytes,5,rep,name=attributes,proto3\" json:\"attributes,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ExecNode) Reset() {\n\t*x = ExecNode{}\n\tmi := &file_api_core_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ExecNode) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ExecNode) ProtoMessage() {}\n\nfunc (x *ExecNode) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ExecNode.ProtoReflect.Descriptor instead.\nfunc (*ExecNode) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *ExecNode) GetNodeName() string {\n\tif x != nil {\n\t\treturn x.NodeName\n\t}\n\treturn \"\"\n}\n\nfunc (x *ExecNode) GetOpType() string {\n\tif x != nil {\n\t\treturn x.OpType\n\t}\n\treturn \"\"\n}\n\nfunc (x *ExecNode) GetInputs() map[string]*TensorList {\n\tif x != nil {\n\t\treturn x.Inputs\n\t}\n\treturn nil\n}\n\nfunc (x *ExecNode) GetOutputs() map[string]*TensorList {\n\tif x != nil {\n\t\treturn x.Outputs\n\t}\n\treturn nil\n}\n\nfunc (x *ExecNode) GetAttributes() map[string]*AttributeValue {\n\tif x != nil {\n\t\treturn x.Attributes\n\t}\n\treturn nil\n}\n\ntype FormalAttribute struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\tName  string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// A complete attribute definition string.\n\tDefinition    string `protobuf:\"bytes,2,opt,name=definition,proto3\" json:\"definition,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *FormalAttribute) Reset() {\n\t*x = FormalAttribute{}\n\tmi := &file_api_core_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *FormalAttribute) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FormalAttribute) ProtoMessage() {}\n\nfunc (x *FormalAttribute) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FormalAttribute.ProtoReflect.Descriptor instead.\nfunc (*FormalAttribute) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *FormalAttribute) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *FormalAttribute) GetDefinition() string {\n\tif x != nil {\n\t\treturn x.Definition\n\t}\n\treturn \"\"\n}\n\n// Formal parameter representation of a SCQL operator.\n// It normally includes formal parameter name, type, and some annotations.\ntype FormalParameter struct {\n\tstate     protoimpl.MessageState `protogen:\"open.v1\"`\n\tParamName string                 `protobuf:\"bytes,1,opt,name=param_name,json=paramName,proto3\" json:\"param_name,omitempty\"`\n\t// Formal parameter option.\n\tOption FormalParameterOptions `protobuf:\"varint,2,opt,name=option,proto3,enum=scql.pb.FormalParameterOptions\" json:\"option,omitempty\"`\n\t// Formal parameter shape information in the case of \"tensor\".\n\t// In the case of scql, the tensor is actually a vector.\n\tParamShape *TensorShape `protobuf:\"bytes,3,opt,name=param_shape,json=paramShape,proto3\" json:\"param_shape,omitempty\"`\n\t// A complete parameter definition string.\n\tDefinition string `protobuf:\"bytes,4,opt,name=definition,proto3\" json:\"definition,omitempty\"`\n\t// Name of parameter status constraint(template name), e.g. \"T\" for template\n\t// name. It's like the `T` in `template<class T> ...` for C++. The parameter\n\t// with the same T should of the same tensor status.\n\tParameterStatusConstraintName string `protobuf:\"bytes,5,opt,name=parameter_status_constraint_name,json=parameterStatusConstraintName,proto3\" json:\"parameter_status_constraint_name,omitempty\"`\n\tunknownFields                 protoimpl.UnknownFields\n\tsizeCache                     protoimpl.SizeCache\n}\n\nfunc (x *FormalParameter) Reset() {\n\t*x = FormalParameter{}\n\tmi := &file_api_core_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *FormalParameter) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FormalParameter) ProtoMessage() {}\n\nfunc (x *FormalParameter) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FormalParameter.ProtoReflect.Descriptor instead.\nfunc (*FormalParameter) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *FormalParameter) GetParamName() string {\n\tif x != nil {\n\t\treturn x.ParamName\n\t}\n\treturn \"\"\n}\n\nfunc (x *FormalParameter) GetOption() FormalParameterOptions {\n\tif x != nil {\n\t\treturn x.Option\n\t}\n\treturn FormalParameterOptions_FORMALPARAMETEROPTIONS_UNDEFINED\n}\n\nfunc (x *FormalParameter) GetParamShape() *TensorShape {\n\tif x != nil {\n\t\treturn x.ParamShape\n\t}\n\treturn nil\n}\n\nfunc (x *FormalParameter) GetDefinition() string {\n\tif x != nil {\n\t\treturn x.Definition\n\t}\n\treturn \"\"\n}\n\nfunc (x *FormalParameter) GetParameterStatusConstraintName() string {\n\tif x != nil {\n\t\treturn x.ParameterStatusConstraintName\n\t}\n\treturn \"\"\n}\n\n// TensorStatus list\ntype TensorStatusList struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// TensorStatus list.\n\tStatus        []TensorStatus `protobuf:\"varint,1,rep,packed,name=status,proto3,enum=scql.pb.TensorStatus\" json:\"status,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TensorStatusList) Reset() {\n\t*x = TensorStatusList{}\n\tmi := &file_api_core_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TensorStatusList) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TensorStatusList) ProtoMessage() {}\n\nfunc (x *TensorStatusList) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TensorStatusList.ProtoReflect.Descriptor instead.\nfunc (*TensorStatusList) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *TensorStatusList) GetStatus() []TensorStatus {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\n// An SCQL operator definition representation.\ntype OperatorDef struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Operator name.\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// Operator input formal parameters.\n\tInputParams []*FormalParameter `protobuf:\"bytes,2,rep,name=input_params,json=inputParams,proto3\" json:\"input_params,omitempty\"`\n\t// Operator output formal parameters.\n\t// For SCQL case, there may be only one output.\n\tOutputParams []*FormalParameter `protobuf:\"bytes,3,rep,name=output_params,json=outputParams,proto3\" json:\"output_params,omitempty\"`\n\t// Operator attribute parameters.\n\tAttributeParams []*FormalAttribute `protobuf:\"bytes,4,rep,name=attribute_params,json=attributeParams,proto3\" json:\"attribute_params,omitempty\"`\n\t// Default attribute values needed when running the operator.\n\t// The default values may be replaced when creating an execution plan\n\t// from a SCQL query.\n\tDefaultAttributeValues map[string]*AttributeValue `protobuf:\"bytes,5,rep,name=default_attribute_values,json=defaultAttributeValues,proto3\" json:\"default_attribute_values,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\t// A complete operator definition string.\n\tDefinition string `protobuf:\"bytes,6,opt,name=definition,proto3\" json:\"definition,omitempty\"`\n\t// Map of key for parameter_status_constraint_name, value for TensorStatusList\n\t// e.g.: {\"T\": TensorStatusList{status: [TENSORSTATUS_PRIVATE]}}\n\tParamStatusConstraints map[string]*TensorStatusList `protobuf:\"bytes,7,rep,name=param_status_constraints,json=paramStatusConstraints,proto3\" json:\"param_status_constraints,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tunknownFields          protoimpl.UnknownFields\n\tsizeCache              protoimpl.SizeCache\n}\n\nfunc (x *OperatorDef) Reset() {\n\t*x = OperatorDef{}\n\tmi := &file_api_core_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *OperatorDef) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OperatorDef) ProtoMessage() {}\n\nfunc (x *OperatorDef) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OperatorDef.ProtoReflect.Descriptor instead.\nfunc (*OperatorDef) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *OperatorDef) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *OperatorDef) GetInputParams() []*FormalParameter {\n\tif x != nil {\n\t\treturn x.InputParams\n\t}\n\treturn nil\n}\n\nfunc (x *OperatorDef) GetOutputParams() []*FormalParameter {\n\tif x != nil {\n\t\treturn x.OutputParams\n\t}\n\treturn nil\n}\n\nfunc (x *OperatorDef) GetAttributeParams() []*FormalAttribute {\n\tif x != nil {\n\t\treturn x.AttributeParams\n\t}\n\treturn nil\n}\n\nfunc (x *OperatorDef) GetDefaultAttributeValues() map[string]*AttributeValue {\n\tif x != nil {\n\t\treturn x.DefaultAttributeValues\n\t}\n\treturn nil\n}\n\nfunc (x *OperatorDef) GetDefinition() string {\n\tif x != nil {\n\t\treturn x.Definition\n\t}\n\treturn \"\"\n}\n\nfunc (x *OperatorDef) GetParamStatusConstraints() map[string]*TensorStatusList {\n\tif x != nil {\n\t\treturn x.ParamStatusConstraints\n\t}\n\treturn nil\n}\n\n// TODO: move PartyId to a proper place.\ntype PartyId struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tCode          string                 `protobuf:\"bytes,1,opt,name=code,proto3\" json:\"code,omitempty\"` // party code\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PartyId) Reset() {\n\t*x = PartyId{}\n\tmi := &file_api_core_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PartyId) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PartyId) ProtoMessage() {}\n\nfunc (x *PartyId) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PartyId.ProtoReflect.Descriptor instead.\nfunc (*PartyId) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *PartyId) GetCode() string {\n\tif x != nil {\n\t\treturn x.Code\n\t}\n\treturn \"\"\n}\n\n// QueryResult represents the result of an executed SQL query.\ntype QueryResult struct {\n\tstate        protoimpl.MessageState `protogen:\"open.v1\"`\n\tAffectedRows int64                  `protobuf:\"varint,1,opt,name=affected_rows,json=affectedRows,proto3\" json:\"affected_rows,omitempty\"`\n\tWarnings     []*SQLWarning          `protobuf:\"bytes,2,rep,name=warnings,proto3\" json:\"warnings,omitempty\"`\n\tCostTimeS    float64                `protobuf:\"fixed64,3,opt,name=cost_time_s,json=costTimeS,proto3\" json:\"cost_time_s,omitempty\"`\n\t// Output columns are used to store the result datas\n\tOutColumns    []*Tensor `protobuf:\"bytes,1000,rep,name=out_columns,json=outColumns,proto3\" json:\"out_columns,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *QueryResult) Reset() {\n\t*x = QueryResult{}\n\tmi := &file_api_core_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *QueryResult) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*QueryResult) ProtoMessage() {}\n\nfunc (x *QueryResult) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use QueryResult.ProtoReflect.Descriptor instead.\nfunc (*QueryResult) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *QueryResult) GetAffectedRows() int64 {\n\tif x != nil {\n\t\treturn x.AffectedRows\n\t}\n\treturn 0\n}\n\nfunc (x *QueryResult) GetWarnings() []*SQLWarning {\n\tif x != nil {\n\t\treturn x.Warnings\n\t}\n\treturn nil\n}\n\nfunc (x *QueryResult) GetCostTimeS() float64 {\n\tif x != nil {\n\t\treturn x.CostTimeS\n\t}\n\treturn 0\n}\n\nfunc (x *QueryResult) GetOutColumns() []*Tensor {\n\tif x != nil {\n\t\treturn x.OutColumns\n\t}\n\treturn nil\n}\n\n// QueryResponse represents the response for a query execution.\ntype QueryResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tStatus        *Status                `protobuf:\"bytes,1,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tResult        *QueryResult           `protobuf:\"bytes,2,opt,name=result,proto3\" json:\"result,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *QueryResponse) Reset() {\n\t*x = QueryResponse{}\n\tmi := &file_api_core_proto_msgTypes[12]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *QueryResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*QueryResponse) ProtoMessage() {}\n\nfunc (x *QueryResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[12]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use QueryResponse.ProtoReflect.Descriptor instead.\nfunc (*QueryResponse) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *QueryResponse) GetStatus() *Status {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\nfunc (x *QueryResponse) GetResult() *QueryResult {\n\tif x != nil {\n\t\treturn x.Result\n\t}\n\treturn nil\n}\n\ntype TensorShape_Dimension struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Types that are valid to be assigned to Value:\n\t//\n\t//\t*TensorShape_Dimension_DimValue\n\t//\t*TensorShape_Dimension_DimParam\n\tValue         isTensorShape_Dimension_Value `protobuf_oneof:\"value\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TensorShape_Dimension) Reset() {\n\t*x = TensorShape_Dimension{}\n\tmi := &file_api_core_proto_msgTypes[13]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TensorShape_Dimension) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TensorShape_Dimension) ProtoMessage() {}\n\nfunc (x *TensorShape_Dimension) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_core_proto_msgTypes[13]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TensorShape_Dimension.ProtoReflect.Descriptor instead.\nfunc (*TensorShape_Dimension) Descriptor() ([]byte, []int) {\n\treturn file_api_core_proto_rawDescGZIP(), []int{0, 0}\n}\n\nfunc (x *TensorShape_Dimension) GetValue() isTensorShape_Dimension_Value {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn nil\n}\n\nfunc (x *TensorShape_Dimension) GetDimValue() int64 {\n\tif x != nil {\n\t\tif x, ok := x.Value.(*TensorShape_Dimension_DimValue); ok {\n\t\t\treturn x.DimValue\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (x *TensorShape_Dimension) GetDimParam() string {\n\tif x != nil {\n\t\tif x, ok := x.Value.(*TensorShape_Dimension_DimParam); ok {\n\t\t\treturn x.DimParam\n\t\t}\n\t}\n\treturn \"\"\n}\n\ntype isTensorShape_Dimension_Value interface {\n\tisTensorShape_Dimension_Value()\n}\n\ntype TensorShape_Dimension_DimValue struct {\n\tDimValue int64 `protobuf:\"varint,1,opt,name=dim_value,json=dimValue,proto3,oneof\"`\n}\n\ntype TensorShape_Dimension_DimParam struct {\n\tDimParam string `protobuf:\"bytes,2,opt,name=dim_param,json=dimParam,proto3,oneof\"` // shape is unknown.\n}\n\nfunc (*TensorShape_Dimension_DimValue) isTensorShape_Dimension_Value() {}\n\nfunc (*TensorShape_Dimension_DimParam) isTensorShape_Dimension_Value() {}\n\nvar File_api_core_proto protoreflect.FileDescriptor\n\nvar file_api_core_proto_rawDesc = []byte{\n\t0x0a, 0x0e, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x12, 0x07, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x1a, 0x10, 0x61, 0x70, 0x69, 0x2f, 0x73,\n\t0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x61, 0x70, 0x69,\n\t0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x93, 0x01,\n\t0x0a, 0x0b, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x53, 0x68, 0x61, 0x70, 0x65, 0x12, 0x30, 0x0a,\n\t0x03, 0x64, 0x69, 0x6d, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x63, 0x71,\n\t0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x53, 0x68, 0x61, 0x70, 0x65,\n\t0x2e, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x64, 0x69, 0x6d, 0x1a,\n\t0x52, 0x0a, 0x09, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x09,\n\t0x64, 0x69, 0x6d, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48,\n\t0x00, 0x52, 0x08, 0x64, 0x69, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x09, 0x64,\n\t0x69, 0x6d, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,\n\t0x52, 0x08, 0x64, 0x69, 0x6d, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61,\n\t0x6c, 0x75, 0x65, 0x22, 0x41, 0x0a, 0x10, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x41, 0x6e, 0x6e,\n\t0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,\n\t0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70,\n\t0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06,\n\t0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xaa, 0x04, 0x0a, 0x06, 0x54, 0x65, 0x6e, 0x73, 0x6f,\n\t0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x70, 0x65, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54,\n\t0x65, 0x6e, 0x73, 0x6f, 0x72, 0x53, 0x68, 0x61, 0x70, 0x65, 0x52, 0x05, 0x73, 0x68, 0x61, 0x70,\n\t0x65, 0x12, 0x37, 0x0a, 0x09, 0x65, 0x6c, 0x65, 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50,\n\t0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65,\n\t0x52, 0x08, 0x65, 0x6c, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63,\n\t0x61, 0x6c, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x63, 0x61, 0x6c, 0x65,\n\t0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52,\n\t0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x2e, 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,\n\t0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62,\n\t0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x06,\n\t0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x63, 0x71,\n\t0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x41, 0x6e, 0x6e, 0x6f, 0x74,\n\t0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x12, 0x21, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18,\n\t0x06, 0x20, 0x03, 0x28, 0x05, 0x42, 0x02, 0x10, 0x01, 0x52, 0x09, 0x69, 0x6e, 0x74, 0x33, 0x32,\n\t0x44, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x64, 0x61,\n\t0x74, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28, 0x03, 0x42, 0x02, 0x10, 0x01, 0x52, 0x09, 0x69, 0x6e,\n\t0x74, 0x36, 0x34, 0x44, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0a, 0x66, 0x6c, 0x6f, 0x61, 0x74,\n\t0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x08, 0x20, 0x03, 0x28, 0x02, 0x42, 0x02, 0x10, 0x01, 0x52,\n\t0x09, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0b, 0x64, 0x6f,\n\t0x75, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x09, 0x20, 0x03, 0x28, 0x01, 0x42,\n\t0x02, 0x10, 0x01, 0x52, 0x0a, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12,\n\t0x1f, 0x0a, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0a, 0x20, 0x03,\n\t0x28, 0x08, 0x42, 0x02, 0x10, 0x01, 0x52, 0x08, 0x62, 0x6f, 0x6f, 0x6c, 0x44, 0x61, 0x74, 0x61,\n\t0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18,\n\t0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74,\n\t0x61, 0x12, 0x27, 0x0a, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x69,\n\t0x74, 0x79, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x08, 0x42, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x64, 0x61,\n\t0x74, 0x61, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x69, 0x74, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x65,\n\t0x66, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x72, 0x65, 0x66,\n\t0x4e, 0x75, 0x6d, 0x22, 0x3a, 0x0a, 0x0e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,\n\t0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x01, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x0f, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f,\n\t0x72, 0x48, 0x00, 0x52, 0x01, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,\n\t0x37, 0x0a, 0x0a, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x29, 0x0a,\n\t0x07, 0x74, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x52,\n\t0x07, 0x74, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x73, 0x22, 0xed, 0x03, 0x0a, 0x08, 0x45, 0x78, 0x65,\n\t0x63, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61,\n\t0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61,\n\t0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6f, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x69,\n\t0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x63,\n\t0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x2e, 0x49,\n\t0x6e, 0x70, 0x75, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75,\n\t0x74, 0x73, 0x12, 0x38, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x78,\n\t0x65, 0x63, 0x4e, 0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x45, 0x6e,\n\t0x74, 0x72, 0x79, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x41, 0x0a, 0x0a,\n\t0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b,\n\t0x32, 0x21, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x4e,\n\t0x6f, 0x64, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e,\n\t0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a,\n\t0x4e, 0x0a, 0x0b, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,\n\t0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,\n\t0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x13, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72,\n\t0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a,\n\t0x4f, 0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,\n\t0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,\n\t0x79, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x13, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f,\n\t0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,\n\t0x1a, 0x56, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e,\n\t0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x41,\n\t0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76,\n\t0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x45, 0x0a, 0x0f, 0x46, 0x6f, 0x72, 0x6d,\n\t0x61, 0x6c, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e,\n\t0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,\n\t0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22,\n\t0x89, 0x02, 0x0a, 0x0f, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65,\n\t0x74, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x6e, 0x61, 0x6d,\n\t0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x4e, 0x61,\n\t0x6d, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x46, 0x6f, 0x72,\n\t0x6d, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x4f, 0x70, 0x74, 0x69,\n\t0x6f, 0x6e, 0x73, 0x52, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x0b, 0x70,\n\t0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x68, 0x61, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x14, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f,\n\t0x72, 0x53, 0x68, 0x61, 0x70, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x68, 0x61,\n\t0x70, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e,\n\t0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69,\n\t0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f,\n\t0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e,\n\t0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x70, 0x61,\n\t0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x6e,\n\t0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x41, 0x0a, 0x10, 0x54,\n\t0x65, 0x6e, 0x73, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12,\n\t0x2d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32,\n\t0x15, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72,\n\t0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xa4,\n\t0x05, 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x44, 0x65, 0x66, 0x12, 0x12,\n\t0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,\n\t0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61,\n\t0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e,\n\t0x70, 0x62, 0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74,\n\t0x65, 0x72, 0x52, 0x0b, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12,\n\t0x3d, 0x0a, 0x0d, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73,\n\t0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62,\n\t0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72,\n\t0x52, 0x0c, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x43,\n\t0x0a, 0x10, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x61,\n\t0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e,\n\t0x70, 0x62, 0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,\n\t0x74, 0x65, 0x52, 0x0f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x50, 0x61, 0x72,\n\t0x61, 0x6d, 0x73, 0x12, 0x6a, 0x0a, 0x18, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x61,\n\t0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18,\n\t0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e,\n\t0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x44, 0x65, 0x66, 0x2e, 0x44, 0x65, 0x66, 0x61,\n\t0x75, 0x6c, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75,\n\t0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x16, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,\n\t0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12,\n\t0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12,\n\t0x6a, 0x0a, 0x18, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f,\n\t0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x30, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x70, 0x65, 0x72,\n\t0x61, 0x74, 0x6f, 0x72, 0x44, 0x65, 0x66, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x74, 0x61,\n\t0x74, 0x75, 0x73, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73, 0x45, 0x6e,\n\t0x74, 0x72, 0x79, 0x52, 0x16, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,\n\t0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73, 0x1a, 0x62, 0x0a, 0x1b, 0x44,\n\t0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56,\n\t0x61, 0x6c, 0x75, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,\n\t0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05,\n\t0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x63,\n\t0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x56,\n\t0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a,\n\t0x64, 0x0a, 0x1b, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f,\n\t0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,\n\t0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,\n\t0x12, 0x2f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x19, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72,\n\t0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1d, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x74, 0x79, 0x49, 0x64,\n\t0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,\n\t0x63, 0x6f, 0x64, 0x65, 0x22, 0xb6, 0x01, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65,\n\t0x73, 0x75, 0x6c, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64,\n\t0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x61, 0x66, 0x66,\n\t0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x2f, 0x0a, 0x08, 0x77, 0x61, 0x72,\n\t0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x63,\n\t0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x51, 0x4c, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67,\n\t0x52, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x63, 0x6f,\n\t0x73, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52,\n\t0x09, 0x63, 0x6f, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x12, 0x31, 0x0a, 0x0b, 0x6f, 0x75,\n\t0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0xe8, 0x07, 0x20, 0x03, 0x28, 0x0b,\n\t0x32, 0x0f, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f,\n\t0x72, 0x52, 0x0a, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x22, 0x66, 0x0a,\n\t0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27,\n\t0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,\n\t0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2c, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c,\n\t0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70,\n\t0x62, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72,\n\t0x65, 0x73, 0x75, 0x6c, 0x74, 0x2a, 0xb9, 0x01, 0x0a, 0x11, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74,\n\t0x69, 0x76, 0x65, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x50,\n\t0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65,\n\t0x5f, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04,\n\t0x49, 0x4e, 0x54, 0x38, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x31, 0x36, 0x10,\n\t0x02, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05,\n\t0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x4c, 0x4f, 0x41, 0x54,\n\t0x33, 0x32, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x36, 0x34, 0x10,\n\t0x06, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4f, 0x4c, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x53,\n\t0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x41, 0x54, 0x45, 0x54,\n\t0x49, 0x4d, 0x45, 0x10, 0x09, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x49, 0x4d, 0x45, 0x53, 0x54, 0x41,\n\t0x4d, 0x50, 0x10, 0x0a, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x43, 0x49, 0x4d, 0x41, 0x4c, 0x10,\n\t0x0b, 0x2a, 0x37, 0x0a, 0x0d, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x4f, 0x70, 0x74, 0x69, 0x6f,\n\t0x6e, 0x73, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x00, 0x12, 0x0d, 0x0a,\n\t0x09, 0x52, 0x45, 0x46, 0x45, 0x52, 0x45, 0x4e, 0x43, 0x45, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08,\n\t0x56, 0x41, 0x52, 0x49, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x02, 0x2a, 0x8d, 0x01, 0x0a, 0x0c, 0x54,\n\t0x65, 0x6e, 0x73, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x14, 0x54,\n\t0x45, 0x4e, 0x53, 0x4f, 0x52, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x4b, 0x4e,\n\t0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x45, 0x4e, 0x53, 0x4f, 0x52, 0x53,\n\t0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12,\n\t0x17, 0x0a, 0x13, 0x54, 0x45, 0x4e, 0x53, 0x4f, 0x52, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f,\n\t0x53, 0x45, 0x43, 0x52, 0x45, 0x54, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x54, 0x45, 0x4e, 0x53,\n\t0x4f, 0x52, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x10,\n\t0x03, 0x12, 0x17, 0x0a, 0x13, 0x54, 0x45, 0x4e, 0x53, 0x4f, 0x52, 0x53, 0x54, 0x41, 0x54, 0x55,\n\t0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x04, 0x2a, 0xab, 0x01, 0x0a, 0x16, 0x46,\n\t0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x4f, 0x70,\n\t0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x20, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x50,\n\t0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f,\n\t0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d, 0x46,\n\t0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x4f, 0x50,\n\t0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x53, 0x49, 0x4e, 0x47, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x23,\n\t0x0a, 0x1f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45,\n\t0x52, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41,\n\t0x4c, 0x10, 0x02, 0x12, 0x23, 0x0a, 0x1f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x50, 0x41, 0x52,\n\t0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x56, 0x41,\n\t0x52, 0x49, 0x41, 0x44, 0x49, 0x43, 0x10, 0x03, 0x42, 0x25, 0x0a, 0x13, 0x6f, 0x72, 0x67, 0x2e,\n\t0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x5a,\n\t0x0e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x63, 0x71, 0x6c, 0x62,\n\t0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_api_core_proto_rawDescOnce sync.Once\n\tfile_api_core_proto_rawDescData = file_api_core_proto_rawDesc\n)\n\nfunc file_api_core_proto_rawDescGZIP() []byte {\n\tfile_api_core_proto_rawDescOnce.Do(func() {\n\t\tfile_api_core_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_core_proto_rawDescData)\n\t})\n\treturn file_api_core_proto_rawDescData\n}\n\nvar file_api_core_proto_enumTypes = make([]protoimpl.EnumInfo, 4)\nvar file_api_core_proto_msgTypes = make([]protoimpl.MessageInfo, 19)\nvar file_api_core_proto_goTypes = []any{\n\t(PrimitiveDataType)(0),        // 0: scql.pb.PrimitiveDataType\n\t(TensorOptions)(0),            // 1: scql.pb.TensorOptions\n\t(TensorStatus)(0),             // 2: scql.pb.TensorStatus\n\t(FormalParameterOptions)(0),   // 3: scql.pb.FormalParameterOptions\n\t(*TensorShape)(nil),           // 4: scql.pb.TensorShape\n\t(*TensorAnnotation)(nil),      // 5: scql.pb.TensorAnnotation\n\t(*Tensor)(nil),                // 6: scql.pb.Tensor\n\t(*AttributeValue)(nil),        // 7: scql.pb.AttributeValue\n\t(*TensorList)(nil),            // 8: scql.pb.TensorList\n\t(*ExecNode)(nil),              // 9: scql.pb.ExecNode\n\t(*FormalAttribute)(nil),       // 10: scql.pb.FormalAttribute\n\t(*FormalParameter)(nil),       // 11: scql.pb.FormalParameter\n\t(*TensorStatusList)(nil),      // 12: scql.pb.TensorStatusList\n\t(*OperatorDef)(nil),           // 13: scql.pb.OperatorDef\n\t(*PartyId)(nil),               // 14: scql.pb.PartyId\n\t(*QueryResult)(nil),           // 15: scql.pb.QueryResult\n\t(*QueryResponse)(nil),         // 16: scql.pb.QueryResponse\n\t(*TensorShape_Dimension)(nil), // 17: scql.pb.TensorShape.Dimension\n\tnil,                           // 18: scql.pb.ExecNode.InputsEntry\n\tnil,                           // 19: scql.pb.ExecNode.OutputsEntry\n\tnil,                           // 20: scql.pb.ExecNode.AttributesEntry\n\tnil,                           // 21: scql.pb.OperatorDef.DefaultAttributeValuesEntry\n\tnil,                           // 22: scql.pb.OperatorDef.ParamStatusConstraintsEntry\n\t(*SQLWarning)(nil),            // 23: scql.pb.SQLWarning\n\t(*Status)(nil),                // 24: scql.pb.Status\n}\nvar file_api_core_proto_depIdxs = []int32{\n\t17, // 0: scql.pb.TensorShape.dim:type_name -> scql.pb.TensorShape.Dimension\n\t2,  // 1: scql.pb.TensorAnnotation.status:type_name -> scql.pb.TensorStatus\n\t4,  // 2: scql.pb.Tensor.shape:type_name -> scql.pb.TensorShape\n\t0,  // 3: scql.pb.Tensor.elem_type:type_name -> scql.pb.PrimitiveDataType\n\t1,  // 4: scql.pb.Tensor.option:type_name -> scql.pb.TensorOptions\n\t5,  // 5: scql.pb.Tensor.annotation:type_name -> scql.pb.TensorAnnotation\n\t6,  // 6: scql.pb.AttributeValue.t:type_name -> scql.pb.Tensor\n\t6,  // 7: scql.pb.TensorList.tensors:type_name -> scql.pb.Tensor\n\t18, // 8: scql.pb.ExecNode.inputs:type_name -> scql.pb.ExecNode.InputsEntry\n\t19, // 9: scql.pb.ExecNode.outputs:type_name -> scql.pb.ExecNode.OutputsEntry\n\t20, // 10: scql.pb.ExecNode.attributes:type_name -> scql.pb.ExecNode.AttributesEntry\n\t3,  // 11: scql.pb.FormalParameter.option:type_name -> scql.pb.FormalParameterOptions\n\t4,  // 12: scql.pb.FormalParameter.param_shape:type_name -> scql.pb.TensorShape\n\t2,  // 13: scql.pb.TensorStatusList.status:type_name -> scql.pb.TensorStatus\n\t11, // 14: scql.pb.OperatorDef.input_params:type_name -> scql.pb.FormalParameter\n\t11, // 15: scql.pb.OperatorDef.output_params:type_name -> scql.pb.FormalParameter\n\t10, // 16: scql.pb.OperatorDef.attribute_params:type_name -> scql.pb.FormalAttribute\n\t21, // 17: scql.pb.OperatorDef.default_attribute_values:type_name -> scql.pb.OperatorDef.DefaultAttributeValuesEntry\n\t22, // 18: scql.pb.OperatorDef.param_status_constraints:type_name -> scql.pb.OperatorDef.ParamStatusConstraintsEntry\n\t23, // 19: scql.pb.QueryResult.warnings:type_name -> scql.pb.SQLWarning\n\t6,  // 20: scql.pb.QueryResult.out_columns:type_name -> scql.pb.Tensor\n\t24, // 21: scql.pb.QueryResponse.status:type_name -> scql.pb.Status\n\t15, // 22: scql.pb.QueryResponse.result:type_name -> scql.pb.QueryResult\n\t8,  // 23: scql.pb.ExecNode.InputsEntry.value:type_name -> scql.pb.TensorList\n\t8,  // 24: scql.pb.ExecNode.OutputsEntry.value:type_name -> scql.pb.TensorList\n\t7,  // 25: scql.pb.ExecNode.AttributesEntry.value:type_name -> scql.pb.AttributeValue\n\t7,  // 26: scql.pb.OperatorDef.DefaultAttributeValuesEntry.value:type_name -> scql.pb.AttributeValue\n\t12, // 27: scql.pb.OperatorDef.ParamStatusConstraintsEntry.value:type_name -> scql.pb.TensorStatusList\n\t28, // [28:28] is the sub-list for method output_type\n\t28, // [28:28] is the sub-list for method input_type\n\t28, // [28:28] is the sub-list for extension type_name\n\t28, // [28:28] is the sub-list for extension extendee\n\t0,  // [0:28] is the sub-list for field type_name\n}\n\nfunc init() { file_api_core_proto_init() }\nfunc file_api_core_proto_init() {\n\tif File_api_core_proto != nil {\n\t\treturn\n\t}\n\tfile_api_status_proto_init()\n\tfile_api_common_proto_init()\n\tfile_api_core_proto_msgTypes[3].OneofWrappers = []any{\n\t\t(*AttributeValue_T)(nil),\n\t}\n\tfile_api_core_proto_msgTypes[13].OneofWrappers = []any{\n\t\t(*TensorShape_Dimension_DimValue)(nil),\n\t\t(*TensorShape_Dimension_DimParam)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_api_core_proto_rawDesc,\n\t\t\tNumEnums:      4,\n\t\t\tNumMessages:   19,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_api_core_proto_goTypes,\n\t\tDependencyIndexes: file_api_core_proto_depIdxs,\n\t\tEnumInfos:         file_api_core_proto_enumTypes,\n\t\tMessageInfos:      file_api_core_proto_msgTypes,\n\t}.Build()\n\tFile_api_core_proto = out.File\n\tfile_api_core_proto_rawDesc = nil\n\tfile_api_core_proto_goTypes = nil\n\tfile_api_core_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/proto-gen/scql/engine.pb.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.3\n// \tprotoc        v5.27.3\n// source: api/engine.proto\n\npackage scql\n\nimport (\n\tcontext \"context\"\n\tspu \"github.com/secretflow/scql/pkg/proto-gen/spu\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype StopJobRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\tJobId string                 `protobuf:\"bytes,1,opt,name=job_id,json=jobId,proto3\" json:\"job_id,omitempty\"`\n\t// job stop reason, it maybe\n\t// - \"Finish\". Job ended normally.\n\t// - \"Timeout\". Job timeout.\n\t// - \"Canceled\". Job canceled by client, maybe triggered by CTRL+C\n\t// - \"Error\". Exception caught when running.\n\t// - \"Killed\". Killed by client.\n\t// - or something else.\n\tReason        string `protobuf:\"bytes,2,opt,name=reason,proto3\" json:\"reason,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *StopJobRequest) Reset() {\n\t*x = StopJobRequest{}\n\tmi := &file_api_engine_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StopJobRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StopJobRequest) ProtoMessage() {}\n\nfunc (x *StopJobRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StopJobRequest.ProtoReflect.Descriptor instead.\nfunc (*StopJobRequest) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *StopJobRequest) GetJobId() string {\n\tif x != nil {\n\t\treturn x.JobId\n\t}\n\treturn \"\"\n}\n\nfunc (x *StopJobRequest) GetReason() string {\n\tif x != nil {\n\t\treturn x.Reason\n\t}\n\treturn \"\"\n}\n\n// A message carries all job session-level (execution plan level) information.\ntype JobStartParams struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// This party code.\n\t// It may be used to get this party information from <parties> below.\n\tPartyCode string `protobuf:\"bytes,1,opt,name=party_code,json=partyCode,proto3\" json:\"party_code,omitempty\"`\n\t// All parties that would jointly complete an execution plan.\n\tParties []*JobStartParams_Party `protobuf:\"bytes,2,rep,name=parties,proto3\" json:\"parties,omitempty\"`\n\t// The job id\n\tJobId string `protobuf:\"bytes,3,opt,name=job_id,json=jobId,proto3\" json:\"job_id,omitempty\"`\n\t// The spu runtime configuration.\n\tSpuRuntimeCfg *spu.RuntimeConfig `protobuf:\"bytes,4,opt,name=spu_runtime_cfg,json=spuRuntimeCfg,proto3\" json:\"spu_runtime_cfg,omitempty\"`\n\t// The query job time zone, only support time offset, like: '+08:00'\n\tTimeZone      string      `protobuf:\"bytes,5,opt,name=time_zone,json=timeZone,proto3\" json:\"time_zone,omitempty\"`\n\tLinkCfg       *LinkConfig `protobuf:\"bytes,6,opt,name=link_cfg,json=linkCfg,proto3\" json:\"link_cfg,omitempty\"`\n\tPsiCfg        *PsiConfig  `protobuf:\"bytes,7,opt,name=psi_cfg,json=psiCfg,proto3\" json:\"psi_cfg,omitempty\"`\n\tLogCfg        *LogConfig  `protobuf:\"bytes,8,opt,name=log_cfg,json=logCfg,proto3\" json:\"log_cfg,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *JobStartParams) Reset() {\n\t*x = JobStartParams{}\n\tmi := &file_api_engine_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *JobStartParams) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*JobStartParams) ProtoMessage() {}\n\nfunc (x *JobStartParams) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use JobStartParams.ProtoReflect.Descriptor instead.\nfunc (*JobStartParams) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *JobStartParams) GetPartyCode() string {\n\tif x != nil {\n\t\treturn x.PartyCode\n\t}\n\treturn \"\"\n}\n\nfunc (x *JobStartParams) GetParties() []*JobStartParams_Party {\n\tif x != nil {\n\t\treturn x.Parties\n\t}\n\treturn nil\n}\n\nfunc (x *JobStartParams) GetJobId() string {\n\tif x != nil {\n\t\treturn x.JobId\n\t}\n\treturn \"\"\n}\n\nfunc (x *JobStartParams) GetSpuRuntimeCfg() *spu.RuntimeConfig {\n\tif x != nil {\n\t\treturn x.SpuRuntimeCfg\n\t}\n\treturn nil\n}\n\nfunc (x *JobStartParams) GetTimeZone() string {\n\tif x != nil {\n\t\treturn x.TimeZone\n\t}\n\treturn \"\"\n}\n\nfunc (x *JobStartParams) GetLinkCfg() *LinkConfig {\n\tif x != nil {\n\t\treturn x.LinkCfg\n\t}\n\treturn nil\n}\n\nfunc (x *JobStartParams) GetPsiCfg() *PsiConfig {\n\tif x != nil {\n\t\treturn x.PsiCfg\n\t}\n\treturn nil\n}\n\nfunc (x *JobStartParams) GetLogCfg() *LogConfig {\n\tif x != nil {\n\t\treturn x.LogCfg\n\t}\n\treturn nil\n}\n\ntype GraphChecksum struct {\n\tstate              protoimpl.MessageState `protogen:\"open.v1\"`\n\tCheckGraphChecksum bool                   `protobuf:\"varint,1,opt,name=check_graph_checksum,json=checkGraphChecksum,proto3\" json:\"check_graph_checksum,omitempty\"`\n\t// map from rank to checksum\n\t// It could be used to verify and ensure that engines execute the same\n\t// graph.\n\tSubGraphChecksums  map[string]string `protobuf:\"bytes,2,rep,name=sub_graph_checksums,json=subGraphChecksums,proto3\" json:\"sub_graph_checksums,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tWholeGraphChecksum string            `protobuf:\"bytes,3,opt,name=whole_graph_checksum,json=wholeGraphChecksum,proto3\" json:\"whole_graph_checksum,omitempty\"`\n\tunknownFields      protoimpl.UnknownFields\n\tsizeCache          protoimpl.SizeCache\n}\n\nfunc (x *GraphChecksum) Reset() {\n\t*x = GraphChecksum{}\n\tmi := &file_api_engine_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *GraphChecksum) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GraphChecksum) ProtoMessage() {}\n\nfunc (x *GraphChecksum) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GraphChecksum.ProtoReflect.Descriptor instead.\nfunc (*GraphChecksum) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *GraphChecksum) GetCheckGraphChecksum() bool {\n\tif x != nil {\n\t\treturn x.CheckGraphChecksum\n\t}\n\treturn false\n}\n\nfunc (x *GraphChecksum) GetSubGraphChecksums() map[string]string {\n\tif x != nil {\n\t\treturn x.SubGraphChecksums\n\t}\n\treturn nil\n}\n\nfunc (x *GraphChecksum) GetWholeGraphChecksum() string {\n\tif x != nil {\n\t\treturn x.WholeGraphChecksum\n\t}\n\treturn \"\"\n}\n\ntype RunExecutionPlanRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tJobParams     *JobStartParams        `protobuf:\"bytes,1,opt,name=job_params,json=jobParams,proto3\" json:\"job_params,omitempty\"`\n\tGraph         *SubGraph              `protobuf:\"bytes,2,opt,name=graph,proto3\" json:\"graph,omitempty\"`\n\tGraphChecksum *GraphChecksum         `protobuf:\"bytes,3,opt,name=graph_checksum,json=graphChecksum,proto3\" json:\"graph_checksum,omitempty\"`\n\t// Whether the whole execution plan on the engine should be executed\n\t// synchronously or asynchronously. By default, the execution plan is executed\n\t// synchronously.\n\tAsync bool `protobuf:\"varint,4,opt,name=async,proto3\" json:\"async,omitempty\"`\n\t// Callback url, e.g.: \"http://alice.com:8080/path/to/callback\".\n\tCallbackUrl   string        `protobuf:\"bytes,5,opt,name=callback_url,json=callbackUrl,proto3\" json:\"callback_url,omitempty\"`\n\tDebugOpts     *DebugOptions `protobuf:\"bytes,6,opt,name=debug_opts,json=debugOpts,proto3\" json:\"debug_opts,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RunExecutionPlanRequest) Reset() {\n\t*x = RunExecutionPlanRequest{}\n\tmi := &file_api_engine_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RunExecutionPlanRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RunExecutionPlanRequest) ProtoMessage() {}\n\nfunc (x *RunExecutionPlanRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RunExecutionPlanRequest.ProtoReflect.Descriptor instead.\nfunc (*RunExecutionPlanRequest) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *RunExecutionPlanRequest) GetJobParams() *JobStartParams {\n\tif x != nil {\n\t\treturn x.JobParams\n\t}\n\treturn nil\n}\n\nfunc (x *RunExecutionPlanRequest) GetGraph() *SubGraph {\n\tif x != nil {\n\t\treturn x.Graph\n\t}\n\treturn nil\n}\n\nfunc (x *RunExecutionPlanRequest) GetGraphChecksum() *GraphChecksum {\n\tif x != nil {\n\t\treturn x.GraphChecksum\n\t}\n\treturn nil\n}\n\nfunc (x *RunExecutionPlanRequest) GetAsync() bool {\n\tif x != nil {\n\t\treturn x.Async\n\t}\n\treturn false\n}\n\nfunc (x *RunExecutionPlanRequest) GetCallbackUrl() string {\n\tif x != nil {\n\t\treturn x.CallbackUrl\n\t}\n\treturn \"\"\n}\n\nfunc (x *RunExecutionPlanRequest) GetDebugOpts() *DebugOptions {\n\tif x != nil {\n\t\treturn x.DebugOpts\n\t}\n\treturn nil\n}\n\ntype RunExecutionPlanResponse struct {\n\tstate  protoimpl.MessageState `protogen:\"open.v1\"`\n\tStatus *Status                `protobuf:\"bytes,1,opt,name=status,proto3\" json:\"status,omitempty\"`\n\t// Output columns used to store result datas.\n\tOutColumns []*Tensor `protobuf:\"bytes,2,rep,name=out_columns,json=outColumns,proto3\" json:\"out_columns,omitempty\"`\n\tJobId      string    `protobuf:\"bytes,3,opt,name=job_id,json=jobId,proto3\" json:\"job_id,omitempty\"`\n\t// Code of party which finished the execution plan.\n\tPartyCode string `protobuf:\"bytes,4,opt,name=party_code,json=partyCode,proto3\" json:\"party_code,omitempty\"`\n\t// The number of rows affected by a select into, update, insert, or delete.\n\tNumRowsAffected int64 `protobuf:\"varint,5,opt,name=num_rows_affected,json=numRowsAffected,proto3\" json:\"num_rows_affected,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *RunExecutionPlanResponse) Reset() {\n\t*x = RunExecutionPlanResponse{}\n\tmi := &file_api_engine_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RunExecutionPlanResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RunExecutionPlanResponse) ProtoMessage() {}\n\nfunc (x *RunExecutionPlanResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RunExecutionPlanResponse.ProtoReflect.Descriptor instead.\nfunc (*RunExecutionPlanResponse) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *RunExecutionPlanResponse) GetStatus() *Status {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\nfunc (x *RunExecutionPlanResponse) GetOutColumns() []*Tensor {\n\tif x != nil {\n\t\treturn x.OutColumns\n\t}\n\treturn nil\n}\n\nfunc (x *RunExecutionPlanResponse) GetJobId() string {\n\tif x != nil {\n\t\treturn x.JobId\n\t}\n\treturn \"\"\n}\n\nfunc (x *RunExecutionPlanResponse) GetPartyCode() string {\n\tif x != nil {\n\t\treturn x.PartyCode\n\t}\n\treturn \"\"\n}\n\nfunc (x *RunExecutionPlanResponse) GetNumRowsAffected() int64 {\n\tif x != nil {\n\t\treturn x.NumRowsAffected\n\t}\n\treturn 0\n}\n\ntype QueryJobStatusRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tJobId         string                 `protobuf:\"bytes,1,opt,name=job_id,json=jobId,proto3\" json:\"job_id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *QueryJobStatusRequest) Reset() {\n\t*x = QueryJobStatusRequest{}\n\tmi := &file_api_engine_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *QueryJobStatusRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*QueryJobStatusRequest) ProtoMessage() {}\n\nfunc (x *QueryJobStatusRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use QueryJobStatusRequest.ProtoReflect.Descriptor instead.\nfunc (*QueryJobStatusRequest) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *QueryJobStatusRequest) GetJobId() string {\n\tif x != nil {\n\t\treturn x.JobId\n\t}\n\treturn \"\"\n}\n\ntype QueryJobStatusResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tStatus        *Status                `protobuf:\"bytes,1,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tJobState      JobState               `protobuf:\"varint,2,opt,name=job_state,json=jobState,proto3,enum=scql.pb.JobState\" json:\"job_state,omitempty\"`\n\tProgress      *JobProgress           `protobuf:\"bytes,3,opt,name=progress,proto3\" json:\"progress,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *QueryJobStatusResponse) Reset() {\n\t*x = QueryJobStatusResponse{}\n\tmi := &file_api_engine_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *QueryJobStatusResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*QueryJobStatusResponse) ProtoMessage() {}\n\nfunc (x *QueryJobStatusResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use QueryJobStatusResponse.ProtoReflect.Descriptor instead.\nfunc (*QueryJobStatusResponse) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *QueryJobStatusResponse) GetStatus() *Status {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\nfunc (x *QueryJobStatusResponse) GetJobState() JobState {\n\tif x != nil {\n\t\treturn x.JobState\n\t}\n\treturn JobState_JOB_STATE_UNSPECIFIED\n}\n\nfunc (x *QueryJobStatusResponse) GetProgress() *JobProgress {\n\tif x != nil {\n\t\treturn x.Progress\n\t}\n\treturn nil\n}\n\n// After finishing running an execution plan, the Engine sends a ReportRequest\n// to result callback server (for example, broker) to return the results.\ntype ReportRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Status including whether the plan run was handled successfully,\n\t// if not, error message and some more information included.\n\tStatus *Status `protobuf:\"bytes,1,opt,name=status,proto3\" json:\"status,omitempty\"`\n\t// Output columns.\n\tOutColumns []*Tensor `protobuf:\"bytes,2,rep,name=out_columns,json=outColumns,proto3\" json:\"out_columns,omitempty\"`\n\t// The job_id that this execution plan belongs to.\n\tJobId string `protobuf:\"bytes,3,opt,name=job_id,json=jobId,proto3\" json:\"job_id,omitempty\"`\n\t// Code of party which finished the plan run.\n\tPartyCode string `protobuf:\"bytes,4,opt,name=party_code,json=partyCode,proto3\" json:\"party_code,omitempty\"`\n\t// The number of rows affected by a select into, update, insert, or delete.\n\tNumRowsAffected int64 `protobuf:\"varint,5,opt,name=num_rows_affected,json=numRowsAffected,proto3\" json:\"num_rows_affected,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *ReportRequest) Reset() {\n\t*x = ReportRequest{}\n\tmi := &file_api_engine_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ReportRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReportRequest) ProtoMessage() {}\n\nfunc (x *ReportRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ReportRequest.ProtoReflect.Descriptor instead.\nfunc (*ReportRequest) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *ReportRequest) GetStatus() *Status {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\nfunc (x *ReportRequest) GetOutColumns() []*Tensor {\n\tif x != nil {\n\t\treturn x.OutColumns\n\t}\n\treturn nil\n}\n\nfunc (x *ReportRequest) GetJobId() string {\n\tif x != nil {\n\t\treturn x.JobId\n\t}\n\treturn \"\"\n}\n\nfunc (x *ReportRequest) GetPartyCode() string {\n\tif x != nil {\n\t\treturn x.PartyCode\n\t}\n\treturn \"\"\n}\n\nfunc (x *ReportRequest) GetNumRowsAffected() int64 {\n\tif x != nil {\n\t\treturn x.NumRowsAffected\n\t}\n\treturn 0\n}\n\ntype StreamingOptions struct {\n\tstate                    protoimpl.MessageState `protogen:\"open.v1\"`\n\tStreamingRowNumThreshold int64                  `protobuf:\"varint,1,opt,name=streaming_row_num_threshold,json=streamingRowNumThreshold,proto3\" json:\"streaming_row_num_threshold,omitempty\"`\n\tBatchRowNum              int64                  `protobuf:\"varint,2,opt,name=batch_row_num,json=batchRowNum,proto3\" json:\"batch_row_num,omitempty\"`\n\tunknownFields            protoimpl.UnknownFields\n\tsizeCache                protoimpl.SizeCache\n}\n\nfunc (x *StreamingOptions) Reset() {\n\t*x = StreamingOptions{}\n\tmi := &file_api_engine_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StreamingOptions) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StreamingOptions) ProtoMessage() {}\n\nfunc (x *StreamingOptions) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StreamingOptions.ProtoReflect.Descriptor instead.\nfunc (*StreamingOptions) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *StreamingOptions) GetStreamingRowNumThreshold() int64 {\n\tif x != nil {\n\t\treturn x.StreamingRowNumThreshold\n\t}\n\treturn 0\n}\n\nfunc (x *StreamingOptions) GetBatchRowNum() int64 {\n\tif x != nil {\n\t\treturn x.BatchRowNum\n\t}\n\treturn 0\n}\n\ntype PsiOptions struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPsiCurveTypes []int64                `protobuf:\"varint,1,rep,packed,name=psi_curve_types,json=psiCurveTypes,proto3\" json:\"psi_curve_types,omitempty\"`\n\tRr22Mode      Rr22Mode               `protobuf:\"varint,2,opt,name=rr22_mode,json=rr22Mode,proto3,enum=scql.pb.Rr22Mode\" json:\"rr22_mode,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PsiOptions) Reset() {\n\t*x = PsiOptions{}\n\tmi := &file_api_engine_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PsiOptions) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PsiOptions) ProtoMessage() {}\n\nfunc (x *PsiOptions) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PsiOptions.ProtoReflect.Descriptor instead.\nfunc (*PsiOptions) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *PsiOptions) GetPsiCurveTypes() []int64 {\n\tif x != nil {\n\t\treturn x.PsiCurveTypes\n\t}\n\treturn nil\n}\n\nfunc (x *PsiOptions) GetRr22Mode() Rr22Mode {\n\tif x != nil {\n\t\treturn x.Rr22Mode\n\t}\n\treturn Rr22Mode_UNDEFINED\n}\n\ntype NegotiationOptions struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tStreamingOptions *StreamingOptions      `protobuf:\"bytes,1,opt,name=streaming_options,json=streamingOptions,proto3\" json:\"streaming_options,omitempty\"`\n\tPsiOptions       *PsiOptions            `protobuf:\"bytes,2,opt,name=psi_options,json=psiOptions,proto3\" json:\"psi_options,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *NegotiationOptions) Reset() {\n\t*x = NegotiationOptions{}\n\tmi := &file_api_engine_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NegotiationOptions) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NegotiationOptions) ProtoMessage() {}\n\nfunc (x *NegotiationOptions) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NegotiationOptions.ProtoReflect.Descriptor instead.\nfunc (*NegotiationOptions) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *NegotiationOptions) GetStreamingOptions() *StreamingOptions {\n\tif x != nil {\n\t\treturn x.StreamingOptions\n\t}\n\treturn nil\n}\n\nfunc (x *NegotiationOptions) GetPsiOptions() *PsiOptions {\n\tif x != nil {\n\t\treturn x.PsiOptions\n\t}\n\treturn nil\n}\n\ntype JobStartParams_Party struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// party code\n\tCode string `protobuf:\"bytes,1,opt,name=code,proto3\" json:\"code,omitempty\"`\n\t// party name\n\tName string `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// party host\n\tHost string `protobuf:\"bytes,3,opt,name=host,proto3\" json:\"host,omitempty\"`\n\t// party rank\n\tRank int32 `protobuf:\"varint,4,opt,name=rank,proto3\" json:\"rank,omitempty\"`\n\t// base64 encoded version of the DER encoded public key\n\t//\n\t// Example:\n\t// # 1. generate private key\n\t// $ openssl genpkey -algorithm ed25519 -out ed25519key.pem\n\t// # 2. generate public key based on above private key\n\t// $ openssl pkey -in ed25519key.pem -pubout\n\t//\n\t// # its output like below:\n\t//\n\t// -----BEGIN PUBLIC KEY-----\n\t// BASE64 ENCODED DATA\n\t// -----END PUBLIC KEY-----\n\t//\n\t// the field `public_key` should be the string between header \"-----BEGIN\n\t// PUBLIC KEY-----\" and footer \"-----END PUBLIC KEY-----\"\n\tPublicKey     string `protobuf:\"bytes,5,opt,name=public_key,json=publicKey,proto3\" json:\"public_key,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *JobStartParams_Party) Reset() {\n\t*x = JobStartParams_Party{}\n\tmi := &file_api_engine_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *JobStartParams_Party) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*JobStartParams_Party) ProtoMessage() {}\n\nfunc (x *JobStartParams_Party) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_engine_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use JobStartParams_Party.ProtoReflect.Descriptor instead.\nfunc (*JobStartParams_Party) Descriptor() ([]byte, []int) {\n\treturn file_api_engine_proto_rawDescGZIP(), []int{1, 0}\n}\n\nfunc (x *JobStartParams_Party) GetCode() string {\n\tif x != nil {\n\t\treturn x.Code\n\t}\n\treturn \"\"\n}\n\nfunc (x *JobStartParams_Party) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *JobStartParams_Party) GetHost() string {\n\tif x != nil {\n\t\treturn x.Host\n\t}\n\treturn \"\"\n}\n\nfunc (x *JobStartParams_Party) GetRank() int32 {\n\tif x != nil {\n\t\treturn x.Rank\n\t}\n\treturn 0\n}\n\nfunc (x *JobStartParams_Party) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\nvar File_api_engine_proto protoreflect.FileDescriptor\n\nvar file_api_engine_proto_rawDesc = []byte{\n\t0x0a, 0x10, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x12, 0x07, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x1a, 0x1b, 0x67, 0x6f, 0x6f,\n\t0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70,\n\t0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x6c, 0x69, 0x62, 0x73, 0x70, 0x75,\n\t0x2f, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x61, 0x70, 0x69, 0x2f,\n\t0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0e, 0x61, 0x70,\n\t0x69, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x61, 0x70,\n\t0x69, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12,\n\t0x61, 0x70, 0x69, 0x2f, 0x73, 0x75, 0x62, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x22, 0x3f, 0x0a, 0x0e, 0x53, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72,\n\t0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61,\n\t0x73, 0x6f, 0x6e, 0x22, 0xdd, 0x03, 0x0a, 0x0e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x72, 0x74,\n\t0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x79, 0x5f,\n\t0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x74,\n\t0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x74, 0x69, 0x65, 0x73,\n\t0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62,\n\t0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e,\n\t0x50, 0x61, 0x72, 0x74, 0x79, 0x52, 0x07, 0x70, 0x61, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x15,\n\t0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,\n\t0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x0f, 0x73, 0x70, 0x75, 0x5f, 0x72, 0x75, 0x6e,\n\t0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x66, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15,\n\t0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x73, 0x70, 0x75, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d,\n\t0x65, 0x43, 0x66, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e,\n\t0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e,\n\t0x65, 0x12, 0x2e, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, 0x66, 0x67, 0x18, 0x06, 0x20,\n\t0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x69,\n\t0x6e, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x66,\n\t0x67, 0x12, 0x2b, 0x0a, 0x07, 0x70, 0x73, 0x69, 0x5f, 0x63, 0x66, 0x67, 0x18, 0x07, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x73, 0x69,\n\t0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x70, 0x73, 0x69, 0x43, 0x66, 0x67, 0x12, 0x2b,\n\t0x0a, 0x07, 0x6c, 0x6f, 0x67, 0x5f, 0x63, 0x66, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x12, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x52, 0x06, 0x6c, 0x6f, 0x67, 0x43, 0x66, 0x67, 0x1a, 0x76, 0x0a, 0x05, 0x50,\n\t0x61, 0x72, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04,\n\t0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74,\n\t0x12, 0x12, 0x0a, 0x04, 0x72, 0x61, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04,\n\t0x72, 0x61, 0x6e, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b,\n\t0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,\n\t0x4b, 0x65, 0x79, 0x22, 0x98, 0x02, 0x0a, 0x0d, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x68, 0x65,\n\t0x63, 0x6b, 0x73, 0x75, 0x6d, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x67,\n\t0x72, 0x61, 0x70, 0x68, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x08, 0x52, 0x12, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43,\n\t0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x12, 0x5d, 0x0a, 0x13, 0x73, 0x75, 0x62, 0x5f, 0x67,\n\t0x72, 0x61, 0x70, 0x68, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x18, 0x02,\n\t0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47,\n\t0x72, 0x61, 0x70, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x2e, 0x53, 0x75, 0x62,\n\t0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x45, 0x6e,\n\t0x74, 0x72, 0x79, 0x52, 0x11, 0x73, 0x75, 0x62, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x68, 0x65,\n\t0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x77, 0x68, 0x6f, 0x6c, 0x65, 0x5f,\n\t0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x68, 0x6f, 0x6c, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68,\n\t0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x1a, 0x44, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x47,\n\t0x72, 0x61, 0x70, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x45, 0x6e, 0x74,\n\t0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa8,\n\t0x02, 0x0a, 0x17, 0x52, 0x75, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50,\n\t0x6c, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x0a, 0x6a, 0x6f,\n\t0x62, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x72,\n\t0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x09, 0x6a, 0x6f, 0x62, 0x50, 0x61, 0x72, 0x61,\n\t0x6d, 0x73, 0x12, 0x27, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x0b, 0x32, 0x11, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x47,\n\t0x72, 0x61, 0x70, 0x68, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x3d, 0x0a, 0x0e, 0x67,\n\t0x72, 0x61, 0x70, 0x68, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20,\n\t0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x72,\n\t0x61, 0x70, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x52, 0x0d, 0x67, 0x72, 0x61,\n\t0x70, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73,\n\t0x79, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63,\n\t0x12, 0x21, 0x0a, 0x0c, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x75, 0x72, 0x6c,\n\t0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,\n\t0x55, 0x72, 0x6c, 0x12, 0x34, 0x0a, 0x0a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6f, 0x70, 0x74,\n\t0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70,\n\t0x62, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x09,\n\t0x64, 0x65, 0x62, 0x75, 0x67, 0x4f, 0x70, 0x74, 0x73, 0x22, 0xd7, 0x01, 0x0a, 0x18, 0x52, 0x75,\n\t0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62,\n\t0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,\n\t0x30, 0x0a, 0x0b, 0x6f, 0x75, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02,\n\t0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54,\n\t0x65, 0x6e, 0x73, 0x6f, 0x72, 0x52, 0x0a, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e,\n\t0x73, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x74,\n\t0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61,\n\t0x72, 0x74, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x6e, 0x75, 0x6d, 0x5f, 0x72,\n\t0x6f, 0x77, 0x73, 0x5f, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01,\n\t0x28, 0x03, 0x52, 0x0f, 0x6e, 0x75, 0x6d, 0x52, 0x6f, 0x77, 0x73, 0x41, 0x66, 0x66, 0x65, 0x63,\n\t0x74, 0x65, 0x64, 0x22, 0x2e, 0x0a, 0x15, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x53,\n\t0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06,\n\t0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f,\n\t0x62, 0x49, 0x64, 0x22, 0xa3, 0x01, 0x0a, 0x16, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62,\n\t0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27,\n\t0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,\n\t0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2e, 0x0a, 0x09, 0x6a, 0x6f, 0x62, 0x5f, 0x73,\n\t0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x73, 0x63, 0x71,\n\t0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x08, 0x6a,\n\t0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x30, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72,\n\t0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x63, 0x71, 0x6c,\n\t0x2e, 0x70, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52,\n\t0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0xcc, 0x01, 0x0a, 0x0d, 0x52, 0x65,\n\t0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x06, 0x73,\n\t0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x63,\n\t0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,\n\t0x61, 0x74, 0x75, 0x73, 0x12, 0x30, 0x0a, 0x0b, 0x6f, 0x75, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x75,\n\t0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x63, 0x71, 0x6c,\n\t0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x52, 0x0a, 0x6f, 0x75, 0x74, 0x43,\n\t0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x1d, 0x0a,\n\t0x0a, 0x70, 0x61, 0x72, 0x74, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x74, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x11,\n\t0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x5f, 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65,\n\t0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x6e, 0x75, 0x6d, 0x52, 0x6f, 0x77, 0x73,\n\t0x41, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x75, 0x0a, 0x10, 0x53, 0x74, 0x72, 0x65,\n\t0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3d, 0x0a, 0x1b,\n\t0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x6f, 0x77, 0x5f, 0x6e, 0x75,\n\t0x6d, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x03, 0x52, 0x18, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x6f, 0x77, 0x4e,\n\t0x75, 0x6d, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x62,\n\t0x61, 0x74, 0x63, 0x68, 0x5f, 0x72, 0x6f, 0x77, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x03, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, 0x68, 0x52, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x22,\n\t0x64, 0x0a, 0x0a, 0x50, 0x73, 0x69, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, 0x0a,\n\t0x0f, 0x70, 0x73, 0x69, 0x5f, 0x63, 0x75, 0x72, 0x76, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73,\n\t0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0d, 0x70, 0x73, 0x69, 0x43, 0x75, 0x72, 0x76, 0x65,\n\t0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x09, 0x72, 0x72, 0x32, 0x32, 0x5f, 0x6d, 0x6f,\n\t0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e,\n\t0x70, 0x62, 0x2e, 0x52, 0x72, 0x32, 0x32, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x72, 0x72, 0x32,\n\t0x32, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x12, 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69,\n\t0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x46, 0x0a, 0x11,\n\t0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,\n\t0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70,\n\t0x62, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x74, 0x69, 0x6f,\n\t0x6e, 0x73, 0x52, 0x10, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x74,\n\t0x69, 0x6f, 0x6e, 0x73, 0x12, 0x34, 0x0a, 0x0b, 0x70, 0x73, 0x69, 0x5f, 0x6f, 0x70, 0x74, 0x69,\n\t0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x63, 0x71, 0x6c,\n\t0x2e, 0x70, 0x62, 0x2e, 0x50, 0x73, 0x69, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0a,\n\t0x70, 0x73, 0x69, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xf4, 0x01, 0x0a, 0x11, 0x53,\n\t0x43, 0x51, 0x4c, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,\n\t0x12, 0x57, 0x0a, 0x10, 0x52, 0x75, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e,\n\t0x50, 0x6c, 0x61, 0x6e, 0x12, 0x20, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52,\n\t0x75, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6c, 0x61, 0x6e, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62,\n\t0x2e, 0x52, 0x75, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6c, 0x61,\n\t0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0e, 0x51, 0x75, 0x65,\n\t0x72, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x2e, 0x73, 0x63,\n\t0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x74,\n\t0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x63,\n\t0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x74,\n\t0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x07,\n\t0x53, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x12, 0x17, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70,\n\t0x62, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x1a, 0x0f, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75,\n\t0x73, 0x32, 0x50, 0x0a, 0x14, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c,\n\t0x74, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x38, 0x0a, 0x06, 0x52, 0x65, 0x70,\n\t0x6f, 0x72, 0x74, 0x12, 0x16, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65,\n\t0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f,\n\t0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,\n\t0x70, 0x74, 0x79, 0x42, 0x13, 0x5a, 0x0e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x67, 0x65, 0x6e,\n\t0x2f, 0x73, 0x63, 0x71, 0x6c, 0x80, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_api_engine_proto_rawDescOnce sync.Once\n\tfile_api_engine_proto_rawDescData = file_api_engine_proto_rawDesc\n)\n\nfunc file_api_engine_proto_rawDescGZIP() []byte {\n\tfile_api_engine_proto_rawDescOnce.Do(func() {\n\t\tfile_api_engine_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_engine_proto_rawDescData)\n\t})\n\treturn file_api_engine_proto_rawDescData\n}\n\nvar file_api_engine_proto_msgTypes = make([]protoimpl.MessageInfo, 13)\nvar file_api_engine_proto_goTypes = []any{\n\t(*StopJobRequest)(nil),           // 0: scql.pb.StopJobRequest\n\t(*JobStartParams)(nil),           // 1: scql.pb.JobStartParams\n\t(*GraphChecksum)(nil),            // 2: scql.pb.GraphChecksum\n\t(*RunExecutionPlanRequest)(nil),  // 3: scql.pb.RunExecutionPlanRequest\n\t(*RunExecutionPlanResponse)(nil), // 4: scql.pb.RunExecutionPlanResponse\n\t(*QueryJobStatusRequest)(nil),    // 5: scql.pb.QueryJobStatusRequest\n\t(*QueryJobStatusResponse)(nil),   // 6: scql.pb.QueryJobStatusResponse\n\t(*ReportRequest)(nil),            // 7: scql.pb.ReportRequest\n\t(*StreamingOptions)(nil),         // 8: scql.pb.StreamingOptions\n\t(*PsiOptions)(nil),               // 9: scql.pb.PsiOptions\n\t(*NegotiationOptions)(nil),       // 10: scql.pb.NegotiationOptions\n\t(*JobStartParams_Party)(nil),     // 11: scql.pb.JobStartParams.Party\n\tnil,                              // 12: scql.pb.GraphChecksum.SubGraphChecksumsEntry\n\t(*spu.RuntimeConfig)(nil),        // 13: spu.pb.RuntimeConfig\n\t(*LinkConfig)(nil),               // 14: scql.pb.LinkConfig\n\t(*PsiConfig)(nil),                // 15: scql.pb.PsiConfig\n\t(*LogConfig)(nil),                // 16: scql.pb.LogConfig\n\t(*SubGraph)(nil),                 // 17: scql.pb.SubGraph\n\t(*DebugOptions)(nil),             // 18: scql.pb.DebugOptions\n\t(*Status)(nil),                   // 19: scql.pb.Status\n\t(*Tensor)(nil),                   // 20: scql.pb.Tensor\n\t(JobState)(0),                    // 21: scql.pb.JobState\n\t(*JobProgress)(nil),              // 22: scql.pb.JobProgress\n\t(Rr22Mode)(0),                    // 23: scql.pb.Rr22Mode\n\t(*emptypb.Empty)(nil),            // 24: google.protobuf.Empty\n}\nvar file_api_engine_proto_depIdxs = []int32{\n\t11, // 0: scql.pb.JobStartParams.parties:type_name -> scql.pb.JobStartParams.Party\n\t13, // 1: scql.pb.JobStartParams.spu_runtime_cfg:type_name -> spu.pb.RuntimeConfig\n\t14, // 2: scql.pb.JobStartParams.link_cfg:type_name -> scql.pb.LinkConfig\n\t15, // 3: scql.pb.JobStartParams.psi_cfg:type_name -> scql.pb.PsiConfig\n\t16, // 4: scql.pb.JobStartParams.log_cfg:type_name -> scql.pb.LogConfig\n\t12, // 5: scql.pb.GraphChecksum.sub_graph_checksums:type_name -> scql.pb.GraphChecksum.SubGraphChecksumsEntry\n\t1,  // 6: scql.pb.RunExecutionPlanRequest.job_params:type_name -> scql.pb.JobStartParams\n\t17, // 7: scql.pb.RunExecutionPlanRequest.graph:type_name -> scql.pb.SubGraph\n\t2,  // 8: scql.pb.RunExecutionPlanRequest.graph_checksum:type_name -> scql.pb.GraphChecksum\n\t18, // 9: scql.pb.RunExecutionPlanRequest.debug_opts:type_name -> scql.pb.DebugOptions\n\t19, // 10: scql.pb.RunExecutionPlanResponse.status:type_name -> scql.pb.Status\n\t20, // 11: scql.pb.RunExecutionPlanResponse.out_columns:type_name -> scql.pb.Tensor\n\t19, // 12: scql.pb.QueryJobStatusResponse.status:type_name -> scql.pb.Status\n\t21, // 13: scql.pb.QueryJobStatusResponse.job_state:type_name -> scql.pb.JobState\n\t22, // 14: scql.pb.QueryJobStatusResponse.progress:type_name -> scql.pb.JobProgress\n\t19, // 15: scql.pb.ReportRequest.status:type_name -> scql.pb.Status\n\t20, // 16: scql.pb.ReportRequest.out_columns:type_name -> scql.pb.Tensor\n\t23, // 17: scql.pb.PsiOptions.rr22_mode:type_name -> scql.pb.Rr22Mode\n\t8,  // 18: scql.pb.NegotiationOptions.streaming_options:type_name -> scql.pb.StreamingOptions\n\t9,  // 19: scql.pb.NegotiationOptions.psi_options:type_name -> scql.pb.PsiOptions\n\t3,  // 20: scql.pb.SCQLEngineService.RunExecutionPlan:input_type -> scql.pb.RunExecutionPlanRequest\n\t5,  // 21: scql.pb.SCQLEngineService.QueryJobStatus:input_type -> scql.pb.QueryJobStatusRequest\n\t0,  // 22: scql.pb.SCQLEngineService.StopJob:input_type -> scql.pb.StopJobRequest\n\t7,  // 23: scql.pb.EngineResultCallback.Report:input_type -> scql.pb.ReportRequest\n\t4,  // 24: scql.pb.SCQLEngineService.RunExecutionPlan:output_type -> scql.pb.RunExecutionPlanResponse\n\t6,  // 25: scql.pb.SCQLEngineService.QueryJobStatus:output_type -> scql.pb.QueryJobStatusResponse\n\t19, // 26: scql.pb.SCQLEngineService.StopJob:output_type -> scql.pb.Status\n\t24, // 27: scql.pb.EngineResultCallback.Report:output_type -> google.protobuf.Empty\n\t24, // [24:28] is the sub-list for method output_type\n\t20, // [20:24] is the sub-list for method input_type\n\t20, // [20:20] is the sub-list for extension type_name\n\t20, // [20:20] is the sub-list for extension extendee\n\t0,  // [0:20] is the sub-list for field type_name\n}\n\nfunc init() { file_api_engine_proto_init() }\nfunc file_api_engine_proto_init() {\n\tif File_api_engine_proto != nil {\n\t\treturn\n\t}\n\tfile_api_common_proto_init()\n\tfile_api_core_proto_init()\n\tfile_api_status_proto_init()\n\tfile_api_subgraph_proto_init()\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_api_engine_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   13,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   2,\n\t\t},\n\t\tGoTypes:           file_api_engine_proto_goTypes,\n\t\tDependencyIndexes: file_api_engine_proto_depIdxs,\n\t\tMessageInfos:      file_api_engine_proto_msgTypes,\n\t}.Build()\n\tFile_api_engine_proto = out.File\n\tfile_api_engine_proto_rawDesc = nil\n\tfile_api_engine_proto_goTypes = nil\n\tfile_api_engine_proto_depIdxs = nil\n}\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ context.Context\nvar _ grpc.ClientConnInterface\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\nconst _ = grpc.SupportPackageIsVersion6\n\n// SCQLEngineServiceClient is the client API for SCQLEngineService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.\ntype SCQLEngineServiceClient interface {\n\t// Run the whole execution plan\n\tRunExecutionPlan(ctx context.Context, in *RunExecutionPlanRequest, opts ...grpc.CallOption) (*RunExecutionPlanResponse, error)\n\t// Query Job Status\n\tQueryJobStatus(ctx context.Context, in *QueryJobStatusRequest, opts ...grpc.CallOption) (*QueryJobStatusResponse, error)\n\t// Stop Job\n\tStopJob(ctx context.Context, in *StopJobRequest, opts ...grpc.CallOption) (*Status, error)\n}\n\ntype sCQLEngineServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewSCQLEngineServiceClient(cc grpc.ClientConnInterface) SCQLEngineServiceClient {\n\treturn &sCQLEngineServiceClient{cc}\n}\n\nfunc (c *sCQLEngineServiceClient) RunExecutionPlan(ctx context.Context, in *RunExecutionPlanRequest, opts ...grpc.CallOption) (*RunExecutionPlanResponse, error) {\n\tout := new(RunExecutionPlanResponse)\n\terr := c.cc.Invoke(ctx, \"/scql.pb.SCQLEngineService/RunExecutionPlan\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *sCQLEngineServiceClient) QueryJobStatus(ctx context.Context, in *QueryJobStatusRequest, opts ...grpc.CallOption) (*QueryJobStatusResponse, error) {\n\tout := new(QueryJobStatusResponse)\n\terr := c.cc.Invoke(ctx, \"/scql.pb.SCQLEngineService/QueryJobStatus\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *sCQLEngineServiceClient) StopJob(ctx context.Context, in *StopJobRequest, opts ...grpc.CallOption) (*Status, error) {\n\tout := new(Status)\n\terr := c.cc.Invoke(ctx, \"/scql.pb.SCQLEngineService/StopJob\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// SCQLEngineServiceServer is the server API for SCQLEngineService service.\ntype SCQLEngineServiceServer interface {\n\t// Run the whole execution plan\n\tRunExecutionPlan(context.Context, *RunExecutionPlanRequest) (*RunExecutionPlanResponse, error)\n\t// Query Job Status\n\tQueryJobStatus(context.Context, *QueryJobStatusRequest) (*QueryJobStatusResponse, error)\n\t// Stop Job\n\tStopJob(context.Context, *StopJobRequest) (*Status, error)\n}\n\n// UnimplementedSCQLEngineServiceServer can be embedded to have forward compatible implementations.\ntype UnimplementedSCQLEngineServiceServer struct {\n}\n\nfunc (*UnimplementedSCQLEngineServiceServer) RunExecutionPlan(context.Context, *RunExecutionPlanRequest) (*RunExecutionPlanResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method RunExecutionPlan not implemented\")\n}\nfunc (*UnimplementedSCQLEngineServiceServer) QueryJobStatus(context.Context, *QueryJobStatusRequest) (*QueryJobStatusResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method QueryJobStatus not implemented\")\n}\nfunc (*UnimplementedSCQLEngineServiceServer) StopJob(context.Context, *StopJobRequest) (*Status, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method StopJob not implemented\")\n}\n\nfunc RegisterSCQLEngineServiceServer(s *grpc.Server, srv SCQLEngineServiceServer) {\n\ts.RegisterService(&_SCQLEngineService_serviceDesc, srv)\n}\n\nfunc _SCQLEngineService_RunExecutionPlan_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RunExecutionPlanRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SCQLEngineServiceServer).RunExecutionPlan(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/scql.pb.SCQLEngineService/RunExecutionPlan\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SCQLEngineServiceServer).RunExecutionPlan(ctx, req.(*RunExecutionPlanRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SCQLEngineService_QueryJobStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(QueryJobStatusRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SCQLEngineServiceServer).QueryJobStatus(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/scql.pb.SCQLEngineService/QueryJobStatus\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SCQLEngineServiceServer).QueryJobStatus(ctx, req.(*QueryJobStatusRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _SCQLEngineService_StopJob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(StopJobRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SCQLEngineServiceServer).StopJob(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/scql.pb.SCQLEngineService/StopJob\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SCQLEngineServiceServer).StopJob(ctx, req.(*StopJobRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _SCQLEngineService_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"scql.pb.SCQLEngineService\",\n\tHandlerType: (*SCQLEngineServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"RunExecutionPlan\",\n\t\t\tHandler:    _SCQLEngineService_RunExecutionPlan_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"QueryJobStatus\",\n\t\t\tHandler:    _SCQLEngineService_QueryJobStatus_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"StopJob\",\n\t\t\tHandler:    _SCQLEngineService_StopJob_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"api/engine.proto\",\n}\n\n// EngineResultCallbackClient is the client API for EngineResultCallback service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.\ntype EngineResultCallbackClient interface {\n\t// Engine report the plan result to driver(for example, broker)\n\tReport(ctx context.Context, in *ReportRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)\n}\n\ntype engineResultCallbackClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewEngineResultCallbackClient(cc grpc.ClientConnInterface) EngineResultCallbackClient {\n\treturn &engineResultCallbackClient{cc}\n}\n\nfunc (c *engineResultCallbackClient) Report(ctx context.Context, in *ReportRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {\n\tout := new(emptypb.Empty)\n\terr := c.cc.Invoke(ctx, \"/scql.pb.EngineResultCallback/Report\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// EngineResultCallbackServer is the server API for EngineResultCallback service.\ntype EngineResultCallbackServer interface {\n\t// Engine report the plan result to driver(for example, broker)\n\tReport(context.Context, *ReportRequest) (*emptypb.Empty, error)\n}\n\n// UnimplementedEngineResultCallbackServer can be embedded to have forward compatible implementations.\ntype UnimplementedEngineResultCallbackServer struct {\n}\n\nfunc (*UnimplementedEngineResultCallbackServer) Report(context.Context, *ReportRequest) (*emptypb.Empty, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Report not implemented\")\n}\n\nfunc RegisterEngineResultCallbackServer(s *grpc.Server, srv EngineResultCallbackServer) {\n\ts.RegisterService(&_EngineResultCallback_serviceDesc, srv)\n}\n\nfunc _EngineResultCallback_Report_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ReportRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(EngineResultCallbackServer).Report(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/scql.pb.EngineResultCallback/Report\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(EngineResultCallbackServer).Report(ctx, req.(*ReportRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _EngineResultCallback_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"scql.pb.EngineResultCallback\",\n\tHandlerType: (*EngineResultCallbackServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"Report\",\n\t\t\tHandler:    _EngineResultCallback_Report_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"api/engine.proto\",\n}\n"
  },
  {
    "path": "pkg/proto-gen/scql/interpreter.pb.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.3\n// \tprotoc        v5.27.3\n// source: api/interpreter.proto\n\npackage scql\n\nimport (\n\tspu \"github.com/secretflow/scql/pkg/proto-gen/spu\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\t_ \"google.golang.org/protobuf/types/known/timestamppb\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype CompiledPlan struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// schema of query result\n\tSchema         *TableSchema       `protobuf:\"bytes,1,opt,name=schema,proto3\" json:\"schema,omitempty\"`\n\tWarning        *Warning           `protobuf:\"bytes,2,opt,name=warning,proto3\" json:\"warning,omitempty\"`\n\tSpuRuntimeConf *spu.RuntimeConfig `protobuf:\"bytes,3,opt,name=spu_runtime_conf,json=spuRuntimeConf,proto3\" json:\"spu_runtime_conf,omitempty\"`\n\t// participants in execution graph.\n\t// The position order matters, the parties[0]'s rank is 0.\n\tParties            []*PartyId           `protobuf:\"bytes,4,rep,name=parties,proto3\" json:\"parties,omitempty\"`\n\tSubGraphs          map[string]*SubGraph `protobuf:\"bytes,5,rep,name=sub_graphs,json=subGraphs,proto3\" json:\"sub_graphs,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tWholeGraphChecksum string               `protobuf:\"bytes,6,opt,name=whole_graph_checksum,json=wholeGraphChecksum,proto3\" json:\"whole_graph_checksum,omitempty\"`\n\t// TODO: Add field to specify the party who report final query result.\n\tExplain       *ExplainInfo `protobuf:\"bytes,1000,opt,name=explain,proto3\" json:\"explain,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CompiledPlan) Reset() {\n\t*x = CompiledPlan{}\n\tmi := &file_api_interpreter_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CompiledPlan) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CompiledPlan) ProtoMessage() {}\n\nfunc (x *CompiledPlan) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CompiledPlan.ProtoReflect.Descriptor instead.\nfunc (*CompiledPlan) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *CompiledPlan) GetSchema() *TableSchema {\n\tif x != nil {\n\t\treturn x.Schema\n\t}\n\treturn nil\n}\n\nfunc (x *CompiledPlan) GetWarning() *Warning {\n\tif x != nil {\n\t\treturn x.Warning\n\t}\n\treturn nil\n}\n\nfunc (x *CompiledPlan) GetSpuRuntimeConf() *spu.RuntimeConfig {\n\tif x != nil {\n\t\treturn x.SpuRuntimeConf\n\t}\n\treturn nil\n}\n\nfunc (x *CompiledPlan) GetParties() []*PartyId {\n\tif x != nil {\n\t\treturn x.Parties\n\t}\n\treturn nil\n}\n\nfunc (x *CompiledPlan) GetSubGraphs() map[string]*SubGraph {\n\tif x != nil {\n\t\treturn x.SubGraphs\n\t}\n\treturn nil\n}\n\nfunc (x *CompiledPlan) GetWholeGraphChecksum() string {\n\tif x != nil {\n\t\treturn x.WholeGraphChecksum\n\t}\n\treturn \"\"\n}\n\nfunc (x *CompiledPlan) GetExplain() *ExplainInfo {\n\tif x != nil {\n\t\treturn x.Explain\n\t}\n\treturn nil\n}\n\ntype Warning struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// If the value is true, it means that the results may be affected by the\n\t// group threshold.\n\tMayAffectedByGroupThreshold bool `protobuf:\"varint,1,opt,name=may_affected_by_group_threshold,json=mayAffectedByGroupThreshold,proto3\" json:\"may_affected_by_group_threshold,omitempty\"`\n\tunknownFields               protoimpl.UnknownFields\n\tsizeCache                   protoimpl.SizeCache\n}\n\nfunc (x *Warning) Reset() {\n\t*x = Warning{}\n\tmi := &file_api_interpreter_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Warning) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Warning) ProtoMessage() {}\n\nfunc (x *Warning) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Warning.ProtoReflect.Descriptor instead.\nfunc (*Warning) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Warning) GetMayAffectedByGroupThreshold() bool {\n\tif x != nil {\n\t\treturn x.MayAffectedByGroupThreshold\n\t}\n\treturn false\n}\n\ntype ExplainInfo struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// execution graph in dot format.\n\t// It has value only when `dump_exe_graph` is true in request compile options.\n\tExeGraphDot   string `protobuf:\"bytes,1,opt,name=exe_graph_dot,json=exeGraphDot,proto3\" json:\"exe_graph_dot,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ExplainInfo) Reset() {\n\t*x = ExplainInfo{}\n\tmi := &file_api_interpreter_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ExplainInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ExplainInfo) ProtoMessage() {}\n\nfunc (x *ExplainInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ExplainInfo.ProtoReflect.Descriptor instead.\nfunc (*ExplainInfo) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ExplainInfo) GetExeGraphDot() string {\n\tif x != nil {\n\t\treturn x.ExeGraphDot\n\t}\n\treturn \"\"\n}\n\n// Metadata used to describe the schema (column names, types, comments)\n// of result sets.\ntype TableSchema struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tColumns       []*ColumnDesc          `protobuf:\"bytes,1,rep,name=columns,proto3\" json:\"columns,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TableSchema) Reset() {\n\t*x = TableSchema{}\n\tmi := &file_api_interpreter_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TableSchema) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TableSchema) ProtoMessage() {}\n\nfunc (x *TableSchema) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TableSchema.ProtoReflect.Descriptor instead.\nfunc (*TableSchema) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *TableSchema) GetColumns() []*ColumnDesc {\n\tif x != nil {\n\t\treturn x.Columns\n\t}\n\treturn nil\n}\n\ntype ColumnDesc struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tType          string                 `protobuf:\"bytes,2,opt,name=type,proto3\" json:\"type,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ColumnDesc) Reset() {\n\t*x = ColumnDesc{}\n\tmi := &file_api_interpreter_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ColumnDesc) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ColumnDesc) ProtoMessage() {}\n\nfunc (x *ColumnDesc) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ColumnDesc.ProtoReflect.Descriptor instead.\nfunc (*ColumnDesc) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *ColumnDesc) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *ColumnDesc) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\ntype OptimizerHints struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// auto means choosing psi type by engine\n\tPsiAlgorithmType PsiAlgorithmType `protobuf:\"varint,1,opt,name=psi_algorithm_type,json=psiAlgorithmType,proto3,enum=scql.pb.PsiAlgorithmType\" json:\"psi_algorithm_type,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *OptimizerHints) Reset() {\n\t*x = OptimizerHints{}\n\tmi := &file_api_interpreter_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *OptimizerHints) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OptimizerHints) ProtoMessage() {}\n\nfunc (x *OptimizerHints) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OptimizerHints.ProtoReflect.Descriptor instead.\nfunc (*OptimizerHints) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *OptimizerHints) GetPsiAlgorithmType() PsiAlgorithmType {\n\tif x != nil {\n\t\treturn x.PsiAlgorithmType\n\t}\n\treturn PsiAlgorithmType_AUTO\n}\n\ntype CompileOptions struct {\n\tstate              protoimpl.MessageState    `protogen:\"open.v1\"`\n\tSpuConf            *spu.RuntimeConfig        `protobuf:\"bytes,1,opt,name=spu_conf,json=spuConf,proto3\" json:\"spu_conf,omitempty\"`\n\tSecurityCompromise *SecurityCompromiseConfig `protobuf:\"bytes,2,opt,name=security_compromise,json=securityCompromise,proto3\" json:\"security_compromise,omitempty\"`\n\t// dump execution graph in graphviz dot format\n\tDumpExeGraph   bool            `protobuf:\"varint,3,opt,name=dump_exe_graph,json=dumpExeGraph,proto3\" json:\"dump_exe_graph,omitempty\"`\n\tOptimizerHints *OptimizerHints `protobuf:\"bytes,4,opt,name=optimizer_hints,json=optimizerHints,proto3\" json:\"optimizer_hints,omitempty\"`\n\t// whether to run in streaming mode\n\tBatched       bool `protobuf:\"varint,5,opt,name=batched,proto3\" json:\"batched,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CompileOptions) Reset() {\n\t*x = CompileOptions{}\n\tmi := &file_api_interpreter_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CompileOptions) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CompileOptions) ProtoMessage() {}\n\nfunc (x *CompileOptions) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CompileOptions.ProtoReflect.Descriptor instead.\nfunc (*CompileOptions) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *CompileOptions) GetSpuConf() *spu.RuntimeConfig {\n\tif x != nil {\n\t\treturn x.SpuConf\n\t}\n\treturn nil\n}\n\nfunc (x *CompileOptions) GetSecurityCompromise() *SecurityCompromiseConfig {\n\tif x != nil {\n\t\treturn x.SecurityCompromise\n\t}\n\treturn nil\n}\n\nfunc (x *CompileOptions) GetDumpExeGraph() bool {\n\tif x != nil {\n\t\treturn x.DumpExeGraph\n\t}\n\treturn false\n}\n\nfunc (x *CompileOptions) GetOptimizerHints() *OptimizerHints {\n\tif x != nil {\n\t\treturn x.OptimizerHints\n\t}\n\treturn nil\n}\n\nfunc (x *CompileOptions) GetBatched() bool {\n\tif x != nil {\n\t\treturn x.Batched\n\t}\n\treturn false\n}\n\ntype SecurityCompromiseConfig struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tRevealGroupMark  bool                   `protobuf:\"varint,1,opt,name=reveal_group_mark,json=revealGroupMark,proto3\" json:\"reveal_group_mark,omitempty\"`\n\tGroupByThreshold uint64                 `protobuf:\"varint,2,opt,name=group_by_threshold,json=groupByThreshold,proto3\" json:\"group_by_threshold,omitempty\"`\n\tRevealGroupCount bool                   `protobuf:\"varint,3,opt,name=reveal_group_count,json=revealGroupCount,proto3\" json:\"reveal_group_count,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *SecurityCompromiseConfig) Reset() {\n\t*x = SecurityCompromiseConfig{}\n\tmi := &file_api_interpreter_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SecurityCompromiseConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SecurityCompromiseConfig) ProtoMessage() {}\n\nfunc (x *SecurityCompromiseConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SecurityCompromiseConfig.ProtoReflect.Descriptor instead.\nfunc (*SecurityCompromiseConfig) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *SecurityCompromiseConfig) GetRevealGroupMark() bool {\n\tif x != nil {\n\t\treturn x.RevealGroupMark\n\t}\n\treturn false\n}\n\nfunc (x *SecurityCompromiseConfig) GetGroupByThreshold() uint64 {\n\tif x != nil {\n\t\treturn x.GroupByThreshold\n\t}\n\treturn 0\n}\n\nfunc (x *SecurityCompromiseConfig) GetRevealGroupCount() bool {\n\tif x != nil {\n\t\treturn x.RevealGroupCount\n\t}\n\treturn false\n}\n\ntype Catalog struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tTables        []*TableEntry          `protobuf:\"bytes,1,rep,name=tables,proto3\" json:\"tables,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Catalog) Reset() {\n\t*x = Catalog{}\n\tmi := &file_api_interpreter_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Catalog) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Catalog) ProtoMessage() {}\n\nfunc (x *Catalog) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Catalog.ProtoReflect.Descriptor instead.\nfunc (*Catalog) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *Catalog) GetTables() []*TableEntry {\n\tif x != nil {\n\t\treturn x.Tables\n\t}\n\treturn nil\n}\n\ntype TableEntry struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// table_name could be qualified name, like \"db_name.table_name\"\n\tTableName string               `protobuf:\"bytes,1,opt,name=table_name,json=tableName,proto3\" json:\"table_name,omitempty\"`\n\tColumns   []*TableEntry_Column `protobuf:\"bytes,2,rep,name=columns,proto3\" json:\"columns,omitempty\"`\n\t// NOTE: So far, the value of `is_view` is always False.\n\t// TODO: Add support to view.\n\tIsView bool `protobuf:\"varint,3,opt,name=is_view,json=isView,proto3\" json:\"is_view,omitempty\"`\n\t// The value of `select_string` is the definition body of create view.\n\t// It valids only when is_view is True.\n\tSelectString string `protobuf:\"bytes,4,opt,name=select_string,json=selectString,proto3\" json:\"select_string,omitempty\"`\n\t// The following fields means when `is_view` is false.\n\t// `ref_table` refers the physical/real table name inside individual parties,\n\t// it could be empty if it's the same as table_name.\n\t// `ref_table` name could be qualified name.\n\tRefTable string `protobuf:\"bytes,5,opt,name=ref_table,json=refTable,proto3\" json:\"ref_table,omitempty\"`\n\t// the db type of ref_table, maybe 'MySQL/PostgreSQL/csvdb/...'\n\tDbType string   `protobuf:\"bytes,6,opt,name=db_type,json=dbType,proto3\" json:\"db_type,omitempty\"`\n\tOwner  *PartyId `protobuf:\"bytes,7,opt,name=owner,proto3\" json:\"owner,omitempty\"`\n\t// The ref_table_uri is utilized to route the ref_table, like domain_data_id\n\t// in kuscia\n\tRefTableUri   string `protobuf:\"bytes,8,opt,name=ref_table_uri,json=refTableUri,proto3\" json:\"ref_table_uri,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TableEntry) Reset() {\n\t*x = TableEntry{}\n\tmi := &file_api_interpreter_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TableEntry) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TableEntry) ProtoMessage() {}\n\nfunc (x *TableEntry) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TableEntry.ProtoReflect.Descriptor instead.\nfunc (*TableEntry) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *TableEntry) GetTableName() string {\n\tif x != nil {\n\t\treturn x.TableName\n\t}\n\treturn \"\"\n}\n\nfunc (x *TableEntry) GetColumns() []*TableEntry_Column {\n\tif x != nil {\n\t\treturn x.Columns\n\t}\n\treturn nil\n}\n\nfunc (x *TableEntry) GetIsView() bool {\n\tif x != nil {\n\t\treturn x.IsView\n\t}\n\treturn false\n}\n\nfunc (x *TableEntry) GetSelectString() string {\n\tif x != nil {\n\t\treturn x.SelectString\n\t}\n\treturn \"\"\n}\n\nfunc (x *TableEntry) GetRefTable() string {\n\tif x != nil {\n\t\treturn x.RefTable\n\t}\n\treturn \"\"\n}\n\nfunc (x *TableEntry) GetDbType() string {\n\tif x != nil {\n\t\treturn x.DbType\n\t}\n\treturn \"\"\n}\n\nfunc (x *TableEntry) GetOwner() *PartyId {\n\tif x != nil {\n\t\treturn x.Owner\n\t}\n\treturn nil\n}\n\nfunc (x *TableEntry) GetRefTableUri() string {\n\tif x != nil {\n\t\treturn x.RefTableUri\n\t}\n\treturn \"\"\n}\n\ntype TableEntry_Column struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tName            string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tType            string                 `protobuf:\"bytes,2,opt,name=type,proto3\" json:\"type,omitempty\"`\n\tOrdinalPosition int32                  `protobuf:\"varint,3,opt,name=ordinal_position,json=ordinalPosition,proto3\" json:\"ordinal_position,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *TableEntry_Column) Reset() {\n\t*x = TableEntry_Column{}\n\tmi := &file_api_interpreter_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TableEntry_Column) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TableEntry_Column) ProtoMessage() {}\n\nfunc (x *TableEntry_Column) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_interpreter_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TableEntry_Column.ProtoReflect.Descriptor instead.\nfunc (*TableEntry_Column) Descriptor() ([]byte, []int) {\n\treturn file_api_interpreter_proto_rawDescGZIP(), []int{9, 0}\n}\n\nfunc (x *TableEntry_Column) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *TableEntry_Column) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\nfunc (x *TableEntry_Column) GetOrdinalPosition() int32 {\n\tif x != nil {\n\t\treturn x.OrdinalPosition\n\t}\n\treturn 0\n}\n\nvar File_api_interpreter_proto protoreflect.FileDescriptor\n\nvar file_api_interpreter_proto_rawDesc = []byte{\n\t0x0a, 0x15, 0x61, 0x70, 0x69, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65,\n\t0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62,\n\t0x1a, 0x10, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x1a, 0x10, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0e, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x75, 0x62, 0x67, 0x72, 0x61,\n\t0x70, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x6c, 0x69, 0x62, 0x73, 0x70, 0x75,\n\t0x2f, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67,\n\t0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65,\n\t0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xce, 0x03, 0x0a, 0x0c,\n\t0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x2c, 0x0a, 0x06,\n\t0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73,\n\t0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x63, 0x68, 0x65,\n\t0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x2a, 0x0a, 0x07, 0x77, 0x61,\n\t0x72, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x63,\n\t0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x77,\n\t0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x3f, 0x0a, 0x10, 0x73, 0x70, 0x75, 0x5f, 0x72, 0x75,\n\t0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x15, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d,\n\t0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x70, 0x75, 0x52, 0x75, 0x6e, 0x74,\n\t0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x2a, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x74, 0x69,\n\t0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e,\n\t0x70, 0x62, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x79, 0x49, 0x64, 0x52, 0x07, 0x70, 0x61, 0x72, 0x74,\n\t0x69, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68,\n\t0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70,\n\t0x62, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x50, 0x6c, 0x61, 0x6e, 0x2e, 0x53,\n\t0x75, 0x62, 0x47, 0x72, 0x61, 0x70, 0x68, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x73,\n\t0x75, 0x62, 0x47, 0x72, 0x61, 0x70, 0x68, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x77, 0x68, 0x6f, 0x6c,\n\t0x65, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d,\n\t0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x68, 0x6f, 0x6c, 0x65, 0x47, 0x72, 0x61,\n\t0x70, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x12, 0x2f, 0x0a, 0x07, 0x65, 0x78,\n\t0x70, 0x6c, 0x61, 0x69, 0x6e, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73,\n\t0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x49, 0x6e,\n\t0x66, 0x6f, 0x52, 0x07, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x1a, 0x4f, 0x0a, 0x0e, 0x53,\n\t0x75, 0x62, 0x47, 0x72, 0x61, 0x70, 0x68, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,\n\t0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,\n\t0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x47, 0x72, 0x61, 0x70,\n\t0x68, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4f, 0x0a, 0x07,\n\t0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x44, 0x0a, 0x1f, 0x6d, 0x61, 0x79, 0x5f, 0x61,\n\t0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70,\n\t0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x1b, 0x6d, 0x61, 0x79, 0x41, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x42, 0x79, 0x47,\n\t0x72, 0x6f, 0x75, 0x70, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x31, 0x0a,\n\t0x0b, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d,\n\t0x65, 0x78, 0x65, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x64, 0x6f, 0x74, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x44, 0x6f, 0x74,\n\t0x22, 0x3c, 0x0a, 0x0b, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12,\n\t0x2d, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,\n\t0x32, 0x13, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d,\n\t0x6e, 0x44, 0x65, 0x73, 0x63, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x22, 0x34,\n\t0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x12, 0x12, 0x0a, 0x04,\n\t0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,\n\t0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,\n\t0x74, 0x79, 0x70, 0x65, 0x22, 0x59, 0x0a, 0x0e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65,\n\t0x72, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x47, 0x0a, 0x12, 0x70, 0x73, 0x69, 0x5f, 0x61, 0x6c,\n\t0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x0e, 0x32, 0x19, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x73, 0x69,\n\t0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x52, 0x10, 0x70,\n\t0x73, 0x69, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x22,\n\t0x98, 0x02, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f,\n\t0x6e, 0x73, 0x12, 0x30, 0x0a, 0x08, 0x73, 0x70, 0x75, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x75,\n\t0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x73, 0x70, 0x75,\n\t0x43, 0x6f, 0x6e, 0x66, 0x12, 0x52, 0x0a, 0x13, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79,\n\t0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x0b, 0x32, 0x21, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x63, 0x75,\n\t0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x52, 0x12, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f,\n\t0x6d, 0x70, 0x72, 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x64, 0x75, 0x6d, 0x70,\n\t0x5f, 0x65, 0x78, 0x65, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x0c, 0x64, 0x75, 0x6d, 0x70, 0x45, 0x78, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x40,\n\t0x0a, 0x0f, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x72, 0x5f, 0x68, 0x69, 0x6e, 0x74,\n\t0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70,\n\t0x62, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x72, 0x48, 0x69, 0x6e, 0x74, 0x73,\n\t0x52, 0x0e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x72, 0x48, 0x69, 0x6e, 0x74, 0x73,\n\t0x12, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28,\n\t0x08, 0x52, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x22, 0xa2, 0x01, 0x0a, 0x18, 0x53,\n\t0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x6f, 0x6d, 0x69, 0x73,\n\t0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x76, 0x65, 0x61,\n\t0x6c, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d,\n\t0x61, 0x72, 0x6b, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x62, 0x79, 0x5f,\n\t0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,\n\t0x10, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c,\n\t0x64, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x5f, 0x67, 0x72, 0x6f, 0x75,\n\t0x70, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72,\n\t0x65, 0x76, 0x65, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22,\n\t0x36, 0x0a, 0x07, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x2b, 0x0a, 0x06, 0x74, 0x61,\n\t0x62, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x63, 0x71,\n\t0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,\n\t0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x22, 0xfe, 0x02, 0x0a, 0x0a, 0x54, 0x61, 0x62, 0x6c,\n\t0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f,\n\t0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c,\n\t0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73,\n\t0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62,\n\t0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6c, 0x75,\n\t0x6d, 0x6e, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x69,\n\t0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73,\n\t0x56, 0x69, 0x65, 0x77, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x5f, 0x73,\n\t0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x6c,\n\t0x65, 0x63, 0x74, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x66,\n\t0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65,\n\t0x66, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x62, 0x5f, 0x74, 0x79, 0x70,\n\t0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x62, 0x54, 0x79, 0x70, 0x65, 0x12,\n\t0x26, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x79, 0x49, 0x64,\n\t0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x5f, 0x74,\n\t0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,\n\t0x72, 0x65, 0x66, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x72, 0x69, 0x1a, 0x5b, 0x0a, 0x06, 0x43,\n\t0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70,\n\t0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a,\n\t0x10, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f,\n\t0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c,\n\t0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x10, 0x5a, 0x0e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x2d, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x63, 0x71, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x33,\n}\n\nvar (\n\tfile_api_interpreter_proto_rawDescOnce sync.Once\n\tfile_api_interpreter_proto_rawDescData = file_api_interpreter_proto_rawDesc\n)\n\nfunc file_api_interpreter_proto_rawDescGZIP() []byte {\n\tfile_api_interpreter_proto_rawDescOnce.Do(func() {\n\t\tfile_api_interpreter_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_interpreter_proto_rawDescData)\n\t})\n\treturn file_api_interpreter_proto_rawDescData\n}\n\nvar file_api_interpreter_proto_msgTypes = make([]protoimpl.MessageInfo, 12)\nvar file_api_interpreter_proto_goTypes = []any{\n\t(*CompiledPlan)(nil),             // 0: scql.pb.CompiledPlan\n\t(*Warning)(nil),                  // 1: scql.pb.Warning\n\t(*ExplainInfo)(nil),              // 2: scql.pb.ExplainInfo\n\t(*TableSchema)(nil),              // 3: scql.pb.TableSchema\n\t(*ColumnDesc)(nil),               // 4: scql.pb.ColumnDesc\n\t(*OptimizerHints)(nil),           // 5: scql.pb.OptimizerHints\n\t(*CompileOptions)(nil),           // 6: scql.pb.CompileOptions\n\t(*SecurityCompromiseConfig)(nil), // 7: scql.pb.SecurityCompromiseConfig\n\t(*Catalog)(nil),                  // 8: scql.pb.Catalog\n\t(*TableEntry)(nil),               // 9: scql.pb.TableEntry\n\tnil,                              // 10: scql.pb.CompiledPlan.SubGraphsEntry\n\t(*TableEntry_Column)(nil),        // 11: scql.pb.TableEntry.Column\n\t(*spu.RuntimeConfig)(nil),        // 12: spu.pb.RuntimeConfig\n\t(*PartyId)(nil),                  // 13: scql.pb.PartyId\n\t(PsiAlgorithmType)(0),            // 14: scql.pb.PsiAlgorithmType\n\t(*SubGraph)(nil),                 // 15: scql.pb.SubGraph\n}\nvar file_api_interpreter_proto_depIdxs = []int32{\n\t3,  // 0: scql.pb.CompiledPlan.schema:type_name -> scql.pb.TableSchema\n\t1,  // 1: scql.pb.CompiledPlan.warning:type_name -> scql.pb.Warning\n\t12, // 2: scql.pb.CompiledPlan.spu_runtime_conf:type_name -> spu.pb.RuntimeConfig\n\t13, // 3: scql.pb.CompiledPlan.parties:type_name -> scql.pb.PartyId\n\t10, // 4: scql.pb.CompiledPlan.sub_graphs:type_name -> scql.pb.CompiledPlan.SubGraphsEntry\n\t2,  // 5: scql.pb.CompiledPlan.explain:type_name -> scql.pb.ExplainInfo\n\t4,  // 6: scql.pb.TableSchema.columns:type_name -> scql.pb.ColumnDesc\n\t14, // 7: scql.pb.OptimizerHints.psi_algorithm_type:type_name -> scql.pb.PsiAlgorithmType\n\t12, // 8: scql.pb.CompileOptions.spu_conf:type_name -> spu.pb.RuntimeConfig\n\t7,  // 9: scql.pb.CompileOptions.security_compromise:type_name -> scql.pb.SecurityCompromiseConfig\n\t5,  // 10: scql.pb.CompileOptions.optimizer_hints:type_name -> scql.pb.OptimizerHints\n\t9,  // 11: scql.pb.Catalog.tables:type_name -> scql.pb.TableEntry\n\t11, // 12: scql.pb.TableEntry.columns:type_name -> scql.pb.TableEntry.Column\n\t13, // 13: scql.pb.TableEntry.owner:type_name -> scql.pb.PartyId\n\t15, // 14: scql.pb.CompiledPlan.SubGraphsEntry.value:type_name -> scql.pb.SubGraph\n\t15, // [15:15] is the sub-list for method output_type\n\t15, // [15:15] is the sub-list for method input_type\n\t15, // [15:15] is the sub-list for extension type_name\n\t15, // [15:15] is the sub-list for extension extendee\n\t0,  // [0:15] is the sub-list for field type_name\n}\n\nfunc init() { file_api_interpreter_proto_init() }\nfunc file_api_interpreter_proto_init() {\n\tif File_api_interpreter_proto != nil {\n\t\treturn\n\t}\n\tfile_api_status_proto_init()\n\tfile_api_common_proto_init()\n\tfile_api_core_proto_init()\n\tfile_api_subgraph_proto_init()\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_api_interpreter_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   12,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_api_interpreter_proto_goTypes,\n\t\tDependencyIndexes: file_api_interpreter_proto_depIdxs,\n\t\tMessageInfos:      file_api_interpreter_proto_msgTypes,\n\t}.Build()\n\tFile_api_interpreter_proto = out.File\n\tfile_api_interpreter_proto_rawDesc = nil\n\tfile_api_interpreter_proto_goTypes = nil\n\tfile_api_interpreter_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/proto-gen/scql/scql_task.pb.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.3\n// \tprotoc        v5.27.3\n// source: api/scql_task.proto\n\npackage scql\n\nimport (\n\tspu \"github.com/secretflow/scql/pkg/proto-gen/spu\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// SCQL job configuration containing execution plans and runtime settings\ntype ScqlConfig struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Table name to input file path mapping\n\tInputFilePaths map[string]string `protobuf:\"bytes,1,rep,name=input_file_paths,json=inputFilePaths,proto3\" json:\"input_file_paths,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\t// Party code to execution graph mapping\n\tAllSubGraphs map[string]*SubGraph `protobuf:\"bytes,2,rep,name=all_sub_graphs,json=allSubGraphs,proto3\" json:\"all_sub_graphs,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\t// Participating parties sorted by rank (starting from 0)\n\tParties []string `protobuf:\"bytes,3,rep,name=parties,proto3\" json:\"parties,omitempty\"`\n\t// Runtime configurations\n\tSpuRuntimeCfg *spu.RuntimeConfig `protobuf:\"bytes,10,opt,name=spu_runtime_cfg,json=spuRuntimeCfg,proto3\" json:\"spu_runtime_cfg,omitempty\"` // SPU protocol settings\n\tTimeZone      string             `protobuf:\"bytes,11,opt,name=time_zone,json=timeZone,proto3\" json:\"time_zone,omitempty\"`                  // Time zone for temporal operations\n\tLinkCfg       *LinkConfig        `protobuf:\"bytes,12,opt,name=link_cfg,json=linkCfg,proto3\" json:\"link_cfg,omitempty\"`                     // Network communication settings\n\tPsiCfg        *PsiConfig         `protobuf:\"bytes,13,opt,name=psi_cfg,json=psiCfg,proto3\" json:\"psi_cfg,omitempty\"`                        // Private set intersection config\n\tLogCfg        *LogConfig         `protobuf:\"bytes,14,opt,name=log_cfg,json=logCfg,proto3\" json:\"log_cfg,omitempty\"`                        // Logging configuration\n\t// Configuration used by the Kpad only\n\tGraphChecksum string `protobuf:\"bytes,20,opt,name=graph_checksum,json=graphChecksum,proto3\" json:\"graph_checksum,omitempty\"` // Checksum of the overall execution graph, used by other parties to verify graph consistency\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ScqlConfig) Reset() {\n\t*x = ScqlConfig{}\n\tmi := &file_api_scql_task_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ScqlConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ScqlConfig) ProtoMessage() {}\n\nfunc (x *ScqlConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_scql_task_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ScqlConfig.ProtoReflect.Descriptor instead.\nfunc (*ScqlConfig) Descriptor() ([]byte, []int) {\n\treturn file_api_scql_task_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ScqlConfig) GetInputFilePaths() map[string]string {\n\tif x != nil {\n\t\treturn x.InputFilePaths\n\t}\n\treturn nil\n}\n\nfunc (x *ScqlConfig) GetAllSubGraphs() map[string]*SubGraph {\n\tif x != nil {\n\t\treturn x.AllSubGraphs\n\t}\n\treturn nil\n}\n\nfunc (x *ScqlConfig) GetParties() []string {\n\tif x != nil {\n\t\treturn x.Parties\n\t}\n\treturn nil\n}\n\nfunc (x *ScqlConfig) GetSpuRuntimeCfg() *spu.RuntimeConfig {\n\tif x != nil {\n\t\treturn x.SpuRuntimeCfg\n\t}\n\treturn nil\n}\n\nfunc (x *ScqlConfig) GetTimeZone() string {\n\tif x != nil {\n\t\treturn x.TimeZone\n\t}\n\treturn \"\"\n}\n\nfunc (x *ScqlConfig) GetLinkCfg() *LinkConfig {\n\tif x != nil {\n\t\treturn x.LinkCfg\n\t}\n\treturn nil\n}\n\nfunc (x *ScqlConfig) GetPsiCfg() *PsiConfig {\n\tif x != nil {\n\t\treturn x.PsiCfg\n\t}\n\treturn nil\n}\n\nfunc (x *ScqlConfig) GetLogCfg() *LogConfig {\n\tif x != nil {\n\t\treturn x.LogCfg\n\t}\n\treturn nil\n}\n\nfunc (x *ScqlConfig) GetGraphChecksum() string {\n\tif x != nil {\n\t\treturn x.GraphChecksum\n\t}\n\treturn \"\"\n}\n\nvar File_api_scql_task_proto protoreflect.FileDescriptor\n\nvar file_api_scql_task_proto_rawDesc = []byte{\n\t0x0a, 0x13, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x63, 0x71, 0x6c, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x1a, 0x10,\n\t0x61, 0x70, 0x69, 0x2f, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x1a, 0x12, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x75, 0x62, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x6c, 0x69, 0x62, 0x73, 0x70, 0x75, 0x2f, 0x73,\n\t0x70, 0x75, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xea, 0x04, 0x0a, 0x0a, 0x53, 0x63, 0x71,\n\t0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x51, 0x0a, 0x10, 0x69, 0x6e, 0x70, 0x75, 0x74,\n\t0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x27, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x63, 0x71, 0x6c,\n\t0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x69, 0x6c, 0x65,\n\t0x50, 0x61, 0x74, 0x68, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x69, 0x6e, 0x70, 0x75,\n\t0x74, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x4b, 0x0a, 0x0e, 0x61, 0x6c,\n\t0x6c, 0x5f, 0x73, 0x75, 0x62, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x73, 0x18, 0x02, 0x20, 0x03,\n\t0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x63, 0x71,\n\t0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x47, 0x72,\n\t0x61, 0x70, 0x68, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x53, 0x75,\n\t0x62, 0x47, 0x72, 0x61, 0x70, 0x68, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x74, 0x69,\n\t0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x74, 0x69, 0x65,\n\t0x73, 0x12, 0x3d, 0x0a, 0x0f, 0x73, 0x70, 0x75, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,\n\t0x5f, 0x63, 0x66, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x70, 0x75,\n\t0x2e, 0x70, 0x62, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x52, 0x0d, 0x73, 0x70, 0x75, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x66, 0x67,\n\t0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x0b, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x12, 0x2e, 0x0a,\n\t0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, 0x66, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x13, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x66, 0x67, 0x12, 0x2b, 0x0a,\n\t0x07, 0x70, 0x73, 0x69, 0x5f, 0x63, 0x66, 0x67, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x73, 0x69, 0x43, 0x6f, 0x6e, 0x66,\n\t0x69, 0x67, 0x52, 0x06, 0x70, 0x73, 0x69, 0x43, 0x66, 0x67, 0x12, 0x2b, 0x0a, 0x07, 0x6c, 0x6f,\n\t0x67, 0x5f, 0x63, 0x66, 0x67, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x63,\n\t0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,\n\t0x06, 0x6c, 0x6f, 0x67, 0x43, 0x66, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x67, 0x72, 0x61, 0x70, 0x68,\n\t0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x0d, 0x67, 0x72, 0x61, 0x70, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x1a, 0x41,\n\t0x0a, 0x13, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73,\n\t0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,\n\t0x01, 0x1a, 0x52, 0x0a, 0x11, 0x41, 0x6c, 0x6c, 0x53, 0x75, 0x62, 0x47, 0x72, 0x61, 0x70, 0x68,\n\t0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70,\n\t0x62, 0x2e, 0x53, 0x75, 0x62, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x3a, 0x02, 0x38, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_api_scql_task_proto_rawDescOnce sync.Once\n\tfile_api_scql_task_proto_rawDescData = file_api_scql_task_proto_rawDesc\n)\n\nfunc file_api_scql_task_proto_rawDescGZIP() []byte {\n\tfile_api_scql_task_proto_rawDescOnce.Do(func() {\n\t\tfile_api_scql_task_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_scql_task_proto_rawDescData)\n\t})\n\treturn file_api_scql_task_proto_rawDescData\n}\n\nvar file_api_scql_task_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_api_scql_task_proto_goTypes = []any{\n\t(*ScqlConfig)(nil),        // 0: scql.pb.ScqlConfig\n\tnil,                       // 1: scql.pb.ScqlConfig.InputFilePathsEntry\n\tnil,                       // 2: scql.pb.ScqlConfig.AllSubGraphsEntry\n\t(*spu.RuntimeConfig)(nil), // 3: spu.pb.RuntimeConfig\n\t(*LinkConfig)(nil),        // 4: scql.pb.LinkConfig\n\t(*PsiConfig)(nil),         // 5: scql.pb.PsiConfig\n\t(*LogConfig)(nil),         // 6: scql.pb.LogConfig\n\t(*SubGraph)(nil),          // 7: scql.pb.SubGraph\n}\nvar file_api_scql_task_proto_depIdxs = []int32{\n\t1, // 0: scql.pb.ScqlConfig.input_file_paths:type_name -> scql.pb.ScqlConfig.InputFilePathsEntry\n\t2, // 1: scql.pb.ScqlConfig.all_sub_graphs:type_name -> scql.pb.ScqlConfig.AllSubGraphsEntry\n\t3, // 2: scql.pb.ScqlConfig.spu_runtime_cfg:type_name -> spu.pb.RuntimeConfig\n\t4, // 3: scql.pb.ScqlConfig.link_cfg:type_name -> scql.pb.LinkConfig\n\t5, // 4: scql.pb.ScqlConfig.psi_cfg:type_name -> scql.pb.PsiConfig\n\t6, // 5: scql.pb.ScqlConfig.log_cfg:type_name -> scql.pb.LogConfig\n\t7, // 6: scql.pb.ScqlConfig.AllSubGraphsEntry.value:type_name -> scql.pb.SubGraph\n\t7, // [7:7] is the sub-list for method output_type\n\t7, // [7:7] is the sub-list for method input_type\n\t7, // [7:7] is the sub-list for extension type_name\n\t7, // [7:7] is the sub-list for extension extendee\n\t0, // [0:7] is the sub-list for field type_name\n}\n\nfunc init() { file_api_scql_task_proto_init() }\nfunc file_api_scql_task_proto_init() {\n\tif File_api_scql_task_proto != nil {\n\t\treturn\n\t}\n\tfile_api_engine_proto_init()\n\tfile_api_subgraph_proto_init()\n\tfile_api_common_proto_init()\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_api_scql_task_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_api_scql_task_proto_goTypes,\n\t\tDependencyIndexes: file_api_scql_task_proto_depIdxs,\n\t\tMessageInfos:      file_api_scql_task_proto_msgTypes,\n\t}.Build()\n\tFile_api_scql_task_proto = out.File\n\tfile_api_scql_task_proto_rawDesc = nil\n\tfile_api_scql_task_proto_goTypes = nil\n\tfile_api_scql_task_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/proto-gen/scql/status.pb.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// Reference:\n// https://github.com/grpc/grpc/blob/master/src/proto/grpc/status/status.proto\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.3\n// \tprotoc        v5.27.3\n// source: api/status.proto\n\npackage scql\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tanypb \"google.golang.org/protobuf/types/known/anypb\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// The `Status` type defines a logical error model that is suitable for\n// different programming environments, including REST APIs and RPC APIs. It is\n// used by [gRPC](https://github.com/grpc). Each `Status` message contains\n// three pieces of data: error code, error message, and error details.\n//\n// You can find out more about this error model and how to work with it in the\n// [API Design Guide](https://cloud.google.com/apis/design/errors).\ntype Status struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The status code, see\n\t// [definition](https://github.com/secretflow/scql/blob/main/api/status_code.proto#L22)\n\tCode int32 `protobuf:\"varint,1,opt,name=code,proto3\" json:\"code,omitempty\"`\n\t// Message for recording the error information.\n\tMessage string `protobuf:\"bytes,2,opt,name=message,proto3\" json:\"message,omitempty\"`\n\t// A list of messages that carry the additional supplementary error details.\n\tDetails       []*anypb.Any `protobuf:\"bytes,3,rep,name=details,proto3\" json:\"details,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Status) Reset() {\n\t*x = Status{}\n\tmi := &file_api_status_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Status) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Status) ProtoMessage() {}\n\nfunc (x *Status) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_status_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Status.ProtoReflect.Descriptor instead.\nfunc (*Status) Descriptor() ([]byte, []int) {\n\treturn file_api_status_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Status) GetCode() int32 {\n\tif x != nil {\n\t\treturn x.Code\n\t}\n\treturn 0\n}\n\nfunc (x *Status) GetMessage() string {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn \"\"\n}\n\nfunc (x *Status) GetDetails() []*anypb.Any {\n\tif x != nil {\n\t\treturn x.Details\n\t}\n\treturn nil\n}\n\nvar File_api_status_proto protoreflect.FileDescriptor\n\nvar file_api_status_proto_rawDesc = []byte{\n\t0x0a, 0x10, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x12, 0x07, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x1a, 0x19, 0x67, 0x6f, 0x6f,\n\t0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x66, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,\n\t0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04,\n\t0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18,\n\t0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e,\n\t0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,\n\t0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x25,\n\t0x0a, 0x13, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x66, 0x6c, 0x6f, 0x77,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x5a, 0x0e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x67, 0x65, 0x6e,\n\t0x2f, 0x73, 0x63, 0x71, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_api_status_proto_rawDescOnce sync.Once\n\tfile_api_status_proto_rawDescData = file_api_status_proto_rawDesc\n)\n\nfunc file_api_status_proto_rawDescGZIP() []byte {\n\tfile_api_status_proto_rawDescOnce.Do(func() {\n\t\tfile_api_status_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_status_proto_rawDescData)\n\t})\n\treturn file_api_status_proto_rawDescData\n}\n\nvar file_api_status_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_api_status_proto_goTypes = []any{\n\t(*Status)(nil),    // 0: scql.pb.Status\n\t(*anypb.Any)(nil), // 1: google.protobuf.Any\n}\nvar file_api_status_proto_depIdxs = []int32{\n\t1, // 0: scql.pb.Status.details:type_name -> google.protobuf.Any\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_api_status_proto_init() }\nfunc file_api_status_proto_init() {\n\tif File_api_status_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_api_status_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_api_status_proto_goTypes,\n\t\tDependencyIndexes: file_api_status_proto_depIdxs,\n\t\tMessageInfos:      file_api_status_proto_msgTypes,\n\t}.Build()\n\tFile_api_status_proto = out.File\n\tfile_api_status_proto_rawDesc = nil\n\tfile_api_status_proto_goTypes = nil\n\tfile_api_status_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/proto-gen/scql/status_code.pb.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.3\n// \tprotoc        v5.27.3\n// source: api/status_code.proto\n\npackage scql\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype Code int32\n\nconst (\n\t// Not an error; returned on success\n\tCode_OK Code = 0\n\t// General bad request\n\tCode_BAD_REQUEST Code = 100\n\t// Failed to authenticate user credential\n\tCode_UNAUTHENTICATED Code = 101\n\t// Parsing SQL error, returned on invalid SQL\n\tCode_SQL_PARSE_ERROR  Code = 102\n\tCode_INVALID_ARGUMENT Code = 103\n\t// Query result is not ready, please try again later\n\tCode_NOT_READY Code = 104\n\t// The user does not have permission to execute the DDL.\n\t// For example, the user try to drop other's table.\n\tCode_DDL_PERMISSION_DENIED Code = 131\n\t// General not found error\n\tCode_NOT_FOUND Code = 140\n\t// Driver session not found\n\tCode_SESSION_NOT_FOUND Code = 141\n\t// Query CCL check failed\n\t// NOTE: CCL (Column Control Language) has been removed from SCQL,\n\t// this error code is kept for backward compatibility only\n\tCode_CCL_CHECK_FAILED Code = 160\n\t// The P2P internal exchange error\n\t// Local storage info is not equal to storage info in other parties\n\tCode_DATA_INCONSISTENCY Code = 170\n\t// In P2P mode, the project status in different members conflicts and cannot\n\t// reach an agreement\n\tCode_PROJECT_CONFLICT Code = 171\n\t// Driver DB error\n\tCode_STORAGE_ERROR Code = 201\n\t// UNKNOWN Server Internal Error\n\tCode_INTERNAL Code = 300\n\t// 320-339 executing execution graph error\n\tCode_UNKNOWN_ENGINE_ERROR Code = 320\n\tCode_ENGINE_RUNSQL_ERROR  Code = 332\n\t// Feature not supported\n\tCode_NOT_SUPPORTED Code = 340\n)\n\n// Enum value maps for Code.\nvar (\n\tCode_name = map[int32]string{\n\t\t0:   \"OK\",\n\t\t100: \"BAD_REQUEST\",\n\t\t101: \"UNAUTHENTICATED\",\n\t\t102: \"SQL_PARSE_ERROR\",\n\t\t103: \"INVALID_ARGUMENT\",\n\t\t104: \"NOT_READY\",\n\t\t131: \"DDL_PERMISSION_DENIED\",\n\t\t140: \"NOT_FOUND\",\n\t\t141: \"SESSION_NOT_FOUND\",\n\t\t160: \"CCL_CHECK_FAILED\",\n\t\t170: \"DATA_INCONSISTENCY\",\n\t\t171: \"PROJECT_CONFLICT\",\n\t\t201: \"STORAGE_ERROR\",\n\t\t300: \"INTERNAL\",\n\t\t320: \"UNKNOWN_ENGINE_ERROR\",\n\t\t332: \"ENGINE_RUNSQL_ERROR\",\n\t\t340: \"NOT_SUPPORTED\",\n\t}\n\tCode_value = map[string]int32{\n\t\t\"OK\":                    0,\n\t\t\"BAD_REQUEST\":           100,\n\t\t\"UNAUTHENTICATED\":       101,\n\t\t\"SQL_PARSE_ERROR\":       102,\n\t\t\"INVALID_ARGUMENT\":      103,\n\t\t\"NOT_READY\":             104,\n\t\t\"DDL_PERMISSION_DENIED\": 131,\n\t\t\"NOT_FOUND\":             140,\n\t\t\"SESSION_NOT_FOUND\":     141,\n\t\t\"CCL_CHECK_FAILED\":      160,\n\t\t\"DATA_INCONSISTENCY\":    170,\n\t\t\"PROJECT_CONFLICT\":      171,\n\t\t\"STORAGE_ERROR\":         201,\n\t\t\"INTERNAL\":              300,\n\t\t\"UNKNOWN_ENGINE_ERROR\":  320,\n\t\t\"ENGINE_RUNSQL_ERROR\":   332,\n\t\t\"NOT_SUPPORTED\":         340,\n\t}\n)\n\nfunc (x Code) Enum() *Code {\n\tp := new(Code)\n\t*p = x\n\treturn p\n}\n\nfunc (x Code) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Code) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_api_status_code_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Code) Type() protoreflect.EnumType {\n\treturn &file_api_status_code_proto_enumTypes[0]\n}\n\nfunc (x Code) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Code.Descriptor instead.\nfunc (Code) EnumDescriptor() ([]byte, []int) {\n\treturn file_api_status_code_proto_rawDescGZIP(), []int{0}\n}\n\nvar File_api_status_code_proto protoreflect.FileDescriptor\n\nvar file_api_status_code_proto_rawDesc = []byte{\n\t0x0a, 0x15, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64,\n\t0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62,\n\t0x2a, 0xe5, 0x02, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10,\n\t0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x42, 0x41, 0x44, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54,\n\t0x10, 0x64, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49,\n\t0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x51, 0x4c, 0x5f, 0x50,\n\t0x41, 0x52, 0x53, 0x45, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x66, 0x12, 0x14, 0x0a, 0x10,\n\t0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x41, 0x52, 0x47, 0x55, 0x4d, 0x45, 0x4e, 0x54,\n\t0x10, 0x67, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x54, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10,\n\t0x68, 0x12, 0x1a, 0x0a, 0x15, 0x44, 0x44, 0x4c, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53,\n\t0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x4e, 0x49, 0x45, 0x44, 0x10, 0x83, 0x01, 0x12, 0x0e, 0x0a,\n\t0x09, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x8c, 0x01, 0x12, 0x16, 0x0a,\n\t0x11, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55,\n\t0x4e, 0x44, 0x10, 0x8d, 0x01, 0x12, 0x15, 0x0a, 0x10, 0x43, 0x43, 0x4c, 0x5f, 0x43, 0x48, 0x45,\n\t0x43, 0x4b, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0xa0, 0x01, 0x12, 0x17, 0x0a, 0x12,\n\t0x44, 0x41, 0x54, 0x41, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4e, 0x53, 0x49, 0x53, 0x54, 0x45, 0x4e,\n\t0x43, 0x59, 0x10, 0xaa, 0x01, 0x12, 0x15, 0x0a, 0x10, 0x50, 0x52, 0x4f, 0x4a, 0x45, 0x43, 0x54,\n\t0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x4c, 0x49, 0x43, 0x54, 0x10, 0xab, 0x01, 0x12, 0x12, 0x0a, 0x0d,\n\t0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0xc9, 0x01,\n\t0x12, 0x0d, 0x0a, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0xac, 0x02, 0x12,\n\t0x19, 0x0a, 0x14, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x45, 0x4e, 0x47, 0x49, 0x4e,\n\t0x45, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0xc0, 0x02, 0x12, 0x18, 0x0a, 0x13, 0x45, 0x4e,\n\t0x47, 0x49, 0x4e, 0x45, 0x5f, 0x52, 0x55, 0x4e, 0x53, 0x51, 0x4c, 0x5f, 0x45, 0x52, 0x52, 0x4f,\n\t0x52, 0x10, 0xcc, 0x02, 0x12, 0x12, 0x0a, 0x0d, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x55, 0x50, 0x50,\n\t0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0xd4, 0x02, 0x42, 0x10, 0x5a, 0x0e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x2d, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x63, 0x71, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x33,\n}\n\nvar (\n\tfile_api_status_code_proto_rawDescOnce sync.Once\n\tfile_api_status_code_proto_rawDescData = file_api_status_code_proto_rawDesc\n)\n\nfunc file_api_status_code_proto_rawDescGZIP() []byte {\n\tfile_api_status_code_proto_rawDescOnce.Do(func() {\n\t\tfile_api_status_code_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_status_code_proto_rawDescData)\n\t})\n\treturn file_api_status_code_proto_rawDescData\n}\n\nvar file_api_status_code_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_api_status_code_proto_goTypes = []any{\n\t(Code)(0), // 0: scql.pb.Code\n}\nvar file_api_status_code_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_api_status_code_proto_init() }\nfunc file_api_status_code_proto_init() {\n\tif File_api_status_code_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_api_status_code_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   0,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_api_status_code_proto_goTypes,\n\t\tDependencyIndexes: file_api_status_code_proto_depIdxs,\n\t\tEnumInfos:         file_api_status_code_proto_enumTypes,\n\t}.Build()\n\tFile_api_status_code_proto = out.File\n\tfile_api_status_code_proto_rawDesc = nil\n\tfile_api_status_code_proto_goTypes = nil\n\tfile_api_status_code_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/proto-gen/scql/subgraph.pb.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.3\n// \tprotoc        v5.27.3\n// source: api/subgraph.proto\n\npackage scql\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// SubGraph is the part of the whole execution graph seen\n// from the perspective of the party.\n// Each party could only see the ExecNode which it participates in.\ntype SubGraph struct {\n\tstate  protoimpl.MessageState `protogen:\"open.v1\"`\n\tNodes  map[string]*ExecNode   `protobuf:\"bytes,1,rep,name=nodes,proto3\" json:\"nodes,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tPolicy *SchedulingPolicy      `protobuf:\"bytes,2,opt,name=policy,proto3\" json:\"policy,omitempty\"`\n\t// checksum of the current sub graph\n\t// It could be used to verify and ensure that engines execute the same graph.\n\tSubGraphChecksum string `protobuf:\"bytes,3,opt,name=sub_graph_checksum,json=subGraphChecksum,proto3\" json:\"sub_graph_checksum,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *SubGraph) Reset() {\n\t*x = SubGraph{}\n\tmi := &file_api_subgraph_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SubGraph) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SubGraph) ProtoMessage() {}\n\nfunc (x *SubGraph) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_subgraph_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SubGraph.ProtoReflect.Descriptor instead.\nfunc (*SubGraph) Descriptor() ([]byte, []int) {\n\treturn file_api_subgraph_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *SubGraph) GetNodes() map[string]*ExecNode {\n\tif x != nil {\n\t\treturn x.Nodes\n\t}\n\treturn nil\n}\n\nfunc (x *SubGraph) GetPolicy() *SchedulingPolicy {\n\tif x != nil {\n\t\treturn x.Policy\n\t}\n\treturn nil\n}\n\nfunc (x *SubGraph) GetSubGraphChecksum() string {\n\tif x != nil {\n\t\treturn x.SubGraphChecksum\n\t}\n\treturn \"\"\n}\n\ntype SubDAG struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\tJobs  []*SubDAG_Job          `protobuf:\"bytes,1,rep,name=jobs,proto3\" json:\"jobs,omitempty\"`\n\t// a barrier to sync among parties\n\tNeedCallBarrierAfterJobs bool `protobuf:\"varint,2,opt,name=need_call_barrier_after_jobs,json=needCallBarrierAfterJobs,proto3\" json:\"need_call_barrier_after_jobs,omitempty\"`\n\tunknownFields            protoimpl.UnknownFields\n\tsizeCache                protoimpl.SizeCache\n}\n\nfunc (x *SubDAG) Reset() {\n\t*x = SubDAG{}\n\tmi := &file_api_subgraph_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SubDAG) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SubDAG) ProtoMessage() {}\n\nfunc (x *SubDAG) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_subgraph_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SubDAG.ProtoReflect.Descriptor instead.\nfunc (*SubDAG) Descriptor() ([]byte, []int) {\n\treturn file_api_subgraph_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *SubDAG) GetJobs() []*SubDAG_Job {\n\tif x != nil {\n\t\treturn x.Jobs\n\t}\n\treturn nil\n}\n\nfunc (x *SubDAG) GetNeedCallBarrierAfterJobs() bool {\n\tif x != nil {\n\t\treturn x.NeedCallBarrierAfterJobs\n\t}\n\treturn false\n}\n\ntype SchedulingPolicy struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tWorkerNum     int32                  `protobuf:\"varint,1,opt,name=worker_num,json=workerNum,proto3\" json:\"worker_num,omitempty\"`\n\tPipelines     []*Pipeline            `protobuf:\"bytes,2,rep,name=pipelines,proto3\" json:\"pipelines,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SchedulingPolicy) Reset() {\n\t*x = SchedulingPolicy{}\n\tmi := &file_api_subgraph_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SchedulingPolicy) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SchedulingPolicy) ProtoMessage() {}\n\nfunc (x *SchedulingPolicy) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_subgraph_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SchedulingPolicy.ProtoReflect.Descriptor instead.\nfunc (*SchedulingPolicy) Descriptor() ([]byte, []int) {\n\treturn file_api_subgraph_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *SchedulingPolicy) GetWorkerNum() int32 {\n\tif x != nil {\n\t\treturn x.WorkerNum\n\t}\n\treturn 0\n}\n\nfunc (x *SchedulingPolicy) GetPipelines() []*Pipeline {\n\tif x != nil {\n\t\treturn x.Pipelines\n\t}\n\treturn nil\n}\n\ntype Pipeline struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// maybe need batch size later\n\tBatched       bool      `protobuf:\"varint,1,opt,name=batched,proto3\" json:\"batched,omitempty\"`\n\tSubdags       []*SubDAG `protobuf:\"bytes,2,rep,name=subdags,proto3\" json:\"subdags,omitempty\"`\n\tInputs        []*Tensor `protobuf:\"bytes,3,rep,name=inputs,proto3\" json:\"inputs,omitempty\"`\n\tOutputs       []*Tensor `protobuf:\"bytes,4,rep,name=outputs,proto3\" json:\"outputs,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Pipeline) Reset() {\n\t*x = Pipeline{}\n\tmi := &file_api_subgraph_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Pipeline) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Pipeline) ProtoMessage() {}\n\nfunc (x *Pipeline) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_subgraph_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Pipeline.ProtoReflect.Descriptor instead.\nfunc (*Pipeline) Descriptor() ([]byte, []int) {\n\treturn file_api_subgraph_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *Pipeline) GetBatched() bool {\n\tif x != nil {\n\t\treturn x.Batched\n\t}\n\treturn false\n}\n\nfunc (x *Pipeline) GetSubdags() []*SubDAG {\n\tif x != nil {\n\t\treturn x.Subdags\n\t}\n\treturn nil\n}\n\nfunc (x *Pipeline) GetInputs() []*Tensor {\n\tif x != nil {\n\t\treturn x.Inputs\n\t}\n\treturn nil\n}\n\nfunc (x *Pipeline) GetOutputs() []*Tensor {\n\tif x != nil {\n\t\treturn x.Outputs\n\t}\n\treturn nil\n}\n\ntype SubDAG_Job struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tWorkerId      int32                  `protobuf:\"varint,1,opt,name=worker_id,json=workerId,proto3\" json:\"worker_id,omitempty\"`\n\tNodeIds       []string               `protobuf:\"bytes,2,rep,name=node_ids,json=nodeIds,proto3\" json:\"node_ids,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SubDAG_Job) Reset() {\n\t*x = SubDAG_Job{}\n\tmi := &file_api_subgraph_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SubDAG_Job) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SubDAG_Job) ProtoMessage() {}\n\nfunc (x *SubDAG_Job) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_subgraph_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SubDAG_Job.ProtoReflect.Descriptor instead.\nfunc (*SubDAG_Job) Descriptor() ([]byte, []int) {\n\treturn file_api_subgraph_proto_rawDescGZIP(), []int{1, 0}\n}\n\nfunc (x *SubDAG_Job) GetWorkerId() int32 {\n\tif x != nil {\n\t\treturn x.WorkerId\n\t}\n\treturn 0\n}\n\nfunc (x *SubDAG_Job) GetNodeIds() []string {\n\tif x != nil {\n\t\treturn x.NodeIds\n\t}\n\treturn nil\n}\n\nvar File_api_subgraph_proto protoreflect.FileDescriptor\n\nvar file_api_subgraph_proto_rawDesc = []byte{\n\t0x0a, 0x12, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x75, 0x62, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x1a, 0x0e, 0x61,\n\t0x70, 0x69, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xec, 0x01,\n\t0x0a, 0x08, 0x53, 0x75, 0x62, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x32, 0x0a, 0x05, 0x6e, 0x6f,\n\t0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x63, 0x71, 0x6c,\n\t0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x47, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x4e, 0x6f, 0x64,\n\t0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x31,\n\t0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,\n\t0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63,\n\t0x79, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x75, 0x62, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x63,\n\t0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x73,\n\t0x75, 0x62, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x1a,\n\t0x4b, 0x0a, 0x0a, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,\n\t0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,\n\t0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x4e, 0x6f, 0x64,\n\t0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xb0, 0x01, 0x0a,\n\t0x06, 0x53, 0x75, 0x62, 0x44, 0x41, 0x47, 0x12, 0x27, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18,\n\t0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e,\n\t0x53, 0x75, 0x62, 0x44, 0x41, 0x47, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73,\n\t0x12, 0x3e, 0x0a, 0x1c, 0x6e, 0x65, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x62, 0x61,\n\t0x72, 0x72, 0x69, 0x65, 0x72, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5f, 0x6a, 0x6f, 0x62, 0x73,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x6e, 0x65, 0x65, 0x64, 0x43, 0x61, 0x6c, 0x6c,\n\t0x42, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x41, 0x66, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x73,\n\t0x1a, 0x3d, 0x0a, 0x03, 0x4a, 0x6f, 0x62, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65,\n\t0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b,\n\t0x65, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x73,\n\t0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x73, 0x22,\n\t0x62, 0x0a, 0x10, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c,\n\t0x69, 0x63, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x6e, 0x75,\n\t0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4e,\n\t0x75, 0x6d, 0x12, 0x2f, 0x0a, 0x09, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18,\n\t0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e,\n\t0x50, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x52, 0x09, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69,\n\t0x6e, 0x65, 0x73, 0x22, 0xa3, 0x01, 0x0a, 0x08, 0x50, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65,\n\t0x12, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x08, 0x52, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x07, 0x73, 0x75,\n\t0x62, 0x64, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x63,\n\t0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x44, 0x41, 0x47, 0x52, 0x07, 0x73, 0x75,\n\t0x62, 0x64, 0x61, 0x67, 0x73, 0x12, 0x27, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18,\n\t0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e,\n\t0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x29,\n\t0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x0f, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72,\n\t0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x42, 0x10, 0x5a, 0x0e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x2d, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x63, 0x71, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_api_subgraph_proto_rawDescOnce sync.Once\n\tfile_api_subgraph_proto_rawDescData = file_api_subgraph_proto_rawDesc\n)\n\nfunc file_api_subgraph_proto_rawDescGZIP() []byte {\n\tfile_api_subgraph_proto_rawDescOnce.Do(func() {\n\t\tfile_api_subgraph_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_subgraph_proto_rawDescData)\n\t})\n\treturn file_api_subgraph_proto_rawDescData\n}\n\nvar file_api_subgraph_proto_msgTypes = make([]protoimpl.MessageInfo, 6)\nvar file_api_subgraph_proto_goTypes = []any{\n\t(*SubGraph)(nil),         // 0: scql.pb.SubGraph\n\t(*SubDAG)(nil),           // 1: scql.pb.SubDAG\n\t(*SchedulingPolicy)(nil), // 2: scql.pb.SchedulingPolicy\n\t(*Pipeline)(nil),         // 3: scql.pb.Pipeline\n\tnil,                      // 4: scql.pb.SubGraph.NodesEntry\n\t(*SubDAG_Job)(nil),       // 5: scql.pb.SubDAG.Job\n\t(*Tensor)(nil),           // 6: scql.pb.Tensor\n\t(*ExecNode)(nil),         // 7: scql.pb.ExecNode\n}\nvar file_api_subgraph_proto_depIdxs = []int32{\n\t4, // 0: scql.pb.SubGraph.nodes:type_name -> scql.pb.SubGraph.NodesEntry\n\t2, // 1: scql.pb.SubGraph.policy:type_name -> scql.pb.SchedulingPolicy\n\t5, // 2: scql.pb.SubDAG.jobs:type_name -> scql.pb.SubDAG.Job\n\t3, // 3: scql.pb.SchedulingPolicy.pipelines:type_name -> scql.pb.Pipeline\n\t1, // 4: scql.pb.Pipeline.subdags:type_name -> scql.pb.SubDAG\n\t6, // 5: scql.pb.Pipeline.inputs:type_name -> scql.pb.Tensor\n\t6, // 6: scql.pb.Pipeline.outputs:type_name -> scql.pb.Tensor\n\t7, // 7: scql.pb.SubGraph.NodesEntry.value:type_name -> scql.pb.ExecNode\n\t8, // [8:8] is the sub-list for method output_type\n\t8, // [8:8] is the sub-list for method input_type\n\t8, // [8:8] is the sub-list for extension type_name\n\t8, // [8:8] is the sub-list for extension extendee\n\t0, // [0:8] is the sub-list for field type_name\n}\n\nfunc init() { file_api_subgraph_proto_init() }\nfunc file_api_subgraph_proto_init() {\n\tif File_api_subgraph_proto != nil {\n\t\treturn\n\t}\n\tfile_api_core_proto_init()\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_api_subgraph_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   6,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_api_subgraph_proto_goTypes,\n\t\tDependencyIndexes: file_api_subgraph_proto_depIdxs,\n\t\tMessageInfos:      file_api_subgraph_proto_msgTypes,\n\t}.Build()\n\tFile_api_subgraph_proto = out.File\n\tfile_api_subgraph_proto_rawDesc = nil\n\tfile_api_subgraph_proto_goTypes = nil\n\tfile_api_subgraph_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/proto-gen/scql/v1alpha1/compiler.pb.go",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.3\n// \tprotoc        v5.27.3\n// source: api/v1alpha1/compiler.proto\n\npackage v1alpha1\n\nimport (\n\tcontext \"context\"\n\tscql \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tspu \"github.com/secretflow/scql/pkg/proto-gen/spu\"\n\t_ \"google.golang.org/genproto/googleapis/api\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tanypb \"google.golang.org/protobuf/types/known/anypb\"\n\ttimestamppb \"google.golang.org/protobuf/types/known/timestamppb\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype CompileOptions struct {\n\tstate   protoimpl.MessageState `protogen:\"open.v1\"`\n\tSpuConf *spu.RuntimeConfig     `protobuf:\"bytes,1,opt,name=spu_conf,json=spuConf,proto3\" json:\"spu_conf,omitempty\"`\n\t// Whether to run in streaming mode\n\tBatched bool `protobuf:\"varint,2,opt,name=batched,proto3\" json:\"batched,omitempty\"`\n\t// The PSI algorithm type to use\n\t// Default is auto, which means choosing PSI type by engine\n\tPsiAlgorithmType scql.PsiAlgorithmType `protobuf:\"varint,3,opt,name=psi_algorithm_type,json=psiAlgorithmType,proto3,enum=scql.pb.PsiAlgorithmType\" json:\"psi_algorithm_type,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *CompileOptions) Reset() {\n\t*x = CompileOptions{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CompileOptions) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CompileOptions) ProtoMessage() {}\n\nfunc (x *CompileOptions) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CompileOptions.ProtoReflect.Descriptor instead.\nfunc (*CompileOptions) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *CompileOptions) GetSpuConf() *spu.RuntimeConfig {\n\tif x != nil {\n\t\treturn x.SpuConf\n\t}\n\treturn nil\n}\n\nfunc (x *CompileOptions) GetBatched() bool {\n\tif x != nil {\n\t\treturn x.Batched\n\t}\n\treturn false\n}\n\nfunc (x *CompileOptions) GetPsiAlgorithmType() scql.PsiAlgorithmType {\n\tif x != nil {\n\t\treturn x.PsiAlgorithmType\n\t}\n\treturn scql.PsiAlgorithmType(0)\n}\n\ntype GlobalSecurityRelaxation struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The number of elements in each group can be revealed\n\tRevealGroupCount bool `protobuf:\"varint,1,opt,name=reveal_group_count,json=revealGroupCount,proto3\" json:\"reveal_group_count,omitempty\"`\n\t// The group mark can be revealed\n\tRevealGroupMark bool `protobuf:\"varint,2,opt,name=reveal_group_mark,json=revealGroupMark,proto3\" json:\"reveal_group_mark,omitempty\"`\n\t// Tensors can be revealed when used as join key\n\t// e.g.: \"select ta.c1, ta.c2, tb.c2 from ta join tb on ta.c1 = tb.c1\", here ta.c1 and tb.c2 are join keys\n\t// \"after join\", we get the \"intersection of ta.c1 and tb.c1\", which can be revealed\n\t// Note that only the intersection of join keys(this is what \"after join\" means) can be revealed\n\t// So in left outer join, only the right join key can be revealed, because left join key will contains values not exits in the intersection after join\n\tRevealKeyAfterJoin bool `protobuf:\"varint,10,opt,name=reveal_key_after_join,json=revealKeyAfterJoin,proto3\" json:\"reveal_key_after_join,omitempty\"`\n\t// Tensors can be revealed when used as filter mask\n\t// This security relaxation also requires the filter mask is result of a comparison,\n\t// e.g.: \"select ta.c1 from ta join tb on ta.c2 = tb.c2 where tb.c1 > ta.c3\", here tb.c1 > ta.c3 is the comparison\n\t// So result of tb.c1 > ta.c3 can be revealed and used as a filter mask\n\tRevealFilterMask bool `protobuf:\"varint,11,opt,name=reveal_filter_mask,json=revealFilterMask,proto3\" json:\"reveal_filter_mask,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *GlobalSecurityRelaxation) Reset() {\n\t*x = GlobalSecurityRelaxation{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *GlobalSecurityRelaxation) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GlobalSecurityRelaxation) ProtoMessage() {}\n\nfunc (x *GlobalSecurityRelaxation) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GlobalSecurityRelaxation.ProtoReflect.Descriptor instead.\nfunc (*GlobalSecurityRelaxation) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *GlobalSecurityRelaxation) GetRevealGroupCount() bool {\n\tif x != nil {\n\t\treturn x.RevealGroupCount\n\t}\n\treturn false\n}\n\nfunc (x *GlobalSecurityRelaxation) GetRevealGroupMark() bool {\n\tif x != nil {\n\t\treturn x.RevealGroupMark\n\t}\n\treturn false\n}\n\nfunc (x *GlobalSecurityRelaxation) GetRevealKeyAfterJoin() bool {\n\tif x != nil {\n\t\treturn x.RevealKeyAfterJoin\n\t}\n\treturn false\n}\n\nfunc (x *GlobalSecurityRelaxation) GetRevealFilterMask() bool {\n\tif x != nil {\n\t\treturn x.RevealFilterMask\n\t}\n\treturn false\n}\n\ntype ColumnSecurityRelaxation struct {\n\tstate    protoimpl.MessageState `protogen:\"open.v1\"`\n\tDatabase string                 `protobuf:\"bytes,1,opt,name=database,proto3\" json:\"database,omitempty\"`\n\tTable    string                 `protobuf:\"bytes,2,opt,name=table,proto3\" json:\"table,omitempty\"`\n\tColumn   string                 `protobuf:\"bytes,3,opt,name=column,proto3\" json:\"column,omitempty\"`\n\t// Corresponding tensor can be revealed when used as join key\n\tRevealKeyAfterJoin bool `protobuf:\"varint,10,opt,name=reveal_key_after_join,json=revealKeyAfterJoin,proto3\" json:\"reveal_key_after_join,omitempty\"`\n\t// Corresponding tensor can be revealed when used as filter mask\n\tRevealFilterMask bool `protobuf:\"varint,11,opt,name=reveal_filter_mask,json=revealFilterMask,proto3\" json:\"reveal_filter_mask,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *ColumnSecurityRelaxation) Reset() {\n\t*x = ColumnSecurityRelaxation{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ColumnSecurityRelaxation) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ColumnSecurityRelaxation) ProtoMessage() {}\n\nfunc (x *ColumnSecurityRelaxation) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ColumnSecurityRelaxation.ProtoReflect.Descriptor instead.\nfunc (*ColumnSecurityRelaxation) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ColumnSecurityRelaxation) GetDatabase() string {\n\tif x != nil {\n\t\treturn x.Database\n\t}\n\treturn \"\"\n}\n\nfunc (x *ColumnSecurityRelaxation) GetTable() string {\n\tif x != nil {\n\t\treturn x.Table\n\t}\n\treturn \"\"\n}\n\nfunc (x *ColumnSecurityRelaxation) GetColumn() string {\n\tif x != nil {\n\t\treturn x.Column\n\t}\n\treturn \"\"\n}\n\nfunc (x *ColumnSecurityRelaxation) GetRevealKeyAfterJoin() bool {\n\tif x != nil {\n\t\treturn x.RevealKeyAfterJoin\n\t}\n\treturn false\n}\n\nfunc (x *ColumnSecurityRelaxation) GetRevealFilterMask() bool {\n\tif x != nil {\n\t\treturn x.RevealFilterMask\n\t}\n\treturn false\n}\n\ntype ReverseInferenceConfig struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Whether to enable reverse inference\n\tEnableReverseInference bool `protobuf:\"varint,1,opt,name=enable_reverse_inference,json=enableReverseInference,proto3\" json:\"enable_reverse_inference,omitempty\"`\n\tunknownFields          protoimpl.UnknownFields\n\tsizeCache              protoimpl.SizeCache\n}\n\nfunc (x *ReverseInferenceConfig) Reset() {\n\t*x = ReverseInferenceConfig{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ReverseInferenceConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReverseInferenceConfig) ProtoMessage() {}\n\nfunc (x *ReverseInferenceConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ReverseInferenceConfig.ProtoReflect.Descriptor instead.\nfunc (*ReverseInferenceConfig) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *ReverseInferenceConfig) GetEnableReverseInference() bool {\n\tif x != nil {\n\t\treturn x.EnableReverseInference\n\t}\n\treturn false\n}\n\n// Security config that may affect the query result\ntype ResultSecurityConfig struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The threshold for group by operation\n\t// If the number of elements in a group is less than this threshold, the group will be filtered\n\tGroupbyThreshold int64 `protobuf:\"varint,1,opt,name=groupby_threshold,json=groupbyThreshold,proto3\" json:\"groupby_threshold,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *ResultSecurityConfig) Reset() {\n\t*x = ResultSecurityConfig{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ResultSecurityConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ResultSecurityConfig) ProtoMessage() {}\n\nfunc (x *ResultSecurityConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ResultSecurityConfig.ProtoReflect.Descriptor instead.\nfunc (*ResultSecurityConfig) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *ResultSecurityConfig) GetGroupbyThreshold() int64 {\n\tif x != nil {\n\t\treturn x.GroupbyThreshold\n\t}\n\treturn 0\n}\n\ntype CompilerSecurityConfig struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Global security config\n\tGlobalRelaxation *GlobalSecurityRelaxation `protobuf:\"bytes,1,opt,name=global_relaxation,json=globalRelaxation,proto3\" json:\"global_relaxation,omitempty\"`\n\t// Security relaxation that attaches to columns\n\t// Not every tensor in the OperatorGraph has a ColumnSecurityRelaxation:\n\t//  1. Users do not need to specify ColumnSecurityRelaxation for every column used in the query,\n\t//     the missing ones will just be default value false.\n\t//  2. Some tensors are in the OperatorGraph are the result of relation operations or expressions,\n\t//     the security relaxation properties of these tensors can be inferred from their inputs' security relaxation properties.\n\tColumnRelaxationList []*ColumnSecurityRelaxation `protobuf:\"bytes,2,rep,name=column_relaxation_list,json=columnRelaxationList,proto3\" json:\"column_relaxation_list,omitempty\"`\n\t// Config related to reverse inference\n\tReverseInferenceConf *ReverseInferenceConfig `protobuf:\"bytes,3,opt,name=reverse_inference_conf,json=reverseInferenceConf,proto3\" json:\"reverse_inference_conf,omitempty\"`\n\t// User-specified visibility of columns\n\t// Used to get the initial visibility of input tensors\n\t// If a column's visibility is not specified, the visible party of corresponding tensor will be {column's owner}\n\t// If specified, the visible party of corresponding tensor will be the union of {column's owner} and the specified visible parties\n\tColumnVisibilityList []*ColumnVisibility `protobuf:\"bytes,4,rep,name=column_visibility_list,json=columnVisibilityList,proto3\" json:\"column_visibility_list,omitempty\"`\n\t// Config that may affect the query result\n\tResultSecurityConf *ResultSecurityConfig `protobuf:\"bytes,5,opt,name=result_security_conf,json=resultSecurityConf,proto3\" json:\"result_security_conf,omitempty\"`\n\tunknownFields      protoimpl.UnknownFields\n\tsizeCache          protoimpl.SizeCache\n}\n\nfunc (x *CompilerSecurityConfig) Reset() {\n\t*x = CompilerSecurityConfig{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CompilerSecurityConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CompilerSecurityConfig) ProtoMessage() {}\n\nfunc (x *CompilerSecurityConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CompilerSecurityConfig.ProtoReflect.Descriptor instead.\nfunc (*CompilerSecurityConfig) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *CompilerSecurityConfig) GetGlobalRelaxation() *GlobalSecurityRelaxation {\n\tif x != nil {\n\t\treturn x.GlobalRelaxation\n\t}\n\treturn nil\n}\n\nfunc (x *CompilerSecurityConfig) GetColumnRelaxationList() []*ColumnSecurityRelaxation {\n\tif x != nil {\n\t\treturn x.ColumnRelaxationList\n\t}\n\treturn nil\n}\n\nfunc (x *CompilerSecurityConfig) GetReverseInferenceConf() *ReverseInferenceConfig {\n\tif x != nil {\n\t\treturn x.ReverseInferenceConf\n\t}\n\treturn nil\n}\n\nfunc (x *CompilerSecurityConfig) GetColumnVisibilityList() []*ColumnVisibility {\n\tif x != nil {\n\t\treturn x.ColumnVisibilityList\n\t}\n\treturn nil\n}\n\nfunc (x *CompilerSecurityConfig) GetResultSecurityConf() *ResultSecurityConfig {\n\tif x != nil {\n\t\treturn x.ResultSecurityConf\n\t}\n\treturn nil\n}\n\ntype ColumnVisibility struct {\n\tstate    protoimpl.MessageState `protogen:\"open.v1\"`\n\tDatabase string                 `protobuf:\"bytes,1,opt,name=database,proto3\" json:\"database,omitempty\"`\n\tTable    string                 `protobuf:\"bytes,2,opt,name=table,proto3\" json:\"table,omitempty\"`\n\tColumn   string                 `protobuf:\"bytes,3,opt,name=column,proto3\" json:\"column,omitempty\"`\n\t// The parties that the tensor need to be visible to\n\tVisibleParties []*scql.PartyId `protobuf:\"bytes,4,rep,name=visible_parties,json=visibleParties,proto3\" json:\"visible_parties,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *ColumnVisibility) Reset() {\n\t*x = ColumnVisibility{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ColumnVisibility) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ColumnVisibility) ProtoMessage() {}\n\nfunc (x *ColumnVisibility) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ColumnVisibility.ProtoReflect.Descriptor instead.\nfunc (*ColumnVisibility) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *ColumnVisibility) GetDatabase() string {\n\tif x != nil {\n\t\treturn x.Database\n\t}\n\treturn \"\"\n}\n\nfunc (x *ColumnVisibility) GetTable() string {\n\tif x != nil {\n\t\treturn x.Table\n\t}\n\treturn \"\"\n}\n\nfunc (x *ColumnVisibility) GetColumn() string {\n\tif x != nil {\n\t\treturn x.Column\n\t}\n\treturn \"\"\n}\n\nfunc (x *ColumnVisibility) GetVisibleParties() []*scql.PartyId {\n\tif x != nil {\n\t\treturn x.VisibleParties\n\t}\n\treturn nil\n}\n\ntype AdditionalInfoSpec struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// If true, OperatorGraph will be provided in the response\n\tNeedOperatorGraph bool `protobuf:\"varint,1,opt,name=need_operator_graph,json=needOperatorGraph,proto3\" json:\"need_operator_graph,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *AdditionalInfoSpec) Reset() {\n\t*x = AdditionalInfoSpec{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AdditionalInfoSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AdditionalInfoSpec) ProtoMessage() {}\n\nfunc (x *AdditionalInfoSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AdditionalInfoSpec.ProtoReflect.Descriptor instead.\nfunc (*AdditionalInfoSpec) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *AdditionalInfoSpec) GetNeedOperatorGraph() bool {\n\tif x != nil {\n\t\treturn x.NeedOperatorGraph\n\t}\n\treturn false\n}\n\ntype CompileSQLRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The SQL query to compile\n\tQuery string `protobuf:\"bytes,1,opt,name=query,proto3\" json:\"query,omitempty\"`\n\t// The database name\n\tDb string `protobuf:\"bytes,2,opt,name=db,proto3\" json:\"db,omitempty\"`\n\t// The issuer of the query\n\tIssuer *scql.PartyId `protobuf:\"bytes,3,opt,name=issuer,proto3\" json:\"issuer,omitempty\"`\n\t// The catalog of the database\n\tCatalog *scql.Catalog `protobuf:\"bytes,4,opt,name=catalog,proto3\" json:\"catalog,omitempty\"`\n\t// The compile options\n\tCompileOpts *CompileOptions `protobuf:\"bytes,5,opt,name=compile_opts,json=compileOpts,proto3\" json:\"compile_opts,omitempty\"`\n\t// The issue time of the query, used for functions like now()\n\tIssueTime *timestamppb.Timestamp `protobuf:\"bytes,6,opt,name=issue_time,json=issueTime,proto3\" json:\"issue_time,omitempty\"`\n\t// Contains the config related to data security\n\tSecurityConfig *CompilerSecurityConfig `protobuf:\"bytes,7,opt,name=security_config,json=securityConfig,proto3\" json:\"security_config,omitempty\"`\n\t// Placeholders used by rule\n\tPlaceholders *scql.Placeholders `protobuf:\"bytes,8,opt,name=placeholders,proto3\" json:\"placeholders,omitempty\"`\n\t// Variables used by rule\n\tVariables []*scql.Variable `protobuf:\"bytes,9,rep,name=variables,proto3\" json:\"variables,omitempty\"`\n\t// Specifies what and how additional information are provided in the response\n\tAdditionalInfo *AdditionalInfoSpec `protobuf:\"bytes,10,opt,name=additional_info,json=additionalInfo,proto3\" json:\"additional_info,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *CompileSQLRequest) Reset() {\n\t*x = CompileSQLRequest{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CompileSQLRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CompileSQLRequest) ProtoMessage() {}\n\nfunc (x *CompileSQLRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CompileSQLRequest.ProtoReflect.Descriptor instead.\nfunc (*CompileSQLRequest) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *CompileSQLRequest) GetQuery() string {\n\tif x != nil {\n\t\treturn x.Query\n\t}\n\treturn \"\"\n}\n\nfunc (x *CompileSQLRequest) GetDb() string {\n\tif x != nil {\n\t\treturn x.Db\n\t}\n\treturn \"\"\n}\n\nfunc (x *CompileSQLRequest) GetIssuer() *scql.PartyId {\n\tif x != nil {\n\t\treturn x.Issuer\n\t}\n\treturn nil\n}\n\nfunc (x *CompileSQLRequest) GetCatalog() *scql.Catalog {\n\tif x != nil {\n\t\treturn x.Catalog\n\t}\n\treturn nil\n}\n\nfunc (x *CompileSQLRequest) GetCompileOpts() *CompileOptions {\n\tif x != nil {\n\t\treturn x.CompileOpts\n\t}\n\treturn nil\n}\n\nfunc (x *CompileSQLRequest) GetIssueTime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.IssueTime\n\t}\n\treturn nil\n}\n\nfunc (x *CompileSQLRequest) GetSecurityConfig() *CompilerSecurityConfig {\n\tif x != nil {\n\t\treturn x.SecurityConfig\n\t}\n\treturn nil\n}\n\nfunc (x *CompileSQLRequest) GetPlaceholders() *scql.Placeholders {\n\tif x != nil {\n\t\treturn x.Placeholders\n\t}\n\treturn nil\n}\n\nfunc (x *CompileSQLRequest) GetVariables() []*scql.Variable {\n\tif x != nil {\n\t\treturn x.Variables\n\t}\n\treturn nil\n}\n\nfunc (x *CompileSQLRequest) GetAdditionalInfo() *AdditionalInfoSpec {\n\tif x != nil {\n\t\treturn x.AdditionalInfo\n\t}\n\treturn nil\n}\n\ntype CompileSQLResponse struct {\n\tstate  protoimpl.MessageState `protogen:\"open.v1\"`\n\tStatus *scql.Status           `protobuf:\"bytes,1,opt,name=status,proto3\" json:\"status,omitempty\"`\n\t// The query execution plan required by the engine\n\tExecutionPlan *scql.CompiledPlan `protobuf:\"bytes,2,opt,name=execution_plan,json=executionPlan,proto3\" json:\"execution_plan,omitempty\"`\n\t// OperatorGraph is provides when additional_info.need_operator_graph is true\n\tOperatorGraph *OperatorGraph `protobuf:\"bytes,3,opt,name=operator_graph,json=operatorGraph,proto3\" json:\"operator_graph,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CompileSQLResponse) Reset() {\n\t*x = CompileSQLResponse{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CompileSQLResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CompileSQLResponse) ProtoMessage() {}\n\nfunc (x *CompileSQLResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CompileSQLResponse.ProtoReflect.Descriptor instead.\nfunc (*CompileSQLResponse) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *CompileSQLResponse) GetStatus() *scql.Status {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\nfunc (x *CompileSQLResponse) GetExecutionPlan() *scql.CompiledPlan {\n\tif x != nil {\n\t\treturn x.ExecutionPlan\n\t}\n\treturn nil\n}\n\nfunc (x *CompileSQLResponse) GetOperatorGraph() *OperatorGraph {\n\tif x != nil {\n\t\treturn x.OperatorGraph\n\t}\n\treturn nil\n}\n\ntype OperatorGraph struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The version of the OperatorGraph, needed for compatibility check\n\tVersion string `protobuf:\"bytes,1,opt,name=version,proto3\" json:\"version,omitempty\"`\n\t// The operator nodes in the OperatorGraph\n\tOperators []*Operator `protobuf:\"bytes,2,rep,name=operators,proto3\" json:\"operators,omitempty\"`\n\t// The tensor metadata catalog for the entire plan\n\tTensors       []*TensorMeta `protobuf:\"bytes,3,rep,name=tensors,proto3\" json:\"tensors,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *OperatorGraph) Reset() {\n\t*x = OperatorGraph{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *OperatorGraph) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OperatorGraph) ProtoMessage() {}\n\nfunc (x *OperatorGraph) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OperatorGraph.ProtoReflect.Descriptor instead.\nfunc (*OperatorGraph) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *OperatorGraph) GetVersion() string {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn \"\"\n}\n\nfunc (x *OperatorGraph) GetOperators() []*Operator {\n\tif x != nil {\n\t\treturn x.Operators\n\t}\n\treturn nil\n}\n\nfunc (x *OperatorGraph) GetTensors() []*TensorMeta {\n\tif x != nil {\n\t\treturn x.Tensors\n\t}\n\treturn nil\n}\n\n// Tensor metadata for the OperatorGraph\ntype TensorMeta struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Tensor id\n\tId int32 `protobuf:\"varint,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\t// Tensor name\n\tName string `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// The element type of the tensor\n\tElemType      scql.PrimitiveDataType `protobuf:\"varint,3,opt,name=elem_type,json=elemType,proto3,enum=scql.pb.PrimitiveDataType\" json:\"elem_type,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TensorMeta) Reset() {\n\t*x = TensorMeta{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TensorMeta) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TensorMeta) ProtoMessage() {}\n\nfunc (x *TensorMeta) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TensorMeta.ProtoReflect.Descriptor instead.\nfunc (*TensorMeta) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *TensorMeta) GetId() int32 {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn 0\n}\n\nfunc (x *TensorMeta) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *TensorMeta) GetElemType() scql.PrimitiveDataType {\n\tif x != nil {\n\t\treturn x.ElemType\n\t}\n\treturn scql.PrimitiveDataType(0)\n}\n\n// A list of tensor IDs for referencing tensors by ID\ntype TensorIdList struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tIds           []int32                `protobuf:\"varint,1,rep,packed,name=ids,proto3\" json:\"ids,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TensorIdList) Reset() {\n\t*x = TensorIdList{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[12]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TensorIdList) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TensorIdList) ProtoMessage() {}\n\nfunc (x *TensorIdList) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[12]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TensorIdList.ProtoReflect.Descriptor instead.\nfunc (*TensorIdList) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *TensorIdList) GetIds() []int32 {\n\tif x != nil {\n\t\treturn x.Ids\n\t}\n\treturn nil\n}\n\n// (-- api-linter: core::0123::resource-annotation=disabled\ntype Operator struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Operator id in the corresponding OperatorGraph\n\tId string `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\t// Operator name\n\tName string `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// Operator type, such as \"Limit\", \"Filter\", \"GroupAgg\"\n\tType string `protobuf:\"bytes,3,opt,name=type,proto3\" json:\"type,omitempty\"`\n\t// Inputs of the operator, the key stands for the role of corresponding tensors, such as \"payload\", \"mask\", \"leftKeys\"\n\t// Each entry maps to a list of tensor IDs that can be resolved from OperatorGraph.tensors\n\tInputs map[string]*TensorIdList `protobuf:\"bytes,4,rep,name=inputs,proto3\" json:\"inputs,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\t// Outputs of the operator, the key stands for the role of corresponding tensors, such as \"rank\", \"leftOutputs\"\n\t// Each entry maps to a list of tensor IDs that can be resolved from OperatorGraph.tensors\n\tOutputs map[string]*TensorIdList `protobuf:\"bytes,5,rep,name=outputs,proto3\" json:\"outputs,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\t// Attributes of the operator\n\tAttributes map[string]*anypb.Any `protobuf:\"bytes,6,rep,name=attributes,proto3\" json:\"attributes,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\t// The kernel represents the concrete mechanism used to implement the functionality of this Operator\n\t// Each query has a deterministic OperatorGraph structure.\n\t// As long as the query remains unchanged, the types and arrangement of Operators in the plan will remain constant.\n\t// However, the type of Kernel corresponding to each Operator may vary with changes in the SecurityConfig.\n\tKernel        *Kernel `protobuf:\"bytes,7,opt,name=kernel,proto3\" json:\"kernel,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Operator) Reset() {\n\t*x = Operator{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[13]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Operator) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Operator) ProtoMessage() {}\n\nfunc (x *Operator) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[13]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Operator.ProtoReflect.Descriptor instead.\nfunc (*Operator) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{13}\n}\n\nfunc (x *Operator) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\nfunc (x *Operator) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Operator) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\nfunc (x *Operator) GetInputs() map[string]*TensorIdList {\n\tif x != nil {\n\t\treturn x.Inputs\n\t}\n\treturn nil\n}\n\nfunc (x *Operator) GetOutputs() map[string]*TensorIdList {\n\tif x != nil {\n\t\treturn x.Outputs\n\t}\n\treturn nil\n}\n\nfunc (x *Operator) GetAttributes() map[string]*anypb.Any {\n\tif x != nil {\n\t\treturn x.Attributes\n\t}\n\treturn nil\n}\n\nfunc (x *Operator) GetKernel() *Kernel {\n\tif x != nil {\n\t\treturn x.Kernel\n\t}\n\treturn nil\n}\n\n// (-- api-linter: core::0123::resource-annotation=disabled\ntype Kernel struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The name of the kernel\n\t// e.g. for GroupAgg, kernel name maybe \"oblivious_group_agg\", \"private_group_agg\"\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// The cost of the kernel for optimization purposes\n\t// Note that comparing Cost values is only meaningful when the original Operator is identical\n\t// range: [0, 1]\n\tCost          float64 `protobuf:\"fixed64,2,opt,name=cost,proto3\" json:\"cost,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Kernel) Reset() {\n\t*x = Kernel{}\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[14]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Kernel) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Kernel) ProtoMessage() {}\n\nfunc (x *Kernel) ProtoReflect() protoreflect.Message {\n\tmi := &file_api_v1alpha1_compiler_proto_msgTypes[14]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Kernel.ProtoReflect.Descriptor instead.\nfunc (*Kernel) Descriptor() ([]byte, []int) {\n\treturn file_api_v1alpha1_compiler_proto_rawDescGZIP(), []int{14}\n}\n\nfunc (x *Kernel) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Kernel) GetCost() float64 {\n\tif x != nil {\n\t\treturn x.Cost\n\t}\n\treturn 0\n}\n\nvar File_api_v1alpha1_compiler_proto protoreflect.FileDescriptor\n\nvar file_api_v1alpha1_compiler_proto_rawDesc = []byte{\n\t0x0a, 0x1b, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x63,\n\t0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x73,\n\t0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x1a,\n\t0x0e, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,\n\t0x10, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x1a, 0x10, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x61, 0x70, 0x69, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72,\n\t0x65, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x6c, 0x69, 0x62, 0x73,\n\t0x70, 0x75, 0x2f, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f,\n\t0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69,\n\t0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67,\n\t0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61,\n\t0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,\n\t0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61,\n\t0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f,\n\t0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb4, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70,\n\t0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x70,\n\t0x75, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73,\n\t0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x07, 0x73, 0x70, 0x75, 0x43, 0x6f, 0x6e,\n\t0x66, 0x12, 0x1d, 0x0a, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x08, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x07, 0x62, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64,\n\t0x12, 0x4c, 0x0a, 0x12, 0x70, 0x73, 0x69, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68,\n\t0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x73,\n\t0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x73, 0x69, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69,\n\t0x74, 0x68, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10, 0x70, 0x73,\n\t0x69, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x22, 0xef,\n\t0x01, 0x0a, 0x18, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,\n\t0x79, 0x52, 0x65, 0x6c, 0x61, 0x78, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x12, 0x72,\n\t0x65, 0x76, 0x65, 0x61, 0x6c, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x63, 0x6f, 0x75, 0x6e,\n\t0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10, 0x72, 0x65,\n\t0x76, 0x65, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2f,\n\t0x0a, 0x11, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d,\n\t0x61, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x0f,\n\t0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x61, 0x72, 0x6b, 0x12,\n\t0x36, 0x0a, 0x15, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x66,\n\t0x74, 0x65, 0x72, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x42, 0x03,\n\t0xe0, 0x41, 0x01, 0x52, 0x12, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x41, 0x66,\n\t0x74, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x31, 0x0a, 0x12, 0x72, 0x65, 0x76, 0x65, 0x61,\n\t0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x0b, 0x20,\n\t0x01, 0x28, 0x08, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c,\n\t0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x73, 0x6b, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x0a,\n\t0x22, 0xe4, 0x01, 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x53, 0x65, 0x63, 0x75, 0x72,\n\t0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x78, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a,\n\t0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,\n\t0x03, 0xe0, 0x41, 0x02, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x19,\n\t0x0a, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0,\n\t0x41, 0x02, 0x52, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x63, 0x6f, 0x6c,\n\t0x75, 0x6d, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06,\n\t0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x36, 0x0a, 0x15, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c,\n\t0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x18,\n\t0x0a, 0x20, 0x01, 0x28, 0x08, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x12, 0x72, 0x65, 0x76, 0x65,\n\t0x61, 0x6c, 0x4b, 0x65, 0x79, 0x41, 0x66, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x31,\n\t0x0a, 0x12, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f,\n\t0x6d, 0x61, 0x73, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52,\n\t0x10, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4d, 0x61, 0x73,\n\t0x6b, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x0a, 0x22, 0x57, 0x0a, 0x16, 0x52, 0x65, 0x76, 0x65, 0x72,\n\t0x73, 0x65, 0x49, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x12, 0x3d, 0x0a, 0x18, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x76, 0x65,\n\t0x72, 0x73, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x08, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x16, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,\n\t0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x49, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,\n\t0x22, 0x48, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69,\n\t0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a, 0x11, 0x67, 0x72, 0x6f, 0x75,\n\t0x70, 0x62, 0x79, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x03, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x62,\n\t0x79, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x80, 0x04, 0x0a, 0x16, 0x43,\n\t0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5c, 0x0a, 0x11, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f,\n\t0x72, 0x65, 0x6c, 0x61, 0x78, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x2a, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70,\n\t0x68, 0x61, 0x31, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69,\n\t0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x78, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x03, 0xe0, 0x41,\n\t0x02, 0x52, 0x10, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x65, 0x6c, 0x61, 0x78, 0x61, 0x74,\n\t0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x16, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x72, 0x65,\n\t0x6c, 0x61, 0x78, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31,\n\t0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x53, 0x65, 0x63,\n\t0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x6c, 0x61, 0x78, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42,\n\t0x03, 0xe0, 0x41, 0x01, 0x52, 0x14, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x65, 0x6c, 0x61,\n\t0x78, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x63, 0x0a, 0x16, 0x72, 0x65,\n\t0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f,\n\t0x63, 0x6f, 0x6e, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x63, 0x71,\n\t0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x52, 0x65,\n\t0x76, 0x65, 0x72, 0x73, 0x65, 0x49, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x14, 0x72, 0x65, 0x76, 0x65, 0x72,\n\t0x73, 0x65, 0x49, 0x6e, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x12,\n\t0x5d, 0x0a, 0x16, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69,\n\t0x6c, 0x69, 0x74, 0x79, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x22, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68,\n\t0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c,\n\t0x69, 0x74, 0x79, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x14, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e,\n\t0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x5d,\n\t0x0a, 0x14, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,\n\t0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73,\n\t0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e,\n\t0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x12, 0x72, 0x65, 0x73, 0x75, 0x6c,\n\t0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x22, 0xab, 0x01,\n\t0x0a, 0x10, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69,\n\t0x74, 0x79, 0x12, 0x1f, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62,\n\t0x61, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x05, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1b,\n\t0x0a, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03,\n\t0xe0, 0x41, 0x02, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x3e, 0x0a, 0x0f, 0x76,\n\t0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x04,\n\t0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50,\n\t0x61, 0x72, 0x74, 0x79, 0x49, 0x64, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0e, 0x76, 0x69, 0x73,\n\t0x69, 0x62, 0x6c, 0x65, 0x50, 0x61, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x49, 0x0a, 0x12, 0x41,\n\t0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x70, 0x65,\n\t0x63, 0x12, 0x33, 0x0a, 0x13, 0x6e, 0x65, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,\n\t0x6f, 0x72, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x42, 0x03,\n\t0xe0, 0x41, 0x01, 0x52, 0x11, 0x6e, 0x65, 0x65, 0x64, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f,\n\t0x72, 0x47, 0x72, 0x61, 0x70, 0x68, 0x22, 0xcf, 0x04, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x69,\n\t0x6c, 0x65, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x05,\n\t0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02,\n\t0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x13, 0x0a, 0x02, 0x64, 0x62, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x02, 0x64, 0x62, 0x12, 0x2d, 0x0a, 0x06,\n\t0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73,\n\t0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x79, 0x49, 0x64, 0x42, 0x03,\n\t0xe0, 0x41, 0x02, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x07, 0x63,\n\t0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73,\n\t0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x42, 0x03,\n\t0xe0, 0x41, 0x02, 0x52, 0x07, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x12, 0x48, 0x0a, 0x0c,\n\t0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61,\n\t0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74,\n\t0x69, 0x6f, 0x6e, 0x73, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x69,\n\t0x6c, 0x65, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x3e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f,\n\t0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,\n\t0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,\n\t0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x09, 0x69, 0x73, 0x73,\n\t0x75, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x56, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69,\n\t0x74, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x28, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68,\n\t0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x63, 0x75, 0x72,\n\t0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0e,\n\t0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3e,\n\t0x0a, 0x0c, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, 0x08,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50,\n\t0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x42, 0x03, 0xe0, 0x41, 0x01,\n\t0x52, 0x0c, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x12, 0x34,\n\t0x0a, 0x09, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x11, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x56, 0x61, 0x72, 0x69,\n\t0x61, 0x62, 0x6c, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x09, 0x76, 0x61, 0x72, 0x69, 0x61,\n\t0x62, 0x6c, 0x65, 0x73, 0x12, 0x52, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,\n\t0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e,\n\t0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,\n\t0x2e, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x53,\n\t0x70, 0x65, 0x63, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69,\n\t0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xd2, 0x01, 0x0a, 0x12, 0x43, 0x6f, 0x6d,\n\t0x70, 0x69, 0x6c, 0x65, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,\n\t0x2c, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x0f, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,\n\t0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x41, 0x0a,\n\t0x0e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x18,\n\t0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e,\n\t0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x50, 0x6c, 0x61, 0x6e, 0x42, 0x03, 0xe0, 0x41,\n\t0x02, 0x52, 0x0d, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6c, 0x61, 0x6e,\n\t0x12, 0x4b, 0x0a, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x67, 0x72, 0x61,\n\t0x70, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e,\n\t0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72,\n\t0x61, 0x74, 0x6f, 0x72, 0x47, 0x72, 0x61, 0x70, 0x68, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x0d,\n\t0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x47, 0x72, 0x61, 0x70, 0x68, 0x22, 0xaa, 0x01,\n\t0x0a, 0x0d, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12,\n\t0x1d, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3d,\n\t0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,\n\t0x0b, 0x32, 0x1a, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c,\n\t0x70, 0x68, 0x61, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x42, 0x03, 0xe0,\n\t0x41, 0x02, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x3b, 0x0a,\n\t0x07, 0x74, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c,\n\t0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,\n\t0x31, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x42, 0x03, 0xe0, 0x41,\n\t0x02, 0x52, 0x07, 0x74, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x73, 0x22, 0x78, 0x0a, 0x0a, 0x54, 0x65,\n\t0x6e, 0x73, 0x6f, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x05, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a,\n\t0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02,\n\t0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x65, 0x6c, 0x65, 0x6d, 0x5f, 0x74,\n\t0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x73, 0x63, 0x71, 0x6c,\n\t0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x61, 0x74,\n\t0x61, 0x54, 0x79, 0x70, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x08, 0x65, 0x6c, 0x65, 0x6d,\n\t0x54, 0x79, 0x70, 0x65, 0x22, 0x25, 0x0a, 0x0c, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x49, 0x64,\n\t0x4c, 0x69, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,\n\t0x05, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0xf2, 0x04, 0x0a, 0x08,\n\t0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a,\n\t0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02,\n\t0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12,\n\t0x43, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x26, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68,\n\t0x61, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x49, 0x6e, 0x70, 0x75,\n\t0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x69, 0x6e,\n\t0x70, 0x75, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18,\n\t0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e,\n\t0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f,\n\t0x72, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x03,\n\t0xe0, 0x41, 0x02, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x4f, 0x0a, 0x0a,\n\t0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b,\n\t0x32, 0x2a, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70,\n\t0x68, 0x61, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x41, 0x74, 0x74,\n\t0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x03, 0xe0, 0x41,\n\t0x02, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x35, 0x0a,\n\t0x06, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e,\n\t0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,\n\t0x2e, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x6b, 0x65,\n\t0x72, 0x6e, 0x65, 0x6c, 0x1a, 0x59, 0x0a, 0x0b, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x45, 0x6e,\n\t0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76,\n\t0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x49, 0x64,\n\t0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a,\n\t0x5a, 0x0a, 0x0c, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,\n\t0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,\n\t0x79, 0x12, 0x34, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x1e, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70,\n\t0x68, 0x61, 0x31, 0x2e, 0x54, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74,\n\t0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x53, 0x0a, 0x0f, 0x41,\n\t0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,\n\t0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,\n\t0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,\n\t0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,\n\t0x22, 0x3a, 0x0a, 0x06, 0x4b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61,\n\t0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x04, 0x6e,\n\t0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x01, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x32, 0x95, 0x01, 0x0a,\n\t0x0f, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,\n\t0x12, 0x81, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x53, 0x51, 0x4c, 0x12,\n\t0x23, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68,\n\t0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x71,\n\t0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x63, 0x71, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x76,\n\t0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x53,\n\t0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93,\n\t0x02, 0x22, 0x3a, 0x01, 0x2a, 0x22, 0x1d, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,\n\t0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x3a, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c,\n\t0x65, 0x53, 0x71, 0x6c, 0x42, 0x19, 0x5a, 0x17, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x67, 0x65,\n\t0x6e, 0x2f, 0x73, 0x63, 0x71, 0x6c, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62,\n\t0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_api_v1alpha1_compiler_proto_rawDescOnce sync.Once\n\tfile_api_v1alpha1_compiler_proto_rawDescData = file_api_v1alpha1_compiler_proto_rawDesc\n)\n\nfunc file_api_v1alpha1_compiler_proto_rawDescGZIP() []byte {\n\tfile_api_v1alpha1_compiler_proto_rawDescOnce.Do(func() {\n\t\tfile_api_v1alpha1_compiler_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_v1alpha1_compiler_proto_rawDescData)\n\t})\n\treturn file_api_v1alpha1_compiler_proto_rawDescData\n}\n\nvar file_api_v1alpha1_compiler_proto_msgTypes = make([]protoimpl.MessageInfo, 18)\nvar file_api_v1alpha1_compiler_proto_goTypes = []any{\n\t(*CompileOptions)(nil),           // 0: scql.pb.v1alpha1.CompileOptions\n\t(*GlobalSecurityRelaxation)(nil), // 1: scql.pb.v1alpha1.GlobalSecurityRelaxation\n\t(*ColumnSecurityRelaxation)(nil), // 2: scql.pb.v1alpha1.ColumnSecurityRelaxation\n\t(*ReverseInferenceConfig)(nil),   // 3: scql.pb.v1alpha1.ReverseInferenceConfig\n\t(*ResultSecurityConfig)(nil),     // 4: scql.pb.v1alpha1.ResultSecurityConfig\n\t(*CompilerSecurityConfig)(nil),   // 5: scql.pb.v1alpha1.CompilerSecurityConfig\n\t(*ColumnVisibility)(nil),         // 6: scql.pb.v1alpha1.ColumnVisibility\n\t(*AdditionalInfoSpec)(nil),       // 7: scql.pb.v1alpha1.AdditionalInfoSpec\n\t(*CompileSQLRequest)(nil),        // 8: scql.pb.v1alpha1.CompileSQLRequest\n\t(*CompileSQLResponse)(nil),       // 9: scql.pb.v1alpha1.CompileSQLResponse\n\t(*OperatorGraph)(nil),            // 10: scql.pb.v1alpha1.OperatorGraph\n\t(*TensorMeta)(nil),               // 11: scql.pb.v1alpha1.TensorMeta\n\t(*TensorIdList)(nil),             // 12: scql.pb.v1alpha1.TensorIdList\n\t(*Operator)(nil),                 // 13: scql.pb.v1alpha1.Operator\n\t(*Kernel)(nil),                   // 14: scql.pb.v1alpha1.Kernel\n\tnil,                              // 15: scql.pb.v1alpha1.Operator.InputsEntry\n\tnil,                              // 16: scql.pb.v1alpha1.Operator.OutputsEntry\n\tnil,                              // 17: scql.pb.v1alpha1.Operator.AttributesEntry\n\t(*spu.RuntimeConfig)(nil),        // 18: spu.pb.RuntimeConfig\n\t(scql.PsiAlgorithmType)(0),       // 19: scql.pb.PsiAlgorithmType\n\t(*scql.PartyId)(nil),             // 20: scql.pb.PartyId\n\t(*scql.Catalog)(nil),             // 21: scql.pb.Catalog\n\t(*timestamppb.Timestamp)(nil),    // 22: google.protobuf.Timestamp\n\t(*scql.Placeholders)(nil),        // 23: scql.pb.Placeholders\n\t(*scql.Variable)(nil),            // 24: scql.pb.Variable\n\t(*scql.Status)(nil),              // 25: scql.pb.Status\n\t(*scql.CompiledPlan)(nil),        // 26: scql.pb.CompiledPlan\n\t(scql.PrimitiveDataType)(0),      // 27: scql.pb.PrimitiveDataType\n\t(*anypb.Any)(nil),                // 28: google.protobuf.Any\n}\nvar file_api_v1alpha1_compiler_proto_depIdxs = []int32{\n\t18, // 0: scql.pb.v1alpha1.CompileOptions.spu_conf:type_name -> spu.pb.RuntimeConfig\n\t19, // 1: scql.pb.v1alpha1.CompileOptions.psi_algorithm_type:type_name -> scql.pb.PsiAlgorithmType\n\t1,  // 2: scql.pb.v1alpha1.CompilerSecurityConfig.global_relaxation:type_name -> scql.pb.v1alpha1.GlobalSecurityRelaxation\n\t2,  // 3: scql.pb.v1alpha1.CompilerSecurityConfig.column_relaxation_list:type_name -> scql.pb.v1alpha1.ColumnSecurityRelaxation\n\t3,  // 4: scql.pb.v1alpha1.CompilerSecurityConfig.reverse_inference_conf:type_name -> scql.pb.v1alpha1.ReverseInferenceConfig\n\t6,  // 5: scql.pb.v1alpha1.CompilerSecurityConfig.column_visibility_list:type_name -> scql.pb.v1alpha1.ColumnVisibility\n\t4,  // 6: scql.pb.v1alpha1.CompilerSecurityConfig.result_security_conf:type_name -> scql.pb.v1alpha1.ResultSecurityConfig\n\t20, // 7: scql.pb.v1alpha1.ColumnVisibility.visible_parties:type_name -> scql.pb.PartyId\n\t20, // 8: scql.pb.v1alpha1.CompileSQLRequest.issuer:type_name -> scql.pb.PartyId\n\t21, // 9: scql.pb.v1alpha1.CompileSQLRequest.catalog:type_name -> scql.pb.Catalog\n\t0,  // 10: scql.pb.v1alpha1.CompileSQLRequest.compile_opts:type_name -> scql.pb.v1alpha1.CompileOptions\n\t22, // 11: scql.pb.v1alpha1.CompileSQLRequest.issue_time:type_name -> google.protobuf.Timestamp\n\t5,  // 12: scql.pb.v1alpha1.CompileSQLRequest.security_config:type_name -> scql.pb.v1alpha1.CompilerSecurityConfig\n\t23, // 13: scql.pb.v1alpha1.CompileSQLRequest.placeholders:type_name -> scql.pb.Placeholders\n\t24, // 14: scql.pb.v1alpha1.CompileSQLRequest.variables:type_name -> scql.pb.Variable\n\t7,  // 15: scql.pb.v1alpha1.CompileSQLRequest.additional_info:type_name -> scql.pb.v1alpha1.AdditionalInfoSpec\n\t25, // 16: scql.pb.v1alpha1.CompileSQLResponse.status:type_name -> scql.pb.Status\n\t26, // 17: scql.pb.v1alpha1.CompileSQLResponse.execution_plan:type_name -> scql.pb.CompiledPlan\n\t10, // 18: scql.pb.v1alpha1.CompileSQLResponse.operator_graph:type_name -> scql.pb.v1alpha1.OperatorGraph\n\t13, // 19: scql.pb.v1alpha1.OperatorGraph.operators:type_name -> scql.pb.v1alpha1.Operator\n\t11, // 20: scql.pb.v1alpha1.OperatorGraph.tensors:type_name -> scql.pb.v1alpha1.TensorMeta\n\t27, // 21: scql.pb.v1alpha1.TensorMeta.elem_type:type_name -> scql.pb.PrimitiveDataType\n\t15, // 22: scql.pb.v1alpha1.Operator.inputs:type_name -> scql.pb.v1alpha1.Operator.InputsEntry\n\t16, // 23: scql.pb.v1alpha1.Operator.outputs:type_name -> scql.pb.v1alpha1.Operator.OutputsEntry\n\t17, // 24: scql.pb.v1alpha1.Operator.attributes:type_name -> scql.pb.v1alpha1.Operator.AttributesEntry\n\t14, // 25: scql.pb.v1alpha1.Operator.kernel:type_name -> scql.pb.v1alpha1.Kernel\n\t12, // 26: scql.pb.v1alpha1.Operator.InputsEntry.value:type_name -> scql.pb.v1alpha1.TensorIdList\n\t12, // 27: scql.pb.v1alpha1.Operator.OutputsEntry.value:type_name -> scql.pb.v1alpha1.TensorIdList\n\t28, // 28: scql.pb.v1alpha1.Operator.AttributesEntry.value:type_name -> google.protobuf.Any\n\t8,  // 29: scql.pb.v1alpha1.CompilerService.CompileSQL:input_type -> scql.pb.v1alpha1.CompileSQLRequest\n\t9,  // 30: scql.pb.v1alpha1.CompilerService.CompileSQL:output_type -> scql.pb.v1alpha1.CompileSQLResponse\n\t30, // [30:31] is the sub-list for method output_type\n\t29, // [29:30] is the sub-list for method input_type\n\t29, // [29:29] is the sub-list for extension type_name\n\t29, // [29:29] is the sub-list for extension extendee\n\t0,  // [0:29] is the sub-list for field type_name\n}\n\nfunc init() { file_api_v1alpha1_compiler_proto_init() }\nfunc file_api_v1alpha1_compiler_proto_init() {\n\tif File_api_v1alpha1_compiler_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_api_v1alpha1_compiler_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   18,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_api_v1alpha1_compiler_proto_goTypes,\n\t\tDependencyIndexes: file_api_v1alpha1_compiler_proto_depIdxs,\n\t\tMessageInfos:      file_api_v1alpha1_compiler_proto_msgTypes,\n\t}.Build()\n\tFile_api_v1alpha1_compiler_proto = out.File\n\tfile_api_v1alpha1_compiler_proto_rawDesc = nil\n\tfile_api_v1alpha1_compiler_proto_goTypes = nil\n\tfile_api_v1alpha1_compiler_proto_depIdxs = nil\n}\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ context.Context\nvar _ grpc.ClientConnInterface\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\nconst _ = grpc.SupportPackageIsVersion6\n\n// CompilerServiceClient is the client API for CompilerService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.\ntype CompilerServiceClient interface {\n\tCompileSQL(ctx context.Context, in *CompileSQLRequest, opts ...grpc.CallOption) (*CompileSQLResponse, error)\n}\n\ntype compilerServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewCompilerServiceClient(cc grpc.ClientConnInterface) CompilerServiceClient {\n\treturn &compilerServiceClient{cc}\n}\n\nfunc (c *compilerServiceClient) CompileSQL(ctx context.Context, in *CompileSQLRequest, opts ...grpc.CallOption) (*CompileSQLResponse, error) {\n\tout := new(CompileSQLResponse)\n\terr := c.cc.Invoke(ctx, \"/scql.pb.v1alpha1.CompilerService/CompileSQL\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// CompilerServiceServer is the server API for CompilerService service.\ntype CompilerServiceServer interface {\n\tCompileSQL(context.Context, *CompileSQLRequest) (*CompileSQLResponse, error)\n}\n\n// UnimplementedCompilerServiceServer can be embedded to have forward compatible implementations.\ntype UnimplementedCompilerServiceServer struct {\n}\n\nfunc (*UnimplementedCompilerServiceServer) CompileSQL(context.Context, *CompileSQLRequest) (*CompileSQLResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method CompileSQL not implemented\")\n}\n\nfunc RegisterCompilerServiceServer(s *grpc.Server, srv CompilerServiceServer) {\n\ts.RegisterService(&_CompilerService_serviceDesc, srv)\n}\n\nfunc _CompilerService_CompileSQL_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(CompileSQLRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(CompilerServiceServer).CompileSQL(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/scql.pb.v1alpha1.CompilerService/CompileSQL\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(CompilerServiceServer).CompileSQL(ctx, req.(*CompileSQLRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _CompilerService_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"scql.pb.v1alpha1.CompilerService\",\n\tHandlerType: (*CompilerServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"CompileSQL\",\n\t\t\tHandler:    _CompilerService_CompileSQL_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"api/v1alpha1/compiler.proto\",\n}\n"
  },
  {
    "path": "pkg/proto-gen/spu/spu.pb.go",
    "content": "// Copyright 2021 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n// This file defines data structures that used to access and control SPU.\n// - IO access (data infeed & outfeed).\n// - Runtime control (runtime config and setup)\n//\n// It does NOT define how to program on SPU, programming part is defined by\n// [pphlo](spu/dialect/pphlo.td)\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.3\n// \tprotoc        v5.27.3\n// source: libspu/spu.proto\n\npackage spu\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// The SPU datatype\ntype DataType int32\n\nconst (\n\tDataType_DT_INVALID DataType = 0\n\tDataType_DT_I1      DataType = 1  // 1bit integer (bool).\n\tDataType_DT_I8      DataType = 2  // int8\n\tDataType_DT_U8      DataType = 3  // uint8\n\tDataType_DT_I16     DataType = 4  // int16\n\tDataType_DT_U16     DataType = 5  // uint16\n\tDataType_DT_I32     DataType = 6  // int32\n\tDataType_DT_U32     DataType = 7  // uint32\n\tDataType_DT_I64     DataType = 8  // int64\n\tDataType_DT_U64     DataType = 9  // uint64\n\tDataType_DT_F16     DataType = 10 // half\n\tDataType_DT_F32     DataType = 11 // float\n\tDataType_DT_F64     DataType = 12 // double\n)\n\n// Enum value maps for DataType.\nvar (\n\tDataType_name = map[int32]string{\n\t\t0:  \"DT_INVALID\",\n\t\t1:  \"DT_I1\",\n\t\t2:  \"DT_I8\",\n\t\t3:  \"DT_U8\",\n\t\t4:  \"DT_I16\",\n\t\t5:  \"DT_U16\",\n\t\t6:  \"DT_I32\",\n\t\t7:  \"DT_U32\",\n\t\t8:  \"DT_I64\",\n\t\t9:  \"DT_U64\",\n\t\t10: \"DT_F16\",\n\t\t11: \"DT_F32\",\n\t\t12: \"DT_F64\",\n\t}\n\tDataType_value = map[string]int32{\n\t\t\"DT_INVALID\": 0,\n\t\t\"DT_I1\":      1,\n\t\t\"DT_I8\":      2,\n\t\t\"DT_U8\":      3,\n\t\t\"DT_I16\":     4,\n\t\t\"DT_U16\":     5,\n\t\t\"DT_I32\":     6,\n\t\t\"DT_U32\":     7,\n\t\t\"DT_I64\":     8,\n\t\t\"DT_U64\":     9,\n\t\t\"DT_F16\":     10,\n\t\t\"DT_F32\":     11,\n\t\t\"DT_F64\":     12,\n\t}\n)\n\nfunc (x DataType) Enum() *DataType {\n\tp := new(DataType)\n\t*p = x\n\treturn p\n}\n\nfunc (x DataType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (DataType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[0].Descriptor()\n}\n\nfunc (DataType) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[0]\n}\n\nfunc (x DataType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use DataType.Descriptor instead.\nfunc (DataType) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{0}\n}\n\n// The visibility type.\n//\n// SPU is a secure evaluation runtime, but not all data are secret, some of them\n// are publicly known to all parties, marking them as public will improve\n// performance significantly.\ntype Visibility int32\n\nconst (\n\tVisibility_VIS_INVALID Visibility = 0\n\tVisibility_VIS_SECRET  Visibility = 1 // Invisible(unknown) for all or some of the parties.\n\tVisibility_VIS_PUBLIC  Visibility = 2 // Visible(public) for all parties.\n\tVisibility_VIS_PRIVATE Visibility = 3 // Visible for only one party\n)\n\n// Enum value maps for Visibility.\nvar (\n\tVisibility_name = map[int32]string{\n\t\t0: \"VIS_INVALID\",\n\t\t1: \"VIS_SECRET\",\n\t\t2: \"VIS_PUBLIC\",\n\t\t3: \"VIS_PRIVATE\",\n\t}\n\tVisibility_value = map[string]int32{\n\t\t\"VIS_INVALID\": 0,\n\t\t\"VIS_SECRET\":  1,\n\t\t\"VIS_PUBLIC\":  2,\n\t\t\"VIS_PRIVATE\": 3,\n\t}\n)\n\nfunc (x Visibility) Enum() *Visibility {\n\tp := new(Visibility)\n\t*p = x\n\treturn p\n}\n\nfunc (x Visibility) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Visibility) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[1].Descriptor()\n}\n\nfunc (Visibility) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[1]\n}\n\nfunc (x Visibility) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Visibility.Descriptor instead.\nfunc (Visibility) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{1}\n}\n\n// Plaintext type\n//\n// SPU runtime does not process with plaintext directly, plaintext type is\n// mainly used for IO purposes, when converting a plaintext buffer to an SPU\n// buffer, we have to let spu know which type the plaintext buffer is.\ntype PtType int32\n\nconst (\n\tPtType_PT_INVALID PtType = 0  //\n\tPtType_PT_I8      PtType = 1  // int8_t\n\tPtType_PT_U8      PtType = 2  // uint8_t\n\tPtType_PT_I16     PtType = 3  // int16_t\n\tPtType_PT_U16     PtType = 4  // uint16_t\n\tPtType_PT_I32     PtType = 5  // int32_t\n\tPtType_PT_U32     PtType = 6  // uint32_t\n\tPtType_PT_I64     PtType = 7  // int64_t\n\tPtType_PT_U64     PtType = 8  // uint64_t\n\tPtType_PT_I128    PtType = 9  // int128_t\n\tPtType_PT_U128    PtType = 10 // uint128_t\n\tPtType_PT_I1      PtType = 11 // bool\n\tPtType_PT_F16     PtType = 30 // half\n\tPtType_PT_F32     PtType = 31 // float\n\tPtType_PT_F64     PtType = 32 // double\n\tPtType_PT_CF32    PtType = 50 // complex float\n\tPtType_PT_CF64    PtType = 51 // complex double\n)\n\n// Enum value maps for PtType.\nvar (\n\tPtType_name = map[int32]string{\n\t\t0:  \"PT_INVALID\",\n\t\t1:  \"PT_I8\",\n\t\t2:  \"PT_U8\",\n\t\t3:  \"PT_I16\",\n\t\t4:  \"PT_U16\",\n\t\t5:  \"PT_I32\",\n\t\t6:  \"PT_U32\",\n\t\t7:  \"PT_I64\",\n\t\t8:  \"PT_U64\",\n\t\t9:  \"PT_I128\",\n\t\t10: \"PT_U128\",\n\t\t11: \"PT_I1\",\n\t\t30: \"PT_F16\",\n\t\t31: \"PT_F32\",\n\t\t32: \"PT_F64\",\n\t\t50: \"PT_CF32\",\n\t\t51: \"PT_CF64\",\n\t}\n\tPtType_value = map[string]int32{\n\t\t\"PT_INVALID\": 0,\n\t\t\"PT_I8\":      1,\n\t\t\"PT_U8\":      2,\n\t\t\"PT_I16\":     3,\n\t\t\"PT_U16\":     4,\n\t\t\"PT_I32\":     5,\n\t\t\"PT_U32\":     6,\n\t\t\"PT_I64\":     7,\n\t\t\"PT_U64\":     8,\n\t\t\"PT_I128\":    9,\n\t\t\"PT_U128\":    10,\n\t\t\"PT_I1\":      11,\n\t\t\"PT_F16\":     30,\n\t\t\"PT_F32\":     31,\n\t\t\"PT_F64\":     32,\n\t\t\"PT_CF32\":    50,\n\t\t\"PT_CF64\":    51,\n\t}\n)\n\nfunc (x PtType) Enum() *PtType {\n\tp := new(PtType)\n\t*p = x\n\treturn p\n}\n\nfunc (x PtType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (PtType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[2].Descriptor()\n}\n\nfunc (PtType) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[2]\n}\n\nfunc (x PtType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use PtType.Descriptor instead.\nfunc (PtType) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{2}\n}\n\n// A security parameter type.\n//\n// The secure evaluation is based on some algebraic structure (ring or field),\ntype FieldType int32\n\nconst (\n\tFieldType_FT_INVALID FieldType = 0\n\tFieldType_FM32       FieldType = 1 // Ring 2^32\n\tFieldType_FM64       FieldType = 2 // Ring 2^64\n\tFieldType_FM128      FieldType = 3 // Ring 2^128\n)\n\n// Enum value maps for FieldType.\nvar (\n\tFieldType_name = map[int32]string{\n\t\t0: \"FT_INVALID\",\n\t\t1: \"FM32\",\n\t\t2: \"FM64\",\n\t\t3: \"FM128\",\n\t}\n\tFieldType_value = map[string]int32{\n\t\t\"FT_INVALID\": 0,\n\t\t\"FM32\":       1,\n\t\t\"FM64\":       2,\n\t\t\"FM128\":      3,\n\t}\n)\n\nfunc (x FieldType) Enum() *FieldType {\n\tp := new(FieldType)\n\t*p = x\n\treturn p\n}\n\nfunc (x FieldType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (FieldType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[3].Descriptor()\n}\n\nfunc (FieldType) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[3]\n}\n\nfunc (x FieldType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use FieldType.Descriptor instead.\nfunc (FieldType) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{3}\n}\n\n// The protocol kind.\ntype ProtocolKind int32\n\nconst (\n\t// Invalid protocol.\n\tProtocolKind_PROT_INVALID ProtocolKind = 0\n\t// The reference implementation in `ring^2k`, note: this 'protocol' only\n\t// behave-like a fixed point secure protocol without any security guarantee.\n\t// Hence, it should only be selected for debugging purposes.\n\tProtocolKind_REF2K ProtocolKind = 1\n\t// A semi-honest multi-party protocol. This protocol requires a trusted third\n\t// party to generate the offline correlated randoms. Currently, SecretFlow by\n\t// default ships this protocol with a trusted first party. Hence, it should\n\t// only be used for debugging purposes.\n\tProtocolKind_SEMI2K ProtocolKind = 2\n\t// A honest majority 3PC-protocol. SecretFlow provides the semi-honest\n\t// implementation without Yao.\n\tProtocolKind_ABY3 ProtocolKind = 3\n\t// The famous [Cheetah](https://eprint.iacr.org/2022/207) protocol, a very\n\t// fast 2PC protocol.\n\tProtocolKind_CHEETAH ProtocolKind = 4\n\t// A semi-honest 3PC-protocol for Neural Network, P2 as the helper,\n\t// (https://eprint.iacr.org/2018/442)\n\tProtocolKind_SECURENN ProtocolKind = 5\n\t// The malicious 3PC-protocol version of swift\n\t// WARNING: This protocol is experimental only.\n\t// (https://eprint.iacr.org/2020/592)\n\tProtocolKind_SWIFT ProtocolKind = 6\n)\n\n// Enum value maps for ProtocolKind.\nvar (\n\tProtocolKind_name = map[int32]string{\n\t\t0: \"PROT_INVALID\",\n\t\t1: \"REF2K\",\n\t\t2: \"SEMI2K\",\n\t\t3: \"ABY3\",\n\t\t4: \"CHEETAH\",\n\t\t5: \"SECURENN\",\n\t\t6: \"SWIFT\",\n\t}\n\tProtocolKind_value = map[string]int32{\n\t\t\"PROT_INVALID\": 0,\n\t\t\"REF2K\":        1,\n\t\t\"SEMI2K\":       2,\n\t\t\"ABY3\":         3,\n\t\t\"CHEETAH\":      4,\n\t\t\"SECURENN\":     5,\n\t\t\"SWIFT\":        6,\n\t}\n)\n\nfunc (x ProtocolKind) Enum() *ProtocolKind {\n\tp := new(ProtocolKind)\n\t*p = x\n\treturn p\n}\n\nfunc (x ProtocolKind) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ProtocolKind) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[4].Descriptor()\n}\n\nfunc (ProtocolKind) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[4]\n}\n\nfunc (x ProtocolKind) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ProtocolKind.Descriptor instead.\nfunc (ProtocolKind) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{4}\n}\n\ntype CheetahOtKind int32\n\nconst (\n\tCheetahOtKind_YACL_Ferret     CheetahOtKind = 0\n\tCheetahOtKind_YACL_Softspoken CheetahOtKind = 1\n\tCheetahOtKind_EMP_Ferret      CheetahOtKind = 2\n)\n\n// Enum value maps for CheetahOtKind.\nvar (\n\tCheetahOtKind_name = map[int32]string{\n\t\t0: \"YACL_Ferret\",\n\t\t1: \"YACL_Softspoken\",\n\t\t2: \"EMP_Ferret\",\n\t}\n\tCheetahOtKind_value = map[string]int32{\n\t\t\"YACL_Ferret\":     0,\n\t\t\"YACL_Softspoken\": 1,\n\t\t\"EMP_Ferret\":      2,\n\t}\n)\n\nfunc (x CheetahOtKind) Enum() *CheetahOtKind {\n\tp := new(CheetahOtKind)\n\t*p = x\n\treturn p\n}\n\nfunc (x CheetahOtKind) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (CheetahOtKind) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[5].Descriptor()\n}\n\nfunc (CheetahOtKind) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[5]\n}\n\nfunc (x CheetahOtKind) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use CheetahOtKind.Descriptor instead.\nfunc (CheetahOtKind) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{5}\n}\n\n// ////////////////////////////////////////////////////////////////////////\n// Compiler relate definition\n// ////////////////////////////////////////////////////////////////////////\ntype SourceIRType int32\n\nconst (\n\tSourceIRType_XLA       SourceIRType = 0\n\tSourceIRType_STABLEHLO SourceIRType = 1\n)\n\n// Enum value maps for SourceIRType.\nvar (\n\tSourceIRType_name = map[int32]string{\n\t\t0: \"XLA\",\n\t\t1: \"STABLEHLO\",\n\t}\n\tSourceIRType_value = map[string]int32{\n\t\t\"XLA\":       0,\n\t\t\"STABLEHLO\": 1,\n\t}\n)\n\nfunc (x SourceIRType) Enum() *SourceIRType {\n\tp := new(SourceIRType)\n\t*p = x\n\treturn p\n}\n\nfunc (x SourceIRType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (SourceIRType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[6].Descriptor()\n}\n\nfunc (SourceIRType) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[6]\n}\n\nfunc (x SourceIRType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use SourceIRType.Descriptor instead.\nfunc (SourceIRType) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{6}\n}\n\ntype XLAPrettyPrintKind int32\n\nconst (\n\tXLAPrettyPrintKind_TEXT XLAPrettyPrintKind = 0\n\tXLAPrettyPrintKind_DOT  XLAPrettyPrintKind = 1\n\tXLAPrettyPrintKind_HTML XLAPrettyPrintKind = 2\n)\n\n// Enum value maps for XLAPrettyPrintKind.\nvar (\n\tXLAPrettyPrintKind_name = map[int32]string{\n\t\t0: \"TEXT\",\n\t\t1: \"DOT\",\n\t\t2: \"HTML\",\n\t}\n\tXLAPrettyPrintKind_value = map[string]int32{\n\t\t\"TEXT\": 0,\n\t\t\"DOT\":  1,\n\t\t\"HTML\": 2,\n\t}\n)\n\nfunc (x XLAPrettyPrintKind) Enum() *XLAPrettyPrintKind {\n\tp := new(XLAPrettyPrintKind)\n\t*p = x\n\treturn p\n}\n\nfunc (x XLAPrettyPrintKind) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (XLAPrettyPrintKind) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[7].Descriptor()\n}\n\nfunc (XLAPrettyPrintKind) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[7]\n}\n\nfunc (x XLAPrettyPrintKind) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use XLAPrettyPrintKind.Descriptor instead.\nfunc (XLAPrettyPrintKind) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{7}\n}\n\ntype RuntimeConfig_SortMethod int32\n\nconst (\n\tRuntimeConfig_SORT_DEFAULT RuntimeConfig_SortMethod = 0 // Implementation defined.\n\tRuntimeConfig_SORT_RADIX   RuntimeConfig_SortMethod = 1 // The radix sort (stable sort, need efficient shuffle).\n\tRuntimeConfig_SORT_QUICK   RuntimeConfig_SortMethod = 2 // The quick sort (unstable, need efficient shuffle).\n\tRuntimeConfig_SORT_NETWORK RuntimeConfig_SortMethod = 3 // The odd-even sorting network (unstable, most general).\n)\n\n// Enum value maps for RuntimeConfig_SortMethod.\nvar (\n\tRuntimeConfig_SortMethod_name = map[int32]string{\n\t\t0: \"SORT_DEFAULT\",\n\t\t1: \"SORT_RADIX\",\n\t\t2: \"SORT_QUICK\",\n\t\t3: \"SORT_NETWORK\",\n\t}\n\tRuntimeConfig_SortMethod_value = map[string]int32{\n\t\t\"SORT_DEFAULT\": 0,\n\t\t\"SORT_RADIX\":   1,\n\t\t\"SORT_QUICK\":   2,\n\t\t\"SORT_NETWORK\": 3,\n\t}\n)\n\nfunc (x RuntimeConfig_SortMethod) Enum() *RuntimeConfig_SortMethod {\n\tp := new(RuntimeConfig_SortMethod)\n\t*p = x\n\treturn p\n}\n\nfunc (x RuntimeConfig_SortMethod) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (RuntimeConfig_SortMethod) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[8].Descriptor()\n}\n\nfunc (RuntimeConfig_SortMethod) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[8]\n}\n\nfunc (x RuntimeConfig_SortMethod) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use RuntimeConfig_SortMethod.Descriptor instead.\nfunc (RuntimeConfig_SortMethod) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{3, 0}\n}\n\n// The exponential approximation method.\ntype RuntimeConfig_ExpMode int32\n\nconst (\n\tRuntimeConfig_EXP_DEFAULT RuntimeConfig_ExpMode = 0 // Implementation defined.\n\tRuntimeConfig_EXP_PADE    RuntimeConfig_ExpMode = 1 // The pade approximation.\n\tRuntimeConfig_EXP_TAYLOR  RuntimeConfig_ExpMode = 2 // Taylor series approximation.\n\tRuntimeConfig_EXP_PRIME   RuntimeConfig_ExpMode = 3 // exp prime only available for some implementations\n)\n\n// Enum value maps for RuntimeConfig_ExpMode.\nvar (\n\tRuntimeConfig_ExpMode_name = map[int32]string{\n\t\t0: \"EXP_DEFAULT\",\n\t\t1: \"EXP_PADE\",\n\t\t2: \"EXP_TAYLOR\",\n\t\t3: \"EXP_PRIME\",\n\t}\n\tRuntimeConfig_ExpMode_value = map[string]int32{\n\t\t\"EXP_DEFAULT\": 0,\n\t\t\"EXP_PADE\":    1,\n\t\t\"EXP_TAYLOR\":  2,\n\t\t\"EXP_PRIME\":   3,\n\t}\n)\n\nfunc (x RuntimeConfig_ExpMode) Enum() *RuntimeConfig_ExpMode {\n\tp := new(RuntimeConfig_ExpMode)\n\t*p = x\n\treturn p\n}\n\nfunc (x RuntimeConfig_ExpMode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (RuntimeConfig_ExpMode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[9].Descriptor()\n}\n\nfunc (RuntimeConfig_ExpMode) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[9]\n}\n\nfunc (x RuntimeConfig_ExpMode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use RuntimeConfig_ExpMode.Descriptor instead.\nfunc (RuntimeConfig_ExpMode) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{3, 1}\n}\n\n// The logarithm approximation method.\ntype RuntimeConfig_LogMode int32\n\nconst (\n\tRuntimeConfig_LOG_DEFAULT RuntimeConfig_LogMode = 0 // Implementation defined.\n\tRuntimeConfig_LOG_PADE    RuntimeConfig_LogMode = 1 // The pade approximation.\n\tRuntimeConfig_LOG_NEWTON  RuntimeConfig_LogMode = 2 // The newton approximation.\n\tRuntimeConfig_LOG_MINMAX  RuntimeConfig_LogMode = 3 // The minmax approximation.\n)\n\n// Enum value maps for RuntimeConfig_LogMode.\nvar (\n\tRuntimeConfig_LogMode_name = map[int32]string{\n\t\t0: \"LOG_DEFAULT\",\n\t\t1: \"LOG_PADE\",\n\t\t2: \"LOG_NEWTON\",\n\t\t3: \"LOG_MINMAX\",\n\t}\n\tRuntimeConfig_LogMode_value = map[string]int32{\n\t\t\"LOG_DEFAULT\": 0,\n\t\t\"LOG_PADE\":    1,\n\t\t\"LOG_NEWTON\":  2,\n\t\t\"LOG_MINMAX\":  3,\n\t}\n)\n\nfunc (x RuntimeConfig_LogMode) Enum() *RuntimeConfig_LogMode {\n\tp := new(RuntimeConfig_LogMode)\n\t*p = x\n\treturn p\n}\n\nfunc (x RuntimeConfig_LogMode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (RuntimeConfig_LogMode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[10].Descriptor()\n}\n\nfunc (RuntimeConfig_LogMode) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[10]\n}\n\nfunc (x RuntimeConfig_LogMode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use RuntimeConfig_LogMode.Descriptor instead.\nfunc (RuntimeConfig_LogMode) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{3, 2}\n}\n\n// The sigmoid approximation method.\ntype RuntimeConfig_SigmoidMode int32\n\nconst (\n\t// Implementation defined.\n\tRuntimeConfig_SIGMOID_DEFAULT RuntimeConfig_SigmoidMode = 0\n\t// Minmax approximation one order.\n\t// f(x) = 0.5 + 0.125 * x\n\tRuntimeConfig_SIGMOID_MM1 RuntimeConfig_SigmoidMode = 1\n\t// Piece-wise simulation.\n\t// f(x) = 0.5 + 0.125x if -4 <= x <= 4\n\t//\n\t//\t1            if       x > 4\n\t//\t0            if  -4 > x\n\tRuntimeConfig_SIGMOID_SEG3 RuntimeConfig_SigmoidMode = 2\n\t// The real definition, which depends on exp's accuracy.\n\t// f(x) = 1 / (1 + exp(-x))\n\tRuntimeConfig_SIGMOID_REAL RuntimeConfig_SigmoidMode = 3\n)\n\n// Enum value maps for RuntimeConfig_SigmoidMode.\nvar (\n\tRuntimeConfig_SigmoidMode_name = map[int32]string{\n\t\t0: \"SIGMOID_DEFAULT\",\n\t\t1: \"SIGMOID_MM1\",\n\t\t2: \"SIGMOID_SEG3\",\n\t\t3: \"SIGMOID_REAL\",\n\t}\n\tRuntimeConfig_SigmoidMode_value = map[string]int32{\n\t\t\"SIGMOID_DEFAULT\": 0,\n\t\t\"SIGMOID_MM1\":     1,\n\t\t\"SIGMOID_SEG3\":    2,\n\t\t\"SIGMOID_REAL\":    3,\n\t}\n)\n\nfunc (x RuntimeConfig_SigmoidMode) Enum() *RuntimeConfig_SigmoidMode {\n\tp := new(RuntimeConfig_SigmoidMode)\n\t*p = x\n\treturn p\n}\n\nfunc (x RuntimeConfig_SigmoidMode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (RuntimeConfig_SigmoidMode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[11].Descriptor()\n}\n\nfunc (RuntimeConfig_SigmoidMode) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[11]\n}\n\nfunc (x RuntimeConfig_SigmoidMode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use RuntimeConfig_SigmoidMode.Descriptor instead.\nfunc (RuntimeConfig_SigmoidMode) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{3, 3}\n}\n\ntype RuntimeConfig_BeaverType int32\n\nconst (\n\t// Assume first party (rank0) as trusted party to generate beaver triple.\n\t// WARNING: It is NOT SAFE and SHOULD NOT BE used in production.\n\tRuntimeConfig_TrustedFirstParty RuntimeConfig_BeaverType = 0\n\t// Generate beaver triple through an additional trusted third party.\n\tRuntimeConfig_TrustedThirdParty RuntimeConfig_BeaverType = 1\n\t// Generate beaver triple through multi-party.\n\tRuntimeConfig_MultiParty RuntimeConfig_BeaverType = 2\n)\n\n// Enum value maps for RuntimeConfig_BeaverType.\nvar (\n\tRuntimeConfig_BeaverType_name = map[int32]string{\n\t\t0: \"TrustedFirstParty\",\n\t\t1: \"TrustedThirdParty\",\n\t\t2: \"MultiParty\",\n\t}\n\tRuntimeConfig_BeaverType_value = map[string]int32{\n\t\t\"TrustedFirstParty\": 0,\n\t\t\"TrustedThirdParty\": 1,\n\t\t\"MultiParty\":        2,\n\t}\n)\n\nfunc (x RuntimeConfig_BeaverType) Enum() *RuntimeConfig_BeaverType {\n\tp := new(RuntimeConfig_BeaverType)\n\t*p = x\n\treturn p\n}\n\nfunc (x RuntimeConfig_BeaverType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (RuntimeConfig_BeaverType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_libspu_spu_proto_enumTypes[12].Descriptor()\n}\n\nfunc (RuntimeConfig_BeaverType) Type() protoreflect.EnumType {\n\treturn &file_libspu_spu_proto_enumTypes[12]\n}\n\nfunc (x RuntimeConfig_BeaverType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use RuntimeConfig_BeaverType.Descriptor instead.\nfunc (RuntimeConfig_BeaverType) EnumDescriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{3, 4}\n}\n\n// @exclude\n// The shape information.\ntype ShapeProto struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDims          []int64                `protobuf:\"varint,1,rep,packed,name=dims,proto3\" json:\"dims,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ShapeProto) Reset() {\n\t*x = ShapeProto{}\n\tmi := &file_libspu_spu_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ShapeProto) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ShapeProto) ProtoMessage() {}\n\nfunc (x *ShapeProto) ProtoReflect() protoreflect.Message {\n\tmi := &file_libspu_spu_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ShapeProto.ProtoReflect.Descriptor instead.\nfunc (*ShapeProto) Descriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ShapeProto) GetDims() []int64 {\n\tif x != nil {\n\t\treturn x.Dims\n\t}\n\treturn nil\n}\n\ntype ValueMetaProto struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The data type.\n\tDataType  DataType `protobuf:\"varint,1,opt,name=data_type,json=dataType,proto3,enum=spu.pb.DataType\" json:\"data_type,omitempty\"`\n\tIsComplex bool     `protobuf:\"varint,2,opt,name=is_complex,json=isComplex,proto3\" json:\"is_complex,omitempty\"`\n\t// The data visibility.\n\tVisibility Visibility `protobuf:\"varint,3,opt,name=visibility,proto3,enum=spu.pb.Visibility\" json:\"visibility,omitempty\"`\n\t// The shape of the value.\n\tShape *ShapeProto `protobuf:\"bytes,4,opt,name=shape,proto3\" json:\"shape,omitempty\"`\n\t// The storage type, defined by the underline evaluation engine.\n\t// i.e. `aby3.AShr<FM64>` means an aby3 arithmetic share in FM64.\n\t// usually, the application does not care about this attribute.\n\tStorageType   string `protobuf:\"bytes,5,opt,name=storage_type,json=storageType,proto3\" json:\"storage_type,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ValueMetaProto) Reset() {\n\t*x = ValueMetaProto{}\n\tmi := &file_libspu_spu_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ValueMetaProto) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ValueMetaProto) ProtoMessage() {}\n\nfunc (x *ValueMetaProto) ProtoReflect() protoreflect.Message {\n\tmi := &file_libspu_spu_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ValueMetaProto.ProtoReflect.Descriptor instead.\nfunc (*ValueMetaProto) Descriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ValueMetaProto) GetDataType() DataType {\n\tif x != nil {\n\t\treturn x.DataType\n\t}\n\treturn DataType_DT_INVALID\n}\n\nfunc (x *ValueMetaProto) GetIsComplex() bool {\n\tif x != nil {\n\t\treturn x.IsComplex\n\t}\n\treturn false\n}\n\nfunc (x *ValueMetaProto) GetVisibility() Visibility {\n\tif x != nil {\n\t\treturn x.Visibility\n\t}\n\treturn Visibility_VIS_INVALID\n}\n\nfunc (x *ValueMetaProto) GetShape() *ShapeProto {\n\tif x != nil {\n\t\treturn x.Shape\n\t}\n\treturn nil\n}\n\nfunc (x *ValueMetaProto) GetStorageType() string {\n\tif x != nil {\n\t\treturn x.StorageType\n\t}\n\treturn \"\"\n}\n\n// The spu Value proto, used for spu value serialization.\ntype ValueChunkProto struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// chunk info\n\tTotalBytes  uint64 `protobuf:\"varint,1,opt,name=total_bytes,json=totalBytes,proto3\" json:\"total_bytes,omitempty\"`\n\tChunkOffset uint64 `protobuf:\"varint,2,opt,name=chunk_offset,json=chunkOffset,proto3\" json:\"chunk_offset,omitempty\"`\n\t// chunk bytes\n\tContent       []byte `protobuf:\"bytes,3,opt,name=content,proto3\" json:\"content,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ValueChunkProto) Reset() {\n\t*x = ValueChunkProto{}\n\tmi := &file_libspu_spu_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ValueChunkProto) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ValueChunkProto) ProtoMessage() {}\n\nfunc (x *ValueChunkProto) ProtoReflect() protoreflect.Message {\n\tmi := &file_libspu_spu_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ValueChunkProto.ProtoReflect.Descriptor instead.\nfunc (*ValueChunkProto) Descriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ValueChunkProto) GetTotalBytes() uint64 {\n\tif x != nil {\n\t\treturn x.TotalBytes\n\t}\n\treturn 0\n}\n\nfunc (x *ValueChunkProto) GetChunkOffset() uint64 {\n\tif x != nil {\n\t\treturn x.ChunkOffset\n\t}\n\treturn 0\n}\n\nfunc (x *ValueChunkProto) GetContent() []byte {\n\tif x != nil {\n\t\treturn x.Content\n\t}\n\treturn nil\n}\n\n// The SPU runtime configuration.\ntype RuntimeConfig struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The protocol kind.\n\tProtocol ProtocolKind `protobuf:\"varint,1,opt,name=protocol,proto3,enum=spu.pb.ProtocolKind\" json:\"protocol,omitempty\"`\n\t// The field type.\n\tField FieldType `protobuf:\"varint,2,opt,name=field,proto3,enum=spu.pb.FieldType\" json:\"field,omitempty\"`\n\t// Number of fraction bits of fixed-point number.\n\t// 0(default) indicates implementation defined.\n\tFxpFractionBits int64 `protobuf:\"varint,3,opt,name=fxp_fraction_bits,json=fxpFractionBits,proto3\" json:\"fxp_fraction_bits,omitempty\"`\n\t// Max number of cores\n\tMaxConcurrency int32 `protobuf:\"varint,4,opt,name=max_concurrency,json=maxConcurrency,proto3\" json:\"max_concurrency,omitempty\"`\n\t// When enabled, runtime prints verbose info of the call stack, debug purpose\n\t// only.\n\tEnableActionTrace bool `protobuf:\"varint,10,opt,name=enable_action_trace,json=enableActionTrace,proto3\" json:\"enable_action_trace,omitempty\"`\n\t// When enabled, runtime checks runtime type infos against the\n\t// compile-time ones, exceptions are raised if mismatches happen. Note:\n\t// Runtime outputs prefer runtime type infos even when flag is on.\n\tEnableTypeChecker bool `protobuf:\"varint,11,opt,name=enable_type_checker,json=enableTypeChecker,proto3\" json:\"enable_type_checker,omitempty\"`\n\t// When enabled, runtime prints executed pphlo list, debug purpose only.\n\tEnablePphloTrace bool `protobuf:\"varint,12,opt,name=enable_pphlo_trace,json=enablePphloTrace,proto3\" json:\"enable_pphlo_trace,omitempty\"`\n\t// When enabled, runtime dumps executed executables in the dump_dir, debug\n\t// purpose only.\n\tEnableRuntimeSnapshot bool   `protobuf:\"varint,13,opt,name=enable_runtime_snapshot,json=enableRuntimeSnapshot,proto3\" json:\"enable_runtime_snapshot,omitempty\"`\n\tSnapshotDumpDir       string `protobuf:\"bytes,14,opt,name=snapshot_dump_dir,json=snapshotDumpDir,proto3\" json:\"snapshot_dump_dir,omitempty\"`\n\t// When enabled, runtime records detailed pphlo timing data, debug purpose\n\t// only.\n\t// WARNING: the `send bytes` information is only accurate when\n\t// `experimental_enable_inter_op_par` and `experimental_enable_intra_op_par`\n\t// options are disabled.\n\tEnablePphloProfile bool `protobuf:\"varint,15,opt,name=enable_pphlo_profile,json=enablePphloProfile,proto3\" json:\"enable_pphlo_profile,omitempty\"`\n\t// When enabled, runtime records detailed hal timing data, debug purpose only.\n\t// WARNING: the `send bytes` information is only accurate when\n\t// `experimental_enable_inter_op_par` and `experimental_enable_intra_op_par`\n\t// options are disabled.\n\tEnableHalProfile bool `protobuf:\"varint,16,opt,name=enable_hal_profile,json=enableHalProfile,proto3\" json:\"enable_hal_profile,omitempty\"`\n\t// The public random variable generated by the runtime, the concrete prg\n\t// function is implementation defined.\n\t// Note: this seed only applies to `public variable` only, it has nothing\n\t// to do with security.\n\tPublicRandomSeed uint64 `protobuf:\"varint,19,opt,name=public_random_seed,json=publicRandomSeed,proto3\" json:\"public_random_seed,omitempty\"`\n\t// max chunk size for Value::toProto\n\t// default: 128 * 1024 * 1024\n\tShareMaxChunkSize uint64 `protobuf:\"varint,20,opt,name=share_max_chunk_size,json=shareMaxChunkSize,proto3\" json:\"share_max_chunk_size,omitempty\"`\n\t// SPU supports multiple sorting algorithms.\n\t//\n\t//\t-for 2pc, only sorting network is supported.\n\t//\t-for 2.5pc or 3pc, all these algorithms are supported.\n\t//\t-for stable sort, only radix sort is supported.\n\tSortMethod RuntimeConfig_SortMethod `protobuf:\"varint,21,opt,name=sort_method,json=sortMethod,proto3,enum=spu.pb.RuntimeConfig_SortMethod\" json:\"sort_method,omitempty\"`\n\t// threshold for quick sort, when the size of the array is less than this\n\t// value, use merge sort instead\n\tQuickSortThreshold int64 `protobuf:\"varint,22,opt,name=quick_sort_threshold,json=quickSortThreshold,proto3\" json:\"quick_sort_threshold,omitempty\"`\n\t// The iterations use in f_div with Goldschmidt method.\n\t// 0(default) indicates implementation defined.\n\tFxpDivGoldschmidtIters int64 `protobuf:\"varint,50,opt,name=fxp_div_goldschmidt_iters,json=fxpDivGoldschmidtIters,proto3\" json:\"fxp_div_goldschmidt_iters,omitempty\"`\n\t// The exponent approximation method.\n\tFxpExpMode RuntimeConfig_ExpMode `protobuf:\"varint,51,opt,name=fxp_exp_mode,json=fxpExpMode,proto3,enum=spu.pb.RuntimeConfig_ExpMode\" json:\"fxp_exp_mode,omitempty\"`\n\t// Number of iterations of `exp` approximation, 0(default) indicates impl\n\t// defined.\n\tFxpExpIters int64 `protobuf:\"varint,52,opt,name=fxp_exp_iters,json=fxpExpIters,proto3\" json:\"fxp_exp_iters,omitempty\"`\n\t// The logarithm approximation method.\n\tFxpLogMode RuntimeConfig_LogMode `protobuf:\"varint,53,opt,name=fxp_log_mode,json=fxpLogMode,proto3,enum=spu.pb.RuntimeConfig_LogMode\" json:\"fxp_log_mode,omitempty\"`\n\t// Number of iterations of `log` approximation, 0(default) indicates\n\t// impl-defined.\n\tFxpLogIters int64 `protobuf:\"varint,54,opt,name=fxp_log_iters,json=fxpLogIters,proto3\" json:\"fxp_log_iters,omitempty\"`\n\t// Number of orders of `log` approximation, 0(default) indicates impl defined.\n\tFxpLogOrders int64 `protobuf:\"varint,55,opt,name=fxp_log_orders,json=fxpLogOrders,proto3\" json:\"fxp_log_orders,omitempty\"`\n\t// The sigmoid function approximation model.\n\tSigmoidMode RuntimeConfig_SigmoidMode `protobuf:\"varint,56,opt,name=sigmoid_mode,json=sigmoidMode,proto3,enum=spu.pb.RuntimeConfig_SigmoidMode\" json:\"sigmoid_mode,omitempty\"`\n\t// Enable a simpler rsqrt approximation\n\tEnableLowerAccuracyRsqrt bool `protobuf:\"varint,57,opt,name=enable_lower_accuracy_rsqrt,json=enableLowerAccuracyRsqrt,proto3\" json:\"enable_lower_accuracy_rsqrt,omitempty\"`\n\t// Sine/Cosine approximation iterations\n\tSineCosineIters int64 `protobuf:\"varint,58,opt,name=sine_cosine_iters,json=sineCosineIters,proto3\" json:\"sine_cosine_iters,omitempty\"`\n\t// beaver config, works for semi2k and spdz2k for now.\n\tBeaverType RuntimeConfig_BeaverType `protobuf:\"varint,70,opt,name=beaver_type,json=beaverType,proto3,enum=spu.pb.RuntimeConfig_BeaverType\" json:\"beaver_type,omitempty\"`\n\t// TrustedThirdParty configs.\n\tTtpBeaverConfig *TTPBeaverConfig `protobuf:\"bytes,71,opt,name=ttp_beaver_config,json=ttpBeaverConfig,proto3\" json:\"ttp_beaver_config,omitempty\"`\n\t// Cheetah 2PC configs.\n\tCheetah_2PcConfig *CheetahConfig `protobuf:\"bytes,72,opt,name=cheetah_2pc_config,json=cheetah2pcConfig,proto3\" json:\"cheetah_2pc_config,omitempty\"`\n\t// For protocol like SecureML, the most significant bit may have error with\n\t// low probability, which lead to huge calculation error.\n\tTruncAllowMsbError bool `protobuf:\"varint,73,opt,name=trunc_allow_msb_error,json=truncAllowMsbError,proto3\" json:\"trunc_allow_msb_error,omitempty\"`\n\t// Experimental: DO NOT USE\n\tExperimentalDisableMmulSplit bool `protobuf:\"varint,100,opt,name=experimental_disable_mmul_split,json=experimentalDisableMmulSplit,proto3\" json:\"experimental_disable_mmul_split,omitempty\"`\n\t// Inter op parallel, aka, DAG level parallel.\n\tExperimentalEnableInterOpPar bool `protobuf:\"varint,101,opt,name=experimental_enable_inter_op_par,json=experimentalEnableInterOpPar,proto3\" json:\"experimental_enable_inter_op_par,omitempty\"`\n\t// Intra op parallel, aka, hal/mpc level parallel.\n\tExperimentalEnableIntraOpPar bool `protobuf:\"varint,102,opt,name=experimental_enable_intra_op_par,json=experimentalEnableIntraOpPar,proto3\" json:\"experimental_enable_intra_op_par,omitempty\"`\n\t// Disable kernel level vectorization.\n\tExperimentalDisableVectorization bool `protobuf:\"varint,103,opt,name=experimental_disable_vectorization,json=experimentalDisableVectorization,proto3\" json:\"experimental_disable_vectorization,omitempty\"`\n\t// Inter op concurrency.\n\tExperimentalInterOpConcurrency uint64 `protobuf:\"varint,104,opt,name=experimental_inter_op_concurrency,json=experimentalInterOpConcurrency,proto3\" json:\"experimental_inter_op_concurrency,omitempty\"`\n\t// Enable use of private type\n\tExperimentalEnableColocatedOptimization bool `protobuf:\"varint,105,opt,name=experimental_enable_colocated_optimization,json=experimentalEnableColocatedOptimization,proto3\" json:\"experimental_enable_colocated_optimization,omitempty\"`\n\t// enable experimental exp prime method\n\tExperimentalEnableExpPrime bool `protobuf:\"varint,106,opt,name=experimental_enable_exp_prime,json=experimentalEnableExpPrime,proto3\" json:\"experimental_enable_exp_prime,omitempty\"`\n\t// The offset parameter for exp prime methods.\n\t// control the valid range of exp prime method.\n\t// valid range is:\n\t// ((47 - offset - 2fxp)/log_2(e), (125 - 2fxp - offset)/log_2(e))\n\t// clamp to value would be\n\t//\n\t//\tlower bound: (48 - offset - 2fxp)/log_2(e)\n\t//\thigher bound: (124 - 2fxp - offset)/log_2(e)\n\t//\n\t// default offset is 13, 0 offset is not supported.\n\tExperimentalExpPrimeOffset uint32 `protobuf:\"varint,107,opt,name=experimental_exp_prime_offset,json=experimentalExpPrimeOffset,proto3\" json:\"experimental_exp_prime_offset,omitempty\"`\n\t// whether to apply the clamping lower bound\n\t// default to enable it\n\tExperimentalExpPrimeDisableLowerBound bool `protobuf:\"varint,108,opt,name=experimental_exp_prime_disable_lower_bound,json=experimentalExpPrimeDisableLowerBound,proto3\" json:\"experimental_exp_prime_disable_lower_bound,omitempty\"`\n\t// whether to apply the clamping upper bound\n\t// default to disable it\n\tExperimentalExpPrimeEnableUpperBound bool `protobuf:\"varint,109,opt,name=experimental_exp_prime_enable_upper_bound,json=experimentalExpPrimeEnableUpperBound,proto3\" json:\"experimental_exp_prime_enable_upper_bound,omitempty\"`\n\tunknownFields                        protoimpl.UnknownFields\n\tsizeCache                            protoimpl.SizeCache\n}\n\nfunc (x *RuntimeConfig) Reset() {\n\t*x = RuntimeConfig{}\n\tmi := &file_libspu_spu_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RuntimeConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RuntimeConfig) ProtoMessage() {}\n\nfunc (x *RuntimeConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_libspu_spu_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RuntimeConfig.ProtoReflect.Descriptor instead.\nfunc (*RuntimeConfig) Descriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *RuntimeConfig) GetProtocol() ProtocolKind {\n\tif x != nil {\n\t\treturn x.Protocol\n\t}\n\treturn ProtocolKind_PROT_INVALID\n}\n\nfunc (x *RuntimeConfig) GetField() FieldType {\n\tif x != nil {\n\t\treturn x.Field\n\t}\n\treturn FieldType_FT_INVALID\n}\n\nfunc (x *RuntimeConfig) GetFxpFractionBits() int64 {\n\tif x != nil {\n\t\treturn x.FxpFractionBits\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetMaxConcurrency() int32 {\n\tif x != nil {\n\t\treturn x.MaxConcurrency\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetEnableActionTrace() bool {\n\tif x != nil {\n\t\treturn x.EnableActionTrace\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetEnableTypeChecker() bool {\n\tif x != nil {\n\t\treturn x.EnableTypeChecker\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetEnablePphloTrace() bool {\n\tif x != nil {\n\t\treturn x.EnablePphloTrace\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetEnableRuntimeSnapshot() bool {\n\tif x != nil {\n\t\treturn x.EnableRuntimeSnapshot\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetSnapshotDumpDir() string {\n\tif x != nil {\n\t\treturn x.SnapshotDumpDir\n\t}\n\treturn \"\"\n}\n\nfunc (x *RuntimeConfig) GetEnablePphloProfile() bool {\n\tif x != nil {\n\t\treturn x.EnablePphloProfile\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetEnableHalProfile() bool {\n\tif x != nil {\n\t\treturn x.EnableHalProfile\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetPublicRandomSeed() uint64 {\n\tif x != nil {\n\t\treturn x.PublicRandomSeed\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetShareMaxChunkSize() uint64 {\n\tif x != nil {\n\t\treturn x.ShareMaxChunkSize\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetSortMethod() RuntimeConfig_SortMethod {\n\tif x != nil {\n\t\treturn x.SortMethod\n\t}\n\treturn RuntimeConfig_SORT_DEFAULT\n}\n\nfunc (x *RuntimeConfig) GetQuickSortThreshold() int64 {\n\tif x != nil {\n\t\treturn x.QuickSortThreshold\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetFxpDivGoldschmidtIters() int64 {\n\tif x != nil {\n\t\treturn x.FxpDivGoldschmidtIters\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetFxpExpMode() RuntimeConfig_ExpMode {\n\tif x != nil {\n\t\treturn x.FxpExpMode\n\t}\n\treturn RuntimeConfig_EXP_DEFAULT\n}\n\nfunc (x *RuntimeConfig) GetFxpExpIters() int64 {\n\tif x != nil {\n\t\treturn x.FxpExpIters\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetFxpLogMode() RuntimeConfig_LogMode {\n\tif x != nil {\n\t\treturn x.FxpLogMode\n\t}\n\treturn RuntimeConfig_LOG_DEFAULT\n}\n\nfunc (x *RuntimeConfig) GetFxpLogIters() int64 {\n\tif x != nil {\n\t\treturn x.FxpLogIters\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetFxpLogOrders() int64 {\n\tif x != nil {\n\t\treturn x.FxpLogOrders\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetSigmoidMode() RuntimeConfig_SigmoidMode {\n\tif x != nil {\n\t\treturn x.SigmoidMode\n\t}\n\treturn RuntimeConfig_SIGMOID_DEFAULT\n}\n\nfunc (x *RuntimeConfig) GetEnableLowerAccuracyRsqrt() bool {\n\tif x != nil {\n\t\treturn x.EnableLowerAccuracyRsqrt\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetSineCosineIters() int64 {\n\tif x != nil {\n\t\treturn x.SineCosineIters\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetBeaverType() RuntimeConfig_BeaverType {\n\tif x != nil {\n\t\treturn x.BeaverType\n\t}\n\treturn RuntimeConfig_TrustedFirstParty\n}\n\nfunc (x *RuntimeConfig) GetTtpBeaverConfig() *TTPBeaverConfig {\n\tif x != nil {\n\t\treturn x.TtpBeaverConfig\n\t}\n\treturn nil\n}\n\nfunc (x *RuntimeConfig) GetCheetah_2PcConfig() *CheetahConfig {\n\tif x != nil {\n\t\treturn x.Cheetah_2PcConfig\n\t}\n\treturn nil\n}\n\nfunc (x *RuntimeConfig) GetTruncAllowMsbError() bool {\n\tif x != nil {\n\t\treturn x.TruncAllowMsbError\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetExperimentalDisableMmulSplit() bool {\n\tif x != nil {\n\t\treturn x.ExperimentalDisableMmulSplit\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetExperimentalEnableInterOpPar() bool {\n\tif x != nil {\n\t\treturn x.ExperimentalEnableInterOpPar\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetExperimentalEnableIntraOpPar() bool {\n\tif x != nil {\n\t\treturn x.ExperimentalEnableIntraOpPar\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetExperimentalDisableVectorization() bool {\n\tif x != nil {\n\t\treturn x.ExperimentalDisableVectorization\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetExperimentalInterOpConcurrency() uint64 {\n\tif x != nil {\n\t\treturn x.ExperimentalInterOpConcurrency\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetExperimentalEnableColocatedOptimization() bool {\n\tif x != nil {\n\t\treturn x.ExperimentalEnableColocatedOptimization\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetExperimentalEnableExpPrime() bool {\n\tif x != nil {\n\t\treturn x.ExperimentalEnableExpPrime\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetExperimentalExpPrimeOffset() uint32 {\n\tif x != nil {\n\t\treturn x.ExperimentalExpPrimeOffset\n\t}\n\treturn 0\n}\n\nfunc (x *RuntimeConfig) GetExperimentalExpPrimeDisableLowerBound() bool {\n\tif x != nil {\n\t\treturn x.ExperimentalExpPrimeDisableLowerBound\n\t}\n\treturn false\n}\n\nfunc (x *RuntimeConfig) GetExperimentalExpPrimeEnableUpperBound() bool {\n\tif x != nil {\n\t\treturn x.ExperimentalExpPrimeEnableUpperBound\n\t}\n\treturn false\n}\n\ntype ClientSSLConfig struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Certificate in PEM format, supported both file path and raw string\n\tCertificate string `protobuf:\"bytes,1,opt,name=certificate,proto3\" json:\"certificate,omitempty\"`\n\t// Private key in PEM format, supported both file path and raw string based on\n\t// prefix\n\tPrivateKey string `protobuf:\"bytes,2,opt,name=private_key,json=privateKey,proto3\" json:\"private_key,omitempty\"`\n\t// The trusted CA file to verify the peer's certificate\n\t// If empty, use the system default CA files\n\tCaFilePath string `protobuf:\"bytes,3,opt,name=ca_file_path,json=caFilePath,proto3\" json:\"ca_file_path,omitempty\"`\n\t// Maximum depth of the certificate chain for verification\n\t// If 0, turn off the verification\n\tVerifyDepth   int32 `protobuf:\"varint,4,opt,name=verify_depth,json=verifyDepth,proto3\" json:\"verify_depth,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ClientSSLConfig) Reset() {\n\t*x = ClientSSLConfig{}\n\tmi := &file_libspu_spu_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ClientSSLConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ClientSSLConfig) ProtoMessage() {}\n\nfunc (x *ClientSSLConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_libspu_spu_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ClientSSLConfig.ProtoReflect.Descriptor instead.\nfunc (*ClientSSLConfig) Descriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *ClientSSLConfig) GetCertificate() string {\n\tif x != nil {\n\t\treturn x.Certificate\n\t}\n\treturn \"\"\n}\n\nfunc (x *ClientSSLConfig) GetPrivateKey() string {\n\tif x != nil {\n\t\treturn x.PrivateKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *ClientSSLConfig) GetCaFilePath() string {\n\tif x != nil {\n\t\treturn x.CaFilePath\n\t}\n\treturn \"\"\n}\n\nfunc (x *ClientSSLConfig) GetVerifyDepth() int32 {\n\tif x != nil {\n\t\treturn x.VerifyDepth\n\t}\n\treturn 0\n}\n\ntype TTPBeaverConfig struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// TrustedThirdParty beaver server's remote ip:port or load-balance uri.\n\tServerHost string `protobuf:\"bytes,1,opt,name=server_host,json=serverHost,proto3\" json:\"server_host,omitempty\"`\n\t// which rank do adjust rpc call, usually choose the rank closer to the\n\t// server.\n\tAdjustRank int32 `protobuf:\"varint,2,opt,name=adjust_rank,json=adjustRank,proto3\" json:\"adjust_rank,omitempty\"`\n\t// asym_crypto_schema: support [\"SM2\"]\n\t// Will support 25519 in the future, after yacl supported it.\n\tAsymCryptoSchema string `protobuf:\"bytes,3,opt,name=asym_crypto_schema,json=asymCryptoSchema,proto3\" json:\"asym_crypto_schema,omitempty\"`\n\t// Server's public key in PEM format\n\tServerPublicKey string `protobuf:\"bytes,4,opt,name=server_public_key,json=serverPublicKey,proto3\" json:\"server_public_key,omitempty\"`\n\t// Transport protocol, support [\"http\", \"h2\"]\n\tTransportProtocol string `protobuf:\"bytes,5,opt,name=transport_protocol,json=transportProtocol,proto3\" json:\"transport_protocol,omitempty\"`\n\t// Configurations related to SSL\n\tSslConfig     *ClientSSLConfig `protobuf:\"bytes,6,opt,name=ssl_config,json=sslConfig,proto3\" json:\"ssl_config,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TTPBeaverConfig) Reset() {\n\t*x = TTPBeaverConfig{}\n\tmi := &file_libspu_spu_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TTPBeaverConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TTPBeaverConfig) ProtoMessage() {}\n\nfunc (x *TTPBeaverConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_libspu_spu_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TTPBeaverConfig.ProtoReflect.Descriptor instead.\nfunc (*TTPBeaverConfig) Descriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *TTPBeaverConfig) GetServerHost() string {\n\tif x != nil {\n\t\treturn x.ServerHost\n\t}\n\treturn \"\"\n}\n\nfunc (x *TTPBeaverConfig) GetAdjustRank() int32 {\n\tif x != nil {\n\t\treturn x.AdjustRank\n\t}\n\treturn 0\n}\n\nfunc (x *TTPBeaverConfig) GetAsymCryptoSchema() string {\n\tif x != nil {\n\t\treturn x.AsymCryptoSchema\n\t}\n\treturn \"\"\n}\n\nfunc (x *TTPBeaverConfig) GetServerPublicKey() string {\n\tif x != nil {\n\t\treturn x.ServerPublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *TTPBeaverConfig) GetTransportProtocol() string {\n\tif x != nil {\n\t\treturn x.TransportProtocol\n\t}\n\treturn \"\"\n}\n\nfunc (x *TTPBeaverConfig) GetSslConfig() *ClientSSLConfig {\n\tif x != nil {\n\t\treturn x.SslConfig\n\t}\n\treturn nil\n}\n\ntype CheetahConfig struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// disable the ciphertext packing for matmul\n\tDisableMatmulPack bool `protobuf:\"varint,1,opt,name=disable_matmul_pack,json=disableMatmulPack,proto3\" json:\"disable_matmul_pack,omitempty\"`\n\t// allow least significant bits error for point-wise mul\n\tEnableMulLsbError bool `protobuf:\"varint,2,opt,name=enable_mul_lsb_error,json=enableMulLsbError,proto3\" json:\"enable_mul_lsb_error,omitempty\"`\n\t// Setup for cheetah ot\n\tOtKind        CheetahOtKind `protobuf:\"varint,3,opt,name=ot_kind,json=otKind,proto3,enum=spu.pb.CheetahOtKind\" json:\"ot_kind,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CheetahConfig) Reset() {\n\t*x = CheetahConfig{}\n\tmi := &file_libspu_spu_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CheetahConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CheetahConfig) ProtoMessage() {}\n\nfunc (x *CheetahConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_libspu_spu_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CheetahConfig.ProtoReflect.Descriptor instead.\nfunc (*CheetahConfig) Descriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *CheetahConfig) GetDisableMatmulPack() bool {\n\tif x != nil {\n\t\treturn x.DisableMatmulPack\n\t}\n\treturn false\n}\n\nfunc (x *CheetahConfig) GetEnableMulLsbError() bool {\n\tif x != nil {\n\t\treturn x.EnableMulLsbError\n\t}\n\treturn false\n}\n\nfunc (x *CheetahConfig) GetOtKind() CheetahOtKind {\n\tif x != nil {\n\t\treturn x.OtKind\n\t}\n\treturn CheetahOtKind_YACL_Ferret\n}\n\ntype CompilationSource struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Input IR type\n\tIrType SourceIRType `protobuf:\"varint,1,opt,name=ir_type,json=irType,proto3,enum=spu.pb.SourceIRType\" json:\"ir_type,omitempty\"`\n\t// IR\n\tIrTxt []byte `protobuf:\"bytes,2,opt,name=ir_txt,json=irTxt,proto3\" json:\"ir_txt,omitempty\"`\n\t// Input visibilities\n\tInputVisibility []Visibility `protobuf:\"varint,3,rep,packed,name=input_visibility,json=inputVisibility,proto3,enum=spu.pb.Visibility\" json:\"input_visibility,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *CompilationSource) Reset() {\n\t*x = CompilationSource{}\n\tmi := &file_libspu_spu_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CompilationSource) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CompilationSource) ProtoMessage() {}\n\nfunc (x *CompilationSource) ProtoReflect() protoreflect.Message {\n\tmi := &file_libspu_spu_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CompilationSource.ProtoReflect.Descriptor instead.\nfunc (*CompilationSource) Descriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *CompilationSource) GetIrType() SourceIRType {\n\tif x != nil {\n\t\treturn x.IrType\n\t}\n\treturn SourceIRType_XLA\n}\n\nfunc (x *CompilationSource) GetIrTxt() []byte {\n\tif x != nil {\n\t\treturn x.IrTxt\n\t}\n\treturn nil\n}\n\nfunc (x *CompilationSource) GetInputVisibility() []Visibility {\n\tif x != nil {\n\t\treturn x.InputVisibility\n\t}\n\treturn nil\n}\n\ntype CompilerOptions struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Pretty print\n\tEnablePrettyPrint  bool               `protobuf:\"varint,1,opt,name=enable_pretty_print,json=enablePrettyPrint,proto3\" json:\"enable_pretty_print,omitempty\"`\n\tPrettyPrintDumpDir string             `protobuf:\"bytes,2,opt,name=pretty_print_dump_dir,json=prettyPrintDumpDir,proto3\" json:\"pretty_print_dump_dir,omitempty\"`\n\tXlaPpKind          XLAPrettyPrintKind `protobuf:\"varint,3,opt,name=xla_pp_kind,json=xlaPpKind,proto3,enum=spu.pb.XLAPrettyPrintKind\" json:\"xla_pp_kind,omitempty\"`\n\t// Disable sqrt(x) + eps to sqrt(x+eps) rewrite\n\tDisableSqrtPlusEpsilonRewrite bool `protobuf:\"varint,10,opt,name=disable_sqrt_plus_epsilon_rewrite,json=disableSqrtPlusEpsilonRewrite,proto3\" json:\"disable_sqrt_plus_epsilon_rewrite,omitempty\"`\n\t// Disable x/sqrt(y) to x*rsqrt(y) rewrite\n\tDisableDivSqrtRewrite bool `protobuf:\"varint,11,opt,name=disable_div_sqrt_rewrite,json=disableDivSqrtRewrite,proto3\" json:\"disable_div_sqrt_rewrite,omitempty\"`\n\t// Disable reduce truncation optimization\n\tDisableReduceTruncationOptimization bool `protobuf:\"varint,12,opt,name=disable_reduce_truncation_optimization,json=disableReduceTruncationOptimization,proto3\" json:\"disable_reduce_truncation_optimization,omitempty\"`\n\t// Disable maxpooling optimization\n\tDisableMaxpoolingOptimization bool `protobuf:\"varint,13,opt,name=disable_maxpooling_optimization,json=disableMaxpoolingOptimization,proto3\" json:\"disable_maxpooling_optimization,omitempty\"`\n\t// Disallow mix type operations\n\tDisallowMixTypesOpts bool `protobuf:\"varint,14,opt,name=disallow_mix_types_opts,json=disallowMixTypesOpts,proto3\" json:\"disallow_mix_types_opts,omitempty\"`\n\t// Disable SelectOp optimization\n\tDisableSelectOptimization bool `protobuf:\"varint,15,opt,name=disable_select_optimization,json=disableSelectOptimization,proto3\" json:\"disable_select_optimization,omitempty\"`\n\t// Enable optimize x/bcast(y) -> x * bcast(1/y)\n\tEnableOptimizeDenominatorWithBroadcast bool `protobuf:\"varint,16,opt,name=enable_optimize_denominator_with_broadcast,json=enableOptimizeDenominatorWithBroadcast,proto3\" json:\"enable_optimize_denominator_with_broadcast,omitempty\"`\n\t// Disable deallocation insertion pass\n\tDisableDeallocationInsertion bool `protobuf:\"varint,17,opt,name=disable_deallocation_insertion,json=disableDeallocationInsertion,proto3\" json:\"disable_deallocation_insertion,omitempty\"`\n\t// Disable sort->topk rewrite when only partial sort is required\n\tDisablePartialSortOptimization bool `protobuf:\"varint,28,opt,name=disable_partial_sort_optimization,json=disablePartialSortOptimization,proto3\" json:\"disable_partial_sort_optimization,omitempty\"`\n\tunknownFields                  protoimpl.UnknownFields\n\tsizeCache                      protoimpl.SizeCache\n}\n\nfunc (x *CompilerOptions) Reset() {\n\t*x = CompilerOptions{}\n\tmi := &file_libspu_spu_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CompilerOptions) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CompilerOptions) ProtoMessage() {}\n\nfunc (x *CompilerOptions) ProtoReflect() protoreflect.Message {\n\tmi := &file_libspu_spu_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CompilerOptions.ProtoReflect.Descriptor instead.\nfunc (*CompilerOptions) Descriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *CompilerOptions) GetEnablePrettyPrint() bool {\n\tif x != nil {\n\t\treturn x.EnablePrettyPrint\n\t}\n\treturn false\n}\n\nfunc (x *CompilerOptions) GetPrettyPrintDumpDir() string {\n\tif x != nil {\n\t\treturn x.PrettyPrintDumpDir\n\t}\n\treturn \"\"\n}\n\nfunc (x *CompilerOptions) GetXlaPpKind() XLAPrettyPrintKind {\n\tif x != nil {\n\t\treturn x.XlaPpKind\n\t}\n\treturn XLAPrettyPrintKind_TEXT\n}\n\nfunc (x *CompilerOptions) GetDisableSqrtPlusEpsilonRewrite() bool {\n\tif x != nil {\n\t\treturn x.DisableSqrtPlusEpsilonRewrite\n\t}\n\treturn false\n}\n\nfunc (x *CompilerOptions) GetDisableDivSqrtRewrite() bool {\n\tif x != nil {\n\t\treturn x.DisableDivSqrtRewrite\n\t}\n\treturn false\n}\n\nfunc (x *CompilerOptions) GetDisableReduceTruncationOptimization() bool {\n\tif x != nil {\n\t\treturn x.DisableReduceTruncationOptimization\n\t}\n\treturn false\n}\n\nfunc (x *CompilerOptions) GetDisableMaxpoolingOptimization() bool {\n\tif x != nil {\n\t\treturn x.DisableMaxpoolingOptimization\n\t}\n\treturn false\n}\n\nfunc (x *CompilerOptions) GetDisallowMixTypesOpts() bool {\n\tif x != nil {\n\t\treturn x.DisallowMixTypesOpts\n\t}\n\treturn false\n}\n\nfunc (x *CompilerOptions) GetDisableSelectOptimization() bool {\n\tif x != nil {\n\t\treturn x.DisableSelectOptimization\n\t}\n\treturn false\n}\n\nfunc (x *CompilerOptions) GetEnableOptimizeDenominatorWithBroadcast() bool {\n\tif x != nil {\n\t\treturn x.EnableOptimizeDenominatorWithBroadcast\n\t}\n\treturn false\n}\n\nfunc (x *CompilerOptions) GetDisableDeallocationInsertion() bool {\n\tif x != nil {\n\t\treturn x.DisableDeallocationInsertion\n\t}\n\treturn false\n}\n\nfunc (x *CompilerOptions) GetDisablePartialSortOptimization() bool {\n\tif x != nil {\n\t\treturn x.DisablePartialSortOptimization\n\t}\n\treturn false\n}\n\n// The executable format accepted by SPU runtime.\n//\n// - Inputs should be prepared before running executable.\n// - Output is maintained after execution, and can be fetched by output name.\n//\n// ```python\n//\n//\trt = spu.Runtime(...)            # create an spu runtime.\n//\trt.set_var('x', ...)             # set variable to the runtime.\n//\texe = spu.ExecutableProto(       # prepare the executable.\n//\t        name = 'balabala',\n//\t        input_names = ['x'],\n//\t        output_names = ['y'],\n//\t        code = ...)\n//\trt.run(exe)                      # run the executable.\n//\ty = rt.get_var('y')              # get the executable from spu runtime.\n//\n// ```\ntype ExecutableProto struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The name of the executable.\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// The input names.\n\tInputNames []string `protobuf:\"bytes,2,rep,name=input_names,json=inputNames,proto3\" json:\"input_names,omitempty\"`\n\t// The output names.\n\tOutputNames []string `protobuf:\"bytes,4,rep,name=output_names,json=outputNames,proto3\" json:\"output_names,omitempty\"`\n\t// The bytecode of the program, with format IR_MLIR_SPU.\n\tCode          []byte `protobuf:\"bytes,6,opt,name=code,proto3\" json:\"code,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ExecutableProto) Reset() {\n\t*x = ExecutableProto{}\n\tmi := &file_libspu_spu_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ExecutableProto) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ExecutableProto) ProtoMessage() {}\n\nfunc (x *ExecutableProto) ProtoReflect() protoreflect.Message {\n\tmi := &file_libspu_spu_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ExecutableProto.ProtoReflect.Descriptor instead.\nfunc (*ExecutableProto) Descriptor() ([]byte, []int) {\n\treturn file_libspu_spu_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *ExecutableProto) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *ExecutableProto) GetInputNames() []string {\n\tif x != nil {\n\t\treturn x.InputNames\n\t}\n\treturn nil\n}\n\nfunc (x *ExecutableProto) GetOutputNames() []string {\n\tif x != nil {\n\t\treturn x.OutputNames\n\t}\n\treturn nil\n}\n\nfunc (x *ExecutableProto) GetCode() []byte {\n\tif x != nil {\n\t\treturn x.Code\n\t}\n\treturn nil\n}\n\nvar File_libspu_spu_proto protoreflect.FileDescriptor\n\nvar file_libspu_spu_proto_rawDesc = []byte{\n\t0x0a, 0x10, 0x6c, 0x69, 0x62, 0x73, 0x70, 0x75, 0x2f, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x12, 0x06, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x22, 0x20, 0x0a, 0x0a, 0x53, 0x68,\n\t0x61, 0x70, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x69, 0x6d, 0x73,\n\t0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x04, 0x64, 0x69, 0x6d, 0x73, 0x22, 0xdf, 0x01, 0x0a,\n\t0x0e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12,\n\t0x2d, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x0e, 0x32, 0x10, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61,\n\t0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d,\n\t0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x12, 0x32, 0x0a,\n\t0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,\n\t0x0e, 0x32, 0x12, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x56, 0x69, 0x73, 0x69, 0x62,\n\t0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74,\n\t0x79, 0x12, 0x28, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x12, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x68, 0x61, 0x70, 0x65, 0x50,\n\t0x72, 0x6f, 0x74, 0x6f, 0x52, 0x05, 0x73, 0x68, 0x61, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73,\n\t0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x6f,\n\t0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x50, 0x72, 0x6f, 0x74,\n\t0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74,\n\t0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6f, 0x66, 0x66, 0x73,\n\t0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x4f,\n\t0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22,\n\t0xde, 0x14, 0x0a, 0x0d, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x12, 0x30, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x63, 0x6f, 0x6c, 0x12, 0x27, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0e, 0x32, 0x11, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x46, 0x69, 0x65, 0x6c,\n\t0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x2a, 0x0a, 0x11,\n\t0x66, 0x78, 0x70, 0x5f, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74,\n\t0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x66, 0x78, 0x70, 0x46, 0x72, 0x61, 0x63,\n\t0x74, 0x69, 0x6f, 0x6e, 0x42, 0x69, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f,\n\t0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28,\n\t0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63,\n\t0x79, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x63, 0x74, 0x69,\n\t0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11,\n\t0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x61, 0x63,\n\t0x65, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65,\n\t0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11,\n\t0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65,\n\t0x72, 0x12, 0x2c, 0x0a, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x70, 0x68, 0x6c,\n\t0x6f, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x65,\n\t0x6e, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x70, 0x68, 0x6c, 0x6f, 0x54, 0x72, 0x61, 0x63, 0x65, 0x12,\n\t0x36, 0x0a, 0x17, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,\n\t0x65, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x15, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x53,\n\t0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x6e, 0x61, 0x70, 0x73,\n\t0x68, 0x6f, 0x74, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x0e, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x0f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x44, 0x75, 0x6d, 0x70,\n\t0x44, 0x69, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x70,\n\t0x68, 0x6c, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28,\n\t0x08, 0x52, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x70, 0x68, 0x6c, 0x6f, 0x50, 0x72,\n\t0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f,\n\t0x68, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28,\n\t0x08, 0x52, 0x10, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x48, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x66,\n\t0x69, 0x6c, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x72, 0x61,\n\t0x6e, 0x64, 0x6f, 0x6d, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x04, 0x52,\n\t0x10, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x53, 0x65, 0x65,\n\t0x64, 0x12, 0x2f, 0x0a, 0x14, 0x73, 0x68, 0x61, 0x72, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x63,\n\t0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x04, 0x52,\n\t0x11, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x61, 0x78, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x53, 0x69,\n\t0x7a, 0x65, 0x12, 0x41, 0x0a, 0x0b, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f,\n\t0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62,\n\t0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x53,\n\t0x6f, 0x72, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0a, 0x73, 0x6f, 0x72, 0x74, 0x4d,\n\t0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x5f, 0x73,\n\t0x6f, 0x72, 0x74, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x16, 0x20,\n\t0x01, 0x28, 0x03, 0x52, 0x12, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x53, 0x6f, 0x72, 0x74, 0x54, 0x68,\n\t0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x39, 0x0a, 0x19, 0x66, 0x78, 0x70, 0x5f, 0x64,\n\t0x69, 0x76, 0x5f, 0x67, 0x6f, 0x6c, 0x64, 0x73, 0x63, 0x68, 0x6d, 0x69, 0x64, 0x74, 0x5f, 0x69,\n\t0x74, 0x65, 0x72, 0x73, 0x18, 0x32, 0x20, 0x01, 0x28, 0x03, 0x52, 0x16, 0x66, 0x78, 0x70, 0x44,\n\t0x69, 0x76, 0x47, 0x6f, 0x6c, 0x64, 0x73, 0x63, 0x68, 0x6d, 0x69, 0x64, 0x74, 0x49, 0x74, 0x65,\n\t0x72, 0x73, 0x12, 0x3f, 0x0a, 0x0c, 0x66, 0x78, 0x70, 0x5f, 0x65, 0x78, 0x70, 0x5f, 0x6d, 0x6f,\n\t0x64, 0x65, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70,\n\t0x62, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,\n\t0x45, 0x78, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x66, 0x78, 0x70, 0x45, 0x78, 0x70, 0x4d,\n\t0x6f, 0x64, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x66, 0x78, 0x70, 0x5f, 0x65, 0x78, 0x70, 0x5f, 0x69,\n\t0x74, 0x65, 0x72, 0x73, 0x18, 0x34, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x78, 0x70, 0x45,\n\t0x78, 0x70, 0x49, 0x74, 0x65, 0x72, 0x73, 0x12, 0x3f, 0x0a, 0x0c, 0x66, 0x78, 0x70, 0x5f, 0x6c,\n\t0x6f, 0x67, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x35, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e,\n\t0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4c, 0x6f, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x66, 0x78,\n\t0x70, 0x4c, 0x6f, 0x67, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x66, 0x78, 0x70, 0x5f,\n\t0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x74, 0x65, 0x72, 0x73, 0x18, 0x36, 0x20, 0x01, 0x28, 0x03, 0x52,\n\t0x0b, 0x66, 0x78, 0x70, 0x4c, 0x6f, 0x67, 0x49, 0x74, 0x65, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0e,\n\t0x66, 0x78, 0x70, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x73, 0x18, 0x37,\n\t0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x66, 0x78, 0x70, 0x4c, 0x6f, 0x67, 0x4f, 0x72, 0x64, 0x65,\n\t0x72, 0x73, 0x12, 0x44, 0x0a, 0x0c, 0x73, 0x69, 0x67, 0x6d, 0x6f, 0x69, 0x64, 0x5f, 0x6d, 0x6f,\n\t0x64, 0x65, 0x18, 0x38, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70,\n\t0x62, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,\n\t0x53, 0x69, 0x67, 0x6d, 0x6f, 0x69, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0b, 0x73, 0x69, 0x67,\n\t0x6d, 0x6f, 0x69, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x3d, 0x0a, 0x1b, 0x65, 0x6e, 0x61, 0x62,\n\t0x6c, 0x65, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x75, 0x72, 0x61, 0x63,\n\t0x79, 0x5f, 0x72, 0x73, 0x71, 0x72, 0x74, 0x18, 0x39, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x65,\n\t0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x41, 0x63, 0x63, 0x75, 0x72, 0x61,\n\t0x63, 0x79, 0x52, 0x73, 0x71, 0x72, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x69, 0x6e, 0x65, 0x5f,\n\t0x63, 0x6f, 0x73, 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x72, 0x73, 0x18, 0x3a, 0x20, 0x01,\n\t0x28, 0x03, 0x52, 0x0f, 0x73, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x73, 0x69, 0x6e, 0x65, 0x49, 0x74,\n\t0x65, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x0b, 0x62, 0x65, 0x61, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x79,\n\t0x70, 0x65, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70,\n\t0x62, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,\n\t0x42, 0x65, 0x61, 0x76, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x62, 0x65, 0x61, 0x76,\n\t0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x43, 0x0a, 0x11, 0x74, 0x74, 0x70, 0x5f, 0x62, 0x65,\n\t0x61, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x47, 0x20, 0x01, 0x28,\n\t0x0b, 0x32, 0x17, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x54, 0x50, 0x42, 0x65,\n\t0x61, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0f, 0x74, 0x74, 0x70, 0x42,\n\t0x65, 0x61, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x43, 0x0a, 0x12, 0x63,\n\t0x68, 0x65, 0x65, 0x74, 0x61, 0x68, 0x5f, 0x32, 0x70, 0x63, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,\n\t0x67, 0x18, 0x48, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62,\n\t0x2e, 0x43, 0x68, 0x65, 0x65, 0x74, 0x61, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10,\n\t0x63, 0x68, 0x65, 0x65, 0x74, 0x61, 0x68, 0x32, 0x70, 0x63, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x12, 0x31, 0x0a, 0x15, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f,\n\t0x6d, 0x73, 0x62, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x49, 0x20, 0x01, 0x28, 0x08, 0x52,\n\t0x12, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4d, 0x73, 0x62, 0x45, 0x72,\n\t0x72, 0x6f, 0x72, 0x12, 0x45, 0x0a, 0x1f, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e,\n\t0x74, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x6d, 0x75, 0x6c,\n\t0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x18, 0x64, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x65, 0x78,\n\t0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c,\n\t0x65, 0x4d, 0x6d, 0x75, 0x6c, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x12, 0x46, 0x0a, 0x20, 0x65, 0x78,\n\t0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c,\n\t0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x5f, 0x70, 0x61, 0x72, 0x18, 0x65,\n\t0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74,\n\t0x61, 0x6c, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x4f, 0x70, 0x50,\n\t0x61, 0x72, 0x12, 0x46, 0x0a, 0x20, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74,\n\t0x61, 0x6c, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x5f,\n\t0x6f, 0x70, 0x5f, 0x70, 0x61, 0x72, 0x18, 0x66, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1c, 0x65, 0x78,\n\t0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65,\n\t0x49, 0x6e, 0x74, 0x72, 0x61, 0x4f, 0x70, 0x50, 0x61, 0x72, 0x12, 0x4c, 0x0a, 0x22, 0x65, 0x78,\n\t0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62,\n\t0x6c, 0x65, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,\n\t0x18, 0x67, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65,\n\t0x6e, 0x74, 0x61, 0x6c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x65, 0x63, 0x74, 0x6f,\n\t0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x21, 0x65, 0x78, 0x70, 0x65,\n\t0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x5f, 0x6f,\n\t0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x68, 0x20,\n\t0x01, 0x28, 0x04, 0x52, 0x1e, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61,\n\t0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x4f, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65,\n\t0x6e, 0x63, 0x79, 0x12, 0x5b, 0x0a, 0x2a, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e,\n\t0x74, 0x61, 0x6c, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x63,\n\t0x61, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x18, 0x69, 0x20, 0x01, 0x28, 0x08, 0x52, 0x27, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d,\n\t0x65, 0x6e, 0x74, 0x61, 0x6c, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6f, 0x63,\n\t0x61, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,\n\t0x12, 0x41, 0x0a, 0x1d, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c,\n\t0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x65, 0x78, 0x70, 0x5f, 0x70, 0x72, 0x69, 0x6d,\n\t0x65, 0x18, 0x6a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d,\n\t0x65, 0x6e, 0x74, 0x61, 0x6c, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x78, 0x70, 0x50, 0x72,\n\t0x69, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x1d, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e,\n\t0x74, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x70, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x5f, 0x6f, 0x66,\n\t0x66, 0x73, 0x65, 0x74, 0x18, 0x6b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1a, 0x65, 0x78, 0x70, 0x65,\n\t0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x50, 0x72, 0x69, 0x6d, 0x65,\n\t0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x59, 0x0a, 0x2a, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69,\n\t0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x70, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x65,\n\t0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x62,\n\t0x6f, 0x75, 0x6e, 0x64, 0x18, 0x6c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x25, 0x65, 0x78, 0x70, 0x65,\n\t0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x45, 0x78, 0x70, 0x50, 0x72, 0x69, 0x6d, 0x65,\n\t0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x42, 0x6f, 0x75, 0x6e,\n\t0x64, 0x12, 0x57, 0x0a, 0x29, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61,\n\t0x6c, 0x5f, 0x65, 0x78, 0x70, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x5f, 0x65, 0x6e, 0x61, 0x62,\n\t0x6c, 0x65, 0x5f, 0x75, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x6d,\n\t0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74,\n\t0x61, 0x6c, 0x45, 0x78, 0x70, 0x50, 0x72, 0x69, 0x6d, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65,\n\t0x55, 0x70, 0x70, 0x65, 0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x50, 0x0a, 0x0a, 0x53, 0x6f,\n\t0x72, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x4f, 0x52, 0x54,\n\t0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x4f,\n\t0x52, 0x54, 0x5f, 0x52, 0x41, 0x44, 0x49, 0x58, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x4f,\n\t0x52, 0x54, 0x5f, 0x51, 0x55, 0x49, 0x43, 0x4b, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x4f,\n\t0x52, 0x54, 0x5f, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x10, 0x03, 0x22, 0x47, 0x0a, 0x07,\n\t0x45, 0x78, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x58, 0x50, 0x5f, 0x44,\n\t0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x58, 0x50, 0x5f,\n\t0x50, 0x41, 0x44, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x58, 0x50, 0x5f, 0x54, 0x41,\n\t0x59, 0x4c, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x58, 0x50, 0x5f, 0x50, 0x52,\n\t0x49, 0x4d, 0x45, 0x10, 0x03, 0x22, 0x48, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x4d, 0x6f, 0x64, 0x65,\n\t0x12, 0x0f, 0x0a, 0x0b, 0x4c, 0x4f, 0x47, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10,\n\t0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x4f, 0x47, 0x5f, 0x50, 0x41, 0x44, 0x45, 0x10, 0x01, 0x12,\n\t0x0e, 0x0a, 0x0a, 0x4c, 0x4f, 0x47, 0x5f, 0x4e, 0x45, 0x57, 0x54, 0x4f, 0x4e, 0x10, 0x02, 0x12,\n\t0x0e, 0x0a, 0x0a, 0x4c, 0x4f, 0x47, 0x5f, 0x4d, 0x49, 0x4e, 0x4d, 0x41, 0x58, 0x10, 0x03, 0x22,\n\t0x57, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6d, 0x6f, 0x69, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x13,\n\t0x0a, 0x0f, 0x53, 0x49, 0x47, 0x4d, 0x4f, 0x49, 0x44, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c,\n\t0x54, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x49, 0x47, 0x4d, 0x4f, 0x49, 0x44, 0x5f, 0x4d,\n\t0x4d, 0x31, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x49, 0x47, 0x4d, 0x4f, 0x49, 0x44, 0x5f,\n\t0x53, 0x45, 0x47, 0x33, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x49, 0x47, 0x4d, 0x4f, 0x49,\n\t0x44, 0x5f, 0x52, 0x45, 0x41, 0x4c, 0x10, 0x03, 0x22, 0x4a, 0x0a, 0x0a, 0x42, 0x65, 0x61, 0x76,\n\t0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65,\n\t0x64, 0x46, 0x69, 0x72, 0x73, 0x74, 0x50, 0x61, 0x72, 0x74, 0x79, 0x10, 0x00, 0x12, 0x15, 0x0a,\n\t0x11, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72,\n\t0x74, 0x79, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x50, 0x61, 0x72,\n\t0x74, 0x79, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, 0x08, 0x12, 0x10, 0x13,\n\t0x22, 0x99, 0x01, 0x0a, 0x0f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x53, 0x4c, 0x43, 0x6f,\n\t0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,\n\t0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69,\n\t0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,\n\t0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69,\n\t0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0c, 0x63, 0x61, 0x5f, 0x66, 0x69,\n\t0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63,\n\t0x61, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x76, 0x65, 0x72,\n\t0x69, 0x66, 0x79, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52,\n\t0x0b, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x44, 0x65, 0x70, 0x74, 0x68, 0x22, 0x94, 0x02, 0x0a,\n\t0x0f, 0x54, 0x54, 0x50, 0x42, 0x65, 0x61, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,\n\t0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x48, 0x6f, 0x73,\n\t0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x6b,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x52, 0x61,\n\t0x6e, 0x6b, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x73, 0x79, 0x6d, 0x5f, 0x63, 0x72, 0x79, 0x70, 0x74,\n\t0x6f, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10,\n\t0x61, 0x73, 0x79, 0x6d, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61,\n\t0x12, 0x2a, 0x0a, 0x11, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69,\n\t0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x72,\n\t0x76, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x12,\n\t0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,\n\t0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,\n\t0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x36, 0x0a, 0x0a, 0x73,\n\t0x73, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x17, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53,\n\t0x53, 0x4c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x73, 0x73, 0x6c, 0x43, 0x6f, 0x6e,\n\t0x66, 0x69, 0x67, 0x22, 0xa0, 0x01, 0x0a, 0x0d, 0x43, 0x68, 0x65, 0x65, 0x74, 0x61, 0x68, 0x43,\n\t0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,\n\t0x5f, 0x6d, 0x61, 0x74, 0x6d, 0x75, 0x6c, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61, 0x74, 0x6d, 0x75,\n\t0x6c, 0x50, 0x61, 0x63, 0x6b, 0x12, 0x2f, 0x0a, 0x14, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f,\n\t0x6d, 0x75, 0x6c, 0x5f, 0x6c, 0x73, 0x62, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20,\n\t0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x75, 0x6c, 0x4c, 0x73,\n\t0x62, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x74, 0x5f, 0x6b, 0x69, 0x6e,\n\t0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x73, 0x70, 0x75, 0x2e, 0x70, 0x62,\n\t0x2e, 0x43, 0x68, 0x65, 0x65, 0x74, 0x61, 0x68, 0x4f, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x06,\n\t0x6f, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x22, 0x98, 0x01, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x69,\n\t0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2d, 0x0a, 0x07,\n\t0x69, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e,\n\t0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x52, 0x54,\n\t0x79, 0x70, 0x65, 0x52, 0x06, 0x69, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x69,\n\t0x72, 0x5f, 0x74, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x72, 0x54,\n\t0x78, 0x74, 0x12, 0x3d, 0x0a, 0x10, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x76, 0x69, 0x73, 0x69,\n\t0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x73,\n\t0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79,\n\t0x52, 0x0f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74,\n\t0x79, 0x22, 0xb4, 0x06, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x4f, 0x70,\n\t0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f,\n\t0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79,\n\t0x50, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x15, 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x5f,\n\t0x70, 0x72, 0x69, 0x6e, 0x74, 0x5f, 0x64, 0x75, 0x6d, 0x70, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x50, 0x72, 0x69, 0x6e,\n\t0x74, 0x44, 0x75, 0x6d, 0x70, 0x44, 0x69, 0x72, 0x12, 0x3a, 0x0a, 0x0b, 0x78, 0x6c, 0x61, 0x5f,\n\t0x70, 0x70, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e,\n\t0x73, 0x70, 0x75, 0x2e, 0x70, 0x62, 0x2e, 0x58, 0x4c, 0x41, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79,\n\t0x50, 0x72, 0x69, 0x6e, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x09, 0x78, 0x6c, 0x61, 0x50, 0x70,\n\t0x4b, 0x69, 0x6e, 0x64, 0x12, 0x48, 0x0a, 0x21, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f,\n\t0x73, 0x71, 0x72, 0x74, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x65, 0x70, 0x73, 0x69, 0x6c, 0x6f,\n\t0x6e, 0x5f, 0x72, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52,\n\t0x1d, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x71, 0x72, 0x74, 0x50, 0x6c, 0x75, 0x73,\n\t0x45, 0x70, 0x73, 0x69, 0x6c, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x12, 0x37,\n\t0x0a, 0x18, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x76, 0x5f, 0x73, 0x71,\n\t0x72, 0x74, 0x5f, 0x72, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x15, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x69, 0x76, 0x53, 0x71, 0x72, 0x74,\n\t0x52, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x12, 0x53, 0x0a, 0x26, 0x64, 0x69, 0x73, 0x61, 0x62,\n\t0x6c, 0x65, 0x5f, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x5f, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,\n\t0x52, 0x65, 0x64, 0x75, 0x63, 0x65, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,\n\t0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x1f,\n\t0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x61, 0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x69,\n\t0x6e, 0x67, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,\n\t0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x61,\n\t0x78, 0x70, 0x6f, 0x6f, 0x6c, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x17, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77,\n\t0x5f, 0x6d, 0x69, 0x78, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x5f, 0x6f, 0x70, 0x74, 0x73, 0x18,\n\t0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4d,\n\t0x69, 0x78, 0x54, 0x79, 0x70, 0x65, 0x73, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x3e, 0x0a, 0x1b, 0x64,\n\t0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x5f, 0x6f, 0x70,\n\t0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08,\n\t0x52, 0x19, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x4f,\n\t0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x2a, 0x65,\n\t0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x64,\n\t0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f,\n\t0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52,\n\t0x26, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x44,\n\t0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x74, 0x68, 0x42, 0x72,\n\t0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x1e, 0x64, 0x69, 0x73, 0x61, 0x62,\n\t0x6c, 0x65, 0x5f, 0x64, 0x65, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,\n\t0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52,\n\t0x1c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x65, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a,\n\t0x21, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c,\n\t0x5f, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69,\n\t0x6f, 0x6e, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,\n\t0x65, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x74, 0x69,\n\t0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x7d, 0x0a, 0x0f, 0x45, 0x78, 0x65, 0x63,\n\t0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e,\n\t0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,\n\t0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02,\n\t0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73,\n\t0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73,\n\t0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4e, 0x61,\n\t0x6d, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28,\n\t0x0c, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x2a, 0xa7, 0x01, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61,\n\t0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x54, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c,\n\t0x49, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x54, 0x5f, 0x49, 0x31, 0x10, 0x01, 0x12,\n\t0x09, 0x0a, 0x05, 0x44, 0x54, 0x5f, 0x49, 0x38, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x54,\n\t0x5f, 0x55, 0x38, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x54, 0x5f, 0x49, 0x31, 0x36, 0x10,\n\t0x04, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x54, 0x5f, 0x55, 0x31, 0x36, 0x10, 0x05, 0x12, 0x0a, 0x0a,\n\t0x06, 0x44, 0x54, 0x5f, 0x49, 0x33, 0x32, 0x10, 0x06, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x54, 0x5f,\n\t0x55, 0x33, 0x32, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x54, 0x5f, 0x49, 0x36, 0x34, 0x10,\n\t0x08, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x54, 0x5f, 0x55, 0x36, 0x34, 0x10, 0x09, 0x12, 0x0a, 0x0a,\n\t0x06, 0x44, 0x54, 0x5f, 0x46, 0x31, 0x36, 0x10, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x54, 0x5f,\n\t0x46, 0x33, 0x32, 0x10, 0x0b, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x54, 0x5f, 0x46, 0x36, 0x34, 0x10,\n\t0x0c, 0x2a, 0x4e, 0x0a, 0x0a, 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12,\n\t0x0f, 0x0a, 0x0b, 0x56, 0x49, 0x53, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00,\n\t0x12, 0x0e, 0x0a, 0x0a, 0x56, 0x49, 0x53, 0x5f, 0x53, 0x45, 0x43, 0x52, 0x45, 0x54, 0x10, 0x01,\n\t0x12, 0x0e, 0x0a, 0x0a, 0x56, 0x49, 0x53, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02,\n\t0x12, 0x0f, 0x0a, 0x0b, 0x56, 0x49, 0x53, 0x5f, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x10,\n\t0x03, 0x2a, 0xd9, 0x01, 0x0a, 0x06, 0x50, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x0a,\n\t0x50, 0x54, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05,\n\t0x50, 0x54, 0x5f, 0x49, 0x38, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x54, 0x5f, 0x55, 0x38,\n\t0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x54, 0x5f, 0x49, 0x31, 0x36, 0x10, 0x03, 0x12, 0x0a,\n\t0x0a, 0x06, 0x50, 0x54, 0x5f, 0x55, 0x31, 0x36, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x54,\n\t0x5f, 0x49, 0x33, 0x32, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x54, 0x5f, 0x55, 0x33, 0x32,\n\t0x10, 0x06, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x54, 0x5f, 0x49, 0x36, 0x34, 0x10, 0x07, 0x12, 0x0a,\n\t0x0a, 0x06, 0x50, 0x54, 0x5f, 0x55, 0x36, 0x34, 0x10, 0x08, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x54,\n\t0x5f, 0x49, 0x31, 0x32, 0x38, 0x10, 0x09, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x54, 0x5f, 0x55, 0x31,\n\t0x32, 0x38, 0x10, 0x0a, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x54, 0x5f, 0x49, 0x31, 0x10, 0x0b, 0x12,\n\t0x0a, 0x0a, 0x06, 0x50, 0x54, 0x5f, 0x46, 0x31, 0x36, 0x10, 0x1e, 0x12, 0x0a, 0x0a, 0x06, 0x50,\n\t0x54, 0x5f, 0x46, 0x33, 0x32, 0x10, 0x1f, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x54, 0x5f, 0x46, 0x36,\n\t0x34, 0x10, 0x20, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x54, 0x5f, 0x43, 0x46, 0x33, 0x32, 0x10, 0x32,\n\t0x12, 0x0b, 0x0a, 0x07, 0x50, 0x54, 0x5f, 0x43, 0x46, 0x36, 0x34, 0x10, 0x33, 0x2a, 0x3a, 0x0a,\n\t0x09, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x54,\n\t0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x4d,\n\t0x33, 0x32, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, 0x09,\n\t0x0a, 0x05, 0x46, 0x4d, 0x31, 0x32, 0x38, 0x10, 0x03, 0x2a, 0x67, 0x0a, 0x0c, 0x50, 0x72, 0x6f,\n\t0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x52, 0x4f,\n\t0x54, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52,\n\t0x45, 0x46, 0x32, 0x4b, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x4d, 0x49, 0x32, 0x4b,\n\t0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x42, 0x59, 0x33, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07,\n\t0x43, 0x48, 0x45, 0x45, 0x54, 0x41, 0x48, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x45, 0x43,\n\t0x55, 0x52, 0x45, 0x4e, 0x4e, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x57, 0x49, 0x46, 0x54,\n\t0x10, 0x06, 0x2a, 0x45, 0x0a, 0x0d, 0x43, 0x68, 0x65, 0x65, 0x74, 0x61, 0x68, 0x4f, 0x74, 0x4b,\n\t0x69, 0x6e, 0x64, 0x12, 0x0f, 0x0a, 0x0b, 0x59, 0x41, 0x43, 0x4c, 0x5f, 0x46, 0x65, 0x72, 0x72,\n\t0x65, 0x74, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x59, 0x41, 0x43, 0x4c, 0x5f, 0x53, 0x6f, 0x66,\n\t0x74, 0x73, 0x70, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x4d, 0x50,\n\t0x5f, 0x46, 0x65, 0x72, 0x72, 0x65, 0x74, 0x10, 0x02, 0x2a, 0x26, 0x0a, 0x0c, 0x53, 0x6f, 0x75,\n\t0x72, 0x63, 0x65, 0x49, 0x52, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x58, 0x4c, 0x41,\n\t0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x48, 0x4c, 0x4f, 0x10,\n\t0x01, 0x2a, 0x31, 0x0a, 0x12, 0x58, 0x4c, 0x41, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x50, 0x72,\n\t0x69, 0x6e, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x45, 0x58, 0x54, 0x10,\n\t0x00, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x4f, 0x54, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54,\n\t0x4d, 0x4c, 0x10, 0x02, 0x42, 0x14, 0x0a, 0x12, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x65, 0x63, 0x72,\n\t0x65, 0x74, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x73, 0x70, 0x75, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x33,\n}\n\nvar (\n\tfile_libspu_spu_proto_rawDescOnce sync.Once\n\tfile_libspu_spu_proto_rawDescData = file_libspu_spu_proto_rawDesc\n)\n\nfunc file_libspu_spu_proto_rawDescGZIP() []byte {\n\tfile_libspu_spu_proto_rawDescOnce.Do(func() {\n\t\tfile_libspu_spu_proto_rawDescData = protoimpl.X.CompressGZIP(file_libspu_spu_proto_rawDescData)\n\t})\n\treturn file_libspu_spu_proto_rawDescData\n}\n\nvar file_libspu_spu_proto_enumTypes = make([]protoimpl.EnumInfo, 13)\nvar file_libspu_spu_proto_msgTypes = make([]protoimpl.MessageInfo, 10)\nvar file_libspu_spu_proto_goTypes = []any{\n\t(DataType)(0),                  // 0: spu.pb.DataType\n\t(Visibility)(0),                // 1: spu.pb.Visibility\n\t(PtType)(0),                    // 2: spu.pb.PtType\n\t(FieldType)(0),                 // 3: spu.pb.FieldType\n\t(ProtocolKind)(0),              // 4: spu.pb.ProtocolKind\n\t(CheetahOtKind)(0),             // 5: spu.pb.CheetahOtKind\n\t(SourceIRType)(0),              // 6: spu.pb.SourceIRType\n\t(XLAPrettyPrintKind)(0),        // 7: spu.pb.XLAPrettyPrintKind\n\t(RuntimeConfig_SortMethod)(0),  // 8: spu.pb.RuntimeConfig.SortMethod\n\t(RuntimeConfig_ExpMode)(0),     // 9: spu.pb.RuntimeConfig.ExpMode\n\t(RuntimeConfig_LogMode)(0),     // 10: spu.pb.RuntimeConfig.LogMode\n\t(RuntimeConfig_SigmoidMode)(0), // 11: spu.pb.RuntimeConfig.SigmoidMode\n\t(RuntimeConfig_BeaverType)(0),  // 12: spu.pb.RuntimeConfig.BeaverType\n\t(*ShapeProto)(nil),             // 13: spu.pb.ShapeProto\n\t(*ValueMetaProto)(nil),         // 14: spu.pb.ValueMetaProto\n\t(*ValueChunkProto)(nil),        // 15: spu.pb.ValueChunkProto\n\t(*RuntimeConfig)(nil),          // 16: spu.pb.RuntimeConfig\n\t(*ClientSSLConfig)(nil),        // 17: spu.pb.ClientSSLConfig\n\t(*TTPBeaverConfig)(nil),        // 18: spu.pb.TTPBeaverConfig\n\t(*CheetahConfig)(nil),          // 19: spu.pb.CheetahConfig\n\t(*CompilationSource)(nil),      // 20: spu.pb.CompilationSource\n\t(*CompilerOptions)(nil),        // 21: spu.pb.CompilerOptions\n\t(*ExecutableProto)(nil),        // 22: spu.pb.ExecutableProto\n}\nvar file_libspu_spu_proto_depIdxs = []int32{\n\t0,  // 0: spu.pb.ValueMetaProto.data_type:type_name -> spu.pb.DataType\n\t1,  // 1: spu.pb.ValueMetaProto.visibility:type_name -> spu.pb.Visibility\n\t13, // 2: spu.pb.ValueMetaProto.shape:type_name -> spu.pb.ShapeProto\n\t4,  // 3: spu.pb.RuntimeConfig.protocol:type_name -> spu.pb.ProtocolKind\n\t3,  // 4: spu.pb.RuntimeConfig.field:type_name -> spu.pb.FieldType\n\t8,  // 5: spu.pb.RuntimeConfig.sort_method:type_name -> spu.pb.RuntimeConfig.SortMethod\n\t9,  // 6: spu.pb.RuntimeConfig.fxp_exp_mode:type_name -> spu.pb.RuntimeConfig.ExpMode\n\t10, // 7: spu.pb.RuntimeConfig.fxp_log_mode:type_name -> spu.pb.RuntimeConfig.LogMode\n\t11, // 8: spu.pb.RuntimeConfig.sigmoid_mode:type_name -> spu.pb.RuntimeConfig.SigmoidMode\n\t12, // 9: spu.pb.RuntimeConfig.beaver_type:type_name -> spu.pb.RuntimeConfig.BeaverType\n\t18, // 10: spu.pb.RuntimeConfig.ttp_beaver_config:type_name -> spu.pb.TTPBeaverConfig\n\t19, // 11: spu.pb.RuntimeConfig.cheetah_2pc_config:type_name -> spu.pb.CheetahConfig\n\t17, // 12: spu.pb.TTPBeaverConfig.ssl_config:type_name -> spu.pb.ClientSSLConfig\n\t5,  // 13: spu.pb.CheetahConfig.ot_kind:type_name -> spu.pb.CheetahOtKind\n\t6,  // 14: spu.pb.CompilationSource.ir_type:type_name -> spu.pb.SourceIRType\n\t1,  // 15: spu.pb.CompilationSource.input_visibility:type_name -> spu.pb.Visibility\n\t7,  // 16: spu.pb.CompilerOptions.xla_pp_kind:type_name -> spu.pb.XLAPrettyPrintKind\n\t17, // [17:17] is the sub-list for method output_type\n\t17, // [17:17] is the sub-list for method input_type\n\t17, // [17:17] is the sub-list for extension type_name\n\t17, // [17:17] is the sub-list for extension extendee\n\t0,  // [0:17] is the sub-list for field type_name\n}\n\nfunc init() { file_libspu_spu_proto_init() }\nfunc file_libspu_spu_proto_init() {\n\tif File_libspu_spu_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_libspu_spu_proto_rawDesc,\n\t\t\tNumEnums:      13,\n\t\t\tNumMessages:   10,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_libspu_spu_proto_goTypes,\n\t\tDependencyIndexes: file_libspu_spu_proto_depIdxs,\n\t\tEnumInfos:         file_libspu_spu_proto_enumTypes,\n\t\tMessageInfos:      file_libspu_spu_proto_msgTypes,\n\t}.Build()\n\tFile_libspu_spu_proto = out.File\n\tfile_libspu_spu_proto_rawDesc = nil\n\tfile_libspu_spu_proto_goTypes = nil\n\tfile_libspu_spu_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/sessionctx/context.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage sessionctx\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/sessionctx/variable\"\n)\n\n// Context is an interface for transaction and executive args environment.\ntype Context interface {\n\tGetSessionVars() *variable.SessionVars\n\n\t// SetValue saves a value associated with this context for key.\n\tSetValue(key fmt.Stringer, value interface{})\n\n\t// Value returns the value associated with this context for key.\n\tValue(key fmt.Stringer) interface{}\n}\n\ntype BaseContext struct {\n\tvalues      map[fmt.Stringer]interface{}\n\tsessionVars *variable.SessionVars\n\tctx         context.Context\n\tcancel      context.CancelFunc\n}\n\n// NewContext creates a new mocked sessionctx.Context.\nfunc NewContext() *BaseContext {\n\tctx, cancel := context.WithCancel(context.Background())\n\tsctx := &BaseContext{\n\t\tvalues:      make(map[fmt.Stringer]interface{}),\n\t\tsessionVars: variable.NewSessionVars(),\n\t\tctx:         ctx,\n\t\tcancel:      cancel,\n\t}\n\treturn sctx\n}\n\n// GetSessionVars implements the sessionctx.Context GetSessionVars interface.\nfunc (c *BaseContext) GetSessionVars() *variable.SessionVars {\n\treturn c.sessionVars\n}\n\n// SetValue implements sessionctx.Context SetValue interface.\nfunc (c *BaseContext) SetValue(key fmt.Stringer, value interface{}) {\n\tc.values[key] = value\n}\n\n// Value implements sessionctx.Context Value interface.\nfunc (c *BaseContext) Value(key fmt.Stringer) interface{} {\n\tvalue := c.values[key]\n\treturn value\n}\n"
  },
  {
    "path": "pkg/sessionctx/stmtctx/stmtctx.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage stmtctx\n\nimport (\n\t\"math\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/secretflow/scql/pkg/util/execdetails\"\n)\n\nconst (\n\t// WarnLevelError represents level \"Error\" for 'SHOW WARNINGS' syntax.\n\tWarnLevelError = \"Error\"\n\t// WarnLevelWarning represents level \"Warning\" for 'SHOW WARNINGS' syntax.\n\tWarnLevelWarning = \"Warning\"\n\t// WarnLevelNote represents level \"Note\" for 'SHOW WARNINGS' syntax.\n\tWarnLevelNote = \"Note\"\n)\n\n// SQLWarn relates a sql warning and it's level.\ntype SQLWarn struct {\n\tLevel string\n\tErr   error\n}\n\n// StatementContext contains variables for a statement.\n// It should be reset before executing a statement.\ntype StatementContext struct {\n\t// IsDDLJobInQueue is used to mark whether the DDL job is put into the queue.\n\t// If IsDDLJobInQueue is true, it means the DDL job is in the queue of storage, and it can be handled by the DDL worker.\n\tIsDDLJobInQueue  bool\n\tInInsertStmt     bool\n\tInUpdateStmt     bool\n\tInDeleteStmt     bool\n\tIgnoreTruncate   bool\n\tIgnoreZeroInDate bool\n\tAllowInvalidDate bool\n\tUseCache         bool\n\n\tRuntimeStatsColl *execdetails.RuntimeStatsColl\n\n\t// mu struct holds variables that change during execution.\n\tmu struct {\n\t\tsync.Mutex\n\n\t\twarnings []SQLWarn\n\t}\n\n\tTimeZone *time.Location\n}\n\n// TableEntry presents table in db.\ntype TableEntry struct {\n\tDB    string\n\tTable string\n}\n\n// HandleTruncate ignores or returns the error based on the StatementContext state.\nfunc (sc *StatementContext) HandleTruncate(err error) error {\n\t// TODO(teng.t): Revisit logic here.\n\treturn err\n}\n\n// HandleOverflow treats ErrOverflow as warnings or returns the error based on the StmtCtx.OverflowAsWarning state.\nfunc (sc *StatementContext) HandleOverflow(err error, warnErr error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\treturn err\n}\n\n// AppendWarning appends a warning with level 'Warning'.\nfunc (sc *StatementContext) AppendWarning(warn error) {\n\tsc.mu.Lock()\n\tif len(sc.mu.warnings) < math.MaxUint16 {\n\t\tsc.mu.warnings = append(sc.mu.warnings, SQLWarn{WarnLevelWarning, warn})\n\t}\n\tsc.mu.Unlock()\n}\n"
  },
  {
    "path": "pkg/sessionctx/variable/session.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage variable\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"gorm.io/gorm\"\n\n\t\"github.com/secretflow/scql/pkg/parser/auth\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\nconst (\n\tMaxAllowedPacket = \"max_allowed_packet\"\n)\n\n// SessionVars is to handle user-defined or global variables in the current session.\ntype SessionVars struct {\n\t// systems variables, don't modify it directly, use GetSystemVar/SetSystemVar method.\n\tsystems map[string]string\n\t// SysWarningCount is the system variable \"warning_count\", because it is on the hot path, so we extract it from the systems\n\tSysWarningCount int\n\t// SysErrorCount is the system variable \"error_count\", because it is on the hot path, so we extract it from the systems\n\tSysErrorCount uint16\n\n\t// StrictSQLMode indicates if the session is in strict mode.\n\tStrictSQLMode bool\n\n\t// ActiveRoles stores active roles for current user\n\tActiveRoles []*auth.RoleIdentity\n\n\t// Status stands for the session status. e.g. in transaction or not, auto commit is on or off, and so on.\n\tStatus uint16\n\n\t// User is the user identity with which the session login.\n\tUser *auth.UserIdentity\n\n\t// CurrentDB is the default database of this session.\n\tCurrentDB string\n\n\t// PlanID is the unique id of logical and physical plan.\n\tPlanID int\n\n\t// StmtCtx holds variables for current executing statement.\n\tStmtCtx *stmtctx.StatementContext\n\n\t// PlanColumnID is the unique id for column when building plan.\n\tPlanColumnID int64\n\n\t// SnapshotTS is used for reading history data.\n\tSnapshotTS uint64\n\n\t// SnapshotInfoschema is used with SnapshotTS, when the schema version at snapshotTS less than current schema\n\t// version, we load an old version schema for query.\n\tSnapshotInfoschema interface{}\n\n\t// StartTime is the start time of the last query.\n\tStartTime time.Time\n\n\t// DurationParse is the duration of parsing SQL string to AST of the last query.\n\tDurationParse time.Duration\n\n\t// DurationPlanning is the duration of compiling AST to logical plan of the last query.\n\tDurationPlanning time.Duration\n\n\t// DurationTranslating is the duration of converting logical plan to execution plan of the last query.\n\tDurationTranslating time.Duration\n\n\t// DurationExecuting is the duration of executing execution plan of the last query.\n\tDurationExecuting time.Duration\n\n\t// Per-connection time zones. Each client that connects has its own time zone setting, given by the session time_zone variable.\n\t// See https://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html\n\tTimeZone string\n\n\t// Storage\n\tStorage *gorm.DB\n\n\t// PreparedParams params for prepared statements\n\tPreparedParams PreparedParams\n\n\tSQLMode mysql.SQLMode\n\n\t// AffectedByGroupThreshold is used to mark whether GroupByThreshold is applied to protect query results\n\tAffectedByGroupThreshold bool\n\n\t// GroupByThreshold applied to protect query results\n\tGroupByThreshold uint64\n\n\t// CreatedAt is the time when the session is created\n\tCreatedAt time.Time\n}\n\n// PreparedParams contains the parameters of the current prepared statement when executing it.\ntype PreparedParams map[string]*types.Datum\n\nfunc (pps PreparedParams) String() (string, error) {\n\tif len(pps) == 0 {\n\t\treturn \"\", nil\n\t}\n\tres := \"[arguments: \"\n\tfor name, data := range pps {\n\t\tdatum_str, err := types.DatumsToString([]types.Datum{*data}, true)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tres += fmt.Sprintf(\"%s=%s, \", name, datum_str)\n\t}\n\treturn res + \"]\", nil\n}\n\nfunc (pps PreparedParams) GetPreparedParam(name string) (*types.Datum, bool) {\n\tdata, ok := pps[name]\n\tif !ok {\n\t\treturn nil, false\n\t}\n\treturn data, true\n}\n\n// NewSessionVars creates a session vars object.\nfunc NewSessionVars() *SessionVars {\n\tvars := &SessionVars{PreparedParams: make(PreparedParams)}\n\treturn vars\n}\n\n// AllocPlanColumnID allocates column id for plan.\nfunc (s *SessionVars) AllocPlanColumnID() int64 {\n\ts.PlanColumnID++\n\treturn s.PlanColumnID\n}\n\n// GetSystemVar gets the string value of a system variable.\nfunc (s *SessionVars) GetSystemVar(name string) (string, bool) {\n\tif name == WarningCount {\n\t\treturn strconv.Itoa(s.SysWarningCount), true\n\t} else if name == ErrorCount {\n\t\treturn strconv.Itoa(int(s.SysErrorCount)), true\n\t}\n\tval, ok := s.systems[name]\n\treturn val, ok\n}\n\nfunc (s *SessionVars) SetTimeZone(TimeZone string) {\n\ts.TimeZone = TimeZone\n}\n\nfunc (s *SessionVars) GetTimeZone() string {\n\treturn s.TimeZone\n}\n"
  },
  {
    "path": "pkg/sessionctx/variable/sysvar.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage variable\n\n// ScopeFlag is for system variable whether can be changed in global/session dynamically or not.\ntype ScopeFlag uint8\n\nconst (\n\t// ScopeNone means the system variable can not be changed dynamically.\n\tScopeNone ScopeFlag = 0\n\t// ScopeGlobal means the system variable can be changed globally.\n\tScopeGlobal ScopeFlag = 1 << 0\n\t// ScopeSession means the system variable can only be changed in current session.\n\tScopeSession ScopeFlag = 1 << 1\n)\n\n// SysVar is for system variable.\ntype SysVar struct {\n\t// Scope is for whether can be changed or not\n\tScope ScopeFlag\n\n\t// Name is the variable name.\n\tName string\n\n\t// Value is the variable value.\n\tValue string\n}\n\nconst (\n\tWarningCount = \"warning_count\"\n\t// ErrorCount is the name for 'error_count' system variable.\n\tErrorCount = \"error_count\"\n)\n\nconst (\n\tDefMaxAllowedPacket uint64 = 67108864\n)\n"
  },
  {
    "path": "pkg/status/status.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage status\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\nvar _ error = &Status{}\n\ntype Status struct {\n\tcode scql.Code\n\terr  error\n}\n\nfunc (s *Status) Error() string {\n\treturn fmt.Sprintf(\"Error: code=%v, msg=\\\"%v\\\"\", int32(s.code), s.err)\n}\n\nfunc (s *Status) Unwrap() error {\n\treturn s.err\n}\n\nfunc (s *Status) Code() scql.Code {\n\treturn s.code\n}\n\nfunc (s *Status) Message() string {\n\treturn s.err.Error()\n}\n\nfunc (s *Status) ToProto() *scql.Status {\n\treturn &scql.Status{\n\t\tCode:    int32(s.code),\n\t\tMessage: s.Message(),\n\t}\n}\n\nfunc NewStatusFromProto(status *scql.Status) *Status {\n\tif status == nil {\n\t\treturn nil\n\t}\n\tcode := status.GetCode()\n\tmsg := status.GetMessage()\n\tif _, ok := scql.Code_name[code]; !ok {\n\t\treturn New(scql.Code_INTERNAL, msg)\n\t}\n\treturn New(scql.Code(code), msg)\n}\n\nfunc New(code scql.Code, msg string) *Status {\n\treturn &Status{code: code, err: errors.New(msg)}\n}\n\nfunc Wrap(code scql.Code, err error) *Status {\n\treturn &Status{code: code, err: err}\n}\n"
  },
  {
    "path": "pkg/status/status_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage status\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tproto \"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\nfunc makeStatusError(code proto.Code) error {\n\treturn New(code, \"some bad happened\")\n}\n\nfunc makeError(msg string) error {\n\treturn errors.New(msg)\n}\n\nfunc TestErrorAsStatus(t *testing.T) {\n\tr := require.New(t)\n\n\t{\n\t\terr := makeStatusError(proto.Code_NOT_FOUND)\n\n\t\tvar status *Status\n\t\tr.True(errors.As(err, &status), \"err must be status error\")\n\t\tr.Equal(status.code, proto.Code_NOT_FOUND)\n\t}\n\n\t{\n\t\terr := makeError(\"xxx\")\n\n\t\tvar status *Status\n\t\tr.False(errors.As(err, &status), \"err is not status error\")\n\t}\n\n\t{\n\t\t// test case with error chains\n\t\terr1 := fmt.Errorf(\"op xxx is not implemented\")\n\n\t\terr2 := Wrap(proto.Code_NOT_SUPPORTED, err1)\n\n\t\t// Wrapping errors with %w\n\t\t// Reference: https://go.dev/blog/go1.13-errors\n\t\terr3 := fmt.Errorf(\"some bad happend: %w\", err2)\n\n\t\tvar status *Status\n\t\tr.True(errors.As(err3, &status), \"err3 must be status error\")\n\t\tr.Equal(status.code, proto.Code_NOT_SUPPORTED)\n\t}\n}\n"
  },
  {
    "path": "pkg/table/column.go",
    "content": "// Copyright 2013 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage table\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n)\n\n// Column provides meta data describing a table column.\ntype Column struct {\n\t*model.ColumnInfo\n}\n\n// ToColumn converts a *model.ColumnInfo to *Column.\nfunc ToColumn(col *model.ColumnInfo) *Column {\n\treturn &Column{\n\t\tcol,\n\t}\n}\n\nfunc (c *Column) ToInfo() *model.ColumnInfo {\n\treturn c.ColumnInfo\n}\n\n// ColDescFieldNames returns the fields name in result set for desc and show columns.\nfunc ColDescFieldNames(full bool) []string {\n\tif full {\n\t\treturn []string{\"Field\", \"Type\", \"Comment\"}\n\t}\n\treturn []string{\"Field\", \"Type\"}\n}\n"
  },
  {
    "path": "pkg/table/table.go",
    "content": "// Copyright 2013 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage table\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n)\n\n// Table is used to retrieve and modify rows in table.\ntype Table interface {\n\t// Cols returns the columns of the table which is used in select, including hidden columns.\n\tCols() []*Column\n\t// Meta returns TableInfo.\n\tMeta() *model.TableInfo\n}\n\n// MockTableFromMeta only serves for test.\nvar MockTableFromMeta func(tableInfo *model.TableInfo) Table\n"
  },
  {
    "path": "pkg/table/tables/tables.go",
    "content": "// Copyright 2013 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage tables\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/table\"\n)\n\n// TableCommon is shared by both Table and partition.\ntype TableCommon struct {\n\ttableID int64\n\tColumns []*table.Column\n\tmeta    *model.TableInfo\n}\n\n// Cols implements table.Table Cols interface.\nfunc (t *TableCommon) Cols() []*table.Column {\n\treturn t.Columns\n}\n\n// Meta implements table.Table Meta interface.\nfunc (t *TableCommon) Meta() *model.TableInfo {\n\treturn t.meta\n}\n\n// MockTableFromMeta only serves for test.\nfunc MockTableFromMeta(tblInfo *model.TableInfo) table.Table {\n\tcolumns := make([]*table.Column, 0, len(tblInfo.Columns))\n\tfor _, colInfo := range tblInfo.Columns {\n\t\tcol := table.ToColumn(colInfo)\n\t\tcolumns = append(columns, col)\n\t}\n\n\tvar t TableCommon\n\tinitTableCommon(&t, tblInfo, tblInfo.ID, columns)\n\treturn &t\n}\n\n// initTableCommon initializes a TableCommon struct.\nfunc initTableCommon(t *TableCommon, tblInfo *model.TableInfo, physicalTableID int64, cols []*table.Column) {\n\tt.tableID = tblInfo.ID\n\tt.meta = tblInfo\n\tt.Columns = cols\n}\n\nfunc init() {\n\ttable.MockTableFromMeta = MockTableFromMeta\n}\n"
  },
  {
    "path": "pkg/types/binary_literal.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n)\n\n// BinaryLiteral is the internal type for storing bit / hex literal type.\ntype BinaryLiteral []byte\n\n// BitLiteral is the bit literal type.\ntype BitLiteral BinaryLiteral\n\n// HexLiteral is the hex literal type.\ntype HexLiteral BinaryLiteral\n\n// ZeroBinaryLiteral is a BinaryLiteral literal with zero value.\nvar ZeroBinaryLiteral = BinaryLiteral{}\n\nfunc trimLeadingZeroBytes(bytes []byte) []byte {\n\tif len(bytes) == 0 {\n\t\treturn bytes\n\t}\n\tpos, posMax := 0, len(bytes)-1\n\tfor ; pos < posMax; pos++ {\n\t\tif bytes[pos] != 0 {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn bytes[pos:]\n}\n\n// NewBinaryLiteralFromUint creates a new BinaryLiteral instance by the given uint value in BitEndian.\n// byteSize will be used as the length of the new BinaryLiteral, with leading bytes filled to zero.\n// If byteSize is -1, the leading zeros in new BinaryLiteral will be trimmed.\nfunc NewBinaryLiteralFromUint(value uint64, byteSize int) BinaryLiteral {\n\tif byteSize != -1 && (byteSize < 1 || byteSize > 8) {\n\t\tpanic(\"Invalid byteSize\")\n\t}\n\tbuf := make([]byte, 8)\n\tbinary.BigEndian.PutUint64(buf, value)\n\tif byteSize == -1 {\n\t\tbuf = trimLeadingZeroBytes(buf)\n\t} else {\n\t\tbuf = buf[8-byteSize:]\n\t}\n\treturn buf\n}\n\n// String implements fmt.Stringer interface.\nfunc (b BinaryLiteral) String() string {\n\tif len(b) == 0 {\n\t\treturn \"\"\n\t}\n\treturn \"0x\" + hex.EncodeToString(b)\n}\n\n// ToString returns the string representation for the literal.\nfunc (b BinaryLiteral) ToString() string {\n\treturn string(b)\n}\n\n// ToBitLiteralString returns the bit literal representation for the literal.\nfunc (b BinaryLiteral) ToBitLiteralString(trimLeadingZero bool) string {\n\tif len(b) == 0 {\n\t\treturn \"b''\"\n\t}\n\tvar buf bytes.Buffer\n\tfor _, data := range b {\n\t\tfmt.Fprintf(&buf, \"%08b\", data)\n\t}\n\tret := buf.Bytes()\n\tif trimLeadingZero {\n\t\tret = bytes.TrimLeft(ret, \"0\")\n\t\tif len(ret) == 0 {\n\t\t\tret = []byte{'0'}\n\t\t}\n\t}\n\treturn fmt.Sprintf(\"b'%s'\", string(ret))\n}\n\n// ToInt returns the int value for the literal.\nfunc (b BinaryLiteral) ToInt(sc *stmtctx.StatementContext) (uint64, error) {\n\tbuf := trimLeadingZeroBytes(b)\n\tlength := len(buf)\n\tif length == 0 {\n\t\treturn 0, nil\n\t}\n\tif length > 8 {\n\t\tvar err error = ErrTruncatedWrongVal.GenWithStackByArgs(\"BINARY\", b)\n\t\tif sc != nil {\n\t\t\terr = sc.HandleTruncate(err)\n\t\t}\n\t\treturn math.MaxUint64, err\n\t}\n\t// Note: the byte-order is BigEndian.\n\tval := uint64(buf[0])\n\tfor i := 1; i < length; i++ {\n\t\tval = (val << 8) | uint64(buf[i])\n\t}\n\treturn val, nil\n}\n\n// Compare compares BinaryLiteral to another one\nfunc (b BinaryLiteral) Compare(b2 BinaryLiteral) int {\n\tbufB := trimLeadingZeroBytes(b)\n\tbufB2 := trimLeadingZeroBytes(b2)\n\tif len(bufB) > len(bufB2) {\n\t\treturn 1\n\t}\n\tif len(bufB) < len(bufB2) {\n\t\treturn -1\n\t}\n\treturn bytes.Compare(bufB, bufB2)\n}\n\n// ParseBitStr parses bit string.\n// The string format can be b'val', B'val' or 0bval, val must be 0 or 1.\n// See https://dev.mysql.com/doc/refman/5.7/en/bit-value-literals.html\nfunc ParseBitStr(s string) (BinaryLiteral, error) {\n\tif len(s) == 0 {\n\t\treturn nil, errors.Errorf(\"invalid empty string for parsing bit type\")\n\t}\n\n\tif s[0] == 'b' || s[0] == 'B' {\n\t\t// format is b'val' or B'val'\n\t\ts = strings.Trim(s[1:], \"'\")\n\t} else if strings.HasPrefix(s, \"0b\") {\n\t\ts = s[2:]\n\t} else {\n\t\t// here means format is not b'val', B'val' or 0bval.\n\t\treturn nil, errors.Errorf(\"invalid bit type format %s\", s)\n\t}\n\n\tif len(s) == 0 {\n\t\treturn ZeroBinaryLiteral, nil\n\t}\n\n\talignedLength := (len(s) + 7) &^ 7\n\ts = (\"00000000\" + s)[len(s)+8-alignedLength:] // Pad with zero (slice from `-alignedLength`)\n\tbyteLength := len(s) >> 3\n\tbuf := make([]byte, byteLength)\n\n\tfor i := 0; i < byteLength; i++ {\n\t\tstrPosition := i << 3\n\t\tval, err := strconv.ParseUint(s[strPosition:strPosition+8], 2, 8)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Trace(err)\n\t\t}\n\t\tbuf[i] = byte(val)\n\t}\n\n\treturn buf, nil\n}\n\n// NewBitLiteral parses bit string as BitLiteral type.\nfunc NewBitLiteral(s string) (BitLiteral, error) {\n\tb, err := ParseBitStr(s)\n\tif err != nil {\n\t\treturn BitLiteral{}, err\n\t}\n\treturn BitLiteral(b), nil\n}\n\n// ToString implement ast.BinaryLiteral interface\nfunc (b BitLiteral) ToString() string {\n\treturn BinaryLiteral(b).ToString()\n}\n\n// ParseHexStr parses hexadecimal string literal.\n// See https://dev.mysql.com/doc/refman/5.7/en/hexadecimal-literals.html\nfunc ParseHexStr(s string) (BinaryLiteral, error) {\n\tif len(s) == 0 {\n\t\treturn nil, errors.Errorf(\"invalid empty string for parsing hexadecimal literal\")\n\t}\n\n\tif s[0] == 'x' || s[0] == 'X' {\n\t\t// format is x'val' or X'val'\n\t\ts = strings.Trim(s[1:], \"'\")\n\t\tif len(s)%2 != 0 {\n\t\t\treturn nil, errors.Errorf(\"invalid hexadecimal format, must even numbers, but %d\", len(s))\n\t\t}\n\t} else if strings.HasPrefix(s, \"0x\") {\n\t\ts = s[2:]\n\t} else {\n\t\t// here means format is not x'val', X'val' or 0xval.\n\t\treturn nil, errors.Errorf(\"invalid hexadecimal format %s\", s)\n\t}\n\n\tif len(s) == 0 {\n\t\treturn ZeroBinaryLiteral, nil\n\t}\n\n\tif len(s)%2 != 0 {\n\t\ts = \"0\" + s\n\t}\n\tbuf, err := hex.DecodeString(s)\n\tif err != nil {\n\t\treturn nil, errors.Trace(err)\n\t}\n\treturn buf, nil\n}\n\n// NewHexLiteral parses hexadecimal string as HexLiteral type.\nfunc NewHexLiteral(s string) (HexLiteral, error) {\n\th, err := ParseHexStr(s)\n\tif err != nil {\n\t\treturn HexLiteral{}, err\n\t}\n\treturn HexLiteral(h), nil\n}\n\n// ToString implement ast.BinaryLiteral interface\nfunc (b HexLiteral) ToString() string {\n\treturn BinaryLiteral(b).ToString()\n}\n"
  },
  {
    "path": "pkg/types/compare.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"math\"\n\t\"time\"\n)\n\n// CompareInt64 returns an integer comparing the int64 x to y.\nfunc CompareInt64(x, y int64) int {\n\tif x < y {\n\t\treturn -1\n\t} else if x == y {\n\t\treturn 0\n\t}\n\n\treturn 1\n}\n\n// CompareUint64 returns an integer comparing the uint64 x to y.\nfunc CompareUint64(x, y uint64) int {\n\tif x < y {\n\t\treturn -1\n\t} else if x == y {\n\t\treturn 0\n\t}\n\n\treturn 1\n}\n\n// VecCompareUU returns []int64 comparing the []uint64 x to []uint64 y\nfunc VecCompareUU(x, y []uint64, res []int64) {\n\tn := len(x)\n\tfor i := 0; i < n; i++ {\n\t\tif x[i] < y[i] {\n\t\t\tres[i] = -1\n\t\t} else if x[i] == y[i] {\n\t\t\tres[i] = 0\n\t\t} else {\n\t\t\tres[i] = 1\n\t\t}\n\t}\n}\n\n// VecCompareII returns []int64 comparing the []int64 x to []int64 y\nfunc VecCompareII(x, y, res []int64) {\n\tn := len(x)\n\tfor i := 0; i < n; i++ {\n\t\tif x[i] < y[i] {\n\t\t\tres[i] = -1\n\t\t} else if x[i] == y[i] {\n\t\t\tres[i] = 0\n\t\t} else {\n\t\t\tres[i] = 1\n\t\t}\n\t}\n}\n\n// VecCompareUI returns []int64 comparing the []uint64 x to []int64y\nfunc VecCompareUI(x []uint64, y, res []int64) {\n\tn := len(x)\n\tfor i := 0; i < n; i++ {\n\t\tif y[i] < 0 || x[i] > math.MaxInt64 {\n\t\t\tres[i] = 1\n\t\t} else if int64(x[i]) < y[i] {\n\t\t\tres[i] = -1\n\t\t} else if int64(x[i]) == y[i] {\n\t\t\tres[i] = 0\n\t\t} else {\n\t\t\tres[i] = 1\n\t\t}\n\t}\n}\n\n// VecCompareIU returns []int64 comparing the []int64 x to []uint64y\nfunc VecCompareIU(x []int64, y []uint64, res []int64) {\n\tn := len(x)\n\tfor i := 0; i < n; i++ {\n\t\tif x[i] < 0 || uint64(y[i]) > math.MaxInt64 {\n\t\t\tres[i] = -1\n\t\t} else if x[i] < int64(y[i]) {\n\t\t\tres[i] = -1\n\t\t} else if x[i] == int64(y[i]) {\n\t\t\tres[i] = 0\n\t\t} else {\n\t\t\tres[i] = 1\n\t\t}\n\t}\n}\n\n// CompareFloat64 returns an integer comparing the float64 x to y.\nfunc CompareFloat64(x, y float64) int {\n\tif x < y {\n\t\treturn -1\n\t} else if x == y {\n\t\treturn 0\n\t}\n\n\treturn 1\n}\n\n// CompareString returns an integer comparing the string x to y.\nfunc CompareString(x, y string) int {\n\tif x < y {\n\t\treturn -1\n\t} else if x == y {\n\t\treturn 0\n\t}\n\n\treturn 1\n}\n\n// CompareDuration returns an integer comparing the duration x to y.\nfunc CompareDuration(x, y time.Duration) int {\n\tif x < y {\n\t\treturn -1\n\t} else if x == y {\n\t\treturn 0\n\t}\n\n\treturn 1\n}\n"
  },
  {
    "path": "pkg/types/convert.go",
    "content": "// Copyright 2014 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n)\n\nfunc truncateStr(str string, flen int) string {\n\tif flen != UnspecifiedLength && len(str) > flen {\n\t\tstr = str[:flen]\n\t}\n\treturn str\n}\n\n// IntergerUnsignedUpperBound indicates the max uint64 values of different mysql types.\nfunc IntergerUnsignedUpperBound(intType byte) uint64 {\n\tswitch intType {\n\tcase mysql.TypeTiny:\n\t\treturn math.MaxUint8\n\tcase mysql.TypeShort:\n\t\treturn math.MaxUint16\n\tcase mysql.TypeInt24:\n\t\treturn mysql.MaxUint24\n\tcase mysql.TypeLong:\n\t\treturn math.MaxUint32\n\tcase mysql.TypeLonglong:\n\t\treturn math.MaxUint64\n\tcase mysql.TypeBit:\n\t\treturn math.MaxUint64\n\tcase mysql.TypeEnum:\n\t\treturn math.MaxUint64\n\tcase mysql.TypeSet:\n\t\treturn math.MaxUint64\n\tdefault:\n\t\tpanic(\"Input byte is not a mysql type\")\n\t}\n}\n\n// IntergerSignedUpperBound indicates the max int64 values of different mysql types.\nfunc IntergerSignedUpperBound(intType byte) int64 {\n\tswitch intType {\n\tcase mysql.TypeTiny:\n\t\treturn math.MaxInt8\n\tcase mysql.TypeShort:\n\t\treturn math.MaxInt16\n\tcase mysql.TypeInt24:\n\t\treturn mysql.MaxInt24\n\tcase mysql.TypeLong:\n\t\treturn math.MaxInt32\n\tcase mysql.TypeLonglong:\n\t\treturn math.MaxInt64\n\tdefault:\n\t\tpanic(\"Input byte is not a mysql type\")\n\t}\n}\n\n// IntergerSignedLowerBound indicates the min int64 values of different mysql types.\nfunc IntergerSignedLowerBound(intType byte) int64 {\n\tswitch intType {\n\tcase mysql.TypeTiny:\n\t\treturn math.MinInt8\n\tcase mysql.TypeShort:\n\t\treturn math.MinInt16\n\tcase mysql.TypeInt24:\n\t\treturn mysql.MinInt24\n\tcase mysql.TypeLong:\n\t\treturn math.MinInt32\n\tcase mysql.TypeLonglong:\n\t\treturn math.MinInt64\n\tdefault:\n\t\tpanic(\"Input byte is not a mysql type\")\n\t}\n}\n\n// ConvertFloatToInt converts a float64 value to a int value.\n// `tp` is used in err msg, if there is overflow, this func will report err according to `tp`\nfunc ConvertFloatToInt(fval float64, lowerBound, upperBound int64, tp byte) (int64, error) {\n\tval := RoundFloat(fval)\n\tif val < float64(lowerBound) {\n\t\treturn lowerBound, overflow(val, tp)\n\t}\n\n\tif val >= float64(upperBound) {\n\t\tif val == float64(upperBound) {\n\t\t\treturn upperBound, nil\n\t\t}\n\t\treturn upperBound, overflow(val, tp)\n\t}\n\treturn int64(val), nil\n}\n\n// ConvertIntToInt converts an int value to another int value of different precision.\nfunc ConvertIntToInt(val int64, lowerBound int64, upperBound int64, tp byte) (int64, error) {\n\tif val < lowerBound {\n\t\treturn lowerBound, overflow(val, tp)\n\t}\n\n\tif val > upperBound {\n\t\treturn upperBound, overflow(val, tp)\n\t}\n\n\treturn val, nil\n}\n\n// ConvertUintToInt converts an uint value to an int value.\nfunc ConvertUintToInt(val uint64, upperBound int64, tp byte) (int64, error) {\n\tif val > uint64(upperBound) {\n\t\treturn upperBound, overflow(val, tp)\n\t}\n\n\treturn int64(val), nil\n}\n\n// ConvertIntToUint converts an int value to an uint value.\nfunc ConvertIntToUint(sc *stmtctx.StatementContext, val int64, upperBound uint64, tp byte) (uint64, error) {\n\tif uint64(val) > upperBound {\n\t\treturn upperBound, overflow(val, tp)\n\t}\n\n\treturn uint64(val), nil\n}\n\n// ConvertUintToUint converts an uint value to another uint value of different precision.\nfunc ConvertUintToUint(val uint64, upperBound uint64, tp byte) (uint64, error) {\n\tif val > upperBound {\n\t\treturn upperBound, overflow(val, tp)\n\t}\n\n\treturn val, nil\n}\n\n// ConvertFloatToUint converts a float value to an uint value.\nfunc ConvertFloatToUint(sc *stmtctx.StatementContext, fval float64, upperBound uint64, tp byte) (uint64, error) {\n\tval := RoundFloat(fval)\n\tif val < 0 {\n\t\treturn uint64(int64(val)), overflow(val, tp)\n\t}\n\n\tubf := float64(upperBound)\n\t// Because math.MaxUint64 can not be represented precisely in iee754(64bit),\n\t// so `float64(math.MaxUint64)` will make a num bigger than math.MaxUint64,\n\t// which can not be represented by 64bit integer.\n\t// So `uint64(float64(math.MaxUint64))` is undefined behavior.\n\tif val == ubf {\n\t\treturn uint64(math.MaxInt64), nil\n\t}\n\tif val > ubf {\n\t\treturn uint64(math.MaxInt64), overflow(val, tp)\n\t}\n\treturn uint64(val), nil\n}\n\n// convertScientificNotation converts a decimal string with scientific notation to a normal decimal string.\n// 1E6 => 1000000, .12345E+5 => 12345\nfunc convertScientificNotation(str string) (string, error) {\n\t// https://golang.org/ref/spec#Floating-point_literals\n\teIdx := -1\n\tpoint := -1\n\tfor i := 0; i < len(str); i++ {\n\t\tif str[i] == '.' {\n\t\t\tpoint = i\n\t\t}\n\t\tif str[i] == 'e' || str[i] == 'E' {\n\t\t\teIdx = i\n\t\t\tif point == -1 {\n\t\t\t\tpoint = i\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\tif eIdx == -1 {\n\t\treturn str, nil\n\t}\n\texp, err := strconv.ParseInt(str[eIdx+1:], 10, 64)\n\tif err != nil {\n\t\treturn \"\", errors.WithStack(err)\n\t}\n\n\tf := str[:eIdx]\n\tif exp == 0 {\n\t\treturn f, nil\n\t} else if exp > 0 { // move point right\n\t\tif point+int(exp) == len(f)-1 { // 123.456 >> 3 = 123456. = 123456\n\t\t\treturn f[:point] + f[point+1:], nil\n\t\t} else if point+int(exp) < len(f)-1 { // 123.456 >> 2 = 12345.6\n\t\t\treturn f[:point] + f[point+1:point+1+int(exp)] + \".\" + f[point+1+int(exp):], nil\n\t\t}\n\t\t// 123.456 >> 5 = 12345600\n\t\treturn f[:point] + f[point+1:] + strings.Repeat(\"0\", point+int(exp)-len(f)+1), nil\n\t} else { // move point left\n\t\texp = -exp\n\t\tif int(exp) < point { // 123.456 << 2 = 1.23456\n\t\t\treturn f[:point-int(exp)] + \".\" + f[point-int(exp):point] + f[point+1:], nil\n\t\t}\n\t\t// 123.456 << 5 = 0.00123456\n\t\treturn \"0.\" + strings.Repeat(\"0\", int(exp)-point) + f[:point] + f[point+1:], nil\n\t}\n}\n\nfunc convertDecimalStrToUint(sc *stmtctx.StatementContext, str string, upperBound uint64, tp byte) (uint64, error) {\n\tstr, err := convertScientificNotation(str)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tvar intStr, fracStr string\n\tp := strings.Index(str, \".\")\n\tif p == -1 {\n\t\tintStr = str\n\t} else {\n\t\tintStr = str[:p]\n\t\tfracStr = str[p+1:]\n\t}\n\tintStr = strings.TrimLeft(intStr, \"0\")\n\tif intStr == \"\" {\n\t\tintStr = \"0\"\n\t}\n\n\tvar round uint64\n\tif fracStr != \"\" && fracStr[0] >= '5' {\n\t\tround++\n\t}\n\n\tupperBound -= round\n\tupperStr := strconv.FormatUint(upperBound, 10)\n\tif len(intStr) > len(upperStr) ||\n\t\t(len(intStr) == len(upperStr) && intStr > upperStr) {\n\t\treturn upperBound, overflow(str, tp)\n\t}\n\n\tval, err := strconv.ParseUint(intStr, 10, 64)\n\tif err != nil {\n\t\treturn val, err\n\t}\n\treturn val + round, nil\n}\n\n// ConvertDecimalToUint converts a decimal to a uint by converting it to a string first to avoid float overflow (#10181).\nfunc ConvertDecimalToUint(sc *stmtctx.StatementContext, d *MyDecimal, upperBound uint64, tp byte) (uint64, error) {\n\treturn convertDecimalStrToUint(sc, string(d.ToString()), upperBound, tp)\n}\n\n// StrToInt converts a string to an integer at the best-effort.\nfunc StrToInt(sc *stmtctx.StatementContext, str string) (int64, error) {\n\tstr = strings.TrimSpace(str)\n\tvalidPrefix, err := getValidIntPrefix(sc, str)\n\tiVal, err1 := strconv.ParseInt(validPrefix, 10, 64)\n\tif err1 != nil {\n\t\treturn iVal, ErrOverflow.GenWithStackByArgs(\"BIGINT\", validPrefix)\n\t}\n\treturn iVal, errors.Trace(err)\n}\n\n// StrToUint converts a string to an unsigned integer at the best-effortt.\nfunc StrToUint(sc *stmtctx.StatementContext, str string) (uint64, error) {\n\tstr = strings.TrimSpace(str)\n\tvalidPrefix, err := getValidIntPrefix(sc, str)\n\tif validPrefix[0] == '+' {\n\t\tvalidPrefix = validPrefix[1:]\n\t}\n\tuVal, err1 := strconv.ParseUint(validPrefix, 10, 64)\n\tif err1 != nil {\n\t\treturn uVal, ErrOverflow.GenWithStackByArgs(\"BIGINT UNSIGNED\", validPrefix)\n\t}\n\treturn uVal, errors.Trace(err)\n}\n\n// getValidIntPrefix gets prefix of the string which can be successfully parsed as int.\nfunc getValidIntPrefix(sc *stmtctx.StatementContext, str string) (string, error) {\n\tvalidLen := 0\n\n\tfor i := 0; i < len(str); i++ {\n\t\tc := str[i]\n\t\tif (c == '+' || c == '-') && i == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif c >= '0' && c <= '9' {\n\t\t\tvalidLen = i + 1\n\t\t\tcontinue\n\t\t}\n\n\t\tbreak\n\t}\n\tvalid := str[:validLen]\n\tif valid == \"\" {\n\t\tvalid = \"0\"\n\t}\n\tif validLen == 0 || validLen != len(str) {\n\t\treturn valid, errors.Trace(ErrTruncatedWrongVal.GenWithStackByArgs(\"INTEGER\", str))\n\t}\n\treturn valid, nil\n}\n\n// roundIntStr is to round a **valid int string** base on the number following dot.\nfunc roundIntStr(numNextDot byte, intStr string) string {\n\tif numNextDot < '5' {\n\t\treturn intStr\n\t}\n\tretStr := []byte(intStr)\n\tidx := len(intStr) - 1\n\tfor ; idx >= 1; idx-- {\n\t\tif retStr[idx] != '9' {\n\t\t\tretStr[idx]++\n\t\t\tbreak\n\t\t}\n\t\tretStr[idx] = '0'\n\t}\n\tif idx == 0 {\n\t\tif intStr[0] == '9' {\n\t\t\tretStr[0] = '1'\n\t\t\tretStr = append(retStr, '0')\n\t\t} else if isDigit(intStr[0]) {\n\t\t\tretStr[0]++\n\t\t} else {\n\t\t\tretStr[1] = '1'\n\t\t\tretStr = append(retStr, '0')\n\t\t}\n\t}\n\treturn string(retStr)\n}\n\n// floatStrToIntStr converts a valid float string into valid integer string which can be parsed by\n// strconv.ParseInt, we can't parse float first then convert it to string because precision will\n// be lost. For example, the string value \"18446744073709551615\" which is the max number of unsigned\n// int will cause some precision to lose. intStr[0] may be a positive and negative sign like '+' or '-'.\n//\n// This func will find serious overflow such as the len of intStr > 20 (without prefix `+/-`)\n// however, it will not check whether the intStr overflow BIGINT.\nfunc floatStrToIntStr(sc *stmtctx.StatementContext, validFloat string, oriStr string) (intStr string, _ error) {\n\tvar dotIdx = -1\n\tvar eIdx = -1\n\tfor i := 0; i < len(validFloat); i++ {\n\t\tswitch validFloat[i] {\n\t\tcase '.':\n\t\t\tdotIdx = i\n\t\tcase 'e', 'E':\n\t\t\teIdx = i\n\t\t}\n\t}\n\tif eIdx == -1 {\n\t\tif dotIdx == -1 {\n\t\t\treturn validFloat, nil\n\t\t}\n\t\tvar digits []byte\n\t\tif validFloat[0] == '-' || validFloat[0] == '+' {\n\t\t\tdotIdx--\n\t\t\tdigits = []byte(validFloat[1:])\n\t\t} else {\n\t\t\tdigits = []byte(validFloat)\n\t\t}\n\t\tif dotIdx == 0 {\n\t\t\tintStr = \"0\"\n\t\t} else {\n\t\t\tintStr = string(digits)[:dotIdx]\n\t\t}\n\t\tif len(digits) > dotIdx+1 {\n\t\t\tintStr = roundIntStr(digits[dotIdx+1], intStr)\n\t\t}\n\t\tif (len(intStr) > 1 || intStr[0] != '0') && validFloat[0] == '-' {\n\t\t\tintStr = \"-\" + intStr\n\t\t}\n\t\treturn intStr, nil\n\t}\n\t// intCnt and digits contain the prefix `+/-` if validFloat[0] is `+/-`\n\tvar intCnt int\n\tdigits := make([]byte, 0, len(validFloat))\n\tif dotIdx == -1 {\n\t\tdigits = append(digits, validFloat[:eIdx]...)\n\t\tintCnt = len(digits)\n\t} else {\n\t\tdigits = append(digits, validFloat[:dotIdx]...)\n\t\tintCnt = len(digits)\n\t\tdigits = append(digits, validFloat[dotIdx+1:eIdx]...)\n\t}\n\texp, err := strconv.Atoi(validFloat[eIdx+1:])\n\tif err != nil {\n\t\treturn validFloat, errors.Trace(err)\n\t}\n\tintCnt += exp\n\tif exp >= 0 && (intCnt > 21 || intCnt < 0) {\n\t\t// TODO(teng.t): Append a warning here?\n\t\t// MaxInt64 has 19 decimal digits.\n\t\t// MaxUint64 has 20 decimal digits.\n\t\t// And the intCnt may contain the len of `+/-`,\n\t\t// so I use 21 here as the early detection.\n\t\t// sc.AppendWarning(ErrOverflow.GenWithStackByArgs(\"BIGINT\", oriStr))\n\t\treturn validFloat[:eIdx], nil\n\t}\n\tif intCnt <= 0 {\n\t\tintStr = \"0\"\n\t\tif intCnt == 0 && len(digits) > 0 && isDigit(digits[0]) {\n\t\t\tintStr = roundIntStr(digits[0], intStr)\n\t\t}\n\t\treturn intStr, nil\n\t}\n\tif intCnt == 1 && (digits[0] == '-' || digits[0] == '+') {\n\t\tintStr = \"0\"\n\t\tif len(digits) > 1 {\n\t\t\tintStr = roundIntStr(digits[1], intStr)\n\t\t}\n\t\tif intStr[0] == '1' {\n\t\t\tintStr = string(digits[:1]) + intStr\n\t\t}\n\t\treturn intStr, nil\n\t}\n\tif intCnt <= len(digits) {\n\t\tintStr = string(digits[:intCnt])\n\t\tif intCnt < len(digits) {\n\t\t\tintStr = roundIntStr(digits[intCnt], intStr)\n\t\t}\n\t} else {\n\t\t// convert scientific notation decimal number\n\t\textraZeroCount := intCnt - len(digits)\n\t\tintStr = string(digits) + strings.Repeat(\"0\", extraZeroCount)\n\t}\n\treturn intStr, nil\n}\n\n// StrToFloat converts a string to a float64 at the best-effort.\nfunc StrToFloat(sc *stmtctx.StatementContext, str string) (float64, error) {\n\tstr = strings.TrimSpace(str)\n\tvalidStr, err := getValidFloatPrefix(sc, str)\n\tf, err1 := strconv.ParseFloat(validStr, 64)\n\tif err1 != nil {\n\t\tif err2, ok := err1.(*strconv.NumError); ok {\n\t\t\t// value will truncate to MAX/MIN if out of range.\n\t\t\tif err2.Err == strconv.ErrRange {\n\t\t\t\terr1 = ErrTruncatedWrongVal.GenWithStackByArgs(\"DOUBLE\", str)\n\t\t\t\tif math.IsInf(f, 1) {\n\t\t\t\t\tf = math.MaxFloat64\n\t\t\t\t} else if math.IsInf(f, -1) {\n\t\t\t\t\tf = -math.MaxFloat64\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn f, errors.Trace(err1)\n\t}\n\treturn f, errors.Trace(err)\n}\n\n// getValidFloatPrefix gets prefix of string which can be successfully parsed as float.\nfunc getValidFloatPrefix(sc *stmtctx.StatementContext, s string) (valid string, err error) {\n\tvar (\n\t\tsawDot   bool\n\t\tsawDigit bool\n\t\tvalidLen int\n\t\teIdx     int\n\t)\n\tfor i := 0; i < len(s); i++ {\n\t\tc := s[i]\n\t\tif c == '+' || c == '-' {\n\t\t\tif i != 0 && i != eIdx+1 { // \"1e+1\" is valid.\n\t\t\t\tbreak\n\t\t\t}\n\t\t} else if c == '.' {\n\t\t\tif sawDot || eIdx > 0 { // \"1.1.\" or \"1e1.1\"\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tsawDot = true\n\t\t\tif sawDigit { // \"123.\" is valid.\n\t\t\t\tvalidLen = i + 1\n\t\t\t}\n\t\t} else if c == 'e' || c == 'E' {\n\t\t\tif !sawDigit { // \"+.e\"\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif eIdx != 0 { // \"1e5e\"\n\t\t\t\tbreak\n\t\t\t}\n\t\t\teIdx = i\n\t\t} else if c < '0' || c > '9' {\n\t\t\tbreak\n\t\t} else {\n\t\t\tsawDigit = true\n\t\t\tvalidLen = i + 1\n\t\t}\n\t}\n\tvalid = s[:validLen]\n\tif valid == \"\" {\n\t\tvalid = \"0\"\n\t}\n\tif validLen == 0 || validLen != len(s) {\n\t\terr = errors.Trace(ErrTruncatedWrongVal.GenWithStackByArgs(\"FLOAT\", s))\n\t}\n\treturn valid, err\n}\n\n// ToString converts an interface to a string.\nfunc ToString(value interface{}) (string, error) {\n\tswitch v := value.(type) {\n\tcase bool:\n\t\tif v {\n\t\t\treturn \"1\", nil\n\t\t}\n\t\treturn \"0\", nil\n\tcase int:\n\t\treturn strconv.FormatInt(int64(v), 10), nil\n\tcase int64:\n\t\treturn strconv.FormatInt(v, 10), nil\n\tcase uint64:\n\t\treturn strconv.FormatUint(v, 10), nil\n\tcase float32:\n\t\treturn strconv.FormatFloat(float64(v), 'f', -1, 32), nil\n\tcase float64:\n\t\treturn strconv.FormatFloat(v, 'f', -1, 64), nil\n\tcase string:\n\t\treturn v, nil\n\tcase []byte:\n\t\treturn string(v), nil\n\tcase BinaryLiteral:\n\t\treturn v.ToString(), nil\n\tdefault:\n\t\treturn \"\", errors.Errorf(\"cannot convert %v(type %T) to string\", value, value)\n\t}\n}\n"
  },
  {
    "path": "pkg/types/datum.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode/utf8\"\n\t\"unsafe\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\t\"github.com/secretflow/scql/pkg/util/hack\"\n)\n\n// Kind constants.\nconst (\n\tKindNull          byte = 0\n\tKindInt64         byte = 1\n\tKindUint64        byte = 2\n\tKindFloat32       byte = 3\n\tKindFloat64       byte = 4\n\tKindString        byte = 5\n\tKindBytes         byte = 6\n\tKindBinaryLiteral byte = 7 // Used for BIT / HEX literals.\n\tKindMysqlDecimal  byte = 8\n\tKindMysqlDuration byte = 9\n\t// KindMysqlEnum     byte = 10\t\t// not supported by scql\n\tKindMysqlBit byte = 11 // Used for BIT table column values.\n\t// KindMysqlSet      byte = 12\t\t// not supported by scql\n\tKindMysqlTime  byte = 13\n\tKindInterface  byte = 14\n\tKindMinNotNull byte = 15\n\tKindMaxValue   byte = 16\n\tKindRaw        byte = 17\n\t// KindMysqlJSON     byte = 18      // not supported by scql\n)\n\n// Datum is a data box holds different kind of data.\n// It has better performance and is easier to use than `interface{}`.\ntype Datum struct {\n\tk         byte        // datum kind.\n\tcollation uint8       // collation can hold uint8 values.\n\tdecimal   uint16      // decimal can hold uint16 values.\n\tlength    uint32      // length can hold uint32 values.\n\ti         int64       // i can hold int64 uint64 float64 values.\n\tb         []byte      // b can hold string or []byte values.\n\tx         interface{} // x hold all other types.\n}\n\n// Copy deep copies a Datum.\nfunc (d *Datum) Copy() *Datum {\n\tret := *d\n\tif d.b != nil {\n\t\tret.b = make([]byte, len(d.b))\n\t\tcopy(ret.b, d.b)\n\t}\n\tswitch ret.Kind() {\n\tcase KindMysqlDecimal:\n\t\td := *d.GetMysqlDecimal()\n\t\tret.SetMysqlDecimal(&d)\n\tcase KindMysqlTime:\n\t\tret.SetMysqlTime(d.GetMysqlTime())\n\t}\n\treturn &ret\n}\n\n// Kind gets the kind of the datum.\nfunc (d *Datum) Kind() byte {\n\treturn d.k\n}\n\n// Collation gets the collation of the datum.\nfunc (d *Datum) Collation() byte {\n\treturn d.collation\n}\n\n// SetCollation sets the collation of the datum.\nfunc (d *Datum) SetCollation(collation byte) {\n\td.collation = collation\n}\n\n// Frac gets the frac of the datum.\nfunc (d *Datum) Frac() int {\n\treturn int(d.decimal)\n}\n\n// SetFrac sets the frac of the datum.\nfunc (d *Datum) SetFrac(frac int) {\n\td.decimal = uint16(frac)\n}\n\n// Length gets the length of the datum.\nfunc (d *Datum) Length() int {\n\treturn int(d.length)\n}\n\n// SetLength sets the length of the datum.\nfunc (d *Datum) SetLength(l int) {\n\td.length = uint32(l)\n}\n\n// IsNull checks if datum is null.\nfunc (d *Datum) IsNull() bool {\n\treturn d.k == KindNull\n}\n\n// GetInt64 gets int64 value.\nfunc (d *Datum) GetInt64() int64 {\n\treturn d.i\n}\n\n// SetInt64 sets int64 value.\nfunc (d *Datum) SetInt64(i int64) {\n\td.k = KindInt64\n\td.i = i\n}\n\n// GetUint64 gets uint64 value.\nfunc (d *Datum) GetUint64() uint64 {\n\treturn uint64(d.i)\n}\n\n// SetUint64 sets uint64 value.\nfunc (d *Datum) SetUint64(i uint64) {\n\td.k = KindUint64\n\td.i = int64(i)\n}\n\n// GetFloat64 gets float64 value.\nfunc (d *Datum) GetFloat64() float64 {\n\treturn math.Float64frombits(uint64(d.i))\n}\n\n// SetFloat64 sets float64 value.\nfunc (d *Datum) SetFloat64(f float64) {\n\td.k = KindFloat64\n\td.i = int64(math.Float64bits(f))\n}\n\n// GetFloat32 gets float32 value.\nfunc (d *Datum) GetFloat32() float32 {\n\treturn float32(math.Float64frombits(uint64(d.i)))\n}\n\n// SetFloat32 sets float32 value.\nfunc (d *Datum) SetFloat32(f float32) {\n\td.k = KindFloat32\n\td.i = int64(math.Float64bits(float64(f)))\n}\n\n// GetString gets string value.\nfunc (d *Datum) GetString() string {\n\treturn string(hack.String(d.b))\n}\n\n// SetString sets string value.\nfunc (d *Datum) SetString(s string) {\n\td.k = KindString\n\tsink(s)\n\td.b = hack.Slice(s)\n}\n\n// sink prevents s from being allocated on the stack.\nvar sink = func(s string) {\n}\n\n// GetBytes gets bytes value.\nfunc (d *Datum) GetBytes() []byte {\n\treturn d.b\n}\n\n// SetBytes sets bytes value to datum.\nfunc (d *Datum) SetBytes(b []byte) {\n\td.k = KindBytes\n\td.b = b\n}\n\n// SetBytesAsString sets bytes value to datum as string type.\nfunc (d *Datum) SetBytesAsString(b []byte) {\n\td.k = KindString\n\td.b = b\n}\n\n// GetInterface gets interface value.\nfunc (d *Datum) GetInterface() interface{} {\n\treturn d.x\n}\n\n// SetInterface sets interface to datum.\nfunc (d *Datum) SetInterface(x interface{}) {\n\td.k = KindInterface\n\td.x = x\n}\n\n// SetNull sets datum to nil.\nfunc (d *Datum) SetNull() {\n\td.k = KindNull\n\td.x = nil\n}\n\n// SetMinNotNull sets datum to minNotNull value.\nfunc (d *Datum) SetMinNotNull() {\n\td.k = KindMinNotNull\n\td.x = nil\n}\n\n// GetBinaryLiteral gets Bit value\nfunc (d *Datum) GetBinaryLiteral() BinaryLiteral {\n\treturn d.b\n}\n\n// GetMysqlBit gets MysqlBit value\nfunc (d *Datum) GetMysqlBit() BinaryLiteral {\n\treturn d.GetBinaryLiteral()\n}\n\n// SetBinaryLiteral sets Bit value\nfunc (d *Datum) SetBinaryLiteral(b BinaryLiteral) {\n\td.k = KindBinaryLiteral\n\td.b = b\n}\n\n// SetMysqlBit sets MysqlBit value\nfunc (d *Datum) SetMysqlBit(b BinaryLiteral) {\n\td.k = KindMysqlBit\n\td.b = b\n}\n\n// GetMysqlDecimal gets Decimal value\nfunc (d *Datum) GetMysqlDecimal() *MyDecimal {\n\treturn d.x.(*MyDecimal)\n}\n\n// SetMysqlDecimal sets Decimal value\nfunc (d *Datum) SetMysqlDecimal(b *MyDecimal) {\n\td.k = KindMysqlDecimal\n\td.x = b\n}\n\n// GetMysqlDuration gets Duration value\nfunc (d *Datum) GetMysqlDuration() Duration {\n\treturn Duration{Duration: time.Duration(d.i), Fsp: int8(d.decimal)}\n}\n\n// SetMysqlDuration sets Duration value\nfunc (d *Datum) SetMysqlDuration(b Duration) {\n\td.k = KindMysqlDuration\n\td.i = int64(b.Duration)\n\td.decimal = uint16(b.Fsp)\n}\n\n// GetMysqlTime gets types.Time value\nfunc (d *Datum) GetMysqlTime() Time {\n\treturn d.x.(Time)\n}\n\n// SetMysqlTime sets types.Time value\nfunc (d *Datum) SetMysqlTime(b Time) {\n\td.k = KindMysqlTime\n\td.x = b\n}\n\n// SetRaw sets raw value.\nfunc (d *Datum) SetRaw(b []byte) {\n\td.k = KindRaw\n\td.b = b\n}\n\n// GetRaw gets raw value.\nfunc (d *Datum) GetRaw() []byte {\n\treturn d.b\n}\n\nfunc (d *Datum) GetFieldType() *FieldType {\n\tswitch d.k {\n\tcase KindNull:\n\t\treturn NewFieldType(mysql.TypeNull)\n\tcase KindInt64, KindUint64:\n\t\treturn NewFieldType(mysql.TypeLonglong)\n\tcase KindFloat32:\n\t\treturn NewFieldType(mysql.TypeFloat)\n\tcase KindFloat64:\n\t\treturn NewFieldType(mysql.TypeDouble)\n\tcase KindString:\n\t\treturn NewFieldType(mysql.TypeString)\n\tcase KindBytes, KindBinaryLiteral:\n\t\treturn NewFieldType(mysql.TypeVarString)\n\tcase KindMysqlDecimal:\n\t\treturn NewFieldType(mysql.TypeDecimal)\n\tcase KindMysqlDuration:\n\t\treturn NewFieldType(mysql.TypeDuration)\n\tcase KindMysqlBit:\n\t\treturn NewFieldType(mysql.TypeBit)\n\tcase KindMysqlTime:\n\t\treturn NewFieldType(mysql.TypeDatetime)\n\t}\n\treturn nil\n}\n\n// SetAutoID set the auto increment ID according to its int flag.\nfunc (d *Datum) SetAutoID(id int64, flag uint) {\n\tif mysql.HasUnsignedFlag(flag) {\n\t\td.SetUint64(uint64(id))\n\t} else {\n\t\td.SetInt64(id)\n\t}\n}\n\n// String returns a human-readable description of Datum. It is intended only for debugging.\nfunc (d Datum) String() string {\n\tvar t string\n\tswitch d.k {\n\tcase KindNull:\n\t\tt = \"KindNull\"\n\tcase KindInt64:\n\t\tt = \"KindInt64\"\n\tcase KindUint64:\n\t\tt = \"KindUint64\"\n\tcase KindFloat32:\n\t\tt = \"KindFloat32\"\n\tcase KindFloat64:\n\t\tt = \"KindFloat64\"\n\tcase KindString:\n\t\tt = \"KindString\"\n\tcase KindBytes:\n\t\tt = \"KindBytes\"\n\tcase KindMysqlDecimal:\n\t\tt = \"KindMysqlDecimal\"\n\tcase KindMysqlDuration:\n\t\tt = \"KindMysqlDuration\"\n\tcase KindBinaryLiteral:\n\t\tt = \"KindBinaryLiteral\"\n\tcase KindMysqlBit:\n\t\tt = \"KindMysqlBit\"\n\tcase KindMysqlTime:\n\t\tt = \"KindMysqlTime\"\n\tdefault:\n\t\tt = \"Unknown\"\n\t}\n\tv := d.GetValue()\n\tif b, ok := v.([]byte); ok && d.k == KindBytes {\n\t\tv = string(b)\n\t}\n\treturn fmt.Sprintf(\"%v %v\", t, v)\n}\n\n// GetValue gets the value of the datum of any kind.\nfunc (d *Datum) GetValue() interface{} {\n\tswitch d.k {\n\tcase KindInt64:\n\t\treturn d.GetInt64()\n\tcase KindUint64:\n\t\treturn d.GetUint64()\n\tcase KindFloat32:\n\t\treturn d.GetFloat32()\n\tcase KindFloat64:\n\t\treturn d.GetFloat64()\n\tcase KindString:\n\t\treturn d.GetString()\n\tcase KindBytes:\n\t\treturn d.GetBytes()\n\tcase KindMysqlDecimal:\n\t\treturn d.GetMysqlDecimal()\n\tcase KindMysqlDuration:\n\t\treturn d.GetMysqlDuration()\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\treturn d.GetBinaryLiteral()\n\tcase KindMysqlTime:\n\t\treturn d.GetMysqlTime()\n\tdefault:\n\t\treturn d.GetInterface()\n\t}\n}\n\n// SetValue sets any kind of value.\nfunc (d *Datum) SetValue(val interface{}) {\n\tswitch x := val.(type) {\n\tcase nil:\n\t\td.SetNull()\n\tcase bool:\n\t\tif x {\n\t\t\td.SetInt64(1)\n\t\t} else {\n\t\t\td.SetInt64(0)\n\t\t}\n\tcase int:\n\t\td.SetInt64(int64(x))\n\tcase int64:\n\t\td.SetInt64(x)\n\tcase uint64:\n\t\td.SetUint64(x)\n\tcase float32:\n\t\td.SetFloat32(x)\n\tcase float64:\n\t\td.SetFloat64(x)\n\tcase string:\n\t\td.SetString(x)\n\tcase []byte:\n\t\td.SetBytes(x)\n\tcase *MyDecimal:\n\t\td.SetMysqlDecimal(x)\n\tcase Duration:\n\t\td.SetMysqlDuration(x)\n\tcase BinaryLiteral:\n\t\td.SetBinaryLiteral(x)\n\tcase BitLiteral: // Store as BinaryLiteral for Bit and Hex literals\n\t\td.SetBinaryLiteral(BinaryLiteral(x))\n\tcase HexLiteral:\n\t\td.SetBinaryLiteral(BinaryLiteral(x))\n\tcase Time:\n\t\td.SetMysqlTime(x)\n\tdefault:\n\t\td.SetInterface(x)\n\t}\n}\n\n// CompareDatum compares datum to another datum.\n// TODO: return error properly.\nfunc (d *Datum) CompareDatum(sc *stmtctx.StatementContext, ad *Datum) (int, error) {\n\tswitch ad.k {\n\tcase KindNull:\n\t\tif d.k == KindNull {\n\t\t\treturn 0, nil\n\t\t}\n\t\treturn 1, nil\n\tcase KindMinNotNull:\n\t\tif d.k == KindNull {\n\t\t\treturn -1, nil\n\t\t} else if d.k == KindMinNotNull {\n\t\t\treturn 0, nil\n\t\t}\n\t\treturn 1, nil\n\tcase KindMaxValue:\n\t\tif d.k == KindMaxValue {\n\t\t\treturn 0, nil\n\t\t}\n\t\treturn -1, nil\n\tcase KindInt64:\n\t\treturn d.compareInt64(sc, ad.GetInt64())\n\tcase KindUint64:\n\t\treturn d.compareUint64(sc, ad.GetUint64())\n\tcase KindFloat32, KindFloat64:\n\t\treturn d.compareFloat64(sc, ad.GetFloat64())\n\tcase KindString:\n\t\treturn d.compareString(sc, ad.GetString())\n\tcase KindBytes:\n\t\treturn d.compareBytes(sc, ad.GetBytes())\n\tcase KindMysqlDecimal:\n\t\treturn d.compareMysqlDecimal(sc, ad.GetMysqlDecimal())\n\tcase KindMysqlDuration:\n\t\treturn d.compareMysqlDuration(sc, ad.GetMysqlDuration())\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\treturn d.compareBinaryLiteral(sc, ad.GetBinaryLiteral())\n\tcase KindMysqlTime:\n\t\treturn d.compareMysqlTime(sc, ad.GetMysqlTime())\n\tdefault:\n\t\treturn 0, nil\n\t}\n}\n\nfunc (d *Datum) compareInt64(sc *stmtctx.StatementContext, i int64) (int, error) {\n\tswitch d.k {\n\tcase KindMaxValue:\n\t\treturn 1, nil\n\tcase KindInt64:\n\t\treturn CompareInt64(d.i, i), nil\n\tcase KindUint64:\n\t\tif i < 0 || d.GetUint64() > math.MaxInt64 {\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn CompareInt64(d.i, i), nil\n\tdefault:\n\t\treturn d.compareFloat64(sc, float64(i))\n\t}\n}\n\nfunc (d *Datum) compareUint64(sc *stmtctx.StatementContext, u uint64) (int, error) {\n\tswitch d.k {\n\tcase KindMaxValue:\n\t\treturn 1, nil\n\tcase KindInt64:\n\t\tif d.i < 0 || u > math.MaxInt64 {\n\t\t\treturn -1, nil\n\t\t}\n\t\treturn CompareInt64(d.i, int64(u)), nil\n\tcase KindUint64:\n\t\treturn CompareUint64(d.GetUint64(), u), nil\n\tdefault:\n\t\treturn d.compareFloat64(sc, float64(u))\n\t}\n}\n\nfunc (d *Datum) compareFloat64(sc *stmtctx.StatementContext, f float64) (int, error) {\n\tswitch d.k {\n\tcase KindNull, KindMinNotNull:\n\t\treturn -1, nil\n\tcase KindMaxValue:\n\t\treturn 1, nil\n\tcase KindInt64:\n\t\treturn CompareFloat64(float64(d.i), f), nil\n\tcase KindUint64:\n\t\treturn CompareFloat64(float64(d.GetUint64()), f), nil\n\tcase KindFloat32, KindFloat64:\n\t\treturn CompareFloat64(d.GetFloat64(), f), nil\n\tcase KindString, KindBytes:\n\t\tfVal, err := StrToFloat(sc, d.GetString())\n\t\treturn CompareFloat64(fVal, f), errors.Trace(err)\n\tcase KindMysqlDecimal:\n\t\tfVal, err := d.GetMysqlDecimal().ToFloat64()\n\t\treturn CompareFloat64(fVal, f), errors.Trace(err)\n\tcase KindMysqlDuration:\n\t\tfVal := d.GetMysqlDuration().Seconds()\n\t\treturn CompareFloat64(fVal, f), nil\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\tval, err := d.GetBinaryLiteral().ToInt(sc)\n\t\tfVal := float64(val)\n\t\treturn CompareFloat64(fVal, f), errors.Trace(err)\n\tcase KindMysqlTime:\n\t\tfVal, err := d.GetMysqlTime().ToNumber().ToFloat64()\n\t\treturn CompareFloat64(fVal, f), errors.Trace(err)\n\tdefault:\n\t\treturn -1, nil\n\t}\n}\n\nfunc (d *Datum) compareString(sc *stmtctx.StatementContext, s string) (int, error) {\n\tswitch d.k {\n\tcase KindNull, KindMinNotNull:\n\t\treturn -1, nil\n\tcase KindMaxValue:\n\t\treturn 1, nil\n\tcase KindString, KindBytes:\n\t\treturn CompareString(d.GetString(), s), nil\n\tcase KindMysqlDecimal:\n\t\tdec := new(MyDecimal)\n\t\terr := sc.HandleTruncate(dec.FromString(hack.Slice(s)))\n\t\treturn d.GetMysqlDecimal().Compare(dec), errors.Trace(err)\n\tcase KindMysqlTime:\n\t\tdt, err := ParseDatetime(sc, s)\n\t\treturn d.GetMysqlTime().Compare(dt), errors.Trace(err)\n\tcase KindMysqlDuration:\n\t\tdur, err := ParseDuration(sc, s, MaxFsp)\n\t\treturn d.GetMysqlDuration().Compare(dur), errors.Trace(err)\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\treturn CompareString(d.GetBinaryLiteral().ToString(), s), nil\n\tdefault:\n\t\tfVal, err := StrToFloat(sc, s)\n\t\tif err != nil {\n\t\t\treturn 0, errors.Trace(err)\n\t\t}\n\t\treturn d.compareFloat64(sc, fVal)\n\t}\n}\n\nfunc (d *Datum) compareBytes(sc *stmtctx.StatementContext, b []byte) (int, error) {\n\tstr := string(hack.String(b))\n\treturn d.compareString(sc, str)\n}\n\nfunc (d *Datum) compareMysqlDecimal(sc *stmtctx.StatementContext, dec *MyDecimal) (int, error) {\n\tswitch d.k {\n\tcase KindNull, KindMinNotNull:\n\t\treturn -1, nil\n\tcase KindMaxValue:\n\t\treturn 1, nil\n\tcase KindMysqlDecimal:\n\t\treturn d.GetMysqlDecimal().Compare(dec), nil\n\tcase KindString, KindBytes:\n\t\tdDec := new(MyDecimal)\n\t\terr := sc.HandleTruncate(dDec.FromString(d.GetBytes()))\n\t\treturn dDec.Compare(dec), errors.Trace(err)\n\tdefault:\n\t\tdVal, err := d.ConvertTo(sc, NewFieldType(mysql.TypeNewDecimal))\n\t\tif err != nil {\n\t\t\treturn 0, errors.Trace(err)\n\t\t}\n\t\treturn dVal.GetMysqlDecimal().Compare(dec), nil\n\t}\n}\n\nfunc (d *Datum) compareMysqlDuration(sc *stmtctx.StatementContext, dur Duration) (int, error) {\n\tswitch d.k {\n\tcase KindMysqlDuration:\n\t\treturn d.GetMysqlDuration().Compare(dur), nil\n\tcase KindString, KindBytes:\n\t\tdDur, err := ParseDuration(sc, d.GetString(), MaxFsp)\n\t\treturn dDur.Compare(dur), errors.Trace(err)\n\tdefault:\n\t\treturn d.compareFloat64(sc, dur.Seconds())\n\t}\n}\n\nfunc (d *Datum) compareBinaryLiteral(sc *stmtctx.StatementContext, b BinaryLiteral) (int, error) {\n\tswitch d.k {\n\tcase KindString, KindBytes:\n\t\treturn CompareString(d.GetString(), b.ToString()), nil\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\treturn CompareString(d.GetBinaryLiteral().ToString(), b.ToString()), nil\n\tdefault:\n\t\tval, err := b.ToInt(sc)\n\t\tif err != nil {\n\t\t\treturn 0, errors.Trace(err)\n\t\t}\n\t\tresult, err := d.compareFloat64(sc, float64(val))\n\t\treturn result, errors.Trace(err)\n\t}\n}\n\nfunc (d *Datum) compareMysqlTime(sc *stmtctx.StatementContext, time Time) (int, error) {\n\tswitch d.k {\n\tcase KindString, KindBytes:\n\t\tdt, err := ParseDatetime(sc, d.GetString())\n\t\treturn dt.Compare(time), errors.Trace(err)\n\tcase KindMysqlTime:\n\t\treturn d.GetMysqlTime().Compare(time), nil\n\tdefault:\n\t\tfVal, err := time.ToNumber().ToFloat64()\n\t\tif err != nil {\n\t\t\treturn 0, errors.Trace(err)\n\t\t}\n\t\treturn d.compareFloat64(sc, fVal)\n\t}\n}\n\n// ConvertTo converts a datum to the target field type.\n// change this method need sync modification to type2Kind in rowcodec/types.go\nfunc (d *Datum) ConvertTo(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\tif d.k == KindNull {\n\t\treturn Datum{}, nil\n\t}\n\tswitch target.Tp { // TODO: implement mysql types convert when \"CAST() AS\" syntax are supported.\n\tcase mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong:\n\t\tunsigned := mysql.HasUnsignedFlag(target.Flag)\n\t\tif unsigned {\n\t\t\treturn d.convertToUint(sc, target)\n\t\t}\n\t\treturn d.convertToInt(sc, target)\n\tcase mysql.TypeFloat, mysql.TypeDouble:\n\t\treturn d.convertToFloat(sc, target)\n\tcase mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\tmysql.TypeString, mysql.TypeVarchar, mysql.TypeVarString:\n\t\treturn d.convertToString(sc, target)\n\tcase mysql.TypeTimestamp:\n\t\treturn d.convertToMysqlTimestamp(sc, target)\n\tcase mysql.TypeDatetime, mysql.TypeDate:\n\t\treturn d.convertToMysqlTime(sc, target)\n\tcase mysql.TypeDuration:\n\t\treturn d.convertToMysqlDuration(sc, target)\n\tcase mysql.TypeNewDecimal:\n\t\treturn d.convertToMysqlDecimal(sc, target)\n\tcase mysql.TypeYear:\n\t\treturn d.convertToMysqlYear(sc, target)\n\tcase mysql.TypeBit:\n\t\treturn d.convertToMysqlBit(sc, target)\n\tcase mysql.TypeNull:\n\t\treturn Datum{}, nil\n\tdefault:\n\t\tpanic(\"should never happen\")\n\t}\n}\n\nfunc (d *Datum) convertToFloat(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\tvar (\n\t\tf   float64\n\t\tret Datum\n\t\terr error\n\t)\n\tswitch d.k {\n\tcase KindNull:\n\t\treturn ret, nil\n\tcase KindInt64:\n\t\tf = float64(d.GetInt64())\n\tcase KindUint64:\n\t\tf = float64(d.GetUint64())\n\tcase KindFloat32, KindFloat64:\n\t\tf = d.GetFloat64()\n\tcase KindString, KindBytes:\n\t\tf, err = StrToFloat(sc, d.GetString())\n\tcase KindMysqlTime:\n\t\tf, err = d.GetMysqlTime().ToNumber().ToFloat64()\n\tcase KindMysqlDuration:\n\t\tf, err = d.GetMysqlDuration().ToNumber().ToFloat64()\n\tcase KindMysqlDecimal:\n\t\tf, err = d.GetMysqlDecimal().ToFloat64()\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\tval, err1 := d.GetBinaryLiteral().ToInt(sc)\n\t\tf, err = float64(val), err1\n\tdefault:\n\t\treturn invalidConv(d, target.Tp)\n\t}\n\tvar err1 error\n\tf, err1 = ProduceFloatWithSpecifiedTp(f, target, sc)\n\tif err == nil && err1 != nil {\n\t\terr = err1\n\t}\n\tif target.Tp == mysql.TypeFloat {\n\t\tret.SetFloat32(float32(f))\n\t} else {\n\t\tret.SetFloat64(f)\n\t}\n\treturn ret, errors.Trace(err)\n}\n\n// ProduceFloatWithSpecifiedTp produces a new float64 according to `flen` and `decimal`.\nfunc ProduceFloatWithSpecifiedTp(f float64, target *FieldType, sc *stmtctx.StatementContext) (_ float64, err error) {\n\t// For float and following double type, we will only truncate it for float(M, D) format.\n\t// If no D is set, we will handle it like origin float whether M is set or not.\n\tif target.Flen != UnspecifiedLength && target.Decimal != UnspecifiedLength {\n\t\tf, err = TruncateFloat(f, target.Flen, target.Decimal)\n\t\tif err = sc.HandleOverflow(err, err); err != nil {\n\t\t\treturn f, errors.Trace(err)\n\t\t}\n\t}\n\tif mysql.HasUnsignedFlag(target.Flag) && f < 0 {\n\t\treturn 0, overflow(f, target.Tp)\n\t}\n\treturn f, nil\n}\n\nfunc (d *Datum) convertToString(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\tvar ret Datum\n\tvar s string\n\tswitch d.k {\n\tcase KindInt64:\n\t\ts = strconv.FormatInt(d.GetInt64(), 10)\n\tcase KindUint64:\n\t\ts = strconv.FormatUint(d.GetUint64(), 10)\n\tcase KindFloat32:\n\t\ts = strconv.FormatFloat(d.GetFloat64(), 'f', -1, 32)\n\tcase KindFloat64:\n\t\ts = strconv.FormatFloat(d.GetFloat64(), 'f', -1, 64)\n\tcase KindString, KindBytes:\n\t\ts = d.GetString()\n\tcase KindMysqlTime:\n\t\ts = d.GetMysqlTime().String()\n\tcase KindMysqlDuration:\n\t\ts = d.GetMysqlDuration().String()\n\tcase KindMysqlDecimal:\n\t\ts = d.GetMysqlDecimal().String()\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\ts = d.GetBinaryLiteral().ToString()\n\tdefault:\n\t\treturn invalidConv(d, target.Tp)\n\t}\n\ts, err := ProduceStrWithSpecifiedTp(s, target, sc, true)\n\tret.SetString(s)\n\tif target.Charset == charset.CharsetBin {\n\t\tret.k = KindBytes\n\t}\n\treturn ret, errors.Trace(err)\n}\n\n// ProduceStrWithSpecifiedTp produces a new string according to `flen` and `chs`. Param `padZero` indicates\n// whether we should pad `\\0` for `binary(flen)` type.\nfunc ProduceStrWithSpecifiedTp(s string, tp *FieldType, sc *stmtctx.StatementContext, padZero bool) (_ string, err error) {\n\tflen, chs := tp.Flen, tp.Charset\n\tif flen >= 0 {\n\t\t// Flen is the rune length, not binary length, for UTF8 charset, we need to calculate the\n\t\t// rune count and truncate to Flen runes if it is too long.\n\t\tif chs == charset.CharsetUTF8 || chs == charset.CharsetUTF8MB4 {\n\t\t\tcharacterLen := utf8.RuneCountInString(s)\n\t\t\tif characterLen > flen {\n\t\t\t\t// 1. If len(s) is 0 and flen is 0, truncateLen will be 0, don't truncate s.\n\t\t\t\t//    CREATE TABLE t (a char(0));\n\t\t\t\t//    INSERT INTO t VALUES (``);\n\t\t\t\t// 2. If len(s) is 10 and flen is 0, truncateLen will be 0 too, but we still need to truncate s.\n\t\t\t\t//    SELECT 1, CAST(1234 AS CHAR(0));\n\t\t\t\t// So truncateLen is not a suitable variable to determine to do truncate or not.\n\t\t\t\tvar runeCount int\n\t\t\t\tvar truncateLen int\n\t\t\t\tfor i := range s {\n\t\t\t\t\tif runeCount == flen {\n\t\t\t\t\t\ttruncateLen = i\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\truneCount++\n\t\t\t\t}\n\t\t\t\terr = ErrDataTooLong.GenWithStack(\"Data Too Long, field len %d, data len %d\", flen, characterLen)\n\t\t\t\ts = truncateStr(s, truncateLen)\n\t\t\t}\n\t\t} else if len(s) > flen {\n\t\t\terr = ErrDataTooLong.GenWithStack(\"Data Too Long, field len %d, data len %d\", flen, len(s))\n\t\t\ts = truncateStr(s, flen)\n\t\t} else if tp.Tp == mysql.TypeString && IsBinaryStr(tp) && len(s) < flen && padZero {\n\t\t\tpadding := make([]byte, flen-len(s))\n\t\t\ts = string(append([]byte(s), padding...))\n\t\t}\n\t}\n\treturn s, errors.Trace(sc.HandleTruncate(err))\n}\n\nfunc (d *Datum) convertToInt(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\ti64, err := d.toSignedInteger(sc, target.Tp)\n\treturn NewIntDatum(i64), errors.Trace(err)\n}\n\nfunc (d *Datum) convertToUint(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\ttp := target.Tp\n\tupperBound := IntergerUnsignedUpperBound(tp)\n\tvar (\n\t\tval uint64\n\t\terr error\n\t\tret Datum\n\t)\n\tswitch d.k {\n\tcase KindInt64:\n\t\tval, err = ConvertIntToUint(sc, d.GetInt64(), upperBound, tp)\n\tcase KindUint64:\n\t\tval, err = ConvertUintToUint(d.GetUint64(), upperBound, tp)\n\tcase KindFloat32, KindFloat64:\n\t\tval, err = ConvertFloatToUint(sc, d.GetFloat64(), upperBound, tp)\n\tcase KindString, KindBytes:\n\t\tuval, err1 := StrToUint(sc, d.GetString())\n\t\tif err1 != nil && ErrOverflow.Equal(err1) {\n\t\t\treturn ret, errors.Trace(err1)\n\t\t}\n\t\tval, err = ConvertUintToUint(uval, upperBound, tp)\n\t\tif err != nil {\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\t\terr = err1\n\tcase KindMysqlTime:\n\t\tdec := d.GetMysqlTime().ToNumber()\n\t\terr = dec.Round(dec, 0, ModeHalfEven)\n\t\tival, err1 := dec.ToInt()\n\t\tif err == nil {\n\t\t\terr = err1\n\t\t}\n\t\tval, err1 = ConvertIntToUint(sc, ival, upperBound, tp)\n\t\tif err == nil {\n\t\t\terr = err1\n\t\t}\n\tcase KindMysqlDuration:\n\t\tdec := d.GetMysqlDuration().ToNumber()\n\t\terr = dec.Round(dec, 0, ModeHalfEven)\n\t\tival, err1 := dec.ToInt()\n\t\tif err1 == nil {\n\t\t\tval, err = ConvertIntToUint(sc, ival, upperBound, tp)\n\t\t}\n\tcase KindMysqlDecimal:\n\t\tval, err = ConvertDecimalToUint(sc, d.GetMysqlDecimal(), upperBound, tp)\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\tval, err = d.GetBinaryLiteral().ToInt(sc)\n\tdefault:\n\t\treturn invalidConv(d, target.Tp)\n\t}\n\tret.SetUint64(val)\n\tif err != nil {\n\t\treturn ret, errors.Trace(err)\n\t}\n\treturn ret, nil\n}\n\nfunc (d *Datum) convertToMysqlTimestamp(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\tvar (\n\t\tret Datum\n\t\tt   Time\n\t\terr error\n\t)\n\tfsp := DefaultFsp\n\tif target.Decimal != UnspecifiedLength {\n\t\tfsp = int8(target.Decimal)\n\t}\n\tswitch d.k {\n\tcase KindMysqlTime:\n\t\tt = d.GetMysqlTime()\n\t\tt, err = t.RoundFrac(sc, fsp)\n\tcase KindMysqlDuration:\n\t\tt, err = d.GetMysqlDuration().ConvertToTime(sc, mysql.TypeTimestamp)\n\t\tif err != nil {\n\t\t\tret.SetValue(t)\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\t\tt, err = t.RoundFrac(sc, fsp)\n\tcase KindString, KindBytes:\n\t\tt, err = ParseTime(sc, d.GetString(), mysql.TypeTimestamp, fsp)\n\tcase KindInt64:\n\t\tt, err = ParseTimeFromNum(sc, d.GetInt64(), mysql.TypeTimestamp, fsp)\n\tcase KindMysqlDecimal:\n\t\tt, err = ParseTimeFromFloatString(sc, d.GetMysqlDecimal().String(), mysql.TypeTimestamp, fsp)\n\tdefault:\n\t\treturn invalidConv(d, mysql.TypeTimestamp)\n\t}\n\tt.SetType(mysql.TypeTimestamp)\n\tret.SetMysqlTime(t)\n\tif err != nil {\n\t\treturn ret, errors.Trace(err)\n\t}\n\treturn ret, nil\n}\n\nfunc (d *Datum) convertToMysqlTime(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\ttp := target.Tp\n\tfsp := DefaultFsp\n\tif target.Decimal != UnspecifiedLength {\n\t\tfsp = int8(target.Decimal)\n\t}\n\tvar (\n\t\tret Datum\n\t\tt   Time\n\t\terr error\n\t)\n\tswitch d.k {\n\tcase KindMysqlTime:\n\t\tt, err = d.GetMysqlTime().Convert(sc, tp)\n\t\tif err != nil {\n\t\t\tret.SetValue(t)\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\t\tt, err = t.RoundFrac(sc, fsp)\n\tcase KindMysqlDuration:\n\t\tt, err = d.GetMysqlDuration().ConvertToTime(sc, tp)\n\t\tif err != nil {\n\t\t\tret.SetValue(t)\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\t\tt, err = t.RoundFrac(sc, fsp)\n\tcase KindMysqlDecimal:\n\t\tt, err = ParseTimeFromFloatString(sc, d.GetMysqlDecimal().String(), tp, fsp)\n\tcase KindString, KindBytes:\n\t\tt, err = ParseTime(sc, d.GetString(), tp, fsp)\n\tcase KindInt64:\n\t\tt, err = ParseTimeFromNum(sc, d.GetInt64(), tp, fsp)\n\tdefault:\n\t\treturn invalidConv(d, tp)\n\t}\n\tif tp == mysql.TypeDate {\n\t\t// Truncate hh:mm:ss part if the type is Date.\n\t\tt.SetCoreTime(FromDate(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0))\n\t}\n\tret.SetValue(t)\n\tif err != nil {\n\t\treturn ret, errors.Trace(err)\n\t}\n\treturn ret, nil\n}\n\nfunc (d *Datum) convertToMysqlDuration(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\ttp := target.Tp\n\tfsp := DefaultFsp\n\tif target.Decimal != UnspecifiedLength {\n\t\tfsp = int8(target.Decimal)\n\t}\n\tvar ret Datum\n\tswitch d.k {\n\tcase KindMysqlTime:\n\t\tdur, err := d.GetMysqlTime().ConvertToDuration()\n\t\tif err != nil {\n\t\t\tret.SetValue(dur)\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\t\tdur, err = dur.RoundFrac(fsp)\n\t\tret.SetValue(dur)\n\t\tif err != nil {\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\tcase KindMysqlDuration:\n\t\tdur, err := d.GetMysqlDuration().RoundFrac(fsp)\n\t\tret.SetValue(dur)\n\t\tif err != nil {\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\tcase KindInt64, KindFloat32, KindFloat64, KindMysqlDecimal:\n\t\t// TODO: We need a ParseDurationFromNum to avoid the cost of converting a num to string.\n\t\ttimeStr, err := d.ToString()\n\t\tif err != nil {\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\t\ttimeNum, err := d.ToInt64(sc)\n\t\tif err != nil {\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\t\t// For huge numbers(>'0001-00-00 00-00-00') try full DATETIME in ParseDuration.\n\t\tif timeNum > MaxDuration && timeNum < 10000000000 {\n\t\t\t// mysql return max in no strict sql mode.\n\t\t\tret.SetValue(Duration{Duration: MaxTime, Fsp: 0})\n\t\t\treturn ret, ErrWrongValue.GenWithStackByArgs(TimeStr, timeStr)\n\t\t}\n\t\tif timeNum < -MaxDuration {\n\t\t\treturn ret, ErrWrongValue.GenWithStackByArgs(TimeStr, timeStr)\n\t\t}\n\t\tt, err := ParseDuration(sc, timeStr, fsp)\n\t\tret.SetValue(t)\n\t\tif err != nil {\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\tcase KindString, KindBytes:\n\t\tt, err := ParseDuration(sc, d.GetString(), fsp)\n\t\tret.SetValue(t)\n\t\tif err != nil {\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\tdefault:\n\t\treturn invalidConv(d, tp)\n\t}\n\treturn ret, nil\n}\n\nfunc (d *Datum) convertToMysqlDecimal(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\tvar ret Datum\n\tret.SetLength(target.Flen)\n\tret.SetFrac(target.Decimal)\n\tvar dec = &MyDecimal{}\n\tvar err error\n\tswitch d.k {\n\tcase KindInt64:\n\t\tdec.FromInt(d.GetInt64())\n\tcase KindUint64:\n\t\tdec.FromUint(d.GetUint64())\n\tcase KindFloat32, KindFloat64:\n\t\terr = dec.FromFloat64(d.GetFloat64())\n\tcase KindString, KindBytes:\n\t\terr = dec.FromString(d.GetBytes())\n\tcase KindMysqlDecimal:\n\t\t*dec = *d.GetMysqlDecimal()\n\tcase KindMysqlTime:\n\t\tdec = d.GetMysqlTime().ToNumber()\n\tcase KindMysqlDuration:\n\t\tdec = d.GetMysqlDuration().ToNumber()\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\tval, err1 := d.GetBinaryLiteral().ToInt(sc)\n\t\terr = err1\n\t\tdec.FromUint(val)\n\tdefault:\n\t\treturn invalidConv(d, target.Tp)\n\t}\n\tvar err1 error\n\tdec, err1 = ProduceDecWithSpecifiedTp(dec, target, sc)\n\tif err == nil && err1 != nil {\n\t\terr = err1\n\t}\n\tif dec.negative && mysql.HasUnsignedFlag(target.Flag) {\n\t\t*dec = zeroMyDecimal\n\t\tif err == nil {\n\t\t\terr = ErrOverflow.GenWithStackByArgs(\"DECIMAL\", fmt.Sprintf(\"(%d, %d)\", target.Flen, target.Decimal))\n\t\t}\n\t}\n\tret.SetValue(dec)\n\treturn ret, err\n}\n\n// ProduceDecWithSpecifiedTp produces a new decimal according to `flen` and `decimal`.\nfunc ProduceDecWithSpecifiedTp(dec *MyDecimal, tp *FieldType, sc *stmtctx.StatementContext) (_ *MyDecimal, err error) {\n\tflen, decimal := tp.Flen, tp.Decimal\n\tif flen != UnspecifiedLength && decimal != UnspecifiedLength {\n\t\tif flen < decimal {\n\t\t\treturn nil, ErrMBiggerThanD.GenWithStackByArgs(\"\")\n\t\t}\n\t\tprec, frac := dec.PrecisionAndFrac()\n\t\tif !dec.IsZero() && prec-frac > flen-decimal {\n\t\t\tdec = NewMaxOrMinDec(dec.IsNegative(), flen, decimal)\n\t\t\t// select (cast 111 as decimal(1)) causes a warning in MySQL.\n\t\t\terr = ErrOverflow.GenWithStackByArgs(\"DECIMAL\", fmt.Sprintf(\"(%d, %d)\", flen, decimal))\n\t\t} else if frac != decimal {\n\t\t\told := *dec\n\t\t\terr = dec.Round(dec, decimal, ModeHalfEven)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif !dec.IsZero() && frac > decimal && dec.Compare(&old) != 0 {\n\t\t\t\tif sc.InInsertStmt || sc.InUpdateStmt || sc.InDeleteStmt {\n\t\t\t\t\t// fix https://github.com/pingcap/tidb/issues/3895\n\t\t\t\t\t// fix https://github.com/pingcap/tidb/issues/5532\n\t\t\t\t\tsc.AppendWarning(ErrTruncatedWrongVal.GenWithStackByArgs(\"DECIMAL\", &old))\n\t\t\t\t\terr = nil\n\t\t\t\t} else {\n\t\t\t\t\terr = sc.HandleTruncate(ErrTruncatedWrongVal.GenWithStackByArgs(\"DECIMAL\", &old))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif ErrOverflow.Equal(err) {\n\t\t// TODO: warnErr need to be ErrWarnDataOutOfRange\n\t\terr = sc.HandleOverflow(err, err)\n\t}\n\tunsigned := mysql.HasUnsignedFlag(tp.Flag)\n\tif unsigned && dec.IsNegative() {\n\t\tdec = dec.FromUint(0)\n\t}\n\treturn dec, err\n}\n\nfunc (d *Datum) convertToMysqlYear(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\tvar (\n\t\tret    Datum\n\t\ty      int64\n\t\terr    error\n\t\tadjust bool\n\t)\n\tswitch d.k {\n\tcase KindString, KindBytes:\n\t\ts := d.GetString()\n\t\ty, err = StrToInt(sc, s)\n\t\tif err != nil {\n\t\t\tret.SetInt64(0)\n\t\t\treturn ret, errors.Trace(err)\n\t\t}\n\t\tif len(s) != 4 && len(s) > 0 && s[0:1] == \"0\" {\n\t\t\tadjust = true\n\t\t}\n\tcase KindMysqlTime:\n\t\ty = int64(d.GetMysqlTime().Year())\n\tcase KindMysqlDuration:\n\t\ty = int64(time.Now().Year())\n\tdefault:\n\t\tret, err = d.convertToInt(sc, NewFieldType(mysql.TypeLonglong))\n\t\tif err != nil {\n\t\t\t_, err = invalidConv(d, target.Tp)\n\t\t\tret.SetInt64(0)\n\t\t\treturn ret, err\n\t\t}\n\t\ty = ret.GetInt64()\n\t}\n\ty, err = AdjustYear(y, adjust)\n\tif err != nil {\n\t\t_, err = invalidConv(d, target.Tp)\n\t}\n\tret.SetInt64(y)\n\treturn ret, err\n}\n\nfunc (d *Datum) convertToMysqlBit(sc *stmtctx.StatementContext, target *FieldType) (Datum, error) {\n\tvar ret Datum\n\tvar uintValue uint64\n\tvar err error\n\tswitch d.k {\n\tcase KindString, KindBytes:\n\t\tuintValue, err = BinaryLiteral(d.b).ToInt(sc)\n\tcase KindInt64:\n\t\t// if input kind is int64 (signed), when trans to bit, we need to treat it as unsigned\n\t\td.k = KindUint64\n\t\tfallthrough\n\tdefault:\n\t\tuintDatum, err1 := d.convertToUint(sc, target)\n\t\tuintValue, err = uintDatum.GetUint64(), err1\n\t}\n\tif target.Flen < 64 && uintValue >= 1<<(uint64(target.Flen)) {\n\t\treturn Datum{}, errors.Trace(ErrDataTooLong.GenWithStack(\"Data Too Long, field len %d\", target.Flen))\n\t}\n\tbyteSize := (target.Flen + 7) >> 3\n\tret.SetMysqlBit(NewBinaryLiteralFromUint(uintValue, byteSize))\n\treturn ret, errors.Trace(err)\n}\n\n// ToBool converts to a bool.\n// We will use 1 for true, and 0 for false.\nfunc (d *Datum) ToBool(sc *stmtctx.StatementContext) (int64, error) {\n\tvar err error\n\tisZero := false\n\tswitch d.Kind() {\n\tcase KindInt64:\n\t\tisZero = d.GetInt64() == 0\n\tcase KindUint64:\n\t\tisZero = d.GetUint64() == 0\n\tcase KindFloat32:\n\t\tisZero = RoundFloat(d.GetFloat64()) == 0\n\tcase KindFloat64:\n\t\tisZero = RoundFloat(d.GetFloat64()) == 0\n\tcase KindString, KindBytes:\n\t\tiVal, err1 := StrToInt(sc, d.GetString())\n\t\tisZero, err = iVal == 0, err1\n\tcase KindMysqlTime:\n\t\tisZero = d.GetMysqlTime().IsZero()\n\tcase KindMysqlDuration:\n\t\tisZero = d.GetMysqlDuration().Duration == 0\n\tcase KindMysqlDecimal:\n\t\tv, err1 := d.GetMysqlDecimal().ToFloat64()\n\t\tisZero, err = RoundFloat(v) == 0, err1\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\tval, err1 := d.GetBinaryLiteral().ToInt(sc)\n\t\tisZero, err = val == 0, err1\n\tdefault:\n\t\treturn 0, errors.Errorf(\"cannot convert %v(type %T) to bool\", d.GetValue(), d.GetValue())\n\t}\n\tvar ret int64\n\tif isZero {\n\t\tret = 0\n\t} else {\n\t\tret = 1\n\t}\n\tif err != nil {\n\t\treturn ret, errors.Trace(err)\n\t}\n\treturn ret, nil\n}\n\n// ConvertDatumToDecimal converts datum to decimal.\nfunc ConvertDatumToDecimal(sc *stmtctx.StatementContext, d Datum) (*MyDecimal, error) {\n\tdec := new(MyDecimal)\n\tvar err error\n\tswitch d.Kind() {\n\tcase KindInt64:\n\t\tdec.FromInt(d.GetInt64())\n\tcase KindUint64:\n\t\tdec.FromUint(d.GetUint64())\n\tcase KindFloat32:\n\t\terr = dec.FromFloat64(float64(d.GetFloat32()))\n\tcase KindFloat64:\n\t\terr = dec.FromFloat64(d.GetFloat64())\n\tcase KindString:\n\t\terr = sc.HandleTruncate(dec.FromString(d.GetBytes()))\n\tcase KindMysqlDecimal:\n\t\t*dec = *d.GetMysqlDecimal()\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\tval, err1 := d.GetBinaryLiteral().ToInt(sc)\n\t\tdec.FromUint(val)\n\t\terr = err1\n\tdefault:\n\t\terr = fmt.Errorf(\"can't convert %v to decimal\", d.GetValue())\n\t}\n\treturn dec, errors.Trace(err)\n}\n\n// ToDecimal converts to a decimal.\nfunc (d *Datum) ToDecimal(sc *stmtctx.StatementContext) (*MyDecimal, error) {\n\tswitch d.Kind() {\n\tcase KindMysqlTime:\n\t\treturn d.GetMysqlTime().ToNumber(), nil\n\tcase KindMysqlDuration:\n\t\treturn d.GetMysqlDuration().ToNumber(), nil\n\tdefault:\n\t\treturn ConvertDatumToDecimal(sc, *d)\n\t}\n}\n\n// ToInt64 converts to a int64.\nfunc (d *Datum) ToInt64(sc *stmtctx.StatementContext) (int64, error) {\n\treturn d.toSignedInteger(sc, mysql.TypeLonglong)\n}\n\nfunc (d *Datum) toSignedInteger(sc *stmtctx.StatementContext, tp byte) (int64, error) {\n\tlowerBound := IntergerSignedLowerBound(tp)\n\tupperBound := IntergerSignedUpperBound(tp)\n\tswitch d.Kind() {\n\tcase KindInt64:\n\t\treturn ConvertIntToInt(d.GetInt64(), lowerBound, upperBound, tp)\n\tcase KindUint64:\n\t\treturn ConvertUintToInt(d.GetUint64(), upperBound, tp)\n\tcase KindFloat32:\n\t\treturn ConvertFloatToInt(float64(d.GetFloat32()), lowerBound, upperBound, tp)\n\tcase KindFloat64:\n\t\treturn ConvertFloatToInt(d.GetFloat64(), lowerBound, upperBound, tp)\n\tcase KindString, KindBytes:\n\t\tiVal, err := StrToInt(sc, d.GetString())\n\t\tiVal, err2 := ConvertIntToInt(iVal, lowerBound, upperBound, tp)\n\t\tif err == nil {\n\t\t\terr = err2\n\t\t}\n\t\treturn iVal, errors.Trace(err)\n\tcase KindMysqlTime:\n\t\t// 2011-11-10 11:11:11.999999 -> 20111110111112\n\t\t// 2011-11-10 11:59:59.999999 -> 20111110120000\n\t\tt, err := d.GetMysqlTime().RoundFrac(sc, DefaultFsp)\n\t\tif err != nil {\n\t\t\treturn 0, errors.Trace(err)\n\t\t}\n\t\tival, err := t.ToNumber().ToInt()\n\t\tival, err2 := ConvertIntToInt(ival, lowerBound, upperBound, tp)\n\t\tif err == nil {\n\t\t\terr = err2\n\t\t}\n\t\treturn ival, errors.Trace(err)\n\tcase KindMysqlDuration:\n\t\t// 11:11:11.999999 -> 111112\n\t\t// 11:59:59.999999 -> 120000\n\t\tdur, err := d.GetMysqlDuration().RoundFrac(DefaultFsp)\n\t\tif err != nil {\n\t\t\treturn 0, errors.Trace(err)\n\t\t}\n\t\tival, err := dur.ToNumber().ToInt()\n\t\tival, err2 := ConvertIntToInt(ival, lowerBound, upperBound, tp)\n\t\tif err == nil {\n\t\t\terr = err2\n\t\t}\n\t\treturn ival, errors.Trace(err)\n\tcase KindMysqlDecimal:\n\t\tvar to MyDecimal\n\t\terr := d.GetMysqlDecimal().Round(&to, 0, ModeHalfEven)\n\t\tival, err1 := to.ToInt()\n\t\tif err == nil {\n\t\t\terr = err1\n\t\t}\n\t\tival, err2 := ConvertIntToInt(ival, lowerBound, upperBound, tp)\n\t\tif err == nil {\n\t\t\terr = err2\n\t\t}\n\t\treturn ival, errors.Trace(err)\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\tval, err := d.GetBinaryLiteral().ToInt(sc)\n\t\treturn int64(val), errors.Trace(err)\n\tdefault:\n\t\treturn 0, errors.Errorf(\"cannot convert %v(type %T) to int64\", d.GetValue(), d.GetValue())\n\t}\n}\n\n// ToFloat64 converts to a float64\nfunc (d *Datum) ToFloat64(sc *stmtctx.StatementContext) (float64, error) {\n\tswitch d.Kind() {\n\tcase KindInt64:\n\t\treturn float64(d.GetInt64()), nil\n\tcase KindUint64:\n\t\treturn float64(d.GetUint64()), nil\n\tcase KindFloat32:\n\t\treturn float64(d.GetFloat32()), nil\n\tcase KindFloat64:\n\t\treturn d.GetFloat64(), nil\n\tcase KindString:\n\t\treturn StrToFloat(sc, d.GetString())\n\tcase KindBytes:\n\t\treturn StrToFloat(sc, string(d.GetBytes()))\n\tcase KindMysqlTime:\n\t\tf, err := d.GetMysqlTime().ToNumber().ToFloat64()\n\t\treturn f, errors.Trace(err)\n\tcase KindMysqlDuration:\n\t\tf, err := d.GetMysqlDuration().ToNumber().ToFloat64()\n\t\treturn f, errors.Trace(err)\n\tcase KindMysqlDecimal:\n\t\tf, err := d.GetMysqlDecimal().ToFloat64()\n\t\treturn f, errors.Trace(err)\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\tval, err := d.GetBinaryLiteral().ToInt(sc)\n\t\treturn float64(val), errors.Trace(err)\n\tdefault:\n\t\treturn 0, errors.Errorf(\"cannot convert %v(type %T) to float64\", d.GetValue(), d.GetValue())\n\t}\n}\n\n// ToString gets the string representation of the datum.\nfunc (d *Datum) ToString() (string, error) {\n\tswitch d.Kind() {\n\tcase KindInt64:\n\t\treturn strconv.FormatInt(d.GetInt64(), 10), nil\n\tcase KindUint64:\n\t\treturn strconv.FormatUint(d.GetUint64(), 10), nil\n\tcase KindFloat32:\n\t\treturn strconv.FormatFloat(float64(d.GetFloat32()), 'f', -1, 32), nil\n\tcase KindFloat64:\n\t\treturn strconv.FormatFloat(d.GetFloat64(), 'f', -1, 64), nil\n\tcase KindString:\n\t\treturn d.GetString(), nil\n\tcase KindBytes:\n\t\treturn d.GetString(), nil\n\tcase KindMysqlTime:\n\t\treturn d.GetMysqlTime().String(), nil\n\tcase KindMysqlDuration:\n\t\treturn d.GetMysqlDuration().String(), nil\n\tcase KindMysqlDecimal:\n\t\treturn d.GetMysqlDecimal().String(), nil\n\tcase KindBinaryLiteral, KindMysqlBit:\n\t\treturn d.GetBinaryLiteral().ToString(), nil\n\tdefault:\n\t\treturn \"\", errors.Errorf(\"cannot convert %v(type %T) to string\", d.GetValue(), d.GetValue())\n\t}\n}\n\n// ToBytes gets the bytes representation of the datum.\nfunc (d *Datum) ToBytes() ([]byte, error) {\n\tswitch d.k {\n\tcase KindString, KindBytes:\n\t\treturn d.GetBytes(), nil\n\tdefault:\n\t\tstr, err := d.ToString()\n\t\tif err != nil {\n\t\t\treturn nil, errors.Trace(err)\n\t\t}\n\t\treturn []byte(str), nil\n\t}\n}\n\nfunc invalidConv(d *Datum, tp byte) (Datum, error) {\n\treturn Datum{}, errors.Errorf(\"cannot convert datum from %s to type %s.\", KindStr(d.Kind()), TypeStr(tp))\n}\n\n// NewDatum creates a new Datum from an interface{}.\nfunc NewDatum(in interface{}) (d Datum) {\n\tswitch x := in.(type) {\n\tcase []interface{}:\n\t\td.SetValue(MakeDatums(x...))\n\tdefault:\n\t\td.SetValue(in)\n\t}\n\treturn d\n}\n\n// NewIntDatum creates a new Datum from an int64 value.\nfunc NewIntDatum(i int64) (d Datum) {\n\td.SetInt64(i)\n\treturn d\n}\n\n// NewUintDatum creates a new Datum from an uint64 value.\nfunc NewUintDatum(i uint64) (d Datum) {\n\td.SetUint64(i)\n\treturn d\n}\n\n// NewBytesDatum creates a new Datum from a byte slice.\nfunc NewBytesDatum(b []byte) (d Datum) {\n\td.SetBytes(b)\n\treturn d\n}\n\n// NewStringDatum creates a new Datum from a string.\nfunc NewStringDatum(s string) (d Datum) {\n\td.SetString(s)\n\treturn d\n}\n\n// NewFloat64Datum creates a new Datum from a float64 value.\nfunc NewFloat64Datum(f float64) (d Datum) {\n\td.SetFloat64(f)\n\treturn d\n}\n\n// NewFloat32Datum creates a new Datum from a float32 value.\nfunc NewFloat32Datum(f float32) (d Datum) {\n\td.SetFloat32(f)\n\treturn d\n}\n\n// NewDurationDatum creates a new Datum from a Duration value.\nfunc NewDurationDatum(dur Duration) (d Datum) {\n\td.SetMysqlDuration(dur)\n\treturn d\n}\n\n// NewTimeDatum creates a new Time from a Time value.\nfunc NewTimeDatum(t Time) (d Datum) {\n\td.SetMysqlTime(t)\n\treturn d\n}\n\n// NewDecimalDatum creates a new Datum form a MyDecimal value.\nfunc NewDecimalDatum(dec *MyDecimal) (d Datum) {\n\td.SetMysqlDecimal(dec)\n\treturn d\n}\n\n// NewBinaryLiteralDatum creates a new BinaryLiteral Datum for a BinaryLiteral value.\nfunc NewBinaryLiteralDatum(b BinaryLiteral) (d Datum) {\n\td.SetBinaryLiteral(b)\n\treturn d\n}\n\n// NewMysqlBitDatum creates a new MysqlBit Datum for a BinaryLiteral value.\nfunc NewMysqlBitDatum(b BinaryLiteral) (d Datum) {\n\td.SetMysqlBit(b)\n\treturn d\n}\n\n// MakeDatums creates datum slice from interfaces.\nfunc MakeDatums(args ...interface{}) []Datum {\n\tdatums := make([]Datum, len(args))\n\tfor i, v := range args {\n\t\tdatums[i] = NewDatum(v)\n\t}\n\treturn datums\n}\n\n// MinNotNullDatum returns a datum represents minimum not null value.\nfunc MinNotNullDatum() Datum {\n\treturn Datum{k: KindMinNotNull}\n}\n\n// MaxValueDatum returns a datum represents max value.\nfunc MaxValueDatum() Datum {\n\treturn Datum{k: KindMaxValue}\n}\n\n// EqualDatums compare if a and b contains the same datum values.\nfunc EqualDatums(sc *stmtctx.StatementContext, a []Datum, b []Datum) (bool, error) {\n\tif len(a) != len(b) {\n\t\treturn false, nil\n\t}\n\tif len(a) == 0 && len(b) == 0 {\n\t\treturn true, nil\n\t}\n\tif len(a) == 0 || len(b) == 0 {\n\t\treturn false, nil\n\t}\n\tfor i, ai := range a {\n\t\tv, err := ai.CompareDatum(sc, &b[i])\n\t\tif err != nil {\n\t\t\treturn false, errors.Trace(err)\n\t\t}\n\t\tif v != 0 {\n\t\t\treturn false, nil\n\t\t}\n\t}\n\treturn true, nil\n}\n\n// DatumsToString converts several datums to formatted string.\nfunc DatumsToString(datums []Datum, handleSpecialValue bool) (string, error) {\n\tstrs := make([]string, 0, len(datums))\n\tfor _, datum := range datums {\n\t\tif handleSpecialValue {\n\t\t\tswitch datum.Kind() {\n\t\t\tcase KindNull:\n\t\t\t\tstrs = append(strs, \"NULL\")\n\t\t\t\tcontinue\n\t\t\tcase KindMinNotNull:\n\t\t\t\tstrs = append(strs, \"-inf\")\n\t\t\t\tcontinue\n\t\t\tcase KindMaxValue:\n\t\t\t\tstrs = append(strs, \"+inf\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tstr, err := datum.ToString()\n\t\tif err != nil {\n\t\t\treturn \"\", errors.Trace(err)\n\t\t}\n\t\tstrs = append(strs, str)\n\t}\n\tsize := len(datums)\n\tif size > 1 {\n\t\tstrs[0] = \"(\" + strs[0]\n\t\tstrs[size-1] = strs[size-1] + \")\"\n\t}\n\treturn strings.Join(strs, \", \"), nil\n}\n\n// DatumsToStrNoErr converts some datums to a formatted string.\n// If an error occurs, it will print a log instead of returning an error.\nfunc DatumsToStrNoErr(datums []Datum) string {\n\tstr, err := DatumsToString(datums, true)\n\tterror.Log(errors.Trace(err))\n\treturn str\n}\n\n// CloneDatum returns a new copy of the datum.\n// TODO: Abandon this function.\nfunc CloneDatum(datum Datum) Datum {\n\treturn *datum.Copy()\n}\n\n// CloneRow deep copies a Datum slice.\nfunc CloneRow(dr []Datum) []Datum {\n\tc := make([]Datum, len(dr))\n\tfor i, d := range dr {\n\t\tc[i] = *d.Copy()\n\t}\n\treturn c\n}\n\n// GetMaxValue returns the max value datum for each type.\nfunc GetMaxValue(ft *FieldType) (max Datum) {\n\tswitch ft.Tp {\n\tcase mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong:\n\t\tif mysql.HasUnsignedFlag(ft.Flag) {\n\t\t\tmax.SetUint64(IntergerUnsignedUpperBound(ft.Tp))\n\t\t} else {\n\t\t\tmax.SetInt64(IntergerSignedUpperBound(ft.Tp))\n\t\t}\n\tcase mysql.TypeFloat:\n\t\tmax.SetFloat32(float32(GetMaxFloat(ft.Flen, ft.Decimal)))\n\tcase mysql.TypeDouble:\n\t\tmax.SetFloat64(GetMaxFloat(ft.Flen, ft.Decimal))\n\tcase mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar, mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob:\n\t\t// codec.Encode KindMaxValue, to avoid import circle\n\t\tbytes := []byte{250}\n\t\tmax.SetBytes(bytes)\n\tcase mysql.TypeNewDecimal:\n\t\tmax.SetMysqlDecimal(NewMaxOrMinDec(false, ft.Flen, ft.Decimal))\n\tcase mysql.TypeDuration:\n\t\tmax.SetMysqlDuration(Duration{Duration: MaxTime})\n\tcase mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:\n\t\tif ft.Tp == mysql.TypeDate || ft.Tp == mysql.TypeDatetime {\n\t\t\tmax.SetMysqlTime(NewTime(MaxDatetime, ft.Tp, 0))\n\t\t} else {\n\t\t\tmax.SetMysqlTime(MaxTimestamp)\n\t\t}\n\t}\n\treturn\n}\n\n// GetMinValue returns the min value datum for each type.\nfunc GetMinValue(ft *FieldType) (min Datum) {\n\tswitch ft.Tp {\n\tcase mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong:\n\t\tif mysql.HasUnsignedFlag(ft.Flag) {\n\t\t\tmin.SetUint64(0)\n\t\t} else {\n\t\t\tmin.SetInt64(IntergerSignedLowerBound(ft.Tp))\n\t\t}\n\tcase mysql.TypeFloat:\n\t\tmin.SetFloat32(float32(-GetMaxFloat(ft.Flen, ft.Decimal)))\n\tcase mysql.TypeDouble:\n\t\tmin.SetFloat64(-GetMaxFloat(ft.Flen, ft.Decimal))\n\tcase mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar, mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob:\n\t\t// codec.Encode KindMinNotNull, to avoid import circle\n\t\tbytes := []byte{1}\n\t\tmin.SetBytes(bytes)\n\tcase mysql.TypeNewDecimal:\n\t\tmin.SetMysqlDecimal(NewMaxOrMinDec(true, ft.Flen, ft.Decimal))\n\tcase mysql.TypeDuration:\n\t\tmin.SetMysqlDuration(Duration{Duration: MinTime})\n\tcase mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:\n\t\tif ft.Tp == mysql.TypeDate || ft.Tp == mysql.TypeDatetime {\n\t\t\tmin.SetMysqlTime(NewTime(MinDatetime, ft.Tp, 0))\n\t\t} else {\n\t\t\tmin.SetMysqlTime(MinTimestamp)\n\t\t}\n\t}\n\treturn\n}\n\n// RoundingType is used to indicate the rounding type for reversing evaluation.\ntype RoundingType uint8\n\nconst (\n\t// Ceiling means rounding up.\n\tCeiling RoundingType = iota\n\t// Floor means rounding down.\n\tFloor\n)\n\nfunc getDatumBound(retType *FieldType, rType RoundingType) Datum {\n\tif rType == Ceiling {\n\t\treturn GetMaxValue(retType)\n\t}\n\treturn GetMinValue(retType)\n}\n\n// ChangeReverseResultByUpperLowerBound is for expression's reverse evaluation.\n// Here is an example for what's effort for the function: CastRealAsInt(t.a),\n//\n//\t\t\tif the type of column `t.a` is mysql.TypeDouble, and there is a row that t.a == MaxFloat64\n//\t\t\tthen the cast function will arrive a result MaxInt64. But when we do the reverse evaluation,\n//\t     if the result is MaxInt64, and the rounding type is ceiling. Then we should get the MaxFloat64\n//\t     instead of float64(MaxInt64).\n//\n// Another example: cast(1.1 as signed) = 1,\n//\n//\twhen we get the answer 1, we can only reversely evaluate 1.0 as the column value. So in this\n//\tcase, we should judge whether the rounding type are ceiling. If it is, then we should plus one for\n//\t1.0 and get the reverse result 2.0.\nfunc ChangeReverseResultByUpperLowerBound(\n\tsc *stmtctx.StatementContext,\n\tretType *FieldType,\n\tres Datum,\n\trType RoundingType) (Datum, error) {\n\td, err := res.ConvertTo(sc, retType)\n\tif terror.ErrorEqual(err, ErrOverflow) {\n\t\treturn d, nil\n\t}\n\tif err != nil {\n\t\treturn d, err\n\t}\n\tresRetType := FieldType{}\n\tswitch res.Kind() {\n\tcase KindInt64:\n\t\tresRetType.Tp = mysql.TypeLonglong\n\tcase KindUint64:\n\t\tresRetType.Tp = mysql.TypeLonglong\n\t\tresRetType.Flag |= mysql.UnsignedFlag\n\tcase KindFloat32:\n\t\tresRetType.Tp = mysql.TypeFloat\n\tcase KindFloat64:\n\t\tresRetType.Tp = mysql.TypeDouble\n\tcase KindMysqlDecimal:\n\t\tresRetType.Tp = mysql.TypeNewDecimal\n\t\tresRetType.Flen = int(res.GetMysqlDecimal().GetDigitsFrac() + res.GetMysqlDecimal().GetDigitsInt())\n\t\tresRetType.Decimal = int(res.GetMysqlDecimal().GetDigitsInt())\n\t}\n\tbound := getDatumBound(&resRetType, rType)\n\tcmp, err := d.CompareDatum(sc, &bound)\n\tif err != nil {\n\t\treturn d, err\n\t}\n\tif cmp == 0 {\n\t\td = getDatumBound(retType, rType)\n\t} else if rType == Ceiling {\n\t\tswitch retType.Tp {\n\t\tcase mysql.TypeShort:\n\t\t\tif mysql.HasUnsignedFlag(retType.Flag) {\n\t\t\t\tif d.GetUint64() != math.MaxUint16 {\n\t\t\t\t\td.SetUint64(d.GetUint64() + 1)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif d.GetInt64() != math.MaxInt16 {\n\t\t\t\t\td.SetInt64(d.GetInt64() + 1)\n\t\t\t\t}\n\t\t\t}\n\t\tcase mysql.TypeLong:\n\t\t\tif mysql.HasUnsignedFlag(retType.Flag) {\n\t\t\t\tif d.GetUint64() != math.MaxUint32 {\n\t\t\t\t\td.SetUint64(d.GetUint64() + 1)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif d.GetInt64() != math.MaxInt32 {\n\t\t\t\t\td.SetInt64(d.GetInt64() + 1)\n\t\t\t\t}\n\t\t\t}\n\t\tcase mysql.TypeLonglong:\n\t\t\tif mysql.HasUnsignedFlag(retType.Flag) {\n\t\t\t\tif d.GetUint64() != math.MaxUint64 {\n\t\t\t\t\td.SetUint64(d.GetUint64() + 1)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif d.GetInt64() != math.MaxInt64 {\n\t\t\t\t\td.SetInt64(d.GetInt64() + 1)\n\t\t\t\t}\n\t\t\t}\n\t\tcase mysql.TypeFloat:\n\t\t\tif d.GetFloat32() != math.MaxFloat32 {\n\t\t\t\td.SetFloat32(d.GetFloat32() + 1.0)\n\t\t\t}\n\t\tcase mysql.TypeDouble:\n\t\t\tif d.GetFloat64() != math.MaxFloat64 {\n\t\t\t\td.SetFloat64(d.GetFloat64() + 1.0)\n\t\t\t}\n\t\tcase mysql.TypeNewDecimal:\n\t\t\tif d.GetMysqlDecimal().Compare(NewMaxOrMinDec(false, retType.Flen, retType.Decimal)) != 0 {\n\t\t\t\tvar decimalOne, newD MyDecimal\n\t\t\t\tone := decimalOne.FromInt(1)\n\t\t\t\terr = DecimalAdd(d.GetMysqlDecimal(), one, &newD)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn d, err\n\t\t\t\t}\n\t\t\t\td = NewDecimalDatum(&newD)\n\t\t\t}\n\t\t}\n\t}\n\treturn d, nil\n}\n\nconst (\n\tsizeOfEmptyDatum = int(unsafe.Sizeof(Datum{}))\n\tsizeOfMysqlTime  = int(unsafe.Sizeof(ZeroTime))\n\tsizeOfMyDecimal  = MyDecimalStructSize\n)\n\n// EstimatedMemUsage returns the estimated bytes consumed of a one-dimensional\n// or two-dimensional datum array.\nfunc EstimatedMemUsage(array []Datum, numOfRows int) int64 {\n\tif numOfRows == 0 {\n\t\treturn 0\n\t}\n\tvar bytesConsumed int\n\tfor _, d := range array {\n\t\tswitch d.Kind() {\n\t\tcase KindMysqlDecimal:\n\t\t\tbytesConsumed += sizeOfMyDecimal\n\t\tcase KindMysqlTime:\n\t\t\tbytesConsumed += sizeOfMysqlTime\n\t\tdefault:\n\t\t\tbytesConsumed += len(d.b)\n\t\t}\n\t}\n\tbytesConsumed += len(array) * sizeOfEmptyDatum\n\treturn int64(bytesConsumed * numOfRows)\n}\n"
  },
  {
    "path": "pkg/types/errors.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\tparser_types \"github.com/secretflow/scql/pkg/parser/types\"\n)\n\n// const strings for ErrWrongValue\nconst (\n\tDateTimeStr = \"datetime\"\n\tTimeStr     = \"time\"\n)\n\nvar (\n\t// ErrInvalidDefault is returned when meet a invalid default value.\n\tErrInvalidDefault = parser_types.ErrInvalidDefault\n\t// ErrDataTooLong is returned when converts a string value that is longer than field type length.\n\tErrDataTooLong = terror.ClassTypes.New(mysql.ErrDataTooLong, mysql.MySQLErrName[mysql.ErrDataTooLong])\n\t// ErrIllegalValueForType is returned when value of type is illegal.\n\tErrIllegalValueForType = terror.ClassTypes.New(mysql.ErrIllegalValueForType, mysql.MySQLErrName[mysql.ErrIllegalValueForType])\n\t// ErrTruncated is returned when data has been truncated during conversion.\n\tErrTruncated = terror.ClassTypes.New(mysql.WarnDataTruncated, mysql.MySQLErrName[mysql.WarnDataTruncated])\n\t// ErrOverflow is returned when data is out of range for a field type.\n\tErrOverflow = terror.ClassTypes.New(mysql.ErrDataOutOfRange, mysql.MySQLErrName[mysql.ErrDataOutOfRange])\n\t// ErrDivByZero is return when do division by 0.\n\tErrDivByZero = terror.ClassTypes.New(mysql.ErrDivisionByZero, mysql.MySQLErrName[mysql.ErrDivisionByZero])\n\t// ErrTooBigDisplayWidth is return when display width out of range for column.\n\tErrTooBigDisplayWidth = terror.ClassTypes.New(mysql.ErrTooBigDisplaywidth, mysql.MySQLErrName[mysql.ErrTooBigDisplaywidth])\n\t// ErrTooBigFieldLength is return when column length too big for column.\n\tErrTooBigFieldLength = terror.ClassTypes.New(mysql.ErrTooBigFieldlength, mysql.MySQLErrName[mysql.ErrTooBigFieldlength])\n\t// ErrTooBigSet is returned when too many strings for column.\n\tErrTooBigSet = terror.ClassTypes.New(mysql.ErrTooBigSet, mysql.MySQLErrName[mysql.ErrTooBigSet])\n\t// ErrTooBigScale is returned when type DECIMAL/NUMERIC scale is bigger than mysql.MaxDecimalScale.\n\tErrTooBigScale = terror.ClassTypes.New(mysql.ErrTooBigScale, mysql.MySQLErrName[mysql.ErrTooBigScale])\n\t// ErrTooBigPrecision is returned when type DECIMAL/NUMERIC precision is bigger than mysql.MaxDecimalWidth\n\tErrTooBigPrecision = terror.ClassTypes.New(mysql.ErrTooBigPrecision, mysql.MySQLErrName[mysql.ErrTooBigPrecision])\n\t// ErrBadNumber is return when parsing an invalid binary decimal number.\n\tErrBadNumber = terror.ClassTypes.New(mysql.ErrBadNumber, mysql.MySQLErrName[mysql.ErrBadNumber])\n\t// ErrInvalidFieldSize is returned when the precision of a column is out of range.\n\tErrInvalidFieldSize = terror.ClassTypes.New(mysql.ErrInvalidFieldSize, mysql.MySQLErrName[mysql.ErrInvalidFieldSize])\n\t// ErrMBiggerThanD is returned when precision less than the scale.\n\tErrMBiggerThanD = terror.ClassTypes.New(mysql.ErrMBiggerThanD, mysql.MySQLErrName[mysql.ErrMBiggerThanD])\n\t// ErrWarnDataOutOfRange is returned when the value in a numeric column that is outside the permissible range of the column data type.\n\t// See https://dev.mysql.com/doc/refman/5.5/en/out-of-range-and-overflow.html for details\n\tErrWarnDataOutOfRange = terror.ClassTypes.New(mysql.ErrWarnDataOutOfRange, mysql.MySQLErrName[mysql.ErrWarnDataOutOfRange])\n\t// ErrDuplicatedValueInType is returned when enum column has duplicated value.\n\tErrDuplicatedValueInType = terror.ClassTypes.New(mysql.ErrDuplicatedValueInType, mysql.MySQLErrName[mysql.ErrDuplicatedValueInType])\n\t// ErrDatetimeFunctionOverflow is returned when the calculation in datetime function cause overflow.\n\tErrDatetimeFunctionOverflow = terror.ClassTypes.New(mysql.ErrDatetimeFunctionOverflow, mysql.MySQLErrName[mysql.ErrDatetimeFunctionOverflow])\n\t// ErrCastAsSignedOverflow is returned when positive out-of-range integer, and convert to it's negative complement.\n\tErrCastAsSignedOverflow = terror.ClassTypes.New(mysql.ErrCastAsSignedOverflow, mysql.MySQLErrName[mysql.ErrCastAsSignedOverflow])\n\t// ErrCastNegIntAsUnsigned is returned when a negative integer be casted to an unsigned int.\n\tErrCastNegIntAsUnsigned = terror.ClassTypes.New(mysql.ErrCastNegIntAsUnsigned, mysql.MySQLErrName[mysql.ErrCastNegIntAsUnsigned])\n\t// ErrInvalidYearFormat is returned when the input is not a valid year format.\n\tErrInvalidYearFormat = terror.ClassTypes.New(mysql.ErrInvalidYearFormat, mysql.MySQLErrName[mysql.ErrInvalidYearFormat])\n\t// ErrInvalidYear is returned when the input value is not a valid year.\n\tErrInvalidYear = terror.ClassTypes.New(mysql.ErrInvalidYear, mysql.MySQLErrName[mysql.ErrInvalidYear])\n\t// ErrTruncatedWrongVal is returned when data has been truncated during conversion.\n\tErrTruncatedWrongVal = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, mysql.MySQLErrName[mysql.ErrTruncatedWrongValue])\n\t// ErrInvalidWeekModeFormat is returned when the week mode is wrong.\n\tErrInvalidWeekModeFormat = terror.ClassTypes.New(mysql.ErrInvalidWeekModeFormat, mysql.MySQLErrName[mysql.ErrInvalidWeekModeFormat])\n\t// ErrWrongValue is returned when the input value is in wrong format.\n\tErrWrongValue = terror.ClassTypes.New(mysql.ErrWrongValue, mysql.MySQLErrName[mysql.ErrWrongValue])\n\t// ErrWrongValueForType is returned when the input value is in wrong format for function.\n\tErrWrongValueForType = terror.ClassTypes.New(mysql.ErrWrongValueForType, mysql.MySQLErrName[mysql.ErrWrongValueForType])\n)\n"
  },
  {
    "path": "pkg/types/etc.go",
    "content": "// Copyright 2014 The ql Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSES/QL-LICENSE file.\n\n// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/opcode\"\n\tast \"github.com/secretflow/scql/pkg/parser/types\"\n)\n\n// IsTypeBlob returns a boolean indicating whether the tp is a blob type.\nvar IsTypeBlob = ast.IsTypeBlob\n\n// IsTypeChar returns a boolean indicating\n// whether the tp is the char type like a string type or a varchar type.\nvar IsTypeChar = ast.IsTypeChar\n\n// IsTypeVarchar returns a boolean indicating\n// whether the tp is the varchar type like a varstring type or a varchar type.\nfunc IsTypeVarchar(tp byte) bool {\n\treturn tp == mysql.TypeVarString || tp == mysql.TypeVarchar\n}\n\n// IsTypeUnspecified returns a boolean indicating whether the tp is the Unspecified type.\nfunc IsTypeUnspecified(tp byte) bool {\n\treturn tp == mysql.TypeUnspecified\n}\n\n// IsTypePrefixable returns a boolean indicating\n// whether an index on a column with the tp can be defined with a prefix.\nfunc IsTypePrefixable(tp byte) bool {\n\treturn IsTypeBlob(tp) || IsTypeChar(tp)\n}\n\n// IsTypeFractionable returns a boolean indicating\n// whether the tp can has time fraction.\nfunc IsTypeFractionable(tp byte) bool {\n\treturn tp == mysql.TypeDatetime || tp == mysql.TypeDuration || tp == mysql.TypeTimestamp\n}\n\n// IsTypeTime returns a boolean indicating\n// whether the tp is time type like datetime, date or timestamp.\nfunc IsTypeTime(tp byte) bool {\n\treturn tp == mysql.TypeDatetime || tp == mysql.TypeDate || tp == mysql.TypeTimestamp\n}\n\n// IsTypeNumeric returns a boolean indicating whether the tp is numeric type.\nfunc IsTypeNumeric(tp byte) bool {\n\tswitch tp {\n\tcase mysql.TypeBit, mysql.TypeTiny, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeNewDecimal,\n\t\tmysql.TypeDecimal, mysql.TypeFloat, mysql.TypeDouble, mysql.TypeShort:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsTemporalWithDate returns a boolean indicating\n// whether the tp is time type with date.\nfunc IsTemporalWithDate(tp byte) bool {\n\treturn IsTypeTime(tp)\n}\n\n// IsBinaryStr returns a boolean indicating\n// whether the field type is a binary string type.\nfunc IsBinaryStr(ft *FieldType) bool {\n\treturn ft.Collate == charset.CollationBin && IsString(ft.Tp)\n}\n\n// IsNonBinaryStr returns a boolean indicating\n// whether the field type is a non-binary string type.\nfunc IsNonBinaryStr(ft *FieldType) bool {\n\tif ft.Collate != charset.CollationBin && IsString(ft.Tp) {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsString returns a boolean indicating\n// whether the field type is a string type.\nfunc IsString(tp byte) bool {\n\treturn IsTypeChar(tp) || IsTypeBlob(tp) || IsTypeVarchar(tp) || IsTypeUnspecified(tp)\n}\n\nvar kind2Str = map[byte]string{\n\tKindNull:          \"null\",\n\tKindInt64:         \"bigint\",\n\tKindUint64:        \"unsigned bigint\",\n\tKindFloat32:       \"float\",\n\tKindFloat64:       \"double\",\n\tKindString:        \"char\",\n\tKindBytes:         \"bytes\",\n\tKindBinaryLiteral: \"bit/hex literal\",\n\tKindMysqlDecimal:  \"decimal\",\n\tKindMysqlDuration: \"time\",\n\tKindMysqlBit:      \"bit\",\n\tKindMysqlTime:     \"datetime\",\n\tKindInterface:     \"interface\",\n\tKindMinNotNull:    \"min_not_null\",\n\tKindMaxValue:      \"max_value\",\n\tKindRaw:           \"raw\",\n}\n\n// TypeStr converts tp to a string.\nvar TypeStr = ast.TypeStr\n\n// TypeToStr converts a field to a string.\n// It is used for converting Text to Blob,\n// or converting Char to Binary.\n// Args:\n//\n//\ttp: type enum\n//\tcs: charset\nvar TypeToStr = ast.TypeToStr\n\n// InvOp2 returns an invalid operation error.\nfunc InvOp2(x, y interface{}, o opcode.Op) (interface{}, error) {\n\treturn nil, errors.Errorf(\"Invalid operation: %v %v %v (mismatched types %T and %T)\", x, o, y, x, y)\n}\n\n// overflow returns an overflowed error.\nfunc overflow(v interface{}, tp byte) error {\n\treturn ErrOverflow.GenWithStack(\"constant %v overflows %s\", v, TypeStr(tp))\n}\n\n// KindStr converts kind to a string.\nfunc KindStr(kind byte) (r string) {\n\treturn kind2Str[kind]\n}\n\n// IsTypeTemporal checks if a type is a temporal type.\nfunc IsTypeTemporal(tp byte) bool {\n\tswitch tp {\n\tcase mysql.TypeDuration, mysql.TypeDatetime, mysql.TypeTimestamp,\n\t\tmysql.TypeDate, mysql.TypeNewDate:\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "pkg/types/eval_type.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport ast \"github.com/secretflow/scql/pkg/parser/types\"\n\n// EvalType indicates the specified types that arguments and result of a built-in function should be.\ntype EvalType = ast.EvalType\n\nconst (\n\t// ETInt represents type INT in evaluation.\n\tETInt = ast.ETInt\n\t// ETReal represents type REAL in evaluation.\n\tETReal = ast.ETReal\n\t// ETDecimal represents type DECIMAL in evaluation.\n\tETDecimal = ast.ETDecimal\n\t// ETString represents type STRING in evaluation.\n\tETString = ast.ETString\n\t// ETDatetime represents type DATETIME in evaluation.\n\tETDatetime = ast.ETDatetime\n\t// ETTimestamp represents type TIMESTAMP in evaluation.\n\tETTimestamp = ast.ETTimestamp\n\t// ETDuration represents type DURATION in evaluation.\n\tETDuration = ast.ETDuration\n\t// ETJson represents type JSON in evaluation.\n\tETJson = ast.ETJson\n)\n"
  },
  {
    "path": "pkg/types/field_name.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"strings\"\n\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n)\n\n// FieldName records the names used for mysql protocol.\ntype FieldName struct {\n\tOrigTblName model.CIStr\n\tOrigColName model.CIStr\n\tDBName      model.CIStr\n\tTblName     model.CIStr\n\tColName     model.CIStr\n\n\tHidden bool\n}\n\nconst emptyName = \"EMPTY_NAME\"\n\n// String implements Stringer interface.\nfunc (name *FieldName) String() string {\n\tbuilder := strings.Builder{}\n\tif name.Hidden {\n\t\treturn emptyName\n\t}\n\tif name.DBName.String() != \"\" {\n\t\tbuilder.WriteString(name.DBName.String() + \".\")\n\t}\n\tif name.TblName.String() != \"\" {\n\t\tbuilder.WriteString(name.TblName.String() + \".\")\n\t}\n\tbuilder.WriteString(name.ColName.String())\n\treturn builder.String()\n}\n\n// NameSlice is the slice of the *fieldName\ntype NameSlice []*FieldName\n\n// Shallow is a shallow copy, only making a new slice.\nfunc (s NameSlice) Shallow() NameSlice {\n\tret := make(NameSlice, len(s))\n\tcopy(ret, s)\n\treturn ret\n}\n\n// EmptyName is to occupy the position in the name slice. If it's set, that column's name is hidden.\nvar EmptyName = &FieldName{Hidden: true}\n"
  },
  {
    "path": "pkg/types/field_type.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/secretflow/scql/pkg/parser/charset\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\tast \"github.com/secretflow/scql/pkg/parser/types\"\n\tutilMath \"github.com/secretflow/scql/pkg/util/math\"\n)\n\n// UnspecifiedLength is unspecified length.\nconst (\n\tUnspecifiedLength = -1\n)\n\n// FieldType records field type information.\ntype FieldType = ast.FieldType\n\n// NewFieldType returns a FieldType,\n// with a type and other information about field type.\nfunc NewFieldType(tp byte) *FieldType {\n\treturn &FieldType{\n\t\tTp:      tp,\n\t\tFlen:    UnspecifiedLength,\n\t\tDecimal: UnspecifiedLength,\n\t}\n}\n\n// AggFieldType aggregates field types for a multi-argument function like `IF`, `IFNULL`, `COALESCE`\n// whose return type is determined by the arguments' FieldTypes.\n// Aggregation is performed by MergeFieldType function.\nfunc AggFieldType(tps []*FieldType) *FieldType {\n\tvar currType FieldType\n\tfor i, t := range tps {\n\t\tif i == 0 && currType.Tp == mysql.TypeUnspecified {\n\t\t\tcurrType = *t\n\t\t\tcontinue\n\t\t}\n\t\tmtp := MergeFieldType(currType.Tp, t.Tp)\n\t\tcurrType.Tp = mtp\n\t}\n\n\treturn &currType\n}\n\n// AggregateEvalType aggregates arguments' EvalType of a multi-argument function.\nfunc AggregateEvalType(fts []*FieldType, flag *uint) EvalType {\n\tvar (\n\t\taggregatedEvalType = ETString\n\t\tunsigned           bool\n\t\tgotFirst           bool\n\t\tgotBinString       bool\n\t)\n\tlft := fts[0]\n\tfor _, ft := range fts {\n\t\tif ft.Tp == mysql.TypeNull {\n\t\t\tcontinue\n\t\t}\n\t\tet := ft.EvalType()\n\t\trft := ft\n\t\tif (IsTypeBlob(ft.Tp) || IsTypeVarchar(ft.Tp) || IsTypeChar(ft.Tp)) && mysql.HasBinaryFlag(ft.Flag) {\n\t\t\tgotBinString = true\n\t\t}\n\t\tif !gotFirst {\n\t\t\tgotFirst = true\n\t\t\taggregatedEvalType = et\n\t\t\tunsigned = mysql.HasUnsignedFlag(ft.Flag)\n\t\t} else {\n\t\t\taggregatedEvalType = mergeEvalType(aggregatedEvalType, et, lft, rft, unsigned, mysql.HasUnsignedFlag(ft.Flag))\n\t\t\tunsigned = unsigned && mysql.HasUnsignedFlag(ft.Flag)\n\t\t}\n\t\tlft = rft\n\t}\n\tsetTypeFlag(flag, mysql.UnsignedFlag, unsigned)\n\tsetTypeFlag(flag, mysql.BinaryFlag, !aggregatedEvalType.IsStringKind() || gotBinString)\n\treturn aggregatedEvalType\n}\n\nfunc mergeEvalType(lhs, rhs EvalType, lft, rft *FieldType, isLHSUnsigned, isRHSUnsigned bool) EvalType {\n\tif lft.Tp == mysql.TypeUnspecified || rft.Tp == mysql.TypeUnspecified {\n\t\tif lft.Tp == rft.Tp {\n\t\t\treturn ETString\n\t\t}\n\t\tif lft.Tp == mysql.TypeUnspecified {\n\t\t\tlhs = rhs\n\t\t} else {\n\t\t\trhs = lhs\n\t\t}\n\t}\n\tif lhs.IsStringKind() || rhs.IsStringKind() {\n\t\treturn ETString\n\t} else if lhs == ETReal || rhs == ETReal {\n\t\treturn ETReal\n\t} else if lhs == ETDecimal || rhs == ETDecimal || isLHSUnsigned != isRHSUnsigned {\n\t\treturn ETDecimal\n\t}\n\treturn ETInt\n}\n\nfunc setTypeFlag(flag *uint, flagItem uint, on bool) {\n\tif on {\n\t\t*flag |= flagItem\n\t} else {\n\t\t*flag &= ^flagItem\n\t}\n}\n\n// DefaultParamTypeForValue returns the default FieldType for the parameterized value.\nfunc DefaultParamTypeForValue(value interface{}, tp *FieldType) {\n\tswitch value.(type) {\n\tcase nil:\n\t\ttp.Tp = mysql.TypeVarString\n\t\ttp.Flen = UnspecifiedLength\n\t\ttp.Decimal = UnspecifiedLength\n\tdefault:\n\t\tDefaultTypeForValue(value, tp)\n\t\tif hasVariantFieldLength(tp) {\n\t\t\ttp.Flen = UnspecifiedLength\n\t\t}\n\t\tif tp.Tp == mysql.TypeUnspecified {\n\t\t\ttp.Tp = mysql.TypeVarString\n\t\t}\n\t}\n}\n\nfunc hasVariantFieldLength(tp *FieldType) bool {\n\tswitch tp.Tp {\n\tcase mysql.TypeLonglong, mysql.TypeVarString, mysql.TypeDouble, mysql.TypeBlob,\n\t\tmysql.TypeBit, mysql.TypeDuration, mysql.TypeNewDecimal, mysql.TypeEnum, mysql.TypeSet:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// DefaultTypeForValue returns the default FieldType for the value.\nfunc DefaultTypeForValue(value interface{}, tp *FieldType) {\n\tswitch x := value.(type) {\n\tcase nil:\n\t\ttp.Tp = mysql.TypeNull\n\t\ttp.Flen = 0\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\tcase bool:\n\t\ttp.Tp = mysql.TypeLonglong\n\t\ttp.Flen = 1\n\t\ttp.Decimal = 0\n\t\ttp.Flag |= mysql.IsBooleanFlag\n\t\tSetBinChsClnFlag(tp)\n\tcase int:\n\t\ttp.Tp = mysql.TypeLonglong\n\t\ttp.Flen = utilMath.StrLenOfInt64Fast(int64(x))\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\tcase int64:\n\t\ttp.Tp = mysql.TypeLonglong\n\t\ttp.Flen = utilMath.StrLenOfInt64Fast(x)\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\tcase uint64:\n\t\ttp.Tp = mysql.TypeLonglong\n\t\ttp.Flag |= mysql.UnsignedFlag\n\t\ttp.Flen = utilMath.StrLenOfUint64Fast(x)\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\tcase string:\n\t\ttp.Tp = mysql.TypeVarString\n\t\t// TODO: tp.Flen should be len(x) * 3 (max bytes length of CharsetUTF8)\n\t\ttp.Flen = len(x)\n\t\ttp.Decimal = UnspecifiedLength\n\t\ttp.Charset, tp.Collate = charset.GetDefaultCharsetAndCollate()\n\tcase float32:\n\t\ttp.Tp = mysql.TypeFloat\n\t\ts := strconv.FormatFloat(float64(x), 'f', -1, 32)\n\t\ttp.Flen = len(s)\n\t\ttp.Decimal = UnspecifiedLength\n\t\tSetBinChsClnFlag(tp)\n\tcase float64:\n\t\ttp.Tp = mysql.TypeDouble\n\t\ts := strconv.FormatFloat(x, 'f', -1, 64)\n\t\ttp.Flen = len(s)\n\t\ttp.Decimal = UnspecifiedLength\n\t\tSetBinChsClnFlag(tp)\n\tcase []byte:\n\t\ttp.Tp = mysql.TypeBlob\n\t\ttp.Flen = len(x)\n\t\ttp.Decimal = UnspecifiedLength\n\t\tSetBinChsClnFlag(tp)\n\tcase BitLiteral:\n\t\ttp.Tp = mysql.TypeVarString\n\t\ttp.Flen = len(x)\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\tcase HexLiteral:\n\t\ttp.Tp = mysql.TypeVarString\n\t\ttp.Flen = len(x) * 3\n\t\ttp.Decimal = 0\n\t\ttp.Flag |= mysql.UnsignedFlag\n\t\tSetBinChsClnFlag(tp)\n\tcase BinaryLiteral:\n\t\ttp.Tp = mysql.TypeBit\n\t\ttp.Flen = len(x) * 8\n\t\ttp.Decimal = 0\n\t\tSetBinChsClnFlag(tp)\n\t\ttp.Flag &= ^mysql.BinaryFlag\n\t\ttp.Flag |= mysql.UnsignedFlag\n\tcase Time:\n\t\ttp.Tp = x.Type()\n\t\tswitch x.Type() {\n\t\tcase mysql.TypeDate:\n\t\t\ttp.Flen = mysql.MaxDateWidth\n\t\t\ttp.Decimal = UnspecifiedLength\n\t\tcase mysql.TypeDatetime, mysql.TypeTimestamp:\n\t\t\ttp.Flen = mysql.MaxDatetimeWidthNoFsp\n\t\t\tif x.Fsp() > DefaultFsp { // consider point('.') and the fractional part.\n\t\t\t\ttp.Flen += int(x.Fsp()) + 1\n\t\t\t}\n\t\t\ttp.Decimal = int(x.Fsp())\n\t\t}\n\t\tSetBinChsClnFlag(tp)\n\tcase Duration:\n\t\ttp.Tp = mysql.TypeDuration\n\t\ttp.Flen = len(x.String())\n\t\tif x.Fsp > DefaultFsp { // consider point('.') and the fractional part.\n\t\t\ttp.Flen = int(x.Fsp) + 1\n\t\t}\n\t\ttp.Decimal = int(x.Fsp)\n\t\tSetBinChsClnFlag(tp)\n\tcase *MyDecimal:\n\t\ttp.Tp = mysql.TypeNewDecimal\n\t\ttp.Flen = len(x.ToString())\n\t\ttp.Decimal = int(x.digitsFrac)\n\t\tSetBinChsClnFlag(tp)\n\tdefault:\n\t\ttp.Tp = mysql.TypeUnspecified\n\t\ttp.Flen = UnspecifiedLength\n\t\ttp.Decimal = UnspecifiedLength\n\t}\n}\n\n// DefaultCharsetForType returns the default charset/collation for mysql type.\nfunc DefaultCharsetForType(tp byte) (string, string) {\n\tswitch tp {\n\tcase mysql.TypeVarString, mysql.TypeString, mysql.TypeVarchar:\n\t\t// Default charset for string types is utf8.\n\t\treturn mysql.DefaultCharset, mysql.DefaultCollationName\n\t}\n\treturn charset.CharsetBin, charset.CollationBin\n}\n\n// MergeFieldType merges two MySQL type to a new type.\n// This is used in hybrid field type expression.\n// For example \"select case c when 1 then 2 when 2 then 'tidb' from t;\"\n// The result field type of the case expression is the merged type of the two when clause.\n// See https://github.com/mysql/mysql-server/blob/5.7/sql/field.cc#L1042\nfunc MergeFieldType(a byte, b byte) byte {\n\tif a == b {\n\t\treturn a\n\t}\n\tia := getFieldTypeIndex(a)\n\tib := getFieldTypeIndex(b)\n\treturn fieldTypeMergeRules[ia][ib]\n}\n\nfunc getFieldTypeIndex(tp byte) int {\n\titp := int(tp)\n\tif itp < fieldTypeTearFrom {\n\t\treturn itp\n\t}\n\treturn fieldTypeTearFrom + itp - fieldTypeTearTo - 1\n}\n\nconst (\n\tfieldTypeTearFrom = int(mysql.TypeBit) + 1\n\tfieldTypeTearTo   = int(mysql.TypeJSON) - 1\n\tfieldTypeNum      = fieldTypeTearFrom + (255 - fieldTypeTearTo)\n)\n\nvar fieldTypeMergeRules = [fieldTypeNum][fieldTypeNum]byte{\n\t/* mysql.TypeDecimal -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeNewDecimal, mysql.TypeNewDecimal,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeNewDecimal, mysql.TypeNewDecimal,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeDouble, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeNewDecimal, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeDecimal, mysql.TypeDecimal,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeNewDecimal, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeTiny -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeNewDecimal, mysql.TypeTiny,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeShort, mysql.TypeLong,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeFloat, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeTiny, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeLonglong, mysql.TypeInt24,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeTiny,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeNewDecimal, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeShort -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeNewDecimal, mysql.TypeShort,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeShort, mysql.TypeLong,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeFloat, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeShort, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeLonglong, mysql.TypeInt24,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeShort,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeNewDecimal, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeLong -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeNewDecimal, mysql.TypeLong,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeLong, mysql.TypeLong,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeDouble, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeLong, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeLonglong, mysql.TypeLong,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeLong,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeNewDecimal, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeFloat -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeDouble, mysql.TypeFloat,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeFloat, mysql.TypeDouble,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeFloat, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeFloat, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeFloat, mysql.TypeFloat,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeFloat,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeDouble, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeDouble -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeDouble, mysql.TypeDouble,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeDouble, mysql.TypeDouble,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeDouble, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeDouble, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeDouble, mysql.TypeDouble,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeDouble,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeDouble, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeNull -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeNewDecimal, mysql.TypeTiny,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeShort, mysql.TypeLong,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeFloat, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeNull, mysql.TypeTimestamp,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeLonglong, mysql.TypeLonglong,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeDate, mysql.TypeDuration,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeDatetime, mysql.TypeYear,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeNewDate, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeBit,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeJSON,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeNewDecimal, mysql.TypeEnum,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeSet, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeGeometry,\n\t},\n\t/* mysql.TypeTimestamp -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeTimestamp, mysql.TypeTimestamp,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeDatetime, mysql.TypeDatetime,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeDatetime, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeNewDate, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeLonglong -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeNewDecimal, mysql.TypeLonglong,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeLonglong, mysql.TypeLonglong,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeDouble, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeLonglong, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeLonglong, mysql.TypeLong,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeLonglong,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeNewDate, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeNewDecimal, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeInt24 -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeNewDecimal, mysql.TypeInt24,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeInt24, mysql.TypeLong,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeFloat, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeInt24, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeLonglong, mysql.TypeInt24,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeInt24,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeNewDate, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal    mysql.TypeEnum\n\t\tmysql.TypeNewDecimal, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeDate -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeDate, mysql.TypeDatetime,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeDate, mysql.TypeDatetime,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeDatetime, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeNewDate, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeTime -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeDuration, mysql.TypeDatetime,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeDatetime, mysql.TypeDuration,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeDatetime, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeNewDate, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeDatetime -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeDatetime, mysql.TypeDatetime,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeDatetime, mysql.TypeDatetime,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeDatetime, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeNewDate, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeYear -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeDecimal, mysql.TypeTiny,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeShort, mysql.TypeLong,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeFloat, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeYear, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeLonglong, mysql.TypeInt24,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeYear,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeNewDecimal, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeNewDate -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeNewDate, mysql.TypeDatetime,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeNewDate, mysql.TypeDatetime,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeDatetime, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeNewDate, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeVarchar -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeBit -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeBit, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeBit,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeJSON -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNewFloat     mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeJSON, mysql.TypeVarchar,\n\t\t//mysql.TypeLongLONG     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         MYSQL_TYPE_TIME\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     MYSQL_TYPE_YEAR\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeJSON,\n\t\t//mysql.TypeNewDecimal   MYSQL_TYPE_ENUM\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeLongBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeLongBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       MYSQL_TYPE_GEOMETRY\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeNewDecimal -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeNewDecimal, mysql.TypeNewDecimal,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeNewDecimal, mysql.TypeNewDecimal,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeDouble, mysql.TypeDouble,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeNewDecimal, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeNewDecimal, mysql.TypeNewDecimal,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeNewDecimal,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeNewDecimal, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeEnum -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeEnum, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeSet -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeSet, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeTinyBlob -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeTinyBlob,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeLongBlob,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeTinyBlob,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeTinyBlob, mysql.TypeTinyBlob,\n\t},\n\t/* mysql.TypeMediumBlob -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeMediumBlob,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeLongBlob,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeMediumBlob, mysql.TypeMediumBlob,\n\t},\n\t/* mysql.TypeLongBlob -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeLongBlob,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeLongBlob,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeLongBlob, mysql.TypeLongBlob,\n\t},\n\t/* mysql.TypeBlob -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeBlob,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeLongBlob,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeBlob, mysql.TypeBlob,\n\t},\n\t/* mysql.TypeVarString -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t},\n\t/* mysql.TypeString -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeString, mysql.TypeString,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeString, mysql.TypeString,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeString, mysql.TypeString,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeString, mysql.TypeString,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeString, mysql.TypeString,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeString, mysql.TypeString,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeString, mysql.TypeString,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeString, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeString,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeString,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeString, mysql.TypeString,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeString, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeString,\n\t},\n\t/* mysql.TypeGeometry -> */\n\t{\n\t\t//mysql.TypeDecimal      mysql.TypeTiny\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeShort        mysql.TypeLong\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeFloat        mysql.TypeDouble\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNull         mysql.TypeTimestamp\n\t\tmysql.TypeGeometry, mysql.TypeVarchar,\n\t\t//mysql.TypeLonglong     mysql.TypeInt24\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDate         mysql.TypeTime\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeDatetime     mysql.TypeYear\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeNewDate      mysql.TypeVarchar\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeBit          <16>-<244>\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeJSON\n\t\tmysql.TypeVarchar,\n\t\t//mysql.TypeNewDecimal   mysql.TypeEnum\n\t\tmysql.TypeVarchar, mysql.TypeVarchar,\n\t\t//mysql.TypeSet          mysql.TypeTinyBlob\n\t\tmysql.TypeVarchar, mysql.TypeTinyBlob,\n\t\t//mysql.TypeMediumBlob  mysql.TypeLongBlob\n\t\tmysql.TypeMediumBlob, mysql.TypeLongBlob,\n\t\t//mysql.TypeBlob         mysql.TypeVarString\n\t\tmysql.TypeBlob, mysql.TypeVarchar,\n\t\t//mysql.TypeString       mysql.TypeGeometry\n\t\tmysql.TypeString, mysql.TypeGeometry,\n\t},\n}\n\n// SetBinChsClnFlag sets charset, collation as 'binary' and adds binaryFlag to FieldType.\nfunc SetBinChsClnFlag(ft *FieldType) {\n\tft.Charset = charset.CharsetBin\n\tft.Collate = charset.CollationBin\n\tft.Flag |= mysql.BinaryFlag\n}\n\n// VarStorageLen indicates this column is a variable length column.\nconst VarStorageLen = ast.VarStorageLen\n"
  },
  {
    "path": "pkg/types/fsp.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/pingcap/errors\"\n)\n\nconst (\n\t// UnspecifiedFsp is the unspecified fractional seconds part.\n\tUnspecifiedFsp = int8(-1)\n\t// MaxFsp is the maximum digit of fractional seconds part.\n\tMaxFsp = int8(6)\n\t// MinFsp is the minimum digit of fractional seconds part.\n\tMinFsp = int8(0)\n\t// DefaultFsp is the default digit of fractional seconds part.\n\t// MySQL use 0 as the default Fsp.\n\tDefaultFsp = int8(0)\n)\n\n// CheckFsp checks whether fsp is in valid range.\nfunc CheckFsp(fsp int) (int8, error) {\n\tif fsp == int(UnspecifiedFsp) {\n\t\treturn DefaultFsp, nil\n\t}\n\tif fsp < int(MinFsp) || fsp > int(MaxFsp) {\n\t\treturn DefaultFsp, errors.Errorf(\"Invalid fsp %d\", fsp)\n\t}\n\treturn int8(fsp), nil\n}\n\n// ParseFrac parses the input string according to fsp, returns the microsecond,\n// and also a bool value to indice overflow. eg:\n// \"999\" fsp=2 will overflow.\nfunc ParseFrac(s string, fsp int8) (v int, overflow bool, err error) {\n\tif len(s) == 0 {\n\t\treturn 0, false, nil\n\t}\n\n\tfsp, err = CheckFsp(int(fsp))\n\tif err != nil {\n\t\treturn 0, false, errors.Trace(err)\n\t}\n\n\tif int(fsp) >= len(s) {\n\t\ttmp, e := strconv.ParseInt(s, 10, 64)\n\t\tif e != nil {\n\t\t\treturn 0, false, errors.Trace(e)\n\t\t}\n\t\tv = int(float64(tmp) * math.Pow10(int(MaxFsp)-len(s)))\n\t\treturn\n\t}\n\n\t// Round when fsp < string length.\n\ttmp, e := strconv.ParseInt(s[:fsp+1], 10, 64)\n\tif e != nil {\n\t\treturn 0, false, errors.Trace(e)\n\t}\n\ttmp = (tmp + 5) / 10\n\n\tif float64(tmp) >= math.Pow10(int(fsp)) {\n\t\t// overflow\n\t\treturn 0, true, nil\n\t}\n\n\t// Get the final frac, with 6 digit number\n\t//  1236 round 3 -> 124 -> 124000\n\t//  0312 round 2 -> 3 -> 30000\n\t//  999 round 2 -> 100 -> overflow\n\tv = int(float64(tmp) * math.Pow10(int(MaxFsp-fsp)))\n\treturn\n}\n\n// alignFrac is used to generate alignment frac, like `100` -> `100000` ,`-100` -> `-100000`\nfunc alignFrac(s string, fsp int) string {\n\tsl := len(s)\n\tif sl > 0 && s[0] == '-' {\n\t\tsl = sl - 1\n\t}\n\tif sl < fsp {\n\t\treturn s + strings.Repeat(\"0\", fsp-sl)\n\t}\n\n\treturn s\n}\n"
  },
  {
    "path": "pkg/types/helper.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"math\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/pingcap/errors\"\n)\n\n// RoundFloat rounds float val to the nearest integer value with float64 format, like MySQL Round function.\n// RoundFloat uses default rounding mode, see https://dev.mysql.com/doc/refman/5.7/en/precision-math-rounding.html\n// so rounding use \"round half away from zero\".\n// e.g, 1.5 -> 2, -1.5 -> -2.\nfunc RoundFloat(f float64) float64 {\n\tif math.Abs(f) < 0.5 {\n\t\treturn 0\n\t}\n\n\treturn math.Trunc(f + math.Copysign(0.5, f))\n}\n\n// Round rounds the argument f to dec decimal places.\n// dec defaults to 0 if not specified. dec can be negative\n// to cause dec digits left of the decimal point of the\n// value f to become zero.\nfunc Round(f float64, dec int) float64 {\n\tshift := math.Pow10(dec)\n\ttmp := f * shift\n\tif math.IsInf(tmp, 0) {\n\t\treturn f\n\t}\n\treturn RoundFloat(tmp) / shift\n}\n\n// Truncate truncates the argument f to dec decimal places.\n// dec defaults to 0 if not specified. dec can be negative\n// to cause dec digits left of the decimal point of the\n// value f to become zero.\nfunc Truncate(f float64, dec int) float64 {\n\tshift := math.Pow10(dec)\n\ttmp := f * shift\n\tif math.IsInf(tmp, 0) {\n\t\treturn f\n\t}\n\treturn math.Trunc(tmp) / shift\n}\n\n// GetMaxFloat gets the max float for given flen and decimal.\nfunc GetMaxFloat(flen int, decimal int) float64 {\n\tintPartLen := flen - decimal\n\tf := math.Pow10(intPartLen)\n\tf -= math.Pow10(-decimal)\n\treturn f\n}\n\n// TruncateFloat tries to truncate f.\n// If the result exceeds the max/min float that flen/decimal allowed, returns the max/min float allowed.\nfunc TruncateFloat(f float64, flen int, decimal int) (float64, error) {\n\tif math.IsNaN(f) {\n\t\t// nan returns 0\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"DOUBLE\", \"\")\n\t}\n\n\tmaxF := GetMaxFloat(flen, decimal)\n\n\tif !math.IsInf(f, 0) {\n\t\tf = Round(f, decimal)\n\t}\n\n\tvar err error\n\tif f > maxF {\n\t\tf = maxF\n\t\terr = ErrOverflow.GenWithStackByArgs(\"DOUBLE\", \"\")\n\t} else if f < -maxF {\n\t\tf = -maxF\n\t\terr = ErrOverflow.GenWithStackByArgs(\"DOUBLE\", \"\")\n\t}\n\n\treturn f, errors.Trace(err)\n}\n\nfunc isSpace(c byte) bool {\n\treturn c == ' ' || c == '\\t'\n}\n\nfunc isDigit(c byte) bool {\n\treturn c >= '0' && c <= '9'\n}\n\nfunc myMax(a, b int) int {\n\tif a > b {\n\t\treturn a\n\t}\n\treturn b\n}\n\nfunc myMaxInt8(a, b int8) int8 {\n\tif a > b {\n\t\treturn a\n\t}\n\treturn b\n}\n\nfunc myMin(a, b int) int {\n\tif a < b {\n\t\treturn a\n\t}\n\treturn b\n}\n\nfunc myMinInt8(a, b int8) int8 {\n\tif a < b {\n\t\treturn a\n\t}\n\treturn b\n}\n\nconst (\n\tmaxUint    = uint64(math.MaxUint64)\n\tuintCutOff = maxUint/uint64(10) + 1\n\tintCutOff  = uint64(math.MaxInt64) + 1\n)\n\n// strToInt converts a string to an integer in best effort.\nfunc strToInt(str string) (int64, error) {\n\tstr = strings.TrimSpace(str)\n\tif len(str) == 0 {\n\t\treturn 0, ErrTruncated\n\t}\n\tnegative := false\n\ti := 0\n\tif str[i] == '-' {\n\t\tnegative = true\n\t\ti++\n\t} else if str[i] == '+' {\n\t\ti++\n\t}\n\n\tvar (\n\t\terr    error\n\t\thasNum = false\n\t)\n\tr := uint64(0)\n\tfor ; i < len(str); i++ {\n\t\tif !unicode.IsDigit(rune(str[i])) {\n\t\t\terr = ErrTruncated\n\t\t\tbreak\n\t\t}\n\t\thasNum = true\n\t\tif r >= uintCutOff {\n\t\t\tr = 0\n\t\t\terr = errors.Trace(ErrBadNumber)\n\t\t\tbreak\n\t\t}\n\t\tr = r * uint64(10)\n\n\t\tr1 := r + uint64(str[i]-'0')\n\t\tif r1 < r || r1 > maxUint {\n\t\t\tr = 0\n\t\t\terr = errors.Trace(ErrBadNumber)\n\t\t\tbreak\n\t\t}\n\t\tr = r1\n\t}\n\tif !hasNum {\n\t\terr = ErrTruncated\n\t}\n\n\tif !negative && r >= intCutOff {\n\t\treturn math.MaxInt64, errors.Trace(ErrBadNumber)\n\t}\n\n\tif negative && r > intCutOff {\n\t\treturn math.MinInt64, errors.Trace(ErrBadNumber)\n\t}\n\n\tif negative {\n\t\tr = -r\n\t}\n\treturn int64(r), err\n}\n"
  },
  {
    "path": "pkg/types/mydecimal.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n)\n\n// RoundMode is the type for round mode.\ntype RoundMode int32\n\n// constant values.\nconst (\n\tten0 = 1\n\tten1 = 10\n\tten2 = 100\n\tten3 = 1000\n\tten4 = 10000\n\tten5 = 100000\n\tten6 = 1000000\n\tten7 = 10000000\n\tten8 = 100000000\n\tten9 = 1000000000\n\n\tmaxWordBufLen = 9 // A MyDecimal holds 9 words.\n\tdigitsPerWord = 9 // A word holds 9 digits.\n\twordSize      = 4 // A word is 4 bytes int32.\n\tdigMask       = ten8\n\twordBase      = ten9\n\twordMax       = wordBase - 1\n\tnotFixedDec   = 31\n\n\tDivFracIncr = 4\n\n\t// ModeHalfEven rounds normally.\n\tModeHalfEven RoundMode = 5\n\t// Truncate just truncates the decimal.\n\tModeTruncate RoundMode = 10\n\t// Ceiling is not supported now.\n\tmodeCeiling RoundMode = 0\n)\n\nvar (\n\twordBufLen = 9\n\tmod9       = [128]int8{\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1, 2, 3, 4, 5, 6, 7, 8,\n\t\t0, 1,\n\t}\n\tdiv9 = [128]int{\n\t\t0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t\t2, 2, 2, 2, 2, 2, 2, 2, 2,\n\t\t3, 3, 3, 3, 3, 3, 3, 3, 3,\n\t\t4, 4, 4, 4, 4, 4, 4, 4, 4,\n\t\t5, 5, 5, 5, 5, 5, 5, 5, 5,\n\t\t6, 6, 6, 6, 6, 6, 6, 6, 6,\n\t\t7, 7, 7, 7, 7, 7, 7, 7, 7,\n\t\t8, 8, 8, 8, 8, 8, 8, 8, 8,\n\t\t9, 9, 9, 9, 9, 9, 9, 9, 9,\n\t\t10, 10, 10, 10, 10, 10, 10, 10, 10,\n\t\t11, 11, 11, 11, 11, 11, 11, 11, 11,\n\t\t12, 12, 12, 12, 12, 12, 12, 12, 12,\n\t\t13, 13, 13, 13, 13, 13, 13, 13, 13,\n\t\t14, 14,\n\t}\n\tpowers10  = [10]int32{ten0, ten1, ten2, ten3, ten4, ten5, ten6, ten7, ten8, ten9}\n\tdig2bytes = [10]int{0, 1, 1, 2, 2, 3, 3, 4, 4, 4}\n\tfracMax   = [8]int32{\n\t\t900000000,\n\t\t990000000,\n\t\t999000000,\n\t\t999900000,\n\t\t999990000,\n\t\t999999000,\n\t\t999999900,\n\t\t999999990,\n\t}\n\tzeroMyDecimal = MyDecimal{}\n)\n\n// get the zero of MyDecimal with the specified result fraction digits\nfunc zeroMyDecimalWithFrac(frac int8) MyDecimal {\n\tzero := MyDecimal{}\n\tzero.digitsFrac = frac\n\tzero.resultFrac = frac\n\treturn zero\n}\n\n// add adds a and b and carry, returns the sum and new carry.\nfunc add(a, b, carry int32) (int32, int32) {\n\tsum := a + b + carry\n\tif sum >= wordBase {\n\t\tcarry = 1\n\t\tsum -= wordBase\n\t} else {\n\t\tcarry = 0\n\t}\n\treturn sum, carry\n}\n\n// add2 adds a and b and carry, returns the sum and new carry.\n// It is only used in DecimalMul.\nfunc add2(a, b, carry int32) (int32, int32) {\n\tsum := int64(a) + int64(b) + int64(carry)\n\tif sum >= wordBase {\n\t\tcarry = 1\n\t\tsum -= wordBase\n\t} else {\n\t\tcarry = 0\n\t}\n\n\tif sum >= wordBase {\n\t\tsum -= wordBase\n\t\tcarry++\n\t}\n\treturn int32(sum), carry\n}\n\n// sub subtracts b and carry from a, returns the diff and new carry.\nfunc sub(a, b, carry int32) (int32, int32) {\n\tdiff := a - b - carry\n\tif diff < 0 {\n\t\tcarry = 1\n\t\tdiff += wordBase\n\t} else {\n\t\tcarry = 0\n\t}\n\treturn diff, carry\n}\n\n// sub2 subtracts b and carry from a, returns the diff and new carry.\n// the new carry may be 2.\nfunc sub2(a, b, carry int32) (int32, int32) {\n\tdiff := a - b - carry\n\tif diff < 0 {\n\t\tcarry = 1\n\t\tdiff += wordBase\n\t} else {\n\t\tcarry = 0\n\t}\n\tif diff < 0 {\n\t\tdiff += wordBase\n\t\tcarry++\n\t}\n\treturn diff, carry\n}\n\n// fixWordCntError limits word count in wordBufLen, and returns overflow or truncate error.\nfunc fixWordCntError(wordsInt, wordsFrac int) (newWordsInt int, newWordsFrac int, err error) {\n\tif wordsInt+wordsFrac > wordBufLen {\n\t\tif wordsInt > wordBufLen {\n\t\t\treturn wordBufLen, 0, ErrOverflow\n\t\t}\n\t\treturn wordsInt, wordBufLen - wordsInt, ErrTruncated\n\t}\n\treturn wordsInt, wordsFrac, nil\n}\n\n/*\ncountLeadingZeroes returns the number of leading zeroes that can be removed from fraction.\n\n@param   i    start index\n@param   word value to compare against list of powers of 10\n*/\nfunc countLeadingZeroes(i int, word int32) int {\n\tleading := 0\n\tfor word < powers10[i] {\n\t\ti--\n\t\tleading++\n\t}\n\treturn leading\n}\n\n/*\ncountTrailingZeros returns the number of trailing zeroes that can be removed from fraction.\n\n@param   i    start index\n@param   word  value to compare against list of powers of 10\n*/\nfunc countTrailingZeroes(i int, word int32) int {\n\ttrailing := 0\n\tfor word%powers10[i] == 0 {\n\t\ti++\n\t\ttrailing++\n\t}\n\treturn trailing\n}\n\nfunc digitsToWords(digits int) int {\n\tif digits+digitsPerWord-1 >= 0 && digits+digitsPerWord-1 < 128 {\n\t\treturn div9[digits+digitsPerWord-1]\n\t}\n\treturn (digits + digitsPerWord - 1) / digitsPerWord\n}\n\n// MyDecimalStructSize is the struct size of MyDecimal.\nconst MyDecimalStructSize = 40\n\n// MyDecimal represents a decimal value.\ntype MyDecimal struct {\n\tdigitsInt int8 // the number of *decimal* digits before the point.\n\n\tdigitsFrac int8 // the number of decimal digits after the point.\n\n\tresultFrac int8 // result fraction digits.\n\n\tnegative bool\n\n\t//  wordBuf is an array of int32 words.\n\t// A word is an int32 value can hold 9 digits.(0 <= word < wordBase)\n\twordBuf [maxWordBufLen]int32\n}\n\n// IsNegative returns whether a decimal is negative.\nfunc (d *MyDecimal) IsNegative() bool {\n\treturn d.negative\n}\n\nfunc (d *MyDecimal) SetNegative(negative bool) {\n\td.negative = negative\n}\n\n// GetDigitsFrac returns the digitsFrac.\nfunc (d *MyDecimal) GetDigitsFrac() int8 {\n\treturn d.digitsFrac\n}\n\n// GetDigitsInt returns the digitsInt.\nfunc (d *MyDecimal) GetDigitsInt() int8 {\n\treturn d.digitsInt\n}\n\n// String returns the decimal string representation rounded to resultFrac.\nfunc (d *MyDecimal) String() string {\n\ttmp := *d\n\terr := tmp.Round(&tmp, int(tmp.resultFrac), ModeHalfEven)\n\tterror.Log(errors.Trace(err))\n\treturn string(tmp.ToString())\n}\n\nfunc (d *MyDecimal) stringSize() int {\n\t// sign, zero integer and dot.\n\treturn int(d.digitsInt + d.digitsFrac + 3)\n}\n\nfunc (d *MyDecimal) removeLeadingZeros() (wordIdx int, digitsInt int) {\n\tdigitsInt = int(d.digitsInt)\n\ti := ((digitsInt - 1) % digitsPerWord) + 1\n\tfor digitsInt > 0 && d.wordBuf[wordIdx] == 0 {\n\t\tdigitsInt -= i\n\t\ti = digitsPerWord\n\t\twordIdx++\n\t}\n\tif digitsInt > 0 {\n\t\tdigitsInt -= countLeadingZeroes((digitsInt-1)%digitsPerWord, d.wordBuf[wordIdx])\n\t} else {\n\t\tdigitsInt = 0\n\t}\n\treturn\n}\n\nfunc (d *MyDecimal) removeTrailingZeros() (lastWordIdx int, digitsFrac int) {\n\tdigitsFrac = int(d.digitsFrac)\n\ti := ((digitsFrac - 1) % digitsPerWord) + 1\n\tlastWordIdx = digitsToWords(int(d.digitsInt)) + digitsToWords(int(d.digitsFrac))\n\tfor digitsFrac > 0 && d.wordBuf[lastWordIdx-1] == 0 {\n\t\tdigitsFrac -= i\n\t\ti = digitsPerWord\n\t\tlastWordIdx--\n\t}\n\tif digitsFrac > 0 {\n\t\tdigitsFrac -= countTrailingZeroes(9-((digitsFrac-1)%digitsPerWord), d.wordBuf[lastWordIdx-1])\n\t} else {\n\t\tdigitsFrac = 0\n\t}\n\treturn\n}\n\n// ToString converts decimal to its printable string representation without rounding.\n//\n//\tRETURN VALUE\n//\n//\t    str       - result string\n//\t    errCode   - eDecOK/eDecTruncate/eDecOverflow\nfunc (d *MyDecimal) ToString() (str []byte) {\n\tstr = make([]byte, d.stringSize())\n\tdigitsFrac := int(d.digitsFrac)\n\twordStartIdx, digitsInt := d.removeLeadingZeros()\n\tif digitsInt+digitsFrac == 0 {\n\t\tdigitsInt = 1\n\t\twordStartIdx = 0\n\t}\n\n\tdigitsIntLen := digitsInt\n\tif digitsIntLen == 0 {\n\t\tdigitsIntLen = 1\n\t}\n\tdigitsFracLen := digitsFrac\n\tlength := digitsIntLen + digitsFracLen\n\tif d.negative {\n\t\tlength++\n\t}\n\tif digitsFrac > 0 {\n\t\tlength++\n\t}\n\tstr = str[:length]\n\tstrIdx := 0\n\tif d.negative {\n\t\tstr[strIdx] = '-'\n\t\tstrIdx++\n\t}\n\tvar fill int\n\tif digitsFrac > 0 {\n\t\tfracIdx := strIdx + digitsIntLen\n\t\tfill = digitsFracLen - digitsFrac\n\t\twordIdx := wordStartIdx + digitsToWords(digitsInt)\n\t\tstr[fracIdx] = '.'\n\t\tfracIdx++\n\t\tfor ; digitsFrac > 0; digitsFrac -= digitsPerWord {\n\t\t\tx := d.wordBuf[wordIdx]\n\t\t\twordIdx++\n\t\t\tfor i := myMin(digitsFrac, digitsPerWord); i > 0; i-- {\n\t\t\t\ty := x / digMask\n\t\t\t\tstr[fracIdx] = byte(y) + '0'\n\t\t\t\tfracIdx++\n\t\t\t\tx -= y * digMask\n\t\t\t\tx *= 10\n\t\t\t}\n\t\t}\n\t\tfor ; fill > 0; fill-- {\n\t\t\tstr[fracIdx] = '0'\n\t\t\tfracIdx++\n\t\t}\n\t}\n\tfill = digitsIntLen - digitsInt\n\tif digitsInt == 0 {\n\t\tfill-- /* symbol 0 before digital point */\n\t}\n\tfor ; fill > 0; fill-- {\n\t\tstr[strIdx] = '0'\n\t\tstrIdx++\n\t}\n\tif digitsInt > 0 {\n\t\tstrIdx += digitsInt\n\t\twordIdx := wordStartIdx + digitsToWords(digitsInt)\n\t\tfor ; digitsInt > 0; digitsInt -= digitsPerWord {\n\t\t\twordIdx--\n\t\t\tx := d.wordBuf[wordIdx]\n\t\t\tfor i := myMin(digitsInt, digitsPerWord); i > 0; i-- {\n\t\t\t\ty := x / 10\n\t\t\t\tstrIdx--\n\t\t\t\tstr[strIdx] = '0' + byte(x-y*10)\n\t\t\t\tx = y\n\t\t\t}\n\t\t}\n\t} else {\n\t\tstr[strIdx] = '0'\n\t}\n\treturn\n}\n\n// FromString parses decimal from string.\nfunc (d *MyDecimal) FromString(str []byte) error {\n\tfor i := 0; i < len(str); i++ {\n\t\tif !isSpace(str[i]) {\n\t\t\tstr = str[i:]\n\t\t\tbreak\n\t\t}\n\t}\n\tif len(str) == 0 {\n\t\t*d = zeroMyDecimal\n\t\treturn ErrBadNumber\n\t}\n\tswitch str[0] {\n\tcase '-':\n\t\td.negative = true\n\t\tfallthrough\n\tcase '+':\n\t\tstr = str[1:]\n\t}\n\tvar strIdx int\n\tfor strIdx < len(str) && isDigit(str[strIdx]) {\n\t\tstrIdx++\n\t}\n\tdigitsInt := strIdx\n\tvar digitsFrac int\n\tvar endIdx int\n\tif strIdx < len(str) && str[strIdx] == '.' {\n\t\tendIdx = strIdx + 1\n\t\tfor endIdx < len(str) && isDigit(str[endIdx]) {\n\t\t\tendIdx++\n\t\t}\n\t\tdigitsFrac = endIdx - strIdx - 1\n\t} else {\n\t\tdigitsFrac = 0\n\t\tendIdx = strIdx\n\t}\n\tif digitsInt+digitsFrac == 0 {\n\t\t*d = zeroMyDecimal\n\t\treturn ErrBadNumber\n\t}\n\twordsInt := digitsToWords(digitsInt)\n\twordsFrac := digitsToWords(digitsFrac)\n\twordsInt, wordsFrac, err := fixWordCntError(wordsInt, wordsFrac)\n\tif err != nil {\n\t\tdigitsFrac = wordsFrac * digitsPerWord\n\t\tif err == ErrOverflow {\n\t\t\tdigitsInt = wordsInt * digitsPerWord\n\t\t}\n\t}\n\td.digitsInt = int8(digitsInt)\n\td.digitsFrac = int8(digitsFrac)\n\twordIdx := wordsInt\n\tstrIdxTmp := strIdx\n\tvar word int32\n\tvar innerIdx int\n\tfor digitsInt > 0 {\n\t\tdigitsInt--\n\t\tstrIdx--\n\t\tword += int32(str[strIdx]-'0') * powers10[innerIdx]\n\t\tinnerIdx++\n\t\tif innerIdx == digitsPerWord {\n\t\t\twordIdx--\n\t\t\td.wordBuf[wordIdx] = word\n\t\t\tword = 0\n\t\t\tinnerIdx = 0\n\t\t}\n\t}\n\tif innerIdx != 0 {\n\t\twordIdx--\n\t\td.wordBuf[wordIdx] = word\n\t}\n\n\twordIdx = wordsInt\n\tstrIdx = strIdxTmp\n\tword = 0\n\tinnerIdx = 0\n\tfor digitsFrac > 0 {\n\t\tdigitsFrac--\n\t\tstrIdx++\n\t\tword = int32(str[strIdx]-'0') + word*10\n\t\tinnerIdx++\n\t\tif innerIdx == digitsPerWord {\n\t\t\td.wordBuf[wordIdx] = word\n\t\t\twordIdx++\n\t\t\tword = 0\n\t\t\tinnerIdx = 0\n\t\t}\n\t}\n\tif innerIdx != 0 {\n\t\td.wordBuf[wordIdx] = word * powers10[digitsPerWord-innerIdx]\n\t}\n\tif endIdx+1 <= len(str) && (str[endIdx] == 'e' || str[endIdx] == 'E') {\n\t\texponent, err1 := strToInt(string(str[endIdx+1:]))\n\t\tif err1 != nil {\n\t\t\terr = errors.Cause(err1)\n\t\t\tif err != ErrTruncated {\n\t\t\t\t*d = zeroMyDecimal\n\t\t\t}\n\t\t}\n\t\tif exponent > math.MaxInt32/2 {\n\t\t\tnegative := d.negative\n\t\t\tmaxDecimal(wordBufLen*digitsPerWord, 0, d)\n\t\t\td.negative = negative\n\t\t\terr = ErrOverflow\n\t\t}\n\t\tif exponent < math.MinInt32/2 && err != ErrOverflow {\n\t\t\t*d = zeroMyDecimal\n\t\t\terr = ErrTruncated\n\t\t}\n\t\tif err != ErrOverflow {\n\t\t\tshiftErr := d.Shift(int(exponent))\n\t\t\tif shiftErr != nil {\n\t\t\t\tif shiftErr == ErrOverflow {\n\t\t\t\t\tnegative := d.negative\n\t\t\t\t\tmaxDecimal(wordBufLen*digitsPerWord, 0, d)\n\t\t\t\t\td.negative = negative\n\t\t\t\t}\n\t\t\t\terr = shiftErr\n\t\t\t}\n\t\t}\n\t}\n\tallZero := true\n\tfor i := 0; i < wordBufLen; i++ {\n\t\tif d.wordBuf[i] != 0 {\n\t\t\tallZero = false\n\t\t\tbreak\n\t\t}\n\t}\n\tif allZero {\n\t\td.negative = false\n\t}\n\td.resultFrac = d.digitsFrac\n\treturn err\n}\n\n// Shift shifts decimal digits in given number (with rounding if it need), shift > 0 means shift to left shift,\n// shift < 0 means right shift. In fact it is multiplying on 10^shift.\n//\n// RETURN\n//\n//\teDecOK          OK\n//\teDecOverflow    operation lead to overflow, number is untoched\n//\teDecTruncated   number was rounded to fit into buffer\nfunc (d *MyDecimal) Shift(shift int) error {\n\tvar err error\n\tif shift == 0 {\n\t\treturn nil\n\t}\n\tvar (\n\t\t// digitBegin is index of first non zero digit (all indexes from 0).\n\t\tdigitBegin int\n\t\t// digitEnd is index of position after last decimal digit.\n\t\tdigitEnd int\n\t\t// point is index of digit position just after point.\n\t\tpoint = digitsToWords(int(d.digitsInt)) * digitsPerWord\n\t\t// new point position.\n\t\tnewPoint = point + shift\n\t\t// number of digits in result.\n\t\tdigitsInt, digitsFrac int\n\t\tnewFront              int\n\t)\n\tdigitBegin, digitEnd = d.digitBounds()\n\tif digitBegin == digitEnd {\n\t\t*d = zeroMyDecimal\n\t\treturn nil\n\t}\n\n\tdigitsInt = newPoint - digitBegin\n\tif digitsInt < 0 {\n\t\tdigitsInt = 0\n\t}\n\tdigitsFrac = digitEnd - newPoint\n\tif digitsFrac < 0 {\n\t\tdigitsFrac = 0\n\t}\n\twordsInt := digitsToWords(digitsInt)\n\twordsFrac := digitsToWords(digitsFrac)\n\tnewLen := wordsInt + wordsFrac\n\tif newLen > wordBufLen {\n\t\tlack := newLen - wordBufLen\n\t\tif wordsFrac < lack {\n\t\t\treturn ErrOverflow\n\t\t}\n\t\t/* cut off fraction part to allow new number to fit in our buffer */\n\t\terr = ErrTruncated\n\t\twordsFrac -= lack\n\t\tdiff := digitsFrac - wordsFrac*digitsPerWord\n\t\terr1 := d.Round(d, digitEnd-point-diff, ModeHalfEven)\n\t\tif err1 != nil {\n\t\t\treturn errors.Trace(err1)\n\t\t}\n\t\tdigitEnd -= diff\n\t\tdigitsFrac = wordsFrac * digitsPerWord\n\t\tif digitEnd <= digitBegin {\n\t\t\t/*\n\t\t\t   We lost all digits (they will be shifted out of buffer), so we can\n\t\t\t   just return 0.\n\t\t\t*/\n\t\t\t*d = zeroMyDecimal\n\t\t\treturn ErrTruncated\n\t\t}\n\t}\n\n\tif shift%digitsPerWord != 0 {\n\t\tvar lMiniShift, rMiniShift, miniShift int\n\t\tvar doLeft bool\n\t\t/*\n\t\t   Calculate left/right shift to align decimal digits inside our bug\n\t\t   digits correctly.\n\t\t*/\n\t\tif shift > 0 {\n\t\t\tlMiniShift = shift % digitsPerWord\n\t\t\trMiniShift = digitsPerWord - lMiniShift\n\t\t\tdoLeft = lMiniShift <= digitBegin\n\t\t} else {\n\t\t\trMiniShift = (-shift) % digitsPerWord\n\t\t\tlMiniShift = digitsPerWord - rMiniShift\n\t\t\tdoLeft = (digitsPerWord*wordBufLen - digitEnd) < rMiniShift\n\t\t}\n\t\tif doLeft {\n\t\t\td.doMiniLeftShift(lMiniShift, digitBegin, digitEnd)\n\t\t\tminiShift = -lMiniShift\n\t\t} else {\n\t\t\td.doMiniRightShift(rMiniShift, digitBegin, digitEnd)\n\t\t\tminiShift = rMiniShift\n\t\t}\n\t\tnewPoint += miniShift\n\t\t/*\n\t\t   If number is shifted and correctly aligned in buffer we can finish.\n\t\t*/\n\t\tif shift+miniShift == 0 && (newPoint-digitsInt) < digitsPerWord {\n\t\t\td.digitsInt = int8(digitsInt)\n\t\t\td.digitsFrac = int8(digitsFrac)\n\t\t\treturn err /* already shifted as it should be */\n\t\t}\n\t\tdigitBegin += miniShift\n\t\tdigitEnd += miniShift\n\t}\n\n\t/* if new 'decimal front' is in first digit, we do not need move digits */\n\tnewFront = newPoint - digitsInt\n\tif newFront >= digitsPerWord || newFront < 0 {\n\t\t/* need to move digits */\n\t\tvar wordShift int\n\t\tif newFront > 0 {\n\t\t\t/* move left */\n\t\t\twordShift = newFront / digitsPerWord\n\t\t\tto := digitBegin/digitsPerWord - wordShift\n\t\t\tbarier := (digitEnd-1)/digitsPerWord - wordShift\n\t\t\tfor ; to <= barier; to++ {\n\t\t\t\td.wordBuf[to] = d.wordBuf[to+wordShift]\n\t\t\t}\n\t\t\tfor barier += wordShift; to <= barier; to++ {\n\t\t\t\td.wordBuf[to] = 0\n\t\t\t}\n\t\t\twordShift = -wordShift\n\t\t} else {\n\t\t\t/* move right */\n\t\t\twordShift = (1 - newFront) / digitsPerWord\n\t\t\tto := (digitEnd-1)/digitsPerWord + wordShift\n\t\t\tbarier := digitBegin/digitsPerWord + wordShift\n\t\t\tfor ; to >= barier; to-- {\n\t\t\t\td.wordBuf[to] = d.wordBuf[to-wordShift]\n\t\t\t}\n\t\t\tfor barier -= wordShift; to >= barier; to-- {\n\t\t\t\td.wordBuf[to] = 0\n\t\t\t}\n\t\t}\n\t\tdigitShift := wordShift * digitsPerWord\n\t\tdigitBegin += digitShift\n\t\tdigitEnd += digitShift\n\t\tnewPoint += digitShift\n\t}\n\t/*\n\t   If there are gaps then fill them with 0.\n\n\t   Only one of following 'for' loops will work because wordIdxBegin <= wordIdxEnd.\n\t*/\n\twordIdxBegin := digitBegin / digitsPerWord\n\twordIdxEnd := (digitEnd - 1) / digitsPerWord\n\twordIdxNewPoint := 0\n\n\t/* We don't want negative new_point below */\n\tif newPoint != 0 {\n\t\twordIdxNewPoint = (newPoint - 1) / digitsPerWord\n\t}\n\tif wordIdxNewPoint > wordIdxEnd {\n\t\tfor wordIdxNewPoint > wordIdxEnd {\n\t\t\td.wordBuf[wordIdxNewPoint] = 0\n\t\t\twordIdxNewPoint--\n\t\t}\n\t} else {\n\t\tfor ; wordIdxNewPoint < wordIdxBegin; wordIdxNewPoint++ {\n\t\t\td.wordBuf[wordIdxNewPoint] = 0\n\t\t}\n\t}\n\td.digitsInt = int8(digitsInt)\n\td.digitsFrac = int8(digitsFrac)\n\treturn err\n}\n\n/*\ndigitBounds returns bounds of decimal digits in the number.\n\n\tstart - index (from 0 ) of first decimal digits.\n\tend   - index of position just after last decimal digit.\n*/\nfunc (d *MyDecimal) digitBounds() (start, end int) {\n\tvar i int\n\tbufBeg := 0\n\tbufLen := digitsToWords(int(d.digitsInt)) + digitsToWords(int(d.digitsFrac))\n\tbufEnd := bufLen - 1\n\n\t/* find non-zero digit from number beginning */\n\tfor bufBeg < bufLen && d.wordBuf[bufBeg] == 0 {\n\t\tbufBeg++\n\t}\n\tif bufBeg >= bufLen {\n\t\treturn 0, 0\n\t}\n\n\t/* find non-zero decimal digit from number beginning */\n\tif bufBeg == 0 && d.digitsInt > 0 {\n\t\ti = (int(d.digitsInt) - 1) % digitsPerWord\n\t\tstart = digitsPerWord - i - 1\n\t} else {\n\t\ti = digitsPerWord - 1\n\t\tstart = bufBeg * digitsPerWord\n\t}\n\tif bufBeg < bufLen {\n\t\tstart += countLeadingZeroes(i, d.wordBuf[bufBeg])\n\t}\n\n\t/* find non-zero digit at the end */\n\tfor bufEnd > bufBeg && d.wordBuf[bufEnd] == 0 {\n\t\tbufEnd--\n\t}\n\t/* find non-zero decimal digit from the end */\n\tif bufEnd == bufLen-1 && d.digitsFrac > 0 {\n\t\ti = (int(d.digitsFrac)-1)%digitsPerWord + 1\n\t\tend = bufEnd*digitsPerWord + i\n\t\ti = digitsPerWord - i + 1\n\t} else {\n\t\tend = (bufEnd + 1) * digitsPerWord\n\t\ti = 1\n\t}\n\tend -= countTrailingZeroes(i, d.wordBuf[bufEnd])\n\treturn start, end\n}\n\n/*\ndoMiniLeftShift does left shift for alignment of data in buffer.\n\n\tshift   number of decimal digits on which it should be shifted\n\tbeg/end bounds of decimal digits (see digitsBounds())\n\nNOTE\n\n\tResult fitting in the buffer should be garanted.\n\t'shift' have to be from 1 to digitsPerWord-1 (inclusive)\n*/\nfunc (d *MyDecimal) doMiniLeftShift(shift, beg, end int) {\n\tbufFrom := beg / digitsPerWord\n\tbufEnd := (end - 1) / digitsPerWord\n\tcShift := digitsPerWord - shift\n\tif beg%digitsPerWord < shift {\n\t\td.wordBuf[bufFrom-1] = d.wordBuf[bufFrom] / powers10[cShift]\n\t}\n\tfor bufFrom < bufEnd {\n\t\td.wordBuf[bufFrom] = (d.wordBuf[bufFrom]%powers10[cShift])*powers10[shift] + d.wordBuf[bufFrom+1]/powers10[cShift]\n\t\tbufFrom++\n\t}\n\td.wordBuf[bufFrom] = (d.wordBuf[bufFrom] % powers10[cShift]) * powers10[shift]\n}\n\n/*\ndoMiniRightShift does right shift for alignment of data in buffer.\n\n\tshift   number of decimal digits on which it should be shifted\n\tbeg/end bounds of decimal digits (see digitsBounds())\n\nNOTE\n\n\tResult fitting in the buffer should be garanted.\n\t'shift' have to be from 1 to digitsPerWord-1 (inclusive)\n*/\nfunc (d *MyDecimal) doMiniRightShift(shift, beg, end int) {\n\tbufFrom := (end - 1) / digitsPerWord\n\tbufEnd := beg / digitsPerWord\n\tcShift := digitsPerWord - shift\n\tif digitsPerWord-((end-1)%digitsPerWord+1) < shift {\n\t\td.wordBuf[bufFrom+1] = (d.wordBuf[bufFrom] % powers10[shift]) * powers10[cShift]\n\t}\n\tfor bufFrom > bufEnd {\n\t\td.wordBuf[bufFrom] = d.wordBuf[bufFrom]/powers10[shift] + (d.wordBuf[bufFrom-1]%powers10[shift])*powers10[cShift]\n\t\tbufFrom--\n\t}\n\td.wordBuf[bufFrom] = d.wordBuf[bufFrom] / powers10[shift]\n}\n\n// Round rounds the decimal to \"frac\" digits.\n//\n//\t   to\t\t\t- result buffer. d == to is allowed\n//\t   frac\t\t\t- to what position after fraction point to round. can be negative!\n//\t   roundMode\t\t- round to nearest even or truncate\n//\t\t\t\tModeHalfEven rounds normally.\n//\t\t\t\tTruncate just truncates the decimal.\n//\n// NOTES\n//\n//\tscale can be negative !\n//\tone TRUNCATED error (line XXX below) isn't treated very logical :(\n//\n// RETURN VALUE\n//\n//\teDecOK/eDecTruncated\nfunc (d *MyDecimal) Round(to *MyDecimal, frac int, roundMode RoundMode) (err error) {\n\t// wordsFracTo is the number of fraction words in buffer.\n\twordsFracTo := (frac + 1) / digitsPerWord\n\tif frac > 0 {\n\t\twordsFracTo = digitsToWords(frac)\n\t}\n\twordsFrac := digitsToWords(int(d.digitsFrac))\n\twordsInt := digitsToWords(int(d.digitsInt))\n\n\troundDigit := int32(roundMode)\n\t/* TODO - fix this code as it won't work for CEILING mode */\n\n\tif wordsInt+wordsFracTo > wordBufLen {\n\t\twordsFracTo = wordBufLen - wordsInt\n\t\tfrac = wordsFracTo * digitsPerWord\n\t\terr = ErrTruncated\n\t}\n\tif int(d.digitsInt)+frac < 0 {\n\t\t*to = zeroMyDecimal\n\t\treturn nil\n\t}\n\tif to != d {\n\t\tcopy(to.wordBuf[:], d.wordBuf[:])\n\t\tto.negative = d.negative\n\t\tto.digitsInt = int8(myMin(wordsInt, wordBufLen) * digitsPerWord)\n\t}\n\tif wordsFracTo > wordsFrac {\n\t\tidx := wordsInt + wordsFrac\n\t\tfor wordsFracTo > wordsFrac {\n\t\t\twordsFracTo--\n\t\t\tto.wordBuf[idx] = 0\n\t\t\tidx++\n\t\t}\n\t\tto.digitsFrac = int8(frac)\n\t\tto.resultFrac = to.digitsFrac\n\t\treturn\n\t}\n\tif frac >= int(d.digitsFrac) {\n\t\tto.digitsFrac = int8(frac)\n\t\tto.resultFrac = to.digitsFrac\n\t\treturn\n\t}\n\n\t// Do increment.\n\ttoIdx := wordsInt + wordsFracTo - 1\n\tif frac == wordsFracTo*digitsPerWord {\n\t\tdoInc := false\n\t\tswitch roundMode {\n\t\t// Notice: No support for ceiling mode now.\n\t\tcase modeCeiling:\n\t\t\t// If any word after scale is not zero, do increment.\n\t\t\t// e.g ceiling 3.0001 to scale 1, gets 3.1\n\t\t\tidx := toIdx + (wordsFrac - wordsFracTo)\n\t\t\tfor idx > toIdx {\n\t\t\t\tif d.wordBuf[idx] != 0 {\n\t\t\t\t\tdoInc = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tidx--\n\t\t\t}\n\t\tcase ModeHalfEven:\n\t\t\tdigAfterScale := d.wordBuf[toIdx+1] / digMask // the first digit after scale.\n\t\t\t// If first digit after scale is 5 and round even, do increment if digit at scale is odd.\n\t\t\tdoInc = (digAfterScale > 5) || (digAfterScale == 5)\n\t\tcase ModeTruncate:\n\t\t\t// Never round, just truncate.\n\t\t\tdoInc = false\n\t\t}\n\t\tif doInc {\n\t\t\tif toIdx >= 0 {\n\t\t\t\tto.wordBuf[toIdx]++\n\t\t\t} else {\n\t\t\t\ttoIdx++\n\t\t\t\tto.wordBuf[toIdx] = wordBase\n\t\t\t}\n\t\t} else if wordsInt+wordsFracTo == 0 {\n\t\t\t*to = zeroMyDecimal\n\t\t\treturn nil\n\t\t}\n\t} else {\n\t\t/* TODO - fix this code as it won't work for CEILING mode */\n\t\tpos := wordsFracTo*digitsPerWord - frac - 1\n\t\tshiftedNumber := to.wordBuf[toIdx] / powers10[pos]\n\t\tdigAfterScale := shiftedNumber % 10\n\t\tif digAfterScale > roundDigit || (roundDigit == 5 && digAfterScale == 5) {\n\t\t\tshiftedNumber += 10\n\t\t}\n\t\tto.wordBuf[toIdx] = powers10[pos] * (shiftedNumber - digAfterScale)\n\t}\n\t/*\n\t   In case we're rounding e.g. 1.5e9 to 2.0e9, the decimal words inside\n\t   the buffer are as follows.\n\n\t   Before <1, 5e8>\n\t   After  <2, 5e8>\n\n\t   Hence we need to set the 2nd field to 0.\n\t   The same holds if we round 1.5e-9 to 2e-9.\n\t*/\n\tif wordsFracTo < wordsFrac {\n\t\tidx := wordsInt + wordsFracTo\n\t\tif frac == 0 && wordsInt == 0 {\n\t\t\tidx = 1\n\t\t}\n\t\tfor idx < wordBufLen {\n\t\t\tto.wordBuf[idx] = 0\n\t\t\tidx++\n\t\t}\n\t}\n\n\t// Handle carry.\n\tvar carry int32\n\tif to.wordBuf[toIdx] >= wordBase {\n\t\tcarry = 1\n\t\tto.wordBuf[toIdx] -= wordBase\n\t\tfor carry == 1 && toIdx > 0 {\n\t\t\ttoIdx--\n\t\t\tto.wordBuf[toIdx], carry = add(to.wordBuf[toIdx], 0, carry)\n\t\t}\n\t\tif carry > 0 {\n\t\t\tif wordsInt+wordsFracTo >= wordBufLen {\n\t\t\t\twordsFracTo--\n\t\t\t\tfrac = wordsFracTo * digitsPerWord\n\t\t\t\terr = ErrTruncated\n\t\t\t}\n\t\t\tfor toIdx = wordsInt + myMax(wordsFracTo, 0); toIdx > 0; toIdx-- {\n\t\t\t\tif toIdx < wordBufLen {\n\t\t\t\t\tto.wordBuf[toIdx] = to.wordBuf[toIdx-1]\n\t\t\t\t} else {\n\t\t\t\t\terr = ErrOverflow\n\t\t\t\t}\n\t\t\t}\n\t\t\tto.wordBuf[toIdx] = 1\n\t\t\t/* We cannot have more than 9 * 9 = 81 digits. */\n\t\t\tif int(to.digitsInt) < digitsPerWord*wordBufLen {\n\t\t\t\tto.digitsInt++\n\t\t\t} else {\n\t\t\t\terr = ErrOverflow\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor {\n\t\t\tif to.wordBuf[toIdx] != 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif toIdx == 0 {\n\t\t\t\t/* making 'zero' with the proper scale */\n\t\t\t\tidx := wordsFracTo + 1\n\t\t\t\tto.digitsInt = 1\n\t\t\t\tto.digitsFrac = int8(myMax(frac, 0))\n\t\t\t\tto.negative = false\n\t\t\t\tfor toIdx < idx {\n\t\t\t\t\tto.wordBuf[toIdx] = 0\n\t\t\t\t\ttoIdx++\n\t\t\t\t}\n\t\t\t\tto.resultFrac = to.digitsFrac\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\ttoIdx--\n\t\t}\n\t}\n\t/* Here we check 999.9 -> 1000 case when we need to increase intDigCnt */\n\tfirstDig := mod9[to.digitsInt]\n\tif firstDig > 0 && to.wordBuf[toIdx] >= powers10[firstDig] {\n\t\tto.digitsInt++\n\t}\n\tif frac < 0 {\n\t\tfrac = 0\n\t}\n\tto.digitsFrac = int8(frac)\n\tto.resultFrac = to.digitsFrac\n\treturn\n}\n\n// FromInt sets the decimal value from int64.\nfunc (d *MyDecimal) FromInt(val int64) *MyDecimal {\n\tvar uVal uint64\n\tif val < 0 {\n\t\td.negative = true\n\t\tuVal = uint64(-val)\n\t} else {\n\t\tuVal = uint64(val)\n\t}\n\treturn d.FromUint(uVal)\n}\n\n// FromUint sets the decimal value from uint64.\nfunc (d *MyDecimal) FromUint(val uint64) *MyDecimal {\n\tx := val\n\twordIdx := 1\n\tfor x >= wordBase {\n\t\twordIdx++\n\t\tx /= wordBase\n\t}\n\td.digitsFrac = 0\n\td.digitsInt = int8(wordIdx * digitsPerWord)\n\tx = val\n\tfor wordIdx > 0 {\n\t\twordIdx--\n\t\ty := x / wordBase\n\t\td.wordBuf[wordIdx] = int32(x - y*wordBase)\n\t\tx = y\n\t}\n\treturn d\n}\n\n// ToInt returns int part of the decimal, returns the result and errcode.\nfunc (d *MyDecimal) ToInt() (int64, error) {\n\tvar x int64\n\twordIdx := 0\n\tfor i := d.digitsInt; i > 0; i -= digitsPerWord {\n\t\ty := x\n\t\t/*\n\t\t   Attention: trick!\n\t\t   we're calculating -|from| instead of |from| here\n\t\t   because |LONGLONG_MIN| > LONGLONG_MAX\n\t\t   so we can convert -9223372036854775808 correctly\n\t\t*/\n\t\tx = x*wordBase - int64(d.wordBuf[wordIdx])\n\t\twordIdx++\n\t\tif y < math.MinInt64/wordBase || x > y {\n\t\t\t/*\n\t\t\t   the decimal is bigger than any possible integer\n\t\t\t   return border integer depending on the sign\n\t\t\t*/\n\t\t\tif d.negative {\n\t\t\t\treturn math.MinInt64, ErrOverflow\n\t\t\t}\n\t\t\treturn math.MaxInt64, ErrOverflow\n\t\t}\n\t}\n\t/* boundary case: 9223372036854775808 */\n\tif !d.negative && x == math.MinInt64 {\n\t\treturn math.MaxInt64, ErrOverflow\n\t}\n\tif !d.negative {\n\t\tx = -x\n\t}\n\tfor i := d.digitsFrac; i > 0; i -= digitsPerWord {\n\t\tif d.wordBuf[wordIdx] != 0 {\n\t\t\treturn x, ErrTruncated\n\t\t}\n\t\twordIdx++\n\t}\n\treturn x, nil\n}\n\n// ToUint returns int part of the decimal, returns the result and errcode.\nfunc (d *MyDecimal) ToUint() (uint64, error) {\n\tif d.negative {\n\t\treturn 0, ErrOverflow\n\t}\n\tvar x uint64\n\twordIdx := 0\n\tfor i := d.digitsInt; i > 0; i -= digitsPerWord {\n\t\ty := x\n\t\tx = x*wordBase + uint64(d.wordBuf[wordIdx])\n\t\twordIdx++\n\t\tif y > math.MaxUint64/wordBase || x < y {\n\t\t\treturn math.MaxUint64, ErrOverflow\n\t\t}\n\t}\n\tfor i := d.digitsFrac; i > 0; i -= digitsPerWord {\n\t\tif d.wordBuf[wordIdx] != 0 {\n\t\t\treturn x, ErrTruncated\n\t\t}\n\t\twordIdx++\n\t}\n\treturn x, nil\n}\n\n// FromFloat64 creates a decimal from float64 value.\nfunc (d *MyDecimal) FromFloat64(f float64) error {\n\ts := strconv.FormatFloat(f, 'g', -1, 64)\n\treturn d.FromString([]byte(s))\n}\n\n// ToFloat64 converts decimal to float64 value.\nfunc (d *MyDecimal) ToFloat64() (float64, error) {\n\tf, err := strconv.ParseFloat(d.String(), 64)\n\tif err != nil {\n\t\terr = ErrOverflow\n\t}\n\treturn f, err\n}\n\n/*\nToBin converts decimal to its binary fixed-length representation\ntwo representations of the same length can be compared with memcmp\nwith the correct -1/0/+1 result\n\n\t  PARAMS\n\t\t\tprecision/frac - if precision is 0, internal value of the decimal will be used,\n\t\t\tthen the encoded value is not memory comparable.\n\n\t  NOTE\n\t    the buffer is assumed to be of the size DecimalBinSize(precision, frac)\n\n\t  RETURN VALUE\n\t  \tbin     - binary value\n\t    errCode - eDecOK/eDecTruncate/eDecOverflow\n\n\t  DESCRIPTION\n\t    for storage decimal numbers are converted to the \"binary\" format.\n\n\t    This format has the following properties:\n\t      1. length of the binary representation depends on the {precision, frac}\n\t      as provided by the caller and NOT on the digitsInt/digitsFrac of the decimal to\n\t      convert.\n\t      2. binary representations of the same {precision, frac} can be compared\n\t      with memcmp - with the same result as DecimalCompare() of the original\n\t      decimals (not taking into account possible precision loss during\n\t      conversion).\n\n\t    This binary format is as follows:\n\t      1. First the number is converted to have a requested precision and frac.\n\t      2. Every full digitsPerWord digits of digitsInt part are stored in 4 bytes\n\t         as is\n\t      3. The first digitsInt % digitesPerWord digits are stored in the reduced\n\t         number of bytes (enough bytes to store this number of digits -\n\t         see dig2bytes)\n\t      4. same for frac - full word are stored as is,\n\t         the last frac % digitsPerWord digits - in the reduced number of bytes.\n\t      5. If the number is negative - every byte is inversed.\n\t      5. The very first bit of the resulting byte array is inverted (because\n\t         memcmp compares unsigned bytes, see property 2 above)\n\n\t    Example:\n\n\t      1234567890.1234\n\n\t    internally is represented as 3 words\n\n\t      1 234567890 123400000\n\n\t    (assuming we want a binary representation with precision=14, frac=4)\n\t    in hex it's\n\n\t      00-00-00-01  0D-FB-38-D2  07-5A-EF-40\n\n\t    now, middle word is full - it stores 9 decimal digits. It goes\n\t    into binary representation as is:\n\n\n\t      ...........  0D-FB-38-D2 ............\n\n\t    First word has only one decimal digit. We can store one digit in\n\t    one byte, no need to waste four:\n\n\t                01 0D-FB-38-D2 ............\n\n\t    now, last word. It's 123400000. We can store 1234 in two bytes:\n\n\t                01 0D-FB-38-D2 04-D2\n\n\t    So, we've packed 12 bytes number in 7 bytes.\n\t    And now we invert the highest bit to get the final result:\n\n\t                81 0D FB 38 D2 04 D2\n\n\t    And for -1234567890.1234 it would be\n\n\t                7E F2 04 C7 2D FB 2D\n*/\nfunc (d *MyDecimal) ToBin(precision, frac int) ([]byte, error) {\n\tif precision > digitsPerWord*maxWordBufLen || precision < 0 || frac > mysql.MaxDecimalScale || frac < 0 {\n\t\treturn nil, ErrBadNumber\n\t}\n\tvar err error\n\tvar mask int32\n\tif d.negative {\n\t\tmask = -1\n\t}\n\tdigitsInt := precision - frac\n\twordsInt := digitsInt / digitsPerWord\n\tleadingDigits := digitsInt - wordsInt*digitsPerWord\n\twordsFrac := frac / digitsPerWord\n\ttrailingDigits := frac - wordsFrac*digitsPerWord\n\n\twordsFracFrom := int(d.digitsFrac) / digitsPerWord\n\ttrailingDigitsFrom := int(d.digitsFrac) - wordsFracFrom*digitsPerWord\n\tintSize := wordsInt*wordSize + dig2bytes[leadingDigits]\n\tfracSize := wordsFrac*wordSize + dig2bytes[trailingDigits]\n\tfracSizeFrom := wordsFracFrom*wordSize + dig2bytes[trailingDigitsFrom]\n\toriginIntSize := intSize\n\toriginFracSize := fracSize\n\tbin := make([]byte, intSize+fracSize)\n\tbinIdx := 0\n\twordIdxFrom, digitsIntFrom := d.removeLeadingZeros()\n\tif digitsIntFrom+fracSizeFrom == 0 {\n\t\tmask = 0\n\t\tdigitsInt = 1\n\t}\n\n\twordsIntFrom := digitsIntFrom / digitsPerWord\n\tleadingDigitsFrom := digitsIntFrom - wordsIntFrom*digitsPerWord\n\tiSizeFrom := wordsIntFrom*wordSize + dig2bytes[leadingDigitsFrom]\n\n\tif digitsInt < digitsIntFrom {\n\t\twordIdxFrom += wordsIntFrom - wordsInt\n\t\tif leadingDigitsFrom > 0 {\n\t\t\twordIdxFrom++\n\t\t}\n\t\tif leadingDigits > 0 {\n\t\t\twordIdxFrom--\n\t\t}\n\t\twordsIntFrom = wordsInt\n\t\tleadingDigitsFrom = leadingDigits\n\t\terr = ErrOverflow\n\t} else if intSize > iSizeFrom {\n\t\tfor intSize > iSizeFrom {\n\t\t\tintSize--\n\t\t\tbin[binIdx] = byte(mask)\n\t\t\tbinIdx++\n\t\t}\n\t}\n\n\tif fracSize < fracSizeFrom {\n\t\twordsFracFrom = wordsFrac\n\t\ttrailingDigitsFrom = trailingDigits\n\t\terr = ErrTruncated\n\t} else if fracSize > fracSizeFrom && trailingDigitsFrom > 0 {\n\t\tif wordsFrac == wordsFracFrom {\n\t\t\ttrailingDigitsFrom = trailingDigits\n\t\t\tfracSize = fracSizeFrom\n\t\t} else {\n\t\t\twordsFracFrom++\n\t\t\ttrailingDigitsFrom = 0\n\t\t}\n\t}\n\t// xIntFrom part\n\tif leadingDigitsFrom > 0 {\n\t\ti := dig2bytes[leadingDigitsFrom]\n\t\tx := (d.wordBuf[wordIdxFrom] % powers10[leadingDigitsFrom]) ^ mask\n\t\twordIdxFrom++\n\t\twriteWord(bin[binIdx:], x, i)\n\t\tbinIdx += i\n\t}\n\n\t// wordsInt + wordsFrac part.\n\tfor stop := wordIdxFrom + wordsIntFrom + wordsFracFrom; wordIdxFrom < stop; binIdx += wordSize {\n\t\tx := d.wordBuf[wordIdxFrom] ^ mask\n\t\twordIdxFrom++\n\t\twriteWord(bin[binIdx:], x, 4)\n\t}\n\n\t// xFracFrom part\n\tif trailingDigitsFrom > 0 {\n\t\tvar x int32\n\t\ti := dig2bytes[trailingDigitsFrom]\n\t\tlim := trailingDigits\n\t\tif wordsFracFrom < wordsFrac {\n\t\t\tlim = digitsPerWord\n\t\t}\n\n\t\tfor trailingDigitsFrom < lim && dig2bytes[trailingDigitsFrom] == i {\n\t\t\ttrailingDigitsFrom++\n\t\t}\n\t\tx = (d.wordBuf[wordIdxFrom] / powers10[digitsPerWord-trailingDigitsFrom]) ^ mask\n\t\twriteWord(bin[binIdx:], x, i)\n\t\tbinIdx += i\n\t}\n\tif fracSize > fracSizeFrom {\n\t\tbinIdxEnd := originIntSize + originFracSize\n\t\tfor fracSize > fracSizeFrom && binIdx < binIdxEnd {\n\t\t\tfracSize--\n\t\t\tbin[binIdx] = byte(mask)\n\t\t\tbinIdx++\n\t\t}\n\t}\n\tbin[0] ^= 0x80\n\treturn bin, err\n}\n\n// ToHashKey removes the leading and trailing zeros and generates a hash key.\n// Two Decimals dec0 and dec1 with different fraction will generate the same hash keys if dec0.Compare(dec1) == 0.\nfunc (d *MyDecimal) ToHashKey() ([]byte, error) {\n\t_, digitsInt := d.removeLeadingZeros()\n\t_, digitsFrac := d.removeTrailingZeros()\n\tprec := digitsInt + digitsFrac\n\tif prec == 0 { // zeroDecimal\n\t\tprec = 1\n\t}\n\tbuf, err := d.ToBin(prec, digitsFrac)\n\tif err == ErrTruncated {\n\t\t// This err is caused by shorter digitsFrac;\n\t\t// After removing the trailing zeros from a Decimal,\n\t\t// so digitsFrac may be less than the real digitsFrac of the Decimal,\n\t\t// thus ErrTruncated may be raised, we can ignore it here.\n\t\terr = nil\n\t}\n\treturn buf, err\n}\n\n// PrecisionAndFrac returns the internal precision and frac number.\nfunc (d *MyDecimal) PrecisionAndFrac() (precision, frac int) {\n\tfrac = int(d.digitsFrac)\n\t_, digitsInt := d.removeLeadingZeros()\n\tprecision = digitsInt + frac\n\tif precision == 0 {\n\t\tprecision = 1\n\t}\n\treturn\n}\n\n// IsZero checks whether it's a zero decimal.\nfunc (d *MyDecimal) IsZero() bool {\n\tisZero := true\n\tfor _, val := range d.wordBuf {\n\t\tif val != 0 {\n\t\t\tisZero = false\n\t\t\tbreak\n\t\t}\n\t}\n\treturn isZero\n}\n\n// FromBin Restores decimal from its binary fixed-length representation.\nfunc (d *MyDecimal) FromBin(bin []byte, precision, frac int) (binSize int, err error) {\n\tif len(bin) == 0 {\n\t\t*d = zeroMyDecimal\n\t\treturn 0, ErrBadNumber\n\t}\n\tdigitsInt := precision - frac\n\twordsInt := digitsInt / digitsPerWord\n\tleadingDigits := digitsInt - wordsInt*digitsPerWord\n\twordsFrac := frac / digitsPerWord\n\ttrailingDigits := frac - wordsFrac*digitsPerWord\n\twordsIntTo := wordsInt\n\tif leadingDigits > 0 {\n\t\twordsIntTo++\n\t}\n\twordsFracTo := wordsFrac\n\tif trailingDigits > 0 {\n\t\twordsFracTo++\n\t}\n\n\tbinIdx := 0\n\tmask := int32(-1)\n\tif bin[binIdx]&0x80 > 0 {\n\t\tmask = 0\n\t}\n\tbinSize = DecimalBinSize(precision, frac)\n\tdCopy := make([]byte, 40)\n\tdCopy = dCopy[:binSize]\n\tcopy(dCopy, bin)\n\tdCopy[0] ^= 0x80\n\tbin = dCopy\n\toldWordsIntTo := wordsIntTo\n\twordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)\n\tif err != nil {\n\t\tif wordsIntTo < oldWordsIntTo {\n\t\t\tbinIdx += dig2bytes[leadingDigits] + (wordsInt-wordsIntTo)*wordSize\n\t\t} else {\n\t\t\ttrailingDigits = 0\n\t\t\twordsFrac = wordsFracTo\n\t\t}\n\t}\n\td.negative = mask != 0\n\td.digitsInt = int8(wordsInt*digitsPerWord + leadingDigits)\n\td.digitsFrac = int8(wordsFrac*digitsPerWord + trailingDigits)\n\n\twordIdx := 0\n\tif leadingDigits > 0 {\n\t\ti := dig2bytes[leadingDigits]\n\t\tx := readWord(bin[binIdx:], i)\n\t\tbinIdx += i\n\t\td.wordBuf[wordIdx] = x ^ mask\n\t\tif uint64(d.wordBuf[wordIdx]) >= uint64(powers10[leadingDigits+1]) {\n\t\t\t*d = zeroMyDecimal\n\t\t\treturn binSize, ErrBadNumber\n\t\t}\n\t\tif wordIdx > 0 || d.wordBuf[wordIdx] != 0 {\n\t\t\twordIdx++\n\t\t} else {\n\t\t\td.digitsInt -= int8(leadingDigits)\n\t\t}\n\t}\n\tfor stop := binIdx + wordsInt*wordSize; binIdx < stop; binIdx += wordSize {\n\t\td.wordBuf[wordIdx] = readWord(bin[binIdx:], 4) ^ mask\n\t\tif uint32(d.wordBuf[wordIdx]) > wordMax {\n\t\t\t*d = zeroMyDecimal\n\t\t\treturn binSize, ErrBadNumber\n\t\t}\n\t\tif wordIdx > 0 || d.wordBuf[wordIdx] != 0 {\n\t\t\twordIdx++\n\t\t} else {\n\t\t\td.digitsInt -= digitsPerWord\n\t\t}\n\t}\n\n\tfor stop := binIdx + wordsFrac*wordSize; binIdx < stop; binIdx += wordSize {\n\t\td.wordBuf[wordIdx] = readWord(bin[binIdx:], 4) ^ mask\n\t\tif uint32(d.wordBuf[wordIdx]) > wordMax {\n\t\t\t*d = zeroMyDecimal\n\t\t\treturn binSize, ErrBadNumber\n\t\t}\n\t\twordIdx++\n\t}\n\n\tif trailingDigits > 0 {\n\t\ti := dig2bytes[trailingDigits]\n\t\tx := readWord(bin[binIdx:], i)\n\t\td.wordBuf[wordIdx] = (x ^ mask) * powers10[digitsPerWord-trailingDigits]\n\t\tif uint32(d.wordBuf[wordIdx]) > wordMax {\n\t\t\t*d = zeroMyDecimal\n\t\t\treturn binSize, ErrBadNumber\n\t\t}\n\t}\n\n\tif d.digitsInt == 0 && d.digitsFrac == 0 {\n\t\t*d = zeroMyDecimal\n\t}\n\td.resultFrac = int8(frac)\n\treturn binSize, err\n}\n\n// DecimalBinSize returns the size of array to hold a binary representation of a decimal.\nfunc DecimalBinSize(precision, frac int) int {\n\tdigitsInt := precision - frac\n\twordsInt := digitsInt / digitsPerWord\n\twordsFrac := frac / digitsPerWord\n\txInt := digitsInt - wordsInt*digitsPerWord\n\txFrac := frac - wordsFrac*digitsPerWord\n\treturn wordsInt*wordSize + dig2bytes[xInt] + wordsFrac*wordSize + dig2bytes[xFrac]\n}\n\nfunc readWord(b []byte, size int) int32 {\n\tvar x int32\n\tswitch size {\n\tcase 1:\n\t\tx = int32(int8(b[0]))\n\tcase 2:\n\t\tx = int32(int8(b[0]))<<8 + int32(b[1])\n\tcase 3:\n\t\tif b[0]&128 > 0 {\n\t\t\tx = int32(uint32(255)<<24 | uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))\n\t\t} else {\n\t\t\tx = int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))\n\t\t}\n\tcase 4:\n\t\tx = int32(b[3]) + int32(b[2])<<8 + int32(b[1])<<16 + int32(int8(b[0]))<<24\n\t}\n\treturn x\n}\n\nfunc writeWord(b []byte, word int32, size int) {\n\tv := uint32(word)\n\tswitch size {\n\tcase 1:\n\t\tb[0] = byte(word)\n\tcase 2:\n\t\tb[0] = byte(v >> 8)\n\t\tb[1] = byte(v)\n\tcase 3:\n\t\tb[0] = byte(v >> 16)\n\t\tb[1] = byte(v >> 8)\n\t\tb[2] = byte(v)\n\tcase 4:\n\t\tb[0] = byte(v >> 24)\n\t\tb[1] = byte(v >> 16)\n\t\tb[2] = byte(v >> 8)\n\t\tb[3] = byte(v)\n\t}\n}\n\n// Compare compares one decimal to another, returns -1/0/1.\nfunc (d *MyDecimal) Compare(to *MyDecimal) int {\n\tif d.negative == to.negative {\n\t\tcmp, err := doSub(d, to, nil)\n\t\tterror.Log(errors.Trace(err))\n\t\treturn cmp\n\t}\n\tif d.negative {\n\t\treturn -1\n\t}\n\treturn 1\n}\n\n// DecimalNeg reverses decimal's sign.\nfunc DecimalNeg(from *MyDecimal) *MyDecimal {\n\tto := *from\n\tif from.IsZero() {\n\t\treturn &to\n\t}\n\tto.negative = !from.negative\n\treturn &to\n}\n\n// DecimalAdd adds two decimals, sets the result to 'to'.\n// Note: DO NOT use `from1` or `from2` as `to` since the metadata\n// of `to` may be changed during evaluating.\nfunc DecimalAdd(from1, from2, to *MyDecimal) error {\n\tfrom1, from2, to = validateArgs(from1, from2, to)\n\tto.resultFrac = myMaxInt8(from1.resultFrac, from2.resultFrac)\n\tif from1.negative == from2.negative {\n\t\treturn doAdd(from1, from2, to)\n\t}\n\t_, err := doSub(from1, from2, to)\n\treturn err\n}\n\n// DecimalSub subs one decimal from another, sets the result to 'to'.\nfunc DecimalSub(from1, from2, to *MyDecimal) error {\n\tfrom1, from2, to = validateArgs(from1, from2, to)\n\tto.resultFrac = myMaxInt8(from1.resultFrac, from2.resultFrac)\n\tif from1.negative == from2.negative {\n\t\t_, err := doSub(from1, from2, to)\n\t\treturn err\n\t}\n\treturn doAdd(from1, from2, to)\n}\n\nfunc validateArgs(f1, f2, to *MyDecimal) (*MyDecimal, *MyDecimal, *MyDecimal) {\n\tif to == nil {\n\t\treturn f1, f2, to\n\t}\n\tif f1 == to {\n\t\ttmp := *f1\n\t\tf1 = &tmp\n\t}\n\tif f2 == to {\n\t\ttmp := *f2\n\t\tf2 = &tmp\n\t}\n\tto.digitsFrac = 0\n\tto.digitsInt = 0\n\tto.resultFrac = 0\n\tto.negative = false\n\tfor i := range to.wordBuf {\n\t\tto.wordBuf[i] = 0\n\t}\n\treturn f1, f2, to\n}\n\nfunc doSub(from1, from2, to *MyDecimal) (cmp int, err error) {\n\tvar (\n\t\twordsInt1   = digitsToWords(int(from1.digitsInt))\n\t\twordsFrac1  = digitsToWords(int(from1.digitsFrac))\n\t\twordsInt2   = digitsToWords(int(from2.digitsInt))\n\t\twordsFrac2  = digitsToWords(int(from2.digitsFrac))\n\t\twordsFracTo = myMax(wordsFrac1, wordsFrac2)\n\n\t\tstart1 = 0\n\t\tstop1  = wordsInt1\n\t\tidx1   = 0\n\t\tstart2 = 0\n\t\tstop2  = wordsInt2\n\t\tidx2   = 0\n\t)\n\tif from1.wordBuf[idx1] == 0 {\n\t\tfor idx1 < stop1 && from1.wordBuf[idx1] == 0 {\n\t\t\tidx1++\n\t\t}\n\t\tstart1 = idx1\n\t\twordsInt1 = stop1 - idx1\n\t}\n\tif from2.wordBuf[idx2] == 0 {\n\t\tfor idx2 < stop2 && from2.wordBuf[idx2] == 0 {\n\t\t\tidx2++\n\t\t}\n\t\tstart2 = idx2\n\t\twordsInt2 = stop2 - idx2\n\t}\n\n\tvar carry int32\n\tif wordsInt2 > wordsInt1 {\n\t\tcarry = 1\n\t} else if wordsInt2 == wordsInt1 {\n\t\tend1 := stop1 + wordsFrac1 - 1\n\t\tend2 := stop2 + wordsFrac2 - 1\n\t\tfor idx1 <= end1 && from1.wordBuf[end1] == 0 {\n\t\t\tend1--\n\t\t}\n\t\tfor idx2 <= end2 && from2.wordBuf[end2] == 0 {\n\t\t\tend2--\n\t\t}\n\t\twordsFrac1 = end1 - stop1 + 1\n\t\twordsFrac2 = end2 - stop2 + 1\n\t\tfor idx1 <= end1 && idx2 <= end2 && from1.wordBuf[idx1] == from2.wordBuf[idx2] {\n\t\t\tidx1++\n\t\t\tidx2++\n\t\t}\n\t\tif idx1 <= end1 {\n\t\t\tif idx2 <= end2 && from2.wordBuf[idx2] > from1.wordBuf[idx1] {\n\t\t\t\tcarry = 1\n\t\t\t} else {\n\t\t\t\tcarry = 0\n\t\t\t}\n\t\t} else {\n\t\t\tif idx2 <= end2 {\n\t\t\t\tcarry = 1\n\t\t\t} else {\n\t\t\t\tif to == nil {\n\t\t\t\t\treturn 0, nil\n\t\t\t\t}\n\t\t\t\t*to = zeroMyDecimalWithFrac(to.resultFrac)\n\t\t\t\treturn 0, nil\n\t\t\t}\n\t\t}\n\t}\n\n\tif to == nil {\n\t\tif carry > 0 == from1.negative { // from2 is negative too.\n\t\t\treturn 1, nil\n\t\t}\n\t\treturn -1, nil\n\t}\n\n\tto.negative = from1.negative\n\n\t/* ensure that always idx1 > idx2 (and wordsInt1 >= wordsInt2) */\n\tif carry > 0 {\n\t\tfrom1, from2 = from2, from1\n\t\tstart1, start2 = start2, start1\n\t\twordsInt1, wordsInt2 = wordsInt2, wordsInt1\n\t\twordsFrac1, wordsFrac2 = wordsFrac2, wordsFrac1\n\t\tto.negative = !to.negative\n\t}\n\n\twordsInt1, wordsFracTo, err = fixWordCntError(wordsInt1, wordsFracTo)\n\tidxTo := wordsInt1 + wordsFracTo\n\tto.digitsFrac = from1.digitsFrac\n\tif to.digitsFrac < from2.digitsFrac {\n\t\tto.digitsFrac = from2.digitsFrac\n\t}\n\tto.digitsInt = int8(wordsInt1 * digitsPerWord)\n\tif err != nil {\n\t\tif to.digitsFrac > int8(wordsFracTo*digitsPerWord) {\n\t\t\tto.digitsFrac = int8(wordsFracTo * digitsPerWord)\n\t\t}\n\t\tif wordsFrac1 > wordsFracTo {\n\t\t\twordsFrac1 = wordsFracTo\n\t\t}\n\t\tif wordsFrac2 > wordsFracTo {\n\t\t\twordsFrac2 = wordsFracTo\n\t\t}\n\t\tif wordsInt2 > wordsInt1 {\n\t\t\twordsInt2 = wordsInt1\n\t\t}\n\t}\n\tcarry = 0\n\n\t/* part 1 - max(frac) ... min (frac) */\n\tif wordsFrac1 > wordsFrac2 {\n\t\tidx1 = start1 + wordsInt1 + wordsFrac1\n\t\tstop1 = start1 + wordsInt1 + wordsFrac2\n\t\tidx2 = start2 + wordsInt2 + wordsFrac2\n\t\tfor wordsFracTo > wordsFrac1 {\n\t\t\twordsFracTo--\n\t\t\tidxTo--\n\t\t\tto.wordBuf[idxTo] = 0\n\t\t}\n\t\tfor idx1 > stop1 {\n\t\t\tidxTo--\n\t\t\tidx1--\n\t\t\tto.wordBuf[idxTo] = from1.wordBuf[idx1]\n\t\t}\n\t} else {\n\t\tidx1 = start1 + wordsInt1 + wordsFrac1\n\t\tidx2 = start2 + wordsInt2 + wordsFrac2\n\t\tstop2 = start2 + wordsInt2 + wordsFrac1\n\t\tfor wordsFracTo > wordsFrac2 {\n\t\t\twordsFracTo--\n\t\t\tidxTo--\n\t\t\tto.wordBuf[idxTo] = 0\n\t\t}\n\t\tfor idx2 > stop2 {\n\t\t\tidxTo--\n\t\t\tidx2--\n\t\t\tto.wordBuf[idxTo], carry = sub(0, from2.wordBuf[idx2], carry)\n\t\t}\n\t}\n\n\t/* part 2 - min(frac) ... wordsInt2 */\n\tfor idx2 > start2 {\n\t\tidxTo--\n\t\tidx1--\n\t\tidx2--\n\t\tto.wordBuf[idxTo], carry = sub(from1.wordBuf[idx1], from2.wordBuf[idx2], carry)\n\t}\n\n\t/* part 3 - wordsInt2 ... wordsInt1 */\n\tfor carry > 0 && idx1 > start1 {\n\t\tidxTo--\n\t\tidx1--\n\t\tto.wordBuf[idxTo], carry = sub(from1.wordBuf[idx1], 0, carry)\n\t}\n\tfor idx1 > start1 {\n\t\tidxTo--\n\t\tidx1--\n\t\tto.wordBuf[idxTo] = from1.wordBuf[idx1]\n\t}\n\tfor idxTo > 0 {\n\t\tidxTo--\n\t\tto.wordBuf[idxTo] = 0\n\t}\n\treturn 0, err\n}\n\nfunc doAdd(from1, from2, to *MyDecimal) error {\n\tvar (\n\t\terr         error\n\t\twordsInt1   = digitsToWords(int(from1.digitsInt))\n\t\twordsFrac1  = digitsToWords(int(from1.digitsFrac))\n\t\twordsInt2   = digitsToWords(int(from2.digitsInt))\n\t\twordsFrac2  = digitsToWords(int(from2.digitsFrac))\n\t\twordsIntTo  = myMax(wordsInt1, wordsInt2)\n\t\twordsFracTo = myMax(wordsFrac1, wordsFrac2)\n\t)\n\n\tvar x int32\n\tif wordsInt1 > wordsInt2 {\n\t\tx = from1.wordBuf[0]\n\t} else if wordsInt2 > wordsInt1 {\n\t\tx = from2.wordBuf[0]\n\t} else {\n\t\tx = from1.wordBuf[0] + from2.wordBuf[0]\n\t}\n\tif x > wordMax-1 { /* yes, there is */\n\t\twordsIntTo++\n\t\tto.wordBuf[0] = 0 /* safety */\n\t}\n\n\twordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)\n\tif err == ErrOverflow {\n\t\tmaxDecimal(wordBufLen*digitsPerWord, 0, to)\n\t\treturn err\n\t}\n\tidxTo := wordsIntTo + wordsFracTo\n\tto.negative = from1.negative\n\tto.digitsInt = int8(wordsIntTo * digitsPerWord)\n\tto.digitsFrac = myMaxInt8(from1.digitsFrac, from2.digitsFrac)\n\n\tif err != nil {\n\t\tif to.digitsFrac > int8(wordsFracTo*digitsPerWord) {\n\t\t\tto.digitsFrac = int8(wordsFracTo * digitsPerWord)\n\t\t}\n\t\tif wordsFrac1 > wordsFracTo {\n\t\t\twordsFrac1 = wordsFracTo\n\t\t}\n\t\tif wordsFrac2 > wordsFracTo {\n\t\t\twordsFrac2 = wordsFracTo\n\t\t}\n\t\tif wordsInt1 > wordsIntTo {\n\t\t\twordsInt1 = wordsIntTo\n\t\t}\n\t\tif wordsInt2 > wordsIntTo {\n\t\t\twordsInt2 = wordsIntTo\n\t\t}\n\t}\n\tvar dec1, dec2 = from1, from2\n\tvar idx1, idx2, stop, stop2 int\n\t/* part 1 - max(frac) ... min (frac) */\n\tif wordsFrac1 > wordsFrac2 {\n\t\tidx1 = wordsInt1 + wordsFrac1\n\t\tstop = wordsInt1 + wordsFrac2\n\t\tidx2 = wordsInt2 + wordsFrac2\n\t\tif wordsInt1 > wordsInt2 {\n\t\t\tstop2 = wordsInt1 - wordsInt2\n\t\t}\n\t} else {\n\t\tidx1 = wordsInt2 + wordsFrac2\n\t\tstop = wordsInt2 + wordsFrac1\n\t\tidx2 = wordsInt1 + wordsFrac1\n\t\tif wordsInt2 > wordsInt1 {\n\t\t\tstop2 = wordsInt2 - wordsInt1\n\t\t}\n\t\tdec1, dec2 = from2, from1\n\t}\n\tfor idx1 > stop {\n\t\tidxTo--\n\t\tidx1--\n\t\tto.wordBuf[idxTo] = dec1.wordBuf[idx1]\n\t}\n\n\t/* part 2 - min(frac) ... min(digitsInt) */\n\tcarry := int32(0)\n\tfor idx1 > stop2 {\n\t\tidx1--\n\t\tidx2--\n\t\tidxTo--\n\t\tto.wordBuf[idxTo], carry = add(dec1.wordBuf[idx1], dec2.wordBuf[idx2], carry)\n\t}\n\n\t/* part 3 - min(digitsInt) ... max(digitsInt) */\n\tstop = 0\n\tif wordsInt1 > wordsInt2 {\n\t\tidx1 = wordsInt1 - wordsInt2\n\t\tdec1 = from1\n\t} else {\n\t\tidx1 = wordsInt2 - wordsInt1\n\t\tdec1 = from2\n\t}\n\tfor idx1 > stop {\n\t\tidxTo--\n\t\tidx1--\n\t\tto.wordBuf[idxTo], carry = add(dec1.wordBuf[idx1], 0, carry)\n\t}\n\tif carry > 0 {\n\t\tidxTo--\n\t\tto.wordBuf[idxTo] = 1\n\t}\n\treturn err\n}\n\nfunc maxDecimal(precision, frac int, to *MyDecimal) {\n\tdigitsInt := precision - frac\n\tto.negative = false\n\tto.digitsInt = int8(digitsInt)\n\tidx := 0\n\tif digitsInt > 0 {\n\t\tfirstWordDigits := digitsInt % digitsPerWord\n\t\tif firstWordDigits > 0 {\n\t\t\tto.wordBuf[idx] = powers10[firstWordDigits] - 1 /* get 9 99 999 ... */\n\t\t\tidx++\n\t\t}\n\t\tfor digitsInt /= digitsPerWord; digitsInt > 0; digitsInt-- {\n\t\t\tto.wordBuf[idx] = wordMax\n\t\t\tidx++\n\t\t}\n\t}\n\tto.digitsFrac = int8(frac)\n\tif frac > 0 {\n\t\tlastDigits := frac % digitsPerWord\n\t\tfor frac /= digitsPerWord; frac > 0; frac-- {\n\t\t\tto.wordBuf[idx] = wordMax\n\t\t\tidx++\n\t\t}\n\t\tif lastDigits > 0 {\n\t\t\tto.wordBuf[idx] = fracMax[lastDigits-1]\n\t\t}\n\t}\n}\n\n/*\nDecimalMul multiplies two decimals.\n\n\t    from1, from2 - factors\n\t    to      - product\n\n\tRETURN VALUE\n\t  E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW;\n\n\tNOTES\n\t  in this implementation, with wordSize=4 we have digitsPerWord=9,\n\t  and 63-digit number will take only 7 words (basically a 7-digit\n\t  \"base 999999999\" number).  Thus there's no need in fast multiplication\n\t  algorithms, 7-digit numbers can be multiplied with a naive O(n*n)\n\t  method.\n\n\t  XXX if this library is to be used with huge numbers of thousands of\n\t  digits, fast multiplication must be implemented.\n*/\nfunc DecimalMul(from1, from2, to *MyDecimal) error {\n\tfrom1, from2, to = validateArgs(from1, from2, to)\n\tvar (\n\t\terr         error\n\t\twordsInt1   = digitsToWords(int(from1.digitsInt))\n\t\twordsFrac1  = digitsToWords(int(from1.digitsFrac))\n\t\twordsInt2   = digitsToWords(int(from2.digitsInt))\n\t\twordsFrac2  = digitsToWords(int(from2.digitsFrac))\n\t\twordsIntTo  = digitsToWords(int(from1.digitsInt) + int(from2.digitsInt))\n\t\twordsFracTo = wordsFrac1 + wordsFrac2\n\t\tidx1        = wordsInt1\n\t\tidx2        = wordsInt2\n\t\tidxTo       int\n\t\ttmp1        = wordsIntTo\n\t\ttmp2        = wordsFracTo\n\t)\n\tto.resultFrac = myMinInt8(from1.resultFrac+from2.resultFrac, mysql.MaxDecimalScale)\n\twordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)\n\tto.negative = from1.negative != from2.negative\n\tto.digitsFrac = from1.digitsFrac + from2.digitsFrac\n\tif to.digitsFrac > notFixedDec {\n\t\tto.digitsFrac = notFixedDec\n\t}\n\tto.digitsInt = int8(wordsIntTo * digitsPerWord)\n\tif err == ErrOverflow {\n\t\treturn err\n\t}\n\tif err != nil {\n\t\tif to.digitsFrac > int8(wordsFracTo*digitsPerWord) {\n\t\t\tto.digitsFrac = int8(wordsFracTo * digitsPerWord)\n\t\t}\n\t\tif to.digitsInt > int8(wordsIntTo*digitsPerWord) {\n\t\t\tto.digitsInt = int8(wordsIntTo * digitsPerWord)\n\t\t}\n\t\tif tmp1 > wordsIntTo {\n\t\t\ttmp1 -= wordsIntTo\n\t\t\ttmp2 = tmp1 >> 1\n\t\t\twordsInt2 -= tmp1 - tmp2\n\t\t\twordsFrac1 = 0\n\t\t\twordsFrac2 = 0\n\t\t} else {\n\t\t\ttmp2 -= wordsFracTo\n\t\t\ttmp1 = tmp2 >> 1\n\t\t\tif wordsFrac1 <= wordsFrac2 {\n\t\t\t\twordsFrac1 -= tmp1\n\t\t\t\twordsFrac2 -= tmp2 - tmp1\n\t\t\t} else {\n\t\t\t\twordsFrac2 -= tmp1\n\t\t\t\twordsFrac1 -= tmp2 - tmp1\n\t\t\t}\n\t\t}\n\t}\n\tstartTo := wordsIntTo + wordsFracTo - 1\n\tstart2 := idx2 + wordsFrac2 - 1\n\tstop1 := idx1 - wordsInt1\n\tstop2 := idx2 - wordsInt2\n\tto.wordBuf = zeroMyDecimal.wordBuf\n\n\tfor idx1 += wordsFrac1 - 1; idx1 >= stop1; idx1-- {\n\t\tcarry := int32(0)\n\t\tidxTo = startTo\n\t\tidx2 = start2\n\t\tfor idx2 >= stop2 {\n\t\t\tvar hi, lo int32\n\t\t\tp := int64(from1.wordBuf[idx1]) * int64(from2.wordBuf[idx2])\n\t\t\thi = int32(p / wordBase)\n\t\t\tlo = int32(p - int64(hi)*wordBase)\n\t\t\tto.wordBuf[idxTo], carry = add2(to.wordBuf[idxTo], lo, carry)\n\t\t\tcarry += hi\n\t\t\tidx2--\n\t\t\tidxTo--\n\t\t}\n\t\tif carry > 0 {\n\t\t\tif idxTo < 0 {\n\t\t\t\treturn ErrOverflow\n\t\t\t}\n\t\t\tto.wordBuf[idxTo], carry = add2(to.wordBuf[idxTo], 0, carry)\n\t\t}\n\t\tfor idxTo--; carry > 0; idxTo-- {\n\t\t\tif idxTo < 0 {\n\t\t\t\treturn ErrOverflow\n\t\t\t}\n\t\t\tto.wordBuf[idxTo], carry = add(to.wordBuf[idxTo], 0, carry)\n\t\t}\n\t\tstartTo--\n\t}\n\n\t/* Now we have to check for -0.000 case */\n\tif to.negative {\n\t\tidx := 0\n\t\tend := wordsIntTo + wordsFracTo\n\t\tfor {\n\t\t\tif to.wordBuf[idx] != 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tidx++\n\t\t\t/* We got decimal zero */\n\t\t\tif idx == end {\n\t\t\t\t*to = zeroMyDecimalWithFrac(to.resultFrac)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tidxTo = 0\n\tdToMove := wordsIntTo + digitsToWords(int(to.digitsFrac))\n\tfor to.wordBuf[idxTo] == 0 && to.digitsInt > digitsPerWord {\n\t\tidxTo++\n\t\tto.digitsInt -= digitsPerWord\n\t\tdToMove--\n\t}\n\tif idxTo > 0 {\n\t\tcurIdx := 0\n\t\tfor dToMove > 0 {\n\t\t\tto.wordBuf[curIdx] = to.wordBuf[idxTo]\n\t\t\tcurIdx++\n\t\t\tidxTo++\n\t\t\tdToMove--\n\t\t}\n\t}\n\treturn err\n}\n\n// DecimalDiv does division of two decimals.\n//\n// from1    - dividend\n// from2    - divisor\n// to       - quotient\n// fracIncr - increment of fraction\nfunc DecimalDiv(from1, from2, to *MyDecimal, fracIncr int) error {\n\tfrom1, from2, to = validateArgs(from1, from2, to)\n\tto.resultFrac = myMinInt8(from1.resultFrac+int8(fracIncr), mysql.MaxDecimalScale)\n\treturn doDivMod(from1, from2, to, nil, fracIncr)\n}\n\n/*\nDecimalMod does modulus of two decimals.\n\n\t    from1   - dividend\n\t    from2   - divisor\n\t    to      - modulus\n\n\tRETURN VALUE\n\t  E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_DIV_ZERO;\n\n\tNOTES\n\t  see do_div_mod()\n\n\tDESCRIPTION\n\t  the modulus R in    R = M mod N\n\n\t is defined as\n\n\t   0 <= |R| < |M|\n\t   sign R == sign M\n\t   R = M - k*N, where k is integer\n\n\t thus, there's no requirement for M or N to be integers\n*/\nfunc DecimalMod(from1, from2, to *MyDecimal) error {\n\tfrom1, from2, to = validateArgs(from1, from2, to)\n\tto.resultFrac = myMaxInt8(from1.resultFrac, from2.resultFrac)\n\treturn doDivMod(from1, from2, nil, to, 0)\n}\n\nfunc doDivMod(from1, from2, to, mod *MyDecimal, fracIncr int) error {\n\tvar (\n\t\tfrac1 = digitsToWords(int(from1.digitsFrac)) * digitsPerWord\n\t\tprec1 = int(from1.digitsInt) + frac1\n\t\tfrac2 = digitsToWords(int(from2.digitsFrac)) * digitsPerWord\n\t\tprec2 = int(from2.digitsInt) + frac2\n\t)\n\tif mod != nil {\n\t\tto = mod\n\t}\n\n\t/* removing all the leading zeros */\n\ti := ((prec2 - 1) % digitsPerWord) + 1\n\tidx2 := 0\n\tfor prec2 > 0 && from2.wordBuf[idx2] == 0 {\n\t\tprec2 -= i\n\t\ti = digitsPerWord\n\t\tidx2++\n\t}\n\tif prec2 <= 0 {\n\t\t/* short-circuit everything: from2 == 0 */\n\t\treturn ErrDivByZero\n\t}\n\n\tprec2 -= countLeadingZeroes((prec2-1)%digitsPerWord, from2.wordBuf[idx2])\n\ti = ((prec1 - 1) % digitsPerWord) + 1\n\tidx1 := 0\n\tfor prec1 > 0 && from1.wordBuf[idx1] == 0 {\n\t\tprec1 -= i\n\t\ti = digitsPerWord\n\t\tidx1++\n\t}\n\tif prec1 <= 0 {\n\t\t/* short-circuit everything: from1 == 0 */\n\t\t*to = zeroMyDecimalWithFrac(to.resultFrac)\n\t\treturn nil\n\t}\n\tprec1 -= countLeadingZeroes((prec1-1)%digitsPerWord, from1.wordBuf[idx1])\n\n\t/* let's fix fracIncr, taking into account frac1,frac2 increase */\n\tfracIncr -= frac1 - int(from1.digitsFrac) + frac2 - int(from2.digitsFrac)\n\tif fracIncr < 0 {\n\t\tfracIncr = 0\n\t}\n\n\tdigitsIntTo := (prec1 - frac1) - (prec2 - frac2)\n\tif from1.wordBuf[idx1] >= from2.wordBuf[idx2] {\n\t\tdigitsIntTo++\n\t}\n\tvar wordsIntTo int\n\tif digitsIntTo < 0 {\n\t\tdigitsIntTo /= digitsPerWord\n\t\twordsIntTo = 0\n\t} else {\n\t\twordsIntTo = digitsToWords(digitsIntTo)\n\t}\n\tvar wordsFracTo int\n\tvar err error\n\tif mod != nil {\n\t\t// we're calculating N1 % N2.\n\t\t// The result will have\n\t\t// digitsFrac=max(frac1, frac2), as for subtraction\n\t\t// digitsInt=from2.digitsInt\n\t\tto.negative = from1.negative\n\t\tto.digitsFrac = myMaxInt8(from1.digitsFrac, from2.digitsFrac)\n\t} else {\n\t\twordsFracTo = digitsToWords(frac1 + frac2 + fracIncr)\n\t\twordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)\n\t\tto.negative = from1.negative != from2.negative\n\t\tto.digitsInt = int8(wordsIntTo * digitsPerWord)\n\t\tto.digitsFrac = int8(wordsFracTo * digitsPerWord)\n\t}\n\tidxTo := 0\n\tstopTo := wordsIntTo + wordsFracTo\n\tif mod == nil {\n\t\tfor digitsIntTo < 0 && idxTo < wordBufLen {\n\t\t\tto.wordBuf[idxTo] = 0\n\t\t\tidxTo++\n\t\t\tdigitsIntTo++\n\t\t}\n\t}\n\ti = digitsToWords(prec1)\n\tlen1 := i + digitsToWords(2*frac2+fracIncr+1) + 1\n\tif len1 < 3 {\n\t\tlen1 = 3\n\t}\n\n\ttmp1 := make([]int32, len1)\n\tcopy(tmp1, from1.wordBuf[idx1:idx1+i])\n\n\tstart1 := 0\n\tvar stop1 int\n\tstart2 := idx2\n\tstop2 := idx2 + digitsToWords(prec2) - 1\n\n\t/* removing end zeroes */\n\tfor from2.wordBuf[stop2] == 0 && stop2 >= start2 {\n\t\tstop2--\n\t}\n\tlen2 := stop2 - start2\n\tstop2++\n\n\t/*\n\t   calculating norm2 (normalized from2.wordBuf[start2]) - we need from2.wordBuf[start2] to be large\n\t   (at least > DIG_BASE/2), but unlike Knuth's Alg. D we don't want to\n\t   normalize input numbers (as we don't make a copy of the divisor).\n\t   Thus we normalize first dec1 of buf2 only, and we'll normalize tmp1[start1]\n\t   on the fly for the purpose of guesstimation only.\n\t   It's also faster, as we're saving on normalization of from2.\n\t*/\n\tnormFactor := wordBase / int64(from2.wordBuf[start2]+1)\n\tnorm2 := int32(normFactor * int64(from2.wordBuf[start2]))\n\tif len2 > 0 {\n\t\tnorm2 += int32(normFactor * int64(from2.wordBuf[start2+1]) / wordBase)\n\t}\n\tdcarry := int32(0)\n\tif tmp1[start1] < from2.wordBuf[start2] {\n\t\tdcarry = tmp1[start1]\n\t\tstart1++\n\t}\n\n\t// main loop\n\tvar guess int64\n\tfor ; idxTo < stopTo; idxTo++ {\n\t\t/* short-circuit, if possible */\n\t\tif dcarry == 0 && tmp1[start1] < from2.wordBuf[start2] {\n\t\t\tguess = 0\n\t\t} else {\n\t\t\t/* D3: make a guess */\n\t\t\tx := int64(tmp1[start1]) + int64(dcarry)*wordBase\n\t\t\ty := int64(tmp1[start1+1])\n\t\t\tguess = (normFactor*x + normFactor*y/wordBase) / int64(norm2)\n\t\t\tif guess >= wordBase {\n\t\t\t\tguess = wordBase - 1\n\t\t\t}\n\n\t\t\tif len2 > 0 {\n\t\t\t\t/* remove normalization */\n\t\t\t\tif int64(from2.wordBuf[start2+1])*guess > (x-guess*int64(from2.wordBuf[start2]))*wordBase+y {\n\t\t\t\t\tguess--\n\t\t\t\t}\n\t\t\t\tif int64(from2.wordBuf[start2+1])*guess > (x-guess*int64(from2.wordBuf[start2]))*wordBase+y {\n\t\t\t\t\tguess--\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* D4: multiply and subtract */\n\t\t\tidx2 = stop2\n\t\t\tidx1 = start1 + len2\n\t\t\tvar carry int32\n\t\t\tfor carry = 0; idx2 > start2; idx1-- {\n\t\t\t\tvar hi, lo int32\n\t\t\t\tidx2--\n\t\t\t\tx = guess * int64(from2.wordBuf[idx2])\n\t\t\t\thi = int32(x / wordBase)\n\t\t\t\tlo = int32(x - int64(hi)*wordBase)\n\t\t\t\ttmp1[idx1], carry = sub2(tmp1[idx1], lo, carry)\n\t\t\t\tcarry += hi\n\t\t\t}\n\t\t\tif dcarry < carry {\n\t\t\t\tcarry = 1\n\t\t\t} else {\n\t\t\t\tcarry = 0\n\t\t\t}\n\n\t\t\t/* D5: check the remainder */\n\t\t\tif carry > 0 {\n\t\t\t\t/* D6: correct the guess */\n\t\t\t\tguess--\n\t\t\t\tidx2 = stop2\n\t\t\t\tidx1 = start1 + len2\n\t\t\t\tfor carry = 0; idx2 > start2; idx1-- {\n\t\t\t\t\tidx2--\n\t\t\t\t\ttmp1[idx1], carry = add(tmp1[idx1], from2.wordBuf[idx2], carry)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif mod == nil {\n\t\t\tto.wordBuf[idxTo] = int32(guess)\n\t\t}\n\t\tdcarry = tmp1[start1]\n\t\tstart1++\n\t}\n\tif mod != nil {\n\t\t/*\n\t\t   now the result is in tmp1, it has\n\t\t   digitsInt=prec1-frac1\n\t\t   digitsFrac=max(frac1, frac2)\n\t\t*/\n\t\tif dcarry != 0 {\n\t\t\tstart1--\n\t\t\ttmp1[start1] = dcarry\n\t\t}\n\t\tidxTo = 0\n\n\t\tdigitsIntTo = prec1 - frac1 - start1*digitsPerWord\n\t\tif digitsIntTo < 0 {\n\t\t\t/* If leading zeroes in the fractional part were earlier stripped */\n\t\t\twordsIntTo = digitsIntTo / digitsPerWord\n\t\t} else {\n\t\t\twordsIntTo = digitsToWords(digitsIntTo)\n\t\t}\n\n\t\twordsFracTo = digitsToWords(int(to.digitsFrac))\n\t\terr = nil\n\t\tif wordsIntTo == 0 && wordsFracTo == 0 {\n\t\t\t*to = zeroMyDecimal\n\t\t\treturn err\n\t\t}\n\t\tif wordsIntTo <= 0 {\n\t\t\tif -wordsIntTo >= wordBufLen {\n\t\t\t\t*to = zeroMyDecimal\n\t\t\t\treturn ErrTruncated\n\t\t\t}\n\t\t\tstop1 = start1 + wordsIntTo + wordsFracTo\n\t\t\twordsFracTo += wordsIntTo\n\t\t\tto.digitsInt = 0\n\t\t\tfor wordsIntTo < 0 {\n\t\t\t\tto.wordBuf[idxTo] = 0\n\t\t\t\tidxTo++\n\t\t\t\twordsIntTo++\n\t\t\t}\n\t\t} else {\n\t\t\tif wordsIntTo > wordBufLen {\n\t\t\t\tto.digitsInt = int8(digitsPerWord * wordBufLen)\n\t\t\t\tto.digitsFrac = 0\n\t\t\t\treturn ErrOverflow\n\t\t\t}\n\t\t\tstop1 = start1 + wordsIntTo + wordsFracTo\n\t\t\tto.digitsInt = int8(myMin(wordsIntTo*digitsPerWord, int(from2.digitsInt)))\n\t\t}\n\t\tif wordsIntTo+wordsFracTo > wordBufLen {\n\t\t\tstop1 -= wordsIntTo + wordsFracTo - wordBufLen\n\t\t\twordsFracTo = wordBufLen - wordsIntTo\n\t\t\tto.digitsFrac = int8(wordsFracTo * digitsPerWord)\n\t\t\terr = ErrTruncated\n\t\t}\n\t\tfor start1 < stop1 {\n\t\t\tto.wordBuf[idxTo] = tmp1[start1]\n\t\t\tidxTo++\n\t\t\tstart1++\n\t\t}\n\t}\n\tidxTo, digitsIntTo = to.removeLeadingZeros()\n\tto.digitsInt = int8(digitsIntTo)\n\tif idxTo != 0 {\n\t\tcopy(to.wordBuf[:], to.wordBuf[idxTo:])\n\t}\n\treturn err\n}\n\n// DecimalPeak returns the length of the encoded decimal.\nfunc DecimalPeak(b []byte) (int, error) {\n\tif len(b) < 3 {\n\t\treturn 0, ErrBadNumber\n\t}\n\tprecision := int(b[0])\n\tfrac := int(b[1])\n\treturn DecimalBinSize(precision, frac) + 2, nil\n}\n\n// NewDecFromInt creates a MyDecimal from int.\nfunc NewDecFromInt(i int64) *MyDecimal {\n\treturn new(MyDecimal).FromInt(i)\n}\n\n// NewDecFromUint creates a MyDecimal from uint.\nfunc NewDecFromUint(i uint64) *MyDecimal {\n\treturn new(MyDecimal).FromUint(i)\n}\n\n// NewDecFromFloatForTest creates a MyDecimal from float, as it returns no error, it should only be used in test.\nfunc NewDecFromFloatForTest(f float64) *MyDecimal {\n\tdec := new(MyDecimal)\n\terr := dec.FromFloat64(f)\n\tterror.Log(errors.Trace(err))\n\treturn dec\n}\n\n// NewDecFromStringForTest creates a MyDecimal from string, as it returns no error, it should only be used in test.\nfunc NewDecFromStringForTest(s string) *MyDecimal {\n\tdec := new(MyDecimal)\n\terr := dec.FromString([]byte(s))\n\tterror.Log(errors.Trace(err))\n\treturn dec\n}\n\n// NewMaxOrMinDec returns the max or min value decimal for given precision and fraction.\nfunc NewMaxOrMinDec(negative bool, prec, frac int) *MyDecimal {\n\tstr := make([]byte, prec+2)\n\tfor i := 0; i < len(str); i++ {\n\t\tstr[i] = '9'\n\t}\n\tif negative {\n\t\tstr[0] = '-'\n\t} else {\n\t\tstr[0] = '+'\n\t}\n\tstr[1+prec-frac] = '.'\n\tdec := new(MyDecimal)\n\terr := dec.FromString(str)\n\tterror.Log(errors.Trace(err))\n\treturn dec\n}\n"
  },
  {
    "path": "pkg/types/mytime.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\tgotime \"time\"\n\n\t\"fmt\"\n\n\t\"github.com/pingcap/errors\"\n)\n\n// MysqlTime is the internal struct type for Time.\n// The order of the attributes is refined to reduce the memory overhead\n// considering memory alignment.\ntype MysqlTime struct {\n\t// When it's type is Time, HH:MM:SS may be 839:59:59, so use uint32 to avoid overflow.\n\thour        uint32 // hour <= 23\n\tmicrosecond uint32\n\tyear        uint16 // year <= 9999\n\tmonth       uint8  // month <= 12\n\tday         uint8  // day <= 31\n\tminute      uint8  // minute <= 59\n\tsecond      uint8  // second <= 59\n\tlocation    *gotime.Location\n}\n\nfunc NewMysqlTime(time gotime.Time) MysqlTime {\n\tyear, month, day := time.Date()\n\thour := time.Hour()\n\tminute := time.Minute()\n\tsecond := time.Second()\n\tmicrosecond := time.Nanosecond() / 1000\n\n\tmysqlTime := MysqlTime{\n\t\tyear:        uint16(year),\n\t\tmonth:       uint8(month),\n\t\tday:         uint8(day),\n\t\thour:        uint32(hour),\n\t\tminute:      uint8(minute),\n\t\tsecond:      uint8(second),\n\t\tmicrosecond: uint32(microsecond),\n\t\tlocation:    time.Location(),\n\t}\n\n\treturn mysqlTime\n}\n\n// return seconds since 1970-01-01 00:00:00 UTC.\nfunc (mt MysqlTime) ToUnixTimestamp() int64 {\n\tt := gotime.Date(int(mt.year), gotime.Month(mt.month), int(mt.day), int(mt.hour), int(mt.minute), int(mt.second), int(mt.microsecond)*1000, mt.location)\n\n\tunixTimestamp := t.Unix()\n\n\treturn unixTimestamp\n}\n\n// String implements fmt.Stringer.\nfunc (t MysqlTime) String() string {\n\treturn fmt.Sprintf(\"{%d %d %d %d %d %d %d}\", t.year, t.month, t.day, t.hour, t.minute, t.second, t.microsecond)\n}\n\n// Year returns the year value.\nfunc (t MysqlTime) Year() int {\n\treturn int(t.year)\n}\n\n// Month returns the month value.\nfunc (t MysqlTime) Month() int {\n\treturn int(t.month)\n}\n\n// Day returns the day value.\nfunc (t MysqlTime) Day() int {\n\treturn int(t.day)\n}\n\n// Hour returns the hour value.\nfunc (t MysqlTime) Hour() int {\n\treturn int(t.hour)\n}\n\n// Minute returns the minute value.\nfunc (t MysqlTime) Minute() int {\n\treturn int(t.minute)\n}\n\n// Second returns the second value.\nfunc (t MysqlTime) Second() int {\n\treturn int(t.second)\n}\n\n// Microsecond returns the microsecond value.\nfunc (t MysqlTime) Microsecond() int {\n\treturn int(t.microsecond)\n}\n\n// Weekday returns the Weekday value.\nfunc (t MysqlTime) Weekday() gotime.Weekday {\n\t// TODO: Consider time_zone variable.\n\tt1, err := t.GoTime(gotime.Local)\n\t// allow invalid dates\n\tif err != nil {\n\t\treturn t1.Weekday()\n\t}\n\treturn t1.Weekday()\n}\n\n// YearDay returns day in year.\nfunc (t MysqlTime) YearDay() int {\n\tif t.month == 0 || t.day == 0 {\n\t\treturn 0\n\t}\n\treturn calcDaynr(int(t.year), int(t.month), int(t.day)) -\n\t\tcalcDaynr(int(t.year), 1, 1) + 1\n}\n\n// YearWeek return year and week.\nfunc (t MysqlTime) YearWeek(mode int) (int, int) {\n\tbehavior := weekMode(mode) | weekBehaviourYear\n\treturn calcWeek(&t, behavior)\n}\n\n// Week returns the week value.\nfunc (t MysqlTime) Week(mode int) int {\n\tif t.month == 0 || t.day == 0 {\n\t\treturn 0\n\t}\n\t_, week := calcWeek(&t, weekMode(mode))\n\treturn week\n}\n\n// GoTime converts MysqlTime to GoTime.\nfunc (t MysqlTime) GoTime(loc *gotime.Location) (gotime.Time, error) {\n\t// gotime.Time can't represent month 0 or day 0, date contains 0 would be converted to a nearest date,\n\t// For example, 2006-12-00 00:00:00 would become 2015-11-30 23:59:59.\n\ttm := gotime.Date(t.Year(), gotime.Month(t.Month()), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Microsecond()*1000, loc)\n\tyear, month, day := tm.Date()\n\thour, minute, second := tm.Clock()\n\tmicrosec := tm.Nanosecond() / 1000\n\t// This function will check the result, and return an error if it's not the same with the origin input.\n\tif year != t.Year() || int(month) != t.Month() || day != t.Day() ||\n\t\thour != t.Hour() || minute != t.Minute() || second != t.Second() ||\n\t\tmicrosec != t.Microsecond() {\n\t\treturn tm, errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, t))\n\t}\n\treturn tm, nil\n}\n\n// IsLeapYear returns if it's leap year.\nfunc (t MysqlTime) IsLeapYear() bool {\n\treturn isLeapYear(t.year)\n}\n\nfunc isLeapYear(year uint16) bool {\n\treturn (year%4 == 0 && year%100 != 0) || year%400 == 0\n}\n\nvar daysByMonth = [12]int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}\n\n// GetLastDay returns the last day of the month\nfunc GetLastDay(year, month int) int {\n\tvar day = 0\n\tif month > 0 && month <= 12 {\n\t\tday = daysByMonth[month-1]\n\t}\n\tif month == 2 && isLeapYear(uint16(year)) {\n\t\tday = 29\n\t}\n\treturn day\n}\n\nfunc getFixDays(year, month, day int, ot gotime.Time) int {\n\tif (year != 0 || month != 0) && day == 0 {\n\t\tod := ot.Day()\n\t\tt := ot.AddDate(year, month, day)\n\t\ttd := t.Day()\n\t\tif od != td {\n\t\t\ttm := int(t.Month()) - 1\n\t\t\ttMax := GetLastDay(t.Year(), tm)\n\t\t\tdd := tMax - od\n\t\t\treturn dd\n\t\t}\n\t}\n\treturn 0\n}\n\n// AddDate fix gap between mysql and golang api\n// When we execute select date_add('2018-01-31',interval 1 month) in mysql we got 2018-02-28\n// but in tidb we got 2018-03-03.\n// Dig it and we found it's caused by golang api time.Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time ,\n// it says October 32 converts to November 1 ,it conflicts with mysql.\n// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-add\nfunc AddDate(year, month, day int64, ot gotime.Time) (nt gotime.Time) {\n\tdf := getFixDays(int(year), int(month), int(day), ot)\n\tif df != 0 {\n\t\tnt = ot.AddDate(int(year), int(month), df)\n\t} else {\n\t\tnt = ot.AddDate(int(year), int(month), int(day))\n\t}\n\treturn nt\n}\n\nfunc calcTimeFromSec(to *MysqlTime, seconds, microseconds int) {\n\tto.hour = uint32(seconds / 3600)\n\tseconds = seconds % 3600\n\tto.minute = uint8(seconds / 60)\n\tto.second = uint8(seconds % 60)\n\tto.microsecond = uint32(microseconds)\n}\n\nconst secondsIn24Hour = 86400\n\n// calcTimeDiff calculates difference between two datetime values as seconds + microseconds.\n// t1 and t2 should be TIME/DATE/DATETIME value.\n// sign can be +1 or -1, and t2 is preprocessed with sign first.\nfunc calcTimeDiff(t1, t2 MysqlTime, sign int) (seconds, microseconds int, neg bool) {\n\tdays := calcDaynr(t1.Year(), t1.Month(), t1.Day())\n\tdays2 := calcDaynr(t2.Year(), t2.Month(), t2.Day())\n\tdays -= sign * days2\n\n\ttmp := (int64(days)*secondsIn24Hour+\n\t\tint64(t1.Hour())*3600+int64(t1.Minute())*60+\n\t\tint64(t1.Second())-\n\t\tint64(sign)*(int64(t2.Hour())*3600+int64(t2.Minute())*60+\n\t\t\tint64(t2.Second())))*\n\t\t1e6 +\n\t\tint64(t1.Microsecond()) - int64(sign)*int64(t2.Microsecond())\n\n\tif tmp < 0 {\n\t\ttmp = -tmp\n\t\tneg = true\n\t}\n\tseconds = int(tmp / 1e6)\n\tmicroseconds = int(tmp % 1e6)\n\treturn\n}\n\n// datetimeToUint64 converts time value to integer in YYYYMMDDHHMMSS format.\nfunc datetimeToUint64(t MysqlTime) uint64 {\n\treturn dateToUint64(t)*1e6 + timeToUint64(t)\n}\n\n// dateToUint64 converts time value to integer in YYYYMMDD format.\nfunc dateToUint64(t MysqlTime) uint64 {\n\treturn uint64(t.Year())*10000 +\n\t\tuint64(t.Month())*100 +\n\t\tuint64(t.Day())\n}\n\n// timeToUint64 converts time value to integer in HHMMSS format.\nfunc timeToUint64(t MysqlTime) uint64 {\n\treturn uint64(t.Hour())*10000 +\n\t\tuint64(t.Minute())*100 +\n\t\tuint64(t.Second())\n}\n\n// calcDaynr calculates days since 0000-00-00.\nfunc calcDaynr(year, month, day int) int {\n\tif year == 0 && month == 0 {\n\t\treturn 0\n\t}\n\n\tdelsum := 365*year + 31*(month-1) + day\n\tif month <= 2 {\n\t\tyear--\n\t} else {\n\t\tdelsum -= (month*4 + 23) / 10\n\t}\n\ttemp := ((year/100 + 1) * 3) / 4\n\treturn delsum + year/4 - temp\n}\n\n// DateDiff calculates number of days between two days.\nfunc DateDiff(startTime, endTime MysqlTime) int {\n\treturn calcDaynr(startTime.Year(), startTime.Month(), startTime.Day()) - calcDaynr(endTime.Year(), endTime.Month(), endTime.Day())\n}\n\n// calcDaysInYear calculates days in one year, it works with 0 <= year <= 99.\nfunc calcDaysInYear(year int) int {\n\tif (year&3) == 0 && (year%100 != 0 || (year%400 == 0 && (year != 0))) {\n\t\treturn 366\n\t}\n\treturn 365\n}\n\n// calcWeekday calculates weekday from daynr, returns 0 for Monday, 1 for Tuesday ...\nfunc calcWeekday(daynr int, sundayFirstDayOfWeek bool) int {\n\tdaynr += 5\n\tif sundayFirstDayOfWeek {\n\t\tdaynr++\n\t}\n\treturn daynr % 7\n}\n\ntype weekBehaviour uint\n\nconst (\n\t// weekBehaviourMondayFirst set Monday as first day of week; otherwise Sunday is first day of week\n\tweekBehaviourMondayFirst weekBehaviour = 1 << iota\n\t// If set, Week is in range 1-53, otherwise Week is in range 0-53.\n\t// Note that this flag is only relevant if WEEK_JANUARY is not set.\n\tweekBehaviourYear\n\t// If not set, Weeks are numbered according to ISO 8601:1988.\n\t// If set, the week that contains the first 'first-day-of-week' is week 1.\n\tweekBehaviourFirstWeekday\n)\n\nfunc (v weekBehaviour) test(flag weekBehaviour) bool {\n\treturn (v & flag) != 0\n}\n\nfunc weekMode(mode int) weekBehaviour {\n\tweekFormat := weekBehaviour(mode & 7)\n\tif (weekFormat & weekBehaviourMondayFirst) == 0 {\n\t\tweekFormat ^= weekBehaviourFirstWeekday\n\t}\n\treturn weekFormat\n}\n\n// calcWeek calculates week and year for the time.\nfunc calcWeek(t *MysqlTime, wb weekBehaviour) (year int, week int) {\n\tvar days int\n\tdaynr := calcDaynr(int(t.year), int(t.month), int(t.day))\n\tfirstDaynr := calcDaynr(int(t.year), 1, 1)\n\tmondayFirst := wb.test(weekBehaviourMondayFirst)\n\tweekYear := wb.test(weekBehaviourYear)\n\tfirstWeekday := wb.test(weekBehaviourFirstWeekday)\n\n\tweekday := calcWeekday(firstDaynr, !mondayFirst)\n\n\tyear = int(t.year)\n\n\tif t.month == 1 && int(t.day) <= 7-weekday {\n\t\tif !weekYear &&\n\t\t\t((firstWeekday && weekday != 0) || (!firstWeekday && weekday >= 4)) {\n\t\t\tweek = 0\n\t\t\treturn\n\t\t}\n\t\tweekYear = true\n\t\tyear--\n\t\tdays = calcDaysInYear(year)\n\t\tfirstDaynr -= days\n\t\tweekday = (weekday + 53*7 - days) % 7\n\t}\n\n\tif (firstWeekday && weekday != 0) ||\n\t\t(!firstWeekday && weekday >= 4) {\n\t\tdays = daynr - (firstDaynr + 7 - weekday)\n\t} else {\n\t\tdays = daynr - (firstDaynr - weekday)\n\t}\n\n\tif weekYear && days >= 52*7 {\n\t\tweekday = (weekday + calcDaysInYear(year)) % 7\n\t\tif (!firstWeekday && weekday < 4) ||\n\t\t\t(firstWeekday && weekday == 0) {\n\t\t\tyear++\n\t\t\tweek = 1\n\t\t\treturn\n\t\t}\n\t}\n\tweek = days/7 + 1\n\treturn\n}\n\n// mixDateAndTime mixes a date value and a time value.\nfunc mixDateAndTime(date, time *MysqlTime, neg bool) {\n\tif !neg && time.hour < 24 {\n\t\tdate.hour = time.hour\n\t\tdate.minute = time.minute\n\t\tdate.second = time.second\n\t\tdate.microsecond = time.microsecond\n\t\treturn\n\t}\n\n\t// Time is negative or outside of 24 hours internal.\n\tsign := -1\n\tif neg {\n\t\tsign = 1\n\t}\n\tseconds, microseconds, _ := calcTimeDiff(*date, *time, sign)\n\n\t// If we want to use this function with arbitrary dates, this code will need\n\t// to cover cases when time is negative and \"date < -time\".\n\n\tdays := seconds / secondsIn24Hour\n\tcalcTimeFromSec(date, seconds%secondsIn24Hour, microseconds)\n\tyear, month, day := getDateFromDaynr(uint(days))\n\tdate.year = uint16(year)\n\tdate.month = uint8(month)\n\tdate.day = uint8(day)\n}\n\nvar daysInMonth = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}\n\n// getDateFromDaynr changes a daynr to year, month and day,\n// daynr 0 is returned as date 00.00.00\nfunc getDateFromDaynr(daynr uint) (year uint, month uint, day uint) {\n\tif daynr <= 365 || daynr >= 3652500 {\n\t\treturn\n\t}\n\n\tyear = daynr * 100 / 36525\n\ttemp := (((year-1)/100 + 1) * 3) / 4\n\tdayOfYear := daynr - year*365 - (year-1)/4 + temp\n\n\tdaysInYear := calcDaysInYear(int(year))\n\tfor dayOfYear > uint(daysInYear) {\n\t\tdayOfYear -= uint(daysInYear)\n\t\tyear++\n\t\tdaysInYear = calcDaysInYear(int(year))\n\t}\n\n\tleapDay := uint(0)\n\tif daysInYear == 366 {\n\t\tif dayOfYear > 31+28 {\n\t\t\tdayOfYear--\n\t\t\tif dayOfYear == 31+28 {\n\t\t\t\t// Handle leapyears leapday.\n\t\t\t\tleapDay = 1\n\t\t\t}\n\t\t}\n\t}\n\n\tmonth = 1\n\tfor _, days := range daysInMonth {\n\t\tif dayOfYear <= uint(days) {\n\t\t\tbreak\n\t\t}\n\t\tdayOfYear -= uint(days)\n\t\tmonth++\n\t}\n\n\tday = dayOfYear + leapDay\n\treturn\n}\n\nconst (\n\tintervalYEAR        = \"YEAR\"\n\tintervalQUARTER     = \"QUARTER\"\n\tintervalMONTH       = \"MONTH\"\n\tintervalWEEK        = \"WEEK\"\n\tintervalDAY         = \"DAY\"\n\tintervalHOUR        = \"HOUR\"\n\tintervalMINUTE      = \"MINUTE\"\n\tintervalSECOND      = \"SECOND\"\n\tintervalMICROSECOND = \"MICROSECOND\"\n)\n\nfunc timestampDiff(intervalType string, t1 MysqlTime, t2 MysqlTime) int64 {\n\tseconds, microseconds, neg := calcTimeDiff(t2, t1, 1)\n\tmonths := uint(0)\n\tif intervalType == intervalYEAR || intervalType == intervalQUARTER ||\n\t\tintervalType == intervalMONTH {\n\t\tvar (\n\t\t\tyearBeg, yearEnd, monthBeg, monthEnd, dayBeg, dayEnd uint\n\t\t\tsecondBeg, secondEnd, microsecondBeg, microsecondEnd uint\n\t\t)\n\n\t\tif neg {\n\t\t\tyearBeg = uint(t2.Year())\n\t\t\tyearEnd = uint(t1.Year())\n\t\t\tmonthBeg = uint(t2.Month())\n\t\t\tmonthEnd = uint(t1.Month())\n\t\t\tdayBeg = uint(t2.Day())\n\t\t\tdayEnd = uint(t1.Day())\n\t\t\tsecondBeg = uint(t2.Hour()*3600 + t2.Minute()*60 + t2.Second())\n\t\t\tsecondEnd = uint(t1.Hour()*3600 + t1.Minute()*60 + t1.Second())\n\t\t\tmicrosecondBeg = uint(t2.Microsecond())\n\t\t\tmicrosecondEnd = uint(t1.Microsecond())\n\t\t} else {\n\t\t\tyearBeg = uint(t1.Year())\n\t\t\tyearEnd = uint(t2.Year())\n\t\t\tmonthBeg = uint(t1.Month())\n\t\t\tmonthEnd = uint(t2.Month())\n\t\t\tdayBeg = uint(t1.Day())\n\t\t\tdayEnd = uint(t2.Day())\n\t\t\tsecondBeg = uint(t1.Hour()*3600 + t1.Minute()*60 + t1.Second())\n\t\t\tsecondEnd = uint(t2.Hour()*3600 + t2.Minute()*60 + t2.Second())\n\t\t\tmicrosecondBeg = uint(t1.Microsecond())\n\t\t\tmicrosecondEnd = uint(t2.Microsecond())\n\t\t}\n\n\t\t// calc years\n\t\tyears := yearEnd - yearBeg\n\t\tif monthEnd < monthBeg ||\n\t\t\t(monthEnd == monthBeg && dayEnd < dayBeg) {\n\t\t\tyears--\n\t\t}\n\n\t\t// calc months\n\t\tmonths = 12 * years\n\t\tif monthEnd < monthBeg ||\n\t\t\t(monthEnd == monthBeg && dayEnd < dayBeg) {\n\t\t\tmonths += 12 - (monthBeg - monthEnd)\n\t\t} else {\n\t\t\tmonths += monthEnd - monthBeg\n\t\t}\n\n\t\tif dayEnd < dayBeg {\n\t\t\tmonths--\n\t\t} else if (dayEnd == dayBeg) &&\n\t\t\t((secondEnd < secondBeg) ||\n\t\t\t\t(secondEnd == secondBeg && microsecondEnd < microsecondBeg)) {\n\t\t\tmonths--\n\t\t}\n\t}\n\n\tnegV := int64(1)\n\tif neg {\n\t\tnegV = -1\n\t}\n\tswitch intervalType {\n\tcase intervalYEAR:\n\t\treturn int64(months) / 12 * negV\n\tcase intervalQUARTER:\n\t\treturn int64(months) / 3 * negV\n\tcase intervalMONTH:\n\t\treturn int64(months) * negV\n\tcase intervalWEEK:\n\t\treturn int64(seconds) / secondsIn24Hour / 7 * negV\n\tcase intervalDAY:\n\t\treturn int64(seconds) / secondsIn24Hour * negV\n\tcase intervalHOUR:\n\t\treturn int64(seconds) / 3600 * negV\n\tcase intervalMINUTE:\n\t\treturn int64(seconds) / 60 * negV\n\tcase intervalSECOND:\n\t\treturn int64(seconds) * negV\n\tcase intervalMICROSECOND:\n\t\t// In MySQL difference between any two valid datetime values\n\t\t// in microseconds fits into longlong.\n\t\treturn int64(seconds*1000000+microseconds) * negV\n\t}\n\n\treturn 0\n}\n"
  },
  {
    "path": "pkg/types/overflow.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"time\"\n\n\t\"github.com/pingcap/errors\"\n)\n\n// AddUint64 adds uint64 a and b if no overflow, else returns error.\nfunc AddUint64(a uint64, b uint64) (uint64, error) {\n\tif math.MaxUint64-a < b {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT UNSIGNED\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\treturn a + b, nil\n}\n\n// AddInt64 adds int64 a and b if no overflow, otherwise returns error.\nfunc AddInt64(a int64, b int64) (int64, error) {\n\tif (a > 0 && b > 0 && math.MaxInt64-a < b) ||\n\t\t(a < 0 && b < 0 && math.MinInt64-a > b) {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\n\treturn a + b, nil\n}\n\n// AddDuration adds time.Duration a and b if no overflow, otherwise returns error.\nfunc AddDuration(a time.Duration, b time.Duration) (time.Duration, error) {\n\tif (a > 0 && b > 0 && math.MaxInt64-a < b) ||\n\t\t(a < 0 && b < 0 && math.MinInt64-a > b) {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"(%d, %d)\", int64(a), int64(b)))\n\t}\n\n\treturn a + b, nil\n}\n\n// SubDuration subtracts time.Duration a with b and returns time.Duration if no overflow error.\nfunc SubDuration(a time.Duration, b time.Duration) (time.Duration, error) {\n\tif (a > 0 && b < 0 && math.MaxInt64-a < -b) ||\n\t\t(a < 0 && b > 0 && math.MinInt64-a > -b) ||\n\t\t(a == 0 && b == math.MinInt64) {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\treturn a - b, nil\n}\n\n// AddInteger adds uint64 a and int64 b and returns uint64 if no overflow error.\nfunc AddInteger(a uint64, b int64) (uint64, error) {\n\tif b >= 0 {\n\t\treturn AddUint64(a, uint64(b))\n\t}\n\n\tif uint64(-b) > a {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT UNSIGNED\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\treturn a - uint64(-b), nil\n}\n\n// SubUint64 subtracts uint64 a with b and returns uint64 if no overflow error.\nfunc SubUint64(a uint64, b uint64) (uint64, error) {\n\tif a < b {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT UNSIGNED\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\treturn a - b, nil\n}\n\n// SubInt64 subtracts int64 a with b and returns int64 if no overflow error.\nfunc SubInt64(a int64, b int64) (int64, error) {\n\tif (a > 0 && b < 0 && math.MaxInt64-a < -b) ||\n\t\t(a < 0 && b > 0 && math.MinInt64-a > -b) ||\n\t\t(a == 0 && b == math.MinInt64) {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\treturn a - b, nil\n}\n\n// SubUintWithInt subtracts uint64 a with int64 b and returns uint64 if no overflow error.\nfunc SubUintWithInt(a uint64, b int64) (uint64, error) {\n\tif b < 0 {\n\t\treturn AddUint64(a, uint64(-b))\n\t}\n\treturn SubUint64(a, uint64(b))\n}\n\n// SubIntWithUint subtracts int64 a with uint64 b and returns uint64 if no overflow error.\nfunc SubIntWithUint(a int64, b uint64) (uint64, error) {\n\tif a < 0 || uint64(a) < b {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT UNSIGNED\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\treturn uint64(a) - b, nil\n}\n\n// MulUint64 multiplies uint64 a and b and returns uint64 if no overflow error.\nfunc MulUint64(a uint64, b uint64) (uint64, error) {\n\tif b > 0 && a > math.MaxUint64/b {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT UNSIGNED\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\treturn a * b, nil\n}\n\n// MulInt64 multiplies int64 a and b and returns int64 if no overflow error.\nfunc MulInt64(a int64, b int64) (int64, error) {\n\tif a == 0 || b == 0 {\n\t\treturn 0, nil\n\t}\n\n\tvar (\n\t\tres      uint64\n\t\terr      error\n\t\tnegative = false\n\t)\n\n\tif a > 0 && b > 0 {\n\t\tres, err = MulUint64(uint64(a), uint64(b))\n\t} else if a < 0 && b < 0 {\n\t\tres, err = MulUint64(uint64(-a), uint64(-b))\n\t} else if a < 0 && b > 0 {\n\t\tnegative = true\n\t\tres, err = MulUint64(uint64(-a), uint64(b))\n\t} else {\n\t\tnegative = true\n\t\tres, err = MulUint64(uint64(a), uint64(-b))\n\t}\n\n\tif err != nil {\n\t\treturn 0, errors.Trace(err)\n\t}\n\n\tif negative {\n\t\t// negative result\n\t\tif res > math.MaxInt64+1 {\n\t\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t\t}\n\n\t\treturn -int64(res), nil\n\t}\n\n\t// positive result\n\tif res > math.MaxInt64 {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\n\treturn int64(res), nil\n}\n\n// MulInteger multiplies uint64 a and int64 b, and returns uint64 if no overflow error.\nfunc MulInteger(a uint64, b int64) (uint64, error) {\n\tif a == 0 || b == 0 {\n\t\treturn 0, nil\n\t}\n\n\tif b < 0 {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT UNSIGNED\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\n\treturn MulUint64(a, uint64(b))\n}\n\n// DivInt64 divides int64 a with b, returns int64 if no overflow error.\n// It just checks overflow, if b is zero, a \"divide by zero\" panic throws.\nfunc DivInt64(a int64, b int64) (int64, error) {\n\tif a == math.MinInt64 && b == -1 {\n\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t}\n\n\treturn a / b, nil\n}\n\n// DivUintWithInt divides uint64 a with int64 b, returns uint64 if no overflow error.\n// It just checks overflow, if b is zero, a \"divide by zero\" panic throws.\nfunc DivUintWithInt(a uint64, b int64) (uint64, error) {\n\tif b < 0 {\n\t\tif a != 0 && uint64(-b) <= a {\n\t\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT UNSIGNED\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t\t}\n\n\t\treturn 0, nil\n\t}\n\n\treturn a / uint64(b), nil\n}\n\n// DivIntWithUint divides int64 a with uint64 b, returns uint64 if no overflow error.\n// It just checks overflow, if b is zero, a \"divide by zero\" panic throws.\nfunc DivIntWithUint(a int64, b uint64) (uint64, error) {\n\tif a < 0 {\n\t\tif uint64(-a) >= b {\n\t\t\treturn 0, ErrOverflow.GenWithStackByArgs(\"BIGINT\", fmt.Sprintf(\"(%d, %d)\", a, b))\n\t\t}\n\n\t\treturn 0, nil\n\t}\n\n\treturn uint64(a) / b, nil\n}\n"
  },
  {
    "path": "pkg/types/parser_driver/value_expr.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage driver\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/parser/ast\"\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/hack\"\n)\n\n// The purpose of driver package is to decompose the dependency of the parser and\n// types package.\n// It provides the NewValueExpr function for the ast package, so the ast package\n// do not depends on the concrete definition of `types.Datum`, thus get rid of\n// the dependency of the types package.\n// The parser package depends on the ast package, but not the types package.\n// The whole relationship:\n// ast imports []\n// tidb/types imports [parser/types]\n// parser imports [ast, parser/types]\n// driver imports [ast, tidb/types]\n// tidb imports [parser, driver]\n\nfunc init() {\n\tast.NewValueExpr = newValueExpr\n\tast.NewParamMarkerExpr = newParamMarkerExpr\n\tast.NewDecimal = func(str string) (interface{}, error) {\n\t\tdec := new(types.MyDecimal)\n\t\terr := dec.FromString(hack.Slice(str))\n\t\treturn dec, err\n\t}\n}\n\nvar (\n\t_ ast.ParamMarkerExpr = &ParamMarkerExpr{}\n\t_ ast.ValueExpr       = &ValueExpr{}\n)\n\n// ValueExpr is the simple value expression.\ntype ValueExpr struct {\n\tast.TexprNode\n\ttypes.Datum\n\tprojectionOffset int\n}\n\n// Restore implements Node interface.\nfunc (n *ValueExpr) Restore(ctx *format.RestoreCtx) error {\n\tswitch n.Kind() {\n\tcase types.KindNull:\n\t\tctx.WriteKeyWord(\"NULL\")\n\tcase types.KindInt64:\n\t\tif n.Type.Flag&mysql.IsBooleanFlag != 0 {\n\t\t\tif n.GetInt64() > 0 {\n\t\t\t\tctx.WriteKeyWord(\"TRUE\")\n\t\t\t} else {\n\t\t\t\tctx.WriteKeyWord(\"FALSE\")\n\t\t\t}\n\t\t} else {\n\t\t\tctx.WritePlain(strconv.FormatInt(n.GetInt64(), 10))\n\t\t}\n\tcase types.KindUint64:\n\t\tctx.WritePlain(strconv.FormatUint(n.GetUint64(), 10))\n\tcase types.KindFloat32:\n\t\tctx.WritePlain(strconv.FormatFloat(n.GetFloat64(), 'e', -1, 32))\n\tcase types.KindFloat64:\n\t\tctx.WritePlain(strconv.FormatFloat(n.GetFloat64(), 'e', -1, 64))\n\tcase types.KindMysqlDecimal:\n\t\tctx.WritePlain(n.GetMysqlDecimal().String())\n\tcase types.KindString:\n\t\tif n.Type.Charset != \"\" && n.Type.Charset != mysql.DefaultCharset {\n\t\t\tctx.WritePlain(\"_\")\n\t\t\tctx.WriteKeyWord(n.Type.Charset)\n\t\t}\n\t\tctx.WriteString(n.GetString())\n\tcase types.KindBytes:\n\t\tctx.WriteString(n.GetString())\n\tcase types.KindMysqlBit,\n\t\ttypes.KindMinNotNull, types.KindMaxValue,\n\t\ttypes.KindRaw, types.KindInterface:\n\t\t// TODO implement Restore function\n\t\treturn errors.New(\"Not implemented\")\n\tdefault:\n\t\treturn errors.New(\"can't format to string\")\n\t}\n\treturn nil\n}\n\n// GetDatumString implements the ast.ValueExpr interface.\nfunc (n *ValueExpr) GetDatumString() string {\n\treturn n.GetString()\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *ValueExpr) Format(w io.Writer) {\n\tvar s string\n\tswitch n.Kind() {\n\tcase types.KindNull:\n\t\ts = \"NULL\"\n\tcase types.KindInt64:\n\t\tif n.Type.Flag&mysql.IsBooleanFlag != 0 {\n\t\t\tif n.GetInt64() > 0 {\n\t\t\t\ts = \"TRUE\"\n\t\t\t} else {\n\t\t\t\ts = \"FALSE\"\n\t\t\t}\n\t\t} else {\n\t\t\ts = strconv.FormatInt(n.GetInt64(), 10)\n\t\t}\n\tcase types.KindUint64:\n\t\ts = strconv.FormatUint(n.GetUint64(), 10)\n\tcase types.KindFloat32:\n\t\ts = strconv.FormatFloat(n.GetFloat64(), 'e', -1, 32)\n\tcase types.KindFloat64:\n\t\ts = strconv.FormatFloat(n.GetFloat64(), 'e', -1, 64)\n\tcase types.KindString, types.KindBytes:\n\t\ts = strconv.Quote(n.GetString())\n\tdefault:\n\t\tpanic(\"Can't format to string\")\n\t}\n\tfmt.Fprint(w, s)\n}\n\n// newValueExpr creates a ValueExpr with value, and sets default field type.\nfunc newValueExpr(value interface{}) ast.ValueExpr {\n\tif ve, ok := value.(*ValueExpr); ok {\n\t\treturn ve\n\t}\n\tve := &ValueExpr{}\n\tve.SetValue(value)\n\ttypes.DefaultTypeForValue(value, &ve.Type)\n\tve.projectionOffset = -1\n\treturn ve\n}\n\n// SetProjectionOffset sets ValueExpr.projectionOffset for logical plan builder.\nfunc (n *ValueExpr) SetProjectionOffset(offset int) {\n\tn.projectionOffset = offset\n}\n\n// GetProjectionOffset returns ValueExpr.projectionOffset.\nfunc (n *ValueExpr) GetProjectionOffset() int {\n\treturn n.projectionOffset\n}\n\n// Accept implements Node interface.\nfunc (n *ValueExpr) Accept(v ast.Visitor) (ast.Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ValueExpr)\n\treturn v.Leave(n)\n}\n\n// ParamMarkerExpr expression holds a place for another expression.\n// Used in parsing prepare statement.\ntype ParamMarkerExpr struct {\n\tValueExpr\n\tOffset    int\n\tOrder     int\n\tParamName string\n\tInExecute bool\n}\n\nfunc newParamMarkerExpr(offset int, paramName string) ast.ParamMarkerExpr {\n\treturn &ParamMarkerExpr{\n\t\tOffset:    offset,\n\t\tParamName: paramName,\n\t}\n}\n\n// Format the ExprNode into a Writer.\nfunc (n *ParamMarkerExpr) Format(w io.Writer) {\n\tpanic(\"Not implemented\")\n}\n\n// Accept implements Node Accept interface.\nfunc (n *ParamMarkerExpr) Accept(v ast.Visitor) (ast.Node, bool) {\n\tnewNode, skipChildren := v.Enter(n)\n\tif skipChildren {\n\t\treturn v.Leave(newNode)\n\t}\n\tn = newNode.(*ParamMarkerExpr)\n\treturn v.Leave(n)\n}\n\n// SetOrder implements the ast.ParamMarkerExpr interface.\nfunc (n *ParamMarkerExpr) SetOrder(order int) {\n\tn.Order = order\n}\n"
  },
  {
    "path": "pkg/types/parser_driver/value_expr_test.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage driver\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/parser/format\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\nvar _ = Suite(&testValueExprRestoreSuite{})\n\nfunc TestT(t *testing.T) {\n\tTestingT(t)\n}\n\ntype testValueExprRestoreSuite struct {\n}\n\nfunc (s *testValueExprRestoreSuite) TestValueExprRestore(c *C) {\n\ttestCases := []struct {\n\t\tdatum  types.Datum\n\t\texpect string\n\t}{\n\t\t{types.NewDatum(nil), \"NULL\"},\n\t\t{types.NewIntDatum(1), \"1\"},\n\t\t{types.NewIntDatum(-1), \"-1\"},\n\t\t{types.NewUintDatum(1), \"1\"},\n\t\t{types.NewFloat32Datum(1.1), \"1.1e+00\"},\n\t\t{types.NewFloat64Datum(1.1), \"1.1e+00\"},\n\t\t{types.NewStringDatum(\"test `s't\\\"r.\"), \"'test `s''t\\\"r.'\"},\n\t\t{types.NewBytesDatum([]byte(\"test `s't\\\"r.\")), \"'test `s''t\\\"r.'\"},\n\t}\n\t// Run Test\n\tvar sb strings.Builder\n\tfor _, testCase := range testCases {\n\t\tsb.Reset()\n\t\texpr := &ValueExpr{Datum: testCase.datum}\n\t\terr := expr.Restore(format.NewRestoreCtx(format.DefaultRestoreFlags, &sb))\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(sb.String(), Equals, testCase.expect, Commentf(\"Datum: %#v\", testCase.datum))\n\t}\n}\n"
  },
  {
    "path": "pkg/types/time.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage types\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\tgotime \"time\"\n\t\"unicode\"\n\n\t\"github.com/pingcap/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/terror\"\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\ttidbMath \"github.com/secretflow/scql/pkg/util/math\"\n)\n\n// Time format without fractional seconds precision.\nconst (\n\tDateFormat = \"2006-01-02\"\n\tTimeFormat = \"2006-01-02 15:04:05\"\n\t// TimeFSPFormat is time format with fractional seconds precision.\n\tTimeFSPFormat = \"2006-01-02 15:04:05.000000\"\n)\n\nconst (\n\t// MinYear is the minimum for mysql year type.\n\tMinYear int16 = 1901\n\t// MaxYear is the maximum for mysql year type.\n\tMaxYear int16 = 2155\n\t// MaxDuration is the maximum for duration.\n\tMaxDuration int64 = 838*10000 + 59*100 + 59\n\t// MinTime is the minimum for mysql time type.\n\tMinTime = -gotime.Duration(838*3600+59*60+59) * gotime.Second\n\t// MaxTime is the maximum for mysql time type.\n\tMaxTime = gotime.Duration(838*3600+59*60+59) * gotime.Second\n\t// ZeroDatetimeStr is the string representation of a zero datetime.\n\tZeroDatetimeStr = \"0000-00-00 00:00:00\"\n\t// ZeroDateStr is the string representation of a zero date.\n\tZeroDateStr = \"0000-00-00\"\n\n\t// TimeMaxHour is the max hour for mysql time type.\n\tTimeMaxHour = 838\n\t// TimeMaxMinute is the max minute for mysql time type.\n\tTimeMaxMinute = 59\n\t// TimeMaxSecond is the max second for mysql time type.\n\tTimeMaxSecond = 59\n\t// TimeMaxValue is the maximum value for mysql time type.\n\tTimeMaxValue = TimeMaxHour*10000 + TimeMaxMinute*100 + TimeMaxSecond\n\t// TimeMaxValueSeconds is the maximum second value for mysql time type.\n\tTimeMaxValueSeconds = TimeMaxHour*3600 + TimeMaxMinute*60 + TimeMaxSecond\n)\n\nconst (\n\t// YearIndex is index of 'YEARS-MONTHS DAYS HOURS:MINUTES:SECONDS.MICROSECONDS' expr Format\n\tYearIndex = 0 + iota\n\t// MonthIndex is index of 'YEARS-MONTHS DAYS HOURS:MINUTES:SECONDS.MICROSECONDS' expr Format\n\tMonthIndex\n\t// DayIndex is index of 'YEARS-MONTHS DAYS HOURS:MINUTES:SECONDS.MICROSECONDS' expr Format\n\tDayIndex\n\t// HourIndex is index of 'YEARS-MONTHS DAYS HOURS:MINUTES:SECONDS.MICROSECONDS' expr Format\n\tHourIndex\n\t// MinuteIndex is index of 'YEARS-MONTHS DAYS HOURS:MINUTES:SECONDS.MICROSECONDS' expr Format\n\tMinuteIndex\n\t// SecondIndex is index of 'YEARS-MONTHS DAYS HOURS:MINUTES:SECONDS.MICROSECONDS' expr Format\n\tSecondIndex\n\t// MicrosecondIndex is index of 'YEARS-MONTHS DAYS HOURS:MINUTES:SECONDS.MICROSECONDS' expr Format\n\tMicrosecondIndex\n)\n\nconst (\n\t// YearMonthMaxCnt is max parameters count 'YEARS-MONTHS' expr Format allowed\n\tYearMonthMaxCnt = 2\n\t// DayHourMaxCnt is max parameters count 'DAYS HOURS' expr Format allowed\n\tDayHourMaxCnt = 2\n\t// DayMinuteMaxCnt is max parameters count 'DAYS HOURS:MINUTES' expr Format allowed\n\tDayMinuteMaxCnt = 3\n\t// DaySecondMaxCnt is max parameters count 'DAYS HOURS:MINUTES:SECONDS' expr Format allowed\n\tDaySecondMaxCnt = 4\n\t// DayMicrosecondMaxCnt is max parameters count 'DAYS HOURS:MINUTES:SECONDS.MICROSECONDS' expr Format allowed\n\tDayMicrosecondMaxCnt = 5\n\t// HourMinuteMaxCnt is max parameters count 'HOURS:MINUTES' expr Format allowed\n\tHourMinuteMaxCnt = 2\n\t// HourSecondMaxCnt is max parameters count 'HOURS:MINUTES:SECONDS' expr Format allowed\n\tHourSecondMaxCnt = 3\n\t// HourMicrosecondMaxCnt is max parameters count 'HOURS:MINUTES:SECONDS.MICROSECONDS' expr Format allowed\n\tHourMicrosecondMaxCnt = 4\n\t// MinuteSecondMaxCnt is max parameters count 'MINUTES:SECONDS' expr Format allowed\n\tMinuteSecondMaxCnt = 2\n\t// MinuteMicrosecondMaxCnt is max parameters count 'MINUTES:SECONDS.MICROSECONDS' expr Format allowed\n\tMinuteMicrosecondMaxCnt = 3\n\t// SecondMicrosecondMaxCnt is max parameters count 'SECONDS.MICROSECONDS' expr Format allowed\n\tSecondMicrosecondMaxCnt = 2\n\t// TimeValueCnt is parameters count 'YEARS-MONTHS DAYS HOURS:MINUTES:SECONDS.MICROSECONDS' expr Format\n\tTimeValueCnt = 7\n)\n\n// Zero values for different types.\nvar (\n\t// ZeroDuration is the zero value for Duration type.\n\tZeroDuration = Duration{Duration: gotime.Duration(0), Fsp: DefaultFsp}\n\n\t// ZeroCoreTime is the zero value for TimeInternal type.\n\tZeroCoreTime = MysqlTime{}\n\n\t// ZeroCoreTime is the zero value for Time type.\n\tZeroTime = Time{}\n\n\t// ZeroDatetime is the zero value for datetime Time.\n\tZeroDatetime = Time{\n\t\ttime: ZeroCoreTime,\n\t\ttp:   mysql.TypeDatetime,\n\t\tfsp:  DefaultFsp,\n\t}\n\n\t// ZeroTimestamp is the zero value for timestamp Time.\n\tZeroTimestamp = Time{\n\t\ttime: ZeroCoreTime,\n\t\ttp:   mysql.TypeTimestamp,\n\t\tfsp:  DefaultFsp,\n\t}\n\n\t// ZeroDate is the zero value for date Time.\n\tZeroDate = Time{\n\t\ttime: ZeroCoreTime,\n\t\ttp:   mysql.TypeDate,\n\t\tfsp:  DefaultFsp,\n\t}\n)\n\nvar (\n\t// MinDatetime is the minimum for mysql datetime type.\n\tMinDatetime = FromDate(1000, 1, 1, 0, 0, 0, 0)\n\t// MaxDatetime is the maximum for mysql datetime type.\n\tMaxDatetime = FromDate(9999, 12, 31, 23, 59, 59, 999999)\n\n\t// BoundTimezone is the timezone for min and max timestamp.\n\tBoundTimezone = gotime.UTC\n\t// MinTimestamp is the minimum for mysql timestamp type.\n\tMinTimestamp = Time{\n\t\ttime: FromDate(1970, 1, 1, 0, 0, 1, 0),\n\t\ttp:   mysql.TypeTimestamp,\n\t\tfsp:  DefaultFsp,\n\t}\n\t// MaxTimestamp is the maximum for mysql timestamp type.\n\tMaxTimestamp = Time{\n\t\ttime: FromDate(2038, 1, 19, 3, 14, 7, 999999),\n\t\ttp:   mysql.TypeTimestamp,\n\t\tfsp:  DefaultFsp,\n\t}\n\n\t// WeekdayNames lists names of weekdays, which are used in builtin time function `dayname`.\n\tWeekdayNames = []string{\n\t\t\"Monday\",\n\t\t\"Tuesday\",\n\t\t\"Wednesday\",\n\t\t\"Thursday\",\n\t\t\"Friday\",\n\t\t\"Saturday\",\n\t\t\"Sunday\",\n\t}\n\n\t// MonthNames lists names of months, which are used in builtin time function `monthname`.\n\tMonthNames = []string{\n\t\t\"January\", \"February\",\n\t\t\"March\", \"April\",\n\t\t\"May\", \"June\",\n\t\t\"July\", \"August\",\n\t\t\"September\", \"October\",\n\t\t\"November\", \"December\",\n\t}\n)\n\nconst (\n\t// GoDurationDay is the gotime.Duration which equals to a Day.\n\tGoDurationDay = gotime.Hour * 24\n\t// GoDurationWeek is the gotime.Duration which equals to a Week.\n\tGoDurationWeek = GoDurationDay * 7\n)\n\n// FromGoTime translates time.Time to mysql time internal representation.\nfunc FromGoTime(t gotime.Time) MysqlTime {\n\t// Plus 500 nanosecond for rounding of the millisecond part.\n\tt = t.Add(500 * gotime.Nanosecond)\n\n\tyear, month, day := t.Date()\n\thour, minute, second := t.Clock()\n\tmicrosecond := t.Nanosecond() / 1000\n\treturn FromDate(year, int(month), day, hour, minute, second, microsecond)\n}\n\n// FromDate makes a internal time representation from the given date.\nfunc FromDate(year int, month int, day int, hour int, minute int, second int, microsecond int) MysqlTime {\n\treturn MysqlTime{\n\t\tyear:        uint16(year),\n\t\tmonth:       uint8(month),\n\t\tday:         uint8(day),\n\t\thour:        uint32(hour),\n\t\tminute:      uint8(minute),\n\t\tsecond:      uint8(second),\n\t\tmicrosecond: uint32(microsecond),\n\t}\n}\n\n// MaxMySQLTime returns Duration with maximum mysql time.\nfunc MaxMySQLTime(fsp int8) Time {\n\treturn NewTime(FromDate(0, 0, 0, TimeMaxHour, TimeMaxMinute, TimeMaxSecond, 0), mysql.TypeDuration, fsp)\n}\n\n// Clock returns the hour, minute, and second within the day specified by t.\nfunc (t Time) Clock() (hour int, minute int, second int) {\n\treturn t.time.Hour(), t.time.Minute(), t.time.Second()\n}\n\n// Time is the struct for handling datetime, timestamp and date.\n// TODO: check if need a NewTime function to set Fsp default value?\ntype Time struct {\n\ttime MysqlTime\n\ttp   uint8\n\t// Fsp is short for Fractional Seconds Precision.\n\t// See http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html\n\tfsp int8\n}\n\n// NewTime constructs time from core time, type and fsp.\nfunc NewTime(mt MysqlTime, tp uint8, fsp int8) Time {\n\treturn Time{\n\t\ttime: mt,\n\t\ttp:   tp,\n\t\tfsp:  fsp,\n\t}\n}\n\n// Year returns year value.\nfunc (t Time) Year() int {\n\treturn t.time.Year()\n}\n\n// Month returns month value.\nfunc (t Time) Month() int {\n\treturn t.time.Month()\n}\n\n// Day returns day value.\nfunc (t Time) Day() int {\n\treturn t.time.Day()\n}\n\n// Hour returns hour value.\nfunc (t Time) Hour() int {\n\treturn t.time.Hour()\n}\n\n// Minute returns minute value.\nfunc (t Time) Minute() int {\n\treturn t.time.Minute()\n}\n\n// Second returns second value.\nfunc (t Time) Second() int {\n\treturn t.time.Second()\n}\n\n// Microsecond returns microsecond value.\nfunc (t Time) Microsecond() int {\n\treturn t.time.Microsecond()\n}\n\n// Type returns type value.\nfunc (t Time) Type() uint8 {\n\treturn t.tp\n}\n\n// Fsp returns fsp value.\nfunc (t Time) Fsp() int8 {\n\treturn t.fsp\n}\n\n// SetType updates the type in Time.\n// Only DateTime/Date/Time is valid.\nfunc (t *Time) SetType(tp uint8) {\n\tt.tp = tp\n}\n\n// SetFsp updates the fsp in Time.\nfunc (t *Time) SetFsp(fsp int8) {\n\tt.fsp = fsp\n}\n\n// CoreTime returns core time.\nfunc (t Time) CoreTime() MysqlTime {\n\treturn t.time\n}\n\n// SetCoreTime updates core time.\nfunc (t *Time) SetCoreTime(mt MysqlTime) {\n\tt.time = mt\n}\n\n// GoTime converts Time to GoTime.\nfunc (t Time) GoTime(loc *gotime.Location) (gotime.Time, error) {\n\treturn t.time.GoTime(loc)\n}\n\n// Weekday returns weekday value.\nfunc (t Time) Weekday() gotime.Weekday {\n\treturn t.time.Weekday()\n}\n\n// YearWeek returns year and week.\nfunc (t Time) YearWeek(mode int) (int, int) {\n\treturn t.time.YearWeek(mode)\n}\n\n// Week returns week value.\nfunc (t Time) Week(mode int) int {\n\treturn t.time.Week(mode)\n}\n\n// YearDay returns year and day.\nfunc (t Time) YearDay() int {\n\treturn t.time.YearDay()\n}\n\n// CurrentTime returns current time with type tp.\nfunc CurrentTime(tp uint8) Time {\n\treturn Time{time: FromGoTime(gotime.Now()), tp: tp, fsp: 0}\n}\n\n// ConvertTimeZone converts the time value from one timezone to another.\n// The input time should be a valid timestamp.\nfunc (t *Time) ConvertTimeZone(from, to *gotime.Location) error {\n\tif !t.IsZero() {\n\t\traw, err := t.time.GoTime(from)\n\t\tif err != nil {\n\t\t\treturn errors.Trace(err)\n\t\t}\n\t\tconverted := raw.In(to)\n\t\tt.time = FromGoTime(converted)\n\t}\n\treturn nil\n}\n\nfunc (t Time) String() string {\n\tif t.tp == mysql.TypeDate {\n\t\t// We control the format, so no error would occur.\n\t\tstr, err := t.DateFormat(\"%Y-%m-%d\")\n\t\tterror.Log(errors.Trace(err))\n\t\treturn str\n\t}\n\n\tstr, err := t.DateFormat(\"%Y-%m-%d %H:%i:%s\")\n\tterror.Log(errors.Trace(err))\n\tif t.fsp > 0 {\n\t\ttmp := fmt.Sprintf(\".%06d\", t.time.Microsecond())\n\t\tstr = str + tmp[:1+t.fsp]\n\t}\n\n\treturn str\n}\n\n// IsZero returns a boolean indicating whether the time is equal to ZeroCoreTime.\nfunc (t Time) IsZero() bool {\n\treturn compareTime(t.time, ZeroCoreTime) == 0\n}\n\n// InvalidZero returns a boolean indicating whether the month or day is zero.\nfunc (t Time) InvalidZero() bool {\n\treturn t.time.Month() == 0 || t.time.Day() == 0\n}\n\nconst numberFormat = \"%Y%m%d%H%i%s\"\nconst dateFormat = \"%Y%m%d\"\n\n// ToNumber returns a formatted number.\n// e.g,\n// 2012-12-12 -> 20121212\n// 2012-12-12T10:10:10 -> 20121212101010\n// 2012-12-12T10:10:10.123456 -> 20121212101010.123456\nfunc (t Time) ToNumber() *MyDecimal {\n\tdec := new(MyDecimal)\n\tt.FillNumber(dec)\n\treturn dec\n}\n\n// FillNumber is the same as ToNumber,\n// but reuses input decimal instead of allocating one.\nfunc (t Time) FillNumber(dec *MyDecimal) {\n\tif t.IsZero() {\n\t\tdec.FromInt(0)\n\t\treturn\n\t}\n\n\t// Fix issue #1046\n\t// Prevents from converting 2012-12-12 to 20121212000000\n\tvar tfStr string\n\tif t.tp == mysql.TypeDate {\n\t\ttfStr = dateFormat\n\t} else {\n\t\ttfStr = numberFormat\n\t}\n\n\ts, err := t.DateFormat(tfStr)\n\tif err != nil {\n\t\tlog.Error(\"[fatal] never happen because we've control the format!\")\n\t}\n\n\tif t.fsp > 0 {\n\t\ts1 := fmt.Sprintf(\"%s.%06d\", s, t.time.Microsecond())\n\t\ts = s1[:len(s)+int(t.fsp)+1]\n\t}\n\t// We skip checking error here because time formatted string can be parsed certainly.\n\terr = dec.FromString([]byte(s))\n\tterror.Log(errors.Trace(err))\n}\n\n// Convert converts t with type tp.\nfunc (t Time) Convert(sc *stmtctx.StatementContext, tp uint8) (Time, error) {\n\tif t.tp == tp || t.IsZero() {\n\t\treturn Time{time: t.time, tp: tp, fsp: t.fsp}, nil\n\t}\n\n\tt1 := Time{time: t.time, tp: tp, fsp: t.fsp}\n\terr := t1.check(sc)\n\treturn t1, errors.Trace(err)\n}\n\n// ConvertToDuration converts mysql datetime, timestamp and date to mysql time type.\n// e.g,\n// 2012-12-12T10:10:10 -> 10:10:10\n// 2012-12-12 -> 0\nfunc (t Time) ConvertToDuration() (Duration, error) {\n\tif t.IsZero() {\n\t\treturn ZeroDuration, nil\n\t}\n\n\thour, minute, second := t.Clock()\n\tfrac := t.time.Microsecond() * 1000\n\n\td := gotime.Duration(hour*3600+minute*60+second)*gotime.Second + gotime.Duration(frac)\n\t// TODO: check convert validation\n\treturn Duration{Duration: d, Fsp: t.fsp}, nil\n}\n\n// Compare returns an integer comparing the time instant t to o.\n// If t is after o, returns 1, equal o, returns 0, before o, returns -1.\nfunc (t Time) Compare(o Time) int {\n\treturn compareTime(t.time, o.time)\n}\n\n// compareTime compare two MysqlTime.\n// return:\n//\n//\t0: if a == b\n//\t1: if a > b\n//\n// -1: if a < b\nfunc compareTime(a, b MysqlTime) int {\n\tta := datetimeToUint64(a)\n\ttb := datetimeToUint64(b)\n\n\tswitch {\n\tcase ta < tb:\n\t\treturn -1\n\tcase ta > tb:\n\t\treturn 1\n\t}\n\n\tswitch {\n\tcase a.Microsecond() < b.Microsecond():\n\t\treturn -1\n\tcase a.Microsecond() > b.Microsecond():\n\t\treturn 1\n\t}\n\n\treturn 0\n}\n\n// CompareString is like Compare,\n// but parses string to Time then compares.\nfunc (t Time) CompareString(sc *stmtctx.StatementContext, str string) (int, error) {\n\t// use MaxFsp to parse the string\n\to, err := ParseTime(sc, str, t.tp, MaxFsp)\n\tif err != nil {\n\t\treturn 0, errors.Trace(err)\n\t}\n\n\treturn t.Compare(o), nil\n}\n\n// roundTime rounds the time value according to digits count specified by fsp.\nfunc roundTime(t gotime.Time, fsp int8) gotime.Time {\n\td := gotime.Duration(math.Pow10(9 - int(fsp)))\n\treturn t.Round(d)\n}\n\n// RoundFrac rounds the fraction part of a time-type value according to `fsp`.\nfunc (t Time) RoundFrac(sc *stmtctx.StatementContext, fsp int8) (Time, error) {\n\tif t.tp == mysql.TypeDate || t.IsZero() {\n\t\t// date type has no fsp\n\t\treturn t, nil\n\t}\n\n\tfsp, err := CheckFsp(int(fsp))\n\tif err != nil {\n\t\treturn t, errors.Trace(err)\n\t}\n\n\tif fsp == t.fsp {\n\t\t// have same fsp\n\t\treturn t, nil\n\t}\n\n\tvar nt MysqlTime\n\tif t1, err := t.time.GoTime(sc.TimeZone); err == nil {\n\t\tt1 = roundTime(t1, fsp)\n\t\tnt = FromGoTime(t1)\n\t} else {\n\t\t// Take the hh:mm:ss part out to avoid handle month or day = 0.\n\t\thour, minute, second, microsecond := t.time.Hour(), t.time.Minute(), t.time.Second(), t.time.Microsecond()\n\t\tt1 := gotime.Date(1, 1, 1, hour, minute, second, microsecond*1000, sc.TimeZone)\n\t\tt2 := roundTime(t1, fsp)\n\t\thour, minute, second = t2.Clock()\n\t\tmicrosecond = t2.Nanosecond() / 1000\n\n\t\t// TODO: when hh:mm:ss overflow one day after rounding, it should be add to yy:mm:dd part,\n\t\t// but mm:dd may contain 0, it makes the code complex, so we ignore it here.\n\t\tif t2.Day()-1 > 0 {\n\t\t\treturn t, errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, t.String()))\n\t\t}\n\t\tnt = FromDate(t.time.Year(), t.time.Month(), t.time.Day(), hour, minute, second, microsecond)\n\t}\n\n\treturn Time{time: nt, tp: t.tp, fsp: fsp}, nil\n}\n\n// GetFsp gets the fsp of a string.\nfunc GetFsp(s string) int8 {\n\tindex := GetFracIndex(s)\n\tvar fsp int\n\tif index < 0 {\n\t\tfsp = 0\n\t} else {\n\t\tfsp = len(s) - index - 1\n\t}\n\n\tif fsp == len(s) {\n\t\tfsp = 0\n\t} else if fsp > 6 {\n\t\tfsp = 6\n\t}\n\treturn int8(fsp)\n}\n\n// GetFracIndex finds the last '.' for get fracStr, index = -1 means fracStr not found.\n// but for format like '2019.01.01 00:00:00', the index should be -1.\nfunc GetFracIndex(s string) (index int) {\n\tindex = -1\n\tfor i := len(s) - 1; i >= 0; i-- {\n\t\tif unicode.IsPunct(rune(s[i])) {\n\t\t\tif s[i] == '.' {\n\t\t\t\tindex = i\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn index\n}\n\n// RoundFrac rounds fractional seconds precision with new fsp and returns a new one.\n// We will use the “round half up” rule, e.g, >= 0.5 -> 1, < 0.5 -> 0,\n// so 2011:11:11 10:10:10.888888 round 0 -> 2011:11:11 10:10:11\n// and 2011:11:11 10:10:10.111111 round 0 -> 2011:11:11 10:10:10\nfunc RoundFrac(t gotime.Time, fsp int8) (gotime.Time, error) {\n\t_, err := CheckFsp(int(fsp))\n\tif err != nil {\n\t\treturn t, errors.Trace(err)\n\t}\n\treturn t.Round(gotime.Duration(math.Pow10(9-int(fsp))) * gotime.Nanosecond), nil\n}\n\n// TruncateFrac truncates fractional seconds precision with new fsp and returns a new one.\n// 2011:11:11 10:10:10.888888 round 0 -> 2011:11:11 10:10:10\n// 2011:11:11 10:10:10.111111 round 0 -> 2011:11:11 10:10:10\nfunc TruncateFrac(t gotime.Time, fsp int8) (gotime.Time, error) {\n\tif _, err := CheckFsp(int(fsp)); err != nil {\n\t\treturn t, err\n\t}\n\treturn t.Truncate(gotime.Duration(math.Pow10(9-int(fsp))) * gotime.Nanosecond), nil\n}\n\n// ToPackedUint encodes Time to a packed uint64 value.\n//\n//\t 1 bit  0\n//\t17 bits year*13+month   (year 0-9999, month 0-12)\n//\t 5 bits day             (0-31)\n//\t 5 bits hour            (0-23)\n//\t 6 bits minute          (0-59)\n//\t 6 bits second          (0-59)\n//\t24 bits microseconds    (0-999999)\n//\n//\tTotal: 64 bits = 8 bytes\n//\n//\t0YYYYYYY.YYYYYYYY.YYdddddh.hhhhmmmm.mmssssss.ffffffff.ffffffff.ffffffff\nfunc (t Time) ToPackedUint() (uint64, error) {\n\ttm := t.time\n\tif t.IsZero() {\n\t\treturn 0, nil\n\t}\n\tyear, month, day := tm.Year(), tm.Month(), tm.Day()\n\thour, minute, sec := tm.Hour(), tm.Minute(), tm.Second()\n\tymd := uint64(((year*13 + month) << 5) | day)\n\thms := uint64(hour<<12 | minute<<6 | sec)\n\tmicro := uint64(tm.Microsecond())\n\treturn ((ymd<<17 | hms) << 24) | micro, nil\n}\n\n// FromPackedUint decodes Time from a packed uint64 value.\nfunc (t *Time) FromPackedUint(packed uint64) error {\n\tif packed == 0 {\n\t\tt.time = ZeroCoreTime\n\t\treturn nil\n\t}\n\tymdhms := packed >> 24\n\tymd := ymdhms >> 17\n\tday := int(ymd & (1<<5 - 1))\n\tym := ymd >> 5\n\tmonth := int(ym % 13)\n\tyear := int(ym / 13)\n\n\thms := ymdhms & (1<<17 - 1)\n\tsecond := int(hms & (1<<6 - 1))\n\tminute := int((hms >> 6) & (1<<6 - 1))\n\thour := int(hms >> 12)\n\tmicrosec := int(packed % (1 << 24))\n\n\tt.time = FromDate(year, month, day, hour, minute, second, microsec)\n\n\treturn nil\n}\n\n// check whether t matches valid Time format.\n// If allowZeroInDate is false, it returns ErrZeroDate when month or day is zero.\n// FIXME: See https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_zero_in_date\nfunc (t *Time) check(sc *stmtctx.StatementContext) error {\n\tallowZeroInDate := false\n\tallowInvalidDate := false\n\t// We should avoid passing sc as nil here as far as possible.\n\tif sc != nil {\n\t\tallowZeroInDate = sc.IgnoreZeroInDate\n\t\tallowInvalidDate = sc.AllowInvalidDate\n\t}\n\tvar err error\n\tswitch t.tp {\n\tcase mysql.TypeTimestamp:\n\t\terr = checkTimestampType(sc, t.time)\n\tcase mysql.TypeDatetime, mysql.TypeDate:\n\t\terr = checkDatetimeType(t.time, allowZeroInDate, allowInvalidDate)\n\t}\n\treturn errors.Trace(err)\n}\n\n// Check if 't' is valid\nfunc (t *Time) Check(sc *stmtctx.StatementContext) error {\n\treturn t.check(sc)\n}\n\n// Sub subtracts t1 from t, returns a duration value.\n// Note that sub should not be done on different time types.\nfunc (t *Time) Sub(sc *stmtctx.StatementContext, t1 *Time) Duration {\n\tvar duration gotime.Duration\n\tif t.tp == mysql.TypeTimestamp && t1.tp == mysql.TypeTimestamp {\n\t\ta, err := t.time.GoTime(sc.TimeZone)\n\t\tterror.Log(errors.Trace(err))\n\t\tb, err := t1.time.GoTime(sc.TimeZone)\n\t\tterror.Log(errors.Trace(err))\n\t\tduration = a.Sub(b)\n\t} else {\n\t\tseconds, microseconds, neg := calcTimeDiff(t.time, t1.time, 1)\n\t\tduration = gotime.Duration(seconds*1e9 + microseconds*1e3)\n\t\tif neg {\n\t\t\tduration = -duration\n\t\t}\n\t}\n\n\tfsp := t.fsp\n\tif fsp < t1.fsp {\n\t\tfsp = t1.fsp\n\t}\n\treturn Duration{\n\t\tDuration: duration,\n\t\tFsp:      fsp,\n\t}\n}\n\n// Add adds d to t, returns the result time value.\nfunc (t *Time) Add(sc *stmtctx.StatementContext, d Duration) (Time, error) {\n\tsign, hh, mm, ss, micro := splitDuration(d.Duration)\n\tseconds, microseconds, _ := calcTimeDiff(t.time, FromDate(0, 0, 0, hh, mm, ss, micro), -sign)\n\tdays := seconds / secondsIn24Hour\n\tyear, month, day := getDateFromDaynr(uint(days))\n\tvar tm MysqlTime\n\ttm.year, tm.month, tm.day = uint16(year), uint8(month), uint8(day)\n\tcalcTimeFromSec(&tm, seconds%secondsIn24Hour, microseconds)\n\tif t.tp == mysql.TypeDate {\n\t\ttm.hour = 0\n\t\ttm.minute = 0\n\t\ttm.second = 0\n\t\ttm.microsecond = 0\n\t}\n\tfsp := t.fsp\n\tif d.Fsp > fsp {\n\t\tfsp = d.Fsp\n\t}\n\tret := Time{\n\t\ttime: tm,\n\t\ttp:   t.tp,\n\t\tfsp:  fsp,\n\t}\n\treturn ret, ret.Check(sc)\n}\n\n// TimestampDiff returns t2 - t1 where t1 and t2 are date or datetime expressions.\n// The unit for the result (an integer) is given by the unit argument.\n// The legal values for unit are \"YEAR\" \"QUARTER\" \"MONTH\" \"DAY\" \"HOUR\" \"SECOND\" and so on.\nfunc TimestampDiff(unit string, t1 Time, t2 Time) int64 {\n\treturn timestampDiff(unit, t1.time, t2.time)\n}\n\n// ParseDateFormat parses a formatted date string and returns separated components.\nfunc ParseDateFormat(format string) []string {\n\tformat = strings.TrimSpace(format)\n\n\tstart := 0\n\t// Initialize `seps` with capacity of 6. The input `format` is typically\n\t// a date time of the form \"2006-01-02 15:04:05\", which has 6 numeric parts\n\t// (the fractional second part is usually removed by `splitDateTime`).\n\t// Setting `seps`'s capacity to 6 avoids reallocation in this common case.\n\tseps := make([]string, 0, 6)\n\tfor i := 0; i < len(format); i++ {\n\t\t// Date format must start and end with number.\n\t\tif i == 0 || i == len(format)-1 {\n\t\t\tif !unicode.IsNumber(rune(format[i])) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// Separator is a single none-number char.\n\t\tif !unicode.IsNumber(rune(format[i])) {\n\t\t\tif !unicode.IsNumber(rune(format[i-1])) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tseps = append(seps, format[start:i])\n\t\t\tstart = i + 1\n\t\t}\n\n\t}\n\n\tseps = append(seps, format[start:])\n\treturn seps\n}\n\n// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html.\n// The only delimiter recognized between a date and time part and a fractional seconds part is the decimal point.\nfunc splitDateTime(format string) (seps []string, fracStr string) {\n\tindex := GetFracIndex(format)\n\tif index > 0 {\n\t\tfracStr = format[index+1:]\n\t\tformat = format[:index]\n\t}\n\n\tseps = ParseDateFormat(format)\n\treturn\n}\n\n// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html.\nfunc parseDatetime(sc *stmtctx.StatementContext, str string, fsp int8, isFloat bool) (Time, error) {\n\t// Try to split str with delimiter.\n\t// TODO: only punctuation can be the delimiter for date parts or time parts.\n\t// But only space and T can be the delimiter between the date and time part.\n\tvar (\n\t\tyear, month, day, hour, minute, second int\n\t\tfracStr                                string\n\t\thhmmss                                 bool\n\t\terr                                    error\n\t)\n\n\tseps, fracStr := splitDateTime(str)\n\tvar truncatedOrIncorrect bool\n\tswitch len(seps) {\n\tcase 1:\n\t\tl := len(seps[0])\n\t\tswitch l {\n\t\tcase 14: // No delimiter.\n\t\t\t// YYYYMMDDHHMMSS\n\t\t\t_, err = fmt.Sscanf(seps[0], \"%4d%2d%2d%2d%2d%2d\", &year, &month, &day, &hour, &minute, &second)\n\t\t\thhmmss = true\n\t\tcase 12: // YYMMDDHHMMSS\n\t\t\t_, err = fmt.Sscanf(seps[0], \"%2d%2d%2d%2d%2d%2d\", &year, &month, &day, &hour, &minute, &second)\n\t\t\tyear = adjustYear(year)\n\t\t\thhmmss = true\n\t\tcase 11: // YYMMDDHHMMS\n\t\t\t_, err = fmt.Sscanf(seps[0], \"%2d%2d%2d%2d%2d%1d\", &year, &month, &day, &hour, &minute, &second)\n\t\t\tyear = adjustYear(year)\n\t\t\thhmmss = true\n\t\tcase 10: // YYMMDDHHMM\n\t\t\t_, err = fmt.Sscanf(seps[0], \"%2d%2d%2d%2d%2d\", &year, &month, &day, &hour, &minute)\n\t\t\tyear = adjustYear(year)\n\t\tcase 9: // YYMMDDHHM\n\t\t\t_, err = fmt.Sscanf(seps[0], \"%2d%2d%2d%2d%1d\", &year, &month, &day, &hour, &minute)\n\t\t\tyear = adjustYear(year)\n\t\tcase 8: // YYYYMMDD\n\t\t\t_, err = fmt.Sscanf(seps[0], \"%4d%2d%2d\", &year, &month, &day)\n\t\tcase 6, 5:\n\t\t\t// YYMMDD && YYMMD\n\t\t\t_, err = fmt.Sscanf(seps[0], \"%2d%2d%2d\", &year, &month, &day)\n\t\t\tyear = adjustYear(year)\n\t\tdefault:\n\t\t\treturn ZeroDatetime, errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, str))\n\t\t}\n\t\tif l == 5 || l == 6 || l == 8 {\n\t\t\t// YYMMDD or YYYYMMDD\n\t\t\t// We must handle float => string => datetime, the difference is that fractional\n\t\t\t// part of float type is discarded directly, while fractional part of string type\n\t\t\t// is parsed to HH:MM:SS.\n\t\t\tif isFloat {\n\t\t\t\t// 20170118.123423 => 2017-01-18 00:00:00\n\t\t\t} else {\n\t\t\t\t// '20170118.123423' => 2017-01-18 12:34:23.234\n\t\t\t\tswitch len(fracStr) {\n\t\t\t\tcase 0:\n\t\t\t\tcase 1, 2:\n\t\t\t\t\t_, err = fmt.Sscanf(fracStr, \"%2d \", &hour)\n\t\t\t\tcase 3, 4:\n\t\t\t\t\t_, err = fmt.Sscanf(fracStr, \"%2d%2d \", &hour, &minute)\n\t\t\t\tdefault:\n\t\t\t\t\t_, err = fmt.Sscanf(fracStr, \"%2d%2d%2d \", &hour, &minute, &second)\n\t\t\t\t}\n\t\t\t\ttruncatedOrIncorrect = err != nil\n\t\t\t}\n\t\t}\n\t\tif l == 9 || l == 10 {\n\t\t\tif len(fracStr) == 0 {\n\t\t\t\tsecond = 0\n\t\t\t} else {\n\t\t\t\t_, err = fmt.Sscanf(fracStr, \"%2d \", &second)\n\t\t\t}\n\t\t\ttruncatedOrIncorrect = err != nil\n\t\t}\n\t\tif truncatedOrIncorrect && sc != nil {\n\t\t\tsc.AppendWarning(ErrTruncatedWrongVal.GenWithStackByArgs(\"datetime\", str))\n\t\t\terr = nil\n\t\t}\n\tcase 2:\n\t\t// YYYY-MM is not valid\n\t\tif len(fracStr) == 0 {\n\t\t\treturn ZeroDatetime, errors.Trace(ErrWrongValue.GenWithStackByArgs(DateTimeStr, str))\n\t\t}\n\n\t\t// YYYY-MM.DD, DD is treat as fracStr\n\t\terr = scanTimeArgs(append(seps, fracStr), &year, &month, &day)\n\t\tfracStr = \"\"\n\tcase 3:\n\t\t// YYYY-MM-DD\n\t\terr = scanTimeArgs(seps, &year, &month, &day)\n\tcase 4:\n\t\t// YYYY-MM-DD HH\n\t\terr = scanTimeArgs(seps, &year, &month, &day, &hour)\n\tcase 5:\n\t\t// YYYY-MM-DD HH-MM\n\t\terr = scanTimeArgs(seps, &year, &month, &day, &hour, &minute)\n\tcase 6:\n\t\t// We don't have fractional seconds part.\n\t\t// YYYY-MM-DD HH-MM-SS\n\t\terr = scanTimeArgs(seps, &year, &month, &day, &hour, &minute, &second)\n\t\thhmmss = true\n\tdefault:\n\t\treturn ZeroDatetime, errors.Trace(ErrWrongValue.GenWithStackByArgs(DateTimeStr, str))\n\t}\n\tif err != nil {\n\t\treturn ZeroDatetime, errors.Trace(err)\n\t}\n\n\t// If str is separated by delimiters, the first one is year, and if the year is 2 digit,\n\t// we should adjust it.\n\t// TODO: adjust year is very complex, now we only consider the simplest way.\n\tif len(seps[0]) == 2 {\n\t\tif year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 && second == 0 && fracStr == \"\" {\n\t\t\t// Skip a special case \"00-00-00\".\n\t\t} else {\n\t\t\tyear = adjustYear(year)\n\t\t}\n\t}\n\n\tvar microsecond int\n\tvar overflow bool\n\tif hhmmss {\n\t\t// If input string is \"20170118.999\", without hhmmss, fsp is meanless.\n\t\tmicrosecond, overflow, err = ParseFrac(fracStr, fsp)\n\t\tif err != nil {\n\t\t\treturn ZeroDatetime, errors.Trace(err)\n\t\t}\n\t}\n\n\ttmp := FromDate(year, month, day, hour, minute, second, microsecond)\n\tif overflow {\n\t\t// Convert to Go time and add 1 second, to handle input like 2017-01-05 08:40:59.575601\n\t\tt1, err := tmp.GoTime(sc.TimeZone)\n\t\tif err != nil {\n\t\t\treturn ZeroDatetime, errors.Trace(err)\n\t\t}\n\t\ttmp = FromGoTime(t1.Add(gotime.Second))\n\t}\n\n\tnt := Time{\n\t\ttime: tmp,\n\t\ttp:   mysql.TypeDatetime,\n\t\tfsp:  fsp}\n\n\treturn nt, nil\n}\n\nfunc scanTimeArgs(seps []string, args ...*int) error {\n\tif len(seps) != len(args) {\n\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, seps))\n\t}\n\n\tvar err error\n\tfor i, s := range seps {\n\t\t*args[i], err = strconv.Atoi(s)\n\t\tif err != nil {\n\t\t\treturn errors.Trace(err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// ParseYear parses a formatted string and returns a year number.\nfunc ParseYear(str string) (int16, error) {\n\tv, err := strconv.ParseInt(str, 10, 16)\n\tif err != nil {\n\t\treturn 0, errors.Trace(err)\n\t}\n\ty := int16(v)\n\n\tif len(str) == 4 {\n\t\t// Nothing to do.\n\t} else if len(str) == 2 || len(str) == 1 {\n\t\ty = int16(adjustYear(int(y)))\n\t} else {\n\t\treturn 0, errors.Trace(ErrInvalidYearFormat)\n\t}\n\n\tif y < MinYear || y > MaxYear {\n\t\treturn 0, errors.Trace(ErrInvalidYearFormat)\n\t}\n\n\treturn y, nil\n}\n\n// adjustYear adjusts year according to y.\n// See https://dev.mysql.com/doc/refman/5.7/en/two-digit-years.html\nfunc adjustYear(y int) int {\n\tif y >= 0 && y <= 69 {\n\t\ty = 2000 + y\n\t} else if y >= 70 && y <= 99 {\n\t\ty = 1900 + y\n\t}\n\treturn y\n}\n\n// AdjustYear is used for adjusting year and checking its validation.\nfunc AdjustYear(y int64, shouldAdjust bool) (int64, error) {\n\tif y == 0 && !shouldAdjust {\n\t\treturn y, nil\n\t}\n\ty = int64(adjustYear(int(y)))\n\tif y < int64(MinYear) || y > int64(MaxYear) {\n\t\treturn 0, errors.Trace(ErrInvalidYear)\n\t}\n\n\treturn y, nil\n}\n\n// NewDuration construct duration with time.\nfunc NewDuration(hour, minute, second, microsecond int, fsp int8) Duration {\n\treturn Duration{\n\t\tDuration: gotime.Duration(hour)*gotime.Hour + gotime.Duration(minute)*gotime.Minute + gotime.Duration(second)*gotime.Second,\n\t\tFsp:      fsp,\n\t}\n}\n\n// Duration is the type for MySQL TIME type.\ntype Duration struct {\n\tgotime.Duration\n\t// Fsp is short for Fractional Seconds Precision.\n\t// See http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html\n\tFsp int8\n}\n\n// Add adds d to d, returns a duration value.\nfunc (d Duration) Add(v Duration) (Duration, error) {\n\tif v == (Duration{}) {\n\t\treturn d, nil\n\t}\n\tdsum, err := AddInt64(int64(d.Duration), int64(v.Duration))\n\tif err != nil {\n\t\treturn Duration{}, errors.Trace(err)\n\t}\n\tif d.Fsp >= v.Fsp {\n\t\treturn Duration{Duration: gotime.Duration(dsum), Fsp: d.Fsp}, nil\n\t}\n\treturn Duration{Duration: gotime.Duration(dsum), Fsp: v.Fsp}, nil\n}\n\n// Sub subtracts d to d, returns a duration value.\nfunc (d Duration) Sub(v Duration) (Duration, error) {\n\tif v == (Duration{}) {\n\t\treturn d, nil\n\t}\n\tdsum, err := SubInt64(int64(d.Duration), int64(v.Duration))\n\tif err != nil {\n\t\treturn Duration{}, errors.Trace(err)\n\t}\n\tif d.Fsp >= v.Fsp {\n\t\treturn Duration{Duration: gotime.Duration(dsum), Fsp: d.Fsp}, nil\n\t}\n\treturn Duration{Duration: gotime.Duration(dsum), Fsp: v.Fsp}, nil\n}\n\n// String returns the time formatted using default TimeFormat and fsp.\nfunc (d Duration) String() string {\n\tvar buf bytes.Buffer\n\n\tsign, hours, minutes, seconds, fraction := splitDuration(d.Duration)\n\tif sign < 0 {\n\t\tbuf.WriteByte('-')\n\t}\n\n\tfmt.Fprintf(&buf, \"%02d:%02d:%02d\", hours, minutes, seconds)\n\tif d.Fsp > 0 {\n\t\tbuf.WriteString(\".\")\n\t\tbuf.WriteString(d.formatFrac(fraction))\n\t}\n\n\tp := buf.String()\n\n\treturn p\n}\n\nfunc (d Duration) formatFrac(frac int) string {\n\ts := fmt.Sprintf(\"%06d\", frac)\n\treturn s[0:d.Fsp]\n}\n\n// ToNumber changes duration to number format.\n// e.g,\n// 10:10:10 -> 101010\nfunc (d Duration) ToNumber() *MyDecimal {\n\tsign, hours, minutes, seconds, fraction := splitDuration(d.Duration)\n\tvar (\n\t\ts       string\n\t\tsignStr string\n\t)\n\n\tif sign < 0 {\n\t\tsignStr = \"-\"\n\t}\n\n\tif d.Fsp == 0 {\n\t\ts = fmt.Sprintf(\"%s%02d%02d%02d\", signStr, hours, minutes, seconds)\n\t} else {\n\t\ts = fmt.Sprintf(\"%s%02d%02d%02d.%s\", signStr, hours, minutes, seconds, d.formatFrac(fraction))\n\t}\n\n\t// We skip checking error here because time formatted string can be parsed certainly.\n\tdec := new(MyDecimal)\n\terr := dec.FromString([]byte(s))\n\tterror.Log(errors.Trace(err))\n\treturn dec\n}\n\n// ConvertToTime converts duration to Time.\n// Tp is TypeDatetime, TypeTimestamp and TypeDate.\nfunc (d Duration) ConvertToTime(sc *stmtctx.StatementContext, tp uint8) (Time, error) {\n\tyear, month, day := gotime.Now().In(sc.TimeZone).Date()\n\tsign, hour, minute, second, frac := splitDuration(d.Duration)\n\tdatePart := FromDate(year, int(month), day, 0, 0, 0, 0)\n\ttimePart := FromDate(0, 0, 0, hour, minute, second, frac)\n\tmixDateAndTime(&datePart, &timePart, sign < 0)\n\n\tt := Time{\n\t\ttime: datePart,\n\t\ttp:   mysql.TypeDatetime,\n\t\tfsp:  d.Fsp,\n\t}\n\treturn t.Convert(sc, tp)\n}\n\n// RoundFrac rounds fractional seconds precision with new fsp and returns a new one.\n// We will use the “round half up” rule, e.g, >= 0.5 -> 1, < 0.5 -> 0,\n// so 10:10:10.999999 round 0 -> 10:10:11\n// and 10:10:10.000000 round 0 -> 10:10:10\nfunc (d Duration) RoundFrac(fsp int8) (Duration, error) {\n\tfsp, err := CheckFsp(int(fsp))\n\tif err != nil {\n\t\treturn d, errors.Trace(err)\n\t}\n\n\tif fsp == d.Fsp {\n\t\treturn d, nil\n\t}\n\n\tn := gotime.Date(0, 0, 0, 0, 0, 0, 0, gotime.Local)\n\tnd := n.Add(d.Duration).Round(gotime.Duration(math.Pow10(9-int(fsp))) * gotime.Nanosecond).Sub(n)\n\treturn Duration{Duration: nd, Fsp: fsp}, nil\n}\n\n// Compare returns an integer comparing the Duration instant t to o.\n// If d is after o, returns 1, equal o, returns 0, before o, returns -1.\nfunc (d Duration) Compare(o Duration) int {\n\tif d.Duration > o.Duration {\n\t\treturn 1\n\t} else if d.Duration == o.Duration {\n\t\treturn 0\n\t} else {\n\t\treturn -1\n\t}\n}\n\n// CompareString is like Compare,\n// but parses str to Duration then compares.\nfunc (d Duration) CompareString(sc *stmtctx.StatementContext, str string) (int, error) {\n\t// use MaxFsp to parse the string\n\to, err := ParseDuration(sc, str, MaxFsp)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn d.Compare(o), nil\n}\n\n// Hour returns current hour.\n// e.g, hour(\"11:11:11\") -> 11\nfunc (d Duration) Hour() int {\n\t_, hour, _, _, _ := splitDuration(d.Duration)\n\treturn hour\n}\n\n// Minute returns current minute.\n// e.g, hour(\"11:11:11\") -> 11\nfunc (d Duration) Minute() int {\n\t_, _, minute, _, _ := splitDuration(d.Duration)\n\treturn minute\n}\n\n// Second returns current second.\n// e.g, hour(\"11:11:11\") -> 11\nfunc (d Duration) Second() int {\n\t_, _, _, second, _ := splitDuration(d.Duration)\n\treturn second\n}\n\n// MicroSecond returns current microsecond.\n// e.g, hour(\"11:11:11.11\") -> 110000\nfunc (d Duration) MicroSecond() int {\n\t_, _, _, _, frac := splitDuration(d.Duration)\n\treturn frac\n}\n\n// ParseDuration parses the time form a formatted string with a fractional seconds part,\n// returns the duration type Time value.\n// See http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html\nfunc ParseDuration(sc *stmtctx.StatementContext, str string, fsp int8) (Duration, error) {\n\tvar (\n\t\tday, hour, minute, second int\n\t\terr                       error\n\t\tsign                      = 0\n\t\tdayExists                 = false\n\t\torigStr                   = str\n\t)\n\n\tfsp, err = CheckFsp(int(fsp))\n\tif err != nil {\n\t\treturn ZeroDuration, errors.Trace(err)\n\t}\n\n\tif len(str) == 0 {\n\t\treturn ZeroDuration, nil\n\t} else if str[0] == '-' {\n\t\tstr = str[1:]\n\t\tsign = -1\n\t}\n\n\t// Time format may has day.\n\tif n := strings.IndexByte(str, ' '); n >= 0 {\n\t\tif day, err = strconv.Atoi(str[:n]); err == nil {\n\t\t\tdayExists = true\n\t\t}\n\t\tstr = str[n+1:]\n\t}\n\n\tvar (\n\t\tintegeralPart = str\n\t\tfracPart      int\n\t\toverflow      bool\n\t)\n\tif n := strings.IndexByte(str, '.'); n >= 0 {\n\t\t// It has fractional precision parts.\n\t\tfracStr := str[n+1:]\n\t\tfracPart, overflow, err = ParseFrac(fracStr, fsp)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, errors.Trace(err)\n\t\t}\n\t\tintegeralPart = str[0:n]\n\t}\n\n\t// It tries to split integeralPart with delimiter, time delimiter must be :\n\tseps := strings.Split(integeralPart, \":\")\n\n\tswitch len(seps) {\n\tcase 1:\n\t\tif dayExists {\n\t\t\thour, err = strconv.Atoi(seps[0])\n\t\t} else {\n\t\t\t// No delimiter.\n\t\t\tswitch len(integeralPart) {\n\t\t\tcase 7: // HHHMMSS\n\t\t\t\t_, err = fmt.Sscanf(integeralPart, \"%3d%2d%2d\", &hour, &minute, &second)\n\t\t\tcase 6: // HHMMSS\n\t\t\t\t_, err = fmt.Sscanf(integeralPart, \"%2d%2d%2d\", &hour, &minute, &second)\n\t\t\tcase 5: // HMMSS\n\t\t\t\t_, err = fmt.Sscanf(integeralPart, \"%1d%2d%2d\", &hour, &minute, &second)\n\t\t\tcase 4: // MMSS\n\t\t\t\t_, err = fmt.Sscanf(integeralPart, \"%2d%2d\", &minute, &second)\n\t\t\tcase 3: // MSS\n\t\t\t\t_, err = fmt.Sscanf(integeralPart, \"%1d%2d\", &minute, &second)\n\t\t\tcase 2: // SS\n\t\t\t\t_, err = fmt.Sscanf(integeralPart, \"%2d\", &second)\n\t\t\tcase 1: // 0S\n\t\t\t\t_, err = fmt.Sscanf(integeralPart, \"%1d\", &second)\n\t\t\tdefault: // Maybe contains date.\n\t\t\t\tt, err1 := ParseDatetime(sc, str)\n\t\t\t\tif err1 != nil {\n\t\t\t\t\treturn ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs(\"time\", origStr)\n\t\t\t\t}\n\t\t\t\tvar dur Duration\n\t\t\t\tdur, err1 = t.ConvertToDuration()\n\t\t\t\tif err1 != nil {\n\t\t\t\t\treturn ZeroDuration, errors.Trace(err)\n\t\t\t\t}\n\t\t\t\treturn dur.RoundFrac(fsp)\n\t\t\t}\n\t\t}\n\tcase 2:\n\t\t// HH:MM\n\t\t_, err = fmt.Sscanf(integeralPart, \"%2d:%2d\", &hour, &minute)\n\tcase 3:\n\t\t// Time format maybe HH:MM:SS or HHH:MM:SS.\n\t\t// See https://dev.mysql.com/doc/refman/5.7/en/time.html\n\t\tif len(seps[0]) == 3 {\n\t\t\t_, err = fmt.Sscanf(integeralPart, \"%3d:%2d:%2d\", &hour, &minute, &second)\n\t\t} else {\n\t\t\t_, err = fmt.Sscanf(integeralPart, \"%2d:%2d:%2d\", &hour, &minute, &second)\n\t\t}\n\tdefault:\n\t\treturn ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs(\"time\", origStr)\n\t}\n\n\tif terror.ErrorEqual(err, io.EOF) {\n\t\terr = ErrTruncatedWrongVal.GenWithStackByArgs(\"time\", origStr)\n\t}\n\tif err != nil {\n\t\treturn ZeroDuration, errors.Trace(err)\n\t}\n\n\tif overflow {\n\t\tsecond++\n\t\tfracPart = 0\n\t}\n\t// Invalid TIME values are converted to '00:00:00'.\n\t// See https://dev.mysql.com/doc/refman/5.7/en/time.html\n\tif minute >= 60 || second > 60 || (!overflow && second == 60) {\n\t\treturn ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs(\"time\", origStr)\n\t}\n\td := gotime.Duration(day*24*3600+hour*3600+minute*60+second)*gotime.Second + gotime.Duration(fracPart)*gotime.Microsecond\n\tif sign == -1 {\n\t\td = -d\n\t}\n\n\td, err = TruncateOverflowMySQLTime(d)\n\treturn Duration{Duration: d, Fsp: fsp}, errors.Trace(err)\n}\n\n// TruncateOverflowMySQLTime truncates d when it overflows, and returns ErrTruncatedWrongVal.\nfunc TruncateOverflowMySQLTime(d gotime.Duration) (gotime.Duration, error) {\n\tif d > MaxTime {\n\t\treturn MaxTime, ErrTruncatedWrongVal.GenWithStackByArgs(\"time\", d)\n\t} else if d < MinTime {\n\t\treturn MinTime, ErrTruncatedWrongVal.GenWithStackByArgs(\"time\", d)\n\t}\n\n\treturn d, nil\n}\n\nfunc splitDuration(t gotime.Duration) (int, int, int, int, int) {\n\tsign := 1\n\tif t < 0 {\n\t\tt = -t\n\t\tsign = -1\n\t}\n\n\thours := t / gotime.Hour\n\tt -= hours * gotime.Hour\n\tminutes := t / gotime.Minute\n\tt -= minutes * gotime.Minute\n\tseconds := t / gotime.Second\n\tt -= seconds * gotime.Second\n\tfraction := t / gotime.Microsecond\n\n\treturn sign, int(hours), int(minutes), int(seconds), int(fraction)\n}\n\nvar maxDaysInMonth = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}\n\nfunc getTime(sc *stmtctx.StatementContext, num int64, tp byte) (Time, error) {\n\ts1 := num / 1000000\n\ts2 := num - s1*1000000\n\n\tyear := int(s1 / 10000)\n\ts1 %= 10000\n\tmonth := int(s1 / 100)\n\tday := int(s1 % 100)\n\n\thour := int(s2 / 10000)\n\ts2 %= 10000\n\tminute := int(s2 / 100)\n\tsecond := int(s2 % 100)\n\n\tt := Time{\n\t\ttime: FromDate(year, month, day, hour, minute, second, 0),\n\t\ttp:   tp,\n\t\tfsp:  DefaultFsp,\n\t}\n\terr := t.check(sc)\n\treturn t, errors.Trace(err)\n}\n\n// parseDateTimeFromNum parses date time from num.\n// See number_to_datetime function.\n// https://github.com/mysql/mysql-server/blob/5.7/sql-common/my_time.c\nfunc parseDateTimeFromNum(sc *stmtctx.StatementContext, num int64) (Time, error) {\n\tt := ZeroDate\n\t// Check zero.\n\tif num == 0 {\n\t\treturn t, nil\n\t}\n\n\t// Check datetime type.\n\tif num >= 10000101000000 {\n\t\tt.tp = mysql.TypeDatetime\n\t\treturn getTime(sc, num, t.tp)\n\t}\n\n\t// Check MMDD.\n\tif num < 101 {\n\t\treturn t, errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, strconv.FormatInt(num, 10)))\n\t}\n\n\t// Adjust year\n\t// YYMMDD, year: 2000-2069\n\tif num <= (70-1)*10000+1231 {\n\t\tnum = (num + 20000000) * 1000000\n\t\treturn getTime(sc, num, t.tp)\n\t}\n\n\t// Check YYMMDD.\n\tif num < 70*10000+101 {\n\t\treturn t, errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, num))\n\t}\n\n\t// Adjust year\n\t// YYMMDD, year: 1970-1999\n\tif num <= 991231 {\n\t\tnum = (num + 19000000) * 1000000\n\t\treturn getTime(sc, num, t.tp)\n\t}\n\n\t// Check YYYYMMDD.\n\tif num < 10000101 {\n\t\treturn t, errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, num))\n\t}\n\n\t// Adjust hour/min/second.\n\tif num <= 99991231 {\n\t\tnum = num * 1000000\n\t\treturn getTime(sc, num, t.tp)\n\t}\n\n\t// Check MMDDHHMMSS.\n\tif num < 101000000 {\n\t\treturn t, errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, num))\n\t}\n\n\t// Set TypeDatetime type.\n\tt.tp = mysql.TypeDatetime\n\n\t// Adjust year\n\t// YYMMDDHHMMSS, 2000-2069\n\tif num <= 69*10000000000+1231235959 {\n\t\tnum = num + 20000000000000\n\t\treturn getTime(sc, num, t.tp)\n\t}\n\n\t// Check YYYYMMDDHHMMSS.\n\tif num < 70*10000000000+101000000 {\n\t\treturn t, errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, num))\n\t}\n\n\t// Adjust year\n\t// YYMMDDHHMMSS, 1970-1999\n\tif num <= 991231235959 {\n\t\tnum = num + 19000000000000\n\t\treturn getTime(sc, num, t.tp)\n\t}\n\n\treturn getTime(sc, num, t.tp)\n}\n\n// ParseTime parses a formatted string with type tp and specific fsp.\n// Type is TypeDatetime, TypeTimestamp and TypeDate.\n// Fsp is in range [0, 6].\n// MySQL supports many valid datetime format, but still has some limitation.\n// If delimiter exists, the date part and time part is separated by a space or T,\n// other punctuation character can be used as the delimiter between date parts or time parts.\n// If no delimiter, the format must be YYYYMMDDHHMMSS or YYMMDDHHMMSS\n// If we have fractional seconds part, we must use decimal points as the delimiter.\n// The valid datetime range is from '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'.\n// The valid timestamp range is from '1970-01-01 00:00:01.000000' to '2038-01-19 03:14:07.999999'.\n// The valid date range is from '1000-01-01' to '9999-12-31'\nfunc ParseTime(sc *stmtctx.StatementContext, str string, tp byte, fsp int8) (Time, error) {\n\treturn parseTime(sc, str, tp, fsp, false)\n}\n\n// ParseTimeFromFloatString is similar to ParseTime, except that it's used to parse a float converted string.\nfunc ParseTimeFromFloatString(sc *stmtctx.StatementContext, str string, tp byte, fsp int8) (Time, error) {\n\t// MySQL compatibility: 0.0 should not be converted to null, see #11203\n\tif len(str) >= 3 && str[:3] == \"0.0\" {\n\t\treturn Time{time: ZeroCoreTime, tp: tp}, nil\n\t}\n\treturn parseTime(sc, str, tp, fsp, true)\n}\n\nfunc parseTime(sc *stmtctx.StatementContext, str string, tp byte, fsp int8, isFloat bool) (Time, error) {\n\tfsp, err := CheckFsp(int(fsp))\n\tif err != nil {\n\t\treturn Time{time: ZeroCoreTime, tp: tp}, errors.Trace(err)\n\t}\n\n\tt, err := parseDatetime(sc, str, fsp, isFloat)\n\tif err != nil {\n\t\treturn Time{time: ZeroCoreTime, tp: tp}, errors.Trace(err)\n\t}\n\n\tt.tp = tp\n\tif err = t.check(sc); err != nil {\n\t\treturn Time{time: ZeroCoreTime, tp: tp}, errors.Trace(err)\n\t}\n\treturn t, nil\n}\n\n// ParseDatetime is a helper function wrapping ParseTime with datetime type and default fsp.\nfunc ParseDatetime(sc *stmtctx.StatementContext, str string) (Time, error) {\n\treturn ParseTime(sc, str, mysql.TypeDatetime, GetFsp(str))\n}\n\n// ParseTimestamp is a helper function wrapping ParseTime with timestamp type and default fsp.\nfunc ParseTimestamp(sc *stmtctx.StatementContext, str string) (Time, error) {\n\treturn ParseTime(sc, str, mysql.TypeTimestamp, GetFsp(str))\n}\n\n// ParseDate is a helper function wrapping ParseTime with date type.\nfunc ParseDate(sc *stmtctx.StatementContext, str string) (Time, error) {\n\t// date has no fractional seconds precision\n\treturn ParseTime(sc, str, mysql.TypeDate, MinFsp)\n}\n\n// ParseTimeFromNum parses a formatted int64,\n// returns the value which type is tp.\nfunc ParseTimeFromNum(sc *stmtctx.StatementContext, num int64, tp byte, fsp int8) (Time, error) {\n\t// MySQL compatibility: 0 should not be converted to null, see #11203\n\tif num == 0 {\n\t\treturn Time{time: ZeroCoreTime, tp: tp}, nil\n\t}\n\tfsp, err := CheckFsp(int(fsp))\n\tif err != nil {\n\t\treturn Time{time: ZeroCoreTime, tp: tp}, errors.Trace(err)\n\t}\n\n\tt, err := parseDateTimeFromNum(sc, num)\n\tif err != nil {\n\t\treturn Time{time: ZeroCoreTime, tp: tp}, errors.Trace(err)\n\t}\n\n\tt.tp = tp\n\tt.fsp = fsp\n\tif err := t.check(sc); err != nil {\n\t\treturn Time{time: ZeroCoreTime, tp: tp}, errors.Trace(err)\n\t}\n\treturn t, nil\n}\n\n// ParseDatetimeFromNum is a helper function wrapping ParseTimeFromNum with datetime type and default fsp.\nfunc ParseDatetimeFromNum(sc *stmtctx.StatementContext, num int64) (Time, error) {\n\treturn ParseTimeFromNum(sc, num, mysql.TypeDatetime, DefaultFsp)\n}\n\n// ParseTimestampFromNum is a helper function wrapping ParseTimeFromNum with timestamp type and default fsp.\nfunc ParseTimestampFromNum(sc *stmtctx.StatementContext, num int64) (Time, error) {\n\treturn ParseTimeFromNum(sc, num, mysql.TypeTimestamp, DefaultFsp)\n}\n\n// ParseDateFromNum is a helper function wrapping ParseTimeFromNum with date type.\nfunc ParseDateFromNum(sc *stmtctx.StatementContext, num int64) (Time, error) {\n\t// date has no fractional seconds precision\n\treturn ParseTimeFromNum(sc, num, mysql.TypeDate, MinFsp)\n}\n\n// TimeFromDays Converts a day number to a date.\nfunc TimeFromDays(num int64) Time {\n\tif num < 0 {\n\t\treturn Time{\n\t\t\ttime: FromDate(0, 0, 0, 0, 0, 0, 0),\n\t\t\ttp:   mysql.TypeDate,\n\t\t\tfsp:  0,\n\t\t}\n\t}\n\tyear, month, day := getDateFromDaynr(uint(num))\n\n\treturn Time{\n\t\ttime: FromDate(int(year), int(month), int(day), 0, 0, 0, 0),\n\t\ttp:   mysql.TypeDate,\n\t\tfsp:  0,\n\t}\n}\n\nfunc checkDateType(t MysqlTime, allowZeroInDate, allowInvalidDate bool) error {\n\tyear, month, day := t.Year(), t.Month(), t.Day()\n\tif year == 0 && month == 0 && day == 0 {\n\t\treturn nil\n\t}\n\n\tif !allowZeroInDate && (month == 0 || day == 0) {\n\t\treturn ErrWrongValue.GenWithStackByArgs(DateTimeStr, fmt.Sprintf(\"%04d-%02d-%02d\", year, month, day))\n\t}\n\n\tif err := checkDateRange(t); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\n\tif err := checkMonthDay(year, month, day, allowInvalidDate); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\n\treturn nil\n}\n\nfunc checkDateRange(t MysqlTime) error {\n\t// Oddly enough, MySQL document says date range should larger than '1000-01-01',\n\t// but we can insert '0001-01-01' actually.\n\tif t.Year() < 0 || t.Month() < 0 || t.Day() < 0 {\n\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, t))\n\t}\n\tif compareTime(t, MaxDatetime) > 0 {\n\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, t))\n\t}\n\treturn nil\n}\n\nfunc checkMonthDay(year, month, day int, allowInvalidDate bool) error {\n\tif month < 0 || month > 12 {\n\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(DateTimeStr, fmt.Sprintf(\"%d-%d-%d\", year, month, day)))\n\t}\n\n\tmaxDay := 31\n\tif !allowInvalidDate {\n\t\tif month > 0 {\n\t\t\tmaxDay = maxDaysInMonth[month-1]\n\t\t}\n\t\tif month == 2 && !isLeapYear(uint16(year)) {\n\t\t\tmaxDay = 28\n\t\t}\n\t}\n\n\tif day < 0 || day > maxDay {\n\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(DateTimeStr, fmt.Sprintf(\"%d-%d-%d\", year, month, day)))\n\t}\n\treturn nil\n}\n\nfunc checkTimestampType(sc *stmtctx.StatementContext, t MysqlTime) error {\n\tif compareTime(t, ZeroCoreTime) == 0 {\n\t\treturn nil\n\t}\n\n\tif sc == nil {\n\t\treturn errors.New(\"statementContext is required during checkTimestampType\")\n\t}\n\n\tvar checkTime MysqlTime\n\tif sc.TimeZone != BoundTimezone {\n\t\tconvertTime := Time{time: t, tp: mysql.TypeTimestamp}\n\t\terr := convertTime.ConvertTimeZone(sc.TimeZone, BoundTimezone)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcheckTime = convertTime.time\n\t} else {\n\t\tcheckTime = t\n\t}\n\tif compareTime(checkTime, MaxTimestamp.time) > 0 || compareTime(checkTime, MinTimestamp.time) < 0 {\n\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, t))\n\t}\n\n\tif _, err := t.GoTime(sc.TimeZone); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\n\treturn nil\n}\n\nfunc checkDatetimeType(t MysqlTime, allowZeroInDate, allowInvalidDate bool) error {\n\tif err := checkDateType(t, allowZeroInDate, allowInvalidDate); err != nil {\n\t\treturn errors.Trace(err)\n\t}\n\n\thour, minute, second := t.Hour(), t.Minute(), t.Second()\n\tif hour < 0 || hour >= 24 {\n\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, hour))\n\t}\n\tif minute < 0 || minute >= 60 {\n\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, minute))\n\t}\n\tif second < 0 || second >= 60 {\n\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, second))\n\t}\n\n\treturn nil\n}\n\n// ExtractDatetimeNum extracts time value number from datetime unit and format.\nfunc ExtractDatetimeNum(t *Time, unit string) (int64, error) {\n\t// TODO: Consider time_zone variable.\n\tswitch strings.ToUpper(unit) {\n\tcase \"DAY\":\n\t\treturn int64(t.time.Day()), nil\n\tcase \"WEEK\":\n\t\tweek := t.time.Week(0)\n\t\treturn int64(week), nil\n\tcase \"MONTH\":\n\t\treturn int64(t.time.Month()), nil\n\tcase \"QUARTER\":\n\t\tm := int64(t.time.Month())\n\t\t// 1 - 3 -> 1\n\t\t// 4 - 6 -> 2\n\t\t// 7 - 9 -> 3\n\t\t// 10 - 12 -> 4\n\t\treturn (m + 2) / 3, nil\n\tcase \"YEAR\":\n\t\treturn int64(t.time.Year()), nil\n\tcase \"DAY_MICROSECOND\":\n\t\th, m, s := t.Clock()\n\t\td := t.time.Day()\n\t\treturn int64(d*1000000+h*10000+m*100+s)*1000000 + int64(t.time.Microsecond()), nil\n\tcase \"DAY_SECOND\":\n\t\th, m, s := t.Clock()\n\t\td := t.time.Day()\n\t\treturn int64(d)*1000000 + int64(h)*10000 + int64(m)*100 + int64(s), nil\n\tcase \"DAY_MINUTE\":\n\t\th, m, _ := t.Clock()\n\t\td := t.time.Day()\n\t\treturn int64(d)*10000 + int64(h)*100 + int64(m), nil\n\tcase \"DAY_HOUR\":\n\t\th, _, _ := t.Clock()\n\t\td := t.time.Day()\n\t\treturn int64(d)*100 + int64(h), nil\n\tcase \"YEAR_MONTH\":\n\t\ty, m := t.time.Year(), t.time.Month()\n\t\treturn int64(y)*100 + int64(m), nil\n\tdefault:\n\t\treturn 0, errors.Errorf(\"invalid unit %s\", unit)\n\t}\n}\n\n// ExtractDurationNum extracts duration value number from duration unit and format.\nfunc ExtractDurationNum(d *Duration, unit string) (int64, error) {\n\tswitch strings.ToUpper(unit) {\n\tcase \"MICROSECOND\":\n\t\treturn int64(d.MicroSecond()), nil\n\tcase \"SECOND\":\n\t\treturn int64(d.Second()), nil\n\tcase \"MINUTE\":\n\t\treturn int64(d.Minute()), nil\n\tcase \"HOUR\":\n\t\treturn int64(d.Hour()), nil\n\tcase \"SECOND_MICROSECOND\":\n\t\treturn int64(d.Second())*1000000 + int64(d.MicroSecond()), nil\n\tcase \"MINUTE_MICROSECOND\":\n\t\treturn int64(d.Minute())*100000000 + int64(d.Second())*1000000 + int64(d.MicroSecond()), nil\n\tcase \"MINUTE_SECOND\":\n\t\treturn int64(d.Minute()*100 + d.Second()), nil\n\tcase \"HOUR_MICROSECOND\":\n\t\treturn int64(d.Hour())*10000000000 + int64(d.Minute())*100000000 + int64(d.Second())*1000000 + int64(d.MicroSecond()), nil\n\tcase \"HOUR_SECOND\":\n\t\treturn int64(d.Hour())*10000 + int64(d.Minute())*100 + int64(d.Second()), nil\n\tcase \"HOUR_MINUTE\":\n\t\treturn int64(d.Hour())*100 + int64(d.Minute()), nil\n\tdefault:\n\t\treturn 0, errors.Errorf(\"invalid unit %s\", unit)\n\t}\n}\n\n// parseSingleTimeValue parse the format according the given unit. If we set strictCheck true, we'll check whether\n// the converted value not exceed the range of MySQL's TIME type.\n// The first four returned values are year, month, day and nanosecond.\nfunc parseSingleTimeValue(unit string, format string, strictCheck bool) (int64, int64, int64, int64, error) {\n\t// Format is a preformatted number, it format should be A[.[B]].\n\tdecimalPointPos := strings.IndexRune(format, '.')\n\tif decimalPointPos == -1 {\n\t\tdecimalPointPos = len(format)\n\t}\n\tsign := int64(1)\n\tif len(format) > 0 && format[0] == '-' {\n\t\tsign = int64(-1)\n\t}\n\tiv, err := strconv.ParseInt(format[0:decimalPointPos], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, format)\n\t}\n\triv := iv // Rounded integer value\n\n\tdv := int64(0)\n\tlf := len(format) - 1\n\t// Has fraction part\n\tif decimalPointPos < lf {\n\t\tif lf-decimalPointPos >= 6 {\n\t\t\t// MySQL rounds down to 1e-6.\n\t\t\tif dv, err = strconv.ParseInt(format[decimalPointPos+1:decimalPointPos+7], 10, 64); err != nil {\n\t\t\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, format)\n\t\t\t}\n\t\t} else {\n\t\t\tif dv, err = strconv.ParseInt(format[decimalPointPos+1:]+\"000000\"[:6-(lf-decimalPointPos)], 10, 64); err != nil {\n\t\t\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, format)\n\t\t\t}\n\t\t}\n\t\tif dv >= 500000 { // Round up, and we should keep 6 digits for microsecond, so dv should in [000000, 999999].\n\t\t\triv += sign\n\t\t}\n\t\tif unit != \"SECOND\" {\n\t\t\terr = ErrTruncatedWrongVal.GenWithStackByArgs(format)\n\t\t}\n\t\tdv *= sign\n\t}\n\tswitch strings.ToUpper(unit) {\n\tcase \"MICROSECOND\":\n\t\tif strictCheck && tidbMath.Abs(riv) > TimeMaxValueSeconds*1000 {\n\t\t\treturn 0, 0, 0, 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t\t}\n\t\tdayCount := riv / int64(GoDurationDay/gotime.Microsecond)\n\t\triv %= int64(GoDurationDay / gotime.Microsecond)\n\t\treturn 0, 0, dayCount, riv * int64(gotime.Microsecond), err\n\tcase \"SECOND\":\n\t\tif strictCheck && tidbMath.Abs(iv) > TimeMaxValueSeconds {\n\t\t\treturn 0, 0, 0, 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t\t}\n\t\tdayCount := iv / int64(GoDurationDay/gotime.Second)\n\t\tiv %= int64(GoDurationDay / gotime.Second)\n\t\treturn 0, 0, dayCount, iv*int64(gotime.Second) + dv*int64(gotime.Microsecond), err\n\tcase \"MINUTE\":\n\t\tif strictCheck && tidbMath.Abs(riv) > TimeMaxHour*60+TimeMaxMinute {\n\t\t\treturn 0, 0, 0, 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t\t}\n\t\tdayCount := riv / int64(GoDurationDay/gotime.Minute)\n\t\triv %= int64(GoDurationDay / gotime.Minute)\n\t\treturn 0, 0, dayCount, riv * int64(gotime.Minute), err\n\tcase \"HOUR\":\n\t\tif strictCheck && tidbMath.Abs(riv) > TimeMaxHour {\n\t\t\treturn 0, 0, 0, 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t\t}\n\t\tdayCount := riv / 24\n\t\triv %= 24\n\t\treturn 0, 0, dayCount, riv * int64(gotime.Hour), err\n\tcase \"DAY\":\n\t\tif strictCheck && tidbMath.Abs(riv) > TimeMaxHour/24 {\n\t\t\treturn 0, 0, 0, 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t\t}\n\t\treturn 0, 0, riv, 0, err\n\tcase \"WEEK\":\n\t\tif strictCheck && 7*tidbMath.Abs(riv) > TimeMaxHour/24 {\n\t\t\treturn 0, 0, 0, 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t\t}\n\t\treturn 0, 0, 7 * riv, 0, err\n\tcase \"MONTH\":\n\t\tif strictCheck && tidbMath.Abs(riv) > 1 {\n\t\t\treturn 0, 0, 0, 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t\t}\n\t\treturn 0, riv, 0, 0, err\n\tcase \"QUARTER\":\n\t\tif strictCheck {\n\t\t\treturn 0, 0, 0, 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t\t}\n\t\treturn 0, 3 * riv, 0, 0, err\n\tcase \"YEAR\":\n\t\tif strictCheck {\n\t\t\treturn 0, 0, 0, 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t\t}\n\t\treturn riv, 0, 0, 0, err\n\t}\n\n\treturn 0, 0, 0, 0, errors.Errorf(\"invalid singel timeunit - %s\", unit)\n}\n\n// parseTimeValue gets years, months, days, nanoseconds from a string\n// nanosecond will not exceed length of single day\n// MySQL permits any punctuation delimiter in the expr format.\n// See https://dev.mysql.com/doc/refman/8.0/en/expressions.html#temporal-intervals\nfunc parseTimeValue(format string, index, cnt int) (int64, int64, int64, int64, error) {\n\tneg := false\n\toriginalFmt := format\n\tformat = strings.TrimSpace(format)\n\tif len(format) > 0 && format[0] == '-' {\n\t\tneg = true\n\t\tformat = format[1:]\n\t}\n\tfields := make([]string, TimeValueCnt)\n\tfor i := range fields {\n\t\tfields[i] = \"0\"\n\t}\n\tmatches := numericRegex.FindAllString(format, -1)\n\tif len(matches) > cnt {\n\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, originalFmt)\n\t}\n\tfor i := range matches {\n\t\tif neg {\n\t\t\tfields[index] = \"-\" + matches[len(matches)-1-i]\n\t\t} else {\n\t\t\tfields[index] = matches[len(matches)-1-i]\n\t\t}\n\t\tindex--\n\t}\n\n\tyears, err := strconv.ParseInt(fields[YearIndex], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, originalFmt)\n\t}\n\tmonths, err := strconv.ParseInt(fields[MonthIndex], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, originalFmt)\n\t}\n\tdays, err := strconv.ParseInt(fields[DayIndex], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, originalFmt)\n\t}\n\n\thours, err := strconv.ParseInt(fields[HourIndex], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, originalFmt)\n\t}\n\tminutes, err := strconv.ParseInt(fields[MinuteIndex], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, originalFmt)\n\t}\n\tseconds, err := strconv.ParseInt(fields[SecondIndex], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, originalFmt)\n\t}\n\tmicroseconds, err := strconv.ParseInt(alignFrac(fields[MicrosecondIndex], int(MaxFsp)), 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, 0, 0, ErrWrongValue.GenWithStackByArgs(DateTimeStr, originalFmt)\n\t}\n\tseconds = hours*3600 + minutes*60 + seconds\n\tdays += seconds / (3600 * 24)\n\tseconds %= 3600 * 24\n\treturn years, months, days, seconds*int64(gotime.Second) + microseconds*int64(gotime.Microsecond), nil\n}\n\nfunc parseAndValidateDurationValue(format string, index, cnt int) (int64, error) {\n\tyear, month, day, nano, err := parseTimeValue(format, index, cnt)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif year != 0 || month != 0 || tidbMath.Abs(day) > TimeMaxHour/24 {\n\t\treturn 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t}\n\tdur := day*int64(GoDurationDay) + nano\n\tif tidbMath.Abs(dur) > int64(MaxTime) {\n\t\treturn 0, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\t}\n\treturn dur, nil\n}\n\n// ParseDurationValue parses time value from time unit and format.\n// Returns y years m months d days + n nanoseconds\n// Nanoseconds will no longer than one day.\nfunc ParseDurationValue(unit string, format string) (y int64, m int64, d int64, n int64, _ error) {\n\tswitch strings.ToUpper(unit) {\n\tcase \"MICROSECOND\", \"SECOND\", \"MINUTE\", \"HOUR\", \"DAY\", \"WEEK\", \"MONTH\", \"QUARTER\", \"YEAR\":\n\t\treturn parseSingleTimeValue(unit, format, false)\n\tcase \"SECOND_MICROSECOND\":\n\t\treturn parseTimeValue(format, MicrosecondIndex, SecondMicrosecondMaxCnt)\n\tcase \"MINUTE_MICROSECOND\":\n\t\treturn parseTimeValue(format, MicrosecondIndex, MinuteMicrosecondMaxCnt)\n\tcase \"MINUTE_SECOND\":\n\t\treturn parseTimeValue(format, SecondIndex, MinuteSecondMaxCnt)\n\tcase \"HOUR_MICROSECOND\":\n\t\treturn parseTimeValue(format, MicrosecondIndex, HourMicrosecondMaxCnt)\n\tcase \"HOUR_SECOND\":\n\t\treturn parseTimeValue(format, SecondIndex, HourSecondMaxCnt)\n\tcase \"HOUR_MINUTE\":\n\t\treturn parseTimeValue(format, MinuteIndex, HourMinuteMaxCnt)\n\tcase \"DAY_MICROSECOND\":\n\t\treturn parseTimeValue(format, MicrosecondIndex, DayMicrosecondMaxCnt)\n\tcase \"DAY_SECOND\":\n\t\treturn parseTimeValue(format, SecondIndex, DaySecondMaxCnt)\n\tcase \"DAY_MINUTE\":\n\t\treturn parseTimeValue(format, MinuteIndex, DayMinuteMaxCnt)\n\tcase \"DAY_HOUR\":\n\t\treturn parseTimeValue(format, HourIndex, DayHourMaxCnt)\n\tcase \"YEAR_MONTH\":\n\t\treturn parseTimeValue(format, MonthIndex, YearMonthMaxCnt)\n\tdefault:\n\t\treturn 0, 0, 0, 0, errors.Errorf(\"invalid single timeunit - %s\", unit)\n\t}\n}\n\n// ExtractDurationValue extract the value from format to Duration.\nfunc ExtractDurationValue(unit string, format string) (Duration, error) {\n\tunit = strings.ToUpper(unit)\n\tswitch unit {\n\tcase \"MICROSECOND\", \"SECOND\", \"MINUTE\", \"HOUR\", \"DAY\", \"WEEK\", \"MONTH\", \"QUARTER\", \"YEAR\":\n\t\t_, month, day, nano, err := parseSingleTimeValue(unit, format, true)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\tdur := Duration{Duration: gotime.Duration((month*30+day)*int64(GoDurationDay) + nano)}\n\t\tif unit == \"MICROSECOND\" {\n\t\t\tdur.Fsp = MaxFsp\n\t\t}\n\t\treturn dur, err\n\tcase \"SECOND_MICROSECOND\":\n\t\td, err := parseAndValidateDurationValue(format, MicrosecondIndex, SecondMicrosecondMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\treturn Duration{Duration: gotime.Duration(d), Fsp: MaxFsp}, nil\n\tcase \"MINUTE_MICROSECOND\":\n\t\td, err := parseAndValidateDurationValue(format, MicrosecondIndex, MinuteMicrosecondMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\treturn Duration{Duration: gotime.Duration(d), Fsp: MaxFsp}, nil\n\tcase \"MINUTE_SECOND\":\n\t\td, err := parseAndValidateDurationValue(format, SecondIndex, MinuteSecondMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\treturn Duration{Duration: gotime.Duration(d), Fsp: MaxFsp}, nil\n\tcase \"HOUR_MICROSECOND\":\n\t\td, err := parseAndValidateDurationValue(format, MicrosecondIndex, HourMicrosecondMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\treturn Duration{Duration: gotime.Duration(d), Fsp: MaxFsp}, nil\n\tcase \"HOUR_SECOND\":\n\t\td, err := parseAndValidateDurationValue(format, SecondIndex, HourSecondMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\treturn Duration{Duration: gotime.Duration(d), Fsp: MaxFsp}, nil\n\tcase \"HOUR_MINUTE\":\n\t\td, err := parseAndValidateDurationValue(format, MinuteIndex, HourMinuteMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\treturn Duration{Duration: gotime.Duration(d), Fsp: 0}, nil\n\tcase \"DAY_MICROSECOND\":\n\t\td, err := parseAndValidateDurationValue(format, MicrosecondIndex, DayMicrosecondMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\treturn Duration{Duration: gotime.Duration(d), Fsp: MaxFsp}, nil\n\tcase \"DAY_SECOND\":\n\t\td, err := parseAndValidateDurationValue(format, SecondIndex, DaySecondMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\treturn Duration{Duration: gotime.Duration(d), Fsp: MaxFsp}, nil\n\tcase \"DAY_MINUTE\":\n\t\td, err := parseAndValidateDurationValue(format, MinuteIndex, DayMinuteMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\treturn Duration{Duration: gotime.Duration(d), Fsp: 0}, nil\n\tcase \"DAY_HOUR\":\n\t\td, err := parseAndValidateDurationValue(format, HourIndex, DayHourMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\treturn Duration{Duration: gotime.Duration(d), Fsp: 0}, nil\n\tcase \"YEAR_MONTH\":\n\t\t_, err := parseAndValidateDurationValue(format, MonthIndex, YearMonthMaxCnt)\n\t\tif err != nil {\n\t\t\treturn ZeroDuration, err\n\t\t}\n\t\t// MONTH must exceed the limit of mysql's duration. So just returns overflow error.\n\t\treturn ZeroDuration, ErrDatetimeFunctionOverflow.GenWithStackByArgs(\"time\")\n\tdefault:\n\t\treturn ZeroDuration, errors.Errorf(\"invalid single timeunit - %s\", unit)\n\t}\n}\n\n// IsClockUnit returns true when unit is interval unit with hour, minute or second.\nfunc IsClockUnit(unit string) bool {\n\tswitch strings.ToUpper(unit) {\n\tcase \"MICROSECOND\", \"SECOND\", \"MINUTE\", \"HOUR\",\n\t\t\"SECOND_MICROSECOND\", \"MINUTE_MICROSECOND\", \"MINUTE_SECOND\",\n\t\t\"HOUR_MICROSECOND\", \"HOUR_SECOND\", \"HOUR_MINUTE\",\n\t\t\"DAY_MICROSECOND\", \"DAY_SECOND\", \"DAY_MINUTE\", \"DAY_HOUR\":\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// IsDateFormat returns true when the specified time format could contain only date.\nfunc IsDateFormat(format string) bool {\n\tformat = strings.TrimSpace(format)\n\tseps := ParseDateFormat(format)\n\tlength := len(format)\n\tswitch len(seps) {\n\tcase 1:\n\t\tif (length == 8) || (length == 6) {\n\t\t\treturn true\n\t\t}\n\tcase 3:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// ParseTimeFromInt64 parses mysql time value from int64.\nfunc ParseTimeFromInt64(sc *stmtctx.StatementContext, num int64) (Time, error) {\n\treturn parseDateTimeFromNum(sc, num)\n}\n\n// DateFormat returns a textual representation of the time value formatted\n// according to layout.\n// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format\nfunc (t Time) DateFormat(layout string) (string, error) {\n\tvar buf bytes.Buffer\n\tinPatternMatch := false\n\tfor _, b := range layout {\n\t\tif inPatternMatch {\n\t\t\tif err := t.convertDateFormat(b, &buf); err != nil {\n\t\t\t\treturn \"\", errors.Trace(err)\n\t\t\t}\n\t\t\tinPatternMatch = false\n\t\t\tcontinue\n\t\t}\n\n\t\t// It's not in pattern match now.\n\t\tif b == '%' {\n\t\t\tinPatternMatch = true\n\t\t} else {\n\t\t\tbuf.WriteRune(b)\n\t\t}\n\t}\n\treturn buf.String(), nil\n}\n\nvar abbrevWeekdayName = []string{\n\t\"Sun\", \"Mon\", \"Tue\",\n\t\"Wed\", \"Thu\", \"Fri\", \"Sat\",\n}\n\nfunc (t Time) convertDateFormat(b rune, buf *bytes.Buffer) error {\n\tswitch b {\n\tcase 'b':\n\t\tm := t.time.Month()\n\t\tif m == 0 || m > 12 {\n\t\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, m))\n\t\t}\n\t\tbuf.WriteString(MonthNames[m-1][:3])\n\tcase 'M':\n\t\tm := t.time.Month()\n\t\tif m == 0 || m > 12 {\n\t\t\treturn errors.Trace(ErrWrongValue.GenWithStackByArgs(TimeStr, m))\n\t\t}\n\t\tbuf.WriteString(MonthNames[m-1])\n\tcase 'm':\n\t\tbuf.WriteString(FormatIntWidthN(t.time.Month(), 2))\n\tcase 'c':\n\t\tbuf.WriteString(strconv.FormatInt(int64(t.time.Month()), 10))\n\tcase 'D':\n\t\tbuf.WriteString(strconv.FormatInt(int64(t.time.Day()), 10))\n\t\tbuf.WriteString(abbrDayOfMonth(t.time.Day()))\n\tcase 'd':\n\t\tbuf.WriteString(FormatIntWidthN(t.time.Day(), 2))\n\tcase 'e':\n\t\tbuf.WriteString(strconv.FormatInt(int64(t.time.Day()), 10))\n\tcase 'j':\n\t\tfmt.Fprintf(buf, \"%03d\", t.time.YearDay())\n\tcase 'H':\n\t\tbuf.WriteString(FormatIntWidthN(t.time.Hour(), 2))\n\tcase 'k':\n\t\tbuf.WriteString(strconv.FormatInt(int64(t.time.Hour()), 10))\n\tcase 'h', 'I':\n\t\tt := t.time.Hour()\n\t\tif t%12 == 0 {\n\t\t\tbuf.WriteString(\"12\")\n\t\t} else {\n\t\t\tbuf.WriteString(FormatIntWidthN(t%12, 2))\n\t\t}\n\tcase 'l':\n\t\tt := t.time.Hour()\n\t\tif t%12 == 0 {\n\t\t\tbuf.WriteString(\"12\")\n\t\t} else {\n\t\t\tbuf.WriteString(strconv.FormatInt(int64(t%12), 10))\n\t\t}\n\tcase 'i':\n\t\tbuf.WriteString(FormatIntWidthN(t.time.Minute(), 2))\n\tcase 'p':\n\t\thour := t.time.Hour()\n\t\tif hour/12%2 == 0 {\n\t\t\tbuf.WriteString(\"AM\")\n\t\t} else {\n\t\t\tbuf.WriteString(\"PM\")\n\t\t}\n\tcase 'r':\n\t\th := t.time.Hour()\n\t\th %= 24\n\t\tswitch {\n\t\tcase h == 0:\n\t\t\tfmt.Fprintf(buf, \"%02d:%02d:%02d AM\", 12, t.time.Minute(), t.time.Second())\n\t\tcase h == 12:\n\t\t\tfmt.Fprintf(buf, \"%02d:%02d:%02d PM\", 12, t.time.Minute(), t.time.Second())\n\t\tcase h < 12:\n\t\t\tfmt.Fprintf(buf, \"%02d:%02d:%02d AM\", h, t.time.Minute(), t.time.Second())\n\t\tdefault:\n\t\t\tfmt.Fprintf(buf, \"%02d:%02d:%02d PM\", h-12, t.time.Minute(), t.time.Second())\n\t\t}\n\tcase 'T':\n\t\tfmt.Fprintf(buf, \"%02d:%02d:%02d\", t.time.Hour(), t.time.Minute(), t.time.Second())\n\tcase 'S', 's':\n\t\tbuf.WriteString(FormatIntWidthN(t.time.Second(), 2))\n\tcase 'f':\n\t\tfmt.Fprintf(buf, \"%06d\", t.time.Microsecond())\n\tcase 'U':\n\t\tw := t.time.Week(0)\n\t\tbuf.WriteString(FormatIntWidthN(w, 2))\n\tcase 'u':\n\t\tw := t.time.Week(1)\n\t\tbuf.WriteString(FormatIntWidthN(w, 2))\n\tcase 'V':\n\t\tw := t.time.Week(2)\n\t\tbuf.WriteString(FormatIntWidthN(w, 2))\n\tcase 'v':\n\t\t_, w := t.time.YearWeek(3)\n\t\tbuf.WriteString(FormatIntWidthN(w, 2))\n\tcase 'a':\n\t\tweekday := t.time.Weekday()\n\t\tbuf.WriteString(abbrevWeekdayName[weekday])\n\tcase 'W':\n\t\tbuf.WriteString(t.time.Weekday().String())\n\tcase 'w':\n\t\tbuf.WriteString(strconv.FormatInt(int64(t.time.Weekday()), 10))\n\tcase 'X':\n\t\tyear, _ := t.time.YearWeek(2)\n\t\tif year < 0 {\n\t\t\tbuf.WriteString(strconv.FormatUint(uint64(math.MaxUint32), 10))\n\t\t} else {\n\t\t\tbuf.WriteString(FormatIntWidthN(year, 4))\n\t\t}\n\tcase 'x':\n\t\tyear, _ := t.time.YearWeek(3)\n\t\tif year < 0 {\n\t\t\tbuf.WriteString(strconv.FormatUint(uint64(math.MaxUint32), 10))\n\t\t} else {\n\t\t\tbuf.WriteString(FormatIntWidthN(year, 4))\n\t\t}\n\tcase 'Y':\n\t\tbuf.WriteString(FormatIntWidthN(t.time.Year(), 4))\n\tcase 'y':\n\t\tstr := FormatIntWidthN(t.time.Year(), 4)\n\t\tbuf.WriteString(str[2:])\n\tdefault:\n\t\tbuf.WriteRune(b)\n\t}\n\n\treturn nil\n}\n\n// FormatIntWidthN uses to format int with width. Insufficient digits are filled by 0.\nfunc FormatIntWidthN(num, n int) string {\n\tnumString := strconv.FormatInt(int64(num), 10)\n\tif len(numString) >= n {\n\t\treturn numString\n\t}\n\tpadBytes := make([]byte, n-len(numString))\n\tfor i := range padBytes {\n\t\tpadBytes[i] = '0'\n\t}\n\treturn string(padBytes) + numString\n}\n\nfunc abbrDayOfMonth(day int) string {\n\tvar str string\n\tswitch day {\n\tcase 1, 21, 31:\n\t\tstr = \"st\"\n\tcase 2, 22:\n\t\tstr = \"nd\"\n\tcase 3, 23:\n\t\tstr = \"rd\"\n\tdefault:\n\t\tstr = \"th\"\n\t}\n\treturn str\n}\n\n// StrToDate converts date string according to format.\n// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format\nfunc (t *Time) StrToDate(sc *stmtctx.StatementContext, date, format string) bool {\n\tctx := make(map[string]int)\n\tvar tm MysqlTime\n\tif !strToDate(&tm, date, format, ctx) {\n\t\tt.time = ZeroCoreTime\n\t\tt.tp = mysql.TypeDatetime\n\t\tt.fsp = 0\n\t\treturn false\n\t}\n\tif err := mysqlTimeFix(&tm, ctx); err != nil {\n\t\treturn false\n\t}\n\n\tt.time = tm\n\tt.tp = mysql.TypeDatetime\n\treturn t.check(sc) == nil\n}\n\n// mysqlTimeFix fixes the MysqlTime use the values in the context.\nfunc mysqlTimeFix(t *MysqlTime, ctx map[string]int) error {\n\t// Key of the ctx is the format char, such as `%j` `%p` and so on.\n\tif yearOfDay, ok := ctx[\"%j\"]; ok {\n\t\t// TODO: Implement the function that converts day of year to yy:mm:dd.\n\t\t_ = yearOfDay\n\t}\n\tif valueAMorPm, ok := ctx[\"%p\"]; ok {\n\t\tif _, ok := ctx[\"%H\"]; ok {\n\t\t\treturn ErrWrongValue.GenWithStackByArgs(TimeStr, t)\n\t\t}\n\t\tif t.hour == 0 {\n\t\t\treturn ErrWrongValue.GenWithStackByArgs(TimeStr, t)\n\t\t}\n\t\tif t.hour == 12 {\n\t\t\t// 12 is a special hour.\n\t\t\tswitch valueAMorPm {\n\t\t\tcase constForAM:\n\t\t\t\tt.hour = 0\n\t\t\tcase constForPM:\n\t\t\t\tt.hour = 12\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tif valueAMorPm == constForPM {\n\t\t\tt.hour += 12\n\t\t}\n\t}\n\treturn nil\n}\n\n// strToDate converts date string according to format, returns true on success,\n// the value will be stored in argument t or ctx.\nfunc strToDate(t *MysqlTime, date string, format string, ctx map[string]int) bool {\n\tdate = skipWhiteSpace(date)\n\tformat = skipWhiteSpace(format)\n\n\ttoken, formatRemain, succ := getFormatToken(format)\n\tif !succ {\n\t\treturn false\n\t}\n\n\tif token == \"\" {\n\t\t// Extra characters at the end of date are ignored.\n\t\treturn true\n\t}\n\n\tif len(date) == 0 {\n\t\tctx[token] = 0\n\t\treturn true\n\t}\n\n\tdateRemain, succ := matchDateWithToken(t, date, token, ctx)\n\tif !succ {\n\t\treturn false\n\t}\n\n\treturn strToDate(t, dateRemain, formatRemain, ctx)\n}\n\n// getFormatToken takes one format control token from the string.\n// format \"%d %H %m\" will get token \"%d\" and the remain is \" %H %m\".\nfunc getFormatToken(format string) (token string, remain string, succ bool) {\n\tif len(format) == 0 {\n\t\treturn \"\", \"\", true\n\t}\n\n\t// Just one character.\n\tif len(format) == 1 {\n\t\tif format[0] == '%' {\n\t\t\treturn \"\", \"\", false\n\t\t}\n\t\treturn format, \"\", true\n\t}\n\n\t// More than one character.\n\tif format[0] == '%' {\n\t\treturn format[:2], format[2:], true\n\t}\n\n\treturn format[:1], format[1:], true\n}\n\nfunc skipWhiteSpace(input string) string {\n\tfor i, c := range input {\n\t\tif !unicode.IsSpace(c) {\n\t\t\treturn input[i:]\n\t\t}\n\t}\n\treturn \"\"\n}\n\nvar monthAbbrev = map[string]gotime.Month{\n\t\"Jan\": gotime.January,\n\t\"Feb\": gotime.February,\n\t\"Mar\": gotime.March,\n\t\"Apr\": gotime.April,\n\t\"May\": gotime.May,\n\t\"Jun\": gotime.June,\n\t\"Jul\": gotime.July,\n\t\"Aug\": gotime.August,\n\t\"Sep\": gotime.September,\n\t\"Oct\": gotime.October,\n\t\"Nov\": gotime.November,\n\t\"Dec\": gotime.December,\n}\n\ntype dateFormatParser func(t *MysqlTime, date string, ctx map[string]int) (remain string, succ bool)\n\nvar dateFormatParserTable = map[string]dateFormatParser{\n\t\"%b\": abbreviatedMonth,      // Abbreviated month name (Jan..Dec)\n\t\"%c\": monthNumeric,          // Month, numeric (0..12)\n\t\"%d\": dayOfMonthNumeric,     // Day of the month, numeric (0..31)\n\t\"%e\": dayOfMonthNumeric,     // Day of the month, numeric (0..31)\n\t\"%f\": microSeconds,          // Microseconds (000000..999999)\n\t\"%h\": hour24TwoDigits,       // Hour (01..12)\n\t\"%H\": hour24Numeric,         // Hour (00..23)\n\t\"%I\": hour12Numeric,         // Hour (01..12)\n\t\"%i\": minutesNumeric,        // Minutes, numeric (00..59)\n\t\"%j\": dayOfYearThreeDigits,  // Day of year (001..366)\n\t\"%k\": hour24Numeric,         // Hour (0..23)\n\t\"%l\": hour12Numeric,         // Hour (1..12)\n\t\"%M\": fullNameMonth,         // Month name (January..December)\n\t\"%m\": monthNumeric,          // Month, numeric (00..12)\n\t\"%p\": isAMOrPM,              // AM or PM\n\t\"%r\": time12Hour,            // Time, 12-hour (hh:mm:ss followed by AM or PM)\n\t\"%s\": secondsNumeric,        // Seconds (00..59)\n\t\"%S\": secondsNumeric,        // Seconds (00..59)\n\t\"%T\": time24Hour,            // Time, 24-hour (hh:mm:ss)\n\t\"%Y\": yearNumericFourDigits, // Year, numeric, four digits\n\t// Deprecated since MySQL 5.7.5\n\t\"%y\": yearNumericTwoDigits, // Year, numeric (two digits)\n\t// TODO: Add the following...\n\t// \"%a\": abbreviatedWeekday,         // Abbreviated weekday name (Sun..Sat)\n\t// \"%D\": dayOfMonthWithSuffix,       // Day of the month with English suffix (0th, 1st, 2nd, 3rd)\n\t// \"%U\": weekMode0,                  // Week (00..53), where Sunday is the first day of the week; WEEK() mode 0\n\t// \"%u\": weekMode1,                  // Week (00..53), where Monday is the first day of the week; WEEK() mode 1\n\t// \"%V\": weekMode2,                  // Week (01..53), where Sunday is the first day of the week; WEEK() mode 2; used with %X\n\t// \"%v\": weekMode3,                  // Week (01..53), where Monday is the first day of the week; WEEK() mode 3; used with %x\n\t// \"%W\": weekdayName,                // Weekday name (Sunday..Saturday)\n\t// \"%w\": dayOfWeek,                  // Day of the week (0=Sunday..6=Saturday)\n\t// \"%X\": yearOfWeek,                 // Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V\n\t// \"%x\": yearOfWeek,                 // Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v\n}\n\n// GetFormatType checks the type(Duration, Date or Datetime) of a format string.\nfunc GetFormatType(format string) (isDuration, isDate bool) {\n\tformat = skipWhiteSpace(format)\n\tvar token string\n\tvar succ bool\n\tfor {\n\t\ttoken, format, succ = getFormatToken(format)\n\t\tif len(token) == 0 {\n\t\t\tbreak\n\t\t}\n\t\tif !succ {\n\t\t\tisDuration, isDate = false, false\n\t\t\tbreak\n\t\t}\n\t\tif len(token) >= 2 && token[0] == '%' {\n\t\t\tswitch token[1] {\n\t\t\tcase 'h', 'H', 'i', 'I', 's', 'S', 'k', 'l', 'f':\n\t\t\t\tisDuration = true\n\t\t\tcase 'y', 'Y', 'm', 'M', 'c', 'b', 'D', 'd', 'e':\n\t\t\t\tisDate = true\n\t\t\t}\n\t\t}\n\t\tif isDuration && isDate {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn\n}\n\nfunc matchDateWithToken(t *MysqlTime, date string, token string, ctx map[string]int) (remain string, succ bool) {\n\tif parse, ok := dateFormatParserTable[token]; ok {\n\t\treturn parse(t, date, ctx)\n\t}\n\n\tif strings.HasPrefix(date, token) {\n\t\treturn date[len(token):], true\n\t}\n\treturn date, false\n}\n\nfunc parseDigits(input string, count int) (int, bool) {\n\tif count <= 0 || len(input) < count {\n\t\treturn 0, false\n\t}\n\n\tv, err := strconv.ParseUint(input[:count], 10, 64)\n\tif err != nil {\n\t\treturn int(v), false\n\t}\n\treturn int(v), true\n}\n\nfunc hour24TwoDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tv, succ := parseDigits(input, 2)\n\tif !succ || v >= 24 {\n\t\treturn input, false\n\t}\n\tt.hour = uint32(v)\n\treturn input[2:], true\n}\n\nfunc secondsNumeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tresult := oneOrTwoDigitRegex.FindString(input)\n\tlength := len(result)\n\n\tv, succ := parseDigits(input, length)\n\tif !succ || v >= 60 {\n\t\treturn input, false\n\t}\n\tt.second = uint8(v)\n\treturn input[length:], true\n}\n\nfunc minutesNumeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tresult := oneOrTwoDigitRegex.FindString(input)\n\tlength := len(result)\n\n\tv, succ := parseDigits(input, length)\n\tif !succ || v >= 60 {\n\t\treturn input, false\n\t}\n\tt.minute = uint8(v)\n\treturn input[length:], true\n}\n\nconst time12HourLen = len(\"hh:mm:ssAM\")\n\nfunc time12Hour(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\t// hh:mm:ss AM\n\tif len(input) < time12HourLen {\n\t\treturn input, false\n\t}\n\thour, succ := parseDigits(input, 2)\n\tif !succ || hour > 12 || hour == 0 || input[2] != ':' {\n\t\treturn input, false\n\t}\n\n\tminute, succ := parseDigits(input[3:], 2)\n\tif !succ || minute > 59 || input[5] != ':' {\n\t\treturn input, false\n\t}\n\n\tsecond, succ := parseDigits(input[6:], 2)\n\tif !succ || second > 59 {\n\t\treturn input, false\n\t}\n\n\tremain := skipWhiteSpace(input[8:])\n\tswitch {\n\tcase strings.HasPrefix(remain, \"AM\"):\n\t\tt.hour = uint32(hour)\n\tcase strings.HasPrefix(remain, \"PM\"):\n\t\tt.hour = uint32(hour + 12)\n\tdefault:\n\t\treturn input, false\n\t}\n\n\tt.minute = uint8(minute)\n\tt.second = uint8(second)\n\treturn remain, true\n}\n\nconst time24HourLen = len(\"hh:mm:ss\")\n\nfunc time24Hour(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\t// hh:mm:ss\n\tif len(input) < time24HourLen {\n\t\treturn input, false\n\t}\n\n\thour, succ := parseDigits(input, 2)\n\tif !succ || hour > 23 || input[2] != ':' {\n\t\treturn input, false\n\t}\n\n\tminute, succ := parseDigits(input[3:], 2)\n\tif !succ || minute > 59 || input[5] != ':' {\n\t\treturn input, false\n\t}\n\n\tsecond, succ := parseDigits(input[6:], 2)\n\tif !succ || second > 59 {\n\t\treturn input, false\n\t}\n\n\tt.hour = uint32(hour)\n\tt.minute = uint8(minute)\n\tt.second = uint8(second)\n\treturn input[8:], true\n}\n\nconst (\n\tconstForAM = 1 + iota\n\tconstForPM\n)\n\nfunc isAMOrPM(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tif len(input) < 2 {\n\t\treturn input, false\n\t}\n\n\ts := strings.ToLower(input[:2])\n\tswitch s {\n\tcase \"am\":\n\t\tctx[\"%p\"] = constForAM\n\tcase \"pm\":\n\t\tctx[\"%p\"] = constForPM\n\tdefault:\n\t\treturn input, false\n\t}\n\treturn input[2:], true\n}\n\n// digitRegex: it was used to scan a variable-length monthly day or month in the string. Ex:  \"01\" or \"1\" or \"30\"\nvar oneOrTwoDigitRegex = regexp.MustCompile(\"^[0-9]{1,2}\")\n\n// oneToSixDigitRegex: it was just for [0, 999999]\nvar oneToSixDigitRegex = regexp.MustCompile(\"^[0-9]{0,6}\")\n\n// numericRegex: it was for any numeric characters\nvar numericRegex = regexp.MustCompile(\"[0-9]+\")\n\nfunc dayOfMonthNumeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tresult := oneOrTwoDigitRegex.FindString(input) // 0..31\n\tlength := len(result)\n\n\tv, ok := parseDigits(input, length)\n\n\tif !ok || v > 31 {\n\t\treturn input, false\n\t}\n\tt.day = uint8(v)\n\treturn input[length:], true\n}\n\nfunc hour24Numeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tresult := oneOrTwoDigitRegex.FindString(input) // 0..23\n\tlength := len(result)\n\n\tv, ok := parseDigits(input, length)\n\n\tif !ok || v > 23 {\n\t\treturn input, false\n\t}\n\tt.hour = uint32(v)\n\tctx[\"%H\"] = v\n\treturn input[length:], true\n}\n\nfunc hour12Numeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tresult := oneOrTwoDigitRegex.FindString(input) // 1..12\n\tlength := len(result)\n\n\tv, ok := parseDigits(input, length)\n\n\tif !ok || v > 12 || v == 0 {\n\t\treturn input, false\n\t}\n\tt.hour = uint32(v)\n\treturn input[length:], true\n}\n\nfunc microSeconds(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tresult := oneToSixDigitRegex.FindString(input)\n\tlength := len(result)\n\tif length == 0 {\n\t\tt.microsecond = 0\n\t\treturn input, true\n\t}\n\n\tv, ok := parseDigits(input, length)\n\n\tif !ok {\n\t\treturn input, false\n\t}\n\tfor v > 0 && v*10 < 1000000 {\n\t\tv *= 10\n\t}\n\tt.microsecond = uint32(v)\n\treturn input[length:], true\n}\n\nfunc yearNumericFourDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\treturn yearNumericNDigits(t, input, ctx, 4)\n}\n\nfunc yearNumericTwoDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\treturn yearNumericNDigits(t, input, ctx, 2)\n}\n\nfunc yearNumericNDigits(t *MysqlTime, input string, ctx map[string]int, n int) (string, bool) {\n\teffectiveCount, effectiveValue := 0, 0\n\tfor effectiveCount+1 <= n {\n\t\tvalue, succeed := parseDigits(input, effectiveCount+1)\n\t\tif !succeed {\n\t\t\tbreak\n\t\t}\n\t\teffectiveCount++\n\t\teffectiveValue = value\n\t}\n\tif effectiveCount == 0 {\n\t\treturn input, false\n\t}\n\tif effectiveCount <= 2 {\n\t\teffectiveValue = adjustYear(effectiveValue)\n\t}\n\tt.year = uint16(effectiveValue)\n\treturn input[effectiveCount:], true\n}\n\nfunc dayOfYearThreeDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tv, succ := parseDigits(input, 3)\n\tif !succ || v == 0 || v > 366 {\n\t\treturn input, false\n\t}\n\tctx[\"%j\"] = v\n\treturn input[3:], true\n}\n\nfunc abbreviatedMonth(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tif len(input) >= 3 {\n\t\tmonthName := input[:3]\n\t\tif month, ok := monthAbbrev[monthName]; ok {\n\t\t\tt.month = uint8(month)\n\t\t\treturn input[len(monthName):], true\n\t\t}\n\t}\n\treturn input, false\n}\n\nfunc fullNameMonth(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tfor i, month := range MonthNames {\n\t\tif strings.HasPrefix(input, month) {\n\t\t\tt.month = uint8(i + 1)\n\t\t\treturn input[len(month):], true\n\t\t}\n\t}\n\treturn input, false\n}\n\nfunc monthNumeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {\n\tresult := oneOrTwoDigitRegex.FindString(input) // 1..12\n\tlength := len(result)\n\n\tv, ok := parseDigits(input, length)\n\n\tif !ok || v > 12 {\n\t\treturn input, false\n\t}\n\tt.month = uint8(v)\n\treturn input[length:], true\n}\n\n// DateFSP gets fsp from date string.\nfunc DateFSP(date string) (fsp int) {\n\ti := strings.LastIndex(date, \".\")\n\tif i != -1 {\n\t\tfsp = len(date) - i - 1\n\t}\n\treturn\n}\n\n// DateTimeIsOverflow returns if this date is overflow.\n// See: https://dev.mysql.com/doc/refman/8.0/en/datetime.html\nfunc DateTimeIsOverflow(sc *stmtctx.StatementContext, date Time) (bool, error) {\n\ttz := sc.TimeZone\n\tif tz == nil {\n\t\ttz = gotime.Local\n\t}\n\n\tvar err error\n\tvar b, e, t gotime.Time\n\tswitch date.tp {\n\tcase mysql.TypeDate, mysql.TypeDatetime:\n\t\tif b, err = MinDatetime.GoTime(tz); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif e, err = MaxDatetime.GoTime(tz); err != nil {\n\t\t\treturn false, err\n\t\t}\n\tcase mysql.TypeTimestamp:\n\t\tminTS, maxTS := MinTimestamp, MaxTimestamp\n\t\tif tz != gotime.UTC {\n\t\t\tif err = minTS.ConvertTimeZone(gotime.UTC, tz); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tif err = maxTS.ConvertTimeZone(gotime.UTC, tz); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t}\n\t\tif b, err = minTS.time.GoTime(tz); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif e, err = maxTS.time.GoTime(tz); err != nil {\n\t\t\treturn false, err\n\t\t}\n\tdefault:\n\t\treturn false, nil\n\t}\n\n\tif t, err = date.time.GoTime(tz); err != nil {\n\t\treturn false, err\n\t}\n\n\tinRange := (t.After(b) || t.Equal(b)) && (t.Before(e) || t.Equal(e))\n\treturn !inRange, nil\n}\n"
  },
  {
    "path": "pkg/util/chunk/chunk.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage chunk\n\nimport (\n\t\"reflect\"\n\t\"unsafe\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/mathutil\"\n)\n\nvar msgErrSelNotNil = \"The selection vector of Chunk is not nil. Please file a bug to the TiDB Team\"\n\n// Chunk stores multiple rows of data in Apache Arrow format.\n// See https://arrow.apache.org/docs/memory_layout.html\n// Values are appended in compact format and can be directly accessed without decoding.\n// When the chunk is done processing, we can reuse the allocated memory by resetting it.\ntype Chunk struct {\n\t// sel indicates which rows are selected.\n\t// If it is nil, all rows are selected.\n\tsel []int\n\n\tcolumns []*Column\n\t// numVirtualRows indicates the number of virtual rows, which have zero Column.\n\t// It is used only when this Chunk doesn't hold any data, i.e. \"len(columns)==0\".\n\tnumVirtualRows int\n\t// capacity indicates the max number of rows this chunk can hold.\n\t// TODO: replace all usages of capacity to requiredRows and remove this field\n\tcapacity int\n\n\t// requiredRows indicates how many rows the parent executor want.\n\trequiredRows int\n}\n\n// Capacity constants.\nconst (\n\tInitialCapacity = 32\n\tZeroCapacity    = 0\n)\n\n// NewChunkWithCapacity creates a new chunk with field types and capacity.\nfunc NewChunkWithCapacity(fields []*types.FieldType, capacity int) *Chunk {\n\treturn New(fields, capacity, capacity) //FIXME: in following PR.\n}\n\n// New creates a new chunk.\n//\n//\tcapacity: the limit for the max number of rows.\n//\tmaxChunkSize: the max limit for the number of rows.\nfunc New(fields []*types.FieldType, capacity, maxChunkSize int) *Chunk {\n\tchk := &Chunk{\n\t\tcolumns:  make([]*Column, 0, len(fields)),\n\t\tcapacity: mathutil.Min(capacity, maxChunkSize),\n\t\t// set the default value of requiredRows to maxChunkSize to let chk.IsFull() behave\n\t\t// like how we judge whether a chunk is full now, then the statement\n\t\t// \"chk.NumRows() < maxChunkSize\"\n\t\t// equals to \"!chk.IsFull()\".\n\t\trequiredRows: maxChunkSize,\n\t}\n\n\tfor _, f := range fields {\n\t\tchk.columns = append(chk.columns, NewColumn(f, chk.capacity))\n\t}\n\n\treturn chk\n}\n\n// renewWithCapacity creates a new Chunk based on an existing Chunk with capacity. The newly\n// created Chunk has the same data schema with the old Chunk.\nfunc renewWithCapacity(chk *Chunk, capacity, maxChunkSize int) *Chunk {\n\tnewChk := new(Chunk)\n\tif chk.columns == nil {\n\t\treturn newChk\n\t}\n\tnewChk.columns = renewColumns(chk.columns, capacity)\n\tnewChk.numVirtualRows = 0\n\tnewChk.capacity = capacity\n\tnewChk.requiredRows = maxChunkSize\n\treturn newChk\n}\n\n// Renew creates a new Chunk based on an existing Chunk. The newly created Chunk\n// has the same data schema with the old Chunk. The capacity of the new Chunk\n// might be doubled based on the capacity of the old Chunk and the maxChunkSize.\n//\n//\tchk: old chunk(often used in previous call).\n//\tmaxChunkSize: the limit for the max number of rows.\nfunc Renew(chk *Chunk, maxChunkSize int) *Chunk {\n\tnewCap := reCalcCapacity(chk, maxChunkSize)\n\treturn renewWithCapacity(chk, newCap, maxChunkSize)\n}\n\n// renewColumns creates the columns of a Chunk. The capacity of the newly\n// created columns is equal to capacity.\nfunc renewColumns(oldCol []*Column, capacity int) []*Column {\n\tcolumns := make([]*Column, 0, len(oldCol))\n\tfor _, col := range oldCol {\n\t\tcolumns = append(columns, newColumn(col.typeSize(), capacity))\n\t}\n\treturn columns\n}\n\n// MemoryUsage returns the total memory usage of a Chunk in B.\n// We ignore the size of Column.length and Column.nullCount\n// since they have little effect of the total memory usage.\nfunc (c *Chunk) MemoryUsage() (sum int64) {\n\tfor _, col := range c.columns {\n\t\tcurColMemUsage := int64(unsafe.Sizeof(*col)) + int64(cap(col.nullBitmap)) + int64(cap(col.offsets)*4) + int64(cap(col.data)) + int64(cap(col.elemBuf))\n\t\tsum += curColMemUsage\n\t}\n\treturn\n}\n\n// newFixedLenColumn creates a fixed length Column with elemLen and initial data capacity.\nfunc newFixedLenColumn(elemLen, capacity int) *Column {\n\treturn &Column{\n\t\telemBuf:    make([]byte, elemLen),\n\t\tdata:       make([]byte, 0, capacity*elemLen),\n\t\tnullBitmap: make([]byte, 0, (capacity+7)>>3),\n\t}\n}\n\n// newVarLenColumn creates a variable length Column with initial data capacity.\nfunc newVarLenColumn(capacity int, old *Column) *Column {\n\testimatedElemLen := 8\n\t// For varLenColumn (e.g. varchar), the accurate length of an element is unknown.\n\t// Therefore, in the first executor.Next we use an experience value -- 8 (so it may make runtime.growslice)\n\t// but in the following Next call we estimate the length as AVG x 1.125 elemLen of the previous call.\n\tif old != nil && old.length != 0 {\n\t\testimatedElemLen = (len(old.data) + len(old.data)/8) / old.length\n\t}\n\treturn &Column{\n\t\toffsets:    make([]int64, 1, capacity+1),\n\t\tdata:       make([]byte, 0, capacity*estimatedElemLen),\n\t\tnullBitmap: make([]byte, 0, (capacity+7)>>3),\n\t}\n}\n\n// RequiredRows returns how many rows is considered full.\nfunc (c *Chunk) RequiredRows() int {\n\treturn c.requiredRows\n}\n\n// SetRequiredRows sets the number of required rows.\nfunc (c *Chunk) SetRequiredRows(requiredRows, maxChunkSize int) *Chunk {\n\tif requiredRows <= 0 || requiredRows > maxChunkSize {\n\t\trequiredRows = maxChunkSize\n\t}\n\tc.requiredRows = requiredRows\n\treturn c\n}\n\n// IsFull returns if this chunk is considered full.\nfunc (c *Chunk) IsFull() bool {\n\treturn c.NumRows() >= c.requiredRows\n}\n\n// MakeRef makes Column in \"dstColIdx\" reference to Column in \"srcColIdx\".\nfunc (c *Chunk) MakeRef(srcColIdx, dstColIdx int) {\n\tc.columns[dstColIdx] = c.columns[srcColIdx]\n}\n\n// MakeRefTo copies columns `src.columns[srcColIdx]` to `c.columns[dstColIdx]`.\nfunc (c *Chunk) MakeRefTo(dstColIdx int, src *Chunk, srcColIdx int) error {\n\tif c.sel != nil || src.sel != nil {\n\t\treturn errors.New(msgErrSelNotNil)\n\t}\n\tc.columns[dstColIdx] = src.columns[srcColIdx]\n\treturn nil\n}\n\n// SwapColumn swaps Column \"c.columns[colIdx]\" with Column\n// \"other.columns[otherIdx]\". If there exists columns refer to the Column to be\n// swapped, we need to re-build the reference.\nfunc (c *Chunk) SwapColumn(colIdx int, other *Chunk, otherIdx int) error {\n\tif c.sel != nil || other.sel != nil {\n\t\treturn errors.New(msgErrSelNotNil)\n\t}\n\t// Find the leftmost Column of the reference which is the actual Column to\n\t// be swapped.\n\tfor i := 0; i < colIdx; i++ {\n\t\tif c.columns[i] == c.columns[colIdx] {\n\t\t\tcolIdx = i\n\t\t}\n\t}\n\tfor i := 0; i < otherIdx; i++ {\n\t\tif other.columns[i] == other.columns[otherIdx] {\n\t\t\totherIdx = i\n\t\t}\n\t}\n\n\t// Find the columns which refer to the actual Column to be swapped.\n\trefColsIdx := make([]int, 0, len(c.columns)-colIdx)\n\tfor i := colIdx; i < len(c.columns); i++ {\n\t\tif c.columns[i] == c.columns[colIdx] {\n\t\t\trefColsIdx = append(refColsIdx, i)\n\t\t}\n\t}\n\trefColsIdx4Other := make([]int, 0, len(other.columns)-otherIdx)\n\tfor i := otherIdx; i < len(other.columns); i++ {\n\t\tif other.columns[i] == other.columns[otherIdx] {\n\t\t\trefColsIdx4Other = append(refColsIdx4Other, i)\n\t\t}\n\t}\n\n\t// Swap columns from two chunks.\n\tc.columns[colIdx], other.columns[otherIdx] = other.columns[otherIdx], c.columns[colIdx]\n\n\t// Rebuild the reference.\n\tfor _, i := range refColsIdx {\n\t\tc.MakeRef(colIdx, i)\n\t}\n\tfor _, i := range refColsIdx4Other {\n\t\tother.MakeRef(otherIdx, i)\n\t}\n\treturn nil\n}\n\n// SwapColumns swaps columns with another Chunk.\nfunc (c *Chunk) SwapColumns(other *Chunk) {\n\tc.sel, other.sel = other.sel, c.sel\n\tc.columns, other.columns = other.columns, c.columns\n\tc.numVirtualRows, other.numVirtualRows = other.numVirtualRows, c.numVirtualRows\n}\n\n// SetNumVirtualRows sets the virtual row number for a Chunk.\n// It should only be used when there exists no Column in the Chunk.\nfunc (c *Chunk) SetNumVirtualRows(numVirtualRows int) {\n\tc.numVirtualRows = numVirtualRows\n}\n\n// Reset resets the chunk, so the memory it allocated can be reused.\n// Make sure all the data in the chunk is not used anymore before you reuse this chunk.\nfunc (c *Chunk) Reset() {\n\tc.sel = nil\n\tif c.columns == nil {\n\t\treturn\n\t}\n\tfor _, col := range c.columns {\n\t\tcol.reset()\n\t}\n\tc.numVirtualRows = 0\n}\n\n// CopyConstruct creates a new chunk and copies this chunk's data into it.\nfunc (c *Chunk) CopyConstruct() *Chunk {\n\tnewChk := &Chunk{numVirtualRows: c.numVirtualRows, capacity: c.capacity, columns: make([]*Column, len(c.columns))}\n\tfor i := range c.columns {\n\t\tnewChk.columns[i] = c.columns[i].CopyConstruct(nil)\n\t}\n\tif c.sel != nil {\n\t\tnewChk.sel = make([]int, len(c.sel))\n\t\tcopy(newChk.sel, c.sel)\n\t}\n\treturn newChk\n}\n\n// GrowAndReset resets the Chunk and doubles the capacity of the Chunk.\n// The doubled capacity should not be larger than maxChunkSize.\n// TODO: this method will be used in following PR.\nfunc (c *Chunk) GrowAndReset(maxChunkSize int) {\n\tc.sel = nil\n\tif c.columns == nil {\n\t\treturn\n\t}\n\tnewCap := reCalcCapacity(c, maxChunkSize)\n\tif newCap <= c.capacity {\n\t\tc.Reset()\n\t\treturn\n\t}\n\tc.capacity = newCap\n\tc.columns = renewColumns(c.columns, newCap)\n\tc.numVirtualRows = 0\n\tc.requiredRows = maxChunkSize\n}\n\n// reCalcCapacity calculates the capacity for another Chunk based on the current\n// Chunk. The new capacity is doubled only when the current Chunk is full.\nfunc reCalcCapacity(c *Chunk, maxChunkSize int) int {\n\tif c.NumRows() < c.capacity {\n\t\treturn c.capacity\n\t}\n\treturn mathutil.Min(c.capacity*2, maxChunkSize)\n}\n\n// Capacity returns the capacity of the Chunk.\nfunc (c *Chunk) Capacity() int {\n\treturn c.capacity\n}\n\n// NumCols returns the number of columns in the chunk.\nfunc (c *Chunk) NumCols() int {\n\treturn len(c.columns)\n}\n\n// NumRows returns the number of rows in the chunk.\nfunc (c *Chunk) NumRows() int {\n\tif c.sel != nil {\n\t\treturn len(c.sel)\n\t}\n\tif c.NumCols() == 0 {\n\t\treturn c.numVirtualRows\n\t}\n\treturn c.columns[0].length\n}\n\n// GetRow gets the Row in the chunk with the row index.\nfunc (c *Chunk) GetRow(idx int) Row {\n\tif c.sel != nil {\n\t\t// mapping the logical RowIdx to the actual physical RowIdx;\n\t\t// for example, if the Sel is [1, 5, 6], then\n\t\t//\tlogical 0 -> physical 1,\n\t\t//\tlogical 1 -> physical 5,\n\t\t//\tlogical 2 -> physical 6.\n\t\t// Then when we iterate this Chunk according to Row, only selected rows will be\n\t\t// accessed while all filtered rows will be ignored.\n\t\treturn Row{c: c, idx: int(c.sel[idx])}\n\t}\n\treturn Row{c: c, idx: idx}\n}\n\n// AppendRow appends a row to the chunk.\nfunc (c *Chunk) AppendRow(row Row) {\n\tc.AppendPartialRow(0, row)\n\tc.numVirtualRows++\n}\n\n// AppendPartialRow appends a row to the chunk.\nfunc (c *Chunk) AppendPartialRow(colIdx int, row Row) {\n\tc.appendSel(colIdx)\n\tfor i, rowCol := range row.c.columns {\n\t\tchkCol := c.columns[colIdx+i]\n\t\tchkCol.appendNullBitmap(!rowCol.IsNull(row.idx))\n\t\tif rowCol.isFixed() {\n\t\t\telemLen := len(rowCol.elemBuf)\n\t\t\toffset := row.idx * elemLen\n\t\t\tchkCol.data = append(chkCol.data, rowCol.data[offset:offset+elemLen]...)\n\t\t} else {\n\t\t\tstart, end := rowCol.offsets[row.idx], rowCol.offsets[row.idx+1]\n\t\t\tchkCol.data = append(chkCol.data, rowCol.data[start:end]...)\n\t\t\tchkCol.offsets = append(chkCol.offsets, int64(len(chkCol.data)))\n\t\t}\n\t\tchkCol.length++\n\t}\n}\n\n// preAlloc pre-allocates the memory space in a Chunk to store the Row.\n// NOTE: only used in test.\n//  1. The Chunk must be empty or holds no useful data.\n//  2. The schema of the Row must be the same with the Chunk.\n//  3. This API is paired with the `Insert()` function, which inserts all the\n//     rows data into the Chunk after the pre-allocation.\n//  4. We set the null bitmap here instead of in the Insert() function because\n//     when the Insert() function is called parallelly, the data race on a byte\n//     can not be avoided although the manipulated bits are different inside a\n//     byte.\nfunc (c *Chunk) preAlloc(row Row) (rowIdx uint32) {\n\trowIdx = uint32(c.NumRows())\n\tfor i, srcCol := range row.c.columns {\n\t\tdstCol := c.columns[i]\n\t\tdstCol.appendNullBitmap(!srcCol.IsNull(row.idx))\n\t\telemLen := len(srcCol.elemBuf)\n\t\tif !srcCol.isFixed() {\n\t\t\telemLen = int(srcCol.offsets[row.idx+1] - srcCol.offsets[row.idx])\n\t\t\tdstCol.offsets = append(dstCol.offsets, int64(len(dstCol.data)+elemLen))\n\t\t}\n\t\tdstCol.length++\n\t\tneedCap := len(dstCol.data) + elemLen\n\t\tif needCap <= cap(dstCol.data) {\n\t\t\t(*reflect.SliceHeader)(unsafe.Pointer(&dstCol.data)).Len = len(dstCol.data) + elemLen\n\t\t\tcontinue\n\t\t}\n\t\t// Grow the capacity according to golang.growslice.\n\t\t// Implementation differences with golang:\n\t\t// 1. We double the capacity when `dstCol.data < 1024*elemLen bytes` but\n\t\t// not `1024 bytes`.\n\t\t// 2. We expand the capacity to 1.5*originCap rather than 1.25*originCap\n\t\t// during the slow-increasing phase.\n\t\tnewCap := cap(dstCol.data)\n\t\tdoubleCap := newCap << 1\n\t\tif needCap > doubleCap {\n\t\t\tnewCap = needCap\n\t\t} else {\n\t\t\tavgElemLen := elemLen\n\t\t\tif !srcCol.isFixed() {\n\t\t\t\tavgElemLen = len(dstCol.data) / len(dstCol.offsets)\n\t\t\t}\n\t\t\t// slowIncThreshold indicates the threshold exceeding which the\n\t\t\t// dstCol.data capacity increase fold decreases from 2 to 1.5.\n\t\t\tslowIncThreshold := 1024 * avgElemLen\n\t\t\tif len(dstCol.data) < slowIncThreshold {\n\t\t\t\tnewCap = doubleCap\n\t\t\t} else {\n\t\t\t\tfor 0 < newCap && newCap < needCap {\n\t\t\t\t\tnewCap += newCap / 2\n\t\t\t\t}\n\t\t\t\tif newCap <= 0 {\n\t\t\t\t\tnewCap = needCap\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdstCol.data = make([]byte, len(dstCol.data)+elemLen, newCap)\n\t}\n\treturn\n}\n\n// insert inserts `row` on the position specified by `rowIdx`.\n// NOTE: only used in test.\n// Note: Insert will cover the origin data, it should be called after\n// PreAlloc.\nfunc (c *Chunk) insert(rowIdx int, row Row) {\n\tfor i, srcCol := range row.c.columns {\n\t\tif row.IsNull(i) {\n\t\t\tcontinue\n\t\t}\n\t\tdstCol := c.columns[i]\n\t\tvar srcStart, srcEnd, destStart, destEnd int\n\t\tif srcCol.isFixed() {\n\t\t\tsrcElemLen, destElemLen := len(srcCol.elemBuf), len(dstCol.elemBuf)\n\t\t\tsrcStart, destStart = row.idx*srcElemLen, rowIdx*destElemLen\n\t\t\tsrcEnd, destEnd = srcStart+srcElemLen, destStart+destElemLen\n\t\t} else {\n\t\t\tsrcStart, srcEnd = int(srcCol.offsets[row.idx]), int(srcCol.offsets[row.idx+1])\n\t\t\tdestStart, destEnd = int(dstCol.offsets[rowIdx]), int(dstCol.offsets[rowIdx+1])\n\t\t}\n\t\tcopy(dstCol.data[destStart:destEnd], srcCol.data[srcStart:srcEnd])\n\t}\n}\n\n// Append appends rows in [begin, end) in another Chunk to a Chunk.\nfunc (c *Chunk) Append(other *Chunk, begin, end int) {\n\tfor colID, src := range other.columns {\n\t\tdst := c.columns[colID]\n\t\tif src.isFixed() {\n\t\t\telemLen := len(src.elemBuf)\n\t\t\tdst.data = append(dst.data, src.data[begin*elemLen:end*elemLen]...)\n\t\t} else {\n\t\t\tbeginOffset, endOffset := src.offsets[begin], src.offsets[end]\n\t\t\tdst.data = append(dst.data, src.data[beginOffset:endOffset]...)\n\t\t\tfor i := begin; i < end; i++ {\n\t\t\t\tdst.offsets = append(dst.offsets, dst.offsets[len(dst.offsets)-1]+src.offsets[i+1]-src.offsets[i])\n\t\t\t}\n\t\t}\n\t\tfor i := begin; i < end; i++ {\n\t\t\tc.appendSel(colID)\n\t\t\tdst.appendNullBitmap(!src.IsNull(i))\n\t\t\tdst.length++\n\t\t}\n\t}\n\tc.numVirtualRows += end - begin\n}\n\n// TruncateTo truncates rows from tail to head in a Chunk to \"numRows\" rows.\nfunc (c *Chunk) TruncateTo(numRows int) {\n\tc.Reconstruct()\n\tfor _, col := range c.columns {\n\t\tif col.isFixed() {\n\t\t\telemLen := len(col.elemBuf)\n\t\t\tcol.data = col.data[:numRows*elemLen]\n\t\t} else {\n\t\t\tcol.data = col.data[:col.offsets[numRows]]\n\t\t\tcol.offsets = col.offsets[:numRows+1]\n\t\t}\n\t\tcol.length = numRows\n\t\tbitmapLen := (col.length + 7) / 8\n\t\tcol.nullBitmap = col.nullBitmap[:bitmapLen]\n\t\tif col.length%8 != 0 {\n\t\t\t// When we append null, we simply increment the nullCount,\n\t\t\t// so we need to clear the unused bits in the last bitmap byte.\n\t\t\tlastByte := col.nullBitmap[bitmapLen-1]\n\t\t\tunusedBitsLen := 8 - uint(col.length%8)\n\t\t\tlastByte <<= unusedBitsLen\n\t\t\tlastByte >>= unusedBitsLen\n\t\t\tcol.nullBitmap[bitmapLen-1] = lastByte\n\t\t}\n\t}\n\tc.numVirtualRows = numRows\n}\n\n// AppendNull appends a null value to the chunk.\nfunc (c *Chunk) AppendNull(colIdx int) {\n\tc.appendSel(colIdx)\n\tc.columns[colIdx].AppendNull()\n}\n\n// AppendInt64 appends a int64 value to the chunk.\nfunc (c *Chunk) AppendInt64(colIdx int, i int64) {\n\tc.appendSel(colIdx)\n\tc.columns[colIdx].AppendInt64(i)\n}\n\n// AppendUint64 appends a uint64 value to the chunk.\nfunc (c *Chunk) AppendUint64(colIdx int, u uint64) {\n\tc.appendSel(colIdx)\n\tc.columns[colIdx].AppendUint64(u)\n}\n\n// AppendFloat32 appends a float32 value to the chunk.\nfunc (c *Chunk) AppendFloat32(colIdx int, f float32) {\n\tc.appendSel(colIdx)\n\tc.columns[colIdx].AppendFloat32(f)\n}\n\n// AppendFloat64 appends a float64 value to the chunk.\nfunc (c *Chunk) AppendFloat64(colIdx int, f float64) {\n\tc.appendSel(colIdx)\n\tc.columns[colIdx].AppendFloat64(f)\n}\n\n// AppendString appends a string value to the chunk.\nfunc (c *Chunk) AppendString(colIdx int, str string) {\n\tc.appendSel(colIdx)\n\tc.columns[colIdx].AppendString(str)\n}\n\n// AppendBytes appends a bytes value to the chunk.\nfunc (c *Chunk) AppendBytes(colIdx int, b []byte) {\n\tc.appendSel(colIdx)\n\tc.columns[colIdx].AppendBytes(b)\n}\n\nfunc (c *Chunk) appendSel(colIdx int) {\n\tif colIdx == 0 && c.sel != nil { // use column 0 as standard\n\t\tc.sel = append(c.sel, c.columns[0].length)\n\t}\n}\n\n// AppendDatum appends a datum into the chunk.\nfunc (c *Chunk) AppendDatum(colIdx int, d *types.Datum) {\n\tswitch d.Kind() {\n\tcase types.KindNull:\n\t\tc.AppendNull(colIdx)\n\tcase types.KindInt64:\n\t\tc.AppendInt64(colIdx, d.GetInt64())\n\tcase types.KindUint64:\n\t\tc.AppendUint64(colIdx, d.GetUint64())\n\tcase types.KindFloat32:\n\t\tc.AppendFloat32(colIdx, d.GetFloat32())\n\tcase types.KindFloat64:\n\t\tc.AppendFloat64(colIdx, d.GetFloat64())\n\tcase types.KindString, types.KindBytes, types.KindBinaryLiteral, types.KindRaw, types.KindMysqlBit:\n\t\tc.AppendBytes(colIdx, d.GetBytes())\n\t}\n}\n\n// Column returns the specific column.\nfunc (c *Chunk) Column(colIdx int) *Column {\n\treturn c.columns[colIdx]\n}\n\n// SetCol sets the colIdx Column to col and returns the old Column.\nfunc (c *Chunk) SetCol(colIdx int, col *Column) *Column {\n\tif col == c.columns[colIdx] {\n\t\treturn nil\n\t}\n\told := c.columns[colIdx]\n\tc.columns[colIdx] = col\n\treturn old\n}\n\n// Sel returns Sel of this Chunk.\nfunc (c *Chunk) Sel() []int {\n\treturn c.sel\n}\n\n// SetSel sets a Sel for this Chunk.\nfunc (c *Chunk) SetSel(sel []int) {\n\tc.sel = sel\n}\n\n// Reconstruct removes all filtered rows in this Chunk.\nfunc (c *Chunk) Reconstruct() {\n\tif len(c.sel) == 0 {\n\t\treturn\n\t}\n\tfor _, col := range c.columns {\n\t\tcol.reconstruct(c.sel)\n\t}\n\tc.numVirtualRows = len(c.sel)\n\tc.sel = nil\n}\n"
  },
  {
    "path": "pkg/util/chunk/chunk_util.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage chunk\n\nimport \"github.com/pingcap/errors\"\n\n// CopySelectedJoinRowsDirect directly copies the selected joined rows from the source Chunk\n// to the destination Chunk.\n// Return true if at least one joined row was selected.\nfunc CopySelectedJoinRowsDirect(src *Chunk, selected []bool, dst *Chunk) (bool, error) {\n\tif src.NumRows() == 0 {\n\t\treturn false, nil\n\t}\n\tif src.sel != nil || dst.sel != nil {\n\t\treturn false, errors.New(msgErrSelNotNil)\n\t}\n\n\toldLen := dst.columns[0].length\n\tfor j, srcCol := range src.columns {\n\t\tdstCol := dst.columns[j]\n\t\tif srcCol.isFixed() {\n\t\t\tfor i := 0; i < len(selected); i++ {\n\t\t\t\tif !selected[i] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tdstCol.appendNullBitmap(!srcCol.IsNull(i))\n\t\t\t\tdstCol.length++\n\n\t\t\t\telemLen := len(srcCol.elemBuf)\n\t\t\t\toffset := i * elemLen\n\t\t\t\tdstCol.data = append(dstCol.data, srcCol.data[offset:offset+elemLen]...)\n\t\t\t}\n\t\t} else {\n\t\t\tfor i := 0; i < len(selected); i++ {\n\t\t\t\tif !selected[i] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tdstCol.appendNullBitmap(!srcCol.IsNull(i))\n\t\t\t\tdstCol.length++\n\n\t\t\t\tstart, end := srcCol.offsets[i], srcCol.offsets[i+1]\n\t\t\t\tdstCol.data = append(dstCol.data, srcCol.data[start:end]...)\n\t\t\t\tdstCol.offsets = append(dstCol.offsets, int64(len(dstCol.data)))\n\t\t\t}\n\t\t}\n\t}\n\tnumSelected := dst.columns[0].length - oldLen\n\tdst.numVirtualRows += numSelected\n\treturn numSelected > 0, nil\n}\n\n// CopySelectedJoinRowsWithSameOuterRows copies the selected joined rows from the source Chunk\n// to the destination Chunk.\n// Return true if at least one joined row was selected.\n//\n// NOTE: All the outer rows in the source Chunk should be the same.\nfunc CopySelectedJoinRowsWithSameOuterRows(src *Chunk, innerColOffset, outerColOffset int, selected []bool, dst *Chunk) (bool, error) {\n\tif src.NumRows() == 0 {\n\t\treturn false, nil\n\t}\n\tif src.sel != nil || dst.sel != nil {\n\t\treturn false, errors.New(msgErrSelNotNil)\n\t}\n\n\tnumSelected := copySelectedInnerRows(innerColOffset, outerColOffset, src, selected, dst)\n\tcopyOuterRows(innerColOffset, outerColOffset, src, numSelected, dst)\n\tdst.numVirtualRows += numSelected\n\treturn numSelected > 0, nil\n}\n\n// copySelectedInnerRows copies the selected inner rows from the source Chunk\n// to the destination Chunk.\n// return the number of rows which is selected.\nfunc copySelectedInnerRows(innerColOffset, outerColOffset int, src *Chunk, selected []bool, dst *Chunk) int {\n\toldLen := dst.columns[innerColOffset].length\n\tvar srcCols []*Column\n\tif innerColOffset == 0 {\n\t\tsrcCols = src.columns[:outerColOffset]\n\t} else {\n\t\tsrcCols = src.columns[innerColOffset:]\n\t}\n\tfor j, srcCol := range srcCols {\n\t\tdstCol := dst.columns[innerColOffset+j]\n\t\tif srcCol.isFixed() {\n\t\t\tfor i := 0; i < len(selected); i++ {\n\t\t\t\tif !selected[i] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tdstCol.appendNullBitmap(!srcCol.IsNull(i))\n\t\t\t\tdstCol.length++\n\n\t\t\t\telemLen := len(srcCol.elemBuf)\n\t\t\t\toffset := i * elemLen\n\t\t\t\tdstCol.data = append(dstCol.data, srcCol.data[offset:offset+elemLen]...)\n\t\t\t}\n\t\t} else {\n\t\t\tfor i := 0; i < len(selected); i++ {\n\t\t\t\tif !selected[i] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tdstCol.appendNullBitmap(!srcCol.IsNull(i))\n\t\t\t\tdstCol.length++\n\n\t\t\t\tstart, end := srcCol.offsets[i], srcCol.offsets[i+1]\n\t\t\t\tdstCol.data = append(dstCol.data, srcCol.data[start:end]...)\n\t\t\t\tdstCol.offsets = append(dstCol.offsets, int64(len(dstCol.data)))\n\t\t\t}\n\t\t}\n\t}\n\treturn dst.columns[innerColOffset].length - oldLen\n}\n\n// copyOuterRows copies the continuous 'numRows' outer rows in the source Chunk\n// to the destination Chunk.\nfunc copyOuterRows(innerColOffset, outerColOffset int, src *Chunk, numRows int, dst *Chunk) {\n\tif numRows <= 0 {\n\t\treturn\n\t}\n\trow := src.GetRow(0)\n\tvar srcCols []*Column\n\tif innerColOffset == 0 {\n\t\tsrcCols = src.columns[outerColOffset:]\n\t} else {\n\t\tsrcCols = src.columns[:innerColOffset]\n\t}\n\tfor i, srcCol := range srcCols {\n\t\tdstCol := dst.columns[outerColOffset+i]\n\t\tdstCol.appendMultiSameNullBitmap(!srcCol.IsNull(row.idx), numRows)\n\t\tdstCol.length += numRows\n\t\tif srcCol.isFixed() {\n\t\t\telemLen := len(srcCol.elemBuf)\n\t\t\tstart := row.idx * elemLen\n\t\t\tend := start + numRows*elemLen\n\t\t\tdstCol.data = append(dstCol.data, srcCol.data[start:end]...)\n\t\t} else {\n\t\t\tstart, end := srcCol.offsets[row.idx], srcCol.offsets[row.idx+numRows]\n\t\t\tdstCol.data = append(dstCol.data, srcCol.data[start:end]...)\n\t\t\toffsets := dstCol.offsets\n\t\t\telemLen := srcCol.offsets[row.idx+1] - srcCol.offsets[row.idx]\n\t\t\tfor j := 0; j < numRows; j++ {\n\t\t\t\toffsets = append(offsets, int64(offsets[len(offsets)-1]+elemLen))\n\t\t\t}\n\t\t\tdstCol.offsets = offsets\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/util/chunk/codec.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage chunk\n\nimport (\n\t\"encoding/binary\"\n\t\"reflect\"\n\t\"unsafe\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/mathutil\"\n)\n\n// Codec is used to:\n// 1. encode a Chunk to a byte slice.\n// 2. decode a Chunk from a byte slice.\ntype Codec struct {\n\t// colTypes is used to check whether a Column is fixed sized and what the\n\t// fixed size for every element.\n\t// NOTE: It's only used for decoding.\n\tcolTypes []*types.FieldType\n}\n\n// NewCodec creates a new Codec object for encode or decode a Chunk.\nfunc NewCodec(colTypes []*types.FieldType) *Codec {\n\treturn &Codec{colTypes}\n}\n\n// Encode encodes a Chunk to a byte slice.\nfunc (c *Codec) Encode(chk *Chunk) []byte {\n\tbuffer := make([]byte, 0, chk.MemoryUsage())\n\tfor _, col := range chk.columns {\n\t\tbuffer = c.encodeColumn(buffer, col)\n\t}\n\treturn buffer\n}\n\nfunc (c *Codec) encodeColumn(buffer []byte, col *Column) []byte {\n\tvar lenBuffer [4]byte\n\t// encode length.\n\tbinary.LittleEndian.PutUint32(lenBuffer[:], uint32(col.length))\n\tbuffer = append(buffer, lenBuffer[:4]...)\n\n\t// encode nullCount.\n\tbinary.LittleEndian.PutUint32(lenBuffer[:], uint32(col.nullCount()))\n\tbuffer = append(buffer, lenBuffer[:4]...)\n\n\t// encode nullBitmap.\n\tif col.nullCount() > 0 {\n\t\tnumNullBitmapBytes := (col.length + 7) / 8\n\t\tbuffer = append(buffer, col.nullBitmap[:numNullBitmapBytes]...)\n\t}\n\n\t// encode offsets.\n\tif !col.isFixed() {\n\t\tnumOffsetBytes := (col.length + 1) * 8\n\t\toffsetBytes := i64SliceToBytes(col.offsets)\n\t\tbuffer = append(buffer, offsetBytes[:numOffsetBytes]...)\n\t}\n\n\t// encode data.\n\tbuffer = append(buffer, col.data...)\n\treturn buffer\n}\n\nfunc i64SliceToBytes(i64s []int64) (b []byte) {\n\tif len(i64s) == 0 {\n\t\treturn nil\n\t}\n\thdr := (*reflect.SliceHeader)(unsafe.Pointer(&b))\n\thdr.Len = len(i64s) * 8\n\thdr.Cap = hdr.Len\n\thdr.Data = uintptr(unsafe.Pointer(&i64s[0]))\n\treturn b\n}\n\n// Decode decodes a Chunk from a byte slice, return the remained unused bytes.\nfunc (c *Codec) Decode(buffer []byte) (*Chunk, []byte) {\n\tchk := &Chunk{}\n\tfor ordinal := 0; len(buffer) > 0; ordinal++ {\n\t\tcol := &Column{}\n\t\tbuffer = c.decodeColumn(buffer, col, ordinal)\n\t\tchk.columns = append(chk.columns, col)\n\t}\n\treturn chk, buffer\n}\n\n// DecodeToChunk decodes a Chunk from a byte slice, return the remained unused bytes.\nfunc (c *Codec) DecodeToChunk(buffer []byte, chk *Chunk) (remained []byte) {\n\tfor i := 0; i < len(chk.columns); i++ {\n\t\tbuffer = c.decodeColumn(buffer, chk.columns[i], i)\n\t}\n\treturn buffer\n}\n\n// decodeColumn decodes a Column from a byte slice, return the remained unused bytes.\nfunc (c *Codec) decodeColumn(buffer []byte, col *Column, ordinal int) (remained []byte) {\n\t// Todo(Shenghui Wu): Optimize all data is null.\n\t// decode length.\n\tcol.length = int(binary.LittleEndian.Uint32(buffer))\n\tbuffer = buffer[4:]\n\n\t// decode nullCount.\n\tnullCount := int(binary.LittleEndian.Uint32(buffer))\n\tbuffer = buffer[4:]\n\n\t// decode nullBitmap.\n\tif nullCount > 0 {\n\t\tnumNullBitmapBytes := (col.length + 7) / 8\n\t\tcol.nullBitmap = buffer[:numNullBitmapBytes:numNullBitmapBytes]\n\t\tbuffer = buffer[numNullBitmapBytes:]\n\t} else {\n\t\tc.setAllNotNull(col)\n\t}\n\n\t// decode offsets.\n\tnumFixedBytes := getFixedLen(c.colTypes[ordinal])\n\tnumDataBytes := int64(numFixedBytes * col.length)\n\tif numFixedBytes == -1 {\n\t\tnumOffsetBytes := (col.length + 1) * 8\n\t\tcol.offsets = bytesToI64Slice(buffer[:numOffsetBytes:numOffsetBytes])\n\t\tbuffer = buffer[numOffsetBytes:]\n\t\tnumDataBytes = col.offsets[col.length]\n\t} else if cap(col.elemBuf) < numFixedBytes {\n\t\tcol.elemBuf = make([]byte, numFixedBytes)\n\t}\n\n\t// decode data.\n\tcol.data = buffer[:numDataBytes:numDataBytes]\n\treturn buffer[numDataBytes:]\n}\n\nvar allNotNullBitmap [128]byte\n\nfunc (c *Codec) setAllNotNull(col *Column) {\n\tnumNullBitmapBytes := (col.length + 7) / 8\n\tcol.nullBitmap = col.nullBitmap[:0]\n\tfor i := 0; i < numNullBitmapBytes; {\n\t\tnumAppendBytes := mathutil.Min(numNullBitmapBytes-i, cap(allNotNullBitmap))\n\t\tcol.nullBitmap = append(col.nullBitmap, allNotNullBitmap[:numAppendBytes]...)\n\t\ti += numAppendBytes\n\t}\n}\n\nfunc bytesToI64Slice(b []byte) (i64s []int64) {\n\tif len(b) == 0 {\n\t\treturn nil\n\t}\n\thdr := (*reflect.SliceHeader)(unsafe.Pointer(&i64s))\n\thdr.Len = len(b) / 8\n\thdr.Cap = hdr.Len\n\thdr.Data = uintptr(unsafe.Pointer(&b[0]))\n\treturn i64s\n}\n\n// varElemLen indicates this Column is a variable length Column.\nconst varElemLen = -1\n\nfunc getFixedLen(colType *types.FieldType) int {\n\tswitch colType.Tp {\n\tcase mysql.TypeFloat:\n\t\treturn 4\n\tcase mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong,\n\t\tmysql.TypeLonglong, mysql.TypeDouble, mysql.TypeYear:\n\t\treturn 8\n\tdefault:\n\t\treturn varElemLen\n\t}\n}\n\n// GetFixedLen get the memory size of a fixed-length type.\n// if colType is not fixed-length, it returns varElemLen, aka -1.\nfunc GetFixedLen(colType *types.FieldType) int {\n\treturn getFixedLen(colType)\n}\n\n// EstimateTypeWidth estimates the average width of values of the type.\n// This is used by the planner, which doesn't require absolutely correct results;\n// it's OK (and expected) to guess if we don't know for sure.\n//\n// mostly study from https://github.com/postgres/postgres/blob/REL_12_STABLE/src/backend/utils/cache/lsyscache.c#L2356\nfunc EstimateTypeWidth(colType *types.FieldType) int {\n\tcolLen := getFixedLen(colType)\n\t// Easy if it's a fixed-width type\n\tif colLen != varElemLen {\n\t\treturn colLen\n\t}\n\n\tcolLen = colType.Flen\n\tif colLen > 0 {\n\t\tif colLen <= 32 {\n\t\t\treturn colLen\n\t\t}\n\t\tif colLen < 1000 {\n\t\t\treturn 32 + (colLen-32)/2 // assume 50%\n\t\t}\n\t\t/*\n\t\t * Beyond 1000, assume we're looking at something like\n\t\t * \"varchar(10000)\" where the limit isn't actually reached often, and\n\t\t * use a fixed estimate.\n\t\t */\n\t\treturn 32 + (1000-32)/2\n\t}\n\t// Oops, we have no idea ... wild guess time.\n\treturn 32\n}\n\nfunc init() {\n\tfor i := 0; i < 128; i++ {\n\t\tallNotNullBitmap[i] = 0xFF\n\t}\n}\n\n// Decoder decodes the data returned from the coprocessor and stores the result in Chunk.\n// How Decoder works:\n//  1. Initialization phase: Decode a whole input byte slice to Decoder.intermChk(intermediate chunk) using Codec.Decode.\n//     intermChk is introduced to simplify the implementation of decode phase. This phase uses pointer operations with\n//     less CPU and memory cost.\n//  2. Decode phase:\n//     2.1 Set the number of rows to be decoded to a value that is a multiple of 8 and greater than\n//     `chk.RequiredRows() - chk.NumRows()`. This reduces the overhead of copying the srcCol.nullBitMap into\n//     destCol.nullBitMap.\n//     2.2 Append srcCol.offsets to destCol.offsets when the elements is of var-length type. And further adjust the\n//     offsets according to descCol.offsets[destCol.length]-srcCol.offsets[0].\n//     2.3 Append srcCol.nullBitMap to destCol.nullBitMap.\n//  3. Go to step 1 when the input byte slice is consumed.\ntype Decoder struct {\n\tintermChk    *Chunk\n\tcodec        *Codec\n\tremainedRows int\n}\n\n// NewDecoder creates a new Decoder object for decode a Chunk.\nfunc NewDecoder(chk *Chunk, colTypes []*types.FieldType) *Decoder {\n\treturn &Decoder{intermChk: chk, codec: NewCodec(colTypes), remainedRows: 0}\n}\n\n// Decode decodes multiple rows of Decoder.intermChk and stores the result in chk.\nfunc (c *Decoder) Decode(chk *Chunk) {\n\trequiredRows := chk.RequiredRows() - chk.NumRows()\n\t// Set the requiredRows to a multiple of 8.\n\trequiredRows = (requiredRows + 7) >> 3 << 3\n\tif requiredRows > c.remainedRows {\n\t\trequiredRows = c.remainedRows\n\t}\n\tfor i := 0; i < chk.NumCols(); i++ {\n\t\tc.decodeColumn(chk, i, requiredRows)\n\t}\n\tc.remainedRows -= requiredRows\n}\n\n// Reset decodes data and store the result in Decoder.intermChk. This decode phase uses pointer operations with less\n// CPU and memory costs.\nfunc (c *Decoder) Reset(data []byte) {\n\tc.codec.DecodeToChunk(data, c.intermChk)\n\tc.remainedRows = c.intermChk.NumRows()\n}\n\n// IsFinished indicates whether Decoder.intermChk has been dried up.\nfunc (c *Decoder) IsFinished() bool {\n\treturn c.remainedRows == 0\n}\n\n// RemainedRows indicates Decoder.intermChk has remained rows.\nfunc (c *Decoder) RemainedRows() int {\n\treturn c.remainedRows\n}\n\n// ReuseIntermChk swaps `Decoder.intermChk` with `chk` directly when `Decoder.intermChk.NumRows()` is no less\n// than `chk.requiredRows * factor` where `factor` is 0.8 now. This can avoid the overhead of appending the\n// data from `Decoder.intermChk` to `chk`. Moreover, the column.offsets needs to be further adjusted\n// according to column.offset[0].\nfunc (c *Decoder) ReuseIntermChk(chk *Chunk) {\n\tfor i, col := range c.intermChk.columns {\n\t\tcol.length = c.remainedRows\n\t\telemLen := getFixedLen(c.codec.colTypes[i])\n\t\tif elemLen == varElemLen {\n\t\t\t// For var-length types, we need to adjust the offsets before reuse.\n\t\t\tif deltaOffset := col.offsets[0]; deltaOffset != 0 {\n\t\t\t\tfor j := 0; j < len(col.offsets); j++ {\n\t\t\t\t\tcol.offsets[j] -= deltaOffset\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tchk.SwapColumns(c.intermChk)\n\tc.remainedRows = 0\n}\n\nfunc (c *Decoder) decodeColumn(chk *Chunk, ordinal int, requiredRows int) {\n\telemLen := getFixedLen(c.codec.colTypes[ordinal])\n\tnumDataBytes := int64(elemLen * requiredRows)\n\tsrcCol := c.intermChk.columns[ordinal]\n\tdestCol := chk.columns[ordinal]\n\n\tif elemLen == varElemLen {\n\t\t// For var-length types, we need to adjust the offsets after appending to destCol.\n\t\tnumDataBytes = srcCol.offsets[requiredRows] - srcCol.offsets[0]\n\t\tdeltaOffset := destCol.offsets[destCol.length] - srcCol.offsets[0]\n\t\tdestCol.offsets = append(destCol.offsets, srcCol.offsets[1:requiredRows+1]...)\n\t\tfor i := destCol.length + 1; i <= destCol.length+requiredRows; i++ {\n\t\t\tdestCol.offsets[i] = destCol.offsets[i] + deltaOffset\n\t\t}\n\t\tsrcCol.offsets = srcCol.offsets[requiredRows:]\n\t}\n\n\tnumNullBitmapBytes := (requiredRows + 7) >> 3\n\tif destCol.length%8 == 0 {\n\t\tdestCol.nullBitmap = append(destCol.nullBitmap, srcCol.nullBitmap[:numNullBitmapBytes]...)\n\t} else {\n\t\tdestCol.appendMultiSameNullBitmap(false, requiredRows)\n\t\tbitMapLen := len(destCol.nullBitmap)\n\t\t// bitOffset indicates the number of valid bits in destCol.nullBitmap's last byte.\n\t\tbitOffset := destCol.length % 8\n\t\tstartIdx := (destCol.length - 1) >> 3\n\t\tfor i := 0; i < numNullBitmapBytes; i++ {\n\t\t\tdestCol.nullBitmap[startIdx+i] |= srcCol.nullBitmap[i] << bitOffset\n\t\t\t// The high order 8-bitOffset bits in `srcCol.nullBitmap[i]` should be appended to the low order of the next slot.\n\t\t\tif startIdx+i+1 < bitMapLen {\n\t\t\t\tdestCol.nullBitmap[startIdx+i+1] |= srcCol.nullBitmap[i] >> (8 - bitOffset)\n\t\t\t}\n\t\t}\n\t}\n\t// Set all the redundant bits in the last slot of destCol.nullBitmap to 0.\n\tnumRedundantBits := uint(len(destCol.nullBitmap)*8 - destCol.length - requiredRows)\n\tbitMask := byte(1<<(8-numRedundantBits)) - 1\n\tdestCol.nullBitmap[len(destCol.nullBitmap)-1] &= bitMask\n\n\tsrcCol.nullBitmap = srcCol.nullBitmap[numNullBitmapBytes:]\n\tdestCol.length += requiredRows\n\n\tdestCol.data = append(destCol.data, srcCol.data[:numDataBytes]...)\n\tsrcCol.data = srcCol.data[numDataBytes:]\n}\n"
  },
  {
    "path": "pkg/util/chunk/column.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage chunk\n\nimport (\n\t\"fmt\"\n\t\"math/bits\"\n\t\"reflect\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/hack\"\n)\n\n// Column stores one column of data in Apache Arrow format.\n// See https://arrow.apache.org/docs/memory_layout.html\ntype Column struct {\n\tlength     int\n\tnullBitmap []byte // bit 0 is null, 1 is not null\n\toffsets    []int64\n\tdata       []byte\n\telemBuf    []byte\n}\n\n// NewColumn creates a new column with the specific length and capacity.\nfunc NewColumn(ft *types.FieldType, capacity int) *Column {\n\treturn newColumn(getFixedLen(ft), capacity)\n}\n\nfunc newColumn(typeSize, capacity int) *Column {\n\tvar col *Column\n\tif typeSize == varElemLen {\n\t\tcol = newVarLenColumn(capacity, nil)\n\t} else {\n\t\tcol = newFixedLenColumn(typeSize, capacity)\n\t}\n\treturn col\n}\n\nfunc (c *Column) typeSize() int {\n\tif len(c.elemBuf) > 0 {\n\t\treturn len(c.elemBuf)\n\t}\n\treturn varElemLen\n}\n\nfunc (c *Column) isFixed() bool {\n\treturn c.elemBuf != nil\n}\n\n// Reset resets this Column according to the EvalType.\n// Different from reset, Reset will reset the elemBuf.\nfunc (c *Column) Reset(eType types.EvalType) {\n\tswitch eType {\n\tcase types.ETInt:\n\t\tc.ResizeInt64(0, false)\n\tcase types.ETReal:\n\t\tc.ResizeFloat64(0, false)\n\tcase types.ETString:\n\t\tc.ReserveString(0)\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"invalid EvalType %v\", eType))\n\t}\n}\n\n// reset resets the underlying data of this Column but doesn't modify its data type.\nfunc (c *Column) reset() {\n\tc.length = 0\n\tc.nullBitmap = c.nullBitmap[:0]\n\tif len(c.offsets) > 0 {\n\t\t// The first offset is always 0, it makes slicing the data easier, we need to keep it.\n\t\tc.offsets = c.offsets[:1]\n\t}\n\tc.data = c.data[:0]\n}\n\n// IsNull returns if this row is null.\nfunc (c *Column) IsNull(rowIdx int) bool {\n\tnullByte := c.nullBitmap[rowIdx/8]\n\treturn nullByte&(1<<(uint(rowIdx)&7)) == 0\n}\n\n// CopyConstruct copies this Column to dst.\n// If dst is nil, it creates a new Column and returns it.\nfunc (c *Column) CopyConstruct(dst *Column) *Column {\n\tif dst != nil {\n\t\tdst.length = c.length\n\t\tdst.nullBitmap = append(dst.nullBitmap[:0], c.nullBitmap...)\n\t\tdst.offsets = append(dst.offsets[:0], c.offsets...)\n\t\tdst.data = append(dst.data[:0], c.data...)\n\t\tdst.elemBuf = append(dst.elemBuf[:0], c.elemBuf...)\n\t\treturn dst\n\t}\n\tnewCol := &Column{length: c.length}\n\tnewCol.nullBitmap = append(newCol.nullBitmap, c.nullBitmap...)\n\tnewCol.offsets = append(newCol.offsets, c.offsets...)\n\tnewCol.data = append(newCol.data, c.data...)\n\tnewCol.elemBuf = append(newCol.elemBuf, c.elemBuf...)\n\treturn newCol\n}\n\nfunc (c *Column) appendNullBitmap(notNull bool) {\n\tidx := c.length >> 3\n\tif idx >= len(c.nullBitmap) {\n\t\tc.nullBitmap = append(c.nullBitmap, 0)\n\t}\n\tif notNull {\n\t\tpos := uint(c.length) & 7\n\t\tc.nullBitmap[idx] |= byte(1 << pos)\n\t}\n}\n\n// appendMultiSameNullBitmap appends multiple same bit value to `nullBitMap`.\n// notNull means not null.\n// num means the number of bits that should be appended.\nfunc (c *Column) appendMultiSameNullBitmap(notNull bool, num int) {\n\tnumNewBytes := ((c.length + num + 7) >> 3) - len(c.nullBitmap)\n\tb := byte(0)\n\tif notNull {\n\t\tb = 0xff\n\t}\n\tfor i := 0; i < numNewBytes; i++ {\n\t\tc.nullBitmap = append(c.nullBitmap, b)\n\t}\n\tif !notNull {\n\t\treturn\n\t}\n\t// 1. Set all the remaining bits in the last slot of old c.numBitMap to 1.\n\tnumRemainingBits := uint(c.length % 8)\n\tbitMask := byte(^((1 << numRemainingBits) - 1))\n\tc.nullBitmap[c.length/8] |= bitMask\n\t// 2. Set all the redundant bits in the last slot of new c.numBitMap to 0.\n\tnumRedundantBits := uint(len(c.nullBitmap)*8 - c.length - num)\n\tbitMask = byte(1<<(8-numRedundantBits)) - 1\n\tc.nullBitmap[len(c.nullBitmap)-1] &= bitMask\n}\n\n// AppendNull appends a null value into this Column.\nfunc (c *Column) AppendNull() {\n\tc.appendNullBitmap(false)\n\tif c.isFixed() {\n\t\tc.data = append(c.data, c.elemBuf...)\n\t} else {\n\t\tc.offsets = append(c.offsets, c.offsets[c.length])\n\t}\n\tc.length++\n}\n\nfunc (c *Column) finishAppendFixed() {\n\tc.data = append(c.data, c.elemBuf...)\n\tc.appendNullBitmap(true)\n\tc.length++\n}\n\n// AppendInt64 appends an int64 value into this Column.\nfunc (c *Column) AppendInt64(i int64) {\n\t*(*int64)(unsafe.Pointer(&c.elemBuf[0])) = i\n\tc.finishAppendFixed()\n}\n\n// AppendUint64 appends a uint64 value into this Column.\nfunc (c *Column) AppendUint64(u uint64) {\n\t*(*uint64)(unsafe.Pointer(&c.elemBuf[0])) = u\n\tc.finishAppendFixed()\n}\n\n// AppendFloat32 appends a float32 value into this Column.\nfunc (c *Column) AppendFloat32(f float32) {\n\t*(*float32)(unsafe.Pointer(&c.elemBuf[0])) = f\n\tc.finishAppendFixed()\n}\n\n// AppendFloat64 appends a float64 value into this Column.\nfunc (c *Column) AppendFloat64(f float64) {\n\t*(*float64)(unsafe.Pointer(&c.elemBuf[0])) = f\n\tc.finishAppendFixed()\n}\n\nfunc (c *Column) finishAppendVar() {\n\tc.appendNullBitmap(true)\n\tc.offsets = append(c.offsets, int64(len(c.data)))\n\tc.length++\n}\n\n// AppendString appends a string value into this Column.\nfunc (c *Column) AppendString(str string) {\n\tc.data = append(c.data, str...)\n\tc.finishAppendVar()\n}\n\n// AppendBytes appends a byte slice into this Column.\nfunc (c *Column) AppendBytes(b []byte) {\n\tc.data = append(c.data, b...)\n\tc.finishAppendVar()\n}\n\nconst (\n\tsizeInt64   = int(unsafe.Sizeof(int64(0)))\n\tsizeUint64  = int(unsafe.Sizeof(uint64(0)))\n\tsizeFloat32 = int(unsafe.Sizeof(float32(0)))\n\tsizeFloat64 = int(unsafe.Sizeof(float64(0)))\n\tsizeTime    = int(unsafe.Sizeof(types.ZeroTime))\n)\n\nvar (\n\temptyBuf = make([]byte, 4*1024)\n)\n\n// resize resizes the column so that it contains n elements, only valid for fixed-length types.\nfunc (c *Column) resize(n, typeSize int, isNull bool) {\n\tsizeData := n * typeSize\n\tif cap(c.data) >= sizeData {\n\t\t(*reflect.SliceHeader)(unsafe.Pointer(&c.data)).Len = sizeData\n\t} else {\n\t\tc.data = make([]byte, sizeData)\n\t}\n\tif !isNull {\n\t\tfor j := 0; j < sizeData; j += len(emptyBuf) {\n\t\t\tcopy(c.data[j:], emptyBuf)\n\t\t}\n\t}\n\n\tnewNulls := false\n\tsizeNulls := (n + 7) >> 3\n\tif cap(c.nullBitmap) >= sizeNulls {\n\t\t(*reflect.SliceHeader)(unsafe.Pointer(&c.nullBitmap)).Len = sizeNulls\n\t} else {\n\t\tc.nullBitmap = make([]byte, sizeNulls)\n\t\tnewNulls = true\n\t}\n\tif !isNull || !newNulls {\n\t\tvar nullVal byte\n\t\tif !isNull {\n\t\t\tnullVal = 0xFF\n\t\t}\n\t\tfor i := range c.nullBitmap {\n\t\t\tc.nullBitmap[i] = nullVal\n\t\t}\n\t}\n\n\tif cap(c.elemBuf) >= typeSize {\n\t\t(*reflect.SliceHeader)(unsafe.Pointer(&c.elemBuf)).Len = typeSize\n\t} else {\n\t\tc.elemBuf = make([]byte, typeSize)\n\t}\n\n\tc.length = n\n}\n\n// reserve makes the column capacity be at least enough to contain n elements.\n// this method is only valid for var-length types and estElemSize is the estimated size of this type.\nfunc (c *Column) reserve(n, estElemSize int) {\n\tsizeData := n * estElemSize\n\tif cap(c.data) >= sizeData {\n\t\tc.data = c.data[:0]\n\t} else {\n\t\tc.data = make([]byte, 0, sizeData)\n\t}\n\n\tsizeNulls := (n + 7) >> 3\n\tif cap(c.nullBitmap) >= sizeNulls {\n\t\tc.nullBitmap = c.nullBitmap[:0]\n\t} else {\n\t\tc.nullBitmap = make([]byte, 0, sizeNulls)\n\t}\n\n\tsizeOffs := n + 1\n\tif cap(c.offsets) >= sizeOffs {\n\t\tc.offsets = c.offsets[:1]\n\t} else {\n\t\tc.offsets = make([]int64, 1, sizeOffs)\n\t}\n\n\tc.elemBuf = nil\n\tc.length = 0\n}\n\n// SetNull sets the rowIdx to null.\nfunc (c *Column) SetNull(rowIdx int, isNull bool) {\n\tif isNull {\n\t\tc.nullBitmap[rowIdx>>3] &= ^(1 << uint(rowIdx&7))\n\t} else {\n\t\tc.nullBitmap[rowIdx>>3] |= 1 << uint(rowIdx&7)\n\t}\n}\n\n// SetNulls sets rows in [begin, end) to null.\nfunc (c *Column) SetNulls(begin, end int, isNull bool) {\n\ti := ((begin + 7) >> 3) << 3\n\tfor ; begin < i && begin < end; begin++ {\n\t\tc.SetNull(begin, isNull)\n\t}\n\tvar v uint8\n\tif !isNull {\n\t\tv = (1 << 8) - 1\n\t}\n\tfor ; begin+8 <= end; begin += 8 {\n\t\tc.nullBitmap[begin>>3] = v\n\t}\n\tfor ; begin < end; begin++ {\n\t\tc.SetNull(begin, isNull)\n\t}\n}\n\n// nullCount returns the number of nulls in this Column.\nfunc (c *Column) nullCount() int {\n\tvar cnt, i int\n\tfor ; i+8 <= c.length; i += 8 {\n\t\t// 0 is null and 1 is not null\n\t\tcnt += 8 - bits.OnesCount8(uint8(c.nullBitmap[i>>3]))\n\t}\n\tfor ; i < c.length; i++ {\n\t\tif c.IsNull(i) {\n\t\t\tcnt++\n\t\t}\n\t}\n\treturn cnt\n}\n\n// ResizeInt64 resizes the column so that it contains n int64 elements.\nfunc (c *Column) ResizeInt64(n int, isNull bool) {\n\tc.resize(n, sizeInt64, isNull)\n}\n\n// ResizeUint64 resizes the column so that it contains n uint64 elements.\nfunc (c *Column) ResizeUint64(n int, isNull bool) {\n\tc.resize(n, sizeUint64, isNull)\n}\n\n// ResizeFloat32 resizes the column so that it contains n float32 elements.\nfunc (c *Column) ResizeFloat32(n int, isNull bool) {\n\tc.resize(n, sizeFloat32, isNull)\n}\n\n// ResizeFloat64 resizes the column so that it contains n float64 elements.\nfunc (c *Column) ResizeFloat64(n int, isNull bool) {\n\tc.resize(n, sizeFloat64, isNull)\n}\n\n// ReserveString changes the column capacity to store n string elements and set the length to zero.\nfunc (c *Column) ReserveString(n int) {\n\tc.reserve(n, 8)\n}\n\n// ReserveBytes changes the column capacity to store n bytes elements and set the length to zero.\nfunc (c *Column) ReserveBytes(n int) {\n\tc.reserve(n, 8)\n}\n\nfunc (c *Column) castSliceHeader(header *reflect.SliceHeader, typeSize int) {\n\theader.Data = (*reflect.SliceHeader)(unsafe.Pointer(&c.data)).Data\n\theader.Len = c.length\n\theader.Cap = cap(c.data) / typeSize\n}\n\n// Int64s returns an int64 slice stored in this Column.\nfunc (c *Column) Int64s() []int64 {\n\tvar res []int64\n\tc.castSliceHeader((*reflect.SliceHeader)(unsafe.Pointer(&res)), sizeInt64)\n\treturn res\n}\n\n// Uint64s returns a uint64 slice stored in this Column.\nfunc (c *Column) Uint64s() []uint64 {\n\tvar res []uint64\n\tc.castSliceHeader((*reflect.SliceHeader)(unsafe.Pointer(&res)), sizeUint64)\n\treturn res\n}\n\n// Float32s returns a float32 slice stored in this Column.\nfunc (c *Column) Float32s() []float32 {\n\tvar res []float32\n\tc.castSliceHeader((*reflect.SliceHeader)(unsafe.Pointer(&res)), sizeFloat32)\n\treturn res\n}\n\n// Float64s returns a float64 slice stored in this Column.\nfunc (c *Column) Float64s() []float64 {\n\tvar res []float64\n\tc.castSliceHeader((*reflect.SliceHeader)(unsafe.Pointer(&res)), sizeFloat64)\n\treturn res\n}\n\n// GetInt64 returns the int64 in the specific row.\nfunc (c *Column) GetInt64(rowID int) int64 {\n\treturn *(*int64)(unsafe.Pointer(&c.data[rowID*8]))\n}\n\n// GetUint64 returns the uint64 in the specific row.\nfunc (c *Column) GetUint64(rowID int) uint64 {\n\treturn *(*uint64)(unsafe.Pointer(&c.data[rowID*8]))\n}\n\n// GetFloat32 returns the float32 in the specific row.\nfunc (c *Column) GetFloat32(rowID int) float32 {\n\treturn *(*float32)(unsafe.Pointer(&c.data[rowID*4]))\n}\n\n// GetFloat64 returns the float64 in the specific row.\nfunc (c *Column) GetFloat64(rowID int) float64 {\n\treturn *(*float64)(unsafe.Pointer(&c.data[rowID*8]))\n}\n\n// GetString returns the string in the specific row.\nfunc (c *Column) GetString(rowID int) string {\n\treturn string(hack.String(c.data[c.offsets[rowID]:c.offsets[rowID+1]]))\n}\n\n// GetBytes returns the byte slice in the specific row.\nfunc (c *Column) GetBytes(rowID int) []byte {\n\treturn c.data[c.offsets[rowID]:c.offsets[rowID+1]]\n}\n\nfunc (c *Column) getNameValue(rowID int) (string, uint64) {\n\tstart, end := c.offsets[rowID], c.offsets[rowID+1]\n\tif start == end {\n\t\treturn \"\", 0\n\t}\n\treturn string(hack.String(c.data[start+8 : end])), *(*uint64)(unsafe.Pointer(&c.data[start]))\n}\n\n// GetRaw returns the underlying raw bytes in the specific row.\nfunc (c *Column) GetRaw(rowID int) []byte {\n\tvar data []byte\n\tif c.isFixed() {\n\t\telemLen := len(c.elemBuf)\n\t\tdata = c.data[rowID*elemLen : rowID*elemLen+elemLen]\n\t} else {\n\t\tdata = c.data[c.offsets[rowID]:c.offsets[rowID+1]]\n\t}\n\treturn data\n}\n\n// SetRaw sets the raw bytes for the rowIdx-th element.\n// NOTE: Two conditions must be satisfied before calling this function:\n// 1. The column should be stored with variable-length elements.\n// 2. The length of the new element should be exactly the same as the old one.\nfunc (c *Column) SetRaw(rowID int, bs []byte) {\n\tcopy(c.data[c.offsets[rowID]:c.offsets[rowID+1]], bs)\n}\n\n// reconstruct reconstructs this Column by removing all filtered rows in it according to sel.\nfunc (c *Column) reconstruct(sel []int) {\n\tif len(sel) == 0 {\n\t\treturn\n\t}\n\tif c.isFixed() {\n\t\telemLen := len(c.elemBuf)\n\t\tfor dst, src := range sel {\n\t\t\tidx := dst >> 3\n\t\t\tpos := uint16(dst & 7)\n\t\t\tif c.IsNull(src) {\n\t\t\t\tc.nullBitmap[idx] &= ^byte(1 << pos)\n\t\t\t} else {\n\t\t\t\tcopy(c.data[dst*elemLen:dst*elemLen+elemLen], c.data[src*elemLen:src*elemLen+elemLen])\n\t\t\t\tc.nullBitmap[idx] |= byte(1 << pos)\n\t\t\t}\n\t\t}\n\t\tc.data = c.data[:len(sel)*elemLen]\n\t} else {\n\t\ttail := 0\n\t\tfor dst, src := range sel {\n\t\t\tidx := dst >> 3\n\t\t\tpos := uint(dst & 7)\n\t\t\tif c.IsNull(src) {\n\t\t\t\tc.nullBitmap[idx] &= ^byte(1 << pos)\n\t\t\t\tc.offsets[dst+1] = int64(tail)\n\t\t\t} else {\n\t\t\t\tstart, end := c.offsets[src], c.offsets[src+1]\n\t\t\t\tcopy(c.data[tail:], c.data[start:end])\n\t\t\t\ttail += int(end - start)\n\t\t\t\tc.offsets[dst+1] = int64(tail)\n\t\t\t\tc.nullBitmap[idx] |= byte(1 << pos)\n\t\t\t}\n\t\t}\n\t\tc.data = c.data[:tail]\n\t\tc.offsets = c.offsets[:len(sel)+1]\n\t}\n\tc.length = len(sel)\n\n\t// clean nullBitmap\n\tc.nullBitmap = c.nullBitmap[:(len(sel)+7)>>3]\n\tidx := len(sel) >> 3\n\tif idx < len(c.nullBitmap) {\n\t\tpos := uint16(len(sel) & 7)\n\t\tc.nullBitmap[idx] &= byte((1 << pos) - 1)\n\t}\n}\n\n// CopyReconstruct copies this Column to dst and removes unselected rows.\n// If dst is nil, it creates a new Column and returns it.\nfunc (c *Column) CopyReconstruct(sel []int, dst *Column) *Column {\n\tif len(sel) == 0 {\n\t\treturn c.CopyConstruct(dst)\n\t}\n\n\tselLength := len(sel)\n\tif selLength == c.length {\n\t\t// The variable 'ascend' is used to check if the sel array is in ascending order\n\t\tascend := true\n\t\tfor i := 1; i < selLength; i++ {\n\t\t\tif sel[i] < sel[i-1] {\n\t\t\t\tascend = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif ascend {\n\t\t\treturn c.CopyConstruct(dst)\n\t\t}\n\t}\n\n\tif dst == nil {\n\t\tdst = newColumn(c.typeSize(), len(sel))\n\t} else {\n\t\tdst.reset()\n\t}\n\n\tif c.isFixed() {\n\t\telemLen := len(c.elemBuf)\n\t\tdst.elemBuf = make([]byte, elemLen)\n\t\tfor _, i := range sel {\n\t\t\tdst.appendNullBitmap(!c.IsNull(i))\n\t\t\tdst.data = append(dst.data, c.data[i*elemLen:i*elemLen+elemLen]...)\n\t\t\tdst.length++\n\t\t}\n\t} else {\n\t\tdst.elemBuf = nil\n\t\tif len(dst.offsets) == 0 {\n\t\t\tdst.offsets = append(dst.offsets, 0)\n\t\t}\n\t\tfor _, i := range sel {\n\t\t\tdst.appendNullBitmap(!c.IsNull(i))\n\t\t\tstart, end := c.offsets[i], c.offsets[i+1]\n\t\t\tdst.data = append(dst.data, c.data[start:end]...)\n\t\t\tdst.offsets = append(dst.offsets, int64(len(dst.data)))\n\t\t\tdst.length++\n\t\t}\n\t}\n\treturn dst\n}\n\n// MergeNulls merges these columns' null bitmaps.\n// For a row, if any column of it is null, the result is null.\n// It works like: if col1.IsNull || col2.IsNull || col3.IsNull.\n// The caller should ensure that all these columns have the same\n// length, and data stored in the result column is fixed-length type.\nfunc (c *Column) MergeNulls(cols ...*Column) {\n\tif !c.isFixed() {\n\t\tpanic(\"result column should be fixed-length type\")\n\t}\n\tfor _, col := range cols {\n\t\tif c.length != col.length {\n\t\t\tpanic(\"should ensure all columns have the same length\")\n\t\t}\n\t}\n\tfor _, col := range cols {\n\t\tfor i := range c.nullBitmap {\n\t\t\t// bit 0 is null, 1 is not null, so do AND operations here.\n\t\t\tc.nullBitmap[i] &= col.nullBitmap[i]\n\t\t}\n\t}\n}\n\n// GetDecimal returns the decimal in the specific row.\nfunc (c *Column) GetDecimal(rowID int) *types.MyDecimal {\n\treturn (*types.MyDecimal)(unsafe.Pointer(&c.data[rowID*types.MyDecimalStructSize]))\n}\n\n// GetTime returns the Time in the specific row.\nfunc (c *Column) GetTime(rowID int) types.Time {\n\treturn *(*types.Time)(unsafe.Pointer(&c.data[rowID*sizeTime]))\n}\n\n// GetDuration returns the Duration in the specific row.\nfunc (c *Column) GetDuration(rowID int, fillFsp int) types.Duration {\n\tdur := *(*int64)(unsafe.Pointer(&c.data[rowID*8]))\n\treturn types.Duration{Duration: time.Duration(dur), Fsp: int8(fillFsp)}\n}\n"
  },
  {
    "path": "pkg/util/chunk/compare.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage chunk\n\nimport (\n\t\"sort\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// CompareFunc is a function to compare the two values in Row, the two columns must have the same type.\ntype CompareFunc = func(l Row, lCol int, r Row, rCol int) int\n\n// GetCompareFunc gets a compare function for the field type.\nfunc GetCompareFunc(tp *types.FieldType) CompareFunc {\n\tswitch tp.Tp {\n\tcase mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeYear:\n\t\tif mysql.HasUnsignedFlag(tp.Flag) {\n\t\t\treturn cmpUint64\n\t\t}\n\t\treturn cmpInt64\n\tcase mysql.TypeFloat:\n\t\treturn cmpFloat32\n\tcase mysql.TypeDouble:\n\t\treturn cmpFloat64\n\tcase mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar,\n\t\tmysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob:\n\t\treturn cmpString\n\t}\n\treturn nil\n}\n\nfunc cmpNull(lNull, rNull bool) int {\n\tif lNull && rNull {\n\t\treturn 0\n\t}\n\tif lNull {\n\t\treturn -1\n\t}\n\treturn 1\n}\n\nfunc cmpInt64(l Row, lCol int, r Row, rCol int) int {\n\tlNull, rNull := l.IsNull(lCol), r.IsNull(rCol)\n\tif lNull || rNull {\n\t\treturn cmpNull(lNull, rNull)\n\t}\n\treturn types.CompareInt64(l.GetInt64(lCol), r.GetInt64(rCol))\n}\n\nfunc cmpUint64(l Row, lCol int, r Row, rCol int) int {\n\tlNull, rNull := l.IsNull(lCol), r.IsNull(rCol)\n\tif lNull || rNull {\n\t\treturn cmpNull(lNull, rNull)\n\t}\n\treturn types.CompareUint64(l.GetUint64(lCol), r.GetUint64(rCol))\n}\n\nfunc cmpString(l Row, lCol int, r Row, rCol int) int {\n\tlNull, rNull := l.IsNull(lCol), r.IsNull(rCol)\n\tif lNull || rNull {\n\t\treturn cmpNull(lNull, rNull)\n\t}\n\treturn types.CompareString(l.GetString(lCol), r.GetString(rCol))\n}\n\nfunc cmpFloat32(l Row, lCol int, r Row, rCol int) int {\n\tlNull, rNull := l.IsNull(lCol), r.IsNull(rCol)\n\tif lNull || rNull {\n\t\treturn cmpNull(lNull, rNull)\n\t}\n\treturn types.CompareFloat64(float64(l.GetFloat32(lCol)), float64(r.GetFloat32(rCol)))\n}\n\nfunc cmpFloat64(l Row, lCol int, r Row, rCol int) int {\n\tlNull, rNull := l.IsNull(lCol), r.IsNull(rCol)\n\tif lNull || rNull {\n\t\treturn cmpNull(lNull, rNull)\n\t}\n\treturn types.CompareFloat64(l.GetFloat64(lCol), r.GetFloat64(rCol))\n}\n\nfunc cmpNameValue(l Row, lCol int, r Row, rCol int) int {\n\tlNull, rNull := l.IsNull(lCol), r.IsNull(rCol)\n\tif lNull || rNull {\n\t\treturn cmpNull(lNull, rNull)\n\t}\n\t_, lVal := l.getNameValue(lCol)\n\t_, rVal := r.getNameValue(rCol)\n\treturn types.CompareUint64(lVal, rVal)\n}\n\n// Compare compares the value with ad.\nfunc Compare(row Row, colIdx int, ad *types.Datum) int {\n\tswitch ad.Kind() {\n\tcase types.KindNull:\n\t\tif row.IsNull(colIdx) {\n\t\t\treturn 0\n\t\t}\n\t\treturn 1\n\tcase types.KindMinNotNull:\n\t\tif row.IsNull(colIdx) {\n\t\t\treturn -1\n\t\t}\n\t\treturn 1\n\tcase types.KindMaxValue:\n\t\treturn -1\n\tcase types.KindInt64:\n\t\treturn types.CompareInt64(row.GetInt64(colIdx), ad.GetInt64())\n\tcase types.KindUint64:\n\t\treturn types.CompareUint64(row.GetUint64(colIdx), ad.GetUint64())\n\tcase types.KindFloat32:\n\t\treturn types.CompareFloat64(float64(row.GetFloat32(colIdx)), float64(ad.GetFloat32()))\n\tcase types.KindFloat64:\n\t\treturn types.CompareFloat64(row.GetFloat64(colIdx), ad.GetFloat64())\n\tcase types.KindString, types.KindBytes, types.KindBinaryLiteral:\n\t\treturn types.CompareString(row.GetString(colIdx), ad.GetString())\n\tdefault:\n\t\treturn 0\n\t}\n}\n\n// LowerBound searches on the non-decreasing Column colIdx,\n// returns the smallest index i such that the value at row i is not less than `d`.\nfunc (c *Chunk) LowerBound(colIdx int, d *types.Datum) (index int, match bool) {\n\tindex = sort.Search(c.NumRows(), func(i int) bool {\n\t\tcmp := Compare(c.GetRow(i), colIdx, d)\n\t\tif cmp == 0 {\n\t\t\tmatch = true\n\t\t}\n\t\treturn cmp >= 0\n\t})\n\treturn\n}\n\n// UpperBound searches on the non-decreasing Column colIdx,\n// returns the smallest index i such that the value at row i is larger than `d`.\nfunc (c *Chunk) UpperBound(colIdx int, d *types.Datum) int {\n\treturn sort.Search(c.NumRows(), func(i int) bool {\n\t\treturn Compare(c.GetRow(i), colIdx, d) > 0\n\t})\n}\n"
  },
  {
    "path": "pkg/util/chunk/iterator.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage chunk\n\nvar (\n\t_ Iterator = (*Iterator4Chunk)(nil)\n)\n\n// Iterator is used to iterate a number of rows.\n//\n//\tfor row := it.Begin(); row != it.End(); row = it.Next() {\n//\t    ...\n//\t}\ntype Iterator interface {\n\t// Begin resets the cursor of the iterator and returns the first Row.\n\tBegin() Row\n\n\t// Next returns the next Row.\n\tNext() Row\n\n\t// End returns the invalid end Row.\n\tEnd() Row\n\n\t// Len returns the length.\n\tLen() int\n\n\t// Current returns the current Row.\n\tCurrent() Row\n\n\t// ReachEnd reaches the end of iterator.\n\tReachEnd()\n\n\t// Error returns none-nil error if anything wrong happens during the iteration.\n\tError() error\n}\n\n// NewIterator4Chunk returns a iterator for Chunk.\nfunc NewIterator4Chunk(chk *Chunk) *Iterator4Chunk {\n\treturn &Iterator4Chunk{chk: chk}\n}\n\n// Iterator4Chunk is used to iterate rows inside a chunk.\ntype Iterator4Chunk struct {\n\tchk     *Chunk\n\tcursor  int32\n\tnumRows int32\n}\n\n// Begin implements the Iterator interface.\nfunc (it *Iterator4Chunk) Begin() Row {\n\tit.numRows = int32(it.chk.NumRows())\n\tif it.numRows == 0 {\n\t\treturn it.End()\n\t}\n\tit.cursor = 1\n\treturn it.chk.GetRow(0)\n}\n\n// Next implements the Iterator interface.\nfunc (it *Iterator4Chunk) Next() Row {\n\tif it.cursor >= it.numRows {\n\t\tit.cursor = it.numRows + 1\n\t\treturn it.End()\n\t}\n\trow := it.chk.GetRow(int(it.cursor))\n\tit.cursor++\n\treturn row\n}\n\n// Current implements the Iterator interface.\nfunc (it *Iterator4Chunk) Current() Row {\n\tif it.cursor == 0 || int(it.cursor) > it.Len() {\n\t\treturn it.End()\n\t}\n\treturn it.chk.GetRow(int(it.cursor) - 1)\n}\n\n// End implements the Iterator interface.\nfunc (it *Iterator4Chunk) End() Row {\n\treturn Row{}\n}\n\n// ReachEnd implements the Iterator interface.\nfunc (it *Iterator4Chunk) ReachEnd() {\n\tit.cursor = int32(it.Len() + 1)\n}\n\n// Len implements the Iterator interface\nfunc (it *Iterator4Chunk) Len() int {\n\treturn it.chk.NumRows()\n}\n\n// GetChunk returns the chunk stored in the Iterator4Chunk\nfunc (it *Iterator4Chunk) GetChunk() *Chunk {\n\treturn it.chk\n}\n\n// Error returns none-nil error if anything wrong happens during the iteration.\nfunc (it *Iterator4Chunk) Error() error {\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/util/chunk/row.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage chunk\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/hack\"\n)\n\n// Row represents a row of data, can be used to access values.\ntype Row struct {\n\tc   *Chunk\n\tidx int\n}\n\n// Chunk returns the Chunk which the row belongs to.\nfunc (r Row) Chunk() *Chunk {\n\treturn r.c\n}\n\n// IsEmpty returns true if the Row is empty.\nfunc (r Row) IsEmpty() bool {\n\treturn r == Row{}\n}\n\n// Idx returns the row index of Chunk.\nfunc (r Row) Idx() int {\n\treturn r.idx\n}\n\n// Len returns the number of values in the row.\nfunc (r Row) Len() int {\n\treturn r.c.NumCols()\n}\n\n// GetInt64 returns the int64 value with the colIdx.\nfunc (r Row) GetInt64(colIdx int) int64 {\n\treturn r.c.columns[colIdx].GetInt64(r.idx)\n}\n\n// GetUint64 returns the uint64 value with the colIdx.\nfunc (r Row) GetUint64(colIdx int) uint64 {\n\treturn r.c.columns[colIdx].GetUint64(r.idx)\n}\n\n// GetFloat32 returns the float32 value with the colIdx.\nfunc (r Row) GetFloat32(colIdx int) float32 {\n\treturn r.c.columns[colIdx].GetFloat32(r.idx)\n}\n\n// GetFloat64 returns the float64 value with the colIdx.\nfunc (r Row) GetFloat64(colIdx int) float64 {\n\treturn r.c.columns[colIdx].GetFloat64(r.idx)\n}\n\n// GetString returns the string value with the colIdx.\nfunc (r Row) GetString(colIdx int) string {\n\treturn r.c.columns[colIdx].GetString(r.idx)\n}\n\n// GetBytes returns the bytes value with the colIdx.\nfunc (r Row) GetBytes(colIdx int) []byte {\n\treturn r.c.columns[colIdx].GetBytes(r.idx)\n}\n\n// GetTime returns the Time value with the colIdx.\nfunc (r Row) GetTime(colIdx int) types.Time {\n\treturn r.c.columns[colIdx].GetTime(r.idx)\n}\n\n// GetDuration returns the Duration value with the colIdx.\nfunc (r Row) GetDuration(colIdx int, fillFsp int) types.Duration {\n\treturn r.c.columns[colIdx].GetDuration(r.idx, fillFsp)\n}\n\nfunc (r Row) getNameValue(colIdx int) (string, uint64) {\n\tcol := r.c.columns[colIdx]\n\tstart, end := col.offsets[r.idx], col.offsets[r.idx+1]\n\tif start == end {\n\t\treturn \"\", 0\n\t}\n\tval := *(*uint64)(unsafe.Pointer(&col.data[start]))\n\tname := string(hack.String(col.data[start+8 : end]))\n\treturn name, val\n}\n\n// GetDatumRow converts chunk.Row to types.DatumRow.\n// Keep in mind that GetDatumRow has a reference to r.c, which is a chunk,\n// this function works only if the underlying chunk is valid or unchanged.\nfunc (r Row) GetDatumRow(fields []*types.FieldType) []types.Datum {\n\tdatumRow := make([]types.Datum, 0, r.c.NumCols())\n\tfor colIdx := 0; colIdx < r.c.NumCols(); colIdx++ {\n\t\tdatum := r.GetDatum(colIdx, fields[colIdx])\n\t\tdatumRow = append(datumRow, datum)\n\t}\n\treturn datumRow\n}\n\n// GetDatum implements the chunk.Row interface.\nfunc (r Row) GetDatum(colIdx int, tp *types.FieldType) types.Datum {\n\tvar d types.Datum\n\tswitch tp.Tp {\n\tcase mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong:\n\t\tif !r.IsNull(colIdx) {\n\t\t\tif mysql.HasUnsignedFlag(tp.Flag) {\n\t\t\t\td.SetUint64(r.GetUint64(colIdx))\n\t\t\t} else {\n\t\t\t\td.SetInt64(r.GetInt64(colIdx))\n\t\t\t}\n\t\t}\n\tcase mysql.TypeYear:\n\t\t// FIXBUG: because insert type of TypeYear is definite int64, so we regardless of the unsigned flag.\n\t\tif !r.IsNull(colIdx) {\n\t\t\td.SetInt64(r.GetInt64(colIdx))\n\t\t}\n\tcase mysql.TypeFloat:\n\t\tif !r.IsNull(colIdx) {\n\t\t\td.SetFloat32(r.GetFloat32(colIdx))\n\t\t}\n\tcase mysql.TypeDouble:\n\t\tif !r.IsNull(colIdx) {\n\t\t\td.SetFloat64(r.GetFloat64(colIdx))\n\t\t}\n\tcase mysql.TypeVarchar, mysql.TypeVarString, mysql.TypeString,\n\t\tmysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob:\n\t\tif !r.IsNull(colIdx) {\n\t\t\td.SetBytes(r.GetBytes(colIdx))\n\t\t}\n\t}\n\treturn d\n}\n\n// GetRaw returns the underlying raw bytes with the colIdx.\nfunc (r Row) GetRaw(colIdx int) []byte {\n\treturn r.c.columns[colIdx].GetRaw(r.idx)\n}\n\n// IsNull returns if the datum in the chunk.Row is null.\nfunc (r Row) IsNull(colIdx int) bool {\n\treturn r.c.columns[colIdx].IsNull(r.idx)\n}\n\n// CopyConstruct creates a new row and copies this row's data into it.\nfunc (r Row) CopyConstruct() Row {\n\tnewChk := renewWithCapacity(r.c, 1, 1)\n\tnewChk.AppendRow(r)\n\treturn newChk.GetRow(0)\n}\n\n// GetMyDecimal returns the MyDecimal value with the colIdx.\nfunc (r Row) GetMyDecimal(colIdx int) *types.MyDecimal {\n\treturn r.c.columns[colIdx].GetDecimal(r.idx)\n}\n"
  },
  {
    "path": "pkg/util/codec/bytes.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage codec\n\nimport (\n\t\"encoding/binary\"\n\t\"runtime\"\n\t\"unsafe\"\n\n\t\"github.com/pingcap/errors\"\n)\n\nconst (\n\tencGroupSize = 8\n\tencMarker    = byte(0xFF)\n\tencPad       = byte(0x0)\n)\n\nvar (\n\tpads = make([]byte, encGroupSize)\n)\n\n// EncodeBytes guarantees the encoded value is in ascending order for comparison,\n// encoding with the following rule:\n//\n//\t[group1][marker1]...[groupN][markerN]\n//\tgroup is 8 bytes slice which is padding with 0.\n//\tmarker is `0xFF - padding 0 count`\n//\n// For example:\n//\n//\t[] -> [0, 0, 0, 0, 0, 0, 0, 0, 247]\n//\t[1, 2, 3] -> [1, 2, 3, 0, 0, 0, 0, 0, 250]\n//\t[1, 2, 3, 0] -> [1, 2, 3, 0, 0, 0, 0, 0, 251]\n//\t[1, 2, 3, 4, 5, 6, 7, 8] -> [1, 2, 3, 4, 5, 6, 7, 8, 255, 0, 0, 0, 0, 0, 0, 0, 0, 247]\n//\n// Refer: https://github.com/facebook/mysql-5.6/wiki/MyRocks-record-format#memcomparable-format\nfunc EncodeBytes(b []byte, data []byte) []byte {\n\t// Allocate more space to avoid unnecessary slice growing.\n\t// Assume that the byte slice size is about `(len(data) / encGroupSize + 1) * (encGroupSize + 1)` bytes,\n\t// that is `(len(data) / 8 + 1) * 9` in our implement.\n\tdLen := len(data)\n\treallocSize := (dLen/encGroupSize + 1) * (encGroupSize + 1)\n\tresult := reallocBytes(b, reallocSize)\n\tfor idx := 0; idx <= dLen; idx += encGroupSize {\n\t\tremain := dLen - idx\n\t\tpadCount := 0\n\t\tif remain >= encGroupSize {\n\t\t\tresult = append(result, data[idx:idx+encGroupSize]...)\n\t\t} else {\n\t\t\tpadCount = encGroupSize - remain\n\t\t\tresult = append(result, data[idx:]...)\n\t\t\tresult = append(result, pads[:padCount]...)\n\t\t}\n\n\t\tmarker := encMarker - byte(padCount)\n\t\tresult = append(result, marker)\n\t}\n\n\treturn result\n}\n\nfunc decodeBytes(b []byte, buf []byte, reverse bool) ([]byte, []byte, error) {\n\tif len(buf) == 0 {\n\t\tbuf = make([]byte, 0, len(b))\n\t}\n\tbuf = buf[:0]\n\tfor {\n\t\tif len(b) < encGroupSize+1 {\n\t\t\treturn nil, nil, errors.New(\"insufficient bytes to decode value\")\n\t\t}\n\n\t\tgroupBytes := b[:encGroupSize+1]\n\n\t\tgroup := groupBytes[:encGroupSize]\n\t\tmarker := groupBytes[encGroupSize]\n\n\t\tvar padCount byte\n\t\tif reverse {\n\t\t\tpadCount = marker\n\t\t} else {\n\t\t\tpadCount = encMarker - marker\n\t\t}\n\t\tif padCount > encGroupSize {\n\t\t\treturn nil, nil, errors.Errorf(\"invalid marker byte, group bytes %q\", groupBytes)\n\t\t}\n\n\t\trealGroupSize := encGroupSize - padCount\n\t\tbuf = append(buf, group[:realGroupSize]...)\n\t\tb = b[encGroupSize+1:]\n\n\t\tif padCount != 0 {\n\t\t\tvar padByte = encPad\n\t\t\tif reverse {\n\t\t\t\tpadByte = encMarker\n\t\t\t}\n\t\t\t// Check validity of padding bytes.\n\t\t\tfor _, v := range group[realGroupSize:] {\n\t\t\t\tif v != padByte {\n\t\t\t\t\treturn nil, nil, errors.Errorf(\"invalid padding byte, group bytes %q\", groupBytes)\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\tif reverse {\n\t\treverseBytes(buf)\n\t}\n\treturn b, buf, nil\n}\n\n// DecodeBytes decodes bytes which is encoded by EncodeBytes before,\n// returns the leftover bytes and decoded value if no error.\n// `buf` is used to buffer data to avoid the cost of makeslice in decodeBytes when DecodeBytes is called by Decoder.DecodeOne.\nfunc DecodeBytes(b []byte, buf []byte) ([]byte, []byte, error) {\n\treturn decodeBytes(b, buf, false)\n}\n\n// EncodeBytesDesc first encodes bytes using EncodeBytes, then bitwise reverses\n// encoded value to guarantee the encoded value is in descending order for comparison.\nfunc EncodeBytesDesc(b []byte, data []byte) []byte {\n\tn := len(b)\n\tb = EncodeBytes(b, data)\n\treverseBytes(b[n:])\n\treturn b\n}\n\n// DecodeBytesDesc decodes bytes which is encoded by EncodeBytesDesc before,\n// returns the leftover bytes and decoded value if no error.\nfunc DecodeBytesDesc(b []byte, buf []byte) ([]byte, []byte, error) {\n\treturn decodeBytes(b, buf, true)\n}\n\n// EncodeCompactBytes joins bytes with its length into a byte slice. It is more\n// efficient in both space and time compare to EncodeBytes. Note that the encoded\n// result is not memcomparable.\nfunc EncodeCompactBytes(b []byte, data []byte) []byte {\n\tb = reallocBytes(b, binary.MaxVarintLen64+len(data))\n\tb = EncodeVarint(b, int64(len(data)))\n\treturn append(b, data...)\n}\n\n// DecodeCompactBytes decodes bytes which is encoded by EncodeCompactBytes before.\nfunc DecodeCompactBytes(b []byte) ([]byte, []byte, error) {\n\tb, n, err := DecodeVarint(b)\n\tif err != nil {\n\t\treturn nil, nil, errors.Trace(err)\n\t}\n\tif int64(len(b)) < n {\n\t\treturn nil, nil, errors.Errorf(\"insufficient bytes to decode value, expected length: %v\", n)\n\t}\n\treturn b[n:], b[:n], nil\n}\n\n// See https://golang.org/src/crypto/cipher/xor.go\nconst wordSize = int(unsafe.Sizeof(uintptr(0)))\nconst supportsUnaligned = runtime.GOARCH == \"386\" || runtime.GOARCH == \"amd64\"\n\nfunc fastReverseBytes(b []byte) {\n\tn := len(b)\n\tw := n / wordSize\n\tif w > 0 {\n\t\tbw := *(*[]uintptr)(unsafe.Pointer(&b))\n\t\tfor i := 0; i < w; i++ {\n\t\t\tbw[i] = ^bw[i]\n\t\t}\n\t}\n\n\tfor i := w * wordSize; i < n; i++ {\n\t\tb[i] = ^b[i]\n\t}\n}\n\nfunc safeReverseBytes(b []byte) {\n\tfor i := range b {\n\t\tb[i] = ^b[i]\n\t}\n}\n\nfunc reverseBytes(b []byte) {\n\tif supportsUnaligned {\n\t\tfastReverseBytes(b)\n\t\treturn\n\t}\n\n\tsafeReverseBytes(b)\n}\n\n// reallocBytes is like realloc.\nfunc reallocBytes(b []byte, n int) []byte {\n\tnewSize := len(b) + n\n\tif cap(b) < newSize {\n\t\tbs := make([]byte, len(b), newSize)\n\t\tcopy(bs, b)\n\t\treturn bs\n\t}\n\n\t// slice b has capability to store n bytes\n\treturn b\n}\n"
  },
  {
    "path": "pkg/util/codec/bytes_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage codec\n\nimport (\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/util/testleak\"\n)\n\nvar _ = Suite(&testBytesSuite{})\n\ntype testBytesSuite struct {\n}\n\nfunc (s *testBytesSuite) TestBytesCodec(c *C) {\n\tdefer testleak.AfterTest(c)()\n\tinputs := []struct {\n\t\tenc  []byte\n\t\tdec  []byte\n\t\tdesc bool\n\t}{\n\t\t{[]byte{}, []byte{0, 0, 0, 0, 0, 0, 0, 0, 247}, false},\n\t\t{[]byte{}, []byte{255, 255, 255, 255, 255, 255, 255, 255, 8}, true},\n\t\t{[]byte{0}, []byte{0, 0, 0, 0, 0, 0, 0, 0, 248}, false},\n\t\t{[]byte{0}, []byte{255, 255, 255, 255, 255, 255, 255, 255, 7}, true},\n\t\t{[]byte{1, 2, 3}, []byte{1, 2, 3, 0, 0, 0, 0, 0, 250}, false},\n\t\t{[]byte{1, 2, 3}, []byte{254, 253, 252, 255, 255, 255, 255, 255, 5}, true},\n\t\t{[]byte{1, 2, 3, 0}, []byte{1, 2, 3, 0, 0, 0, 0, 0, 251}, false},\n\t\t{[]byte{1, 2, 3, 0}, []byte{254, 253, 252, 255, 255, 255, 255, 255, 4}, true},\n\t\t{[]byte{1, 2, 3, 4, 5, 6, 7}, []byte{1, 2, 3, 4, 5, 6, 7, 0, 254}, false},\n\t\t{[]byte{1, 2, 3, 4, 5, 6, 7}, []byte{254, 253, 252, 251, 250, 249, 248, 255, 1}, true},\n\t\t{[]byte{0, 0, 0, 0, 0, 0, 0, 0}, []byte{0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 247}, false},\n\t\t{[]byte{0, 0, 0, 0, 0, 0, 0, 0}, []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 255, 8}, true},\n\t\t{[]byte{1, 2, 3, 4, 5, 6, 7, 8}, []byte{1, 2, 3, 4, 5, 6, 7, 8, 255, 0, 0, 0, 0, 0, 0, 0, 0, 247}, false},\n\t\t{[]byte{1, 2, 3, 4, 5, 6, 7, 8}, []byte{254, 253, 252, 251, 250, 249, 248, 247, 0, 255, 255, 255, 255, 255, 255, 255, 255, 8}, true},\n\t\t{[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, []byte{1, 2, 3, 4, 5, 6, 7, 8, 255, 9, 0, 0, 0, 0, 0, 0, 0, 248}, false},\n\t\t{[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, []byte{254, 253, 252, 251, 250, 249, 248, 247, 0, 246, 255, 255, 255, 255, 255, 255, 255, 7}, true},\n\t}\n\n\tfor _, input := range inputs {\n\t\tif input.desc {\n\t\t\tb := EncodeBytesDesc(nil, input.enc)\n\t\t\tc.Assert(b, BytesEquals, input.dec)\n\t\t\t_, d, err := DecodeBytesDesc(b, nil)\n\t\t\tc.Assert(err, IsNil)\n\t\t\tc.Assert(d, BytesEquals, input.enc)\n\t\t} else {\n\t\t\tb := EncodeBytes(nil, input.enc)\n\t\t\tc.Assert(b, BytesEquals, input.dec)\n\t\t\t_, d, err := DecodeBytes(b, nil)\n\t\t\tc.Assert(err, IsNil)\n\t\t\tc.Assert(d, BytesEquals, input.enc)\n\t\t}\n\t}\n\n\t// Test error decode.\n\terrInputs := [][]byte{\n\t\t{1, 2, 3, 4},\n\t\t{0, 0, 0, 0, 0, 0, 0, 247},\n\t\t{0, 0, 0, 0, 0, 0, 0, 0, 246},\n\t\t{0, 0, 0, 0, 0, 0, 0, 1, 247},\n\t\t{1, 2, 3, 4, 5, 6, 7, 8, 0},\n\t\t{1, 2, 3, 4, 5, 6, 7, 8, 255, 1},\n\t\t{1, 2, 3, 4, 5, 6, 7, 8, 255, 1, 2, 3, 4, 5, 6, 7, 8},\n\t\t{1, 2, 3, 4, 5, 6, 7, 8, 255, 1, 2, 3, 4, 5, 6, 7, 8, 255},\n\t\t{1, 2, 3, 4, 5, 6, 7, 8, 255, 1, 2, 3, 4, 5, 6, 7, 8, 0},\n\t}\n\n\tfor _, input := range errInputs {\n\t\t_, _, err := DecodeBytes(input, nil)\n\t\tc.Assert(err, NotNil)\n\t}\n}\n"
  },
  {
    "path": "pkg/util/codec/codec.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage codec\n\nimport (\n\t\"encoding/binary\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n)\n\n// First byte in the encoded value which specifies the encoding type.\nconst (\n\tNilFlag          byte = 0\n\tbytesFlag        byte = 1\n\tcompactBytesFlag byte = 2\n\tintFlag          byte = 3\n\tuintFlag         byte = 4\n\tfloatFlag        byte = 5\n\tdecimalFlag      byte = 6\n\tdurationFlag     byte = 7\n\tvarintFlag       byte = 8\n\tuvarintFlag      byte = 9\n\tjsonFlag         byte = 10\n\tmaxFlag          byte = 250\n)\n\nfunc preRealloc(b []byte, vals []types.Datum, isComparable bool) []byte {\n\tvar size int\n\tfor i := range vals {\n\t\tswitch vals[i].Kind() {\n\t\tcase types.KindInt64, types.KindUint64, types.KindMysqlBit, types.KindBinaryLiteral:\n\t\t\tsize += sizeInt(isComparable)\n\t\tcase types.KindString, types.KindBytes:\n\t\t\tsize += sizeBytes(vals[i].GetBytes(), isComparable)\n\t\tcase types.KindMysqlTime, types.KindMysqlDuration, types.KindFloat32, types.KindFloat64:\n\t\t\tsize += 9\n\t\tcase types.KindNull, types.KindMinNotNull, types.KindMaxValue:\n\t\t\tsize += 1\n\t\tdefault:\n\t\t\treturn b\n\t\t}\n\t}\n\treturn reallocBytes(b, size)\n}\n\nfunc sizeInt(isComparable bool) int {\n\tif isComparable {\n\t\treturn 9\n\t}\n\treturn 1 + binary.MaxVarintLen64\n}\n\nfunc sizeBytes(v []byte, isComparable bool) int {\n\tif isComparable {\n\t\treallocSize := (len(v)/encGroupSize + 1) * (encGroupSize + 1)\n\t\treturn 1 + reallocSize\n\t}\n\treallocSize := binary.MaxVarintLen64 + len(v)\n\treturn 1 + reallocSize\n}\n\n// encode will encode a datum and append it to a byte slice. If isComparable is true, the encoded bytes can be sorted as it's original order.\n// If hash is true, the encoded bytes can be checked equal as it's original value.\nfunc encode(sc *stmtctx.StatementContext, b []byte, vals []types.Datum, isComparable bool) (_ []byte, err error) {\n\tb = preRealloc(b, vals, isComparable)\n\tfor i, length := 0, len(vals); i < length; i++ {\n\t\tswitch vals[i].Kind() {\n\t\tcase types.KindInt64:\n\t\t\tb = encodeSignedInt(b, vals[i].GetInt64(), isComparable)\n\t\tcase types.KindUint64:\n\t\t\tb = encodeUnsignedInt(b, vals[i].GetUint64(), isComparable)\n\t\tcase types.KindFloat32, types.KindFloat64:\n\t\t\tb = append(b, floatFlag)\n\t\t\tb = EncodeFloat(b, vals[i].GetFloat64())\n\t\tcase types.KindString, types.KindBytes:\n\t\t\tb = encodeBytes(b, vals[i].GetBytes(), isComparable)\n\t\tcase types.KindNull:\n\t\t\tb = append(b, NilFlag)\n\t\tcase types.KindMinNotNull:\n\t\t\tb = append(b, bytesFlag)\n\t\tcase types.KindMaxValue:\n\t\t\tb = append(b, maxFlag)\n\t\tdefault:\n\t\t\treturn b, errors.Errorf(\"unsupport encode type %d\", vals[i].Kind())\n\t\t}\n\t}\n\n\treturn b, errors.Trace(err)\n}\n\n// EstimateValueSize uses to estimate the value  size of the encoded values.\nfunc EstimateValueSize(sc *stmtctx.StatementContext, val types.Datum) (int, error) {\n\tl := 0\n\tswitch val.Kind() {\n\tcase types.KindInt64:\n\t\tl = valueSizeOfSignedInt(val.GetInt64())\n\tcase types.KindUint64:\n\t\tl = valueSizeOfUnsignedInt(val.GetUint64())\n\tcase types.KindFloat32, types.KindFloat64, types.KindMysqlTime, types.KindMysqlDuration:\n\t\tl = 9\n\tcase types.KindString, types.KindBytes:\n\t\tl = valueSizeOfBytes(val.GetBytes())\n\tcase types.KindNull, types.KindMinNotNull, types.KindMaxValue:\n\t\tl = 1\n\tdefault:\n\t\treturn l, errors.Errorf(\"unsupported encode type %d\", val.Kind())\n\t}\n\treturn l, nil\n}\n\n// EncodeKey appends the encoded values to byte slice b, returns the appended\n// slice. It guarantees the encoded value is in ascending order for comparison.\n// For Decimal type, datum must set datum's length and frac.\nfunc EncodeKey(sc *stmtctx.StatementContext, b []byte, v ...types.Datum) ([]byte, error) {\n\treturn encode(sc, b, v, true)\n}\n\n// EncodeValue appends the encoded values to byte slice b, returning the appended\n// slice. It does not guarantee the order for comparison.\nfunc EncodeValue(sc *stmtctx.StatementContext, b []byte, v ...types.Datum) ([]byte, error) {\n\treturn encode(sc, b, v, false)\n}\n\nfunc encodeSignedInt(b []byte, v int64, isComparable bool) []byte {\n\tif isComparable {\n\t\tb = append(b, intFlag)\n\t\tb = EncodeInt(b, v)\n\t} else {\n\t\tb = append(b, varintFlag)\n\t\tb = EncodeVarint(b, v)\n\t}\n\treturn b\n}\n\nfunc encodeUnsignedInt(b []byte, v uint64, isComparable bool) []byte {\n\tif isComparable {\n\t\tb = append(b, uintFlag)\n\t\tb = EncodeUint(b, v)\n\t} else {\n\t\tb = append(b, uvarintFlag)\n\t\tb = EncodeUvarint(b, v)\n\t}\n\treturn b\n}\n\nfunc encodeBytes(b []byte, v []byte, isComparable bool) []byte {\n\tif isComparable {\n\t\tb = append(b, bytesFlag)\n\t\tb = EncodeBytes(b, v)\n\t} else {\n\t\tb = append(b, compactBytesFlag)\n\t\tb = EncodeCompactBytes(b, v)\n\t}\n\treturn b\n}\n\n// Decode decodes values from a byte slice generated with EncodeKey or EncodeValue\n// before.\n// size is the size of decoded datum slice.\nfunc Decode(b []byte, size int) ([]types.Datum, error) {\n\tif len(b) < 1 {\n\t\treturn nil, errors.New(\"invalid encoded key\")\n\t}\n\n\tvar (\n\t\terr    error\n\t\tvalues = make([]types.Datum, 0, size)\n\t)\n\n\tfor len(b) > 0 {\n\t\tvar d types.Datum\n\t\tb, d, err = DecodeOne(b)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Trace(err)\n\t\t}\n\n\t\tvalues = append(values, d)\n\t}\n\n\treturn values, nil\n}\n\n// DecodeOne decodes on datum from a byte slice generated with EncodeKey or EncodeValue.\nfunc DecodeOne(b []byte) (remain []byte, d types.Datum, err error) {\n\tif len(b) < 1 {\n\t\treturn nil, d, errors.New(\"invalid encoded key\")\n\t}\n\tflag := b[0]\n\tb = b[1:]\n\tswitch flag {\n\tcase intFlag:\n\t\tvar v int64\n\t\tb, v, err = DecodeInt(b)\n\t\td.SetInt64(v)\n\tcase uintFlag:\n\t\tvar v uint64\n\t\tb, v, err = DecodeUint(b)\n\t\td.SetUint64(v)\n\tcase varintFlag:\n\t\tvar v int64\n\t\tb, v, err = DecodeVarint(b)\n\t\td.SetInt64(v)\n\tcase uvarintFlag:\n\t\tvar v uint64\n\t\tb, v, err = DecodeUvarint(b)\n\t\td.SetUint64(v)\n\tcase floatFlag:\n\t\tvar v float64\n\t\tb, v, err = DecodeFloat(b)\n\t\td.SetFloat64(v)\n\tcase bytesFlag:\n\t\tvar v []byte\n\t\tb, v, err = DecodeBytes(b, nil)\n\t\td.SetBytes(v)\n\tcase compactBytesFlag:\n\t\tvar v []byte\n\t\tb, v, err = DecodeCompactBytes(b)\n\t\td.SetBytes(v)\n\tcase NilFlag:\n\tdefault:\n\t\treturn b, d, errors.Errorf(\"invalid encoded key flag %v\", flag)\n\t}\n\tif err != nil {\n\t\treturn b, d, errors.Trace(err)\n\t}\n\treturn b, d, nil\n}\n\nfunc valueSizeOfBytes(v []byte) int {\n\treturn valueSizeOfSignedInt(int64(len(v))) + len(v)\n}\n\nfunc valueSizeOfSignedInt(v int64) int {\n\tif v < 0 {\n\t\tv = 0 - v - 1\n\t}\n\t// Flag occupy 1 bit and at lease 1 bit.\n\tsize := 2\n\tv = v >> 6\n\tfor v > 0 {\n\t\tsize++\n\t\tv = v >> 7\n\t}\n\treturn size\n}\n\nfunc valueSizeOfUnsignedInt(v uint64) int {\n\t// Flag occupy 1 bit and at lease 1 bit.\n\tsize := 2\n\tv = v >> 7\n\tfor v > 0 {\n\t\tsize++\n\t\tv = v >> 7\n\t}\n\treturn size\n}\n"
  },
  {
    "path": "pkg/util/codec/codec_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage codec\n\nimport (\n\t\"bytes\"\n\t\"math\"\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/sessionctx/stmtctx\"\n\t\"github.com/secretflow/scql/pkg/types\"\n\t\"github.com/secretflow/scql/pkg/util/testleak\"\n)\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nvar _ = Suite(&testCodecSuite{})\n\ntype testCodecSuite struct {\n}\n\nfunc (s *testCodecSuite) TestCodecKey(c *C) {\n\tdefer testleak.AfterTest(c)()\n\ttable := []struct {\n\t\tInput  []types.Datum\n\t\tExpect []types.Datum\n\t}{\n\t\t{\n\t\t\ttypes.MakeDatums(int64(1)),\n\t\t\ttypes.MakeDatums(int64(1)),\n\t\t},\n\n\t\t{\n\t\t\ttypes.MakeDatums(float32(1), float64(3.15), []byte(\"123\"), \"123\"),\n\t\t\ttypes.MakeDatums(float64(1), float64(3.15), []byte(\"123\"), []byte(\"123\")),\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(uint64(1), float64(3.15), []byte(\"123\"), int64(-1)),\n\t\t\ttypes.MakeDatums(uint64(1), float64(3.15), []byte(\"123\"), int64(-1)),\n\t\t},\n\n\t\t{\n\t\t\ttypes.MakeDatums(true, false),\n\t\t\ttypes.MakeDatums(int64(1), int64(0)),\n\t\t},\n\n\t\t{\n\t\t\ttypes.MakeDatums(nil),\n\t\t\ttypes.MakeDatums(nil),\n\t\t},\n\t}\n\tsc := &stmtctx.StatementContext{}\n\tfor i, t := range table {\n\t\tcomment := Commentf(\"%d %v\", i, t)\n\t\tb, err := EncodeKey(sc, nil, t.Input...)\n\t\tc.Assert(err, IsNil, comment)\n\t\targs, err := Decode(b, 1)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(args, DeepEquals, t.Expect)\n\n\t\tb, err = EncodeValue(sc, nil, t.Input...)\n\t\tc.Assert(err, IsNil)\n\t\tsize, err := estimateValuesSize(sc, t.Input)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(len(b), Equals, size)\n\t\targs, err = Decode(b, 1)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(args, DeepEquals, t.Expect)\n\t}\n}\n\nfunc estimateValuesSize(sc *stmtctx.StatementContext, vals []types.Datum) (int, error) {\n\tsize := 0\n\tfor _, val := range vals {\n\t\tlength, err := EstimateValueSize(sc, val)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tsize += length\n\t}\n\treturn size, nil\n}\n\nfunc (s *testCodecSuite) TestCodecKeyCompare(c *C) {\n\tdefer testleak.AfterTest(c)()\n\ttable := []struct {\n\t\tLeft   []types.Datum\n\t\tRight  []types.Datum\n\t\tExpect int\n\t}{\n\t\t{\n\t\t\ttypes.MakeDatums(1),\n\t\t\ttypes.MakeDatums(1),\n\t\t\t0,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(-1),\n\t\t\ttypes.MakeDatums(1),\n\t\t\t-1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(3.15),\n\t\t\ttypes.MakeDatums(3.12),\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(\"abc\"),\n\t\t\ttypes.MakeDatums(\"abcd\"),\n\t\t\t-1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(\"abcdefgh\"),\n\t\t\ttypes.MakeDatums(\"abcdefghi\"),\n\t\t\t-1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(1, \"abc\"),\n\t\t\ttypes.MakeDatums(1, \"abcd\"),\n\t\t\t-1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(1, \"abc\", \"def\"),\n\t\t\ttypes.MakeDatums(1, \"abcd\", \"af\"),\n\t\t\t-1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(3.12, \"ebc\", \"def\"),\n\t\t\ttypes.MakeDatums(2.12, \"abcd\", \"af\"),\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums([]byte{0x01, 0x00}, []byte{0xFF}),\n\t\t\ttypes.MakeDatums([]byte{0x01, 0x00, 0xFF}),\n\t\t\t-1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums([]byte{0x01}, uint64(0xFFFFFFFFFFFFFFF)),\n\t\t\ttypes.MakeDatums([]byte{0x01, 0x10}, 0),\n\t\t\t-1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(0),\n\t\t\ttypes.MakeDatums(nil),\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums([]byte{0x00}),\n\t\t\ttypes.MakeDatums(nil),\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(math.SmallestNonzeroFloat64),\n\t\t\ttypes.MakeDatums(nil),\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(int64(math.MinInt64)),\n\t\t\ttypes.MakeDatums(nil),\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(1, int64(math.MinInt64), nil),\n\t\t\ttypes.MakeDatums(1, nil, uint64(math.MaxUint64)),\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\ttypes.MakeDatums(1, []byte{}, nil),\n\t\t\ttypes.MakeDatums(1, nil, 123),\n\t\t\t1,\n\t\t},\n\t}\n\tsc := &stmtctx.StatementContext{}\n\tfor _, t := range table {\n\t\tb1, err := EncodeKey(sc, nil, t.Left...)\n\t\tc.Assert(err, IsNil)\n\n\t\tb2, err := EncodeKey(sc, nil, t.Right...)\n\t\tc.Assert(err, IsNil)\n\n\t\tc.Assert(bytes.Compare(b1, b2), Equals, t.Expect, Commentf(\"%v - %v - %v - %v - %v\", t.Left, t.Right, b1, b2, t.Expect))\n\t}\n}\n\nfunc (s *testCodecSuite) TestNumberCodec(c *C) {\n\tdefer testleak.AfterTest(c)()\n\ttblInt64 := []int64{\n\t\tmath.MinInt64,\n\t\tmath.MinInt32,\n\t\tmath.MinInt16,\n\t\tmath.MinInt8,\n\t\t0,\n\t\tmath.MaxInt8,\n\t\tmath.MaxInt16,\n\t\tmath.MaxInt32,\n\t\tmath.MaxInt64,\n\t\t1<<47 - 1,\n\t\t-1 << 47,\n\t\t1<<23 - 1,\n\t\t-1 << 23,\n\t\t1<<55 - 1,\n\t\t-1 << 55,\n\t\t1,\n\t\t-1,\n\t}\n\n\tfor _, t := range tblInt64 {\n\t\tb := EncodeInt(nil, t)\n\t\t_, v, err := DecodeInt(b)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(v, Equals, t)\n\n\t\tb = EncodeIntDesc(nil, t)\n\t\t_, v, err = DecodeIntDesc(b)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(v, Equals, t)\n\n\t\tb = EncodeVarint(nil, t)\n\t\t_, v, err = DecodeVarint(b)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(v, Equals, t)\n\n\t\tb = EncodeComparableVarint(nil, t)\n\t\t_, v, err = DecodeComparableVarint(b)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(v, Equals, t)\n\t}\n\n\ttblUint64 := []uint64{\n\t\t0,\n\t\tmath.MaxUint8,\n\t\tmath.MaxUint16,\n\t\tmath.MaxUint32,\n\t\tmath.MaxUint64,\n\t\t1<<24 - 1,\n\t\t1<<48 - 1,\n\t\t1<<56 - 1,\n\t\t1,\n\t\tmath.MaxInt16,\n\t\tmath.MaxInt8,\n\t\tmath.MaxInt32,\n\t\tmath.MaxInt64,\n\t}\n\n\tfor _, t := range tblUint64 {\n\t\tb := EncodeUint(nil, t)\n\t\t_, v, err := DecodeUint(b)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(v, Equals, t)\n\n\t\tb = EncodeUintDesc(nil, t)\n\t\t_, v, err = DecodeUintDesc(b)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(v, Equals, t)\n\n\t\tb = EncodeUvarint(nil, t)\n\t\t_, v, err = DecodeUvarint(b)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(v, Equals, t)\n\n\t\tb = EncodeComparableUvarint(nil, t)\n\t\t_, v, err = DecodeComparableUvarint(b)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(v, Equals, t)\n\t}\n\tvar b []byte\n\tb = EncodeComparableVarint(b, -1)\n\tb = EncodeComparableUvarint(b, 1)\n\tb = EncodeComparableVarint(b, 2)\n\tb, i, err := DecodeComparableVarint(b)\n\tc.Assert(err, IsNil)\n\tc.Assert(i, Equals, int64(-1))\n\tb, u, err := DecodeComparableUvarint(b)\n\tc.Assert(err, IsNil)\n\tc.Assert(u, Equals, uint64(1))\n\t_, i, err = DecodeComparableVarint(b)\n\tc.Assert(err, IsNil)\n\tc.Assert(i, Equals, int64(2))\n}\n\nfunc (s *testCodecSuite) TestNumberOrder(c *C) {\n\tdefer testleak.AfterTest(c)()\n\ttblInt64 := []struct {\n\t\tArg1 int64\n\t\tArg2 int64\n\t\tRet  int\n\t}{\n\t\t{-1, 1, -1},\n\t\t{math.MaxInt64, math.MinInt64, 1},\n\t\t{math.MaxInt64, math.MaxInt32, 1},\n\t\t{math.MinInt32, math.MaxInt16, -1},\n\t\t{math.MinInt64, math.MaxInt8, -1},\n\t\t{0, math.MaxInt8, -1},\n\t\t{math.MinInt8, 0, -1},\n\t\t{math.MinInt16, math.MaxInt16, -1},\n\t\t{1, -1, 1},\n\t\t{1, 0, 1},\n\t\t{-1, 0, -1},\n\t\t{0, 0, 0},\n\t\t{math.MaxInt16, math.MaxInt16, 0},\n\t}\n\n\tfor _, t := range tblInt64 {\n\t\tb1 := EncodeInt(nil, t.Arg1)\n\t\tb2 := EncodeInt(nil, t.Arg2)\n\n\t\tret := bytes.Compare(b1, b2)\n\t\tc.Assert(ret, Equals, t.Ret)\n\n\t\tb1 = EncodeIntDesc(nil, t.Arg1)\n\t\tb2 = EncodeIntDesc(nil, t.Arg2)\n\n\t\tret = bytes.Compare(b1, b2)\n\t\tc.Assert(ret, Equals, -t.Ret)\n\n\t\tb1 = EncodeComparableVarint(nil, t.Arg1)\n\t\tb2 = EncodeComparableVarint(nil, t.Arg2)\n\t\tret = bytes.Compare(b1, b2)\n\t\tc.Assert(ret, Equals, t.Ret)\n\t}\n\n\ttblUint64 := []struct {\n\t\tArg1 uint64\n\t\tArg2 uint64\n\t\tRet  int\n\t}{\n\t\t{0, 0, 0},\n\t\t{1, 0, 1},\n\t\t{0, 1, -1},\n\t\t{math.MaxInt8, math.MaxInt16, -1},\n\t\t{math.MaxUint32, math.MaxInt32, 1},\n\t\t{math.MaxUint8, math.MaxInt8, 1},\n\t\t{math.MaxUint16, math.MaxInt32, -1},\n\t\t{math.MaxUint64, math.MaxInt64, 1},\n\t\t{math.MaxInt64, math.MaxUint32, 1},\n\t\t{math.MaxUint64, 0, 1},\n\t\t{0, math.MaxUint64, -1},\n\t}\n\n\tfor _, t := range tblUint64 {\n\t\tb1 := EncodeUint(nil, t.Arg1)\n\t\tb2 := EncodeUint(nil, t.Arg2)\n\n\t\tret := bytes.Compare(b1, b2)\n\t\tc.Assert(ret, Equals, t.Ret)\n\n\t\tb1 = EncodeUintDesc(nil, t.Arg1)\n\t\tb2 = EncodeUintDesc(nil, t.Arg2)\n\n\t\tret = bytes.Compare(b1, b2)\n\t\tc.Assert(ret, Equals, -t.Ret)\n\n\t\tb1 = EncodeComparableUvarint(nil, t.Arg1)\n\t\tb2 = EncodeComparableUvarint(nil, t.Arg2)\n\t\tret = bytes.Compare(b1, b2)\n\t\tc.Assert(ret, Equals, t.Ret)\n\t}\n}\n\nfunc (s *testCodecSuite) TestFloatCodec(c *C) {\n\tdefer testleak.AfterTest(c)()\n\ttblFloat := []float64{\n\t\t-1,\n\t\t0,\n\t\t1,\n\t\tmath.MaxFloat64,\n\t\tmath.MaxFloat32,\n\t\tmath.SmallestNonzeroFloat32,\n\t\tmath.SmallestNonzeroFloat64,\n\t\tmath.Inf(-1),\n\t\tmath.Inf(1),\n\t}\n\n\tfor _, t := range tblFloat {\n\t\tb := EncodeFloat(nil, t)\n\t\t_, v, err := DecodeFloat(b)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(v, Equals, t)\n\n\t\tb = EncodeFloatDesc(nil, t)\n\t\t_, v, err = DecodeFloatDesc(b)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(v, Equals, t)\n\t}\n\n\ttblCmp := []struct {\n\t\tArg1 float64\n\t\tArg2 float64\n\t\tRet  int\n\t}{\n\t\t{1, -1, 1},\n\t\t{1, 0, 1},\n\t\t{0, -1, 1},\n\t\t{0, 0, 0},\n\t\t{math.MaxFloat64, 1, 1},\n\t\t{math.MaxFloat32, math.MaxFloat64, -1},\n\t\t{math.MaxFloat64, 0, 1},\n\t\t{math.MaxFloat64, math.SmallestNonzeroFloat64, 1},\n\t\t{math.Inf(-1), 0, -1},\n\t\t{math.Inf(1), 0, 1},\n\t\t{math.Inf(-1), math.Inf(1), -1},\n\t}\n\n\tfor _, t := range tblCmp {\n\t\tb1 := EncodeFloat(nil, t.Arg1)\n\t\tb2 := EncodeFloat(nil, t.Arg2)\n\n\t\tret := bytes.Compare(b1, b2)\n\t\tc.Assert(ret, Equals, t.Ret)\n\n\t\tb1 = EncodeFloatDesc(nil, t.Arg1)\n\t\tb2 = EncodeFloatDesc(nil, t.Arg2)\n\n\t\tret = bytes.Compare(b1, b2)\n\t\tc.Assert(ret, Equals, -t.Ret)\n\t}\n}\n\nfunc (s *testCodecSuite) TestBytes(c *C) {\n\tdefer testleak.AfterTest(c)()\n\ttblBytes := [][]byte{\n\t\t{},\n\t\t{0x00, 0x01},\n\t\t{0xff, 0xff},\n\t\t{0x01, 0x00},\n\t\t[]byte(\"abc\"),\n\t\t[]byte(\"hello world\"),\n\t}\n\n\tfor _, t := range tblBytes {\n\t\tb := EncodeBytes(nil, t)\n\t\t_, v, err := DecodeBytes(b, nil)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(t, DeepEquals, v, Commentf(\"%v - %v - %v\", t, b, v))\n\n\t\tb = EncodeBytesDesc(nil, t)\n\t\t_, v, err = DecodeBytesDesc(b, nil)\n\t\tc.Assert(err, IsNil)\n\t\tc.Assert(t, DeepEquals, v, Commentf(\"%v - %v - %v\", t, b, v))\n\t}\n\n\ttblCmp := []struct {\n\t\tArg1 []byte\n\t\tArg2 []byte\n\t\tRet  int\n\t}{\n\t\t{[]byte{}, []byte{0x00}, -1},\n\t\t{[]byte{0x00}, []byte{0x00}, 0},\n\t\t{[]byte{0xFF}, []byte{0x00}, 1},\n\t\t{[]byte{0xFF}, []byte{0xFF, 0x00}, -1},\n\t\t{[]byte(\"a\"), []byte(\"b\"), -1},\n\t\t{[]byte(\"a\"), []byte{0x00}, 1},\n\t\t{[]byte{0x00}, []byte{0x01}, -1},\n\t\t{[]byte{0x00, 0x01}, []byte{0x00, 0x00}, 1},\n\t\t{[]byte{0x00, 0x00, 0x00}, []byte{0x00, 0x00}, 1},\n\t\t{[]byte{0x00, 0x00, 0x00}, []byte{0x00, 0x00}, 1},\n\t\t{[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -1},\n\t\t{[]byte{0x01, 0x02, 0x03, 0x00}, []byte{0x01, 0x02, 0x03}, 1},\n\t\t{[]byte{0x01, 0x03, 0x03, 0x04}, []byte{0x01, 0x03, 0x03, 0x05}, -1},\n\t\t{[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, -1},\n\t\t{[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, 1},\n\t\t{[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00}, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, 1},\n\t}\n\n\tfor _, t := range tblCmp {\n\t\tb1 := EncodeBytes(nil, t.Arg1)\n\t\tb2 := EncodeBytes(nil, t.Arg2)\n\n\t\tret := bytes.Compare(b1, b2)\n\t\tc.Assert(ret, Equals, t.Ret)\n\n\t\tb1 = EncodeBytesDesc(nil, t.Arg1)\n\t\tb2 = EncodeBytesDesc(nil, t.Arg2)\n\n\t\tret = bytes.Compare(b1, b2)\n\t\tc.Assert(ret, Equals, -t.Ret)\n\t}\n}\n"
  },
  {
    "path": "pkg/util/codec/float.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage codec\n\nimport (\n\t\"math\"\n\n\t\"github.com/pingcap/errors\"\n)\n\nfunc encodeFloatToCmpUint64(f float64) uint64 {\n\tu := math.Float64bits(f)\n\tif f >= 0 {\n\t\tu |= signMask\n\t} else {\n\t\tu = ^u\n\t}\n\treturn u\n}\n\nfunc decodeCmpUintToFloat(u uint64) float64 {\n\tif u&signMask > 0 {\n\t\tu &= ^signMask\n\t} else {\n\t\tu = ^u\n\t}\n\treturn math.Float64frombits(u)\n}\n\n// EncodeFloat encodes a float v into a byte slice which can be sorted lexicographically later.\n// EncodeFloat guarantees that the encoded value is in ascending order for comparison.\nfunc EncodeFloat(b []byte, v float64) []byte {\n\tu := encodeFloatToCmpUint64(v)\n\treturn EncodeUint(b, u)\n}\n\n// DecodeFloat decodes a float from a byte slice generated with EncodeFloat before.\nfunc DecodeFloat(b []byte) ([]byte, float64, error) {\n\tb, u, err := DecodeUint(b)\n\treturn b, decodeCmpUintToFloat(u), errors.Trace(err)\n}\n\n// EncodeFloatDesc encodes a float v into a byte slice which can be sorted lexicographically later.\n// EncodeFloatDesc guarantees that the encoded value is in descending order for comparison.\nfunc EncodeFloatDesc(b []byte, v float64) []byte {\n\tu := encodeFloatToCmpUint64(v)\n\treturn EncodeUintDesc(b, u)\n}\n\n// DecodeFloatDesc decodes a float from a byte slice generated with EncodeFloatDesc before.\nfunc DecodeFloatDesc(b []byte) ([]byte, float64, error) {\n\tb, u, err := DecodeUintDesc(b)\n\treturn b, decodeCmpUintToFloat(u), errors.Trace(err)\n}\n"
  },
  {
    "path": "pkg/util/codec/number.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage codec\n\nimport (\n\t\"encoding/binary\"\n\t\"math\"\n\n\t\"github.com/pingcap/errors\"\n)\n\nconst signMask uint64 = 0x8000000000000000\n\n// EncodeIntToCmpUint make int v to comparable uint type\nfunc EncodeIntToCmpUint(v int64) uint64 {\n\treturn uint64(v) ^ signMask\n}\n\n// DecodeCmpUintToInt decodes the u that encoded by EncodeIntToCmpUint\nfunc DecodeCmpUintToInt(u uint64) int64 {\n\treturn int64(u ^ signMask)\n}\n\n// EncodeInt appends the encoded value to slice b and returns the appended slice.\n// EncodeInt guarantees that the encoded value is in ascending order for comparison.\nfunc EncodeInt(b []byte, v int64) []byte {\n\tvar data [8]byte\n\tu := EncodeIntToCmpUint(v)\n\tbinary.BigEndian.PutUint64(data[:], u)\n\treturn append(b, data[:]...)\n}\n\n// EncodeIntDesc appends the encoded value to slice b and returns the appended slice.\n// EncodeIntDesc guarantees that the encoded value is in descending order for comparison.\nfunc EncodeIntDesc(b []byte, v int64) []byte {\n\tvar data [8]byte\n\tu := EncodeIntToCmpUint(v)\n\tbinary.BigEndian.PutUint64(data[:], ^u)\n\treturn append(b, data[:]...)\n}\n\n// DecodeInt decodes value encoded by EncodeInt before.\n// It returns the leftover un-decoded slice, decoded value if no error.\nfunc DecodeInt(b []byte) ([]byte, int64, error) {\n\tif len(b) < 8 {\n\t\treturn nil, 0, errors.New(\"insufficient bytes to decode value\")\n\t}\n\n\tu := binary.BigEndian.Uint64(b[:8])\n\tv := DecodeCmpUintToInt(u)\n\tb = b[8:]\n\treturn b, v, nil\n}\n\n// DecodeIntDesc decodes value encoded by EncodeInt before.\n// It returns the leftover un-decoded slice, decoded value if no error.\nfunc DecodeIntDesc(b []byte) ([]byte, int64, error) {\n\tif len(b) < 8 {\n\t\treturn nil, 0, errors.New(\"insufficient bytes to decode value\")\n\t}\n\n\tu := binary.BigEndian.Uint64(b[:8])\n\tv := DecodeCmpUintToInt(^u)\n\tb = b[8:]\n\treturn b, v, nil\n}\n\n// EncodeUint appends the encoded value to slice b and returns the appended slice.\n// EncodeUint guarantees that the encoded value is in ascending order for comparison.\nfunc EncodeUint(b []byte, v uint64) []byte {\n\tvar data [8]byte\n\tbinary.BigEndian.PutUint64(data[:], v)\n\treturn append(b, data[:]...)\n}\n\n// EncodeUintDesc appends the encoded value to slice b and returns the appended slice.\n// EncodeUintDesc guarantees that the encoded value is in descending order for comparison.\nfunc EncodeUintDesc(b []byte, v uint64) []byte {\n\tvar data [8]byte\n\tbinary.BigEndian.PutUint64(data[:], ^v)\n\treturn append(b, data[:]...)\n}\n\n// DecodeUint decodes value encoded by EncodeUint before.\n// It returns the leftover un-decoded slice, decoded value if no error.\nfunc DecodeUint(b []byte) ([]byte, uint64, error) {\n\tif len(b) < 8 {\n\t\treturn nil, 0, errors.New(\"insufficient bytes to decode value\")\n\t}\n\n\tv := binary.BigEndian.Uint64(b[:8])\n\tb = b[8:]\n\treturn b, v, nil\n}\n\n// DecodeUintDesc decodes value encoded by EncodeInt before.\n// It returns the leftover un-decoded slice, decoded value if no error.\nfunc DecodeUintDesc(b []byte) ([]byte, uint64, error) {\n\tif len(b) < 8 {\n\t\treturn nil, 0, errors.New(\"insufficient bytes to decode value\")\n\t}\n\n\tdata := b[:8]\n\tv := binary.BigEndian.Uint64(data)\n\tb = b[8:]\n\treturn b, ^v, nil\n}\n\n// EncodeVarint appends the encoded value to slice b and returns the appended slice.\n// Note that the encoded result is not memcomparable.\nfunc EncodeVarint(b []byte, v int64) []byte {\n\tvar data [binary.MaxVarintLen64]byte\n\tn := binary.PutVarint(data[:], v)\n\treturn append(b, data[:n]...)\n}\n\n// DecodeVarint decodes value encoded by EncodeVarint before.\n// It returns the leftover un-decoded slice, decoded value if no error.\nfunc DecodeVarint(b []byte) ([]byte, int64, error) {\n\tv, n := binary.Varint(b)\n\tif n > 0 {\n\t\treturn b[n:], v, nil\n\t}\n\tif n < 0 {\n\t\treturn nil, 0, errors.New(\"value larger than 64 bits\")\n\t}\n\treturn nil, 0, errors.New(\"insufficient bytes to decode value\")\n}\n\n// EncodeUvarint appends the encoded value to slice b and returns the appended slice.\n// Note that the encoded result is not memcomparable.\nfunc EncodeUvarint(b []byte, v uint64) []byte {\n\tvar data [binary.MaxVarintLen64]byte\n\tn := binary.PutUvarint(data[:], v)\n\treturn append(b, data[:n]...)\n}\n\n// DecodeUvarint decodes value encoded by EncodeUvarint before.\n// It returns the leftover un-decoded slice, decoded value if no error.\nfunc DecodeUvarint(b []byte) ([]byte, uint64, error) {\n\tv, n := binary.Uvarint(b)\n\tif n > 0 {\n\t\treturn b[n:], v, nil\n\t}\n\tif n < 0 {\n\t\treturn nil, 0, errors.New(\"value larger than 64 bits\")\n\t}\n\treturn nil, 0, errors.New(\"insufficient bytes to decode value\")\n}\n\nconst (\n\tnegativeTagEnd   = 8        // negative tag is (negativeTagEnd - length).\n\tpositiveTagStart = 0xff - 8 // Positive tag is (positiveTagStart + length).\n)\n\n// EncodeComparableVarint encodes an int64 to a mem-comparable bytes.\nfunc EncodeComparableVarint(b []byte, v int64) []byte {\n\tif v < 0 {\n\t\t// All negative value has a tag byte prefix (negativeTagEnd - length).\n\t\t// Smaller negative value encodes to more bytes, has smaller tag.\n\t\tif v >= -0xff {\n\t\t\treturn append(b, negativeTagEnd-1, byte(v))\n\t\t} else if v >= -0xffff {\n\t\t\treturn append(b, negativeTagEnd-2, byte(v>>8), byte(v))\n\t\t} else if v >= -0xffffff {\n\t\t\treturn append(b, negativeTagEnd-3, byte(v>>16), byte(v>>8), byte(v))\n\t\t} else if v >= -0xffffffff {\n\t\t\treturn append(b, negativeTagEnd-4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))\n\t\t} else if v >= -0xffffffffff {\n\t\t\treturn append(b, negativeTagEnd-5, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))\n\t\t} else if v >= -0xffffffffffff {\n\t\t\treturn append(b, negativeTagEnd-6, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8),\n\t\t\t\tbyte(v))\n\t\t} else if v >= -0xffffffffffffff {\n\t\t\treturn append(b, negativeTagEnd-7, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16),\n\t\t\t\tbyte(v>>8), byte(v))\n\t\t}\n\t\treturn append(b, negativeTagEnd-8, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24),\n\t\t\tbyte(v>>16), byte(v>>8), byte(v))\n\t}\n\treturn EncodeComparableUvarint(b, uint64(v))\n}\n\n// EncodeComparableUvarint encodes uint64 into mem-comparable bytes.\nfunc EncodeComparableUvarint(b []byte, v uint64) []byte {\n\t// The first byte has 256 values, [0, 7] is reserved for negative tags,\n\t// [248, 255] is reserved for larger positive tags,\n\t// So we can store value [0, 239] in a single byte.\n\t// Values cannot be stored in single byte has a tag byte prefix (positiveTagStart+length).\n\t// Larger value encodes to more bytes, has larger tag.\n\tif v <= positiveTagStart-negativeTagEnd {\n\t\treturn append(b, byte(v)+negativeTagEnd)\n\t} else if v <= 0xff {\n\t\treturn append(b, positiveTagStart+1, byte(v))\n\t} else if v <= 0xffff {\n\t\treturn append(b, positiveTagStart+2, byte(v>>8), byte(v))\n\t} else if v <= 0xffffff {\n\t\treturn append(b, positiveTagStart+3, byte(v>>16), byte(v>>8), byte(v))\n\t} else if v <= 0xffffffff {\n\t\treturn append(b, positiveTagStart+4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))\n\t} else if v <= 0xffffffffff {\n\t\treturn append(b, positiveTagStart+5, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))\n\t} else if v <= 0xffffffffffff {\n\t\treturn append(b, positiveTagStart+6, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8),\n\t\t\tbyte(v))\n\t} else if v <= 0xffffffffffffff {\n\t\treturn append(b, positiveTagStart+7, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16),\n\t\t\tbyte(v>>8), byte(v))\n\t}\n\treturn append(b, positiveTagStart+8, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24),\n\t\tbyte(v>>16), byte(v>>8), byte(v))\n}\n\nvar (\n\terrDecodeInsufficient = errors.New(\"insufficient bytes to decode value\")\n\terrDecodeInvalid      = errors.New(\"invalid bytes to decode value\")\n)\n\n// DecodeComparableUvarint decodes mem-comparable uvarint.\nfunc DecodeComparableUvarint(b []byte) ([]byte, uint64, error) {\n\tif len(b) == 0 {\n\t\treturn nil, 0, errDecodeInsufficient\n\t}\n\tfirst := b[0]\n\tb = b[1:]\n\tif first < negativeTagEnd {\n\t\treturn nil, 0, errors.Trace(errDecodeInvalid)\n\t}\n\tif first <= positiveTagStart {\n\t\treturn b, uint64(first) - negativeTagEnd, nil\n\t}\n\tlength := int(first) - positiveTagStart\n\tif len(b) < length {\n\t\treturn nil, 0, errors.Trace(errDecodeInsufficient)\n\t}\n\tvar v uint64\n\tfor _, c := range b[:length] {\n\t\tv = (v << 8) | uint64(c)\n\t}\n\treturn b[length:], v, nil\n}\n\n// DecodeComparableVarint decodes mem-comparable varint.\nfunc DecodeComparableVarint(b []byte) ([]byte, int64, error) {\n\tif len(b) == 0 {\n\t\treturn nil, 0, errors.Trace(errDecodeInsufficient)\n\t}\n\tfirst := b[0]\n\tif first >= negativeTagEnd && first <= positiveTagStart {\n\t\treturn b, int64(first) - negativeTagEnd, nil\n\t}\n\tb = b[1:]\n\tvar length int\n\tvar v uint64\n\tif first < negativeTagEnd {\n\t\tlength = negativeTagEnd - int(first)\n\t\tv = math.MaxUint64 // negative value has all bits on by default.\n\t} else {\n\t\tlength = int(first) - positiveTagStart\n\t}\n\tif len(b) < length {\n\t\treturn nil, 0, errors.Trace(errDecodeInsufficient)\n\t}\n\tfor _, c := range b[:length] {\n\t\tv = (v << 8) | uint64(c)\n\t}\n\tif first > positiveTagStart && v > math.MaxInt64 {\n\t\treturn nil, 0, errors.Trace(errDecodeInvalid)\n\t} else if first < negativeTagEnd && v <= math.MaxInt64 {\n\t\treturn nil, 0, errors.Trace(errDecodeInvalid)\n\t}\n\treturn b[length:], int64(v), nil\n}\n"
  },
  {
    "path": "pkg/util/execdetails/execdetails.go",
    "content": "// Copyright 2018 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage execdetails\n\nimport (\n\t\"sync\"\n)\n\n// RuntimeStatsColl collects executors's execution info.\ntype RuntimeStatsColl struct {\n\tmu        sync.Mutex\n\trootStats map[string]*RuntimeStats\n}\n\n// concurrencyInfo is used to save the concurrency information of the executor operator\ntype concurrencyInfo struct {\n\tconcurrencyName string\n\tconcurrencyNum  int\n}\n\n// RuntimeStats collects one executor's execution info.\ntype RuntimeStats struct {\n\t// executor's Next() called times.\n\tloop int32\n\t// executor consume time.\n\tconsume int64\n\t// executor return row count.\n\trows int64\n\n\tmu sync.Mutex\n\t// executor concurrency information\n\tconcurrency []concurrencyInfo\n}\n\n// GetRootStats gets execStat for a executor.\nfunc (e *RuntimeStatsColl) GetRootStats(planID string) *RuntimeStats {\n\te.mu.Lock()\n\tdefer e.mu.Unlock()\n\truntimeStats, exists := e.rootStats[planID]\n\tif !exists {\n\t\truntimeStats = &RuntimeStats{}\n\t\te.rootStats[planID] = runtimeStats\n\t}\n\treturn runtimeStats\n}\n"
  },
  {
    "path": "pkg/util/hack/hack.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage hack\n\nimport (\n\t\"reflect\"\n\t\"unsafe\"\n)\n\n// MutableString can be used as string via string(MutableString) without performance loss.\ntype MutableString string\n\n// String converts slice to MutableString without copy.\n// The MutableString can be converts to string without copy.\n// Use it at your own risk.\nfunc String(b []byte) (s MutableString) {\n\tif len(b) == 0 {\n\t\treturn \"\"\n\t}\n\tpbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))\n\tpstring := (*reflect.StringHeader)(unsafe.Pointer(&s))\n\tpstring.Data = pbytes.Data\n\tpstring.Len = pbytes.Len\n\treturn\n}\n\n// Slice converts string to slice without copy.\n// Use at your own risk.\nfunc Slice(s string) (b []byte) {\n\tpbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))\n\tpstring := (*reflect.StringHeader)(unsafe.Pointer(&s))\n\tpbytes.Data = pstring.Data\n\tpbytes.Len = pstring.Len\n\tpbytes.Cap = pstring.Len\n\treturn\n}\n"
  },
  {
    "path": "pkg/util/hack/hack_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage hack\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n)\n\nfunc TestT(t *testing.T) {\n\tTestingT(t)\n}\n\nfunc TestString(t *testing.T) {\n\tb := []byte(\"hello world\")\n\ta := String(b)\n\n\tif a != \"hello world\" {\n\t\tt.Fatal(a)\n\t}\n\n\tb[0] = 'a'\n\n\tif a != \"aello world\" {\n\t\tt.Fatal(a)\n\t}\n\n\tb = append(b, \"abc\"...)\n\tif a != \"aello world\" {\n\t\tt.Fatalf(\"a:%v, b:%v\", a, b)\n\t}\n}\n\nfunc TestByte(t *testing.T) {\n\ta := \"hello world\"\n\n\tb := Slice(a)\n\n\tif !bytes.Equal(b, []byte(\"hello world\")) {\n\t\tt.Fatal(string(b))\n\t}\n}\n\nfunc TestMutable(t *testing.T) {\n\ta := []byte{'a', 'b', 'c'}\n\tb := String(a) // b is a mutable string.\n\tc := string(b) // Warn, c is a mutable string\n\tif c != \"abc\" {\n\t\tt.Fatalf(\"assert fail\")\n\t}\n\n\t// c changed after a is modified\n\ta[0] = 's'\n\tif c != \"sbc\" {\n\t\tt.Fatal(\"test mutable string fail\")\n\t}\n}\n"
  },
  {
    "path": "pkg/util/keyutil/key_util.go",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage keyutil\n\nimport (\n\t\"crypto/ed25519\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/tjfoc/gmsm/sm2\"\n\tsmx509 \"github.com/tjfoc/gmsm/x509\"\n)\n\nfunc LoadPrivateKeyFromPemFile(pemPath string) (any, error) {\n\tdata, err := os.ReadFile(pemPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn LoadPrivateKeyFromPem(data)\n}\n\nfunc LoadPrivateKeyFromPem(pemData []byte) (any, error) {\n\tfor block, rest := pem.Decode(pemData); block != nil; block, rest = pem.Decode(rest) {\n\t\tif block.Type == \"PRIVATE KEY\" {\n\t\t\t// find private key and parse it\n\t\t\tpk, err := x509.ParsePKCS8PrivateKey(block.Bytes)\n\t\t\tif err != nil {\n\t\t\t\tlogrus.Warnf(\"%v\\ntry sm2\", err)\n\t\t\t\treturn smx509.ParsePKCS8PrivateKey(block.Bytes, nil)\n\t\t\t}\n\t\t\treturn pk, err\n\t\t}\n\t\tif block.Type == \"RSA PRIVATE KEY\" {\n\t\t\treturn x509.ParsePKCS1PrivateKey(block.Bytes)\n\t\t}\n\t}\n\treturn nil, errors.New(\"failed to decode PEM block containing private key\")\n}\n\nfunc GetPublicKeyInDER(privKey any) ([]byte, error) {\n\tswitch priv := privKey.(type) {\n\tcase ed25519.PrivateKey:\n\t\tpub := priv.Public()\n\t\treturn x509.MarshalPKIXPublicKey(pub)\n\tcase *rsa.PrivateKey:\n\t\treturn x509.MarshalPKIXPublicKey(&priv.PublicKey)\n\tcase *sm2.PrivateKey:\n\t\treturn smx509.MarshalSm2PublicKey(&priv.PublicKey)\n\tdefault:\n\t\treturn nil, errors.New(\"unsupported type of private key\")\n\t}\n}\n\n// pubKey is in PEM format\nfunc ParsePubKey(pubKey string) (any, error) {\n\tpubDER, err := base64.StdEncoding.DecodeString(pubKey)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse public key in base64 encoding: %v\", err)\n\t}\n\n\tpub, err := x509.ParsePKIXPublicKey(pubDER)\n\tif err != nil {\n\t\tlogrus.Warnf(\"%v, try sm2\", err)\n\t\tpub, err = smx509.ParseSm2PublicKey(pubDER)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse DER encoded public key: %v\", err)\n\t\t}\n\t}\n\n\treturn pub, nil\n}\n\n// return pubKey in PEM format\nfunc GetPubKeyInPEM(priv any) (string, error) {\n\tpubKeyinDER, err := GetPublicKeyInDER(priv)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to parse public key in DER: %v\", err)\n\t}\n\tpubKeyBase64 := base64.StdEncoding.EncodeToString(pubKeyinDER)\n\n\treturn pubKeyBase64, nil\n}\n"
  },
  {
    "path": "pkg/util/kusciaclient/kusciaclient.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage kusciaclient\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/secretflow/scql/pkg/config\"\n)\n\nconst (\n\tkusciaTokenHeader = \"token\"\n)\n\ntype TLSMode string\n\nconst (\n\tNoTLS     TLSMode = \"notls\"\n\tTLS       TLSMode = \"tls\"\n\tMutualTLS TLSMode = \"mtls\"\n)\n\nfunc NewKusciaClientConn(endpoint string, tlsMode string, certPath, keyPath, cacertPath, token string) (*grpc.ClientConn, error) {\n\tvar grpcDialOpts []grpc.DialOption\n\tlowerTlsMode := strings.ToLower(tlsMode)\n\tswitch lowerTlsMode {\n\tcase string(NoTLS):\n\t\tgrpcDialOpts = append(grpcDialOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))\n\tcase string(TLS), string(MutualTLS):\n\t\t// header must contain token if TLSMode is TLS or MutualTLS\n\t\tgrpcDialOpts = append(grpcDialOpts, grpc.WithUnaryInterceptor(grpcClientTokenInterceptor(token)))\n\n\t\tvar creds credentials.TransportCredentials\n\t\tif lowerTlsMode == string(MutualTLS) {\n\t\t\ttlsConfig, err := config.LoadTLSConfig(lowerTlsMode, cacertPath, certPath, keyPath)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tcreds = credentials.NewTLS(tlsConfig)\n\t\t} else {\n\t\t\tvar err error\n\t\t\tcreds, err = credentials.NewClientTLSFromFile(cacertPath, \"\")\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tgrpcDialOpts = append(grpcDialOpts, grpc.WithTransportCredentials(creds))\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown kusciaapi tls_mode: %s\", tlsMode)\n\t}\n\n\treturn grpc.NewClient(endpoint, grpcDialOpts...)\n}\n\nfunc grpcClientTokenInterceptor(tokenStr string) grpc.UnaryClientInterceptor {\n\treturn func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {\n\t\tctx = metadata.AppendToOutgoingContext(ctx, kusciaTokenHeader, tokenStr)\n\t\treturn invoker(ctx, method, req, reply, cc, opts...)\n\t}\n}\n"
  },
  {
    "path": "pkg/util/logutil/log.go",
    "content": "// Copyright 2024 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage logutil\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\nvar _ logrus.Formatter = &CustomMonitorFormatter{}\n\n// custom monitor formatter, e.g.: \"2020-07-14 16:59:47.7144 INFO main.go:107 |msg\"\ntype CustomMonitorFormatter struct {\n\tTimestampFormat string\n}\n\nfunc NewCustomMonitorFormatter(timestampFormat string) *CustomMonitorFormatter {\n\treturn &CustomMonitorFormatter{\n\t\tTimestampFormat: timestampFormat,\n\t}\n}\n\nfunc (f *CustomMonitorFormatter) Format(entry *logrus.Entry) ([]byte, error) {\n\tvar fileWithLine string\n\tif entry.HasCaller() {\n\t\tfileWithLine = fmt.Sprintf(\"%s:%d\", filepath.Base(entry.Caller.File), entry.Caller.Line)\n\t} else {\n\t\tfileWithLine = \":\"\n\t}\n\treturn []byte(fmt.Sprintf(\"%s %s %s %s\\n\", entry.Time.Format(f.TimestampFormat),\n\t\tstrings.ToUpper(entry.Level.String()), fileWithLine, entry.Message)), nil\n}\n"
  },
  {
    "path": "pkg/util/logutil/monitor_log_entry.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage logutil\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\n// MonitorLogEntry is Log entry struct builder adapter for log-based based system\ntype MonitorLogEntry struct {\n\tRequestID  string\n\tSessionID  string\n\tActionName string\n\tCostTime   time.Duration\n\tReason     string\n\tErrorMsg   string\n\tRawRequest string\n}\n\nfunc (b MonitorLogEntry) String() string {\n\treturn fmt.Sprintf(\"|RequestID:%v|SessionID:%v|ActionName:%v|CostTime:%v|Reason:%v|ErrorMsg:%v|Request:%v\",\n\t\tb.RequestID, b.SessionID, b.ActionName, b.CostTime, b.Reason, b.ErrorMsg, b.RawRequest)\n}\n\ntype BrokerMonitorLogEntry struct {\n\tRequestID    string\n\tRequestParty string\n\tJobID        string\n\tActionName   string\n\tCostTime     time.Duration\n\tReason       string\n\tErrorMsg     string\n\tRawRequest   string\n}\n\nfunc (b BrokerMonitorLogEntry) String() string {\n\treturn fmt.Sprintf(\"|RequestID:%v|RequestParty:%v|SessionID:%v|ActionName:%v|CostTime:%v|Reason:%v|ErrorMsg:%v|Request:%v\",\n\t\tb.RequestID, b.RequestParty, b.JobID, b.ActionName, b.CostTime, b.Reason, b.ErrorMsg, b.RawRequest)\n}\n"
  },
  {
    "path": "pkg/util/logutil/monitor_log_entry_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage logutil\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestToString(t *testing.T) {\n\t// GIVEN\n\tb := MonitorLogEntry{\n\t\tRequestID:  \"id\",\n\t\tSessionID:  \"session\",\n\t\tActionName: \"ac\",\n\t\tCostTime:   1 * time.Millisecond,\n\t\tReason:     \"None\",\n\t\tErrorMsg:   \"msg\",\n\t\tRawRequest: \"xxx\",\n\t}\n\t// WHEN\n\tactual := fmt.Sprint(b)\n\texpected := \"|RequestID:id|SessionID:session|ActionName:ac|CostTime:1ms|Reason:None|ErrorMsg:msg|Request:xxx\"\n\t// THEN\n\tif expected != actual {\n\t\tt.Errorf(\"expected: %v, actual: %v\", expected, actual)\n\t}\n}\n"
  },
  {
    "path": "pkg/util/math/math.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage math\n\nimport \"math\"\n\n// Abs implement the abs function according to http://cavaliercoder.com/blog/optimized-abs-for-int64-in-go.html\nfunc Abs(n int64) int64 {\n\ty := n >> 63\n\treturn (n ^ y) - y\n}\n\n// uintSizeTable is used as a table to do comparison to get uint length is faster than doing loop on division with 10\nvar uintSizeTable = [21]uint64{\n\t0, // redundant 0 here, so to make function StrLenOfUint64Fast to count from 1 and return i directly\n\t9, 99, 999, 9999, 99999,\n\t999999, 9999999, 99999999, 999999999, 9999999999,\n\t99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999,\n\t9999999999999999, 99999999999999999, 999999999999999999, 9999999999999999999,\n\tmath.MaxUint64,\n} // math.MaxUint64 is 18446744073709551615 and it has 20 digits\n\n// StrLenOfUint64Fast efficiently calculate the string character lengths of an uint64 as input\nfunc StrLenOfUint64Fast(x uint64) int {\n\tfor i := 1; ; i++ {\n\t\tif x <= uintSizeTable[i] {\n\t\t\treturn i\n\t\t}\n\t}\n}\n\n// StrLenOfInt64Fast efficiently calculate the string character lengths of an int64 as input\nfunc StrLenOfInt64Fast(x int64) int {\n\tsize := 0\n\tif x < 0 {\n\t\tsize = 1 // add \"-\" sign on the length count\n\t}\n\treturn size + StrLenOfUint64Fast(uint64(Abs(x)))\n}\n"
  },
  {
    "path": "pkg/util/math/math_test.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage math\n\nimport (\n\t\"math/rand\"\n\t\"strconv\"\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n)\n\nfunc TestT(t *testing.T) {\n\tTestingT(t)\n}\n\nvar _ = Suite(&testMath{})\n\ntype testMath struct{}\n\nfunc (s *testMath) TestStrLenOfUint64Fast_RandomTestCases(c *C) {\n\tfor i := 0; i < 1000000; i++ {\n\t\tnum := rand.Uint64()\n\t\texpected := len(strconv.FormatUint(num, 10))\n\t\tactual := StrLenOfUint64Fast(num)\n\t\tc.Assert(actual, Equals, expected)\n\t}\n}\n\nfunc (s *testMath) TestStrLenOfUint64Fast_ManualTestCases(c *C) {\n\tnums := [22]uint64{0,\n\t\t1, 12, 123, 1234, 12345,\n\t\t123456, 1234567, 12345678, 123456789, 1234567890,\n\t\t1234567891, 12345678912, 123456789123, 1234567891234, 12345678912345,\n\t\t123456789123456, 1234567891234567, 12345678912345678, 123456789123456789,\n\t\t123456789123457890,\n\t\t^uint64(0),\n\t}\n\n\tfor _, num := range nums {\n\t\texpected := len(strconv.FormatUint(num, 10))\n\t\tactual := StrLenOfUint64Fast(num)\n\t\tc.Assert(actual, Equals, expected)\n\t}\n}\n"
  },
  {
    "path": "pkg/util/mathutil/mathutil.go",
    "content": "// Copyright 2019-present PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n//go:build darwin || linux || windows\n// +build darwin linux windows\n\npackage mathutil\n\n// Reexport functions and variables from mathutil\nimport (\n\t\"github.com/cznic/mathutil\"\n)\n\nconst (\n\t// MaxInt presents the maximum number of Int\n\tMaxInt = mathutil.MaxInt\n\t// MinInt presents the minimum number of Int\n\tMinInt = mathutil.MinInt\n)\n\n// MaxUint64 returns the larger of a and b.\nvar MaxUint64 = mathutil.MaxUint64\n\n// MinUint64 returns the smaller of a and b.\nvar MinUint64 = mathutil.MinUint64\n\n// MaxUint32 returns the larger of a and b.\nvar MaxUint32 = mathutil.MaxUint32\n\n// MinUint32 returns the smaller of a and b.\nvar MinUint32 = mathutil.MinUint32\n\n// MaxInt64 returns the larger of a and b.\nvar MaxInt64 = mathutil.MaxInt64\n\n// MinInt64 returns the smaller of a and b.\nvar MinInt64 = mathutil.MinInt64\n\n// MaxInt8 returns the larger of a and b.\nvar MaxInt8 = mathutil.MaxInt8\n\n// MinInt8 returns the smaller of a and b.\nvar MinInt8 = mathutil.MinInt8\n\n// Max returns the larger of a and b.\nvar Max = mathutil.Max\n\n// Min returns the smaller of a and b.\nvar Min = mathutil.Min\n"
  },
  {
    "path": "pkg/util/mathutil/mathutil_wasm.go",
    "content": "// Copyright 2019-present PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mathutil\n\n// The maximum number uint can record\nconst (\n\tMaxUint = ^uint(0)\n\tMinUint = 0\n\tMaxInt  = int(MaxUint >> 1)\n\tMinInt  = -MaxInt - 1\n)\n\n// MaxUint64 returns the larger of a and b.\nfunc MaxUint64(x, y uint64) uint64 {\n\tif x > y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// MinUint64 returns the smaller of a and b.\nfunc MinUint64(x, y uint64) uint64 {\n\tif x < y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// MaxUint32 returns the larger of a and b.\nfunc MaxUint32(x, y uint32) uint32 {\n\tif x > y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// MinUint32 returns the smaller of a and b.\nfunc MinUint32(x, y uint32) uint32 {\n\tif x < y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// MaxInt64 returns the larger of a and b.\nfunc MaxInt64(x, y int64) int64 {\n\tif x > y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// MinInt64 returns the smaller of a and b.\nfunc MinInt64(x, y int64) int64 {\n\tif x < y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// MaxInt32 returns the larger of a and b.\nfunc MaxInt32(x, y int32) int32 {\n\tif x > y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// MinInt32 returns the smaller of a and b.\nfunc MinInt32(x, y int32) int32 {\n\tif x < y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// MaxInt8 returns the larger of a and b.\nfunc MaxInt8(x, y int8) int8 {\n\tif x > y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// MinInt8 returns the smaller of a and b.\nfunc MinInt8(x, y int8) int8 {\n\tif x < y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// Max returns the larger of a and b.\nfunc Max(x, y int) int {\n\tif x > y {\n\t\treturn x\n\t}\n\treturn y\n}\n\n// Min returns the larger of a and b.\nfunc Min(x, y int) int {\n\tif x < y {\n\t\treturn x\n\t}\n\treturn y\n}\n"
  },
  {
    "path": "pkg/util/message/message_io_util.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage message\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\ntype ContentEncodingType int\n\nconst (\n\tEncodingTypeUnknown ContentEncodingType = iota + 1\n\tEncodingTypeJson\n\tEncodingTypeProtobuf\n)\n\nvar ContentType2EncodingType = map[string]ContentEncodingType{\n\t\"application/json\":       EncodingTypeJson,\n\t\"application/x-protobuf\": EncodingTypeProtobuf,\n}\n\nvar EncodingType2ContentType = map[ContentEncodingType]string{\n\tEncodingTypeJson:     \"application/json\",\n\tEncodingTypeProtobuf: \"application/x-protobuf\",\n}\n\nvar (\n\tProtoMarshal   = protojson.MarshalOptions{UseProtoNames: true, EmitUnpopulated: true}.Marshal\n\tProtoUnmarshal = protojson.UnmarshalOptions{}.Unmarshal\n)\n\nvar maxPrintContentLength = 1000\n\nfunc DeserializeFrom(in io.ReadCloser, request proto.Message, contentType string) (ContentEncodingType, error) {\n\tif request == nil {\n\t\treturn EncodingTypeUnknown, fmt.Errorf(\"unexpected empty message\")\n\t}\n\tbody, err := io.ReadAll(in)\n\tif err != nil {\n\t\treturn EncodingTypeUnknown, err\n\t}\n\tswitch contentType {\n\tcase EncodingType2ContentType[EncodingTypeJson]:\n\t\terr = ProtoUnmarshal(body, request)\n\t\tif err == nil {\n\t\t\treturn EncodingTypeJson, nil\n\t\t}\n\tcase EncodingType2ContentType[EncodingTypeProtobuf]:\n\t\terr = proto.Unmarshal(body, request)\n\t\tif err == nil {\n\t\t\treturn EncodingTypeProtobuf, nil\n\t\t}\n\tdefault:\n\t\tif contentType == \"\" {\n\t\t\tlogrus.Warning(\"empty content-type\")\n\t\t} else {\n\t\t\tlogrus.Warningf(\"content-type (%s) is not one of application/json and application/x-protobuf\", contentType)\n\t\t}\n\n\t\t// Try to parse protobuf first, then json\n\t\terr = proto.Unmarshal(body, request)\n\t\tif err == nil {\n\t\t\treturn EncodingTypeProtobuf, nil\n\t\t}\n\t\terr = ProtoUnmarshal(body, request)\n\t\tif err == nil {\n\t\t\treturn EncodingTypeJson, nil\n\t\t}\n\t}\n\n\thighLimit := len(body)\n\tif highLimit > maxPrintContentLength {\n\t\thighLimit = maxPrintContentLength\n\t}\n\treturn EncodingTypeUnknown, fmt.Errorf(\"got unexpected error=\\\"%w\\\" while unmarshal proto from content=%s\", err, string(body[:highLimit]))\n}\n\nfunc SerializeTo(response proto.Message, encodingType ContentEncodingType) (content string, err error) {\n\tif response == nil {\n\t\treturn \"\", fmt.Errorf(\"unexpected empty message\")\n\t}\n\tswitch encodingType {\n\tcase EncodingTypeProtobuf:\n\t\tc, err := proto.Marshal(response)\n\t\treturn string(c), err\n\tcase EncodingTypeJson:\n\t\tc, err := ProtoMarshal(response)\n\t\treturn string(c), err\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"not implemented\")\n\t}\n}\n"
  },
  {
    "path": "pkg/util/misc.go",
    "content": "// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage util\n\nimport (\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n)\n\nvar (\n\t// InformationSchemaName is the `INFORMATION_SCHEMA` database name.\n\tInformationSchemaName = model.NewCIStr(\"INFORMATION_SCHEMA\")\n)\n"
  },
  {
    "path": "pkg/util/mock/Makefile",
    "content": "default: create\n\ncreate:\n\tpython3 mock_schema.py"
  },
  {
    "path": "pkg/util/mock/README.md",
    "content": "# MOCK\n\n## MOCK SCHEMA\n\n* If you want to create new table schema or add new data type, edit mock_schema.py then run command `make` in current folder. mock_schema.py will create *.json in testdata folder which read by mock_data.go\n\n**Warning**: Don't modify testdata/generated_*.json directly, it will be overwritten.\n\n## MOCK DATA\n\n* If you want to create data from schema, use script named `mock_from_testdata.py` with type \"data\"\n\n## FINALLY\n\n* If you want to update schema, and run tests in `.ci`, just run `bash mock.sh`\n"
  },
  {
    "path": "pkg/util/mock/mock.sh",
    "content": "#!/bin/bash\n#\n# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# get work dir\nSCRIPT_DIR=$(\n  cd \"$(dirname \"$0\")\"\n  pwd\n)\n\nWORK_DIR=$(\n  cd $SCRIPT_DIR/../../..\n  pwd\n)\n\ncd ${SCRIPT_DIR}\npython mock_from_testdata.py -dd=testdata -s=\"testdata/db.json\"\n\nmv testdata/mysql_*_init.sql ${WORK_DIR}/.ci/test-data/mysql/\nmv testdata/postgres_*_init.sql ${WORK_DIR}/.ci/test-data/postgres\nmv testdata/*.csv ${WORK_DIR}/.ci/test-data/csv\n\nfind . -type f -name '*.py' -print0 | xargs -0 black"
  },
  {
    "path": "pkg/util/mock/mock_data.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mock\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/secretflow/scql/pkg/parser/model\"\n\t\"github.com/secretflow/scql/pkg/parser/mysql\"\n\t\"github.com/secretflow/scql/pkg/parser/types\"\n\t\"github.com/secretflow/scql/pkg/proto-gen/scql\"\n\tv1 \"github.com/secretflow/scql/pkg/proto-gen/scql/v1alpha1\"\n\t\"github.com/secretflow/scql/pkg/sessionctx\"\n\t\"github.com/secretflow/scql/pkg/util/sliceutil\"\n)\n\nvar MockDBPath = \"db.json\"\n\nvar dTypeString2FieldType = map[string]types.FieldType{\n\t\"int\":       *(types.NewFieldType(mysql.TypeLong)),\n\t\"string\":    *(types.NewFieldType(mysql.TypeString)),\n\t\"float\":     *(types.NewFieldType(mysql.TypeFloat)),\n\t\"datetime\":  *(types.NewFieldType(mysql.TypeDatetime)),\n\t\"timestamp\": *(types.NewFieldType(mysql.TypeTimestamp)),\n}\n\n// TODO: rename PhysicalTableMeta\ntype PhysicalTableMeta struct {\n\tDBName    string\n\tTableName string\n\tDBType    string\n\tColumns   []columnMeta\n}\n\ntype columnMeta struct {\n\tName  string\n\tDType string\n}\n\nfunc (pt *PhysicalTableMeta) ToCreateTableStmt(newTblName string, ifNotExists bool) string {\n\tvar b strings.Builder\n\tb.WriteString(\"CREATE TABLE\")\n\tif ifNotExists {\n\t\tb.WriteString(\" IF NOT EXISTS\")\n\t}\n\tb.WriteString(\" \")\n\tb.WriteString(newTblName)\n\tb.WriteString(\" (\")\n\tfor i, col := range pt.Columns {\n\t\tif i != 0 {\n\t\t\tb.WriteString(\",\")\n\t\t}\n\t\tb.WriteString(fmt.Sprintf(\"%s %s\", col.Name, col.DType))\n\t}\n\tb.WriteString(\") \")\n\tb.WriteString(fmt.Sprintf(\"REF_TABLE=%s.%s DB_TYPE='%s'\", pt.DBName, pt.TableName, pt.DBType))\n\treturn b.String()\n}\n\nfunc (pt *PhysicalTableMeta) RefTable() string {\n\treturn fmt.Sprintf(\"%s.%s\", pt.DBName, pt.TableName)\n}\n\ntype allDBData struct {\n\tDbName    string\n\tPartyCode string\n\tTables    map[string]tableInfo\n\tDBType    string\n}\n\ntype db struct {\n\tTableFiles []string          `json:\"table_files\"`\n\tDBInfo     map[string]dbInfo `json:\"db_info\"`\n}\n\ntype dbInfo struct {\n\tPartyCode string `json:\"party_code\"`\n\tDBType    string `json:\"db_type\"`\n}\n\ntype tableInfo struct {\n\tDbName  string       `json:\"db_name\"`\n\tColumns []columnInfo `json:\"columns\"`\n}\ntype columnInfo struct {\n\tColumnName string   `json:\"column_name\"`\n\tDtype      string   `json:\"dtype\"`\n\tOpenConds  []string `json:\"open_conds\"`\n}\n\nfunc getByteArrayFromJson(filePath string) (res []byte, err error) {\n\tjsonFile, err := os.Open(filePath)\n\tif err != nil {\n\t\treturn res, err\n\t}\n\tdefer func() {\n\t\tif err1 := jsonFile.Close(); err == nil && err1 != nil {\n\t\t\terr = err1\n\t\t}\n\t}()\n\tbyteValue, err := io.ReadAll(jsonFile)\n\tif err != nil {\n\t\treturn res, err\n\t}\n\t// Remove comments, since they are not allowed in json.\n\tre := regexp.MustCompile(\"(?s)//.*?\\n\")\n\treturn re.ReplaceAll(byteValue, nil), nil\n}\n\nfunc getDataFromJson[retType any](filePath string) (res retType, err error) {\n\tbyteValue, err := getByteArrayFromJson(filePath)\n\tif err != nil {\n\t\treturn\n\t}\n\terr = json.Unmarshal(byteValue, &res)\n\treturn\n}\n\nfunc getMockData() ([]allDBData, []string, error) {\n\tvar mock_db db\n\tvar err error\n\tmockDBPath := MockDBPath\n\tif filepath.IsAbs(MockDBPath) {\n\t\tmock_db, err = getDataFromJson[db](MockDBPath)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t} else {\n\t\tpre := \"util/mock/testdata\"\n\t\tworkDir, _ := os.Getwd()\n\t\tre := regexp.MustCompile(\".*/pkg\")\n\t\tdir := re.FindString(workDir)\n\n\t\tif dir == \"\" {\n\t\t\tre = regexp.MustCompile(\".*/cmd\")\n\t\t\tdir = re.FindString(workDir)\n\t\t\tif dir == \"\" {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"cannot find pkg dir\")\n\t\t\t}\n\t\t\tdir, _ = filepath.Split(dir)\n\t\t\tdir = dir + \"pkg\"\n\t\t}\n\t\tmockDBPath = filepath.Join(filepath.Join(dir, pre), MockDBPath)\n\t\tmock_db, err = getDataFromJson[db](mockDBPath)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t}\n\n\tall_dbs := make(map[string]allDBData)\n\tfor name, info := range mock_db.DBInfo {\n\t\tall_dbs[name] = allDBData{\n\t\t\tDbName:    name,\n\t\t\tPartyCode: info.PartyCode,\n\t\t\tDBType:    info.DBType,\n\t\t\tTables:    make(map[string]tableInfo),\n\t\t}\n\t}\n\tfor _, file := range mock_db.TableFiles {\n\t\tmock_table, err := getDataFromJson[map[string]tableInfo](filepath.Join(filepath.Dir(mockDBPath), file))\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tfor table_name, table := range mock_table {\n\t\t\tif data, ok := all_dbs[table.DbName]; !ok {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"db %s not found\", table.DbName)\n\t\t\t} else {\n\t\t\t\tdata.DbName = table.DbName\n\t\t\t\tdata.Tables[table_name] = table\n\t\t\t}\n\t\t}\n\t}\n\tvar res []allDBData\n\tvar allPartyCodes []string\n\tfor db := range sliceutil.ValueSortedByMapKey(all_dbs) {\n\t\tres = append(res, db)\n\t\tallPartyCodes = append(allPartyCodes, db.PartyCode)\n\t}\n\treturn res, allPartyCodes, nil\n}\n\nfunc AssignTableId(dbTables map[string][]*model.TableInfo) {\n\tvar dbNames []string\n\tfor dbName := range dbTables {\n\t\tdbNames = append(dbNames, dbName)\n\t}\n\tsort.Strings(dbNames)\n\n\tcount := int64(0)\n\tfor _, dbName := range dbNames {\n\t\tfor _, table := range dbTables[dbName] {\n\t\t\ttable.ID = count\n\t\t\tcount += 1\n\t\t}\n\t}\n}\n\nfunc createTableSchema(tableName string, columns map[string]types.FieldType) *model.TableInfo {\n\tvar columnNames []string\n\tfor name := range columns {\n\t\tcolumnNames = append(columnNames, name)\n\t}\n\tsort.Strings(columnNames)\n\n\tcolumnInfos := []*model.ColumnInfo{}\n\tfor i, name := range columnNames {\n\t\tcolumnInfos = append(columnInfos,\n\t\t\t&model.ColumnInfo{\n\t\t\t\tState:     model.StatePublic,\n\t\t\t\tOffset:    i,\n\t\t\t\tName:      model.NewCIStr(name),\n\t\t\t\tFieldType: columns[name],\n\t\t\t\tID:        int64(i + 1),\n\t\t\t})\n\t}\n\ttable := &model.TableInfo{\n\t\tColumns: columnInfos,\n\t\tName:    model.NewCIStr(tableName),\n\t}\n\treturn table\n}\n\nfunc MockAllTables() (map[string][]*model.TableInfo, error) {\n\tdata, _, err := getMockData()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdbTables := make(map[string][]*model.TableInfo)\n\n\tfor _, db := range data {\n\t\tif dbTables[db.DbName] == nil {\n\t\t\tdbTables[db.DbName] = []*model.TableInfo{}\n\t\t}\n\t\tfor tableName, table := range db.Tables {\n\t\t\tcolumnInfos := map[string]types.FieldType{}\n\t\t\tfor _, column := range table.Columns {\n\t\t\t\tcolumnInfos[column.ColumnName] = dTypeString2FieldType[column.Dtype]\n\t\t\t}\n\t\t\ttableSchema := createTableSchema(tableName, columnInfos)\n\t\t\ttableSchema.PartyCode = db.PartyCode\n\t\t\tdbTables[db.DbName] = append(dbTables[db.DbName], tableSchema)\n\t\t}\n\t}\n\n\tAssignTableId(dbTables)\n\treturn dbTables, nil\n}\n\n// MockContext is only used for plan related tests.\nfunc MockContext() sessionctx.Context {\n\tctx := sessionctx.NewContext()\n\tctx.GetSessionVars().CurrentDB = \"test\"\n\tctx.GetSessionVars().CreatedAt = time.Date(2023, 10, 1, 8, 30, 0, 0, time.FixedZone(\"UTC+8\", 8*3600))\n\treturn ctx\n}\n\ntype MockEnginesInfo struct {\n\tPartyToUrls        map[string]string\n\tPartyToCredentials map[string]string\n\tPartyToTables      map[string][]string\n\tTableToRefs        map[string]string\n}\n\nfunc MockEngines() (*MockEnginesInfo, error) {\n\tdata, allPartyCodes, err := getMockData()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresult := &MockEnginesInfo{\n\t\tPartyToUrls:        make(map[string]string),\n\t\tPartyToCredentials: make(map[string]string),\n\t\tPartyToTables:      make(map[string][]string),\n\t\tTableToRefs:        make(map[string]string),\n\t}\n\tfor _, p := range allPartyCodes {\n\t\tresult.PartyToUrls[p] = fmt.Sprintf(\"%s.com\", p)\n\t\tresult.PartyToCredentials[p] = fmt.Sprintf(\"%s_credential\", p)\n\t}\n\tfor _, db := range data {\n\t\tfor tableName := range db.Tables {\n\t\t\tqualifiedName := strings.Join([]string{db.DbName, tableName}, \".\")\n\t\t\tresult.PartyToTables[db.PartyCode] = append(result.PartyToTables[db.PartyCode], qualifiedName)\n\t\t\tresult.TableToRefs[qualifiedName] = qualifiedName\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc MockPhysicalTableMetas() (map[string]*PhysicalTableMeta, error) {\n\tdata, _, err := getMockData()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresult := make(map[string]*PhysicalTableMeta)\n\tfor _, db := range data {\n\t\tfor tableName, tableConf := range db.Tables {\n\t\t\tpt := &PhysicalTableMeta{\n\t\t\t\tDBName:    db.DbName,\n\t\t\t\tTableName: tableName,\n\t\t\t\tDBType:    db.DBType,\n\t\t\t}\n\t\t\tfor _, col := range tableConf.Columns {\n\t\t\t\tpt.Columns = append(pt.Columns, columnMeta{\n\t\t\t\t\tName:  col.ColumnName,\n\t\t\t\t\tDType: col.Dtype,\n\t\t\t\t})\n\t\t\t}\n\t\t\tresult[fmt.Sprintf(`%s_%s`, pt.DBName, pt.TableName)] = pt\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc MockCatalog() (*scql.Catalog, error) {\n\tdata, _, err := getMockData()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar tableEntries []*scql.TableEntry\n\tfor _, dbData := range data {\n\t\tfor tableName, tableInfo := range dbData.Tables {\n\t\t\ttableEntry := &scql.TableEntry{\n\t\t\t\tTableName:   fmt.Sprintf(\"%s.%s\", dbData.DbName, tableName),\n\t\t\t\tIsView:      false,\n\t\t\t\tRefTable:    fmt.Sprintf(\"%s.%s\", tableInfo.DbName, tableName),\n\t\t\t\tRefTableUri: fmt.Sprintf(\"url_for_%s_%s\", tableInfo.DbName, tableName),\n\t\t\t\tDbType:      dbData.DBType,\n\t\t\t\tOwner:       &scql.PartyId{Code: dbData.PartyCode},\n\t\t\t}\n\t\t\tfor _, colInfo := range tableInfo.Columns {\n\t\t\t\tcol := &scql.TableEntry_Column{\n\t\t\t\t\tName: colInfo.ColumnName,\n\t\t\t\t\tType: colInfo.Dtype,\n\t\t\t\t}\n\t\t\t\ttableEntry.Columns = append(tableEntry.Columns, col)\n\t\t\t}\n\t\t\ttableEntries = append(tableEntries, tableEntry)\n\t\t}\n\t}\n\n\treturn &scql.Catalog{\n\t\tTables: tableEntries,\n\t}, nil\n}\n\nfunc MockColumnVisibility() ([]*v1.ColumnVisibility, error) {\n\tdata, _, err := getMockData()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar allParties []*scql.PartyId\n\tfor _, dbData := range data {\n\t\tallParties = append(allParties, &scql.PartyId{Code: dbData.PartyCode})\n\t}\n\n\tvar result []*v1.ColumnVisibility\n\tfor _, dbData := range data {\n\t\tfor tableName, tableInfo := range dbData.Tables {\n\t\t\tfor _, colInfo := range tableInfo.Columns {\n\t\t\t\tcolName := strings.ToLower(colInfo.ColumnName)\n\t\t\t\tif strings.Contains(colName, \"plain_\") {\n\t\t\t\t\tresult = append(result, &v1.ColumnVisibility{\n\t\t\t\t\t\tDatabase:       dbData.DbName,\n\t\t\t\t\t\tTable:          tableName,\n\t\t\t\t\t\tColumn:         colInfo.ColumnName,\n\t\t\t\t\t\tVisibleParties: allParties,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "pkg/util/mock/mock_db_data.py",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport random\nimport datetime\n\nDEFAULT_MAX_STR_LEN = 10\nPOOL_SIZE = 50\nDB_TYPES = [\"postgres\", \"mysql\"]\nDROP_TABLE = \"\"\"DROP TABLE IF EXISTS {};\"\"\"\nCREATE_TABLE_STR = \"\"\"\nCREATE TABLE {0} ({1});\n\"\"\"\nCREATE_DB_STR = [\n    \"\"\"\nCREATE SCHEMA IF NOT EXISTS {0};\nset search_path to {0};\n\n\"\"\",\n    \"\"\"\nCREATE DATABASE IF NOT EXISTS `{0}`;\nUSE `{0}`;\n\n\"\"\",\n]\n\nCOLUMN_NAME_FORMAT = \"{}_{}_{}\"\nTYPE_TO_COLUMN = {\n    \"int\": \"{} integer NOT NULL DEFAULT 0\",\n    \"float\": \"{} FLOAT_TYPE NOT NULL DEFAULT 0.0\",\n    \"string\": \"{} varchar(64) NOT NULL DEFAULT ''\",\n    \"datetime\": \"{} DATETIME_TYPE NOT NULL DEFAULT '2020-10-10 10:10:10'\",\n    \"timestamp\": \"{} timestamp NOT NULL DEFAULT '2020-10-10 10:10:10'\",\n}\n\nREPLACE_MAP = {\n    \"postgres\": {\"FLOAT_TYPE\": \"numeric\", \"DATETIME_TYPE\": \"timestamp with time zone\"},\n    \"mysql\": {\"FLOAT_TYPE\": \"double\", \"DATETIME_TYPE\": \"datetime\"},\n}\n\nINSERT_STR = \"\"\"\nINSERT INTO {} VALUES {};\"\"\"\nSQL_FILE_LIST = {\n    \"alice\": \"alice_init.sql\",\n    \"bob\": \"bob_init.sql\",\n    \"carol\": \"carol_init.sql\",\n}\nIS_DB_USE_FILE = {\n    \"mysql\": {\n        \"alice\": 1,\n        \"bob\": 1,\n        \"carol\": 1,\n    },  # mysql contains all data for comparing results\n    \"csv\": {\"alice\": 0, \"bob\": 1, \"carol\": 0},  # bob use csv as data source\n    \"postgres\": {\"alice\": 0, \"bob\": 0, \"carol\": 1},  # carol use postgres as data source\n}\n\n\ndef create_str_pool(pool_size, min_num=97, max_num=115):\n    pool = []\n    for _ in range(pool_size):\n        # from ascii 97-115\n        str_len = random.randint(0, DEFAULT_MAX_STR_LEN)\n        chr_list = []\n        for i in range(str_len):\n            chr_list.append(chr(random.randint(min_num, max_num)))\n        pool.append(\"'\" + \"\".join(chr_list) + \"'\")\n    return pool\n\n\ndef create_random_datatime():\n    year = random.randint(1971, 2030)\n    month = random.randint(1, 12)\n    day = random.randint(1, 28)\n    # avoid DST problem\n    hour = random.randint(0, 23)\n    while hour == 2:\n        hour = random.randint(0, 23)\n\n    minute = random.randint(0, 59)\n    second = random.randint(0, 59)\n    ds = datetime.datetime(year, month, day, hour, minute, second)\n    str_ds = \"'\" + ds.strftime(\"%Y-%m-%d %H:%M:%S\") + \"'\"\n    return str_ds\n\n\ndef create_data(data_type, str_pool):\n    if data_type == \"int\":\n        return random.randint(-100, 100)\n    elif data_type == \"float\":\n        return random.randint(-10000, 10000) / 100\n    elif data_type == \"string\":\n        return str_pool[random.randint(0, POOL_SIZE - 1)]\n    elif data_type == \"datetime\" or data_type == \"timestamp\":\n        return create_random_datatime()\n    else:\n        return 0\n\n\ndef fill_column_name(columns):\n    column_strs = []\n    data_types = []\n    for column in columns:\n        column_strs.append(\n            TYPE_TO_COLUMN[column[\"dtype\"]].format(column[\"column_name\"])\n        )\n        data_types.append(column[\"dtype\"])\n    return column_strs, data_types\n\n\ndef create_table(table_name, columns):\n    str = DROP_TABLE.format(table_name)\n    column_strs, _ = fill_column_name(columns)\n    all_column_strs = \",\\n\".join(column_strs)\n    str += CREATE_TABLE_STR.format(table_name, all_column_strs)\n    return str\n\n\ndef create_insert(table_name, columns, str_pool, rows):\n    batch_size = 50\n\n    insert_str = \"START TRANSACTION;\\n\"\n    for _ in range((rows + batch_size - 1) // batch_size):\n        _, data_types = fill_column_name(columns)\n        batch_insert = []\n        for _ in range(min(batch_size, rows)):\n            column_datas = []\n            for dt in data_types:\n                column_datas.append(str(create_data(dt, str_pool)))\n            batch_insert.append(\"({})\".format(\", \".join(column_datas)))\n\n        insert_str += INSERT_STR.format(table_name, \", \".join(batch_insert))\n        rows -= batch_size\n    insert_str += \"\\nCOMMIT;\"\n\n    return insert_str\n"
  },
  {
    "path": "pkg/util/mock/mock_from_testdata.py",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport json\nimport os\nimport re\nimport argparse\nfrom mock_schema import CUR_PATH\nfrom mock_db_data import *\n\nBACKEND_TYPE = {\"alice\": \"MYSQL\", \"bob\": \"CSVDB\", \"carol\": \"POSTGRESQL\"}\n\n\n# create mock xxx.sql used in mysql initiating\ndef create_mock_data(source: dict, rows: int, dest_dir: str):\n    db_infos = get_db_from_json(source)\n    str_pool = create_str_pool(POOL_SIZE)\n    for db_name in db_infos:\n        schema_info = db_infos.get(db_name)\n        tables = schema_info.get(\"table_info\")\n        contents = [\"\"] * len(DB_TYPES)\n        for table_name in tables:\n            table = tables.get(table_name)\n            columns = table.get(\"columns\")\n            table_str = create_table(table_name, columns)\n            insert_str = create_insert(table_name, columns, str_pool, rows)\n            for i, db_type in enumerate(DB_TYPES):\n                contents[i] += table_str\n                contents[i] += insert_str\n                contents[i] += \"\\n\\n\\n\\n\"\n            if IS_DB_USE_FILE[\"csv\"][db_name]:\n                column_strs = []\n                for column in columns:\n                    column_strs.append(column[\"column_name\"])\n                csv_contents = \", \".join(column_strs)\n                csv_contents += (\n                    insert_str.replace(\"START TRANSACTION;\\n\", \"\")\n                    .replace(\"\\nCOMMIT;\", \"\")\n                    .replace(\"INSERT INTO \" + table_name + \" VALUES \", \"\")\n                    .replace(\";\", \"\")\n                    .replace(\", \", \",\")\n                    .replace(\"'\", '\"')\n                    .replace(\"(\", \"\")\n                    .replace(\"),\", \"\\n\")\n                    .replace(\")\", \"\")\n                )\n                with open(\n                    os.path.join(CUR_PATH, dest_dir, f\"{db_name}_{table_name}.csv\"),\n                    \"w\",\n                ) as f:\n                    f.write(csv_contents)\n        for i, db_type in enumerate(DB_TYPES):\n            # replace float type in content\n            # postgres use numeric, mysql use float\n            contents[i] = (\n                contents[i]\n                .replace(\"FLOAT_TYPE\", REPLACE_MAP[db_type][\"FLOAT_TYPE\"])\n                .replace(\"DATETIME_TYPE\", REPLACE_MAP[db_type][\"DATETIME_TYPE\"])\n            )\n            if IS_DB_USE_FILE[db_type][db_name]:\n                with open(\n                    os.path.join(\n                        CUR_PATH, dest_dir, f\"{db_type}_{SQL_FILE_LIST[db_name]}\"\n                    ),\n                    \"w\",\n                ) as f:\n                    f.write(CREATE_DB_STR[i].format(db_name))\n                    f.write(contents[i])\n            contents[i] = \"\"\n\n\ndef get_db_from_json(source_file: str):\n    result = dict()\n    info = parse_json(source_file)\n    db_info = info.get(\"db_info\")\n    for db_name in db_info:\n        result[db_name] = db_info[db_name]\n        result[db_name][\"table_info\"] = dict()\n    for table_file in info.get(\"table_files\"):\n        table_info = parse_json(os.path.join(f\"testdata\", table_file))\n        for table_name in table_info:\n            result[table_info[table_name][\"db_name\"]][\"table_info\"][table_name] = (\n                table_info[table_name]\n            )\n    return result\n\n\ndef parse_json(source_file: str):\n    result = {}\n    with open(os.path.join(CUR_PATH, source_file), \"r\") as f:\n        result = json.load(f)\n    return result\n\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(description=\"parameters\")\n    parser.add_argument(\n        \"--dest_data\",\n        \"-dd\",\n        type=str,\n        help=\"destination dir\",\n        default=\"testdata\",\n    )\n    parser.add_argument(\n        \"--source\",\n        \"-s\",\n        type=str,\n        help=\"source path\",\n        default=\"testdata/db.json\",\n    )\n    parser.add_argument(\"--rows\", \"-r\", type=int, help=\"rows of table\", default=600)\n    args = vars(parser.parse_args())\n    source = args[\"source\"]\n    rows = args[\"rows\"]\n    data_dest = args[\"dest_data\"]\n    create_mock_data(source, rows, data_dest)\n"
  },
  {
    "path": "pkg/util/mock/mock_schema.py",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\nimport json\nimport os\nfrom pathlib import Path\nfrom typing import List\n\nCOLUMN_COPY_NUM = 3\nTABLE_COPY_NUM = 3\nDATA_TYPE = [\"int\", \"float\", \"string\", \"datetime\", \"timestamp\"]\nCCL_LEVEL = [\n    \"plain\",\n    \"join\",\n    \"joinpayload\",\n    \"groupby\",\n    \"compare\",\n    \"aggregate\",\n    \"encrypt\",\n    \"rank\",\n]\nCUR_PATH = Path(__file__).parent.resolve()\nDATABASES = [\"alice\", \"bob\", \"carol\"]\n\n\ndef create_table_for_db(db_name: str):\n    tables = dict()\n    for i in range(TABLE_COPY_NUM):\n        name, table_info = create_table(i, db_name)\n        tables[name] = table_info\n    return tables\n\n\ndef create_table(pos, db_name: str):\n    table_name_prefix = \"tbl\"\n    table = dict()\n    table_name = f\"{table_name_prefix}_{pos}\"\n    table[\"columns\"] = list()\n    table[\"db_name\"] = db_name\n    for i in range(COLUMN_COPY_NUM):\n        for dtype in DATA_TYPE:\n            for level in CCL_LEVEL:\n                table[\"columns\"].append(create_column(dtype, [level], i))\n    return table_name, table\n\n\ndef create_column(data_type: str, levels: List[str], pos: int):\n    column = dict()\n    level_strs = \"-\".join(levels)\n    column[\"column_name\"] = f\"{level_strs}_{data_type}_{pos}\"\n    column[\"dtype\"] = data_type\n    column[\"ccl\"] = levels\n    return column\n\n\ndef write_table(file_name):\n    path = os.path.join(CUR_PATH, f\"testdata\")\n    if not os.path.exists(path):\n        os.system(f\"mkdir {path}\")\n    file = os.path.join(path, f\"{file_name}.json\")\n    with open(file, \"w\", encoding=\"utf-8\") as f:\n        json.dump(data, f, indent=4, separators=(\",\", \": \"), ensure_ascii=False)\n    print(\"write success\")\n\n\nif __name__ == \"__main__\":\n    for db_name in DATABASES:\n        file_name = f\"generated_table_{db_name}.json\"\n        path = os.path.join(CUR_PATH, f\"testdata\")\n        file = os.path.join(path, file_name)\n        if os.path.exists(file):\n            os.remove(file)\n        with open(file, \"w\", encoding=\"utf-8\") as f:\n            json.dump(\n                create_table_for_db(db_name),\n                f,\n                indent=2,\n                separators=(\",\", \": \"),\n                ensure_ascii=False,\n            )\n        print(\"write success\")\n"
  },
  {
    "path": "pkg/util/mock/testdata/db.json",
    "content": "{\n  \"db_info\": {\n    \"alice\": {\n      \"party_code\": \"alice\",\n      \"db_type\": \"MYSQL\"\n    },\n    \"bob\": {\n      \"party_code\": \"bob\",\n      \"db_type\": \"CSVDB\"\n    },\n    \"carol\": {\n      \"party_code\": \"carol\",\n      \"db_type\": \"POSTGRESQL\"\n    }\n  },\n  \"table_files\": [\n    \"generated_table_alice.json\",\n    \"table_alice.json\",\n    \"generated_table_bob.json\",\n    \"table_bob.json\",\n    \"generated_table_carol.json\",\n    \"table_carol.json\"\n  ]\n}\n"
  },
  {
    "path": "pkg/util/mock/testdata/generated_table_alice.json",
    "content": "{\n  \"tbl_0\": {\n    \"db_name\": \"alice\",\n    \"columns\": [\n      {\n        \"column_name\": \"plain_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  },\n  \"tbl_1\": {\n    \"db_name\": \"alice\",\n    \"columns\": [\n      {\n        \"column_name\": \"plain_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  },\n  \"tbl_2\": {\n    \"db_name\": \"alice\",\n    \"columns\": [\n      {\n        \"column_name\": \"plain_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "pkg/util/mock/testdata/generated_table_bob.json",
    "content": "{\n  \"tbl_0\": {\n    \"db_name\": \"bob\",\n    \"columns\": [\n      {\n        \"column_name\": \"plain_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  },\n  \"tbl_1\": {\n    \"db_name\": \"bob\",\n    \"columns\": [\n      {\n        \"column_name\": \"plain_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  },\n  \"tbl_2\": {\n    \"db_name\": \"bob\",\n    \"columns\": [\n      {\n        \"column_name\": \"plain_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "pkg/util/mock/testdata/generated_table_carol.json",
    "content": "{\n  \"tbl_0\": {\n    \"db_name\": \"carol\",\n    \"columns\": [\n      {\n        \"column_name\": \"plain_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  },\n  \"tbl_1\": {\n    \"db_name\": \"carol\",\n    \"columns\": [\n      {\n        \"column_name\": \"plain_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  },\n  \"tbl_2\": {\n    \"db_name\": \"carol\",\n    \"columns\": [\n      {\n        \"column_name\": \"plain_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_1\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_1\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_1\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"plain_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"join_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"joinpayload_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"compare_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"aggregate_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"encrypt_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"rank_int_2\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"join_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"joinpayload_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"groupby_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"aggregate_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"encrypt_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"rank_float_2\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"plain_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"joinpayload_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"groupby_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"compare_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"aggregate_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"encrypt_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"rank_string_2\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"plain_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"join_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"joinpayload_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"groupby_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"compare_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"aggregate_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"encrypt_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"rank_datetime_2\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"join_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"joinpayload_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"groupby_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"compare_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"aggregate_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"encrypt_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      },\n      {\n        \"column_name\": \"rank_timestamp_2\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "pkg/util/mock/testdata/table_alice.json",
    "content": "{\n  \"tbl_3\": {\n    \"db_name\": \"alice\",\n    \"columns\": [\n      {\n        \"column_name\": \"gb_gb_gb_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"cp_cp_cp_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"jn_jn_jn_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"pl_jn_cp_int_0\",\n        \"dtype\": \"int\"\n      }\n    ]\n  },\n  \"UPPER_table\": {\n    \"db_name\": \"alice\",\n    \"columns\": [\n      {\n        \"column_name\": \"GROUPBY_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"JOIN_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"COMPARE_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "pkg/util/mock/testdata/table_bob.json",
    "content": "{\n  \"tbl_3\": {\n    \"db_name\": \"bob\",\n    \"columns\": [\n      {\n        \"column_name\": \"cp_pl_jn_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"cp_pl_jn_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"jn_pl_cp_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"jn_pl_cp_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"ag_pl_en_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"gb_pl_en_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  },\n  \"UPPER_table\": {\n    \"db_name\": \"bob\",\n    \"columns\": [\n      {\n        \"column_name\": \"GROUPBY_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"JOIN_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"COMPARE_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "pkg/util/mock/testdata/table_carol.json",
    "content": "{\n  \"tbl_3\": {\n    \"db_name\": \"carol\",\n    \"columns\": [\n      {\n        \"column_name\": \"cp_jn_pl_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"cp_jn_pl_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"gb_en_pl_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"agg_en_pl_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"plain_datetime_0\",\n        \"dtype\": \"datetime\"\n      },\n      {\n        \"column_name\": \"plain_timestamp_0\",\n        \"dtype\": \"timestamp\"\n      }\n    ]\n  },\n  \"UPPER_table\": {\n    \"db_name\": \"carol\",\n    \"columns\": [\n      {\n        \"column_name\": \"GROUPBY_int_0\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"groupby_int_1\",\n        \"dtype\": \"int\"\n      },\n      {\n        \"column_name\": \"JOIN_string_0\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"join_string_1\",\n        \"dtype\": \"string\"\n      },\n      {\n        \"column_name\": \"COMPARE_float_0\",\n        \"dtype\": \"float\"\n      },\n      {\n        \"column_name\": \"compare_float_1\",\n        \"dtype\": \"float\"\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "pkg/util/mvmap/fnv.go",
    "content": "// Copyright 2011 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mvmap\n\nconst (\n\toffset64 uint64 = 14695981039346656037\n\tprime64  uint64 = 1099511628211\n)\n\n// fnvHash64 is ported from go library, which is thread-safe.\nfunc fnvHash64(data []byte) uint64 {\n\thash := offset64\n\tfor _, c := range data {\n\t\thash *= prime64\n\t\thash ^= uint64(c)\n\t}\n\treturn hash\n}\n"
  },
  {
    "path": "pkg/util/mvmap/mvmap.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mvmap\n\nimport (\n\t\"bytes\"\n)\n\ntype entry struct {\n\taddr   dataAddr\n\tkeyLen uint32\n\tvalLen uint32\n\tnext   entryAddr\n}\n\ntype entryStore struct {\n\tslices   [][]entry\n\tsliceIdx uint32\n\tsliceLen uint32\n}\n\ntype dataStore struct {\n\tslices   [][]byte\n\tsliceIdx uint32\n\tsliceLen uint32\n}\n\ntype entryAddr struct {\n\tsliceIdx uint32\n\toffset   uint32\n}\n\ntype dataAddr struct {\n\tsliceIdx uint32\n\toffset   uint32\n}\n\nconst (\n\tmaxDataSliceLen  = 64 * 1024\n\tmaxEntrySliceLen = 8 * 1024\n)\n\nfunc (ds *dataStore) put(key, value []byte) dataAddr {\n\tdataLen := uint32(len(key) + len(value))\n\tif ds.sliceLen != 0 && ds.sliceLen+dataLen > maxDataSliceLen {\n\t\tds.slices = append(ds.slices, make([]byte, 0, max(maxDataSliceLen, int(dataLen))))\n\t\tds.sliceLen = 0\n\t\tds.sliceIdx++\n\t}\n\taddr := dataAddr{sliceIdx: ds.sliceIdx, offset: ds.sliceLen}\n\tslice := ds.slices[ds.sliceIdx]\n\tslice = append(slice, key...)\n\tslice = append(slice, value...)\n\tds.slices[ds.sliceIdx] = slice\n\tds.sliceLen += dataLen\n\treturn addr\n}\n\nfunc max(a, b int) int {\n\tif a > b {\n\t\treturn a\n\t}\n\treturn b\n}\n\nfunc (ds *dataStore) get(e entry, key []byte) []byte {\n\tslice := ds.slices[e.addr.sliceIdx]\n\tvalOffset := e.addr.offset + e.keyLen\n\tif !bytes.Equal(key, slice[e.addr.offset:valOffset]) {\n\t\treturn nil\n\t}\n\treturn slice[valOffset : valOffset+e.valLen]\n}\n\nfunc (ds *dataStore) getEntryData(e entry) (key, value []byte) {\n\tslice := ds.slices[e.addr.sliceIdx]\n\tkeyOffset := e.addr.offset\n\tkey = slice[keyOffset : keyOffset+e.keyLen]\n\tvalOffset := e.addr.offset + e.keyLen\n\tvalue = slice[valOffset : valOffset+e.valLen]\n\treturn\n}\n\nvar nullEntryAddr = entryAddr{}\n\nfunc (es *entryStore) put(e entry) entryAddr {\n\tif es.sliceLen == maxEntrySliceLen {\n\t\tes.slices = append(es.slices, make([]entry, 0, maxEntrySliceLen))\n\t\tes.sliceLen = 0\n\t\tes.sliceIdx++\n\t}\n\taddr := entryAddr{sliceIdx: es.sliceIdx, offset: es.sliceLen}\n\tslice := es.slices[es.sliceIdx]\n\tslice = append(slice, e)\n\tes.slices[es.sliceIdx] = slice\n\tes.sliceLen++\n\treturn addr\n}\n\nfunc (es *entryStore) get(addr entryAddr) entry {\n\treturn es.slices[addr.sliceIdx][addr.offset]\n}\n\n// MVMap stores multiple value for a given key with minimum GC overhead.\n// A given key can store multiple values.\n// It is not thread-safe, should only be used in one goroutine.\ntype MVMap struct {\n\tentryStore entryStore\n\tdataStore  dataStore\n\thashTable  map[uint64]entryAddr\n\tlength     int\n}\n\n// NewMVMap creates a new multi-value map.\nfunc NewMVMap() *MVMap {\n\tm := new(MVMap)\n\tm.hashTable = make(map[uint64]entryAddr)\n\tm.entryStore.slices = [][]entry{make([]entry, 0, 64)}\n\t// Append the first empty entry, so the zero entryAddr can represent null.\n\tm.entryStore.put(entry{})\n\tm.dataStore.slices = [][]byte{make([]byte, 0, 1024)}\n\treturn m\n}\n\n// Put puts the key/value pairs to the MVMap, if the key already exists, old value will not be overwritten,\n// values are stored in a list.\nfunc (m *MVMap) Put(key, value []byte) {\n\thashKey := fnvHash64(key)\n\toldEntryAddr := m.hashTable[hashKey]\n\tdataAddr := m.dataStore.put(key, value)\n\te := entry{\n\t\taddr:   dataAddr,\n\t\tkeyLen: uint32(len(key)),\n\t\tvalLen: uint32(len(value)),\n\t\tnext:   oldEntryAddr,\n\t}\n\tnewEntryAddr := m.entryStore.put(e)\n\tm.hashTable[hashKey] = newEntryAddr\n\tm.length++\n}\n\n// Get gets the values of the \"key\" and appends them to \"values\".\nfunc (m *MVMap) Get(key []byte, values [][]byte) [][]byte {\n\thashKey := fnvHash64(key)\n\tentryAddr := m.hashTable[hashKey]\n\tfor entryAddr != nullEntryAddr {\n\t\te := m.entryStore.get(entryAddr)\n\t\tentryAddr = e.next\n\t\tval := m.dataStore.get(e, key)\n\t\tif len(val) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tvalues = append(values, val)\n\t}\n\t// Keep the order of input.\n\tfor i := 0; i < len(values)/2; i++ {\n\t\tj := len(values) - 1 - i\n\t\tvalues[i], values[j] = values[j], values[i]\n\t}\n\treturn values\n}\n\n// Len returns the number of values in th mv map, the number of keys may be less than Len\n// if the same key is put more than once.\nfunc (m *MVMap) Len() int {\n\treturn m.length\n}\n\n// Iterator is used to iterate the MVMap.\ntype Iterator struct {\n\tm        *MVMap\n\tsliceCur int\n\tentryCur int\n}\n\n// Next returns the next key/value pair of the MVMap.\n// It returns (nil, nil) when there is no more entries to iterate.\nfunc (i *Iterator) Next() (key, value []byte) {\n\tfor {\n\t\tif i.sliceCur >= len(i.m.entryStore.slices) {\n\t\t\treturn nil, nil\n\t\t}\n\t\tentrySlice := i.m.entryStore.slices[i.sliceCur]\n\t\tif i.entryCur >= len(entrySlice) {\n\t\t\ti.sliceCur++\n\t\t\ti.entryCur = 0\n\t\t\tcontinue\n\t\t}\n\t\tentry := entrySlice[i.entryCur]\n\t\tkey, value = i.m.dataStore.getEntryData(entry)\n\t\ti.entryCur++\n\t\treturn\n\t}\n}\n\n// NewIterator creates a iterator for the MVMap.\nfunc (m *MVMap) NewIterator() *Iterator {\n\t// The first entry is empty, so init entryCur to 1.\n\treturn &Iterator{m: m, entryCur: 1}\n}\n"
  },
  {
    "path": "pkg/util/mvmap/mvmap_test.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage mvmap\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n)\n\nfunc TestT(t *testing.T) {\n\tTestingT(t)\n}\n\nfunc TestMVMap(t *testing.T) {\n\tm := NewMVMap()\n\tvar vals [][]byte\n\tm.Put([]byte(\"abc\"), []byte(\"abc1\"))\n\tm.Put([]byte(\"abc\"), []byte(\"abc2\"))\n\tm.Put([]byte(\"def\"), []byte(\"def1\"))\n\tm.Put([]byte(\"def\"), []byte(\"def2\"))\n\tvals = m.Get([]byte(\"abc\"), vals[:0])\n\tif fmt.Sprintf(\"%s\", vals) != \"[abc1 abc2]\" {\n\t\tt.FailNow()\n\t}\n\tvals = m.Get([]byte(\"def\"), vals[:0])\n\tif fmt.Sprintf(\"%s\", vals) != \"[def1 def2]\" {\n\t\tt.FailNow()\n\t}\n\n\tif m.Len() != 4 {\n\t\tt.FailNow()\n\t}\n\n\tresults := []string{\"abc abc1\", \"abc abc2\", \"def def1\", \"def def2\"}\n\tit := m.NewIterator()\n\tfor i := 0; i < 4; i++ {\n\t\tkey, val := it.Next()\n\t\tif fmt.Sprintf(\"%s %s\", key, val) != results[i] {\n\t\t\tt.FailNow()\n\t\t}\n\t}\n\tkey, val := it.Next()\n\tif key != nil || val != nil {\n\t\tt.FailNow()\n\t}\n}\n\nfunc BenchmarkMVMapPut(b *testing.B) {\n\tm := NewMVMap()\n\tbuffer := make([]byte, 8)\n\tfor i := 0; i < b.N; i++ {\n\t\tbinary.BigEndian.PutUint64(buffer, uint64(i))\n\t\tm.Put(buffer, buffer)\n\t}\n}\n\nfunc BenchmarkMVMapGet(b *testing.B) {\n\tm := NewMVMap()\n\tbuffer := make([]byte, 8)\n\tfor i := 0; i < b.N; i++ {\n\t\tbinary.BigEndian.PutUint64(buffer, uint64(i))\n\t\tm.Put(buffer, buffer)\n\t}\n\tval := make([][]byte, 0, 8)\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tbinary.BigEndian.PutUint64(buffer, uint64(i))\n\t\tval = m.Get(buffer, val[:0])\n\t\tif len(val) != 1 || !bytes.Equal(val[0], buffer) {\n\t\t\tb.FailNow()\n\t\t}\n\t}\n}\n\nfunc TestFNVHash(t *testing.T) {\n\tb := []byte{0xcb, 0xf2, 0x9c, 0xe4, 0x84, 0x22, 0x23, 0x25}\n\tsum1 := fnvHash64(b)\n\thash := fnv.New64()\n\thash.Reset()\n\thash.Write(b)\n\tsum2 := hash.Sum64()\n\tif sum1 != sum2 {\n\t\tt.FailNow()\n\t}\n}\n"
  },
  {
    "path": "pkg/util/parallel/parallel.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parallel\n\nimport \"errors\"\n\nfunc ParallelRun[resultT any, t any](inputs []t, fn func(input t) (resultT, error)) ([]resultT, error) {\n\ttype errStruct struct {\n\t\tresult resultT\n\t\terr    error\n\t}\n\tretCh := make(chan errStruct, len(inputs))\n\tfor _, input := range inputs {\n\t\tgo func(input t) {\n\t\t\tres, resError := fn(input)\n\t\t\tretCh <- errStruct{res, resError}\n\t\t}(input)\n\t}\n\tvar err error\n\tvar results []resultT\n\tfor range inputs {\n\t\tretData := <-retCh\n\t\tresults = append(results, retData.result)\n\t\terr = errors.Join(err, retData.err)\n\t}\n\treturn results, err\n}\n"
  },
  {
    "path": "pkg/util/plancodec/id.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage plancodec\n\nconst (\n\t// TypeSel is the type of Selection.\n\tTypeSel = \"Selection\"\n\t// TypeSet is the type of Set.\n\tTypeSet = \"Set\"\n\t// TypeProj is the type of Projection.\n\tTypeProj = \"Projection\"\n\t// TypeAgg is the type of Aggregation.\n\tTypeAgg = \"Aggregation\"\n\t// TypeHashAgg is the type of HashAgg.\n\tTypeHashAgg = \"HashAgg\"\n\t// TypeShow is the type of show.\n\tTypeShow = \"Show\"\n\t// TypeJoin is the type of Join.\n\tTypeJoin = \"Join\"\n\t// TypeUnion is the type of Union.\n\tTypeUnion = \"Union\"\n\t// TypeTableScan is the type of TableScan.\n\tTypeTableScan = \"TableScan\"\n\t// TypeDual is the type of TableDual.\n\tTypeDual = \"TableDual\"\n\t// TypeUnionScan is the type of UnionScan.\n\tTypeUnionScan = \"UnionScan\"\n\t// TypeSort is the type of Sort.\n\tTypeSort = \"Sort\"\n\t// TypeTopN is the type of TopN.\n\tTypeTopN = \"TopN\"\n\t// TypeLimit is the type of Limit.\n\tTypeLimit = \"Limit\"\n\t// TypeHashLeftJoin is the type of left hash join.\n\tTypeHashLeftJoin = \"HashLeftJoin\"\n\t// TypeHashRightJoin is the type of right hash join.\n\tTypeHashRightJoin = \"HashRightJoin\"\n\t// TypeMergeJoin is the type of merge join.\n\tTypeMergeJoin = \"MergeJoin\"\n\t// TypeIndexJoin is the type of index look up join.\n\tTypeIndexJoin = \"IndexJoin\"\n\t// TypeIndexMergeJoin is the type of index look up merge join.\n\tTypeIndexMergeJoin = \"IndexMergeJoin\"\n\t// TypeIndexHashJoin is the type of index nested loop hash join.\n\tTypeIndexHashJoin = \"IndexHashJoin\"\n\t// TypeApply is the type of Apply.\n\tTypeApply = \"Apply\"\n\t// TypeMaxOneRow is the type of MaxOneRow.\n\tTypeMaxOneRow = \"MaxOneRow\"\n\t// TypeExists is the type of Exists.\n\tTypeExists = \"Exists\"\n\t// TypeTableReader is the type of TableReader.\n\tTypeTableReader = \"TableReader\"\n\t// TypeWindow is the type of Window.\n\tTypeWindow = \"Window\"\n)\n\n// plan id.\nconst (\n\ttypeSelID int = iota + 1\n\ttypeSetID\n\ttypeProjID\n\ttypeAggID\n\ttypeStreamAggID\n\ttypeHashAggID\n\ttypeShowID\n\ttypeJoinID\n\ttypeUnionID\n\ttypeTableScanID\n\ttypeUnionScanID\n\ttypeIdxScanID\n\ttypeSortID\n\ttypeTopNID\n\ttypeLimitID\n\ttypeHashLeftJoinID\n\ttypeHashRightJoinID\n\ttypeMergeJoinID\n\ttypeIndexJoinID\n\ttypeIndexMergeJoinID\n\ttypeIndexHashJoinID\n\ttypeApplyID\n\ttypeMaxOneRowID\n\ttypeExistsID\n\ttypeTableReaderID\n\ttypeIndexMergeID\n\ttypePointGet\n\ttypeShowDDLJobs\n\ttypeBatchPointGet\n)\n"
  },
  {
    "path": "pkg/util/prometheus/prom.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage prom\n\nimport (\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\nconst MetricsPath = \"/metrics\"\n\nconst ResponseStatusKey = \"response_code\"\n\nvar (\n\tdefaultDuration = []float64{3 * 60, 30 * 60, 2 * 60 * 60, 12 * 60 * 60, 24 * 60 * 60}\n\tonce            sync.Once\n\tmonitor         *Monitor\n)\n\ntype Monitor struct {\n\tRequestTotal    *prometheus.CounterVec\n\tRequestDuration *prometheus.HistogramVec\n}\n\nfunc GetMonitor() *Monitor {\n\tonce.Do(initMonitor)\n\treturn monitor\n}\n\nfunc (m *Monitor) Middleware(ctx *gin.Context) {\n\tif ctx.Request.URL.Path == MetricsPath {\n\t\tctx.Next()\n\t\treturn\n\t}\n\tstartTime := time.Now()\n\n\t// execute normal process.\n\tctx.Next()\n\n\t// after request\n\tr := ctx.Request\n\tcode := strconv.Itoa(ctx.Writer.Status())\n\tstatus := ctx.GetString(ResponseStatusKey)\n\n\t// set request total\n\tm.RequestTotal.WithLabelValues(ctx.FullPath(), r.Method, code, status).Inc()\n\n\t// set request duration\n\tlatency := time.Since(startTime)\n\tm.RequestDuration.WithLabelValues(ctx.FullPath(), r.Method, code, status).Observe(latency.Seconds())\n\n}\n\nfunc initMonitor() {\n\tmonitor = &Monitor{}\n\n\tmonitor.RequestTotal = prometheus.NewCounterVec(\n\t\tprometheus.CounterOpts{\n\t\t\tName: \"http_request_total\",\n\t\t\tHelp: \"all the server received request num.\",\n\t\t},\n\t\t[]string{\"uri\", \"method\", \"code\", \"status\"})\n\tprometheus.MustRegister(monitor.RequestTotal)\n\n\tmonitor.RequestDuration = prometheus.NewHistogramVec(\n\t\tprometheus.HistogramOpts{\n\t\t\tName:    \"http_request_duration_seconds\",\n\t\t\tHelp:    \"the time server took to handle the request.\",\n\t\t\tBuckets: defaultDuration,\n\t\t},\n\t\t[]string{\"uri\", \"method\", \"code\", \"status\"})\n\tprometheus.MustRegister(monitor.RequestDuration)\n}\n"
  },
  {
    "path": "pkg/util/ranger/types.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.  // You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ranger\n\ntype Range struct {\n}\n"
  },
  {
    "path": "pkg/util/sliceutil/slice_util.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage sliceutil\n\nimport (\n\t\"cmp\"\n\t\"fmt\"\n\t\"iter\"\n\t\"maps\"\n\t\"slices\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// SliceDeDup removes duplicate elements from a slice.\nfunc SliceDeDup[S ~[]E, E cmp.Ordered](s S) S {\n\tnewS := slices.Clone(s)\n\tslices.Sort(newS)\n\treturn slices.Compact(newS)\n}\n\n// AllOf returns true if all elements in slice satisfy the predicate function.\nfunc AllOf[S ~[]E, E any](slice S, predicate func(E) bool) bool {\n\tfor _, element := range slice {\n\t\tif !predicate(element) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// Filter returns a new slice containing only elements that satisfy the predicate function.\n// Returns nil if the input slice is empty.\nfunc Filter[T any](slice []T, predicate func(T) bool) []T {\n\tif len(slice) == 0 {\n\t\treturn nil\n\t}\n\tvar result []T\n\tfor _, item := range slice {\n\t\tif predicate(item) {\n\t\t\tresult = append(result, item)\n\t\t}\n\t}\n\treturn result\n}\n\n// Contains reports whether all elements in sub are present in super.\nfunc ContainsAll[S ~[]E, E comparable](super S, sub S) bool {\n\treturn AllOf(sub, func(element E) bool {\n\t\treturn slices.Contains(super, element)\n\t})\n}\n\n// Subtraction returns a new slice containing elements in a that are not present in b.\nfunc Subtraction[S ~[]E, E comparable](a S, b S) S {\n\treturn Filter(a, func(element E) bool {\n\t\treturn !slices.Contains(b, element)\n\t})\n}\n\n// Exclude returns a new slice containing elements in set that are not equal to excludeElement.\nfunc Exclude[S ~[]E, E comparable](set S, excludeElement E) S {\n\treturn Filter(set, func(element E) bool {\n\t\treturn element != excludeElement\n\t})\n}\n\n// Take returns a new slice containing elements from slice where the corresponding element in predicate is true.\n// Please ensure len(slice) <= len(predicate) before calling this function.\nfunc Take[T any](slice []T, predicate []bool) []T {\n\tvar result []T\n\tfor i, item := range slice {\n\t\tif predicate[i] {\n\t\t\tresult = append(result, item)\n\t\t}\n\t}\n\treturn result\n}\n\n// InplaceTake modifies the slice in place to contain only elements where the corresponding element in predicate is true.\n// Please ensure len(slice) <= len(predicate) before calling this function.\nfunc InplaceTake[T any](slice []T, predicate []bool) []T {\n\tnewIndex := 0\n\tfor oldIndex := range slice {\n\t\tif predicate[oldIndex] {\n\t\t\tslice[newIndex] = slice[oldIndex]\n\t\t\tnewIndex++\n\t\t}\n\t}\n\tclear(slice[newIndex:])\n\treturn slice[:newIndex]\n}\n\n// SortMapKeyForDeterminism returns a slice of keys from a map in sorted order.\nfunc SortMapKeyForDeterminism[k cmp.Ordered, v any](m map[k]v) []k {\n\tkeys := maps.Keys(m)\n\treturn slices.Sorted(keys)\n}\n\n// SortedMap returns an iterator that yields key-value pairs from a map in sorted key order\nfunc SortedMap[k cmp.Ordered, v any](m map[k]v) iter.Seq2[k, v] {\n\treturn func(yield func(k, v) bool) {\n\t\tkeys := SortMapKeyForDeterminism(m)\n\t\tfor _, key := range keys {\n\t\t\tif !yield(key, m[key]) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ValueSortedByMapKey returns an iterator that yields values from a map in sorted key order.\nfunc ValueSortedByMapKey[k cmp.Ordered, v any](m map[k]v) iter.Seq[v] {\n\treturn func(yield func(v) bool) {\n\t\tkeys := SortMapKeyForDeterminism(m)\n\t\tfor _, key := range keys {\n\t\t\tif !yield(m[key]) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc CollectMapValues[K comparable, V any](m map[K]V) []V {\n\tvalues := make([]V, 0, len(m))\n\tfor _, value := range m {\n\t\tvalues = append(values, value)\n\t}\n\treturn values\n}\n\nfunc Intersection[S ~[]E, E comparable](a S, b S) S {\n\tvar result []E\n\tfor _, element := range a {\n\t\tif slices.Contains(b, element) {\n\t\t\tresult = append(result, element)\n\t\t}\n\t}\n\treturn result\n}\n\nfunc MergeSlices[T any](slices ...[]T) []T {\n\tvar merged []T\n\tfor _, slice := range slices {\n\t\tmerged = append(merged, slice...)\n\t}\n\treturn merged\n}\n\nfunc MergeMaps[K comparable, V any](map1, map2 map[K]V) map[K]V {\n\tresult := make(map[K]V)\n\tfor k, v := range map1 {\n\t\tresult[k] = v\n\t}\n\tfor k, v := range map2 {\n\t\tresult[k] = v\n\t}\n\treturn result\n}\n\nfunc JoinStringers[T fmt.Stringer](elements []T, sep string) string {\n\tstringValues := make([]string, len(elements))\n\tfor i, elem := range elements {\n\t\tstringValues[i] = elem.String()\n\t}\n\treturn strings.Join(stringValues, sep)\n}\n\nfunc TakeByIndices[T any](slice []T, indices []int) ([]T, error) {\n\tvar result []T\n\tfor _, index := range indices {\n\t\tif index < 0 || index >= len(slice) {\n\t\t\treturn nil, fmt.Errorf(\"index %d is out of range\", index)\n\t\t}\n\t\tresult = append(result, slice[index])\n\t}\n\treturn result, nil\n}\n\nfunc ArgSort[T any](slice []T, less func(a, b T) bool) []int {\n\tindexes := make([]int, len(slice))\n\tfor i := range indexes {\n\t\tindexes[i] = i\n\t}\n\tsort.Slice(indexes, func(i, j int) bool {\n\t\treturn less(slice[indexes[i]], slice[indexes[j]])\n\t})\n\treturn indexes\n}\n\nfunc UnOrderedSliceEqual[S ~[]E, E cmp.Ordered](s1, s2 S) bool {\n\tslices.Sort(s1)\n\tslices.Sort(s2)\n\treturn slices.Equal(s1, s2)\n}\n"
  },
  {
    "path": "pkg/util/sliceutil/slice_util_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage sliceutil\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSliceDeDup(t *testing.T) {\n\tr := require.New(t)\n\tr.Equal([]string{\"a\", \"b\"}, SliceDeDup([]string{\"a\", \"b\", \"a\", \"b\", \"b\"}))\n\tr.Equal([]int{1, 2, 3}, SliceDeDup([]int{1, 2, 1, 2, 2, 1, 3}))\n\tr.Equal([]float64{0.1, 0.2}, SliceDeDup([]float64{0.1, 0.2, 0.1}))\n}\n\nfunc TestAllOf(t *testing.T) {\n\tr := require.New(t)\n\n\t// Test with integers\n\tintSlice := []int{2, 4, 6, 8, 10}\n\tr.True(AllOf(intSlice, func(n int) bool { return n%2 == 0 }))\n\tr.False(AllOf(intSlice, func(n int) bool { return n > 5 }))\n\n\t// Test with strings\n\tstrSlice := []string{\"hello\", \"world\", \"hello\"}\n\tr.True(AllOf(strSlice, func(s string) bool { return len(s) > 0 }))\n\tr.False(AllOf(strSlice, func(s string) bool { return s == \"hello\" }))\n\n\t// Test with empty slice\n\temptySlice := []int{}\n\tr.True(AllOf(emptySlice, func(n int) bool { return n > 0 }))\n}\n\nfunc TestFilter(t *testing.T) {\n\tr := require.New(t)\n\n\t// Test with integers\n\tintSlice := []int{1, 2, 3, 4, 5, 6}\n\tevenNums := Filter(intSlice, func(n int) bool { return n%2 == 0 })\n\tr.Equal([]int{2, 4, 6}, evenNums)\n\n\t// Test with strings\n\tstrSlice := []string{\"hello\", \"world\", \"golang\"}\n\tlongStrs := Filter(strSlice, func(s string) bool { return len(s) > 5 })\n\tr.Equal([]string{\"golang\"}, longStrs)\n\n\t// Test with empty slice\n\temptySlice := []int{}\n\tr.Nil(Filter(emptySlice, func(n int) bool { return n > 0 }))\n}\n\nfunc TestContainsAll(t *testing.T) {\n\tr := require.New(t)\n\t// Test string slices\n\tr.True(ContainsAll([]string{\"a\", \"b\", \"c\"}, []string{\"a\", \"b\", \"c\"}))       // Equal sets\n\tr.True(ContainsAll([]string{\"a\", \"b\", \"c\"}, []string{\"a\", \"c\"}))            // Proper subset\n\tr.True(ContainsAll([]string{\"a\", \"b\", \"c\"}, []string{\"a\", \"a\", \"c\"}))       // Subset with duplicates\n\tr.False(ContainsAll([]string{\"a\", \"b\", \"c\"}, []string{\"a\", \"a\", \"c\", \"d\"})) // Not a subset\n\tr.False(ContainsAll([]string{}, []string{\"a\", \"a\", \"c\", \"d\"}))              // Empty super set\n\tr.True(ContainsAll([]string{\"a\", \"b\", \"c\"}, []string{}))                    // Empty subset\n\n\t// Test int slices\n\tr.True(ContainsAll([]int{1, 2, 3}, []int{1, 2, 3}))    // Equal sets\n\tr.True(ContainsAll([]int{1, 2, 3}, []int{1, 2, 3, 3})) // Subset with duplicates\n\tr.False(ContainsAll([]int{1, 2}, []int{1, 2, 3, 3}))   // Not a subset\n\tr.False(ContainsAll([]int{}, []int{1, 2, 3, 3}))       // Empty super set\n\tr.True(ContainsAll([]int{1, 2, 3}, []int{}))           // Empty subset\n\tr.True(ContainsAll([]int{}, []int{}))                  // Both empty\n}\n\nfunc TestSubtraction(t *testing.T) {\n\tr := require.New(t)\n\t// Test subtraction of int slices\n\ta := []int{1, 2, 3, 4, 5}\n\tb := []int{2, 4}\n\tr.Equal([]int{1, 3, 5}, Subtraction(a, b))\n\n\t// Test subtraction of string slices\n\tc := []string{\"a\", \"b\", \"c\"}\n\td := []string{\"a\", \"d\"}\n\tr.Equal([]string{\"b\", \"c\"}, Subtraction(c, d))\n}\n\nfunc TestExclude(t *testing.T) {\n\tr := require.New(t)\n\n\t// Test with integers\n\tintSlice := []int{1, 2, 3, 4, 5}\n\tr.Equal([]int{1, 2, 4, 5}, Exclude(intSlice, 3))\n\n\t// Test with strings\n\tstrSlice := []string{\"a\", \"b\", \"c\", \"d\"}\n\tr.Equal([]string{\"a\", \"b\", \"d\"}, Exclude(strSlice, \"c\"))\n\n\t// Test with empty slice\n\temptySlice := []int{}\n\tr.Empty(Exclude(emptySlice, 1))\n}\n\nfunc TestTake(t *testing.T) {\n\tr := require.New(t)\n\n\tslice := []int{1, 2, 3, 4, 5}\n\tpredicate := []bool{true, false, true, false, true}\n\n\tresult := Take(slice, predicate)\n\tr.Equal([]int{1, 3, 5}, result)\n\n\t// Test with empty slice\n\temptySlice := []int{}\n\temptyPredicate := []bool{}\n\tr.Empty(Take(emptySlice, emptyPredicate))\n}\n\nfunc TestInplaceTake(t *testing.T) {\n\tr := require.New(t)\n\n\tslice := []int{1, 2, 3, 4, 5}\n\tpredicate := []bool{true, false, true, false, true}\n\n\tresult := InplaceTake(slice, predicate)\n\tr.Equal([]int{1, 3, 5}, result)\n\n\t// Test with empty slice\n\temptySlice := []int{}\n\temptyPredicate := []bool{}\n\tr.Empty(InplaceTake(emptySlice, emptyPredicate))\n}\n\nfunc TestSortMapKeyForDeterminism(t *testing.T) {\n\tr := require.New(t)\n\n\tm := map[string]int{\n\t\t\"c\": 3,\n\t\t\"a\": 1,\n\t\t\"b\": 2,\n\t}\n\n\tkeys := SortMapKeyForDeterminism(m)\n\tr.Equal([]string{\"a\", \"b\", \"c\"}, keys)\n\n\t// Test with empty map\n\temptyMap := map[string]int{}\n\tr.Empty(SortMapKeyForDeterminism(emptyMap))\n}\n\nfunc TestSortedMap(t *testing.T) {\n\tr := require.New(t)\n\n\tm := map[string]int{\n\t\t\"c\": 3,\n\t\t\"a\": 1,\n\t\t\"b\": 2,\n\t}\n\n\tvar pairs []struct {\n\t\tkey   string\n\t\tvalue int\n\t}\n\n\tfor k, v := range SortedMap(m) {\n\t\tpairs = append(pairs, struct {\n\t\t\tkey   string\n\t\t\tvalue int\n\t\t}{k, v})\n\t}\n\n\tr.Equal([]struct {\n\t\tkey   string\n\t\tvalue int\n\t}{\n\t\t{\"a\", 1},\n\t\t{\"b\", 2},\n\t\t{\"c\", 3},\n\t}, pairs)\n}\n\nfunc TestValueSortedByMapKey(t *testing.T) {\n\tr := require.New(t)\n\n\tm := map[string]int{\n\t\t\"c\": 3,\n\t\t\"a\": 1,\n\t\t\"b\": 2,\n\t}\n\n\tvar values []int\n\tfor v := range ValueSortedByMapKey(m) {\n\t\tvalues = append(values, v)\n\t}\n\n\tr.Equal([]int{1, 2, 3}, values)\n}\n\nfunc TestUnorderedSlicesEqual(t *testing.T) {\n\tr := require.New(t)\n\n\t// dedup\n\ts1 := []string{\"a\", \"b\", \"c\"}\n\ts2 := []string{\"b\", \"a\", \"c\"}\n\tr.Equal(true, UnOrderedSliceEqual(s1, s2))\n\n\t// dup\n\ts1 = []string{\"a\", \"b\", \"c\"}\n\ts2 = []string{\"b\", \"a\", \"c\", \"c\"}\n\tr.Equal(false, UnOrderedSliceEqual(s1, s2))\n\n\ts1 = []string{\"c\", \"a\", \"b\", \"c\"}\n\ts2 = []string{\"b\", \"a\", \"c\", \"c\"}\n\tr.Equal(true, UnOrderedSliceEqual(s1, s2))\n\n\t// empty\n\ts1 = []string{}\n\ts2 = []string{}\n\tr.Equal(true, UnOrderedSliceEqual(s1, s2))\n}\n"
  },
  {
    "path": "pkg/util/sqlbuilder/sqlbuilder.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage sqlbuilder\n\nimport (\n\t\"crypto\"\n\t\"crypto/ed25519\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tjfoc/gmsm/sm2\"\n\n\t\"github.com/secretflow/scql/pkg/util/keyutil\"\n)\n\ntype AuthMethod int\n\nconst (\n\tauthMethodNone AuthMethod = iota\n\tauthMethodToken\n\tauthMethodPubkey\n)\n\ntype CreateUserStmtBuilder struct {\n\tifNotExists bool\n\tuserName    string\n\tpasswd      string\n\tpartyCode   string\n\tauthMethod  AuthMethod\n\ttoken       string\n\ttp          time.Time\n\tprivKey     any\n\tendpoints   []string\n\terr         error\n}\n\nfunc NewCreateUserStmtBuilder() *CreateUserStmtBuilder {\n\treturn &CreateUserStmtBuilder{\n\t\tifNotExists: false,\n\t\tauthMethod:  authMethodNone,\n\t\ttp:          time.Now(),\n\t}\n}\n\nfunc (b *CreateUserStmtBuilder) SetUser(user string) *CreateUserStmtBuilder {\n\tb.userName = user\n\treturn b\n}\n\nfunc (b *CreateUserStmtBuilder) SetPassword(passwd string) *CreateUserStmtBuilder {\n\tb.passwd = passwd\n\treturn b\n}\n\nfunc (b *CreateUserStmtBuilder) SetParty(partyCode string) *CreateUserStmtBuilder {\n\tb.partyCode = partyCode\n\treturn b\n}\n\nfunc (b *CreateUserStmtBuilder) WithEndpoinits(endpoints []string) *CreateUserStmtBuilder {\n\tb.endpoints = append([]string{}, endpoints...)\n\treturn b\n}\n\nfunc (b *CreateUserStmtBuilder) IfNotExists() *CreateUserStmtBuilder {\n\tb.ifNotExists = true\n\treturn b\n}\n\nfunc (b *CreateUserStmtBuilder) AuthByToken(token string) *CreateUserStmtBuilder {\n\tb.authMethod = authMethodToken\n\tb.token = token\n\treturn b\n}\n\nfunc (b *CreateUserStmtBuilder) AuthByPubkeyWithPemFile(pemPath string) *CreateUserStmtBuilder {\n\tb.authMethod = authMethodPubkey\n\tb.privKey, b.err = keyutil.LoadPrivateKeyFromPemFile(pemPath)\n\treturn b\n}\n\nfunc (b *CreateUserStmtBuilder) AuthByPubkeyWithPrivateKey(key any) *CreateUserStmtBuilder {\n\tb.authMethod = authMethodPubkey\n\tb.privKey = key\n\treturn b\n}\n\n// only for test purpose\nfunc (b *CreateUserStmtBuilder) MockTime(t time.Time) *CreateUserStmtBuilder {\n\tb.tp = t\n\treturn b\n}\n\nfunc (b *CreateUserStmtBuilder) ToSQL() (string, error) {\n\tif b.err != nil {\n\t\treturn \"\", b.err\n\t}\n\tvar sb strings.Builder\n\tsb.WriteString(\"CREATE USER \")\n\tif b.ifNotExists {\n\t\tsb.WriteString(\"IF NOT EXISTS \")\n\t}\n\n\tif len(b.userName) == 0 {\n\t\treturn \"\", errors.New(\"user name is empty\")\n\t}\n\tsb.WriteString(fmt.Sprintf(\"`%s` \", b.userName))\n\n\tif len(b.partyCode) == 0 {\n\t\treturn \"\", errors.New(\"party code is empty\")\n\t}\n\tsb.WriteString(fmt.Sprintf(\"PARTY_CODE '%s' \", b.partyCode))\n\n\tif len(b.passwd) == 0 {\n\t\treturn \"\", errors.New(\"password is empty\")\n\t}\n\tsb.WriteString(fmt.Sprintf(\"IDENTIFIED BY '%s'\", b.passwd))\n\n\tif b.authMethod == authMethodNone && len(b.endpoints) == 0 {\n\t\treturn sb.String(), nil\n\t}\n\n\tsb.WriteString(\" WITH\")\n\tif b.authMethod == authMethodToken {\n\t\tif len(b.token) == 0 {\n\t\t\treturn \"\", errors.New(\"token is empty while auth by TOKEN\")\n\t\t}\n\t\tsb.WriteString(fmt.Sprintf(\" TOKEN '%s'\", b.token))\n\t} else if b.authMethod == authMethodPubkey {\n\t\tmsg, err := b.tp.MarshalText()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tsig, err := signMessage(b.privKey, msg)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tpub, err := keyutil.GetPublicKeyInDER(b.privKey)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tsb.WriteString(fmt.Sprintf(\" '%s' '%s' '%s'\", string(msg), sig, base64.StdEncoding.EncodeToString(pub)))\n\t}\n\n\tif len(b.endpoints) > 0 {\n\t\tsb.WriteString(\" ENDPOINT \")\n\t\tfor i, endpoint := range b.endpoints {\n\t\t\tif i > 0 {\n\t\t\t\tsb.WriteString(\",\")\n\t\t\t}\n\t\t\tsb.WriteString(fmt.Sprintf(\"'%s'\", endpoint))\n\t\t}\n\t}\n\treturn sb.String(), nil\n}\n\nfunc signMessage(key any, msg []byte) (string, error) {\n\tvar sig []byte\n\tvar err error\n\tswitch priv := key.(type) {\n\tcase ed25519.PrivateKey:\n\t\tsig = ed25519.Sign(priv, msg)\n\tcase *rsa.PrivateKey:\n\t\tmsgHashSum := sha256.Sum256(msg)\n\t\tsig, err = rsa.SignPSS(rand.Reader, priv, crypto.SHA256, msgHashSum[:], nil)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\tcase *sm2.PrivateKey:\n\t\tsig, err = priv.Sign(rand.Reader, msg, nil)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\tdefault:\n\t\treturn \"\", errors.New(\"unsupported type of private key\")\n\t}\n\n\treturn base64.StdEncoding.EncodeToString(sig), nil\n}\n"
  },
  {
    "path": "pkg/util/sqlbuilder/sqlbuilder_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage sqlbuilder\n\nimport (\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBuildCreateUserStmtWithoutAuth(t *testing.T) {\n\tr := require.New(t)\n\n\texpectSql := \"CREATE USER `alice` PARTY_CODE 'ALICE' IDENTIFIED BY 'some_passwd'\"\n\tbuilder := NewCreateUserStmtBuilder()\n\tsql, err := builder.SetUser(\"alice\").SetParty(\"ALICE\").SetPassword(\"some_passwd\").ToSQL()\n\tr.NoError(err)\n\tr.Equal(expectSql, sql)\n}\n\nfunc TestBuildCreateUserStmtWithEndpoints(t *testing.T) {\n\tr := require.New(t)\n\n\texpectSql := \"CREATE USER `alice` PARTY_CODE 'ALICE' IDENTIFIED BY 'some_passwd' WITH ENDPOINT 'addr1:port1','addr2:port2'\"\n\tbuilder := NewCreateUserStmtBuilder()\n\tsql, err := builder.SetUser(\"alice\").SetParty(\"ALICE\").SetPassword(\"some_passwd\").WithEndpoinits([]string{\"addr1:port1\", \"addr2:port2\"}).ToSQL()\n\tr.NoError(err)\n\tr.Equal(expectSql, sql)\n}\n\nfunc TestBuildCreateUserStmtWithTokenAndEndpoint(t *testing.T) {\n\tr := require.New(t)\n\n\texpectSql := \"CREATE USER `alice` PARTY_CODE 'ALICE' IDENTIFIED BY 'some_passwd' WITH TOKEN 'xxxx' ENDPOINT 'addr1:port1'\"\n\tbuilder := NewCreateUserStmtBuilder()\n\tsql, err := builder.SetUser(\"alice\").SetParty(\"ALICE\").SetPassword(\"some_passwd\").AuthByToken(\"xxxx\").WithEndpoinits([]string{\"addr1:port1\"}).ToSQL()\n\tr.NoError(err)\n\tr.Equal(expectSql, sql)\n}\n\nfunc TestBuildCreateUserStmtWithPubkeyAuth(t *testing.T) {\n\tr := require.New(t)\n\n\texpectSql := \"CREATE USER `alice` PARTY_CODE 'ALICE' IDENTIFIED BY 'some_passwd' WITH '2023-08-18T18:12:04.00507585+08:00' 'FKNla5+qiybxx0Tx5gGpn5bHX1+0NgKJPNshq1eCT00/Pogu3QAPXJneUdtYQlmaf7dW1Vr25t+oDLRV9+TiCA==' 'MCowBQYDK2VwAyEA8tjoIkf3mIyz/HGdjBD+p/SDxlzHiNDcaTmhF3dHjZY='\"\n\tmockTime, err := time.Parse(time.RFC3339Nano, \"2023-08-18T18:12:04.00507585+08:00\")\n\tr.NoError(err)\n\n\tprivPemData := []byte(`\n-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIBSXcCv5G1YpIZSD127ImyGnlqA9s9HCpk7jYbl7OQZ5\n-----END PRIVATE KEY-----\n`)\n\tblock, _ := pem.Decode(privPemData)\n\tr.True(block != nil && block.Type == \"PRIVATE KEY\")\n\n\tpriv, err := x509.ParsePKCS8PrivateKey(block.Bytes)\n\tr.NoError(err)\n\n\tbuilder := NewCreateUserStmtBuilder()\n\tsql, err := builder.SetUser(\"alice\").SetParty(\"ALICE\").SetPassword(\"some_passwd\").AuthByPubkeyWithPrivateKey(priv).MockTime(mockTime).ToSQL()\n\n\tr.NoError(err)\n\tr.Equal(expectSql, sql)\n}\n"
  },
  {
    "path": "pkg/util/stringutil/string_util.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage stringutil\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode/utf8\"\n\n\t\"golang.org/x/exp/rand\"\n\n\t\"github.com/pingcap/errors\"\n\n\t\"github.com/secretflow/scql/pkg/util/hack\"\n)\n\n// ErrSyntax indicates that a value does not have the right syntax for the target type.\nvar ErrSyntax = errors.New(\"invalid syntax\")\n\n// UnquoteChar decodes the first character or byte in the escaped string\n// or character literal represented by the string s.\n// It returns four values:\n//\n// 1) value, the decoded Unicode code point or byte value;\n// 2) multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation;\n// 3) tail, the remainder of the string after the character; and\n// 4) an error that will be nil if the character is syntactically valid.\n//\n// The second argument, quote, specifies the type of literal being parsed\n// and therefore which escaped quote character is permitted.\n// If set to a single quote, it permits the sequence \\' and disallows unescaped '.\n// If set to a double quote, it permits \\\" and disallows unescaped \".\n// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped.\n// Different with strconv.UnquoteChar, it permits unnecessary backslash.\nfunc UnquoteChar(s string, quote byte) (value []byte, tail string, err error) {\n\t// easy cases\n\tswitch c := s[0]; {\n\tcase c == quote:\n\t\terr = errors.Trace(ErrSyntax)\n\t\treturn\n\tcase c >= utf8.RuneSelf:\n\t\tr, size := utf8.DecodeRuneInString(s)\n\t\tif r == utf8.RuneError {\n\t\t\tvalue = append(value, c)\n\t\t\treturn value, s[1:], nil\n\t\t}\n\t\tvalue = append(value, string(r)...)\n\t\treturn value, s[size:], nil\n\tcase c != '\\\\':\n\t\tvalue = append(value, c)\n\t\treturn value, s[1:], nil\n\t}\n\t// hard case: c is backslash\n\tif len(s) <= 1 {\n\t\terr = errors.Trace(ErrSyntax)\n\t\treturn\n\t}\n\tc := s[1]\n\ts = s[2:]\n\tswitch c {\n\tcase 'b':\n\t\tvalue = append(value, '\\b')\n\tcase 'n':\n\t\tvalue = append(value, '\\n')\n\tcase 'r':\n\t\tvalue = append(value, '\\r')\n\tcase 't':\n\t\tvalue = append(value, '\\t')\n\tcase 'Z':\n\t\tvalue = append(value, '\\032')\n\tcase '0':\n\t\tvalue = append(value, '\\000')\n\tcase '_', '%':\n\t\tvalue = append(value, '\\\\')\n\t\tvalue = append(value, c)\n\tcase '\\\\':\n\t\tvalue = append(value, '\\\\')\n\tcase '\\'', '\"':\n\t\tvalue = append(value, c)\n\tdefault:\n\t\tvalue = append(value, c)\n\t}\n\ttail = s\n\treturn\n}\n\n// Unquote interprets s as a single-quoted, double-quoted,\n// or backquoted Go string literal, returning the string value\n// that s quotes. For example: test=`\"\\\"\\n\"` (hex: 22 5c 22 5c 6e 22)\n// should be converted to `\"\\n` (hex: 22 0a).\nfunc Unquote(s string) (t string, err error) {\n\tn := len(s)\n\tif n < 2 {\n\t\treturn \"\", errors.Trace(ErrSyntax)\n\t}\n\tquote := s[0]\n\tif quote != s[n-1] {\n\t\treturn \"\", errors.Trace(ErrSyntax)\n\t}\n\ts = s[1 : n-1]\n\tif quote != '\"' && quote != '\\'' {\n\t\treturn \"\", errors.Trace(ErrSyntax)\n\t}\n\t// Avoid allocation. No need to convert if there is no '\\'\n\tif strings.IndexByte(s, '\\\\') == -1 && strings.IndexByte(s, quote) == -1 {\n\t\treturn s, nil\n\t}\n\tbuf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.\n\tfor len(s) > 0 {\n\t\tmb, ss, err := UnquoteChar(s, quote)\n\t\tif err != nil {\n\t\t\treturn \"\", errors.Trace(err)\n\t\t}\n\t\ts = ss\n\t\tbuf = append(buf, mb...)\n\t}\n\treturn string(buf), nil\n}\n\nconst (\n\tpatMatch = iota + 1\n\tpatOne\n\tpatAny\n)\n\n// CompilePattern handles escapes and wild cards convert pattern characters and\n// pattern types.\nfunc CompilePattern(pattern string, escape byte) (patChars, patTypes []byte) {\n\tvar lastAny bool\n\tpatChars = make([]byte, len(pattern))\n\tpatTypes = make([]byte, len(pattern))\n\tpatLen := 0\n\tfor i := 0; i < len(pattern); i++ {\n\t\tvar tp byte\n\t\tvar c = pattern[i]\n\t\tswitch c {\n\t\tcase escape:\n\t\t\tlastAny = false\n\t\t\ttp = patMatch\n\t\t\tif i < len(pattern)-1 {\n\t\t\t\ti++\n\t\t\t\tc = pattern[i]\n\t\t\t\tif c == escape || c == '_' || c == '%' {\n\t\t\t\t\t// Valid escape.\n\t\t\t\t} else {\n\t\t\t\t\t// Invalid escape, fall back to escape byte.\n\t\t\t\t\t// mysql will treat escape character as the origin value even\n\t\t\t\t\t// the escape sequence is invalid in Go or C.\n\t\t\t\t\t// e.g., \\m is invalid in Go, but in MySQL we will get \"m\" for select '\\m'.\n\t\t\t\t\t// Following case is correct just for escape \\, not for others like +.\n\t\t\t\t\t// TODO: Add more checks for other escapes.\n\t\t\t\t\ti--\n\t\t\t\t\tc = escape\n\t\t\t\t}\n\t\t\t}\n\t\tcase '_':\n\t\t\tif lastAny {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttp = patOne\n\t\tcase '%':\n\t\t\tif lastAny {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlastAny = true\n\t\t\ttp = patAny\n\t\tdefault:\n\t\t\tlastAny = false\n\t\t\ttp = patMatch\n\t\t}\n\t\tpatChars[patLen] = c\n\t\tpatTypes[patLen] = tp\n\t\tpatLen++\n\t}\n\tpatChars = patChars[:patLen]\n\tpatTypes = patTypes[:patLen]\n\treturn\n}\n\n// NOTE: Currently tikv's like function is case sensitive, so we keep its behavior here.\nfunc matchByteCI(a, b byte) bool {\n\treturn a == b\n\t// We may reuse below code block when like function go back to case insensitive.\n\t/*\n\t\tif a == b {\n\t\t\treturn true\n\t\t}\n\t\tif a >= 'a' && a <= 'z' && a-caseDiff == b {\n\t\t\treturn true\n\t\t}\n\t\treturn a >= 'A' && a <= 'Z' && a+caseDiff == b\n\t*/\n}\n\n// CompileLike2Regexp convert a like `lhs` to a regular expression\nfunc CompileLike2Regexp(str string) string {\n\tpatChars, patTypes := CompilePattern(str, '\\\\')\n\tvar result []byte\n\tfor i := 0; i < len(patChars); i++ {\n\t\tswitch patTypes[i] {\n\t\tcase patMatch:\n\t\t\tresult = append(result, patChars[i])\n\t\tcase patOne:\n\t\t\t// .*. == .*\n\t\t\tif !bytes.HasSuffix(result, []byte{'.', '*'}) {\n\t\t\t\tresult = append(result, '.')\n\t\t\t}\n\t\tcase patAny:\n\t\t\t// ..* == .*\n\t\t\tif bytes.HasSuffix(result, []byte{'.'}) {\n\t\t\t\tresult = append(result, '*')\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// .*.* == .*\n\t\t\tif !bytes.HasSuffix(result, []byte{'.', '*'}) {\n\t\t\t\tresult = append(result, '.')\n\t\t\t\tresult = append(result, '*')\n\t\t\t}\n\t\t}\n\t}\n\treturn string(result)\n}\n\n// DoMatch matches the string with patChars and patTypes.\n// The algorithm has linear time complexity.\n// https://research.swtch.com/glob\nfunc DoMatch(str string, patChars, patTypes []byte) bool {\n\tvar sIdx, pIdx, nextSIdx, nextPIdx int\n\tfor pIdx < len(patChars) || sIdx < len(str) {\n\t\tif pIdx < len(patChars) {\n\t\t\tswitch patTypes[pIdx] {\n\t\t\tcase patMatch:\n\t\t\t\tif sIdx < len(str) && matchByteCI(str[sIdx], patChars[pIdx]) {\n\t\t\t\t\tpIdx++\n\t\t\t\t\tsIdx++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\tcase patOne:\n\t\t\t\tif sIdx < len(str) {\n\t\t\t\t\tpIdx++\n\t\t\t\t\tsIdx++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\tcase patAny:\n\t\t\t\t// Try to match at sIdx.\n\t\t\t\t// If that doesn't work out,\n\t\t\t\t// restart at sIdx+1 next.\n\t\t\t\tnextPIdx = pIdx\n\t\t\t\tnextSIdx = sIdx + 1\n\t\t\t\tpIdx++\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\t// Mismatch. Maybe restart.\n\t\tif 0 < nextSIdx && nextSIdx <= len(str) {\n\t\t\tpIdx = nextPIdx\n\t\t\tsIdx = nextSIdx\n\t\t\tcontinue\n\t\t}\n\t\treturn false\n\t}\n\t// Matched all of pattern to all of name. Success.\n\treturn true\n}\n\n// IsExactMatch return true if no wildcard character\nfunc IsExactMatch(patTypes []byte) bool {\n\tfor _, pt := range patTypes {\n\t\tif pt != patMatch {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// Copy deep copies a string.\nfunc Copy(src string) string {\n\treturn string(hack.Slice(src))\n}\n\n// StringerFunc defines string func implement fmt.Stringer.\ntype StringerFunc func() string\n\n// String implements fmt.Stringer\nfunc (l StringerFunc) String() string {\n\treturn l()\n}\n\n// MemoizeStr returns memoized version of stringFunc.\nfunc MemoizeStr(l func() string) fmt.Stringer {\n\treturn StringerFunc(func() string {\n\t\treturn l()\n\t})\n}\n\n// StringerStr defines a alias to normal string.\n// implement fmt.Stringer\ntype StringerStr string\n\n// String implements fmt.Stringer\nfunc (i StringerStr) String() string {\n\treturn string(i)\n}\n\nfunc RemoveSensitiveInfo(sqlStr string) string {\n\texp := regexp.MustCompile(`(?i)\\s+IDENTIFIED\\s+`)\n\tif match := exp.FindStringIndex(sqlStr); match != nil {\n\t\treturn sqlStr[:match[1]] + \"***\"\n\t}\n\treturn sqlStr\n}\n\nfunc RandString(n int) string {\n\tvar letters = []rune(\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\")\n\n\trand.Seed(uint64(time.Now().UnixNano()))\n\tb := make([]rune, n)\n\tfor i := range b {\n\t\tb[i] = letters[rand.Intn(len(letters))]\n\t}\n\treturn string(b)\n}\n\nfunc IsDateString(s string) bool {\n\tmatched, _ := regexp.MatchString(`^\\d{4}-\\d{2}-\\d{2}(\\s\\d{2}:\\d{2}:\\d{2})?$`, s)\n\treturn matched\n}\n\nfunc StringToUnixSec(s string) (int64, error) {\n\tvar t time.Time\n\tvar err error\n\n\tif len(s) == len(\"2006-01-02 15:04:05\") {\n\t\tt, err = time.Parse(\"2006-01-02 15:04:05\", s)\n\t\tif err == nil {\n\t\t\treturn t.Unix(), nil\n\t\t}\n\t}\n\n\tif len(s) == len(\"2006-01-02\") {\n\t\tt, err = time.Parse(\"2006-01-02\", s)\n\t\tif err == nil {\n\t\t\treturn t.Unix(), nil\n\t\t}\n\t}\n\n\treturn 0, fmt.Errorf(\"unsupported datetime format: %s\", s)\n}\n\nfunc StringToUnixSecWithTimezone(s string) (int64, error) {\n\tsupportedLayouts := []string{\n\t\t// e.g., \"2024-10-25T10:00:00+08:00\" or \"2024-10-25T02:00:00Z\"\n\t\ttime.RFC3339,\n\t\t// e.g., \"2024-10-25T10:00:00+0800\"\n\t\t\"2006-01-02T15:04:05Z0700\",\n\t\t// e.g., \"2024-10-25 10:00:00+08:00\"\n\t\t\"2006-01-02 15:04:05Z07:00\",\n\t\t// e.g., \"2024-10-25 10:00:00+0800\"\n\t\t\"2006-01-02 15:04:05Z0700\",\n\t}\n\n\tvar t time.Time\n\tvar err error\n\n\tfor _, layout := range supportedLayouts {\n\t\tt, err = time.Parse(layout, s)\n\t\tif err == nil {\n\t\t\treturn t.Unix(), nil\n\t\t}\n\t}\n\n\treturn 0, fmt.Errorf(\"unsupported timestamp format or missing timezone: %q\", s)\n}\n\nfunc MySQLDateFormatToGoLayout(mysqlFormat string) (string, error) {\n\tvar mapping = map[string]string{\n\t\t\"%Y\": \"2006\",        // Year, four digits\n\t\t\"%y\": \"06\",          // Year, two digits\n\t\t\"%m\": \"01\",          // Month (01–12)\n\t\t\"%c\": \"1\",           // Month (1–12)\n\t\t\"%d\": \"02\",          // Day (01–31)\n\t\t\"%e\": \"2\",           // Day (1–31)\n\t\t\"%H\": \"15\",          // Hour (00–23)\n\t\t\"%k\": \"15\",          // Hour (0–23)\n\t\t\"%h\": \"03\",          // Hour (01–12)\n\t\t\"%I\": \"03\",          // Hour (01–12)\n\t\t\"%l\": \"3\",           // Hour (1–12)\n\t\t\"%i\": \"04\",          // Minute (00–59)\n\t\t\"%S\": \"05\",          // Second (00–59)\n\t\t\"%s\": \"05\",          // Same as %S\n\t\t\"%f\": \"000000\",      // Microsecond\n\t\t\"%p\": \"PM\",          // AM or PM\n\t\t\"%T\": \"15:04:05\",    // Time in 24-hour format\n\t\t\"%r\": \"03:04:05 PM\", // Time in 12-hour format\n\t\t\"%b\": \"Jan\",         // Abbreviated month name\n\t\t\"%M\": \"January\",     // Full month name\n\t\t\"%a\": \"Mon\",         // Abbreviated weekday\n\t\t\"%W\": \"Monday\",      // Full weekday\n\t}\n\n\tvar goLayout strings.Builder\n\trunes := []rune(mysqlFormat)\n\ti := 0\n\tfor i < len(runes) {\n\t\tif runes[i] == '%' {\n\t\t\tif i+1 < len(runes) {\n\t\t\t\tspecifierRune := runes[i+1]\n\t\t\t\t// Handle %% separately\n\t\t\t\tif specifierRune == '%' {\n\t\t\t\t\tgoLayout.WriteRune('%')\n\t\t\t\t\ti += 2\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tspecifier := \"%\" + string(specifierRune)\n\t\t\t\tif layoutPart, ok := mapping[specifier]; ok {\n\t\t\t\t\tgoLayout.WriteString(layoutPart)\n\t\t\t\t} else {\n\t\t\t\t\treturn \"\", fmt.Errorf(\"unsupported MySQL format specifier: %s\", specifier)\n\t\t\t\t}\n\t\t\t\ti += 2\n\t\t\t} else {\n\t\t\t\treturn \"\", fmt.Errorf(\"invalid format string: trailing %%\")\n\t\t\t}\n\t\t} else {\n\t\t\tgoLayout.WriteRune(runes[i])\n\t\t\ti += 1\n\t\t}\n\t}\n\treturn goLayout.String(), nil\n}\n\nvar kMySQLToArrowFormatMapping = map[string]string{\n\t\"%Y\": \"%Y\",          // 4-digit year\n\t\"%y\": \"%y\",          // 2-digit year\n\t\"%m\": \"%m\",          // Month (01-12)\n\t\"%c\": \"%-m\",         // Month (1-12), '%-m' in Arrow is for non-padded month\n\t\"%d\": \"%d\",          // Day (01-31)\n\t\"%e\": \"%-d\",         // Day (1-31), '%-d' in Arrow is for non-padded day\n\t\"%H\": \"%H\",          // Hour (00-23)\n\t\"%k\": \"%-H\",         // Hour (0-23), '%-H' in Arrow is for non-padded hour\n\t\"%h\": \"%I\",          // Hour (01-12), maps to 12-hour format\n\t\"%I\": \"%I\",          // Hour (01-12)\n\t\"%l\": \"%-I\",         // Hour (1-12), '%-I' in Arrow is for non-padded 12-hour\n\t\"%i\": \"%M\",          // MySQL minute -> standard strptime minute (%M)\n\t\"%S\": \"%S\",          // Second (00-59)\n\t\"%s\": \"%S\",          // MySQL second alias -> standard strptime second (%S)\n\t\"%f\": \"%f\",          // Microsecond\n\t\"%p\": \"%p\",          // AM/PM\n\t\"%T\": \"%H:%M:%S\",    // Shortcut: 24-hour time\n\t\"%r\": \"%I:%M:%S %p\", // Shortcut: 12-hour time\n\t\"%b\": \"%b\",          // Abbreviated month name\n\t\"%M\": \"%B\",          // MySQL full month name -> standard strptime full month name (%B)\n\t\"%a\": \"%a\",          // Abbreviated weekday name\n\t\"%W\": \"%A\",          // MySQL full weekday name -> standard strptime full weekday name (%A)\n}\n\nfunc MySQLDateFormatToArrowFormat(mysqlFormat string) (string, error) {\n\tvar result strings.Builder\n\ti := 0\n\tfor i < len(mysqlFormat) {\n\t\tif mysqlFormat[i] == '%' {\n\t\t\t// Check for a dangling '%' at the end of the string.\n\t\t\tif i+1 >= len(mysqlFormat) {\n\t\t\t\treturn \"\", fmt.Errorf(\"invalid format string: trailing %%\")\n\t\t\t}\n\n\t\t\t// Special case '%%', which represents a literal '%' character.\n\t\t\tif mysqlFormat[i+1] == '%' {\n\t\t\t\tresult.WriteByte('%')\n\t\t\t\ti += 2\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Extract the two-character specifier, e.g., \"%Y\".\n\t\t\tspecifier := mysqlFormat[i : i+2]\n\t\t\tarrowSpecifier, ok := kMySQLToArrowFormatMapping[specifier]\n\t\t\tif !ok {\n\t\t\t\treturn \"\", fmt.Errorf(\"unsupported MySQL format specifier: %s\", specifier)\n\t\t\t}\n\n\t\t\tresult.WriteString(arrowSpecifier)\n\t\t\ti += 2\n\t\t} else {\n\t\t\t// Non-'%' characters are treated as literals and appended directly.\n\t\t\tresult.WriteByte(mysqlFormat[i])\n\t\t\ti++\n\t\t}\n\t}\n\treturn result.String(), nil\n}\n"
  },
  {
    "path": "pkg/util/stringutil/string_util_test.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage stringutil\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/secretflow/scql/pkg/util/testleak\"\n)\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nvar _ = Suite(&testStringUtilSuite{})\n\ntype testStringUtilSuite struct {\n}\n\nfunc (s *testStringUtilSuite) TestUnquote(c *C) {\n\tdefer testleak.AfterTest(c)()\n\ttable := []struct {\n\t\tstr    string\n\t\texpect string\n\t\tok     bool\n\t}{\n\t\t{``, ``, false},\n\t\t{`'`, ``, false},\n\t\t{`'abc\"`, ``, false},\n\t\t{`abcdea`, ``, false},\n\t\t{`'abc'def'`, ``, false},\n\t\t{`\"abc\\\"`, ``, false},\n\n\t\t{`\"abcdef\"`, `abcdef`, true},\n\t\t{`\"abc'def\"`, `abc'def`, true},\n\t\t{`\"\\a汉字测试\"`, `a汉字测试`, true},\n\t\t{`\"☺\"`, `☺`, true},\n\t\t{`\"\\xFF\"`, `xFF`, true},\n\t\t{`\"\\U00010111\"`, `U00010111`, true},\n\t\t{`\"\\U0001011111\"`, `U0001011111`, true},\n\t\t{`\"\\a\\b\\f\\n\\r\\t\\v\\\\\\\"\"`, \"a\\bf\\n\\r\\tv\\\\\\\"\", true},\n\t\t{`\"\\Z\\%\\_\"`, \"\\032\" + `\\%\\_`, true},\n\t\t{`\"abc\\0\"`, \"abc\\000\", true},\n\t\t{`\"abc\\\"abc\"`, `abc\"abc`, true},\n\n\t\t{`'abcdef'`, `abcdef`, true},\n\t\t{`'\"'`, \"\\\"\", true},\n\t\t{`'\\a\\b\\f\\n\\r\\t\\v\\\\\\''`, \"a\\bf\\n\\r\\tv\\\\'\", true},\n\t\t{`' '`, ` `, true},\n\t\t{\"'\\\\a汉字'\", \"a汉字\", true},\n\t\t{\"'\\\\a\\x90'\", \"a\\x90\", true},\n\t\t{\"\\\"\\\\a\\x18èàø»\\x05\\\"\", \"a\\x18èàø»\\x05\", true},\n\t}\n\n\tfor _, t := range table {\n\t\tx, err := Unquote(t.str)\n\t\tc.Assert(x, Equals, t.expect)\n\t\tcomment := Commentf(\"source %v\", t.str)\n\t\tif t.ok {\n\t\t\tc.Assert(err, IsNil, comment)\n\t\t} else {\n\t\t\tc.Assert(err, NotNil, comment)\n\t\t}\n\t}\n}\n\nfunc (s *testStringUtilSuite) TestPatternMatch(c *C) {\n\tdefer testleak.AfterTest(c)()\n\ttbl := []struct {\n\t\tpattern string\n\t\tinput   string\n\t\tescape  byte\n\t\tmatch   bool\n\t}{\n\t\t{``, `a`, '\\\\', false},\n\t\t{`a`, `a`, '\\\\', true},\n\t\t{`a`, `b`, '\\\\', false},\n\t\t{`aA`, `aA`, '\\\\', true},\n\t\t{`_`, `a`, '\\\\', true},\n\t\t{`_`, `ab`, '\\\\', false},\n\t\t{`__`, `b`, '\\\\', false},\n\t\t{`%`, `abcd`, '\\\\', true},\n\t\t{`%`, ``, '\\\\', true},\n\t\t{`%b`, `AAA`, '\\\\', false},\n\t\t{`%a%`, `BBB`, '\\\\', false},\n\t\t{`a%`, `BBB`, '\\\\', false},\n\t\t{`\\%a`, `%a`, '\\\\', true},\n\t\t{`\\%a`, `aa`, '\\\\', false},\n\t\t{`\\_a`, `_a`, '\\\\', true},\n\t\t{`\\_a`, `aa`, '\\\\', false},\n\t\t{`\\\\_a`, `\\xa`, '\\\\', true},\n\t\t{`\\a\\b`, `\\a\\b`, '\\\\', true},\n\t\t{`%%_`, `abc`, '\\\\', true},\n\t\t{`%_%_aA`, \"aaaA\", '\\\\', true},\n\t\t{`+_a`, `_a`, '+', true},\n\t\t{`+%a`, `%a`, '+', true},\n\t\t{`\\%a`, `%a`, '+', false},\n\t\t{`++a`, `+a`, '+', true},\n\t\t{`++_a`, `+xa`, '+', true},\n\t\t// We may reopen these test when like function go back to case insensitive.\n\t\t/*\n\t\t\t{\"_ab\", \"AAB\", '\\\\', true},\n\t\t\t{\"%a%\", \"BAB\", '\\\\', true},\n\t\t\t{\"%a\", \"AAA\", '\\\\', true},\n\t\t\t{\"b%\", \"BBB\", '\\\\', true},\n\t\t*/\n\t}\n\tfor _, v := range tbl {\n\t\tpatChars, patTypes := CompilePattern(v.pattern, v.escape)\n\t\tmatch := DoMatch(v.input, patChars, patTypes)\n\t\tc.Assert(match, Equals, v.match, Commentf(\"%v\", v))\n\t}\n}\n\nfunc (s *testStringUtilSuite) TestCompileLike2Regexp(c *C) {\n\tdefer testleak.AfterTest(c)()\n\ttbl := []struct {\n\t\tpattern string\n\t\tregexp  string\n\t}{\n\t\t{``, ``},\n\t\t{`a`, `a`},\n\t\t{`aA`, `aA`},\n\t\t{`_`, `.`},\n\t\t{`__`, `..`},\n\t\t{`%`, `.*`},\n\t\t{`%b`, `.*b`},\n\t\t{`%a%`, `.*a.*`},\n\t\t{`a%`, `a.*`},\n\t\t{`\\%a`, `%a`},\n\t\t{`\\_a`, `_a`},\n\t\t{`\\\\_a`, `\\.a`},\n\t\t{`\\a\\b`, `\\a\\b`},\n\t\t{`%%_`, `.*`},\n\t\t{`%_%_aA`, \".*aA\"},\n\t}\n\tfor _, v := range tbl {\n\t\tresult := CompileLike2Regexp(v.pattern)\n\t\tc.Assert(result, Equals, v.regexp, Commentf(\"%v\", v))\n\t}\n}\n\nfunc (s *testStringUtilSuite) TestIsExactMatch(c *C) {\n\tdefer testleak.AfterTest(c)()\n\ttbl := []struct {\n\t\tpattern    string\n\t\tescape     byte\n\t\texactMatch bool\n\t}{\n\t\t{``, '\\\\', true},\n\t\t{`_`, '\\\\', false},\n\t\t{`%`, '\\\\', false},\n\t\t{`a`, '\\\\', true},\n\t\t{`a_`, '\\\\', false},\n\t\t{`a%`, '\\\\', false},\n\t\t{`a\\_`, '\\\\', true},\n\t\t{`a\\%`, '\\\\', true},\n\t\t{`a\\\\`, '\\\\', true},\n\t\t{`a\\\\_`, '\\\\', false},\n\t\t{`a+%`, '+', true},\n\t\t{`a\\%`, '+', false},\n\t\t{`a++`, '+', true},\n\t\t{`a++_`, '+', false},\n\t}\n\tfor _, v := range tbl {\n\t\t_, patTypes := CompilePattern(v.pattern, v.escape)\n\t\tc.Assert(IsExactMatch(patTypes), Equals, v.exactMatch, Commentf(\"%v\", v))\n\t}\n}\n\nfunc BenchmarkMatchSpecial(b *testing.B) {\n\tvar (\n\t\tpattern = `a%a%a%a%a%a%a%a%b`\n\t\ttarget  = `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`\n\t\tescape  = byte('\\\\')\n\t)\n\n\tpatChars, patTypes := CompilePattern(pattern, escape)\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tmatch := DoMatch(target, patChars, patTypes)\n\t\tif match {\n\t\t\tb.Fatal(\"Unmatch expected.\")\n\t\t}\n\t}\n}\n\nfunc TestRemoveSensitiveInfo(t *testing.T) {\n\tr := require.New(t)\n\ttype sPair struct {\n\t\toriginSql string\n\t\texpectSql string\n\t}\n\ttestCase := []sPair{\n\t\t{`select plain_int_0 from scdb.alice_tbl_1;`, `select plain_int_0 from scdb.alice_tbl_1;`},\n\t\t{`CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED BY \"some_pwd\"`, `CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED ***`},\n\t\t{`CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED BY     \"some_pwd\"`, `CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED ***`},\n\t\t{`CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED    BY \"some_pwd\"`, `CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED    ***`},\n\t\t{`CREATE USER alice PARTY_CODE \"party_A\"    IDENTIFIED    BY \"some_pwd\"`, `CREATE USER alice PARTY_CODE \"party_A\"    IDENTIFIED    ***`},\n\t\t{`CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED WITH \"some_pwd\"`, `CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED ***`},\n\t\t{`CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED WITH    \"some_pwd\"`, `CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED ***`},\n\t\t{`CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED    WITH \"some_pwd\"`, `CREATE USER alice PARTY_CODE \"party_A\" IDENTIFIED    ***`},\n\t\t{`CREATE USER alice PARTY_CODE \"party_A\"   IDENTIFIED WITH \"some_pwd\"`, `CREATE USER alice PARTY_CODE \"party_A\"   IDENTIFIED ***`},\n\t\t{`CREATE USER alice PARTY_CODE \"party_A\"   IDENTIFIED WITH \"     some_pwd\"`, `CREATE USER alice PARTY_CODE \"party_A\"   IDENTIFIED ***`},\n\t\t{`ALTER USER alice IDENTIFIED BY \"new_password\"`, `ALTER USER alice IDENTIFIED ***`},\n\t\t{`ALTER USER alice IDENTIFIED WITH \"new_password\"`, `ALTER USER alice IDENTIFIED ***`},\n\t}\n\tfor _, ca := range testCase {\n\t\toriginSql := ca.originSql\n\t\texpected := ca.expectSql\n\t\tactual := RemoveSensitiveInfo(originSql)\n\t\tr.Equal(expected, actual)\n\t}\n}\n\nfunc TestIsDateString(t *testing.T) {\n\tr := require.New(t)\n\ttype pair struct {\n\t\tin     string\n\t\texpect bool\n\t}\n\ttestCases := []pair{\n\t\t{\"2024-05-01\", true},\n\t\t{\"2024-5-1\", false},\n\t\t{\"2024-05-01 11:12:13\", true},\n\t\t{\"2024-05-01T11:12:13Z\", false},\n\t\t{\"05/01/2024\", false},\n\t\t{\"\", false},\n\t\t{\"2024-05-01 1:12:13\", false},\n\t}\n\tfor _, ca := range testCases {\n\t\tr.Equal(ca.expect, IsDateString(ca.in), ca.in)\n\t}\n}\n\nfunc TestStringToUnixSec(t *testing.T) {\n\tr := require.New(t)\n\ttype pair struct {\n\t\tin         string\n\t\texpectUnix int64\n\t\texpectErr  bool\n\t}\n\ttestCases := []pair{\n\t\t{\"2024-05-01\", 1714521600, false},\n\t\t{\"2024-05-01 11:12:13\", 1714561933, false},\n\t\t{\"2024-05-01T11:12:13Z\", 0, true},\n\t\t{\"\", 0, true},\n\t\t{\"2024-05-01 1:12:13\", 0, true},\n\t}\n\tfor _, ca := range testCases {\n\t\tunixSec, err := StringToUnixSec(ca.in)\n\t\tif ca.expectErr {\n\t\t\tr.Error(err, ca.in)\n\t\t} else {\n\t\t\tr.NoError(err, ca.in)\n\t\t\tr.Equal(ca.expectUnix, unixSec, ca.in)\n\t\t}\n\t}\n}\n\nfunc TestStringToUnixSecWithTimezone(t *testing.T) {\n\t// Define a specific point in time: May 1, 2024, 10:00:00 UTC.\n\t// The corresponding Unix timestamp in seconds is 1714557600.\n\tconst targetUnixTime = 1714557600\n\n\ttype testCase struct {\n\t\tin         string\n\t\texpectUnix int64\n\t\texpectErr  bool\n\t\tcomment    string\n\t}\n\n\ttestCases := []testCase{\n\t\t// --- Success Cases ---\n\t\t// All successful test cases should resolve to the same point in time (targetUnixTime).\n\t\t{\n\t\t\tin:         \"2024-05-01T10:00:00Z\",\n\t\t\texpectUnix: targetUnixTime,\n\t\t\texpectErr:  false,\n\t\t\tcomment:    \"Standard UTC format using 'Z'\",\n\t\t},\n\t\t{\n\t\t\tin:         \"2024-05-01T18:00:00+08:00\",\n\t\t\texpectUnix: targetUnixTime,\n\t\t\texpectErr:  false,\n\t\t\tcomment:    \"Positive offset (+08:00), should convert to the same UTC time\",\n\t\t},\n\t\t{\n\t\t\tin:         \"2024-05-01T06:00:00-04:00\",\n\t\t\texpectUnix: targetUnixTime,\n\t\t\texpectErr:  false,\n\t\t\tcomment:    \"Negative offset (-04:00), should convert to the same UTC time\",\n\t\t},\n\t\t{\n\t\t\tin:         \"2024-05-01 13:00:00+03:00\",\n\t\t\texpectUnix: targetUnixTime,\n\t\t\texpectErr:  false,\n\t\t\tcomment:    \"Space separator with a positive offset\",\n\t\t},\n\t\t// --- Failure Cases ---\n\t\t{\n\t\t\tin:         \"2024-05-01 10:00:00\",\n\t\t\texpectUnix: 0,\n\t\t\texpectErr:  true,\n\t\t\tcomment:    \"Failure: missing timezone information\",\n\t\t},\n\t\t{\n\t\t\tin:         \"2024-05-01\",\n\t\t\texpectUnix: 0,\n\t\t\texpectErr:  true,\n\t\t\tcomment:    \"Failure: date only, missing time and timezone\",\n\t\t},\n\t\t{\n\t\t\tin:         \"2024-05-01T10:00:00\",\n\t\t\texpectUnix: 0,\n\t\t\texpectErr:  true,\n\t\t\tcomment:    \"Failure: 'T' separator but missing timezone information\",\n\t\t},\n\t\t{\n\t\t\tin:         \"not-a-real-date\",\n\t\t\texpectUnix: 0,\n\t\t\texpectErr:  true,\n\t\t\tcomment:    \"Failure: completely malformed string\",\n\t\t},\n\t\t{\n\t\t\tin:         \"\",\n\t\t\texpectUnix: 0,\n\t\t\texpectErr:  true,\n\t\t\tcomment:    \"Failure: empty string\",\n\t\t},\n\t\t{\n\t\t\tin:         \"2024-11-20 10:00:00 MST\",\n\t\t\texpectUnix: 0,\n\t\t\texpectErr:  true,\n\t\t\tcomment:    \"Failure: mbiguous formats\",\n\t\t},\n\t\t{\n\t\t\tin:         \"2024-12-10 15:00:00 PST\",\n\t\t\texpectUnix: 0,\n\t\t\texpectErr:  true,\n\t\t\tcomment:    \"Failure: mbiguous formats\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.comment, func(t *testing.T) {\n\t\t\tunixSec, err := StringToUnixSecWithTimezone(tc.in)\n\n\t\t\tif tc.expectErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, tc.expectUnix, unixSec)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestMySQLDateFormatToGoLayout(t *testing.T) {\n\tr := require.New(t)\n\n\ttype testCase struct {\n\t\tmysqlFormat string\n\t\texpectedGo  string\n\t\texpectErr   bool\n\t}\n\n\tcases := []testCase{\n\t\t{\"%Y-%m-%d\", \"2006-01-02\", false},\n\t\t{\"%Y-%m-%d %H:%i:%s\", \"2006-01-02 15:04:05\", false},\n\t\t{\"%r\", \"03:04:05 PM\", false},\n\t\t{\"%T\", \"15:04:05\", false},\n\t\t{\"%b %d, %Y\", \"Jan 02, 2006\", false},\n\t\t{\"%M %d, %Y\", \"January 02, 2006\", false},\n\t\t{\"%H:%i\", \"15:04\", false},\n\t\t{\"%p\", \"PM\", false},\n\t\t{\"%%\", \"%\", false},\n\t\t{\"%Y/%m/%d\", \"2006/01/02\", false},\n\t\t{\"2024-%m-%d\", \"2024-01-02\", false},\n\t\t{\"%x-%m-%d\", \"\", true}, // unsupported specifier %x\n\t\t{\"%Y-%m-%\", \"\", true},  // trailing %\n\t}\n\n\tfor _, ca := range cases {\n\t\tout, err := MySQLDateFormatToGoLayout(ca.mysqlFormat)\n\t\tif ca.expectErr {\n\t\t\tr.Error(err, ca.mysqlFormat)\n\t\t} else {\n\t\t\tr.NoError(err, ca.mysqlFormat)\n\t\t\tr.Equal(ca.expectedGo, out, ca.mysqlFormat)\n\t\t}\n\t}\n}\n\nfunc TestMySQLDateFormatToArrowFormat(t *testing.T) {\n\tr := require.New(t)\n\n\ttype testCase struct {\n\t\tname             string\n\t\tmysqlFormat      string\n\t\texpectedArrowFmt string\n\t\texpectErr        bool\n\t}\n\n\t// A slice of test cases covering various scenarios.\n\tcases := []testCase{\n\t\t{\n\t\t\tname:             \"Common MySQL datetime format with %i and %s\",\n\t\t\tmysqlFormat:      \"%Y-%m-%d %H:%i:%s\",\n\t\t\texpectedArrowFmt: \"%Y-%m-%d %H:%M:%S\", // %i -> %M, %s -> %S\n\t\t\texpectErr:        false,\n\t\t},\n\t\t{\n\t\t\tname:             \"Format with full month name (%M) and non-padded day (%e)\",\n\t\t\tmysqlFormat:      \"%M %e, %Y\",\n\t\t\texpectedArrowFmt: \"%B %-d, %Y\", // %M -> %B, %e -> %-d\n\t\t\texpectErr:        false,\n\t\t},\n\t\t{\n\t\t\tname:             \"12-hour format shortcut (%r)\",\n\t\t\tmysqlFormat:      \"%r\",\n\t\t\texpectedArrowFmt: \"%I:%M:%S %p\",\n\t\t\texpectErr:        false,\n\t\t},\n\t\t{\n\t\t\tname:             \"24-hour format shortcut (%T) with microseconds (%f)\",\n\t\t\tmysqlFormat:      \"%T.%f\",\n\t\t\texpectedArrowFmt: \"%H:%M:%S.%f\",\n\t\t\texpectErr:        false,\n\t\t},\n\t\t{\n\t\t\tname:             \"Format with literal percent sign (%%)\",\n\t\t\tmysqlFormat:      \"Progress: 100%%\",\n\t\t\texpectedArrowFmt: \"Progress: 100%\",\n\t\t\texpectErr:        false,\n\t\t},\n\t\t{\n\t\t\tname:             \"Format with abbreviated names\",\n\t\t\tmysqlFormat:      \"%a, %d %b %Y\",\n\t\t\texpectedArrowFmt: \"%a, %d %b %Y\", // These map directly\n\t\t\texpectErr:        false,\n\t\t},\n\t\t{\n\t\t\tname:             \"Empty format string\",\n\t\t\tmysqlFormat:      \"\",\n\t\t\texpectedArrowFmt: \"\",\n\t\t\texpectErr:        false,\n\t\t},\n\t\t{\n\t\t\tname:             \"Unsupported specifier %j\",\n\t\t\tmysqlFormat:      \"%Y-%j\", // %j for day of year is not in our map\n\t\t\texpectedArrowFmt: \"\",\n\t\t\texpectErr:        true,\n\t\t},\n\t\t{\n\t\t\tname:             \"Dangling percent at the end\",\n\t\t\tmysqlFormat:      \"Error %\",\n\t\t\texpectedArrowFmt: \"\",\n\t\t\texpectErr:        true,\n\t\t},\n\t\t{\n\t\t\tname:             \"Plain string with no specifiers\",\n\t\t\tmysqlFormat:      \"A simple literal string\",\n\t\t\texpectedArrowFmt: \"A simple literal string\",\n\t\t\texpectErr:        false,\n\t\t},\n\t}\n\n\tfor _, ca := range cases {\n\t\tt.Run(ca.name, func(t *testing.T) {\n\t\t\tarrowFmt, err := MySQLDateFormatToArrowFormat(ca.mysqlFormat)\n\n\t\t\tif ca.expectErr {\n\t\t\t\tr.Error(err, \"Expected an error for mysqlFormat: '%s'\", ca.mysqlFormat)\n\t\t\t} else {\n\t\t\t\tr.NoError(err, \"Did not expect an error for mysqlFormat: '%s'\", ca.mysqlFormat)\n\t\t\t\tr.Equal(ca.expectedArrowFmt, arrowFmt, \"Format string mismatch for mysqlFormat: '%s'\", ca.mysqlFormat)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/util/tableview/tableview.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage tableview\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/olekukonko/tablewriter\"\n\n\t\"github.com/secretflow/scql/pkg/proto-gen/scql\"\n)\n\n// ConvertToTable convert tensors to table\nfunc ConvertToTable(tensors []*scql.Tensor, table *tablewriter.Table) error {\n\tvar headerNames []string\n\tfor _, t := range tensors {\n\t\theaderNames = append(headerNames, t.Name)\n\t}\n\ttable.SetHeader(headerNames)\n\tif len(tensors) == 0 {\n\t\treturn nil\n\t}\n\tvar rows int64\n\tswitch x := tensors[0].Shape.Dim[0].Value.(type) {\n\tcase *scql.TensorShape_Dimension_DimValue:\n\t\trows = x.DimValue\n\tcase *scql.TensorShape_Dimension_DimParam:\n\t\treturn fmt.Errorf(\"unexpected type:%T\", x)\n\t}\n\tfor i := int64(0); i < rows; i++ {\n\t\tvar curRow []string\n\t\tfor _, t := range tensors {\n\t\t\tif len(t.DataValidity) > 0 && !t.DataValidity[i] {\n\t\t\t\tcurRow = append(curRow, \"null\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tswitch t.ElemType {\n\t\t\tcase scql.PrimitiveDataType_STRING, scql.PrimitiveDataType_DATETIME:\n\t\t\t\tcurRow = append(curRow, t.GetStringData()[i])\n\t\t\tcase scql.PrimitiveDataType_FLOAT32:\n\t\t\t\tcurRow = append(curRow, fmt.Sprint(t.GetFloatData()[i]))\n\t\t\tcase scql.PrimitiveDataType_FLOAT64:\n\t\t\t\tcurRow = append(curRow, fmt.Sprint(t.GetDoubleData()[i]))\n\t\t\tcase scql.PrimitiveDataType_BOOL:\n\t\t\t\tcurRow = append(curRow, fmt.Sprint(t.GetBoolData()[i]))\n\t\t\tcase scql.PrimitiveDataType_INT8, scql.PrimitiveDataType_INT16, scql.PrimitiveDataType_INT32:\n\t\t\t\tcurRow = append(curRow, fmt.Sprint(t.GetInt32Data()[i]))\n\t\t\tcase scql.PrimitiveDataType_INT64, scql.PrimitiveDataType_TIMESTAMP:\n\t\t\t\tcurRow = append(curRow, fmt.Sprint(t.GetInt64Data()[i]))\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unsupported type:%s\", t.ElemType)\n\t\t\t}\n\t\t}\n\t\ttable.Append(curRow)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/util/testleak/fake.go",
    "content": "// Copyright 2017 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//go:build !leak\n// +build !leak\n\npackage testleak\n\nimport (\n\t\"testing\"\n\n\t\"github.com/pingcap/check\"\n)\n\n// BeforeTest is a dummy implementation when build tag 'leak' is not set.\nfunc BeforeTest() {\n}\n\n// AfterTest is a dummy implementation when build tag 'leak' is not set.\nfunc AfterTest(c *check.C) func() {\n\treturn func() {\n\t}\n}\n\n// AfterTestT is used after all the test cases is finished.\nfunc AfterTestT(t *testing.T) func() {\n\treturn func() {\n\t}\n}\n"
  },
  {
    "path": "pkg/util/testleak/leaktest.go",
    "content": "// Copyright 2013 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// Copyright 2016 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//go:build leak\n// +build leak\n\npackage testleak\n\nimport (\n\t\"runtime\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/pingcap/check\"\n)\n\nfunc interestingGoroutines() (gs []string) {\n\tbuf := make([]byte, 2<<20)\n\tbuf = buf[:runtime.Stack(buf, true)]\n\tfor _, g := range strings.Split(string(buf), \"\\n\\n\") {\n\t\tsl := strings.SplitN(g, \"\\n\", 2)\n\t\tif len(sl) != 2 {\n\t\t\tcontinue\n\t\t}\n\t\tstack := strings.TrimSpace(sl[1])\n\t\tif stack == \"\" ||\n\t\t\tstrings.Contains(stack, \"created by github.com/pingcap/tidb.init\") ||\n\t\t\tstrings.Contains(stack, \"testing.RunTests\") ||\n\t\t\tstrings.Contains(stack, \"check.(*resultTracker).start\") ||\n\t\t\tstrings.Contains(stack, \"check.(*suiteRunner).runFunc\") ||\n\t\t\tstrings.Contains(stack, \"check.(*suiteRunner).parallelRun\") ||\n\t\t\tstrings.Contains(stack, \"localstore.(*dbStore).scheduler\") ||\n\t\t\tstrings.Contains(stack, \"tikv.(*noGCHandler).Start\") ||\n\t\t\tstrings.Contains(stack, \"ddl.(*ddl).start\") ||\n\t\t\tstrings.Contains(stack, \"ddl.(*delRange).startEmulator\") ||\n\t\t\tstrings.Contains(stack, \"domain.NewDomain\") ||\n\t\t\tstrings.Contains(stack, \"testing.(*T).Run\") ||\n\t\t\tstrings.Contains(stack, \"domain.(*Domain).LoadPrivilegeLoop\") ||\n\t\t\tstrings.Contains(stack, \"domain.(*Domain).UpdateTableStatsLoop\") ||\n\t\t\tstrings.Contains(stack, \"testing.Main(\") ||\n\t\t\tstrings.Contains(stack, \"runtime.goexit\") ||\n\t\t\tstrings.Contains(stack, \"created by runtime.gc\") ||\n\t\t\tstrings.Contains(stack, \"interestingGoroutines\") ||\n\t\t\tstrings.Contains(stack, \"runtime.MHeap_Scavenger\") {\n\t\t\tcontinue\n\t\t}\n\t\tgs = append(gs, stack)\n\t}\n\tsort.Strings(gs)\n\treturn\n}\n\nvar beforeTestGorountines = map[string]bool{}\n\n// BeforeTest gets the current goroutines.\n// It's used for check.Suite.SetUpSuite() function.\n// Now it's only used in the tidb_test.go.\nfunc BeforeTest() {\n\tfor _, g := range interestingGoroutines() {\n\t\tbeforeTestGorountines[g] = true\n\t}\n}\n\nconst defaultCheckCnt = 50\n\nfunc checkLeakAfterTest(errorFunc func(cnt int, g string)) func() {\n\tif len(beforeTestGorountines) == 0 {\n\t\tfor _, g := range interestingGoroutines() {\n\t\t\tbeforeTestGorountines[g] = true\n\t\t}\n\t}\n\n\tcnt := defaultCheckCnt\n\treturn func() {\n\t\tdefer func() {\n\t\t\tbeforeTestGorountines = map[string]bool{}\n\t\t}()\n\n\t\tvar leaked []string\n\t\tfor i := 0; i < cnt; i++ {\n\t\t\tleaked = leaked[:0]\n\t\t\tfor _, g := range interestingGoroutines() {\n\t\t\t\tif !beforeTestGorountines[g] {\n\t\t\t\t\tleaked = append(leaked, g)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Bad stuff found, but goroutines might just still be\n\t\t\t// shutting down, so give it some time.\n\t\t\tif len(leaked) != 0 {\n\t\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\t\tfor _, g := range leaked {\n\t\t\terrorFunc(cnt, g)\n\t\t}\n\t}\n}\n\n// AfterTest gets the current goroutines and runs the returned function to\n// get the goroutines at that time to contrast whether any goroutines leaked.\n// Usage: defer testleak.AfterTest(c)()\n// It can call with BeforeTest() at the beginning of check.Suite.TearDownSuite() or\n// call alone at the beginning of each test.\nfunc AfterTest(c *check.C) func() {\n\terrorFunc := func(cnt int, g string) {\n\t\tc.Errorf(\"Test %s check-count %d appears to have leaked: %v\", c.TestName(), cnt, g)\n\t}\n\treturn checkLeakAfterTest(errorFunc)\n}\n\n// AfterTestT is used after all the test cases is finished.\nfunc AfterTestT(t *testing.T) func() {\n\terrorFunc := func(cnt int, g string) {\n\t\tt.Errorf(\"Test %s check-count %d appears to have leaked: %v\", t.Name(), cnt, g)\n\t}\n\treturn checkLeakAfterTest(errorFunc)\n}\n"
  },
  {
    "path": "pkg/util/testutil/testutil.go",
    "content": "// Copyright 2015 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Modified by Ant Group in 2023\n\n//go:build !codes\n// +build !codes\n\npackage testutil\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/pingcap/check\"\n\t\"github.com/pingcap/errors\"\n)\n\n// record is a flag used for generate test result.\nvar record bool\n\n// IsRecording returns true if the -record flag is set\nfunc IsRecording() bool {\n\treturn record\n}\n\nfunc init() {\n\tflag.BoolVar(&record, \"record\", false, \"to generate test result\")\n}\n\ntype testCases struct {\n\tName       string           `json:\"name\"`\n\tCases      *json.RawMessage `json:\"cases\"` // For delayed parse.\n\tdecodedOut interface{}      // For generate output.\n}\n\n// TestData stores all the data of a test suite.\ntype TestData struct {\n\tinput          []testCases\n\toutput         []testCases\n\tfilePathPrefix string\n\tfuncMap        map[string]int\n\thasOutFile     bool // Whether this test suite has a separate output file\n}\n\n// LoadTestSuiteData loads test suite data from file.\nfunc LoadTestSuiteData(dir, suiteName string) (res TestData, err error) {\n\tres.filePathPrefix = filepath.Join(dir, suiteName)\n\tres.input, err = loadTestSuiteCases(fmt.Sprintf(\"%s_in.json\", res.filePathPrefix))\n\tif err != nil {\n\t\treturn res, err\n\t}\n\n\t// Check if output file exists\n\toutFilePath := fmt.Sprintf(\"%s_out.json\", res.filePathPrefix)\n\tif record {\n\t\t// In record mode, check if out file exists to decide where to write\n\t\tif _, err = os.Stat(outFilePath); err == nil {\n\t\t\tres.hasOutFile = true\n\t\t} else {\n\t\t\tres.hasOutFile = false\n\t\t}\n\t\tres.output = make([]testCases, len(res.input))\n\t\tfor i := range res.input {\n\t\t\tres.output[i].Name = res.input[i].Name\n\t\t}\n\t} else {\n\t\t// In normal mode, try to load output file\n\t\tres.output, err = loadTestSuiteCases(outFilePath)\n\t\tif err != nil {\n\t\t\tif os.IsNotExist(err) {\n\t\t\t\t// Out file doesn't exist, use input-only mode\n\t\t\t\tres.hasOutFile = false\n\t\t\t\tres.output = make([]testCases, len(res.input))\n\t\t\t} else {\n\t\t\t\treturn res, err\n\t\t\t}\n\t\t} else {\n\t\t\t// Out file exists and loaded successfully\n\t\t\tres.hasOutFile = true\n\t\t\tif len(res.input) != len(res.output) {\n\t\t\t\treturn res, errors.New(fmt.Sprintf(\"Number of test input cases %d does not match test output cases %d\", len(res.input), len(res.output)))\n\t\t\t}\n\t\t}\n\t}\n\n\tres.funcMap = make(map[string]int, len(res.input))\n\tfor i, test := range res.input {\n\t\tres.funcMap[test.Name] = i\n\t\tif res.hasOutFile && test.Name != res.output[i].Name {\n\t\t\treturn res, errors.New(fmt.Sprintf(\"Input name of the %d-case %s does not match output %s\", i, test.Name, res.output[i].Name))\n\t\t}\n\t}\n\n\treturn res, nil\n}\n\nfunc loadTestSuiteCases(filePath string) (res []testCases, err error) {\n\tjsonFile, err := os.Open(filePath)\n\tif err != nil {\n\t\treturn res, err\n\t}\n\tdefer func() {\n\t\tif err1 := jsonFile.Close(); err == nil && err1 != nil {\n\t\t\terr = err1\n\t\t}\n\t}()\n\tbyteValue, err := io.ReadAll(jsonFile)\n\tif err != nil {\n\t\treturn res, err\n\t}\n\t// Remove comments(keep a // b), since they are not allowed in json\n\tre := regexp.MustCompile(\"(?s)  //.*?\\n\")\n\terr = json.Unmarshal(re.ReplaceAll(byteValue, nil), &res)\n\treturn res, err\n}\n\n// GetTestCases gets the test cases for a test function.\nfunc (t *TestData) GetTestCases(c *check.C, in interface{}, out interface{}) {\n\t// Extract caller's name.\n\tpc, _, _, ok := runtime.Caller(1)\n\tc.Assert(ok, check.IsTrue)\n\tdetails := runtime.FuncForPC(pc)\n\tfuncNameIdx := strings.LastIndex(details.Name(), \".\")\n\tfuncName := details.Name()[funcNameIdx+1:]\n\n\tcasesIdx, ok := t.funcMap[funcName]\n\tc.Assert(ok, check.IsTrue, check.Commentf(\"Must get test %s\", funcName))\n\terr := json.Unmarshal(*t.input[casesIdx].Cases, in)\n\tc.Assert(err, check.IsNil)\n\tif !record {\n\t\terr = json.Unmarshal(*t.output[casesIdx].Cases, out)\n\t\tc.Assert(err, check.IsNil)\n\t} else {\n\t\t// Init for generate output file.\n\t\tinputLen := reflect.ValueOf(in).Elem().Len()\n\t\tv := reflect.ValueOf(out).Elem()\n\t\tif v.Kind() == reflect.Slice {\n\t\t\tv.Set(reflect.MakeSlice(v.Type(), inputLen, inputLen))\n\t\t}\n\t}\n\tt.output[casesIdx].decodedOut = out\n}\n\n// GetTestCasesWithoutOut gets the test cases for a test function without separate output.\n// This is used for tests where the test data includes both inputs and expected outputs\n// in the same structure (e.g., when there is no separate output file).\nfunc (t *TestData) GetTestCasesWithoutOut(c *check.C, in interface{}) {\n\t// Extract caller's name.\n\tpc, _, _, ok := runtime.Caller(1)\n\tc.Assert(ok, check.IsTrue)\n\tdetails := runtime.FuncForPC(pc)\n\tfuncNameIdx := strings.LastIndex(details.Name(), \".\")\n\tfuncName := details.Name()[funcNameIdx+1:]\n\tcasesIdx, ok := t.funcMap[funcName]\n\tc.Assert(ok, check.IsTrue, check.Commentf(\"Must get test %s\", funcName))\n\terr := json.Unmarshal(*t.input[casesIdx].Cases, in)\n\tc.Assert(err, check.IsNil)\n\n\t// When in record mode, store the input as the decodedOut so it can be written back\n\tif record {\n\t\tt.output[casesIdx].decodedOut = in\n\t}\n}\n\n// OnRecord execute the function to update result.\nfunc (t *TestData) OnRecord(updateFunc func()) {\n\tif record {\n\t\tupdateFunc()\n\t}\n}\n\n// GenerateOutputIfNeeded generate the output file.\nfunc (t *TestData) GenerateOutputIfNeeded() error {\n\tif !record {\n\t\treturn nil\n\t}\n\n\t// Skip if testData was not initialized (filePathPrefix is empty)\n\tif t.filePathPrefix == \"\" {\n\t\treturn nil\n\t}\n\n\tbuf := new(bytes.Buffer)\n\tenc := json.NewEncoder(buf)\n\tenc.SetEscapeHTML(false)\n\tenc.SetIndent(\"\", \"  \")\n\n\t// Determine which data to write based on whether output file exists\n\tvar dataToWrite []testCases\n\tvar outputFile string\n\n\tif t.hasOutFile {\n\t\t// When output file exists, write to *_out.json (original behavior)\n\t\tfor i, test := range t.output {\n\t\t\terr := enc.Encode(test.decodedOut)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tres := make([]byte, len(buf.Bytes()))\n\t\t\tcopy(res, buf.Bytes())\n\t\t\tbuf.Reset()\n\t\t\trm := json.RawMessage(res)\n\t\t\tt.output[i].Cases = &rm\n\t\t}\n\t\tdataToWrite = t.output\n\t\toutputFile = fmt.Sprintf(\"%s_out.json\", t.filePathPrefix)\n\t} else {\n\t\t// When output file doesn't exist, write to *_in.json\n\t\tdataToWrite = make([]testCases, len(t.input))\n\t\tfor i := range t.input {\n\t\t\tdataToWrite[i].Name = t.input[i].Name\n\t\t\t// Encode the decoded output data\n\t\t\terr := enc.Encode(t.output[i].decodedOut)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tres := make([]byte, len(buf.Bytes()))\n\t\t\tcopy(res, buf.Bytes())\n\t\t\tbuf.Reset()\n\t\t\trm := json.RawMessage(res)\n\t\t\tdataToWrite[i].Cases = &rm\n\t\t}\n\t\toutputFile = fmt.Sprintf(\"%s_in.json\", t.filePathPrefix)\n\t}\n\n\terr := enc.Encode(dataToWrite)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfile, err := os.Create(outputFile)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tif err1 := file.Close(); err == nil && err1 != nil {\n\t\t\terr = err1\n\t\t}\n\t}()\n\t_, err = file.Write(buf.Bytes())\n\treturn err\n}\n"
  },
  {
    "path": "pkg/util/texttree/texttree.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage texttree\n\nconst (\n\t// TreeBody indicates the current operator sub-tree is not finished, still\n\t// has child operators to be attached on.\n\tTreeBody = '│'\n\t// TreeMiddleNode indicates this operator is not the last child of the\n\t// current sub-tree rooted by its parent.\n\tTreeMiddleNode = '├'\n\t// TreeLastNode indicates this operator is the last child of the current\n\t// sub-tree rooted by its parent.\n\tTreeLastNode = '└'\n\t// TreeGap is used to represent the gap between the branches of the tree.\n\tTreeGap = ' '\n\t// TreeNodeIdentifier is used to replace the treeGap once we need to attach\n\t// a node to a sub-tree.\n\tTreeNodeIdentifier = '─'\n)\n\n// Indent4Child appends more blank to the `indent` string\nfunc Indent4Child(indent string, isLastChild bool) string {\n\tif !isLastChild {\n\t\treturn string(append([]rune(indent), TreeBody, TreeGap))\n\t}\n\n\t// If the current node is the last node of the current operator tree, we\n\t// need to end this sub-tree by changing the closest treeBody to a treeGap.\n\tindentBytes := []rune(indent)\n\tfor i := len(indentBytes) - 1; i >= 0; i-- {\n\t\tif indentBytes[i] == TreeBody {\n\t\t\tindentBytes[i] = TreeGap\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn string(append(indentBytes, TreeBody, TreeGap))\n}\n\n// PrettyIdentifier returns a pretty identifier which contains indent and tree node hierarchy indicator\nfunc PrettyIdentifier(id, indent string, isLastChild bool) string {\n\tif len(indent) == 0 {\n\t\treturn id\n\t}\n\n\tindentBytes := []rune(indent)\n\tfor i := len(indentBytes) - 1; i >= 0; i-- {\n\t\tif indentBytes[i] != TreeBody {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Here we attach a new node to the current sub-tree by changing\n\t\t// the closest treeBody to a:\n\t\t// 1. treeLastNode, if this operator is the last child.\n\t\t// 2. treeMiddleNode, if this operator is not the last child..\n\t\tif isLastChild {\n\t\t\tindentBytes[i] = TreeLastNode\n\t\t} else {\n\t\t\tindentBytes[i] = TreeMiddleNode\n\t\t}\n\t\tbreak\n\t}\n\n\t// Replace the treeGap between the treeBody and the node to a\n\t// treeNodeIdentifier.\n\tindentBytes[len(indentBytes)-1] = TreeNodeIdentifier\n\treturn string(indentBytes) + id\n}\n"
  },
  {
    "path": "pkg/util/texttree/texttree_test.go",
    "content": "// Copyright 2019 PingCAP, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage texttree_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/pingcap/check\"\n\n\t\"github.com/secretflow/scql/pkg/util/texttree\"\n)\n\ntype texttreeSuite struct{}\n\nvar _ = Suite(&texttreeSuite{})\n\nfunc TestT(t *testing.T) {\n\tCustomVerboseFlag = true\n\tTestingT(t)\n}\n\nfunc (s *texttreeSuite) TestPrettyIdentifier(c *C) {\n\tc.Assert(texttree.PrettyIdentifier(\"test\", \"\", false), Equals, \"test\")\n\tc.Assert(texttree.PrettyIdentifier(\"test\", \"  │  \", false), Equals, \"  ├ ─test\")\n\tc.Assert(texttree.PrettyIdentifier(\"test\", \"\\t\\t│\\t\\t\", false), Equals, \"\\t\\t├\\t─test\")\n\tc.Assert(texttree.PrettyIdentifier(\"test\", \"  │  \", true), Equals, \"  └ ─test\")\n\tc.Assert(texttree.PrettyIdentifier(\"test\", \"\\t\\t│\\t\\t\", true), Equals, \"\\t\\t└\\t─test\")\n}\n\nfunc (s *texttreeSuite) TestIndent4Child(c *C) {\n\tc.Assert(texttree.Indent4Child(\"    \", false), Equals, \"    │ \")\n\tc.Assert(texttree.Indent4Child(\"    \", true), Equals, \"    │ \")\n\tc.Assert(texttree.Indent4Child(\"   │ \", true), Equals, \"     │ \")\n}\n"
  },
  {
    "path": "pkg/util/transaction/tx.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage transaction\n\nimport (\n\t\"gorm.io/gorm\"\n\t\"gorm.io/gorm/clause\"\n)\n\n// refer to https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html\nfunc AddExclusiveLock(tx *gorm.DB) *gorm.DB {\n\treturn tx.Clauses(clause.Locking{Strength: \"UPDATE\"})\n}\n"
  },
  {
    "path": "pkg/util/url/url_util.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage url\n\nimport (\n\t\"strings\"\n)\n\n// JoinHostPath join host and path by concat them directly with only extra proccessing flows:\n// 1. Add missig slash '/' between host and path\n// 2. Remove duplidate slash '/' between host and path\nfunc JoinHostPath(host, path string) string {\n\t// note: path.Join(\"http://localhost/\", \"/public/query\") will produce \"http:/localhost/public/query\", prefix 'http:/' but not 'http://'\n\tif strings.HasPrefix(path, \"/\") {\n\t\treturn strings.TrimSuffix(host, \"/\") + path\n\t}\n\treturn strings.TrimSuffix(host, \"/\") + \"/\" + path\n}\n"
  },
  {
    "path": "pkg/util/url/url_util_test.go",
    "content": "// Copyright 2023 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage url\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestJoinHostPath(t *testing.T) {\n\tassert.Equal(t, \"http://x.com/a/b\", JoinHostPath(\"http://x.com/\", \"/a/b\"))\n\tassert.Equal(t, \"http://x.com/a/b\", JoinHostPath(\"http://x.com/\", \"a/b\"))\n\tassert.Equal(t, \"http://x.com/a/b\", JoinHostPath(\"http://x.com\", \"/a/b\"))\n\tassert.Equal(t, \"http://x.com/a/b\", JoinHostPath(\"http://x.com\", \"a/b\"))\n\tassert.Equal(t, \"x.com/a/b\", JoinHostPath(\"x.com\", \"a/b\"))\n}\n"
  },
  {
    "path": "python/build.py",
    "content": "#!/usr/bin/env python3\n# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"SCQL Python Package Build Script\n\nThis script builds the SCQL Python package components:\n- C++ Engine: Built with Bazel in Docker (default, for glibc compatibility)\n- Go Compiler: Built with gopy locally\n\nUsage:\n    python build.py           # Build all components (engine in Docker, compiler locally)\n    python build.py engine    # Build only engine (engine in Docker)\n    python build.py compiler  # Build only compiler (locally)\n    python build.py clean     # Clean build artifacts\n\nAdvanced Options:\n    --no-docker               # Build engine locally (not recommended)\n    --docker-image IMAGE      # Use custom Docker image\n    --docker-name NAME        # Use custom container name\n    --docker-restart          # Force restart Docker container\n\nExamples:\n    python build.py                    # Default: engine in Docker, compiler locally\n    python build.py engine             # Build only engine in Docker\n    python build.py compiler           # Build only compiler locally\n    python build.py --no-docker        # Build everything locally (glibc compatibility issues)\n    python build.py --docker-restart   # Build with fresh Docker container\n\"\"\"\n\nimport os\nimport subprocess\nimport sys\nimport shutil\nimport tempfile\nimport argparse\nfrom pathlib import Path\n\n\n# Configuration\nPYTHON_ROOT = Path(__file__).parent.absolute()\nSCQL_ROOT = PYTHON_ROOT.parent\nSRC_DIR = PYTHON_ROOT / \"src\"\nSRC_PKG_DIR = SRC_DIR / \"scql\"\nBUILD_DIR = PYTHON_ROOT / \"build\"\nPACKAGE_DIR = PYTHON_ROOT / \"package\"\n\n# Source directories\nSRC_ENGINE_DIR = SRC_PKG_DIR / \"engine\"\nSRC_COMPILER_DIR = SRC_PKG_DIR / \"compiler\"\n\n# Build directories\nBUILD_ENGINE_DIR = BUILD_DIR / \"engine\"\nBUILD_COMPILER_DIR = BUILD_DIR / \"compiler\"\n\n# Package directories\nPKG_ENGINE_DIR = PACKAGE_DIR / \"scql\" / \"engine\"\nPKG_COMPILER_DIR = PACKAGE_DIR / \"scql\" / \"compiler\"\n\n# Build configuration\nPYTHON_VM = \"python3\"\nGO_PACKAGE_PATH = \"./pkg/interpreter/sc\"\n\n# Docker configuration\nCONTAINER_NAME = f\"scql-dev-{os.getenv('USER', 'unknown')}\"\n\n\nclass DockerEngineBuilder:\n    \"\"\"Manages Docker container for building SCQL engine to avoid glibc compatibility issues.\"\"\"\n\n    def __init__(self, scql_root, container_name=None, image=None):\n        self.scql_root = Path(scql_root)\n        self.container_name = container_name or CONTAINER_NAME\n        self.image = image\n        self.bazel_cache_dir = Path.home() / \".cache\" / \"bazel\"\n        self.bazelisk_cache_dir = Path.home() / \".cache\" / \"bazelisk\"\n\n    def ensure_container_running(self, force_restart=False):\n        \"\"\"Ensure the Docker container is running.\"\"\"\n        # Check if container exists\n        result = run_command(\n            [\"docker\", \"ps\", \"-a\", \"--filter\", f\"name={self.container_name}\"],\n            capture_output=True,\n        )\n\n        if result.returncode == 0 and self.container_name in result.stdout:\n            # Container exists\n            if force_restart:\n                print(f\"Removing existing container: {self.container_name}\")\n                run_command([\"docker\", \"rm\", \"-f\", self.container_name])\n                return self.create_and_start_container()\n            else:\n                # Check if it's running\n                result = run_command(\n                    [\"docker\", \"ps\", \"--filter\", f\"name={self.container_name}\"],\n                    capture_output=True,\n                )\n                if result.returncode == 0 and self.container_name in result.stdout:\n                    print(f\"Container {self.container_name} is already running\")\n                    return True\n                else:\n                    print(f\"Starting existing container: {self.container_name}\")\n                    run_command([\"docker\", \"start\", self.container_name])\n                    return True\n        else:\n            # Container doesn't exist, create it\n            return self.create_and_start_container()\n\n    def create_and_start_container(self):\n        \"\"\"Create and start a new Docker container.\"\"\"\n        print(f\"Creating new container: {self.container_name}\")\n\n        # Ensure cache directories exist\n        self.bazel_cache_dir.mkdir(parents=True, exist_ok=True)\n        self.bazelisk_cache_dir.mkdir(parents=True, exist_ok=True)\n\n        # Docker run command\n        cmd = [\n            \"docker\",\n            \"run\",\n            \"-d\",\n            \"-it\",\n            \"--name\",\n            self.container_name,\n            \"--mount\",\n            f\"type=bind,source={self.scql_root},target=/home/admin/dev/\",\n            \"--mount\",\n            f\"type=bind,source={self.bazel_cache_dir},target=/root/.cache/bazel\",\n            \"--mount\",\n            f\"type=bind,source={self.bazelisk_cache_dir},target=/root/.cache/bazelisk\",\n            \"-w\",\n            \"/home/admin/dev\",\n            \"--cap-add=SYS_PTRACE\",\n            \"--security-opt\",\n            \"seccomp=unconfined\",\n            \"--cap-add=NET_ADMIN\",\n            \"--privileged=true\",\n            self.image,\n            \"/bin/bash\",\n        ]\n\n        try:\n            run_command(cmd)\n            print(\n                f\"✅ Container {self.container_name} created and started successfully\"\n            )\n            return True\n        except subprocess.CalledProcessError as e:\n            print(f\"❌ Failed to create container: {e}\")\n            return False\n\n    def execute_in_container(self, cmd, cwd=\"/home/admin/dev\"):\n        \"\"\"Execute command inside the Docker container.\"\"\"\n        docker_cmd = [\"docker\", \"exec\", self.container_name] + cmd\n        return run_command(docker_cmd, cwd=None)  # cwd is relative to container\n\n    def copy_from_container(self, container_path, host_path):\n        \"\"\"Copy file from container to host.\"\"\"\n        cmd = [\n            \"docker\",\n            \"cp\",\n            f\"{self.container_name}:{container_path}\",\n            str(host_path),\n        ]\n        run_command(cmd)\n\n\nclass BazelRcManager:\n    \"\"\"Context manager to temporarily modify .bazelrc for engine build.\"\"\"\n\n    def __init__(self, scql_root, use_docker=False, docker_builder=None):\n        self.scql_root = Path(scql_root)\n        self.bazelrc_path = self.scql_root / \".bazelrc\"\n        self.backup_path = None\n        self.tls_option = '# Avoid static TLS error for pybind11\\nbuild --copt=\"-ftls-model=global-dynamic\"'\n        self.use_docker = use_docker\n        self.docker_builder = docker_builder\n\n    def __enter__(self):\n        \"\"\"Backup and modify .bazelrc\"\"\"\n        if self.use_docker:\n            # In Docker mode, modify .bazelrc inside the container\n            container_bazelrc = \"/home/admin/dev/.bazelrc\"\n\n            # Backup existing .bazelrc in container\n            result = run_command(\n                [\n                    \"docker\",\n                    \"exec\",\n                    self.docker_builder.container_name,\n                    \"test\",\n                    \"-f\",\n                    container_bazelrc,\n                ],\n                capture_output=True,\n                check=False,\n            )\n            if result.returncode == 0:\n                run_command(\n                    [\n                        \"docker\",\n                        \"exec\",\n                        self.docker_builder.container_name,\n                        \"cp\",\n                        container_bazelrc,\n                        f\"{container_bazelrc}.bak\",\n                    ]\n                )\n                print(\"Backed up .bazelrc in container\")\n\n            # Add TLS option to .bazelrc in container\n            run_command(\n                [\n                    \"docker\",\n                    \"exec\",\n                    self.docker_builder.container_name,\n                    \"sh\",\n                    \"-c\",\n                    f\"echo '{self.tls_option}' >> {container_bazelrc}\",\n                ]\n            )\n            print(\"Added temporary TLS option to .bazelrc in container\")\n        else:\n            # Local mode - original logic\n            if self.bazelrc_path.exists():\n                self.backup_path = self.bazelrc_path.with_suffix(\".bak\")\n                shutil.copy2(self.bazelrc_path, self.backup_path)\n                print(f\"Backed up .bazelrc to {self.backup_path}\")\n\n            # Add TLS option to .bazelrc\n            with open(self.bazelrc_path, \"a\") as f:\n                f.write(f\"\\n{self.tls_option}\\n\")\n            print(\"Added temporary TLS option to .bazelrc\")\n\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        \"\"\"Restore original .bazelrc\"\"\"\n        if self.use_docker:\n            # Restore .bazelrc in container\n            container_bazelrc = \"/home/admin/dev/.bazelrc\"\n\n            result = run_command(\n                [\n                    \"docker\",\n                    \"exec\",\n                    self.docker_builder.container_name,\n                    \"test\",\n                    \"-f\",\n                    f\"{container_bazelrc}.bak\",\n                ],\n                capture_output=True,\n                check=False,\n            )\n            if result.returncode == 0:\n                run_command(\n                    [\n                        \"docker\",\n                        \"exec\",\n                        self.docker_builder.container_name,\n                        \"cp\",\n                        f\"{container_bazelrc}.bak\",\n                        container_bazelrc,\n                    ]\n                )\n                run_command(\n                    [\n                        \"docker\",\n                        \"exec\",\n                        self.docker_builder.container_name,\n                        \"rm\",\n                        f\"{container_bazelrc}.bak\",\n                    ]\n                )\n                print(\"Restored original .bazelrc in container\")\n            elif (\n                run_command(\n                    [\n                        \"docker\",\n                        \"exec\",\n                        self.docker_builder.container_name,\n                        \"test\",\n                        \"-f\",\n                        container_bazelrc,\n                    ],\n                    capture_output=True,\n                    check=False,\n                ).returncode\n                == 0\n            ):\n                # Remove the added TLS option\n                result = run_command(\n                    [\n                        \"docker\",\n                        \"exec\",\n                        self.docker_builder.container_name,\n                        \"cat\",\n                        container_bazelrc,\n                    ],\n                    capture_output=True,\n                )\n                if result.returncode == 0:\n                    content = result.stdout\n                    lines = content.split(\"\\n\")\n                    filtered_lines = []\n                    skip_next = False\n                    for line in lines:\n                        if \"# Avoid static TLS error for pybind11\" in line:\n                            skip_next = True\n                            continue\n                        elif (\n                            skip_next\n                            and 'build --copt=\"-ftls-model=global-dynamic\"' in line\n                        ):\n                            skip_next = False\n                            continue\n                        filtered_lines.append(line)\n\n                    # Write back to file\n                    filtered_content = \"\\n\".join(filtered_lines)\n                    run_command(\n                        [\n                            \"docker\",\n                            \"exec\",\n                            self.docker_builder.container_name,\n                            \"sh\",\n                            \"-c\",\n                            f\"echo '{filtered_content}' > {container_bazelrc}\",\n                        ]\n                    )\n                    print(\"Removed temporary TLS option from .bazelrc in container\")\n        else:\n            # Local mode - original logic\n            if self.backup_path and self.backup_path.exists():\n                shutil.copy2(self.backup_path, self.bazelrc_path)\n                self.backup_path.unlink()\n                print(\"Restored original .bazelrc\")\n            elif self.bazelrc_path.exists():\n                # Remove the added TLS option\n                with open(self.bazelrc_path, \"r\") as f:\n                    content = f.read()\n\n                # Remove the TLS option we added\n                lines = content.split(\"\\n\")\n                filtered_lines = []\n                skip_next = False\n                for line in lines:\n                    if \"# Avoid static TLS error for pybind11\" in line:\n                        skip_next = True\n                        continue\n                    elif (\n                        skip_next\n                        and 'build --copt=\"-ftls-model=global-dynamic\"' in line\n                    ):\n                        skip_next = False\n                        continue\n                    filtered_lines.append(line)\n\n                with open(self.bazelrc_path, \"w\") as f:\n                    f.write(\"\\n\".join(filtered_lines))\n                print(\"Removed temporary TLS option from .bazelrc\")\n\n\ndef run_command(cmd, cwd=None, check=True, capture_output=False):\n    \"\"\"Run a shell command with logging.\"\"\"\n    cmd_str = \" \".join(cmd) if isinstance(cmd, list) else cmd\n    print(f\"Running: {cmd_str}\")\n\n    if capture_output:\n        result = subprocess.run(\n            cmd, cwd=cwd, check=check, capture_output=True, text=True\n        )\n        return result\n    else:\n        subprocess.run(cmd, cwd=cwd, check=check)\n\n\ndef ensure_directory(path):\n    \"\"\"Ensure directory exists.\"\"\"\n    path.mkdir(parents=True, exist_ok=True)\n\n\ndef build_cpp_engine(use_docker=False):\n    \"\"\"Build SCQL C++ engine using Bazel.\"\"\"\n    print(\"\\n>>> [1/3] Building C++ Engine with Bazel...\")\n\n    if use_docker:\n        print(\n            \"🐳 Using Docker container for engine compilation (avoids glibc compatibility issues)\"\n        )\n    else:\n        print(\"🔧 Using local environment for engine compilation\")\n\n    os.chdir(SCQL_ROOT)\n\n    if use_docker:\n        # Use global Docker builder if available (when called from main with args.docker)\n        docker_builder = globals().get(\"docker_builder\")\n        if docker_builder is None:\n            # Initialize Docker builder for standalone calls\n            docker_builder = DockerEngineBuilder(SCQL_ROOT)\n\n            # Ensure container is running\n            if not docker_builder.ensure_container_running():\n                raise RuntimeError(\"Failed to start Docker container\")\n\n        # Temporarily modify .bazelrc in container to add TLS option\n        with BazelRcManager(SCQL_ROOT, use_docker=True, docker_builder=docker_builder):\n            # Build with Bazel in container\n            docker_builder.execute_in_container(\n                [\n                    \"bazelisk\",\n                    \"build\",\n                    \"//python/engine:scql_engine\",\n                    \"-c\",\n                    \"opt\",\n                ]\n            )\n\n        # Copy artifacts from container to host\n        container_build_path = \"/home/admin/dev/bazel-bin/python/engine/scql_engine.so\"\n        target_file = BUILD_ENGINE_DIR / \"scql_engine.so\"\n\n        ensure_directory(BUILD_ENGINE_DIR)\n        docker_builder.copy_from_container(container_build_path, target_file)\n\n        # Verify file was copied\n        if not target_file.exists():\n            raise FileNotFoundError(\n                f\"Engine artifact not found after copy: {target_file}\"\n            )\n\n        print(f\"Built engine to: {target_file}\")\n        print(\"✅ Engine compiled in Docker container for better glibc compatibility\")\n    else:\n        # Local compilation (original logic)\n        with BazelRcManager(SCQL_ROOT, use_docker=False):\n            # Build with Bazel\n            run_command(\n                [\n                    \"bazelisk\",\n                    \"build\",\n                    \"//python/engine:scql_engine\",\n                    \"-c\",\n                    \"opt\",\n                ]\n            )\n\n        # Copy artifacts to build directory\n        bazel_bin = SCQL_ROOT / \"bazel-bin\" / \"python\" / \"engine\"\n        source_file = bazel_bin / \"scql_engine.so\"\n        target_file = BUILD_ENGINE_DIR / \"scql_engine.so\"\n\n        if not source_file.exists():\n            raise FileNotFoundError(f\"Engine artifact not found: {source_file}\")\n\n        ensure_directory(BUILD_ENGINE_DIR)\n        shutil.copy2(source_file, target_file)\n        print(f\"Built engine to: {target_file}\")\n\n\ndef build_go_compiler():\n    \"\"\"Build SCQL Go compiler using gopy.\"\"\"\n    print(\"\\n>>> [2/3] Building Go Compiler with gopy...\")\n\n    os.chdir(SCQL_ROOT)\n\n    # Install gopy if not present\n    try:\n        run_command([\"gopy\", \"--version\"], capture_output=True)\n    except (subprocess.CalledProcessError, FileNotFoundError):\n        print(\"Installing gopy...\")\n        run_command([\"go\", \"install\", \"github.com/go-python/gopy@latest\"])\n\n    # Build Go bindings\n    ensure_directory(BUILD_COMPILER_DIR)\n    run_command(\n        [\n            \"gopy\",\n            \"build\",\n            \"-output\",\n            str(BUILD_COMPILER_DIR),\n            \"-vm\",\n            PYTHON_VM,\n            \"-name\",\n            \"scql_compiler\",\n            GO_PACKAGE_PATH,\n        ]\n    )\n\n    print(f\"Built compiler to: {BUILD_COMPILER_DIR}\")\n\n\ndef create_package_directory():\n    \"\"\"Create package directory by copying source files.\"\"\"\n    print(\"\\n>>> [3/4] Creating package directory...\")\n\n    if PACKAGE_DIR.exists():\n        shutil.rmtree(PACKAGE_DIR)\n\n    # Copy source directory to package\n    shutil.copytree(SRC_DIR, PACKAGE_DIR)\n    print(f\"Copied source to: {PACKAGE_DIR}\")\n\n\ndef copy_artifacts():\n    \"\"\"Copy artifacts from build directory to package directory.\"\"\"\n    print(\"\\n>>> [4/4] Copying artifacts to package directory...\")\n\n    # Copy engine\n    engine_source = BUILD_ENGINE_DIR / \"scql_engine.so\"\n    engine_target = PKG_ENGINE_DIR / \"scql_engine.so\"\n\n    if engine_source.exists():\n        ensure_directory(PKG_ENGINE_DIR)\n        shutil.copy2(engine_source, engine_target)\n        print(f\"Copied engine to: {engine_target}\")\n    else:\n        print(f\"Warning: Engine artifact not found: {engine_source}\")\n        return False\n\n    # Copy compiler - find actual .so file generated by gopy\n    compiler_sources = list(BUILD_COMPILER_DIR.glob(\"*.so\"))\n\n    if not compiler_sources:\n        print(f\"Warning: No compiler .so files found in {BUILD_COMPILER_DIR}\")\n        return False\n\n    # Use the first .so file found and rename it\n    compiler_source = compiler_sources[0]\n    compiler_target = PKG_COMPILER_DIR / \"scql_compiler.so\"\n\n    ensure_directory(PKG_COMPILER_DIR)\n    shutil.copy2(compiler_source, compiler_target)\n    print(f\"Copied compiler to: {compiler_target}\")\n    print(f\"  Source: {compiler_source}\")\n\n    # Copy any .py files gopy might generate, except __init__.py (keep our modified version)\n    for py_file in BUILD_COMPILER_DIR.glob(\"*.py\"):\n        if py_file.name == \"__init__.py\":\n            print(f\"Skipping {py_file.name} - keeping our modified version\")\n            continue\n        py_target = PKG_COMPILER_DIR / py_file.name\n        shutil.copy2(py_file, py_target)\n        print(f\"Copied compiler Python wrapper: {py_target}\")\n\n    print(\"✅ All artifacts copied to package directory\")\n    return True\n\n\ndef clean_artifacts():\n    \"\"\"Clean build artifacts.\"\"\"\n    print(\"\\n>>> Cleaning build artifacts...\")\n\n    # Clean build directory\n    if BUILD_DIR.exists():\n        print(f\"Removing build directory: {BUILD_DIR}\")\n        shutil.rmtree(BUILD_DIR)\n\n    # Clean package directory\n    if PACKAGE_DIR.exists():\n        print(f\"Removing package directory: {PACKAGE_DIR}\")\n        shutil.rmtree(PACKAGE_DIR)\n\n\ndef main():\n    \"\"\"Main build function.\"\"\"\n    parser = argparse.ArgumentParser(\n        description=\"Build SCQL Python package (engine in Docker, compiler locally)\"\n    )\n\n    # Positional arguments\n    parser.add_argument(\n        \"component\",\n        choices=[\"all\", \"engine\", \"compiler\", \"clean\"],\n        nargs=\"?\",\n        default=\"all\",\n        help=\"Component to build (default: all)\",\n    )\n\n    # Docker options for advanced users\n    parser.add_argument(\n        \"--docker-image\",\n        help=f\"Docker image to use\",\n    )\n    parser.add_argument(\n        \"--docker-name\", help=f\"Docker container name (default: {CONTAINER_NAME})\"\n    )\n    parser.add_argument(\n        \"--docker-restart\",\n        action=\"store_true\",\n        help=\"Force restart Docker container if it exists\",\n    )\n    parser.add_argument(\n        \"--no-docker\",\n        action=\"store_true\",\n        help=\"Build engine locally (not recommended due to glibc compatibility issues)\",\n    )\n\n    args = parser.parse_args()\n\n    print(\"SCQL Python Package Build Script\")\n    print(\"=\" * 50)\n\n    # By default, use Docker for engine compilation unless explicitly disabled\n    use_docker = not args.no_docker and args.component in [\"all\", \"engine\"]\n\n    if use_docker:\n        print(\n            \"🐳 Engine will be built in Docker container for better glibc compatibility\"\n        )\n\n    # Global Docker configuration for containers\n    docker_builder = None\n    if use_docker:\n        container_name = args.docker_name or CONTAINER_NAME\n        docker_builder = DockerEngineBuilder(\n            SCQL_ROOT, container_name, args.docker_image\n        )\n\n        # Ensure container is running with restart option if needed\n        if not docker_builder.ensure_container_running(\n            force_restart=args.docker_restart\n        ):\n            print(\"❌ Failed to start Docker container\")\n            sys.exit(1)\n\n    try:\n        if args.component == \"clean\":\n            clean_artifacts()\n            return\n\n        if args.component in [\"all\", \"engine\"]:\n            build_cpp_engine(use_docker=use_docker)\n\n        if args.component in [\"all\", \"compiler\"]:\n            build_go_compiler()\n\n        if args.component == \"all\":\n            create_package_directory()\n            copy_result = copy_artifacts()\n        elif args.component in [\"engine\", \"compiler\"]:\n            print(\"\\n📦 Build artifacts ready in build directory:\")\n            if BUILD_ENGINE_DIR.exists():\n                print(f\"  Engine: {BUILD_ENGINE_DIR}/\")\n            if BUILD_COMPILER_DIR.exists():\n                print(f\"  Compiler: {BUILD_COMPILER_DIR}/\")\n            copy_result = True\n        else:\n            copy_result = False\n\n        if copy_result and args.component == \"all\":\n            # Build wheel package\n            print(\"\\n>>> Building wheel package...\")\n            os.chdir(PACKAGE_DIR)\n\n            # Build wheel (python -m build will create .whl in a dist/ subdirectory)\n            run_command([\"python\", \"-m\", \"build\", \"--wheel\", \".\"])\n\n            # Fix wheel to include .so files\n            wheel_dir = PACKAGE_DIR / \"dist\"\n            wheel_files = list(wheel_dir.glob(\"*.whl\")) if wheel_dir.exists() else []\n            if wheel_files:\n                original_wheel = wheel_files[0]\n\n                # Extract version from the original wheel filename\n                original_name = original_wheel.stem  # Get name without .whl extension\n                # Name format is: scql-{version}-{python_tag}-{abi_tag}-{platform_tag}\n                # Example: scql-0.1.0.dev20251229-py311-none-any\n                parts = original_name.split(\"-\")\n                version_part = parts[1]  # The second part should be the version\n                fixed_wheel = PACKAGE_DIR / f\"scql-{version_part}-py311-none-any.whl\"\n\n                with tempfile.TemporaryDirectory() as temp_dir:\n                    temp_dir = Path(temp_dir)\n\n                    # Extract wheel\n                    run_command(\n                        [\"unzip\", \"-q\", str(original_wheel), \"-d\", str(temp_dir)]\n                    )\n\n                    # Copy .so files to wheel\n                    engine_so = PKG_ENGINE_DIR / \"scql_engine.so\"\n                    compiler_so = PKG_COMPILER_DIR / \"scql_compiler.so\"\n\n                    if engine_so.exists():\n                        shutil.copy2(\n                            engine_so, temp_dir / \"scql\" / \"engine\" / \"scql_engine.so\"\n                        )\n                        print(\"✅ Added scql_engine.so to wheel\")\n\n                    if compiler_so.exists():\n                        shutil.copy2(\n                            compiler_so,\n                            temp_dir / \"scql\" / \"compiler\" / \"scql_compiler.so\",\n                        )\n                        print(\"✅ Added scql_compiler.so to wheel\")\n\n                    # Create fixed wheel\n                    old_cwd = os.getcwd()\n                    os.chdir(temp_dir)\n                    run_command([\"zip\", \"-r\", str(fixed_wheel.name), \".\"])\n                    # Move the created wheel to the correct location\n                    temp_wheel = temp_dir / fixed_wheel.name\n                    if temp_wheel.exists():\n                        shutil.move(str(temp_wheel), str(fixed_wheel))\n                    os.chdir(old_cwd)\n\n                    # Remove original wheel\n                original_wheel.unlink()\n\n                print(\"\\n✅ Build completed successfully!\")\n                print(\"\\n📦 Distribution package created:\")\n                print(f\"  Build artifacts: {BUILD_DIR}/\")\n                print(f\"  Package directory: {PACKAGE_DIR}/\")\n                print(f\"  Installable wheel: {fixed_wheel}\")\n                print(\"\\n🚀 Installation:\")\n                print(f\"  cd {PACKAGE_DIR}\")\n                print(f\"  uv pip install {fixed_wheel.name}\")\n                print(\"\\n📋 The wheel includes all required components:\")\n                print(\n                    \"  • SCQL compiler with ideal interface (import scql.compiler as sc)\"\n                )\n                print(\"  • SCQL engine for secure execution\")\n                print(\"  • All native binary libraries (.so files)\")\n            else:\n                print(\"❌ No wheel file created!\")\n                sys.exit(1)\n        elif copy_result:\n            print(\"\\n✅ Partial build completed!\")\n        else:\n            print(\"\\n❌ Build failed - no artifacts found!\")\n            sys.exit(1)\n\n    except subprocess.CalledProcessError as e:\n        print(\"\\n❌ Build failed with error:\")\n        print(f\"Command: {' '.join(e.cmd) if e.cmd else 'Unknown'}\")\n        print(f\"Return code: {e.returncode}\")\n        sys.exit(1)\n    except Exception as e:\n        print(f\"\\n❌ Build failed with exception: {e}\")\n        sys.exit(1)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "python/engine/BUILD.bazel",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# Python bindings for SCQL Engine\nload(\"@pybind11_bazel//:build_defs.bzl\", \"pybind_extension\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\npybind_extension(\n    name = \"scql_engine\",\n    srcs = [\"engine_bindings.cc\"],\n    # Use global-dynamic TLS model to avoid static TLS errors when loading this module\n    # in Python interpreter with pybind11\n    copts = [\"-ftls-model=global-dynamic\"],\n    linkopts = select({\n        \"@platforms//os:linux\": [\n            \"-static-libgcc\",\n            \"-static-libstdc++\",\n            \"-Wl,-Bstatic\",\n            \"-lpthread\",\n            \"-Wl,-Bdynamic\",\n            \"-Wl,--exclude-libs,ALL\",\n        ],\n        \"//conditions:default\": [],\n    }),\n    deps = [\n        \"//api:core_cc_proto\",\n        \"//api:interpreter_cc_proto\",\n        \"//api:status_cc_proto\",\n        \"//engine/core:tensor\",\n        \"//engine/datasource:datasource_adaptor_mgr\",\n        \"//engine/datasource:embed_router\",\n        \"//engine/datasource:router\",\n        \"//engine/framework:exec\",\n        \"//engine/framework:executor\",\n        \"//engine/framework:session\",\n        \"//engine/operator:all_ops_register\",\n        \"//engine/services:pipeline\",\n        \"//engine/services:run_plan_core\",  # new independent RunPlanCore function\n        \"//engine/util:trace_categories\",\n        \"@gflags\",\n        \"@org_apache_arrow//:arrow\",\n        \"@spulib//libspu/core:config\",\n        \"@spulib//libspu/core:context\",\n        \"@spulib//libspu/device:symbol_table\",\n        \"@spulib//libspu/mpc:factory\",\n        \"@yacl//yacl/link\",\n    ],\n)\n"
  },
  {
    "path": "python/engine/engine_bindings.cc",
    "content": "// Copyright 2025 Ant Group Co., Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//   http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <pybind11/numpy.h>\n#include <pybind11/pybind11.h>\n#include <pybind11/stl.h>\n\n#include <memory>\n\n#include \"gflags/gflags.h\"\n#include \"google/protobuf/util/json_util.h\"\n#include \"spdlog/sinks/basic_file_sink.h\"\n#include \"spdlog/spdlog.h\"\n\n#include \"engine/datasource/datasource_adaptor_mgr.h\"\n#include \"engine/datasource/embed_router.h\"\n#include \"engine/datasource/router.h\"\n#include \"engine/framework/party_info.h\"\n#include \"engine/framework/session.h\"\n#include \"engine/operator/all_ops_register.h\"\n#include \"engine/services/run_plan_core.h\"\n\n#include \"api/core.pb.h\"\n#include \"api/engine.pb.h\"\n#include \"api/interpreter.pb.h\"\n#include \"api/status_code.pb.h\"\n#include \"api/subgraph.pb.h\"\n\nnamespace py = pybind11;\n// using namespace scql::engine;\nnamespace scql_pb = ::scql::pb;\n\n// Python Engine Runner\nclass PythonEngineRunner {\n public:\n  PythonEngineRunner(const std::string& party_code,\n                     const std::string& embed_router_conf) {\n    // Initialize gflags with our specific setting (only once)\n    static bool gflags_initialized = false;\n    if (!gflags_initialized) {\n      char argv0[] = \"scql_engine\";\n      char argv1[] = \"--enable_restricted_read_path=false\";\n      char* argv_array[] = {argv0, argv1};\n      char** argv = argv_array;\n      int argc = sizeof(argv_array) / sizeof(argv_array[0]);\n\n      gflags::ParseCommandLineFlags(&argc, &argv, true);\n      gflags_initialized = true;\n    }\n\n    // Initialize operator registration\n    scql::engine::op::RegisterAllOps();\n\n    party_code_ = party_code;\n    ds_router_ = scql::engine::EmbedRouter::FromJsonStr(embed_router_conf);\n    ds_mgr_ = std::make_unique<scql::engine::DatasourceAdaptorMgr>();\n    // TODO: add more options, such as timezone, allowed spu protocols, etc.\n  }\n\n  scql_pb::RunExecutionPlanResponse RunPlan(\n      std::string_view serialized_compile_plan,\n      std::shared_ptr<yacl::link::Context> link_context) {\n    scql_pb::RunExecutionPlanResponse response;\n    if (!link_context) {\n      response.mutable_status()->set_code(scql_pb::Code::INVALID_ARGUMENT);\n      response.mutable_status()->set_message(\"link_context is null\");\n      return response;\n    }\n\n    // Redirect C++ logs to file\n    std::string log_file = \"scql_engine.log\";\n    auto file_sink =\n        std::make_shared<spdlog::sinks::basic_file_sink_mt>(log_file, true);\n    auto engine_logger =\n        std::make_shared<spdlog::logger>(\"engine_logger\", file_sink);\n    spdlog::set_default_logger(engine_logger);\n\n    scql_pb::CompiledPlan compiled_plan;\n    {\n      // Parse proto from serialized_compile_plan in json format\n      google::protobuf::util::JsonParseOptions options;\n      options.ignore_unknown_fields = true;\n      auto status = google::protobuf::util::JsonStringToMessage(\n          std::string(serialized_compile_plan), &compiled_plan, options);\n      if (!status.ok()) {\n        response.mutable_status()->set_code(scql_pb::Code::INVALID_ARGUMENT);\n        response.mutable_status()->set_message(\"Failed to parse JSON plan: \" +\n                                               std::string(status.message()));\n        return response;\n      }\n    }\n\n    try {\n      auto request = ConvertPlanToRequest(compiled_plan);\n      auto session = CreateSessionFromContext(compiled_plan, link_context);\n      session->SetState(scql::engine::SessionState::RUNNING);\n      scql::engine::RunPlanCore(request, session.get(), &response);\n      session->GetLink()->WaitLinkTaskFinish();\n    } catch (const std::exception& e) {\n      // Convert exception information to error status in response\n      response.mutable_status()->set_code(scql_pb::Code::UNKNOWN_ENGINE_ERROR);\n      response.mutable_status()->set_message(\"Engine execution failed: \" +\n                                             std::string(e.what()));\n    }\n\n    return response;\n  }\n\n private:\n  // Directly construct Session using provided Context and basic parameters\n  std::unique_ptr<scql::engine::Session> CreateSessionFromContext(\n      const scql_pb::CompiledPlan& plan,\n      std::shared_ptr<yacl::link::Context> link_context) {\n    scql::engine::PartyInfo party_info(party_code_, plan.parties());\n    return std::make_unique<scql::engine::Session>(\n        party_info, plan.spu_runtime_conf(), ds_router_.get(), ds_mgr_.get(),\n        link_context);\n  }\n\n  scql_pb::RunExecutionPlanRequest ConvertPlanToRequest(\n      const scql_pb::CompiledPlan& compile_plan) {\n    scql_pb::RunExecutionPlanRequest request;\n    auto iter = compile_plan.sub_graphs().find(party_code_);\n    if (iter == compile_plan.sub_graphs().end()) {\n      throw std::runtime_error(\"no subgraph found for party: \" + party_code_);\n    }\n    request.mutable_graph()->CopyFrom(iter->second);\n    return request;\n  }\n\n private:\n  std::string party_code_;\n  std::unique_ptr<scql::engine::Router> ds_router_;\n  std::unique_ptr<scql::engine::DatasourceAdaptorMgr> ds_mgr_;\n};\n\n// Pybind11 module definition\nPYBIND11_MODULE(scql_engine, m) {\n  m.doc() = \"SCQL Engine Python Bindings\";\n\n  // Bind core classes\n  py::class_<PythonEngineRunner>(m, \"Engine\")\n      .def(py::init<const std::string&, const std::string&>(),\n           \"Create SCQL Engine instance with party code and embed_router_conf \"\n           \"string\",\n           py::arg(\"party_code\"), py::arg(\"embed_router_conf\"))\n      .def(\"run_plan\", &PythonEngineRunner::RunPlan,\n           \"Run execution plan with request and link context\",\n           py::arg(\"request\"), py::arg(\"link_context\"),\n           py::call_guard<py::gil_scoped_release>(),\n           py::return_value_policy::copy);\n\n  // Fully bind RunExecutionPlanResponse, Python uses original response object\n  // directly\n  py::class_<scql_pb::RunExecutionPlanResponse>(m, \"RunExecutionPlanResponse\")\n      .def(py::init<>(), \"Create empty response\")\n      .def(\"status\", &scql_pb::RunExecutionPlanResponse::status,\n           \"Get execution status\", py::return_value_policy::reference)\n      .def(\n          \"out_columns\",\n          [](const scql_pb::RunExecutionPlanResponse& self) {\n            // Return list of output columns\n            std::vector<scql_pb::Tensor> columns;\n            for (const auto& col : self.out_columns()) {\n              columns.push_back(col);\n            }\n            return columns;\n          },\n          \"Get output columns\")\n      .def(\"num_rows_affected\",\n           &scql_pb::RunExecutionPlanResponse::num_rows_affected,\n           \"Get number of rows affected\")\n      .def(\n          \"is_success\",\n          [](const scql_pb::RunExecutionPlanResponse& self) {\n            return self.status().code() == scql_pb::Code::OK;\n          },\n          \"Check if execution was successful\")\n      .def(\n          \"get_error_message\",\n          [](const scql_pb::RunExecutionPlanResponse& self) {\n            if (self.status().code() == scql_pb::Code::OK) {\n              return std::string(\"\");\n            }\n            return self.status().message();\n          },\n          \"Get error message if execution failed\")\n      .def(\"__str__\",\n           [](const scql_pb::RunExecutionPlanResponse& self) {\n             return self.DebugString();\n           })\n      .def(\"__repr__\", [](const scql_pb::RunExecutionPlanResponse& self) {\n        return self.DebugString();\n      });\n\n  // Bind Status class\n  py::class_<scql_pb::Status>(m, \"Status\")\n      .def(py::init<>())\n      .def(\"code\", &scql_pb::Status::code)\n      .def(\"message\", &scql_pb::Status::message)\n      .def(\"set_code\",\n           [](scql_pb::Status& self, int code) {\n             self.set_code(static_cast<scql_pb::Code>(code));\n           })\n      .def(\"set_message\", [](scql_pb::Status& self, const std::string& msg) {\n        self.set_message(msg);\n      });\n\n  // Bind PrimitiveDataType enum\n  py::enum_<scql_pb::PrimitiveDataType>(m, \"PrimitiveDataType\")\n      .value(\"UNDEFINED\",\n             scql_pb::PrimitiveDataType::PrimitiveDataType_UNDEFINED)\n      .value(\"INT8\", scql_pb::PrimitiveDataType::INT8)\n      .value(\"INT16\", scql_pb::PrimitiveDataType::INT16)\n      .value(\"INT32\", scql_pb::PrimitiveDataType::INT32)\n      .value(\"INT64\", scql_pb::PrimitiveDataType::INT64)\n      .value(\"FLOAT32\", scql_pb::PrimitiveDataType::FLOAT32)\n      .value(\"FLOAT64\", scql_pb::PrimitiveDataType::FLOAT64)\n      .value(\"BOOL\", scql_pb::PrimitiveDataType::BOOL)\n      .value(\"STRING\", scql_pb::PrimitiveDataType::STRING)\n      .value(\"DATETIME\", scql_pb::PrimitiveDataType::DATETIME)\n      .value(\"TIMESTAMP\", scql_pb::PrimitiveDataType::TIMESTAMP);\n\n  // Bind TensorShape class\n  py::class_<scql_pb::TensorShape>(m, \"TensorShape\")\n      .def(py::init<>())\n      .def(\"dim_size\", &scql_pb::TensorShape::dim_size)\n      .def(\n          \"dim\",\n          [](const scql_pb::TensorShape& self, int index) {\n            return self.dim(index);\n          },\n          py::return_value_policy::reference);\n\n  // Bind TensorShape::Dimension class\n  py::class_<scql_pb::TensorShape_Dimension>(m, \"TensorShape_Dimension\")\n      .def(\"dim_value\", &scql_pb::TensorShape_Dimension::dim_value)\n      .def(\"dim_param\", &scql_pb::TensorShape_Dimension::dim_param)\n      .def(\"has_dim_value\", &scql_pb::TensorShape_Dimension::has_dim_value)\n      .def(\"has_dim_param\", &scql_pb::TensorShape_Dimension::has_dim_param);\n\n  // Bind Tensor class for output results - full version supports accessing\n  // element data\n  py::class_<scql_pb::Tensor>(m, \"Tensor\")\n      .def(py::init<>())\n      .def(\"name\", &scql_pb::Tensor::name)\n      .def(\n          \"elem_type\",\n          [](const scql_pb::Tensor& self) {\n            return static_cast<int>(self.elem_type());\n          },\n          \"Get element type as integer\")\n      .def(\"shape\", &scql_pb::Tensor::shape, py::return_value_policy::reference)\n      .def(\n          \"int32_data\",\n          [](const scql_pb::Tensor& self) {\n            return py::array_t<int32_t>(self.int32_data().size(),\n                                        self.int32_data().data());\n          },\n          \"Get int32 data as numpy array\")\n      .def(\n          \"int64_data\",\n          [](const scql_pb::Tensor& self) {\n            return py::array_t<int64_t>(self.int64_data().size(),\n                                        self.int64_data().data());\n          },\n          \"Get int64 data as numpy array\")\n      .def(\n          \"float_data\",\n          [](const scql_pb::Tensor& self) {\n            return py::array_t<float>(self.float_data().size(),\n                                      self.float_data().data());\n          },\n          \"Get float32 data as numpy array\")\n      .def(\n          \"double_data\",\n          [](const scql_pb::Tensor& self) {\n            return py::array_t<double>(self.double_data().size(),\n                                       self.double_data().data());\n          },\n          \"Get float64 data as numpy array\")\n      .def(\n          \"bool_data\",\n          [](const scql_pb::Tensor& self) {\n            return py::array_t<bool>(self.bool_data().size(),\n                                     self.bool_data().data());\n          },\n          \"Get bool data as numpy array\")\n      .def(\n          \"string_data\",\n          [](const scql_pb::Tensor& self) {\n            std::vector<std::string> result;\n            result.reserve(self.string_data().size());\n            for (const auto& str : self.string_data()) {\n              result.push_back(str);\n            }\n            return result;\n          },\n          \"Get string data as list\")\n      .def(\n          \"data_validity\",\n          [](const scql_pb::Tensor& self) {\n            return py::array_t<bool>(self.data_validity().size(),\n                                     self.data_validity().data());\n          },\n          \"Get data validity mask as numpy array\")\n      .def(\"__str__\",\n           [](const scql_pb::Tensor& self) { return self.DebugString(); })\n      .def(\"__repr__\",\n           [](const scql_pb::Tensor& self) { return self.DebugString(); });\n}\n"
  },
  {
    "path": "python/src/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "python/src/README.md",
    "content": "# SCQL Python Package\n\nSecure Collaborative Query Language (SCQL) Python bindings for compiling SQL queries and executing them on secure multi-party computation engine.\n\n## Overview\n\nSCQL Python package provides two main components:\n\n- **SCQL Compiler**: Translates SQL queries into secure multi-party computation execution plans\n- **SCQL Engine**: Executes the compiled plans on secure multi-party computation engine\n\n## Requirements\n\n- Python 3.11\n- Linux x86_64\n\n## Installation\n\n```bash\npip install scql\n```\n\n## Usage\n\n```python\nimport scql\n\n# Build catalog\ncatalog = scql.compiler.Catalog()\ntable = scql.compiler.TableEntry()\ntable.Name = \"users\"\ntable.Db = \"test_db\"\ntable.Owner = \"alice\"\n\n# Add columns\ncol1 = scql.compiler.Column()\ncol1.Name = \"id\"\ncol1.Type = \"INT64\"\ntable.AddColumn(col1)\n\ncol2 = scql.compiler.Column()\ncol2.Name = \"name\"\ncol2.Type = \"STRING\"\ntable.AddColumn(col2)\n\ncatalog.AddTableEntry(table)\n\n# Compile SQL query\ninputs = scql.compiler.CompileInputs()\ninputs.Query = \"SELECT id FROM users WHERE name = 'alice'\"\ninputs.Issuer = \"alice\"\ninputs.Db = \"test_db\"\ninputs.Catalog = catalog\n\n# Compile to execution plan\nresult = scql.compiler.Compile(inputs)\nprint(f\"Operator graph: {result.OperatorGraph}\")\nprint(f\"Marshaled plan size: {len(result.MarshaledPlan)} bytes\")\n\n# Execute with engine (requires link context setup)\nengine = scql.engine.Engine(\"alice\", '{\"router_type\": \"embed\"}')\n# execution_response = engine.run_plan(result.MarshaledPlan, link_context)\n```\n\n## Architecture\n\nThe SCQL Python package provides:\n\n- **Compiler Module**: SQL query compilation and planning\n- **Engine Module**: Secure multi-party computation execution\n- **Unified Interface**: Single package with integrated functionality\n\n## License\n\nApache License 2.0\n"
  },
  {
    "path": "python/src/pyproject.toml",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n[build-system]\nrequires = [\n    \"setuptools>=61.0\",\n    \"wheel\",\n]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"scql\"\nversion = \"0.1.1.dev20260104\"\ndescription = \"Python binding for SCQL(Secure Collaborative Query Language)\"\nreadme = \"README.md\"\nlicense = \"Apache-2.0\"\nauthors = [\n    {name = \"SecretFlow Team\", email = \"secretflow-contact@service.alipay.com\"},\n]\nkeywords = [\"scql\", \"secure-computation\", \"sql\", \"mppc\", \"privacy-preserving\"]\nclassifiers = [\n    \"Development Status :: 4 - Beta\",\n    \"Intended Audience :: Developers\",\n    \"Intended Audience :: Science/Research\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Operating System :: Linux\",\n    \"Topic :: Scientific/Engineering\",\n    \"Topic :: Security :: Cryptography\",\n    \"Topic :: Database\",\n]\nrequires-python = \">=3.11,<3.12\"\ndependencies = []\n\n[tool.setuptools.packages.find]\nwhere = [\".\"]\ninclude = [\"scql*\"]\nexclude = [\"tests*\"]\n\n[tool.setuptools.package-data]\nscql = [\"*.so\", \"*.dll\", \"*.dylib\"]\n"
  },
  {
    "path": "python/src/scql/__init__.py",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"SCQL Python Package\n\nSecure Collaborative Query Language (SCQL) Python bindings for compiling\nSQL queries and executing them on secure multi-party computation engine.\n\nFor detailed documentation and usage examples, see:\nhttps://github.com/secretflow/scql/tree/main/python/README.md\n\"\"\"\n\nfrom . import compiler\nfrom . import engine\n\n__version__ = \"0.1.0\"\n__all__ = [\"compiler\", \"engine\"]\n"
  },
  {
    "path": "python/src/scql/compiler/__init__.py",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"SCQL Compiler Module\n\nProvides Python bindings for SCQL compiler that translates SQL queries\ninto secure multi-party computation execution plans.\n\"\"\"\n\ntry:\n    # Try import with correct module name (gopy uses underscore prefix)\n    import importlib.util\n    import os\n\n    # Load the .so file manually\n    so_path = os.path.join(os.path.dirname(__file__), \"scql_compiler.so\")\n    if os.path.exists(so_path):\n        # Load using the correct module name and make it available as _scql_compiler\n        spec = importlib.util.spec_from_file_location(\"_scql_compiler\", so_path)\n        module = importlib.util.module_from_spec(spec)\n        spec.loader.exec_module(module)\n\n        # Make _scql_compiler available for sc.py import\n        globals()[\"_scql_compiler\"] = module\n\n        # Load the sc.py module and merge its interface directly into this module\n        try:\n            from . import sc\n\n            # Expose all sc module classes and functions directly in compiler module\n            for name in dir(sc):\n                if not name.startswith(\"_\"):\n                    obj = getattr(sc, name)\n                    globals()[name] = obj\n\n        except ImportError as sc_error:\n            # If sc.py import fails, fall back to direct low-level interface\n            import warnings\n\n            warnings.warn(\n                f\"Could not import sc.py wrapper: {sc_error}. Using low-level interface.\",\n                ImportWarning,\n            )\n\n            # Expose all symbols from the module for direct access\n            for name in dir(module):\n                if not name.startswith(\"_\"):\n                    globals()[name] = getattr(module, name)\n\n    else:\n        raise ImportError(f\"scql_compiler.so not found in {so_path}\")\n\nexcept Exception as e:\n    import sys\n    import warnings\n\n    warnings.warn(\n        f\"Failed to import SCQL compiler: {e}. \"\n        \"Make sure the Go bindings are properly built.\",\n        ImportWarning,\n    )\n    sys.modules[__name__] = None\n"
  },
  {
    "path": "python/src/scql/engine/__init__.py",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"SCQL Engine Module\n\nProvides Python bindings for SCQL execution engine that runs\nsecure multi-party computation on compiled execution plans.\n\"\"\"\n\ntry:\n    from .scql_engine import *\n\n    print(\"✅ Engine module loaded successfully\")\nexcept ImportError as e:\n    import sys\n    import warnings\n\n    warnings.warn(\n        f\"Failed to import SCQL engine: {e}. \"\n        \"Make sure the C++ bindings are properly built.\",\n        ImportWarning,\n    )\n    print(f\"❌ Engine import failed: {e}\")\n    # Don't set sys.modules[__name__] = None to allow module to be imported\n"
  },
  {
    "path": "python/src/setup.py",
    "content": "# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"SCQL Python Package Setup\n\nThis setup.py is responsible only for packaging the pre-built artifacts.\nUse build.py to build the components first.\n\nUsage:\n    python build.py        # Build all components\n    pip install .          # Package and install\n\"\"\"\n\nfrom setuptools import setup\n\nif __name__ == \"__main__\":\n    setup()\n    # All configuration comes from pyproject.toml\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:recommended\"\n  ],\n  \"labels\": [\n    \"dependencies\"\n  ],\n  \"ignoreDeps\": [\n    \"bazel\"\n  ],\n  \"reviewers\": [\n    \"team:scql-dev\"\n  ]\n}\n\n"
  },
  {
    "path": "scripts/check-whitespace.sh",
    "content": "#!/usr/bin/env bash\n#\n# Check that commits after a specified point do not contain new or modified\n# lines with whitespace errors. An optional formatted summary can be generated\n# by providing an output file path and url as additional arguments.\n#\n\nbaseCommit=$1\noutputFile=$2\nurl=$3\n\nif test \"$#\" -ne 1 && test \"$#\" -ne 3 || test -z \"$1\"\nthen\n\techo \"USAGE: $0 <BASE_COMMIT> [<OUTPUT_FILE> <URL>]\"\n\texit 1\nfi\n\nproblems=()\ncommit=\ncommitText=\ncommitTextmd=\ngoodParent=\n\nif ! git rev-parse --quiet --verify \"${baseCommit}\"\nthen\n    echo \"Invalid <BASE_COMMIT> '${baseCommit}'\"\n    exit 1\nfi\n\nwhile read dash sha etc\ndo\n\tcase \"${dash}\" in\n\t\"---\") # Line contains commit information.\n\t\tif test -z \"${goodParent}\"\n\t\tthen\n\t\t\t# Assume the commit has no whitespace errors until detected otherwise.\n\t\t\tgoodParent=${sha}\n\t\tfi\n\n\t\tcommit=\"${sha}\"\n\t\tcommitText=\"${sha} ${etc}\"\n\t\tcommitTextmd=\"[${sha}](${url}/commit/${sha}) ${etc}\"\n\t\t;;\n\t\"\")\n\t\t;;\n\t*) # Line contains whitespace error information for current commit.\n\t\tif test -n \"${goodParent}\"\n\t\tthen\n\t\t\tproblems+=(\"1) --- ${commitTextmd}\")\n\t\t\techo \"\"\n\t\t\techo \"--- ${commitText}\"\n\t\t\tgoodParent=\n\t\tfi\n\n\t\tcase \"${dash}\" in\n\t\t*:[1-9]*:) # contains file and line number information\n\t\t\tdashend=${dash#*:}\n\t\t\tproblems+=(\"[${dash}](${url}/blob/${commit}/${dash%%:*}#L${dashend%:}) ${sha} ${etc}\")\n\t\t\t;;\n\t\t*)\n\t\t\tproblems+=(\"\\`${dash} ${sha} ${etc}\\`\")\n\t\t\t;;\n\t\tesac\n\t\techo \"${dash} ${sha} ${etc}\"\n\t\t;;\n\tesac\ndone <<< \"$(git diff --check \"${baseCommit}\" HEAD -- . ':(exclude)*.patch')\"\n\nif test ${#problems[*]} -gt 0\nthen\n\tif test -z \"${goodParent}\"\n\tthen\n\t\tgoodParent=${baseCommit: 0:7}\n\tfi\n\n\techo \"A whitespace issue was found in one or more of the commits.\"\n\techo \"Run the following command to resolve whitespace issues:\"\n\techo \"git rebase --whitespace=fix ${goodParent}\"\n\n\t# If target output file is provided, write formatted output.\n\tif test -n \"$outputFile\"\n\tthen\n\t\techo \"🛑 Please review the Summary output for further information.\"\n\t\t(\n\t\t\techo \"### :x: A whitespace issue was found in one or more of the commits.\"\n\t\t\techo \"\"\n\t\t\techo \"Run these commands to correct the problem:\"\n\t\t\techo \"1. \\`git rebase --whitespace=fix ${goodParent}\\`\"\n\t\t\techo \"1. \\`git push --force\\`\"\n\t\t\techo \"\"\n\t\t\techo \"Errors:\"\n\n\t\t\tfor i in \"${problems[@]}\"\n\t\t\tdo\n\t\t\t\techo \"${i}\"\n\t\t\tdone\n\t\t) >\"$outputFile\"\n\tfi\n\n\texit 2\nfi\n"
  },
  {
    "path": "scripts/format/clang-format.sh",
    "content": "#!/bin/bash\n\nfind . -type f \\( -name \"*.cpp\" -o -name \"*.cc\" -o -name \"*.h\" -o -name \"*.hpp\" -o -name \"*.proto\" \\) \\\n  -exec clang-format-19 -i {} +\n\necho \"All source and proto files formatted with clang-format-19.\"\n"
  },
  {
    "path": "scripts/graph-visualization/dot2js.py",
    "content": "# Copyright 2024 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\nimport os\nimport re\n\n\ndef parse_dot_file(dot_file_path):\n    nodes = []\n    links = []\n\n    with open(dot_file_path, \"r\") as file:\n        lines = file.readlines()\n\n    node_pattern = re.compile(r'(\\d+) \\[label=\"(.+?)\"\\]')\n    link_pattern = re.compile(r'(\\d+) -> (\\d+) \\[label = \"(.+?)\"\\]')\n\n    for line in lines:\n        node_match = node_pattern.match(line)\n        if node_match:\n            nodes.append(\n                {\n                    \"id\": int(node_match.group(1)),\n                    \"label\": node_match.group(2),\n                }\n            )\n        else:\n            link_match = link_pattern.match(line)\n            if link_match:\n                links.append(\n                    {\n                        \"source\": int(link_match.group(1)),\n                        \"target\": int(link_match.group(2)),\n                        \"label\": link_match.group(3),\n                    }\n                )\n\n    return nodes, links\n\n\ndef generate_js_data(nodes, links):\n    js_data = \"const data = {\\n\"\n\n    js_data += \"    nodes: [\\n\"\n    for node in nodes:\n        js_data += f'        {{ id: {node[\"id\"]}, label: \"{node[\"label\"]}\" }},\\n'\n    js_data += \"    ],\\n\"\n\n    js_data += \"    links: [\\n\"\n    for link in links:\n        js_data += f'        {{ source: {link[\"source\"]}, target: {link[\"target\"]}, label: \"{link[\"label\"]}\" }},\\n'\n    js_data += \"    ]\\n\"\n\n    js_data += \"};\\n\"\n    return js_data\n\n\ndef insert_js_data_into_html(html_template_path, js_data, output_path):\n    with open(html_template_path, \"r\") as file:\n        html_content = file.read()\n\n    modified_html_content = re.sub(\n        r\"const data = {[^}]*};\", js_data, html_content, flags=re.DOTALL\n    )\n\n    with open(output_path, \"w\") as file:\n        file.write(modified_html_content)\n\n\nif __name__ == \"__main__\":\n    script_directory = os.path.dirname(os.path.abspath(__file__))\n\n    dot_file_path = os.path.join(script_directory, \"graph.dot\")\n    html_template_path = os.path.join(script_directory, \"template.html\")\n    output_path = os.path.join(script_directory, \"graph_visualization.html\")\n\n    nodes, links = parse_dot_file(dot_file_path)\n    js_data = generate_js_data(nodes, links)\n    insert_js_data_into_html(html_template_path, js_data, output_path)\n\n    print(\"HTML file generated successfully.\")\n"
  },
  {
    "path": "scripts/graph-visualization/graph.dot",
    "content": "digraph G {\n0 [label=\"runsql:{in:[],out:[Out:{t_0,t_1,t_2,t_3,},],attr:[sql:select user_credit.ID,user_credit.age,user_credit.credit_rank,user_credit.income from alice.user_credit where (user_credit.age>=20) and (user_credit.age<=30),table_refs:[alice.user_credit],],party:[alice,]}\"]\n1 [label=\"runsql:{in:[],out:[Out:{t_4,t_5,t_6,},],attr:[sql:select user_stats.ID,user_stats.is_active,user_stats.order_amount from bob.user_stats where user_stats.is_active=1,table_refs:[bob.user_stats],],party:[bob,]}\"]\n2 [label=\"join:{in:[Left:{t_0,},Right:{t_4,},],out:[LeftJoinIndex:{t_7,},RightJoinIndex:{t_8,},],attr:[input_party_codes:[alice bob],join_type:0,psi_algorithm:0,],party:[alice,bob,]}\"]\n3 [label=\"filter_by_index:{in:[Data:{t_0,t_1,t_2,t_3,},RowsIndexFilter:{t_7,},],out:[Out:{t_9,t_10,t_11,t_12,},],attr:[],party:[alice,]}\"]\n4 [label=\"filter_by_index:{in:[Data:{t_4,t_5,t_6,},RowsIndexFilter:{t_8,},],out:[Out:{t_13,t_14,t_15,},],attr:[],party:[bob,]}\"]\n5 [label=\"make_share:{in:[In:{t_11,},],out:[Out:{t_16,},],attr:[],party:[alice,bob,]}\"]\n6 [label=\"make_share:{in:[In:{t_9,},],out:[Out:{t_17,},],attr:[],party:[alice,bob,]}\"]\n7 [label=\"make_share:{in:[In:{t_10,},],out:[Out:{t_18,},],attr:[],party:[alice,bob,]}\"]\n8 [label=\"make_share:{in:[In:{t_12,},],out:[Out:{t_19,},],attr:[],party:[alice,bob,]}\"]\n9 [label=\"make_share:{in:[In:{t_13,},],out:[Out:{t_20,},],attr:[],party:[alice,bob,]}\"]\n10 [label=\"make_share:{in:[In:{t_14,},],out:[Out:{t_21,},],attr:[],party:[alice,bob,]}\"]\n11 [label=\"make_share:{in:[In:{t_15,},],out:[Out:{t_22,},],attr:[],party:[alice,bob,]}\"]\n12 [label=\"sort:{in:[In:{t_16,t_17,t_18,t_16,t_19,t_20,t_21,t_22,},Key:{t_16,},],out:[Out:{t_23,t_24,t_25,t_26,t_27,t_28,t_29,t_30,},],attr:[reverse:false,],party:[alice,bob,]}\"]\n13 [label=\"group_mark:{in:[Key:{t_23,},],out:[Group:{t_31,},],attr:[],party:[alice,bob,]}\"]\n14 [label=\"count:{in:[Group:{t_31,},In:{t_31,},],out:[Out:{t_32,},],attr:[],party:[alice,bob,]}\"]\n15 [label=\"avg:{in:[Group:{t_31,},In:{t_27,},],out:[Out:{t_33,},],attr:[],party:[alice,bob,]}\"]\n16 [label=\"avg:{in:[Group:{t_31,},In:{t_30,},],out:[Out:{t_34,},],attr:[],party:[alice,bob,]}\"]\n17 [label=\"shuffle:{in:[In:{t_32,t_33,t_34,t_26,t_31,},],out:[Out:{t_35,t_36,t_37,t_38,t_39,},],attr:[],party:[alice,bob,]}\"]\n18 [label=\"make_public:{in:[In:{t_39,},],out:[Out:{t_40,},],attr:[],party:[alice,bob,]}\"]\n19 [label=\"filter:{in:[Filter:{t_40,},In:{t_35,t_36,t_37,t_38,},],out:[Out:{t_41,t_42,t_43,t_44,},],attr:[],party:[alice,bob,]}\"]\n20 [label=\"make_constant:{in:[],out:[Out:{t_45,},],attr:[scalar:4,to_status:1,],party:[alice,bob,]}\"]\n21 [label=\"broadcast:{in:[In:{t_45,},ShapeRefTensor:{t_41,},],out:[Out:{t_46,},],attr:[],party:[alice,bob,]}\"]\n22 [label=\"make_private:{in:[In:{t_41,},],out:[Out:{t_47,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n23 [label=\"make_private:{in:[In:{t_46,},],out:[Out:{t_48,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n24 [label=\"GreaterEqual:{in:[Left:{t_47,},Right:{t_48,},],out:[Out:{t_49,},],attr:[],party:[alice,]}\"]\n25 [label=\"make_public:{in:[In:{t_49,},],out:[Out:{t_50,},],attr:[],party:[alice,bob,]}\"]\n26 [label=\"apply_filter:{in:[Filter:{t_50,},In:{t_44,t_41,t_42,t_43,},],out:[Out:{t_51,t_52,t_53,t_54,},],attr:[],party:[alice,bob,]}\"]\n27 [label=\"make_private:{in:[In:{t_51,},],out:[Out:{t_55,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n28 [label=\"make_private:{in:[In:{t_52,},],out:[Out:{t_57,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n29 [label=\"make_private:{in:[In:{t_53,},],out:[Out:{t_59,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n30 [label=\"make_private:{in:[In:{t_54,},],out:[Out:{t_61,},],attr:[reveal_to:alice,],party:[alice,bob,]}\"]\n31 [label=\"publish:{in:[In:{t_55,t_57,t_59,t_61,},],out:[Out:{t_56,t_58,t_60,t_62,},],attr:[],party:[alice,]}\"]\n0 -> 2 [label = \"t_0:{ID:PRIVATE:STRING}\"]\n0 -> 3 [label = \"t_0:{ID:PRIVATE:STRING}\"]\n0 -> 3 [label = \"t_1:{age:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_2:{credit_rank:PRIVATE:INT64}\"]\n0 -> 3 [label = \"t_3:{income:PRIVATE:INT64}\"]\n1 -> 2 [label = \"t_4:{ID:PRIVATE:STRING}\"]\n1 -> 4 [label = \"t_4:{ID:PRIVATE:STRING}\"]\n1 -> 4 [label = \"t_5:{is_active:PRIVATE:INT64}\"]\n1 -> 4 [label = \"t_6:{order_amount:PRIVATE:FLOAT64}\"]\n10 -> 12 [label = \"t_21:{is_active:SECRET:INT64}\"]\n11 -> 12 [label = \"t_22:{order_amount:SECRET:FLOAT64}\"]\n12 -> 13 [label = \"t_23:{credit_rank:SECRET:INT64}\"]\n12 -> 15 [label = \"t_27:{income:SECRET:INT64}\"]\n12 -> 16 [label = \"t_30:{order_amount:SECRET:FLOAT64}\"]\n12 -> 17 [label = \"t_26:{credit_rank:SECRET:INT64}\"]\n13 -> 14 [label = \"t_31:{group_mark:SECRET:BOOL}\"]\n13 -> 14 [label = \"t_31:{group_mark:SECRET:BOOL}\"]\n13 -> 15 [label = \"t_31:{group_mark:SECRET:BOOL}\"]\n13 -> 16 [label = \"t_31:{group_mark:SECRET:BOOL}\"]\n13 -> 17 [label = \"t_31:{group_mark:SECRET:BOOL}\"]\n14 -> 17 [label = \"t_32:{group_mark:SECRET:INT64}\"]\n15 -> 17 [label = \"t_33:{income:SECRET:FLOAT64}\"]\n16 -> 17 [label = \"t_34:{order_amount:SECRET:FLOAT64}\"]\n17 -> 18 [label = \"t_39:{group_mark:SECRET:BOOL}\"]\n17 -> 19 [label = \"t_35:{group_mark:SECRET:INT64}\"]\n17 -> 19 [label = \"t_36:{income:SECRET:FLOAT64}\"]\n17 -> 19 [label = \"t_37:{order_amount:SECRET:FLOAT64}\"]\n17 -> 19 [label = \"t_38:{credit_rank:SECRET:INT64}\"]\n18 -> 19 [label = \"t_40:{group_mark:PUBLIC:BOOL}\"]\n19 -> 21 [label = \"t_41:{group_mark:SECRET:INT64}\"]\n19 -> 22 [label = \"t_41:{group_mark:SECRET:INT64}\"]\n19 -> 26 [label = \"t_41:{group_mark:SECRET:INT64}\"]\n19 -> 26 [label = \"t_42:{income:SECRET:FLOAT64}\"]\n19 -> 26 [label = \"t_43:{order_amount:SECRET:FLOAT64}\"]\n19 -> 26 [label = \"t_44:{credit_rank:SECRET:INT64}\"]\n2 -> 3 [label = \"t_7:{ID:PRIVATE:INT64}\"]\n2 -> 4 [label = \"t_8:{ID:PRIVATE:INT64}\"]\n20 -> 21 [label = \"t_45:{constant_data:PUBLIC:INT64}\"]\n21 -> 23 [label = \"t_46:{constant_data:PUBLIC:INT64}\"]\n22 -> 24 [label = \"t_47:{group_mark:PRIVATE:INT64}\"]\n23 -> 24 [label = \"t_48:{constant_data:PRIVATE:INT64}\"]\n24 -> 25 [label = \"t_49:{GreaterEqual_out:PRIVATE:BOOL}\"]\n25 -> 26 [label = \"t_50:{GreaterEqual_out:PUBLIC:BOOL}\"]\n26 -> 27 [label = \"t_51:{credit_rank:SECRET:INT64}\"]\n26 -> 28 [label = \"t_52:{group_mark:SECRET:INT64}\"]\n26 -> 29 [label = \"t_53:{income:SECRET:FLOAT64}\"]\n26 -> 30 [label = \"t_54:{order_amount:SECRET:FLOAT64}\"]\n27 -> 31 [label = \"t_55:{credit_rank:PRIVATE:INT64}\"]\n28 -> 31 [label = \"t_57:{group_mark:PRIVATE:INT64}\"]\n29 -> 31 [label = \"t_59:{income:PRIVATE:FLOAT64}\"]\n3 -> 5 [label = \"t_11:{credit_rank:PRIVATE:INT64}\"]\n3 -> 6 [label = \"t_9:{ID:PRIVATE:STRING}\"]\n3 -> 7 [label = \"t_10:{age:PRIVATE:INT64}\"]\n3 -> 8 [label = \"t_12:{income:PRIVATE:INT64}\"]\n30 -> 31 [label = \"t_61:{order_amount:PRIVATE:FLOAT64}\"]\n4 -> 10 [label = \"t_14:{is_active:PRIVATE:INT64}\"]\n4 -> 11 [label = \"t_15:{order_amount:PRIVATE:FLOAT64}\"]\n4 -> 9 [label = \"t_13:{ID:PRIVATE:STRING}\"]\n5 -> 12 [label = \"t_16:{credit_rank:SECRET:INT64}\"]\n5 -> 12 [label = \"t_16:{credit_rank:SECRET:INT64}\"]\n5 -> 12 [label = \"t_16:{credit_rank:SECRET:INT64}\"]\n6 -> 12 [label = \"t_17:{ID:SECRET:STRING}\"]\n7 -> 12 [label = \"t_18:{age:SECRET:INT64}\"]\n8 -> 12 [label = \"t_19:{income:SECRET:INT64}\"]\n9 -> 12 [label = \"t_20:{ID:SECRET:STRING}\"]\n}"
  },
  {
    "path": "scripts/graph-visualization/template.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Graph Visualization</title>\n    <script src=\"https://d3js.org/d3.v6.min.js\"></script>\n    <style>\n        .node circle {\n            cursor: pointer;\n        }\n\n        .node text {\n            font: 12px sans-serif;\n            pointer-events: none;\n            fill: #333;\n        }\n\n        .link {\n            fill: none;\n            stroke: #999;\n            stroke-width: 2px;\n            cursor: pointer;\n        }\n\n        .arrowhead {\n            fill: #999;\n        }\n\n        .tooltip {\n            position: absolute;\n            text-align: center;\n            width: auto;\n            height: auto;\n            padding: 8px;\n            font: 12px sans-serif;\n            background: lightsteelblue;\n            border: 1px solid #aaa;\n            border-radius: 4px;\n            pointer-events: none;\n            opacity: 0;\n            white-space: pre-wrap;\n        }\n\n        .legend text {\n            font: 12px sans-serif;\n        }\n    </style>\n</head>\n\n<body>\n    <div id=\"tooltip\" class=\"tooltip\"></div>\n    <script>\n        const data = {\n            // Your nodes and links here\n        };\n\n        const width = window.innerWidth;\n        const height = window.innerHeight;\n\n        // Calculate each node's level\n        function calculateNodeLevels(nodes, links) {\n            const nodeLevels = {};\n            const inDegree = {};\n            const nodesSet = new Set(nodes.map(d => d.id));\n\n            nodes.forEach(node => {\n                inDegree[node.id] = 0;\n            });\n\n            links.forEach(link => {\n                inDegree[link.target]++;\n            });\n\n            let currentLevel = 0;\n            let maxLevel = 0;\n            while (nodesSet.size > 0) {\n                const currentLevelNodes = Array.from(nodesSet).filter(node => inDegree[node] === 0);\n                currentLevelNodes.forEach(node => {\n                    nodeLevels[node] = currentLevel;\n                    nodesSet.delete(node);\n                    links.forEach(link => {\n                        if (link.source === node) {\n                            inDegree[link.target]--;\n                        }\n                    });\n                });\n                maxLevel = currentLevel;\n                currentLevel++;\n            }\n            return { nodeLevels, levels: maxLevel + 1 };\n        }\n        const { nodeLevels, levels } = calculateNodeLevels(data.nodes, data.links);\n        const levelHeight = levels > 10 ? height * 2 / levels : height / levels;\n\n        // Combine links with the same source and target\n        const combinedLinks = {};\n        data.links.forEach(link => {\n            const key = `${link.source}-${link.target}`;\n            if (combinedLinks[key]) {\n                combinedLinks[key].label += `\\n${link.label}`;\n            } else {\n                combinedLinks[key] = { ...link };\n            }\n        });\n        const combinedLinksArray = Object.values(combinedLinks);\n\n        const colors = d3.schemeCategory10.filter(c => c !== '#ff0000'); // Excluding red\n        const partyColors = {};\n        let colorIndex = 0;\n\n        data.nodes.forEach(node => {\n            const parties = node.label.match(/party:\\[([^\\]]+)\\]/);\n            if (parties) {\n                const partyList = parties[1].split(',').map(party => party.trim()).slice(0, -1); // Exclude the last element\n                if (partyList.length === 1) {\n                    const party = partyList[0];\n                    if (!partyColors[party]) {\n                        partyColors[party] = colors[colorIndex % colors.length];\n                        colorIndex++;\n                    }\n                } else {\n                    partyColors[partyList.join(',')] = '#ff0000'; // Use red for nodes with multiple parties\n                }\n            }\n        });\n\n        // Adjust node levels based on the minimum target level\n        data.nodes.forEach(d => {\n            const linkedTargets = combinedLinksArray.filter(link => link.source === d.id).map(link => nodeLevels[link.target]);\n            const minTargetLevel = d3.min(linkedTargets);\n            const nodeLevel = nodeLevels[d.id];\n            if (minTargetLevel - nodeLevel > 1) {\n                nodeLevels[d.id] = minTargetLevel - 1;\n            }\n        });\n\n        // Add random x offset to nodes to avoid overlap\n        const xOffset = 20;\n        data.nodes.forEach(d => {\n            d.xOffset = (Math.random() - 0.5) * xOffset;\n        });\n\n        const svg = d3.select(\"body\").append(\"svg\")\n            .attr(\"width\", width)\n            .attr(\"height\", height)\n            .call(d3.zoom().on(\"zoom\", (event) => {\n                svg.attr(\"transform\", event.transform);\n            }))\n            .append(\"g\");\n\n        // Define arrowhead marker\n        svg.append(\"defs\").append(\"marker\")\n            .attr(\"id\", \"arrowhead\")\n            .attr(\"viewBox\", \"-0 -5 10 10\")\n            .attr(\"refX\", 13)\n            .attr(\"refY\", 0)\n            .attr(\"orient\", \"auto\")\n            .attr(\"markerWidth\", 6)\n            .attr(\"markerHeight\", 6)\n            .attr(\"xoverflow\", \"visible\")\n            .append(\"svg:path\")\n            .attr(\"d\", \"M 0,-5 L 10 ,0 L 0,5\")\n            .attr(\"class\", \"arrowhead\");\n\n        const tooltip = d3.select(\"#tooltip\");\n\n        // Initialize simulation\n        const simulation = d3.forceSimulation(data.nodes)\n            .force(\"link\", d3.forceLink(combinedLinksArray).id(d => d.id).distance(250))\n            .force(\"charge\", d3.forceManyBody().strength(-500))\n            .force(\"center\", d3.forceCenter(width / 2, height / 2))\n            .force(\"y\", d3.forceY().strength(1).y(d => levelHeight * (nodeLevels[d.id] + 1)))\n            .force(\"x\", d3.forceX().strength(1).x(d => {\n                const sameLevelNodes = data.nodes.filter(node => nodeLevels[node.id] === nodeLevels[d.id]);\n                const index = sameLevelNodes.indexOf(d);\n                const xSpacing = width / (sameLevelNodes.length + 1);\n                return xSpacing * (index + 1) + d.xOffset; // Apply random offset\n            }))\n            .alphaTarget(0.3)\n            .on(\"tick\", ticked);\n\n        // Create links\n        const link = svg.append(\"g\")\n            .attr(\"class\", \"links\")\n            .selectAll(\"g\")\n            .data(combinedLinksArray)\n            .enter().append(\"g\")\n            .attr(\"class\", \"link\");\n\n        const linkLine = link.append(\"line\")\n            .attr(\"id\", (d, i) => `link${i}`)\n            .attr(\"marker-end\", \"url(#arrowhead)\")\n            .on(\"mouseover\", function (event, d) {\n                tooltip.transition()\n                    .duration(200)\n                    .style(\"opacity\", .9);\n                tooltip.html(d.label)\n                    .style(\"left\", (event.pageX + 5) + \"px\")\n                    .style(\"top\", (event.pageY - 28) + \"px\");\n            })\n            .on(\"mouseout\", function (d) {\n                tooltip.transition()\n                    .duration(500)\n                    .style(\"opacity\", 0);\n            });\n\n        // Create nodes\n        const node = svg.append(\"g\")\n            .attr(\"class\", \"nodes\")\n            .selectAll(\"g\")\n            .data(data.nodes)\n            .enter().append(\"g\")\n            .attr(\"class\", \"node\")\n            .on(\"mouseover\", function (event, d) {\n                tooltip.transition()\n                    .duration(200)\n                    .style(\"opacity\", .9);\n                tooltip.html(d.label)\n                    .style(\"left\", (event.pageX + 5) + \"px\")\n                    .style(\"top\", (event.pageY - 28) + \"px\");\n            })\n            .on(\"mouseout\", function (d) {\n                tooltip.transition()\n                    .duration(500)\n                    .style(\"opacity\", 0);\n            });\n\n        node.append(\"circle\")\n            .attr(\"r\", 10)\n            .attr(\"fill\", d => {\n                const parties = d.label.match(/party:\\[([^\\]]+)\\]/);\n                if (parties) {\n                    const partyList = parties[1].split(',').map(party => party.trim()).slice(0, -1); // Exclude the last element\n                    if (partyList.length === 1) {\n                        return partyColors[partyList[0]];\n                    } else {\n                        return '#ff0000';\n                    }\n                }\n                return '#69b3a2'; // Default color if no party is specified\n            });\n\n        node.append(\"text\")\n            .attr(\"dy\", -3)\n            .attr(\"x\", 15)\n            .text(d => d.label.split(\":\")[0]);\n\n        // Create legend\n        const legend = svg.append(\"g\")\n            .attr(\"class\", \"legend\")\n            .attr(\"transform\", \"translate(20, 20)\");\n        Object.entries(partyColors).forEach(([party, color], i) => {\n            const legendRow = legend.append(\"g\")\n                .attr(\"transform\", `translate(0, ${i * 20})`);\n\n            legendRow.append(\"rect\")\n                .attr(\"width\", 18)\n                .attr(\"height\", 18)\n                .attr(\"fill\", color);\n\n            legendRow.append(\"text\")\n                .attr(\"x\", 24)\n                .attr(\"y\", 9)\n                .attr(\"dy\", \"0.35em\")\n                .text(party);\n        });\n\n        function ticked() {\n            linkLine\n                .attr(\"x1\", d => d.source.x)\n                .attr(\"y1\", d => d.source.y)\n                .attr(\"x2\", d => d.target.x)\n                .attr(\"y2\", d => d.target.y);\n\n            node\n                .attr(\"transform\", d => `translate(${d.x},${d.y})`);\n        }\n    </script>\n</body>\n\n</html>"
  },
  {
    "path": "test-tools/README.md",
    "content": "# How to use ca_generator.sh\n\nIf you want to enable tls in SCQL but don't have existing CA files, ca_generator.sh can help to generate self-signed CA files.\n\n``NOTE``: Self-signed CA files are ``not safe`` and can only be used for testing. Considering security, commercial CA files must be used in production environments.\n\n## Step 1\n\nRun the command below to generate CA files:\n\n```sh\nbash ca_generator.sh\n```\n\nIf the script completes successfully, you can obtain these CA files as follows:\n\n```sh\n└── tls\n    ├── broker_alice-ca.crt\n    ├── broker_alice-ca.key\n    ├── broker_alice-ca.pem\n    ├── broker_bob-ca.crt\n    ├── broker_bob-ca.key\n    ├── broker_bob-ca.pem\n    ├── broker_carol-ca.crt\n    ├── broker_carol-ca.key\n    ├── broker_carol-ca.pem\n    ├── engine_alice-ca.crt\n    ├── engine_alice-ca.key\n    ├── engine_alice-ca.pem\n    ├── engine_bob-ca.crt\n    ├── engine_bob-ca.key\n    ├── engine_bob-ca.pem\n    ├── engine_carol-ca.crt\n    ├── engine_carol-ca.key\n    ├── engine_carol-ca.pem\n    ├── intermediate-ca.crt\n    ├── intermediate-ca.key\n    ├── intermediate-ca.pem\n    ├── root-ca.crt\n    ├── root-ca.key\n    └── root-ca.pem\n```\n\n* broker_xxx-ca.crt and broker_xxx-ca.key are for SCQLBrokers\n* engine_xxx-ca.crt and engine_xxx-ca.key are for SCQLEngines\n* root-ca.*and intermediate-ca.* are files used for signing and you should save them carefully.\n\n## Step 2\n\nDeploy CA files in your environments for SCQL to use:\n> You need to add corresponding files in the environment of each SCQLBroker and SCQLEngine, and specify the relevant path in the configuration. For configuration details, refer to the [Document](https://www.secretflow.org.cn/docs/scql/en/development/scql_config_manual.html)\n\n## Trouble shooting\n\nThe default generated CA files may not work well in your environment, if you encounter problems, please check the following:\n\n* Script default add hosts ``localhost/engine_xxx/broker_xxx`` to ``subjectAltName``, so the generated CA can only be used for these hosts. please modifying if nodes' hosts do not matched.\n  > e.g: If your broker listens on IP xxx, you need to add ``IP.2 = xxx`` to ``[sans]`` in ca_generator.sh\n\n* Auto generated root-ca.crt may not be trusted by default, try to use trusted CA as root-ca.crt and run the script again, please refer to the comments at the beginning of the ca_generator.sh for usage. If and only if in linux ``test environments``, you can optionally cp root-ca.crt to /etc/ssl/certs in the environments running SCQL components\n"
  },
  {
    "path": "test-tools/ca_generator.sh",
    "content": "#!/usr/bin/env bash\n#\n# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# Example SCQL CA certificate generation script.\n# It is mainly modified from https://github.com/k3s-io/k3s/blob/master/contrib/util/generate-custom-ca-certs.sh\n#\n# This script will generate CA files certificate for SCQL to enalbe tls.\n# The required files are default located under `./tls` directory.\n#\n# This script will also auto-generate certificates and keys for both root and intermediate\n# certificate authorities if none are found.\n# If you have existing certs, you must place them in `./tls`.\n# If you have only an existing root CA, provide:\n#   root-ca.pem\n#   root-ca.key\n# If you have an existing root and intermediate CA, provide:\n#   root-ca.pem\n#   intermediate-ca.pem\n#   intermediate-ca.key\n\nset -e\numask 027\n\nTIMESTAMP=$(date +%s)\nPRODUCT=\"SCQL\"\nDATA_DIR=\"./tls\"\n\nif type -t openssl-3 &>/dev/null; then\n  OPENSSL=openssl-3\nelse\n  OPENSSL=openssl\nfi\n\necho \"Using $(type -p ${OPENSSL}): $(${OPENSSL} version)\"\n\nif ! ${OPENSSL} ecparam -name prime256v1 -genkey -noout -out /dev/null &>/dev/null; then\n  echo \"openssl not found or missing Elliptic Curve (ecparam) support.\"\n  exit 1\nfi\n\n${OPENSSL} version | grep -qF 'OpenSSL 3' && OPENSSL_GENRSA_FLAGS=-traditional\n\nmkdir -p \"${DATA_DIR}\"\ncd \"${DATA_DIR}\"\n\n# Set up temporary openssl configuration\nmkdir -p \".ca/certs\"\ntrap \"rm -rf .ca\" EXIT\ntouch .ca/index\nopenssl rand -hex 8 > .ca/serial\ncat >.ca/config <<'EOF'\n[ca]\ndefault_ca = ca_default\n[ca_default]\ndir = ./.ca\ndatabase = $dir/index\nserial = $dir/serial\nnew_certs_dir = $dir/certs\ndefault_md = sha256\npolicy = policy_anything\n[policy_anything]\ncommonName = supplied\n[req]\ndistinguished_name = req_distinguished_name\n[req_distinguished_name]\n[v3_ca]\nsubjectKeyIdentifier = hash\nauthorityKeyIdentifier = keyid:always\nbasicConstraints = critical, CA:true\nkeyUsage = critical, digitalSignature, keyEncipherment, keyCertSign\nsubjectAltName = @sans\n[sans]\nDNS.1 = localhost\nDNS.2 = engine_alice\nDNS.3 = engine_bob\nDNS.4 = engine_carol\nDNS.5 = broker_alice\nDNS.6 = broker_bob\nDNS.7 = broker_carol\nIP.1 = 127.0.0.1\nEOF\n\n# Use existing root CA if present\nif [[ -e root-ca.pem ]]; then\n  echo \"Using existing root certificate\"\nelse\n  echo \"Generating root certificate authority RSA key and certificate\"\n  ${OPENSSL} genrsa ${OPENSSL_GENRSA_FLAGS:-} -out root-ca.key 4096\n  ${OPENSSL} req -x509 -new -nodes -sha256 -days 7300 \\\n                 -subj \"/CN=${PRODUCT}-root-ca@${TIMESTAMP}\" \\\n                 -key root-ca.key \\\n                 -out root-ca.pem \\\n                 -config .ca/config \\\n                 -extensions v3_ca\nfi\ncat root-ca.pem > root-ca.crt\n\n# Use existing intermediate CA if present\nif [[ -e intermediate-ca.pem ]]; then\n  echo \"Using existing intermediate certificate\"\nelse\n  if [[ ! -e root-ca.key ]]; then\n    echo \"Cannot generate intermediate certificate without root certificate private key\"\n    exit 1\n  fi\n\n  echo \"Generating intermediate certificate authority RSA key and certificate\"\n  ${OPENSSL} genrsa ${OPENSSL_GENRSA_FLAGS:-} -out intermediate-ca.key 4096\n  ${OPENSSL} req -new -nodes \\\n                 -subj \"/CN=${PRODUCT}-intermediate-ca@${TIMESTAMP}\" \\\n                 -key intermediate-ca.key |\n  ${OPENSSL} ca  -batch -notext -days 3700 \\\n                 -in /dev/stdin \\\n                 -out intermediate-ca.pem \\\n                 -keyfile root-ca.key \\\n                 -cert root-ca.pem \\\n                 -config .ca/config \\\n                 -extensions v3_ca\nfi\ncat intermediate-ca.pem root-ca.pem > intermediate-ca.crt\n\nif [[ ! -e intermediate-ca.key ]]; then\n  echo \"Cannot generate leaf certificates without intermediate certificate private key\"\n  exit 1\nfi\n\n# Generate new leaf CAs for all SCQLEngines and brokers\nfor TYPE in engine_alice engine_bob engine_carol broker_alice broker_bob broker_carol; do\n  CERT_NAME=\"${PRODUCT}-$(echo ${TYPE} | tr / -)-ca\"\n  echo \"Generating ${CERT_NAME} leaf certificate authority EC key and certificate\"\n  ${OPENSSL} ecparam -name prime256v1 -genkey -noout -out ${TYPE}-ca.key\n  ${OPENSSL} req -new -nodes \\\n                 -subj \"/CN=${CERT_NAME}@${TIMESTAMP}\" \\\n                 -key ${TYPE}-ca.key |\n\n  ${OPENSSL} ca  -batch -notext -days 3700 \\\n                 -in /dev/stdin \\\n                 -out ${TYPE}-ca.pem \\\n                 -keyfile intermediate-ca.key \\\n                 -cert intermediate-ca.pem \\\n                 -config .ca/config \\\n                 -extensions v3_ca\n\n  cat ${TYPE}-ca.pem \\\n      intermediate-ca.pem \\\n      root-ca.pem > ${TYPE}-ca.crt\ndone\n\necho\necho \"CA certificate generation complete. Required files are now present in: ${DATA_DIR}\"\n"
  },
  {
    "path": "test-tools/find_uncover_err.py",
    "content": "#!/usr/bin/env bash\n#\n# Copyright 2025 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nimport os\nimport sys\nimport re\n\nPACKAGE_PREFIX = \"github.com/secretflow/scql\"\n\n\ndef parse_cover_file(cover_file):\n    \"\"\"\n    Parse go cover profile, extract all uncovered blocks.\n    Returns: list of (filename, start_line, end_line) for uncovered blocks\n    \"\"\"\n    result = []\n    with open(cover_file, encoding=\"utf-8\") as f:\n        for line in f:\n            line = line.strip()\n            if line.startswith(\"mode:\"):\n                result.append(line)\n                continue\n            parts = line.split()\n            if len(parts) != 3:\n                result.append(line)\n                continue\n            filepath_pos, stmt_count, exec_count = parts\n            if exec_count != \"0\":\n                result.append(line)\n                continue  # only care about uncovered\n            if \":\" not in filepath_pos:\n                result.append(line)\n                continue\n            filepath, pos = filepath_pos.split(\":\", 1)\n            if \",\" not in pos:\n                result.append(line)\n                continue\n            start, end = pos.split(\",\")\n            sline = int(start.split(\".\")[0])\n            eline = int(end.split(\".\")[0])\n            replaced_filepath = filepath.replace(PACKAGE_PREFIX, os.getcwd())\n            if not os.path.exists(replaced_filepath):\n                print(f\"{replaced_filepath} not exists\")\n                result.append(line)\n                continue\n            if find_if_err_block((replaced_filepath, sline, eline)):\n                result.append(f\"{filepath}:{start},{end} {stmt_count} 1\")\n                continue\n            result.append(line)\n    return result\n\n\ndef find_if_err_block(block):\n    \"\"\"\n    Iterate over uncovered blocks, locate lines containing patterns like 'if xxxErr != nil {'\n    \"\"\"\n    # This regex pattern looks for:\n    # - \"if\" followed by whitespace\n    # - any characters (the variable name, e.g., \"result.\", \"finish\")\n    # - \"err\" or \"Err\" or \"Error\"\n    # - \"!=\" surrounded by optional whitespace\n    # - \"nil\"\n    # - an opening curly brace \"{\"\n    err_pattern = re.compile(r\"if\\s+.*([Ee]rr|Error)\\s*!=\\s*nil\\s*\\{\")\n    try:\n        with open(block[0], encoding=\"utf-8\") as f:\n            lines = f.readlines()\n            # lines number starts at 1!\n            for i in range(block[1], min(block[2] + 1, len(lines) + 1)):\n                code = lines[i - 1]\n                if err_pattern.search(code):\n                    print(f\"Matched: {block[0]}:{i}: {code.strip()}\")\n                    return True\n    except Exception as e:\n        # file might not exist or encoding issue\n        print(e)\n        return False\n    return False\n\n\ndef main():\n    results = parse_cover_file(sys.argv[1])\n    with open(sys.argv[2], \"w\", encoding=\"utf-8\") as f:\n        for line in results:\n            f.write(line)\n            f.write(\"\\n\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "version.txt",
    "content": "# Copyright 2023 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nversion = \"0.9.5dev\"\n"
  },
  {
    "path": "version_build.sh",
    "content": "#!/bin/bash\n#\n# Copyright 2024 Ant Group Co., Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n# NOTE: used internally by Makefile, please not call it manually\n\nset -eu\n\nRESTORE_FLAG=false\n\nusage() {\n  echo \"Usage: $0 [-r]\"\n  echo \"default build version info and change version.h in engine\"\n  echo \"Options:\"\n  echo \"  -r, restore version changes in version.h, using after version built.\"\n}\n\nwhile getopts \"r\" options; do\n  case \"${options}\" in\n  r)\n    RESTORE_FLAG=true\n    ;;\n  *)\n    usage\n    exit 1\n    ;;\n  esac\ndone\n\n# get work dir\nSCRIPT_DIR=$(\n  cd \"$(dirname \"$0\")\"\n  pwd\n)\n\nif $RESTORE_FLAG; then\n  if [ -e ${SCRIPT_DIR}/engine/exe/version.h.bak ]; then\n    cp -p ${SCRIPT_DIR}/engine/exe/version.h.bak ${SCRIPT_DIR}/engine/exe/version.h\n    rm ${SCRIPT_DIR}/engine/exe/version.h.bak\n    echo \"restore version.h succeed\"\n  else\n    echo \"no bak file existing, please build version first\"\n  fi\n  exit\nfi\n\nVERSION=$(grep \"version\" ${SCRIPT_DIR}/version.txt | awk -F'\"' '{print $2}')\nVERSION+=\".$(date '+%Y%m%d-%H:%M:%S')\"\nVERSION+=\".$(git rev-parse --short HEAD)\"\n\n# backup and replace version info for engine\ncp -p ${SCRIPT_DIR}/engine/exe/version.h ${SCRIPT_DIR}/engine/exe/version.h.bak\nsed -i \"s/ENGINE_VERSION_STRING.*/ENGINE_VERSION_STRING \\\"${VERSION}\\\"/g\" ${SCRIPT_DIR}/engine/exe/version.h\n\n\necho ${VERSION}"
  }
]